Use the Twin CLI
Sign in, inspect recent sessions and channels, read artifacts, and query your Twin from a terminal.
The Twin CLI is the shortest route for Codex, Claude Code, and other local agents. It uses MLX's shared HTTPS gateway. You do not need SSH, Tailscale, an API key, a copied token, or a tenant or organisation ID.
Install it globally
The official package is a public GitHub Release. Install it for your user rather than in a project:
npm install --global \
https://github.com/mercury-labs/twin-cli/releases/latest/download/twin-cli.tgz
command -v twin
twin help --jsonThe release is downloadable without a GitHub account or token. The final two
commands prove that twin is available on PATH and can be used from any
working directory. Do not use npx, add the CLI as a project dependency,
install a similarly named package, or use sudo.
If installation succeeds but command -v twin fails, add npm's user-level
global binary directory to your persistent shell PATH, open a new terminal,
and restart Codex or Claude Code so it inherits the updated environment.
Public CLI, private organisation access
Anyone can install the CLI. twin login still uses browser OAuth and
independently determines which organisation and channels the user may query.
Learn the interface
twin help
twin help sessions
twin help query
twin help feedback
twin help --jsonThe JSON help is a capability manifest intended for agents. Start with
sessions, channels, query, artifacts, and feedback; login, logout,
status, and organisations manage local sign-in context. These are starting
points, not the complete command list. Use twin help --json for the commands
available in your installed version and twin help <command> for their usage.
Sign in
twin loginComplete sign-in and organisation selection in the browser. Desktop sessions use the operating system's credential store. Never paste credentials, cookies, or tokens into the terminal or an agent conversation.
After sign-in, the browser briefly returns to
http://127.0.0.1:<random-port>. This is the CLI's temporary OAuth callback:
it passes a one-time code back to the command running on the same computer.
The page shows Twin connected only after the CLI has verified and saved the
credential, at which point you can close the tab. The Twin gateway and all
subsequent API traffic remain on HTTPS; the loopback address is not a customer
server and does not expose Twin data.
From SSH or a headless host
On gateways with cloud CLI sign-in enabled, run twin login inside SSH or
twin login --headless in another headless terminal. Open the printed URL in
your workstation browser, complete sign-in and consent, then wait for the
remote CLI's success message. You do not need port forwarding or copied tokens.
The browser returns to the gateway's HTTPS callback, not your workstation's
loopback listener.
The gateway hands off only a short-lived, single-use code. The remote CLI keeps
its PKCE verifier, verifies the returned identity, and stores the session on that
host under $XDG_CONFIG_HOME/twin/credentials or ~/.config/twin/credentials.
Directories are private (0700) and files are private (0600), but these files
are not encrypted by a desktop keyring: use a host and account you trust.
Subsequent commands find the same saved session even outside SSH; twin logout
ends the sign-in and removes it from that host.
The gateway must support cloud callbacks and the issuer must approve its exact callback URL. If registration is refused, sign-in stops with an explicit error; it does not silently switch to local-browser authentication. A handoff expires after five minutes or is lost when the gateway restarts; run a new login.
One gateway, organisation-scoped access
The default CLI connects to https://twins.mlx.systems. The gateway derives
tenant, organisation, and user authority from the signed-in identity. It does
not make every tenant or channel accessible.
Choose an organisation
twin status
twin organisations --json
twin channels --assert-org <organisation-id-or-exact-name> --json
TWIN_ORG=<organisation-id-or-exact-name> twin channels --json
twin organisations --use <organisation-id-or-exact-name>One browser login covers every organisation available to that identity on the
gateway. --assert-org (or --org) chooses the organisation for one command,
and TWIN_ORG for every command in a process. Neither changes your saved default
organisation, so agents working in different organisations don't disturb each
other. Only twin organisations --use and twin login change the default, and
twin organisations marks it with *. No choice of organisation asks you to sign
in again.
A command that can change something must name its organisation in one of these ways, or it is refused. A command that names none prints the organisation it used.
An agent must show the organisation before its first query. When more than one is available, it must ask the user which one to use rather than guess, and then name it on every command. Choosing an organisation in the CLI does not change the organisation selected in an open web-app tab.
Discover and read sessions
twin sessions
twin sessions --limit 50 --json
twin sessions --session <session-id> --json
twin sessions --session <session-id> --cursor <older-cursor> --jsonSession discovery is ordered by most recent activity first. Every row includes the title, session ID, canonical owner ID, status, and timestamps so an agent can select the right conversation without guessing from channel activity. Reading one session returns bounded user and assistant turns only. Internal prompts, tools, events, routing, skills, model metadata, and reasoning are not part of the public response. The same member and organisation-admin visibility rules used by the app apply to both listing and reading.
Create and test workflows
Discover the exact authoring contract and the read-only source tools currently available to your user before creating a definition:
twin workflows schema --json
twin workflows sources --json
twin workflows source-schema --source google_gmail_operation --json
twin workflows example > workflow.json
twin workflows validate --file workflow.json --json
twin workflows create --session <session-id> --file workflow.json \
--assert-org <organisation-id> --allow-write --json
twin workflows update --workflow <workflow-id> --expected-version <n> \
--file workflow.json --assert-org <organisation-id> --allow-write --json
twin workflows list --json
twin workflows versions --session <session-id> --json
twin workflows sample --workflow <workflow-id> --version <n> \
--idempotency-key <unique-key> --json
twin workflows result --workflow <workflow-id> --run <run-id> --jsonFor a V2 durable definition, review the exact resource plan before applying it. Applying provisions resources but leaves execution paused. Activate only after checking the returned bindings, permitted effects and trigger schedule:
twin workflows plan --workflow <workflow-id> --expected-version <n> \
--assert-org <organisation-id> --allow-write --json
twin workflows apply --workflow <workflow-id> --plan <plan-id> --hash <plan-hash> \
--assert-org <organisation-id> --allow-write --json
twin workflows activate --workflow <workflow-id> --activation <activation-id> \
--expected-version <n> --assert-org <organisation-id> --allow-write --json
twin workflows pause --workflow <workflow-id> --activation <activation-id> \
--expected-version <n> --assert-org <organisation-id> --allow-write --jsonResuming rechecks live source access and resource bindings. Pausing prevents new trigger dispatch and fences workflow effects while retaining the dataset, intake records and reviewer decisions.
Definitions are private to the verified owner. Updates and restores append an
immutable version. Mutations require both an exact
organisation assertion and --allow-write; inspect twin workflows --help for
restore and archive commands.
Sample creation persists a run and result receipt, but source access is limited
to authorised reads. It cannot modify channel records or external systems.
Repeat result until the run is terminal. Reusing an idempotency key returns the
same run; use a new key for a fresh sample. When your organisation enables Twin
Judge, judgment nodes automatically send their state and questions, which can
include source records, to TypeSafe. No per-workflow approval is required.
The organisation's configured policy automatically allows Share Guard warnings
and approval outcomes for that exact destination; explicit blocks still stop it.
Discover channels
twin channels
twin channels --json
twin channels --channel <channel-id-or-slug> --json
twin channels --channel <channel-id-or-slug> --views --json
twin channels --channel <channel-id-or-slug> --view <view-id-or-slug> --json
twin channels --channel <channel-id-or-slug> --view <view-id-or-slug> --data --json
twin channels --channel <channel-id-or-slug> --view <view-id-or-slug> --data --fields id,title,status --limit 25 --json
twin channels --channel <channel-id-or-slug> --view <view-id-or-slug> --data --widget <widget-id> --jsonThe list contains only channels the signed-in user may access. Inspecting a
channel returns its Data Sets and queryable field keys. In JSON, a Data Set is
still named objectType and linked with objectTypeId; those stable wire names
remain unchanged for existing clients. Product definitions
may govern the data behind a channel, but they are not part of the customer
query interface.
Use the returned channel and saved-view slugs as readable references, or their IDs when storing a durable reference. Data Sets and fields still require the exact IDs and keys returned by inspection. Public responses omit tenant metadata, source relation names, dataset IDs, and other internal plumbing.
All six renderer types use the canonical saved-View data endpoint. Table,
Board, Calendar, and Timeline Views return bounded records from the Data Set's
one schema. Dashboards return widget results, while Pivot tables return their
canonical live period columns and rows. The CLI does not recreate saved filters,
projections, pivots, or renderer behaviour locally. --widget narrows a
Dashboard response to one inspected widget, which helps an agent avoid loading
an entire dashboard into its context.
Record-based view reads default to 50 rows. Use --limit for smaller pages,
--fields for a comma-separated projection, and --filters for a JSON array
using the same filter shape as a saved View, given inline or as a file. The
temporary filters are combined with the View's saved filters. For example:
[
{ "fieldKey": "status", "op": "eq", "value": "active" },
{ "fieldKey": "dueDate", "op": "isNotBlank" }
]twin channels --channel <channel> --view <view> --data \
--fields title,status,dueDate --filters filters.json --limit 25 --json
twin channels --channel <channel> --view <view> --data \
--fields title,status,dueDate --filters filters.json --limit 25 \
--cursor <nextCursor> --json
twin channels --channel <channel> --view <view> --data \
--filters '[{"fieldKey":"status","op":"eq","value":"active"}]' --jsonTreat the cursor as opaque and reuse it only with the same View, projection,
and temporary filters. Every page retains source freshness metadata. When one
page holds the whole view, it also carries totalCount and totals: the sum
of each number field, and of each amount in one currency, read as the app's
column totals read them. totalsCounted and totalsSkipped say, per field, how
many values were added and how many were not numbers and were left out.
Follow channel activity
The channel feed combines human and agent posts with recent artifact changes, file uploads, and linked sessions. Read it in small pages when an agent only needs recent context:
twin channels --channel <channel-id> --feed --limit 10 --json
twin channels --channel <channel-id> --feed --cursor <next-cursor> --limit 10 --json
twin channels --channel <channel-id> --members --json
twin channels --channel <channel-id> --replies <post-id> --json
twin channels --channel <channel-id> --thread session:<session-id> --jsonCreate a top-level update, or continue an existing thread, only after the user approves the exact text and channel:
twin channels --channel <channel-id> \
--post "Weekly close is ready for review." --allow-write --json
twin channels --channel <channel-id> \
--post "Reviewed and approved." --reply-to <post-id> --allow-write --json
twin channels --channel <channel-id> \
--thread artifact:<artifact-id> --comment "@Alex Please review." \
--mention-user-ids <user-id> --allow-write --json
twin channels --channel <channel-id> \
--thread session:<session-id> --reaction eyes --allow-write --jsonPosts, replies, and thread comments render Markdown in the app, including lists,
emphasis, links, fenced code blocks, and tables. Start each list item on a new
line with - , * , or + , and leave a blank line before the list. Literal
• characters are plain text, not Markdown list markers. Preserve actual
newlines in the argument; a literal \n inside ordinary quotes is not a newline.
For example, in Bash or Zsh:
twin channels --channel <channel-id> \
--post $'Summary\n\n- First item\n- Second item' --allow-write --json
twin channels --channel <channel-id> --thread artifact:<artifact-id> \
--comment $'Review notes\n\n- First item\n- Second item' --allow-write --jsonMLX records the authenticated author and whether the post came from the web,
CLI, API, MCP, or Twin agent runtime. --members returns canonical mention IDs
for active human members explicitly attached to the channel; shared channels
may also be visible to other organisation users. Threads are flat and can be
attached to posts, sessions, artifacts, or files. Authors can edit or delete
their comments, and reactions can acknowledge the root or a comment. Use
eyes for seen and check for handled—reading alone does not mark an item
seen. Keep updates complete and concise; do not publish internal reasoning or
tool-by-tool progress.
Pass --client-app claude-code, codex, gemini, or chatgpt when an
external agent initiates the post. The web app pairs the authenticated user's
avatar with that client icon. This is display and audit attribution only; it
does not change identity, authority, or routing.
The same attribution follows CLI-created Sessions, posts, and artifacts into the web app. It appears as an overlapping user-and-client pair in the Sessions table, sidebar previews, and Channel feed sub-rows. Hover or focus the pair for the full explanation. When a response actually retrieves governed Twin data, the Twin mark appears with the pair and below the response; it is not shown merely because Twin retrieval was available.
Create a Data Set and saved Views
Create channel structure through the same authenticated public surface used for
record writes. Each operation requires twin.write and explicit
--allow-write approval. Start with a stable slug:
{
"slug": "product-activations",
"name": "Product & Activations",
"description": "Product customers, use cases, launches and health.",
"purpose": "Operate product activation from discovery through live use.",
"visibility": "shared"
}twin channels --create-channel channel.json --allow-write --jsonCreate a Data Set in the returned Channel, then use its exact returned ID when
adding fields. The compatibility flags and JSON payloads continue to say
object-type and objectTypeId:
{
"slug": "activation",
"name": "Activation",
"description": "One customer product activation."
}{
"key": "activation_status",
"label": "Activation status",
"type": "select",
"required": true,
"position": 0,
"config": { "options": ["Discovery", "Pre-live", "Live", "Closed"] }
}twin channels --channel product-activations \
--create-object-type object-type.json --allow-write --json
twin channels --channel product-activations \
--object-type <returned-object-type-id> \
--create-field field.json --allow-write --jsonCreating a Data Set also creates its initial Table View. The View uses the supplied Data Set name rather than a generic fallback; create additional Views with their own explicit names.
A create never changes an existing Data Set or field. If the channel already
has a Data Set with that slug (given, or made from the name), or the Data Set
already has a field with that key, the command fails with 409 and names the
existing Data Set or field, even when it is archived. Change it with
--update-object-type or --update-field, or choose another slug or key.
A saved View is a complete validated definition. Its objectTypeId must be the
exact created Data Set ID:
{
"slug": "activations-by-status",
"name": "Activations by status",
"type": "board",
"objectTypeId": "<returned-object-type-id>",
"definition": {
"version": 1,
"objectTypeId": "<returned-object-type-id>",
"groupBy": "activation_status",
"groupByFieldKey": "activation_status",
"cardFields": ["activation_status"]
},
"makeDefault": true
}twin channels --channel product-activations \
--create-view view.json --allow-write --jsonCreating a View is Save as: it preserves the current View and gives the new
filter and renderer combination its own name. To Save changes to an existing
View, inspect it, include its currentVersionId as
expectedCurrentVersionId in the update file, and run --update-view.
Read back the channel schema and view before adding records. Creation does not grant authority: channel ACLs and the OAuth scopes are still enforced by the server.
Use the correct filter contract
Saved-View definitions and channels --filters files share one validated
record-filter contract for every renderer. Use fieldKey and op:
[
{ "fieldKey": "taskType", "op": "eq", "value": "BD Task" },
{ "fieldKey": "status", "op": "notIn", "values": ["Done", "Cancelled"] },
{ "fieldKey": "owner", "op": "isNotBlank" }
]Supported saved-View operators are eq, neq, gt, gte, lt, lte,
contains, notContains, startsWith, endsWith, in, notIn, between,
notBetween, isBlank, and isNotBlank.
Negative filters (neq, notContains, notIn, notBetween) include blank
fields. Blank means a missing value, null, an empty string, or an empty array
for multiselect and multiuser fields, matching isBlank. Zero and false are
not blank. Add isNotBlank on the same field when you want to exclude blanks.
Existing saved Views using negative filters may therefore show additional rows
whose fields are blank; their saved filter definitions do not need to change.
Only a deterministic twin query --intent-file uses the older field and
operator shape:
[
{ "field": "taskType", "operator": "eq", "value": "BD Task" },
{ "field": "status", "operator": "not_in", "values": ["Done", "Cancelled"] },
{ "field": "owner", "operator": "is_not_blank" }
]The deterministic spellings are eq, not_eq, gt, gte, lt, lte,
contains, starts_with, in, not_in, is_null, is_not_null,
is_blank, and is_not_blank. As in saved Views, not_eq, not_in,
not_contains and not_between include blank fields; add is_not_blank on
the same field to exclude them. Record-based channels --data reads always
apply the saved View's filters; an explicit --filters file adds further AND
conditions.
The two shapes remain distinct public contracts for compatibility. View authors
and channels --filters callers should not mix the deterministic shape into a
saved-View operation. Any future
consolidation must use a versioned public-contract migration rather than
silently reinterpreting existing JSON.
Read, add, and update a channel record
Inspect the Channel first and use the exact Data Set ID and field keys it returns. For example, a native Clients channel might accept:
{
"objectTypeId": "client",
"title": "Acme Ltd",
"values": {
"name": "Acme Ltd",
"status": "active"
}
}twin channels --channel <clients-channel-id> \
--add-record client.json \
--idempotency-key <stable-operation-key> \
--allow-write \
--jsonThe command requires the twin.write OAuth grant and the explicit
--allow-write flag. If you signed in before this capability was enabled, run
twin login again to grant the updated scope. The server validates required
fields and records the normal channel audit event. Source-backed Data Sets
reject record creation; add the row in the source system instead.
The creation response includes the complete normalized public record—ID,
Data Set, title, values, status, and version—plus a stable receipt and the
channel audit-event ID. The CLI generates an idempotency key for interactive
use. For automation, pass --idempotency-key and reuse it after a lost response;
the same content returns the original record and receipt, while different
content returns 409 Conflict. Independently read back consequential writes.
Do not let an agent add a record merely because it inferred one from a conversation. The user should approve the exact record content and target channel first.
Read one existing record before changing it:
twin channels --channel <channel-id> --record <record-id> --jsonThe response includes the complete public values and monotonic version.
Copy that version into a patch containing only the intended changes:
{
"expectedVersion": 3,
"values": { "nextAction": "Schedule review" }
}twin channels --channel <channel-id> --record <record-id> \
--update-record record-patch.json --allow-write --jsonValue keys are merged rather than replacing the complete record. A stale
version returns 409 Conflict. Native records can also update title or
status; source-backed records accept only title, status, and fields marked as
MLX-owned overlays.
To remove a native record from active channel data without destroying its audit history, read it first and archive the exact version the user approved:
twin channels --channel <channel-id> --archive-record <record-id> \
--expected-version <current-version> --allow-write --jsonArchiving is the public delete contract. It uses the same optimistic conflict check as an update and returns the complete archived record with its incremented version.
Read, create, or update an artifact
List artifacts from an accessible session and read supported text content:
twin artifacts --session <session-id> --json
twin artifacts --artifact <artifact-id>
twin artifacts --artifact <artifact-id> --version <version-id> --jsonArtifact metadata is deliberately narrow and content reads support MLX Markdown and CSV. Internal source-event, tool-call, and execution metadata are not exposed. External-resource artifacts remain discoverable but are not streamed as text.
An external agent can store complete Markdown or CSV directly without asking a model to generate it. The user must approve the content and channel first:
twin artifacts --kind markdown --title "Weekly brief" --file brief.md \
--channel <channel-id> --client-app claude-code --allow-write --jsonThe response includes the artifact and version IDs. To publish a revision, send the exact current version ID:
twin artifacts --artifact <artifact-id> --expected-version <version-id> \
--title "Revised weekly brief" --file brief.md \
--client-app claude-code --allow-write --jsonCreation and updates are idempotent. Updates return a conflict if the artifact
changed after it was inspected; re-read the current version and show the user
the competing change rather than silently overwriting it. When --channel is
present on creation, the artifact appears in that channel's feed with the
authenticated user and initiating client attribution.
Publish a saved-view update
Read the view, copy its complete current definition into a JSON file, make the approved change, and include the version you inspected:
{
"expectedCurrentVersionId": "version_123",
"definition": {
"version": 1,
"layout": { "columns": 12, "rowHeight": 28, "gap": 12 },
"filters": [],
"widgets": [
{
"id": "clients",
"title": "Clients",
"type": "record_list",
"columns": ["name", "status"],
"position": { "x": 0, "y": 0, "w": 12, "h": 9 }
}
]
}
}twin channels --channel <channel-id> --view <view-id> \
--update-view view-update.json \
--allow-write \
--jsonThe definition must be valid for that view type. MLX publishes it as a new
version and returns 409 Conflict if another user changed the view after the
version you inspected.
Ask the Twin
Natural-language queries use the same persisted session and router as the web app:
twin query --question "What changed this week?"
twin query --channel <channel-id> --question "Summarise the open risks"
twin query --channel <channel-id> --question "Summarise the open risks" --stream
twin query --question "Apply the approved source update" --streamThe command creates a private session and returns its query, task, and session
IDs. cli, api, or mcp is recorded as audit metadata; it does not select a
different router or change authority.
Routed sessions inherit the tenant-approved readonly-data and writeback
capabilities and require the twin.write OAuth scope. The prompt still controls
whether a write should occur: use an explicit read-only instruction for audits,
and require the user to confirm an exact source action before asking the agent
to perform it. The router still chooses the source; callers do not select plugin
or connector slugs.
Without --stream, the command waits quietly and prints one terminal result.
Use --stream when an agent should keep the user informed. It writes one JSON
object per line as the public query moves through queued, running, and a
terminal state:
{"type":"query.submitting"}
{"type":"query.queued","queryId":"query_123","taskId":"task_123","sessionId":"session_123"}
{"type":"query.running","queryId":"query_123","taskId":"task_123","sessionId":"session_123"}
{"type":"query.completed","query":{"id":"query_123","status":"completed","answer":"..."}}query.submitting is an immediate local acknowledgement while the server
creates the query. Intermediate transitions contain only stable identifiers so
an external agent can report progress without spending tokens on repeated query
data. The terminal query.completed event contains the complete public result.
A deterministic query moves directly from query.submitting to
query.completed. A timeout or transport failure emits query.error before
the command exits unsuccessfully.
A local timeout does not cancel server work. Recover the same query without creating a duplicate session:
twin query --result <query-id> --json
twin query --wait <query-id> --streamThe stream reports the public lifecycle, not model tokens, private reasoning, prompts, SQL, or internal run events.
Run a deterministic query
When an external agent already knows the exact result shape, it can submit a typed intent instead of asking the router to interpret prose:
{
"mode": "deterministic",
"channelId": "invoices",
"objectTypeId": "invoice",
"operation": "aggregate",
"groupBy": ["month"],
"metrics": [
{ "alias": "revenue", "function": "sum", "field": "amount" }
],
"filters": [
{ "field": "status", "operator": "eq", "value": "paid" }
],
"orderBy": [{ "field": "month", "direction": "asc" }],
"limit": 24
}twin query --intent-file query.json --json--intent '<json>' takes the same object inline, for an agent that cannot
write files.
Deterministic requests support records, aggregate, and saved view
operations. A view intent supplies channelId, viewId, and optionally
widgetIds; it returns the same canonical widget results as channels --data.
Aggregate metrics use one of count_rows, count_distinct, sum, average,
minimum, or maximum. count_rows must omit field; every other function
requires an inspected field key. Run twin help --json for complete records,
aggregate, and view examples plus the supported filter operators and limits.
For record and aggregate intents, the server
checks channel access, validates every field against the channel schema,
injects organisation scope, and compiles a parameterised query. Raw SQL,
relation names, tenant IDs, and organisation IDs are not accepted.
Two query modes, one authority boundary
Session mode uses the canonical Twin router. Deterministic mode skips model interpretation because the caller supplied typed intent, but it still uses the same identity, channel access, and server-owned data bindings.
Handle errors
Human-readable failures include the problem title, detail, and exact validation
path, for example metrics[0].function. With --json, failures are written as
a stable { "error": { ... } } object to standard error. Keep that detail when
reporting a failure to the user; do not replace it with only Bad Request or
retry by guessing another field or function.
Submit feedback
When the user corrects an answer or explains how the Twin could improve, their agent can submit that feedback directly:
twin feedback \
--query <query-id> \
--description "Use invoiced revenue rather than bookings for this question."Use --description-file for longer feedback. The query ID attaches the
existing session and run provenance; omit it for general Twin feedback.
Submit only feedback the end user provided or confirmed. Do not include credentials, raw private records, or unrelated conversation text.
Agent setup prompt
Connect this computer to my Twin with the official `twin` CLI.
Read https://docs.mlx.systems/docs/connect/cli before setup and use the live
guide if installation, sign-in, or a command is unclear. After installation,
treat `twin help --json` as the exact contract for that installed CLI version.
Run `command -v twin`. If it is missing, install the public GitHub Release
globally for my user using the exact command on this page. Do not request a
GitHub account or token, use `npx`, add a project dependency, use `sudo`, or
install a similarly named package. Verify `command -v twin` and `twin help
--json` work outside this repository. If the global binary is not on my
persistent user `PATH`, fix that without overwriting unrelated configuration and
tell me to restart this agent.
Run `twin login` and let me complete browser sign-in. Never request SSH,
Tailscale, an API key, cookie, pasted token, tenant ID, or organisation ID.
Use the help result as the command contract. Run `twin status --json` and `twin
organisations --json`, tell me the current organisation, and if more than one is
available ask me which one to use. Switch with `twin organisations --use` and
confirm the result with `twin status --json`; do not run `twin login` again.
Then run `twin channels --json`.
Inspect the relevant channel before querying it. Inspect its saved views and use `--data --widget`
when one dashboard widget answers the question. Use `twin query --question` for a normal Twin
answer through the canonical router, and add `--stream` so you can report
queued, running, and terminal status while it works. Use `--intent` or `--intent-file` only
when you can state a typed records, aggregate, or saved-view query using
inspected Channel or View references, Data Set IDs, and field keys. Never submit raw SQL or guess internal product or
relation names. Add records or publish view updates only after I approve the
exact write; use `--allow-write` and never retry a rejected or conflicting
write by weakening its inputs.
Create or update Markdown and CSV artifacts with `twin artifacts` only after I
approve the complete file, title, and channel. Pass `--client-app` for this
agent and use the inspected artifact version for every update.
If I provide or confirm feedback, use `twin feedback` and attach the routed
query ID when relevant. Do not infer or submit feedback without asking me.Sign out
twin logoutThis removes the saved credential from the local credential store.