# Tweeks Engine API Reference

Canonical page: https://www.tweeks.io/docs
Markdown source: https://www.tweeks.io/docs/tw-engine-extensions.md
Machine-readable JSON: https://www.tweeks.io/docs/tw-engine-extensions.json

Reference for the `TW_*` APIs available in Tweeks scripts. Use them when a tweek needs to do more than modify a page — for example, run AI inference, send email, show notifications, or add context menu items. Generated from the code that ships today.

## Scope

- Total APIs: 7
- Total permission groups: 5
- Source files:
  - extension/shared/permission-system.js
  - extension/shared/script-compiler.js
  - extension/content/gm-api-constants.js
  - extension/content/content-runtime.js
  - extension/sw/gm-network-handlers.js
  - server/app/api/tw/inference/route.ts
  - server/app/api/tw/email/route.ts

## How These APIs Fit Into Tweeks

- Tweeks keeps the familiar Greasemonkey-style scripting model.
- On top of that, Tweeks adds `TW_*` methods plus matching `TW.*` and `GM.*` convenience calls.
- Some APIs stay local to the Tweeks runtime, while others use Tweeks services behind the scenes.
- Permission checks happen against `@grant` directives before privileged calls are allowed.

## Recommended Metadata Block

```js
// ==UserScript==
// @name         TW API Example
// @grant        TW_inference
// @grant        TW_email
// @grant        TW_contextMenu
// @grant        TW_notifications
// ==/UserScript==
```

## Permission Groups

### TW_inference

- Description: AI inference calls that leave the page, cross into the service worker, and hit the server-side inference endpoint.
- Members: TW_inference
- Notes:
  - Recommended grant: @grant TW_inference
  - Also accepted: @grant TW.inference, @grant inference

### TW_email

- Description: Email delivery and delayed email scheduling for the signed-in user.
- Members: TW_email
- Notes:
  - Recommended grant: @grant TW_email
  - Also accepted: @grant TW.email, @grant email

### TW_avatar

- Description: Avatar index, lookup, and self-profile operations backed by Tweeks avatar endpoints and local caches.
- Members: TW_avatar
- Notes:
  - Recommended grant: @grant TW_avatar
  - Also accepted: @grant TW.avatar, @grant avatar

### TW_contextMenu

- Description: Browser context-menu creation and cleanup in privileged extension context.
- Members: TW_contextMenu, TW_removeContextMenu
- Notes:
  - @grant TW_contextMenu implicitly enables removal as well.
  - You can request only removal with @grant TW_removeContextMenu, but creation requires TW_contextMenu.

### TW_notifications

- Description: Local notification UI surfaced inside the Tweeks runtime: toasts and confirm-style alerts.
- Members: TW_toast, TW_alert
- Notes:
  - @grant TW_notifications unlocks both TW_toast and TW_alert.
  - Individual grants like @grant TW_toast and @grant TW_alert are also accepted and are folded into the same permission group internally.

## API Catalog

## TW_inference

- Category: AI
- Summary: Runs a prompt through Tweeks' configured inference model and returns plain text back to the userscript. The call is forwarded through the Tweeks runtime and requires the user to be signed in.
- Recommended grant: `TW_inference`
- Accepted grants: `TW_inference`, `TW.inference`, `inference`
- Permission group: `TW_inference`
- Execution: Extension + server endpoint
- Call surfaces: `TW_inference(prompt, data)`, `TW.inference(prompt, data)`, `GM.inference(prompt, data)`
- Notes:
  - This API is async-only.
  - The service worker rejects unauthenticated requests with a standardized sign-in error and the Tweeks panel shows a sign-in alert.
  - The server logs successful usage to inference_logs and counts those rows against quota.

### inference

- Signature: `TW_inference(prompt, data?)`
- Summary: Submit a prompt and optional structured data, then receive a text completion.
- Auth: required
- Returns: `Promise<string>`
- Delivery: Uses Tweeks service
- Notes:
  - prompt must be a non-empty string
  - prompt is capped at 10,000 characters
  - prompt + serialized data is capped at 50,000 characters
  - server max output is 4,096 tokens
  - client-side timeout is 120 seconds
  - successful calls consume shared Tweeks quota when FREE_QUOTA_INFERENCE_COST is above zero

```js
// ==UserScript==
// @grant TW_inference
// ==/UserScript==

const summary = await TW.inference(
  "Summarize the visible article in three bullets.",
  { title: document.title, url: location.href }
);

console.log(summary);
```

## TW_email

- Category: Automation
- Summary: Sends an email to the authenticated Tweeks account, immediately or on a delay. Delivery is handled by Tweeks after the runtime accepts the call.
- Recommended grant: `TW_email`
- Accepted grants: `TW_email`, `TW.email`, `email`
- Permission group: `TW_email`
- Execution: Extension + server endpoint
- Call surfaces: `TW_email(subject, body, delay)`, `TW.email(subject, body, delay)`, `GM.email(subject, body, delay)`
- Notes:
  - Newlines are stripped from the subject before delivery.
  - Unauthenticated calls return a sign-in error.
  - Delayed delivery returns a workflow run id instead of sending immediately.

### email

- Signature: `TW_email(subject, body?, delay?)`
- Summary: Deliver a message to the current user's email address, optionally scheduled in the future.
- Auth: required
- Returns: `Promise<{ success: true; messageId?: string; scheduled: boolean; runId?: string }>`
- Delivery: Uses Tweeks service
- Notes:
  - subject must be a non-empty string and is capped at 200 characters
  - body must be a string if provided and is capped at 50,000 characters
  - delay must be a string like 10s, 5m, 1h, 24h, or 7d
  - maximum delay is 30 days
  - client-side timeout is 30 seconds

```js
// ==UserScript==
// @grant TW_email
// ==/UserScript==

await GM.email(
  "Daily page digest",
  document.body.innerText.slice(0, 4000),
  "15m"
);
```

## TW_avatar

- Category: Identity
- Summary: Reads and updates public avatar profile data, with caching and action-specific sign-in rules.
- Recommended grant: `TW_avatar`
- Accepted grants: `TW_avatar`, `TW.avatar`, `avatar`
- Permission group: `TW_avatar`
- Execution: Extension + cache + endpoint
- Call surfaces: `TW_avatar("getIndex", payload)`, `TW.avatar("queryProfiles", payload)`, `TW.avatar("upsertSelf", payload)`, `GM.avatar("getSelf", payload)`
- Notes:
  - This API uses session storage caches for both index and profile data.
  - The client-side timeout is 45 seconds.
  - Unsupported actions fail with Unsupported TW_avatar action.

### getIndex

- Signature: `TW_avatar("getIndex", { provider?, forceRefresh? })`
- Summary: Fetch the public index of user keys for a provider, optionally with a snapshot payload and local cache reuse.
- Auth: optional
- Returns: `Promise<{ provider: string; revision: string; schemaVersion: number; mode: "keys_only" | "snapshot"; ttlSec: number; userKeys: string[]; profiles?: Record<string, PublicAvatarConfig>; fromCache: boolean; stale?: boolean; warning?: string }>`
- Delivery: Uses Tweeks service
- Notes:
  - only the twitter provider is currently accepted
  - response mode may be keys_only or snapshot
  - If-None-Match is used to revalidate cached indexes
  - stale cached data may be returned when refresh fails

### queryProfiles

- Signature: `TW_avatar("queryProfiles", { provider?, userKeys })`
- Summary: Resolve a batch of public avatar profiles by user key, mixing fresh cache entries with endpoint fetches.
- Auth: optional
- Returns: `Promise<{ provider: string; ttlSec: number; ttlSecByUserKey: Record<string, number>; profiles: Record<string, PublicAvatarConfig> }>`
- Delivery: Uses Tweeks service
- Notes:
  - payload.userKeys must be an array
  - invalid user keys fail the entire call
  - the service worker enforces a maximum batch size
  - missing profiles are cached with a shorter negative TTL

### upsertSelf

- Signature: `TW_avatar("upsertSelf", { provider?, userKey, dna, animated, walking, talking, waving, bw, multiplayerEnabled })`
- Summary: Create or update the signed-in user's own avatar profile for a provider.
- Auth: required
- Returns: `Promise<{ provider: string; profile: StoredAvatarProfile }>`
- Delivery: Uses Tweeks service
- Notes:
  - provider defaults to twitter and must currently stay there
  - dna must be 6-7 lowercase hex characters
  - animated, walking, talking, waving, bw, and multiplayerEnabled must all be booleans
  - 401 responses are surfaced as AUTH_REQUIRED with authRequired: true; treat legacy UNAUTHORIZED as sign-in-required when supporting older extension builds

### getSelf

- Signature: `TW_avatar("getSelf", { provider? })`
- Summary: Read the signed-in user's stored avatar profiles for a provider.
- Auth: required
- Returns: `Promise<{ provider: string; profiles: Record<string, PublicAvatarConfig & { provider: string; userKey: string; multiplayerEnabled: boolean }>; count: number }>`
- Delivery: Uses Tweeks service
- Notes:
  - private server-side fields are stripped before the result is posted back to page context
  - 401 responses are surfaced as AUTH_REQUIRED with authRequired: true; treat legacy UNAUTHORIZED as sign-in-required when supporting older extension builds

```js
// ==UserScript==
// @grant TW_avatar
// ==/UserScript==

const index = await TW.avatar("getIndex", { provider: "twitter" });
const profiles = await TW.avatar("queryProfiles", {
  provider: "twitter",
  userKeys: index.userKeys.slice(0, 5),
});

console.table(profiles.profiles);
```

## TW_contextMenu

- Category: Browser UI
- Summary: Creates browser context-menu entries owned by the current script. Menus are persisted per script and cleaned up automatically when permissions or script state change.
- Recommended grant: `TW_contextMenu`
- Accepted grants: `TW_contextMenu`, `TW.contextMenu`, `contextMenu`
- Permission group: `TW_contextMenu`
- Execution: Browser runtime
- Call surfaces: `TW_contextMenu(title, callback, options)`, `TW.contextMenu(title, callback, options)`, `GM.contextMenu(title, callback, options)`
- Notes:
  - Granting TW_contextMenu implicitly enables TW_removeContextMenu.
  - Menu ids are deterministic per script and title hash.
  - This stays inside the Tweeks browser runtime.

### create

- Signature: `TW_contextMenu(title, callback, options?)`
- Summary: Create or update a context-menu item and bind its callback through the injected runtime.
- Auth: none
- Returns: `string | null`
- Delivery: Runs locally in Tweeks
- Notes:
  - title is required unless options.type === separator
  - callback must be a function
  - supported options include contexts, documentUrlPatterns, targetUrlPatterns, type, and parentId
  - if documentUrlPatterns are omitted, the script's @match patterns are used when available

```js
// ==UserScript==
// @grant TW_contextMenu
// ==/UserScript==

const menuId = TW.contextMenu("Summarize selection", async () => {
  const text = window.getSelection()?.toString() || "";
  console.log(text);
}, {
  contexts: ["selection"],
});
```

## TW_removeContextMenu

- Category: Browser UI
- Summary: Removes a context-menu entry previously registered by the same script. Guarded by script ownership — the runtime refuses to remove menu ids the current script did not create.
- Recommended grant: `TW_removeContextMenu`
- Accepted grants: `TW_removeContextMenu`, `TW.removeContextMenu`, `removeContextMenu`, `TW_contextMenu`, `TW.contextMenu`, `contextMenu`
- Permission group: `TW_contextMenu`
- Execution: Browser runtime
- Call surfaces: `TW_removeContextMenu(menuId)`, `TW.removeContextMenu(menuId)`, `GM.removeContextMenu(menuId)`
- Notes:
  - TW_contextMenu implicitly grants this capability.
  - The service worker tracks menu ownership in session storage for cleanup.

### remove

- Signature: `TW_removeContextMenu(menuId)`
- Summary: Remove a menu item owned by the current script and unregister its callback.
- Auth: none
- Returns: `void`
- Delivery: Runs locally in Tweeks
- Notes:
  - menuId must be a string
  - the menu must belong to the current script
  - missing menu items are tolerated during browser removal, but non-owned ids fail

```js
// ==UserScript==
// @grant TW_removeContextMenu
// ==/UserScript==

TW.removeContextMenu("ctx_abcd1234_demo");
```

## TW_toast

- Category: Notifications
- Summary: Shows a transient in-extension toast notification through the Tweeks UI layer. Stays inside the extension runtime and does not hit the network.
- Recommended grant: `TW_notifications`
- Accepted grants: `TW_notifications`, `TW.notifications`, `notifications`, `TW_toast`, `TW.toast`, `toast`
- Permission group: `TW_notifications`
- Execution: On page runtime
- Call surfaces: `TW_toast(message, type, title, duration)`, `TW.toast(message, type, title, duration)`, `GM.toast(message, type, title, duration)`
- Notes:
  - Grant TW_notifications if you want both toast and alert.
  - This API initializes the local menu UI if needed.

### toast

- Signature: `TW_toast(message, type?, title?, duration?)`
- Summary: Display a toast in the Tweeks notification layer and receive its generated id.
- Auth: none
- Returns: `Promise<{ success: true; toastId: string | null }>`
- Delivery: Runs locally in Tweeks
- Notes:
  - message must be a non-empty string
  - type defaults to info
  - duration defaults to 4000 ms if omitted
  - client-side timeout is 5 seconds

```js
// ==UserScript==
// @grant TW_notifications
// ==/UserScript==

await TW.toast("Saved filters for this page", "success", "Tweeks", 2500);
```

## TW_alert

- Category: Notifications
- Summary: Shows a confirm-style modal alert through the Tweeks notification layer. Resolves to the user's confirm or cancel choice.
- Recommended grant: `TW_notifications`
- Accepted grants: `TW_notifications`, `TW.notifications`, `notifications`, `TW_alert`, `TW.alert`, `alert`
- Permission group: `TW_notifications`
- Execution: On page runtime
- Call surfaces: `TW_alert(message, type, title, confirmText, cancelText)`, `TW.alert(message, type, title, confirmText, cancelText)`, `GM.alert(message, type, title, confirmText, cancelText)`
- Notes:
  - Grant TW_notifications if you want both alert and toast.
  - The content runtime returns confirmed: true only when the user picks the confirm branch.

### alert

- Signature: `TW_alert(message, type?, title?, confirmText?, cancelText?)`
- Summary: Display an interactive alert and resolve with the user's confirmation choice.
- Auth: none
- Returns: `Promise<{ confirmed: boolean }>`
- Delivery: Runs locally in Tweeks
- Notes:
  - message must be a non-empty string
  - type defaults to info
  - confirmText defaults to OK
  - client-side timeout is 60 seconds

```js
// ==UserScript==
// @grant TW_notifications
// ==/UserScript==

const { confirmed } = await GM.alert(
  "Archive this page state?",
  "warning",
  "Tweeks",
  "Archive",
  "Cancel"
);
```
