CLI

Command reference

Every Ghosty CLI command with examples (agents, channels, connectors, credentials, turns, sites, browser), global options and exit codes.

Updated 2026-11-05

Every command accepts --json and --help (ghosty skills --help and ghosty help skills show that command's usage and examples). <id> is an agent: its name (ghosty agents get pia-0, case-insensitive) or its id (shown by ghosty agents ls). If several share a name, the one in the ghosty use workspace wins; if there are still several, the CLI prints their ids to pick from.

Naming rule (like gh): noun then verb (ghosty cards show, ghosty boards create); turning something on or off is enable / disable (ghosty skills disable <id> pdf-doc); on / off only as an option's value (--sponsor on). The old forms (board, skills on|off, --on/--off, --vence) still work and say which one is new.

Session

CommandWhat it does
ghosty loginOpens the browser and signs you in (OAuth2).
ghosty login --deviceSign in from another device with a link + code (automatic over SSH or CI).
ghosty login --device --profile <client>Operate SOMEONE ELSE's account (a client): send them the link and code, they approve, and the session lands in that profile. Use it with --profile <client>; ghosty logout --profile <client> revokes it.
ghosty logoutSigns out and revokes the session on the server.
ghosty whoamiWhich email you are signed in as. With --json it also returns your account's plan.
ghosty usageYour plan and how much you've used this week and month (also ghosty me usage). See .
ghosty use <workspace>Default workspace: boards takes it without typing it, agents create is born there (--workspace none for a personal one) and agents ls shows only its agents (--all for all). ghosty use tells which; --clear removes it. Per profile (--profile).

Agents

bash
ghosty agents ls                                       # --json: engine, model and workspace on every rowghosty agents ls --engine ghosty-lite --ids            # only ids, to chain with xargsghosty agents ls --sponsor testers@ghosty.studio       # staff: agents of ANY account (also --owner EMAIL); operate them by idghosty agents set <id> --prompt-file persona.md --prompt-mode replace   # its prompt WITHOUT the house personaghosty agents create --name Moon --engine ghosty-lite --model gpt-5.6-luna --env GHOSTY_THINKING_EFFORT=maxghosty agents get <id>                         # full config (also: agents show <id>)ghosty agents get <id> --fields name,model,promptghosty agents get <id> --prompt-out PROMPT.md  # the prompt to a file (come back with set --prompt-file)ghosty agents create --name Pia --workspace sales --channels teams=off   # born in the workspace, owned by its ownerghosty agents create --name tania-mkt --like <pia-id> --dry-run          # with another agent's setup (not its prompt, env or channels)ghosty agents create --name tania-mkt --like <pia-id> --board new --no-notify   # its own board with the source's columns; shared without emailsghosty agents get <id> --fields toolsets,connectors   # what it really has: effective toolsets and connectorsghosty agents set <id> --prompt-file PROMPT.md # identity / instructionsghosty agents set <id> --name "Sales" --model claude-sonnet-5ghosty agents set <id> --engine claude --model claude-haiku-5-5 --env FLEET_EFFORT=highghosty agents set <id> --engine claude --dry-run      # what changing the engine does (sessions, machines, memory), without changing itghosty agents set <id> --connect google-drive          # gives it access to your Drive (--disconnect removes it)ghosty agents set <id> --channels wa=on,teams=off      # turn channels on/off (wa = personal WhatsApp)ghosty agents set <id> --unset-env EASYBITS_API_KEY,EASYBITS_BASE_URL   # delete env variables (also: --env K=)ghosty agents set <id> --prompt-base <base-id> --prompt-overlay overlay.json --dry-run   # prompt = another agent's + an overlay; regenerates by itselfghosty agents set <id> --prompt-base <base-id> --prompt-overlay mirror.json      # mirror.json = {"edits":[]}: one prompt and one memory; changes to the base replicateghosty agents set <id> --toolsets +crm                 # gs tool groups: a list replaces; +x / -x adds or removesghosty agents share <id> ana@company.com --role admin  # share without handing it over (editor or admin); agents shares <id> lists themghosty agents unshare <id> ana@company.comghosty agents teams ls <id>                    # Teams workspaces you administer: where it answers and with which @handleghosty agents teams on <id> lawyers --handle counsel   # turn it on there (without --handle, from its name); on an active one it changes the @handleghosty agents teams on <id> lawyers --factory plan,build,check   # make it @plan, @build and @check of that workspace's Software Factoryghosty agents teams off <id> lawyers           # pause it there: it stops answering and keeps its @handleghosty agents teams rm <id> lawyers --yes      # remove it from there and free the @handle; the agent staysghosty agents set <id> --voice elevenlabs:<voice-id> --voice-replies auto   # voice notes in channelsghosty agents set <id> --auto-stage on         # moves board cards by itself after each customer turnghosty agents set <id> --web-search on        # the engine's native web search (Claude, Gemini), apart from gs toolsghosty agents set <id> --chat-starters "What's pending?|Summarize my email"   # suggestions in ITS chat (app, Mac, /c): up to 5, ≤ 80 chars; "" removes themghosty agents set <id> --channel-roles teams=cliente,programado=equipo   # who talks on each channel: equipo (team: writes to databases, admin tools) or cliente (customer)ghosty agents set <id> --extensions developer=off   # its box's config.yaml extensions (Ghosty · Lite and Goose); merged with what's savedghosty agents set <id> --email-any on          # enviar_correo may write to any address from customer channels (off = only to whoever writes; owner only)ghosty agents set <id> --quote iva=0,prefix=SFI,vigencia=15   # house cotizar tool config (issuer, VAT, folio); empty clears it (rfc=)ghosty agents set <id> --quote plantilla=@quote.html,logo=https://…/logo.png,comercial="Ana Ruiz",numeros=es   # the PDF comes out in YOUR format (your own HTML template)ghosty agents set <id> --catalog products.csv   # its catalog (sku,nombre,precio,unidad,categoria); replaces the previous oneghosty agents set <id> --quote iva-incluido=true,iva.GRANEL=16,solo-factura=true   # prices include VAT except bulk, which adds 16% only with an invoiceghosty agents set <id> --tool cotizar=off      # turns a house tool off in every channel (per channel: wa:cotizar=off)ghosty agents doctor <id>                      # checks the config; exits 1 if it finds a problemghosty agents archive <id>                     # stops answering on every channel and leaves the lists; nothing is deleted. Deleted automatically after 7 daysghosty agents restore <id>                     # brings it back as it was: Teams with its @handle, WhatsApp, memory and conversationsghosty agents ls --archived                    # archived agents and the date they get deletedghosty agents rm <id>                          # deletes the agent, its machines, its bundle (skills) and its versions; usage and turns stay (billing). Owner or staff (logged); asks you to type its nameghosty agents rm <id> --from-workspace         # if it's active in Teams: turn it off there first, then delete it (owner or staff)ghosty agents set <id> --tool wa:actualizar_identidad=off   # one tool per channel (channel:tool) or everywhere (tool=off); =on only removes the vetoghosty agents set <id> --avatar ./face.png     # its face in Teams (or an https link); stored at img.ghosty.studioghosty agents set <id> --bag "MiniGhosty"      # which bag of its workspace it spends from (staff only; none = the workspace balance)ghosty agents set <id> --box 4096:10           # a 4 GB box that serves 10 conversations at once (staff only; recycles its boxes)ghosty engines ls --models                     # engines and models valid for --engine/--model, with their costghosty agents restart <id>                     # Ghosty · Lite and Goose only: loads new skillsghosty agents demo <id> --slug shifts && ghosty agents demo enable <id>     # public link to try it without an account (see below)ghosty agents box <id> --contains /opt/claude-worker/skills/pdf-doc/render-doc.mjs=pdf-templates   # is its machine on the new image?ghosty agents box <id> --recycle               # replace it (never mid-answer); the new one starts on the next turn (Ghosty · Lite and Goose too, with history from their last backup) (--reenv only re-bakes the env; --force even if busy)ghosty agents box <id> --start                 # start (or wake) its box now, without spending a turn; within your plan's boxesghosty agents box <id>                         # also shows its capacity: conversations per box, boxes on, turns now and what the plan allows

agents get shows the agent's env; values that look like secrets (…KEY, …TOKEN, …SECRET) come back as •••.

agents box shows which machines serve the agent and, with --check PATH (repeatable) or --contains PATH=TEXT, whether they have what you expect. Use it after an image change: on ✗, --recycle and check again after one turn. On Ghosty · Lite and Goose use agents restart.

create adds an agent to your account (no workspace) and returns its id. Without --engine it uses Claude; without --model, the engine's default. An engine or model that doesn't exist is rejected (also without --engine) and the error lists the valid ones; ghosty engines ls --models shows them beforehand.

--env K=V,K2=V2 sets variables on the agent's machine, in create or set; K= removes one. The most useful: GHOSTY_THINKING_EFFORT (off · low · medium · high · max) sets how much the model thinks on Ghosty · Lite.

Connecting Drive (or another connector) to your account gives no agent access: each one gets it with --connect <connector> or on its page → Connectors. Only the owner can grant it.

set changes only what you pass. Prompt and model apply from the next turn. --engine switches the engine; --model is then a model of the new engine. On Claude, effort is --env FLEET_EFFORT=low|medium|high|xhigh|max; without it, it runs at medium. Codex, DeepSeek, Goose and DeepAgents are deprecated: use Claude, Ghosty · Lite or Gemini.

--chat-starters are the suggestions in the agent's own chat (app, Mac, /c); the web widget's are a different list, set with agents embed --starters. --channel-roles only changes teams and programado (scheduled turns): chat is always the team, and WhatsApp Business, Messenger, the demo and the widget are always customers; personal WhatsApp sets the role per group (channels wa groups set --role).

Token, memory and handover

bash
ghosty agents token rotate <id>                # new gat_ token: printed ONCE on stdout (the old one stops working)ghosty agents token revoke <id>                # closes the editor channel; nothing gets in until you rotate a new oneghosty agents memory ls <id>                   # rules its team taught it, and its promos (live today, on, off)ghosty agents memory add <id> "Don't offer delivery on Sundays" --scope wa   # without --scope it applies on every channelghosty agents memory edit <id> <rule-id> "Free delivery over $999"ghosty agents memory add <id> --promo --title "Black Friday" --details "15% off everything" --from 2026-11-13 --until 2026-11-16ghosty agents memory disable <id> <promo-id>   # stops offering it and keeps it (enable turns it back on; rm deletes it)ghosty agents transfer <id> --to ana@company.com --dry-run   # hand it over with its box, memory and files: which workspace it lands in and what they'd be missingghosty agents transfer <id> --workspace sales --dry-run      # move it between your workspaces (none = your personal space)

token and transfer use your owner session, never the agent's gat_ token: a token can't rotate itself or give its agent away. On Claude Code, Ghosty · Lite and Goose (ACP engines), rotating or revoking restarts the relay and cuts the turn in flight; if the change can't reach the box, nothing changes. Rotating is the same as "Connect your editor" on the agent's page.

memory is the agent page → Memory: rules travel in every conversation of the agent, also with customers (your personal preferences go in me memories). A promo with dates is only offered on those days (Mexico City time).

transfer --to asks you to type the email: the agent stops being yours. It lands in the workspace you pass with --workspace (one of theirs); if they have one, that one, otherwise their personal space. The dry run warns if they lack the provider key. Moving between your workspaces checks the plan's limit, the model and the @handle first, and won't move a box with a turn in flight unless --force. It's logged (agent.transfer, agent.move, agent.token.rotate).

Public demo: agents demo

A /p/<name>-<code> link so anyone can try your agent without an account, exactly as you built it (its machine, its skills, its engine), paid by you. With "Keep it" the visitor creates an account and takes their own copy, with the trial conversation and files.

bash
ghosty agents demo <id>                                   # status: link, expiry, caps and numbersghosty agents demo <id> --slug shifts && ghosty agents demo enable <id>                # create the link and turn it onghosty agents demo <id> --expires "2026-10-15T20:00"        # stops accepting messages then (your machine's time)ghosty agents demo <id> --expires no                        # no expiryghosty agents demo <id> --welcome "Hi! Upload your shift spreadsheet" --starter "Show me how to start" --chips "What do you do?|How much is it?"ghosty agents demo <id> --turns 150 --per-ip 30           # abuse capsghosty agents demo <id> --sponsor on                      # the copy of whoever keeps it runs on YOUR keyghosty agents demo <id> --rotate                          # new code: the old link stops workingghosty agents demo disable <id>
OptionWhat it does
--slug NAMELink name. A 6-character code is appended so it can't be guessed.
enable · disableghosty agents demo enable <id> turns it on and disable off (--on/--off still work as aliases).
--expires "YYYY-MM-DDTHH:MM"Fixed date when it stops accepting messages, the same for everyone; in your machine's time. --expires no removes it. After it, visitors only see "Keep it".
--turns NMessages per visitor (default 150).
--per-ip NMessages per IP per day (default 30).
--welcome TEXTChat greeting. Empty = the default greeting.
--starter TEXTHighlighted suggestion, first and in color; tapping it gets a 3-step walkthrough. --starter "" removes it.
--chips "a|b|c"Suggestions, separated by | (they may contain commas and question marks).
--sponsor on|offWith on, the copy of whoever keeps it uses your engine key (that agent only) and doesn't count against their plan.
--rotateNew code if the link leaked; open conversations continue.

With no options it only shows the status. The output includes trials, messages and copies kept (how many on your key) and, if the agent failed to answer a visitor, the last reason.

Web widget: agents embed

A chat bubble with your agent on your site, with one line of code. It only loads on the domains you list; each visitor gets their own isolated conversation and talks as a customer. Details in .

bash
ghosty agents embed enable <id> --domains "mystore.com,*.mystore.io"   # turns it on and gives you the <script> to pasteghosty agents embed <id>                                   # state, domains, caps, the code and numbersghosty agents embed <id> --welcome "Hi! How can I help?" --color "#0e1317"ghosty agents embed <id> --per-visitor 30 --per-ip 60      # abuse capsghosty agents embed <id> --title "My store" --subtitle "Replies in minutes" --avatar https://mystore.com/logo.png --icon avatarghosty agents embed <id> --position left --offset 24,24 --theme auto --placeholder "Ask anything"ghosty agents embed <id> --bubble-text "Questions?" --auto-open 15 --starters "Prices?|Shipping?"   # your suggestions (up to 4)ghosty agents embed <id> --style '{"fontFamily":"Barlow","radius":0,"headerBg":"#2d4a2e"}'   # fine style; --style none resets itghosty agents embed <id> --theme-source teams                # your Teams workspace brand (--workspace SLUG)ghosty agents embed <id> --theme-source site --site-url https://mystore.com   # your site's colorsghosty agents embed <id> theme > theme.json                  # export the theme; --style-file theme.json applies itghosty agents embed <id> --copy '{"waking":"One moment, please","thinking":["Reviewing your question…"]}'   # what it says while it works; --copy none resetsghosty agents embed <id> --out src/components/GhostyChat.tsx   # your own React component (token and theme baked in; .jsx without types; --force overwrites)ghosty agents embed <id> --rotate                          # new token: the old code stops loadingghosty agents embed disable <id>
OptionWhat it does
enable · disableTurns it on or off everywhere, instantly. Turning it on needs the Claude engine and at least one domain.
--domains "a.com,*.b.com"Where it may load. a.com includes www.a.com; *.b.com, its subdomains. Replaces the list.
--per-visitor NMessages per visitor per day (default 30).
--per-ip NMessages per IP per day (default 60).
--welcome TEXTThe first message the visitor sees (empty = "¡Hola! ¿En qué te ayudo?").
--color "#rrggbb"Main color; the text on top is computed by contrast.
--title T · --subtitle THeader name (default: the agent's) and a line under it.
--avatar URL|noneYour https image (re-hosted on img.ghosty.studio); none = the agent's ghost.
--icon chat|avatar|ghostWhat the floating button shows.
--placeholder TGrey text in the message box.
--position right|left · --offset X[,Y]Corner and distance in px from the side and the bottom (0–200).
--theme light|dark|autoPanel theme (auto = the visitor's).
--bubble-text TLabel next to the button.
--auto-open S|offOpens by itself after S seconds (1–120), once per visit, never on phones.
--starters "a|b"Up to 4 of your suggestions; "" removes them. Ghosty's are never shown.
--style '{json}'|noneFine style without free CSS (typeface, corners, per-piece colors). Patch per key; see .
--font NAME · --radius 0-24Shortcuts for style.fontFamily and style.radius.
--theme-source custom|teams|siteImports the theme from your Teams brand (--workspace SLUG) or your site (--site-url); it stays editable.
--style-file FILEApplies a theme exported with agents embed <id> theme.
--copy '{json}'|noneThe phrases while the agent works (waking, connecting, thinking 1–8, stillWorking, cantStart, interrupted, retryLabel; plain text ≤ 80) and showDuration/showCopyButton. Patch per key (null = Ghosty's); see .
--copy-file FILEThe same copy object from a file.
themeghosty agents embed <id> theme prints the theme (and copy) as JSON.
--out FILE.tsx|.jsxWrites a complete, editable, dependency-free React component with your token and theme at the top. Won't overwrite an existing file without --force. See .
--rotateNew token if the code leaked or you want to cut it off everywhere.

The output also includes the React snippet (npm i @ghostystudio/widget + <GhostyWidget token="emb_…" />); in --json, under react ({install, code}).

Try a demo and see what happened: demos

bash
ghosty demos try guardias-k3x9q2 "remember MANZANA-47"                # as a visitor, no browser (same thread across runs; --new for another)ghosty demos try guardias-k3x9q2 "what word did I tell you?" --recycle-between --agent <id>   # switches boxes between messages: does it remember?ghosty demos history <id> --since 2d --timeline                       # what visitors did (Ghosty staff only)

demos try counts against the demo's caps (messages per visitor and per IP per day) and shows up in its numbers and CRM. demos history shows turns, messages, attachments, deliveries and clones; it is Ghosty staff only: the owner sees numbers (agents demo), not their visitors' chats.

The agent as a file

ghosty agents export writes an agent's whole setup to a YAML (compatible with recipes); ghosty apply makes an agent match the file, showing the plan first.

bash
ghosty agents export pia-0 --out ./pia          # agent.yaml + skills/<slug>/… (without --out: YAML to stdout)ghosty apply ./pia --dry-run                    # the plan: + adds, ~ changes, - removes, ! notesghosty apply ./pia                              # asks and applies (--yes without a terminal)ghosty apply ./pia --agent tania-mkt --dry-run  # the same file on another agentghosty apply ./pia --create --name sofi-mkt     # a new agent from the file
  • Anything the file doesn't mention is left alone; the fields it has become exactly what it says.
  • Lists (databases, documents, shares, own skills, env vars) add and change; removing needs --prune (without it they show with !).
  • Secrets never leave: they're exported as ${NAME}. With NAME in your environment it changes; otherwise today's value stays.
  • Before applying, the agent's current version is saved (Versions, in the web). apply doesn't move an agent between workspaces.

Configure an agent

Every agent has its own machine and disk: files, skills and MCP work with any engine. On pool engines (Claude, Codex, DeepSeek, Gemini) they enter by themselves on the next turn; on Ghosty · Lite and Goose new skills enter with agents restart (needsRestart in agents get).

Files

bash
# Up to 10 MB eachghosty files ls <id>ghosty files put <id> prices.md --file ./prices.mdcat notes.txt | ghosty files put <id> notes.txtghosty files get <id> prices.md --out ./copy.mdghosty files rm <id> prices.mdghosty files ls <id> adjuntos --session <conversation>   # pool agent: THAT conversation's folder in its boxghosty files rm <id> adjuntos/ab12cd34/cookies.txt --session <conversation>

files is the agent's disk; the files in your account (what you uploaded and what agents delivered) are ghosty me files. --session never wakes a paused box: if it is, you get paused.

Derived prompt

An agent can inherit another agent's prompt plus an overlay of edits: a store's branch using the head office's prompt with its own name, hours and catalog. When the base changes, the derived prompt regenerates by itself.

json
{ "edits": [  { "what": "name", "find": "Tania", "replace": "Pia", "all": true },  { "what": "branch", "find": "## Minimum order\n", "replace": "## Ixmiquilpan branch\n…\n\n## Minimum order\n" },  { "what": "scope", "find": "\\*\\*What I handle:\\*\\*[^\\n]*", "regex": true, "replace": "**What I handle:** both brands." }] }
  • Edits run in order and each must find its place. If the base changed right there, the derived agent keeps its previous prompt and agents doctor flags it (prompt.base).
  • --dry-run tells whether every edit applies (--out FILE writes the result). --prompt-base none unlinks and keeps today's prompt.
  • While linked, its prompt can't be edited directly (409): change the base or the overlay.

Patch the prompt

To change one piece of the prompt without rewriting all of it (and without overwriting what someone else changed in between), with the same overlay format:

bash
ghosty agents set <id> --prompt-patch hours.json --dry-run   # the diff: which lines changeghosty agents set <id> --prompt-patch hours.jsonghosty agents set <id> --prompt-append october-notice.md     # add that text at the end
  • It applies on the server, on the prompt as it is at that moment: no need to download it with get --prompt-out and upload it again.
  • If an edit doesn't find its place, nothing changes (409 saying which one). --prompt-patch and --prompt-append together: edits first, then the text.
  • It's logged (agent.prompt_patch). It doesn't apply to a derived prompt: change the base or the overlay there.

Skills

bash
# From the catalog by name, or your own with --fileghosty skills ls <id>ghosty skills disable <id> pdf-doc                 # turn one off (its own or Ghosty's); enable turns it back onghosty skills house <id> --only pdf-doc,office-reader --dry-run   # Ghosty's skills in bulk (--enable / --disable)ghosty skills add <id> grill-meghosty skills add <id> my-skill --file ./SKILL.mdghosty skills get <id> my-skill                    # list its filesghosty skills get <id> my-skill --out ./my-skill   # download the whole folder (prints the absolute path)ghosty skills templates <id>                       # pdf-doc templates: its own and Ghosty'sghosty skills add <id> my-skill --dir ./my-skill   # upload a folder (SKILL.md + assets)ghosty skills rm <id> my-skill                     # keeps a local copy and prints the undo commandghosty agents restart <id>                         # Ghosty · Lite and Goose only

skills rm saves the copy under ~/.config/ghosty/trash/ and prints the command that restores it.

skills templates reads a live machine (run one turn first) and lists what pdf-doc sees: agente:<skill> or casa. An agent's own template is <skill>/pdf-templates/<name>.html in any of its skills; with the same name it wins over the house one.

MCP servers

bash
# `set` REPLACES the whole listghosty mcp get <id> > servers.jsonghosty mcp set <id> --file servers.json
# One remote server by its URL (the agent page's «Your system»)ghosty mcp connect <id> --name notion --url https://mcp.notion.com/mcp     # if it asks for OAuth, opens the sign-in (--no-open prints the link)ghosty mcp connect <id> --name crm --url https://crm.example.com/mcp --from-env CRM_TOKEN   # with a token: goes as Authorization: Bearer

connect adds one server without rewriting the list (it replaces one with the same name). Without --from-env, gs tries the server: if it answers it's added as is; if it asks for OAuth you authorize it in the browser and gs adds it and refreshes its token. The token is the NAME of an environment variable, never the value as an argument.

One key per end user: in an http MCP, a header may carry ${turn.token} ("Authorization": "Bearer ${turn.token}"). Each message-stream or turns call sends its turnToken and gs applies it to that turn only, through its proxy: the token never enters the box and is never stored. A turn without turnToken on that agent fails with an error. Not allowed in sse, stdio, the URL, or ACP agents.

Quoting with the house tool: VAT and catalog

The cotizar tool does the math, the folio and the PDF; the agent only sends the lines. Each line's VAT comes from the agent's config, in this order:

  1. If the call sends iva_pct, that one for everything.
  2. With solo-factura=true and no factura: true on the quote: 0.
  3. If the line's category has a rule (iva.GRANEL=16): that one.
  4. With iva-incluido=true (prices already include it): 0.
  5. Otherwise: iva (16 by default).

The category comes from the agent's catalog (--catalog), not from the model; the one the agent sends only counts when the product is not in the catalog. When lines carry different rates, the PDF breaks it down ("IVA (GRANEL 16%)"). An agent with its own cotizar skill doesn't use this tool: saving that skill turns it off.

Your own template. With --quote plantilla=@quote.html the PDF is rendered from your HTML (one sheet, your logo and layout) instead of Ghosty's format; plantilla= goes back to Ghosty's. Variables: {{logo}}, {{empresa}}, {{rfc}}, {{direccion}}, {{telefono}}, {{correo}}, {{comercial}}, {{folio}}, {{fecha}}, {{vigencia}}, {{cliente}}, {{cliente_domicilio}}, {{cliente_rfc}}, {{subtotal}}, {{descuento}}, {{base}}, {{iva_pct}}, {{iva}}, {{total}}, {{moneda}}, {{notas}}; per line, inside {{#items}}…{{/items}}: {{sku}}, {{concepto}}, {{cantidad}}, {{unidad}}, {{precio}}, {{iva_pct}}, {{importe}}. {{#variable}}…{{/variable}} renders the block only when there is a value. Amounts come without a currency symbol; numeros=es writes them as 1.234,56.

Check an agent: agents doctor

Like brew doctor: it only prints what needs attention, each finding with the command that fixes it, and exits 1 when there is a problem (usable as a gate in a script). --verbose also lists what passed.

Above the checks it prints the agent's card: engine and model, effort (FLEET_EFFORT, or the model's default), whether it has native subagents, whether it answers /c without an account (ANON_NATIVE_AGENT_ID) and, for Ghosty staff only, its box size (MB and conversations per box). In --json it is the info field.

It checks: skills that could fire on the same request (two quoting skills on at once), skills the prompt names (skill \cotizar`, .claude/skills/cotizar/) that the agent lacks or has off, an own skill named like a house tool that is still on (the model may use the generic one), tools the prompt names that don't exist or have no permission, customer-write tables that no longer exist, db_/doc_` in the prompt with nothing granted, and turns that failed in the last 24 h.

Databases

bash
ghosty dbs ls <id>                                   # the account's databases and what this agent hasghosty dbs tables <id> <db>                          # tables, rows and columnsghosty dbs query <id> <db> "SELECT count(*) FROM products"ghosty dbs query <id> <db> "SELECT * FROM products WHERE sku = ?" --arg ABC-12ghosty dbs query <id> <db> "UPDATE folio SET n = n + 1" --writeghosty dbs checkpoints <id> <db>                     # restore points: one is taken before each agent writeghosty dbs restore <id> <db> <checkpoint>            # rolls the database back to that point (takes another first, so it can be undone)ghosty dbs export <id> <db>                          # the whole database: <db>.sqlite (sqlite3, DB Browser for SQLite, DBeaver)ghosty dbs export <id> <db> --table products         # one table as CSV (opens in Excel): <db>-products.csvghosty dbs grant <id> <db> --external-write quotes,folio   # what it may write from WhatsApp/Messengerghosty dbs grant <id> <db> --external-rows customers:phone+phone2   # from WhatsApp/Messenger each customer sees only THEIR rows ("" = no filter)ghosty dbs revoke <id> <db>ghosty dbs rename <id> totequim siiqtec --dry-run    # also rewrites the prompts, env and SKILL.md that name itghosty dbs ls <id> --orphans                         # databases no agent has grantedghosty dbs rm <id> <db> --dry-run                    # deletes the whole database (revoke only removes access); owner or staffghosty dbs import <id> <db> --from easybits:<db-id> --dry-run   # copy tables from EasyBits ($EASYBITS_API_KEY)ghosty dbs import <id> <db> --from easybits:<db-id> --tables products,prices --append
  • query is read only; --write allows INSERT/UPDATE/DELETE/DDL. --arg V gives the value of each ?, in order (repeatable).
  • export downloads a copy: without --table, the whole database as SQLite (every table with its rows); with --table, that table as UTF-8 CSV. --out says where to save it. It uses your session, not the agent's gat_ token, and is recorded in the audit log. The same downloads are on each database's page (/app/datos?tab=dbs → the database → .sqlite / table.csv).
  • import replaces each table's rows (idempotent); --append adds them instead and --tables a,b copies only those. --dry-run prints the plan (+ create, ~ replace N → M rows) and changes nothing. If the database is shared with agents already writing in gs (quotes, folios), it warns about the rows that exist only in gs and asks before deleting them.
  • db is an alias of dbs, and dbs sql of dbs query.

Catalog photos

A catalog's photos should live at permanent links (img.ghosty.studio): links from EasyBits or the customer's website expire or change, and WhatsApp stops sending them.

bash
ghosty dbs tables <id> <db>                                                # per photo column: permanent · external · emptyghosty dbs rehost <id> <db> --table catalogo --column imagen_url           # copies external ones to permanent links (idempotent)ghosty dbs import <id> <db> --from easybits:<db-id> --rehost-images catalogo.imagen_urlghosty dbs photos put <id> <db> --table catalogo --key-column sku --dir photos/ --dry-run   # loose photos: SKU-123.jpg → the row with sku = SKU-123
  • import warns when replacing a table would turn permanent links back into external ones, and gives you the exact flag.
  • photos put only takes JPEG, PNG or WebP up to 10 MB; --dry-run lists keys with no row and files that aren't images. The column is imagen_url unless --column.
  • On the web (/app/dbs, Tables tab) you get the same counts, a «Hacer permanentes» button, and you can drag a photo onto a row.

Documents

bash
ghosty agents docs ls <id>                           # documents it reads and may sendghosty agents docs grant <id> "Catalog 2026.pdf"     # --write: it may replace it · --no-deliver: never sends itghosty agents docs grant <id> "Catalog.pdf" "Prices.xlsx"     # several at once; --like <other> copies another agent'sghosty agents docs revoke <id> "Catalog 2026.pdf"ghosty agents docs add <id> --url https://example.com/prices.pdf --description "2026 prices"   # upload and grant (--file for a local one)ghosty agents docs replace <id> "Catalog.pdf" --file catalog-oct.pdf --note "October prices"   # new versionghosty agents docs history <id> "Catalog.pdf"        # versions: who, when and from where; and which agents use itghosty agents docs restore <id> "Catalog.pdf" 3      # back to v3 as a new version

<db> and the document accept the id or the name. An agent token (gat_…) only sees what was granted and cannot grant itself anything.

A document is one document even when several agents use it: replace uploads a new version that keeps the name (only the extension follows the type), the access and every agent that uses it, so a prompt that names it doesn't break. The previous version stays in the history (20 are kept). With an agent token, replace and restore only work if the agent has «Can update it» (grant --write).

Turns

bash
ghosty turns ls <id> --errors --since 1h             # failed turns and whyghosty turns ls <id> --status running                # running · done · stopped · errorghosty turns ls <id> --skipped --since 1d            # WhatsApp Business messages that did NOT open a turn, and why (operator active, records only, paused…)ghosty turns ls <id> --session web:…                 # one conversation; on Claude the «resumed» column says whether it resumed (✓) or started from scratch (⚠ orphan|stale|replaced)ghosty turns ls --workspace descti --quota-hits      # a WHOLE workspace's messages (WhatsApp Business and Teams) that got no turn because the balance ran outghosty turns ls <id> --canal anon --since 1d          # only one channel: chat · teams · whatsapp · wa · messenger · programado · prueba · demo · embed · anon (/c without an account); every row says its canalghosty turns ls <id> --json --limit 100ghosty turns show <id>                               # last turn: what came in, what it answered, each tool with its secondsghosty turns show <id> --full                        # the whole message and answerghosty turns cancel <id> <conversation>              # stop: the running turn AND its background jobs (video, subagents, wake-ups)ghosty turns jobs <id>                               # what it has in the background from your chats (video, audio, captions, downloads; 24 h) and whether it was deliveredghosty turns show <id> <turn-id>                     # a specific one (the id is in turns ls)ghosty turns grep <id> "IVA" --since 7d --role agent # what the agent said (or --role user, the customer) and in which turn

turns grep searches the conversation text (not steps or tools) and returns each match with its turn, to open with turns show. In the «resumed» column, «1st turn» is the first turn of a new SDK session: not a memory loss.

turns jobs is read-only (GET /api/v2/me/agents/:id/tasks): the background jobs from your personal chats in the last 24 h. Stop them with turns cancel; something that repeats on a clock isn't a job but a scheduled turn (schedule add --every).

--errors is the same as --status error. --since takes 30m, 1h, 2d or an ISO date; --limit defaults to 20 (max 500).

turns show first prints what came in (in) and what it answered (out), on any engine and channel (WhatsApp groups included). Then it answers "where did 4 minutes go?": the turn's timeline (+12.3s Bash office-reader … 8.1 s), the slowest tools and the total model calls and output tokens. That part reads the engine's transcript, so it only exists on pool engines (Claude, Codex, DeepSeek, Gemini), not on Ghosty · Lite or Goose.

WhatsApp channels

bash
ghosty channels whatsapp ls <id>                     # WhatsApp Business numbers and who answers themghosty channels whatsapp enable <id> 5512345678 --dry-runghosty channels whatsapp disable <id> 5512345678ghosty channels whatsapp connect <id>               # starts or resumes connecting a number and gives a link for any screenghosty channels messenger connect <id>              # opens Channels to connect a page with Meta

whatsapp connect needs no balance and does not turn the agent on. The link works for 1 hour on any screen, in case your phone doesn't finish the Meta sign-in. Run it again and it resumes the same connection and tells you whether it finished (--no-open or --json only print the URL). messenger connect opens the Channels page, because that Meta sign-in can't be done from the terminal.

Enabling a number makes the agent answer real customers: it asks you to type the number's last 4 digits (or --yes). A number has one agent: enabling it takes it from the other.

Groups belong to the agent's paired personal WhatsApp (not WhatsApp Business): which ones it answers, and as whom. equipo = the team (writes to databases, admin tools); cliente = like any customer.

bash
ghosty channels wa groups ls <id>                                   # name, on/off, role, jid (--cached: don't ask WhatsApp)ghosty channels wa groups enable <id> "Pia-cotizadora" --role equipo --dry-runghosty channels wa groups set <id> 120363…@g.us --name "SoFi team"   # the name gs shows (WhatsApp's doesn't change)ghosty channels wa groups disable <id> "Pia-cotizadora"ghosty channels wa groups set <id> "Sales team" --wake mention      # only answers when mentioned or replied toghosty channels wa groups create <id> "Sales team" --role equipo     # creates the group and prints the invite link

<group> is its name or its jid. Turning a group on asks first (or --yes): the agent starts answering there.

--wake: mention (the default when you turn a group on) only opens a turn when someone @-mentions the agent, writes its name or replies to one of its messages; everything else reaches it as context on its next turn. name only wakes when the text writes its name or an alias (an @ or a reply doesn't count). all answers every message (imported groups and groups made with create). --alias "tilin,ghos": other names that wake it in that group besides its own, like the nickname people use there (replaces the list; --alias "" clears it).

Who was answering this number?

If a number or a page was left without an agent, the «last answered by» column tells which agent answered it last and when (from gs's turns), so you can give it back:

bash
ghosty channels whatsapp integrations <id>            # + «last answered by» per numberghosty channels whatsapp integrations <id> --orphans  # only those nobody answers today that did have turnsghosty channels messenger ls <id> [--orphans]         # the same for the workspace's Messenger pagesghosty channels messenger status <id>                 # each page: who answers, last webhook and whether the token is alive (asks Meta)ghosty channels messenger on|off <id> <page> [--take] [--dry-run] [--yes]   # this agent answers it, or stops (off keeps logging)ghosty channels whatsapp enable <agent> 5512345678 --dry-run   # give it back

Microsoft Teams

The agent as a bot in a company's Microsoft Teams, with an Azure Bot registered in THEIR tenant (no app store). Step by step in .

bash
ghosty channels mteams connect <id> --app-id <guid> --tenant <guid> [--name "Sofi"]   # secret: --secret or GHOSTY_MTEAMS_SECRETghosty channels mteams ls <id>                       # bots, messaging endpoint, last message and last problem (token rejected, send failed, app uninstalled)ghosty channels mteams zip <id> <bot> --out sofi-teams.zip   # the package the admin uploads in Teamsghosty channels mteams off|on|rm <id> <bot>

Bring a number from somewhere else

To migrate an agent from EasyBits (or a droplet) without signing the number up again:

bash
# WhatsApp Business: the number already lives in Formmy; point it at this agentghosty channels whatsapp integrations <id>                                            # the owner's numbers in Formmy (and those already linked in gs): number, who answers today, id; staff: --email other-accountghosty channels whatsapp link <id> --integration <formmy-id> --answer off --dry-run   # the plan: what changes in gs and in Formmyghosty channels whatsapp link <id> --integration <formmy-id> --answer on              # from now on it answers real customersghosty channels whatsapp history <id> --integration <formmy-id> --days 7 --dry-run    # recent cards, messages, orders and files from Formmy to the board (the dry run works before linking; importing counts the ones that arrive paused and retries by itself during a deploy)ghosty channels whatsapp history <id> --integration <id> --days 7 --dry-run --list      # WHICH ones: phone, name, first message, whether from an adghosty channels whatsapp history <id> --integration <id> --only-ads --column "New"     # import only those from an ad (or --phones a,b) into that columnghosty channels whatsapp link <id> --integration <id> --answer off --forward --ads-only on   # only conversations from an ad open a cardghosty channels whatsapp contacts <id> --integration <id> --mute 5512345678   # the agent never answers that numberghosty channels whatsapp contacts <id> --integration <id> --allow 5512345678  # always answers it, even if it's a known contact (--unmute puts it back on the general rule)ghosty channels whatsapp contacts <id> --integration <id> --signature 👾        # its messages start with "👾: "; off = unsignedghosty channels whatsapp contacts <id> --integration <id> --list --q mom       # the phone contacts with each contact's ruleghosty channels whatsapp link <id> --integration <id> --new-only on   # the agent answers only new contacts; earlier ones stay with youghosty channels whatsapp link <id> --integration <id> --board Sales   # one agent, several numbers: each number fills its own board (agent = the agent's)ghosty channels whatsapp link <id> --integration <id> --answer on --partner-tenant org_123 --partner-agent nik-public   # a number of one of your partner's businesses: that agent answers it (see Partners)ghosty channels whatsapp history <id> --integration <formmy-id> --days 7 --media      # only re-copy the missing filesghosty channels whatsapp unlink <id> --integration <formmy-id>                        # back to where it was
# Personal WhatsApp: the Baileys session exported from EasyBits, no QRghosty channels wa import <id> --from easybits:<agent-id> --own-number no --dry-run   # straight from EasyBits ($EASYBITS_API_KEY): first says whether the origin session is alive, keys and groupsghosty channels wa import <id> --from-file session.json --own-number no --dry-runghosty channels wa import <id> --from-file session.json --own-number noghosty channels wa import <id> --from-dir store/auth --own-number no --dry-run   # Baileys multi-file folder (nanoclaw)ghosty channels wa status <id>ghosty channels wa pause <id>                    # the way back on this side (keeps the session)ghosty channels wa pair <id> --phone 5215512345678   # pair a new number by code, no QR (in Mexico 52… and 521… are different accounts: it tells you which to try)
  • --answer has no default: on answers real customers; off only records. Formmy only forwards when its channel is on: on turns it on; with off, only if you add --forward (the plan warns when gs won't see the conversations).
  • The owner, an admin of the agent or Ghosty staff can do it. If the number's owner in Formmy has a different email, only staff.
  • history goes after link and never duplicates: run it before the cutover and again right at it. It fires no "new lead" alerts.
  • history also copies the files (photos, PDFs, audio) to gs, and the summary says how many were copied and how many failed. Formmy deletes them after 7 days: bring the number within that week. Failed ones are retried with --media, which touches no cards or messages; with --dry-run it says how many are missing.
  • import: first turn off WhatsApp in EasyBits without logging out (two connections with the same keys knock each other off; logging out invalidates them). --own-number no = it's a person's number: only their chat with themselves counts as the owner's. Delete the file afterwards: it holds the account's keys.

Board

bash
ghosty boards ls siiqtec                                 # the workspace's boards, with agents and cardsghosty boards create siiqtec "Siiqtec - Ixmiquilpan" --columns-from mainghosty boards assign <id> "Siiqtec - Ixmiquilpan"        # where its NEW cards goghosty boards move-cards siiqtec --from main --to "Siiqtec - Ixmiquilpan" --integration <formmy-id> --dry-run   # and the existing onesghosty boards rm siiqtec "Test"                          # only an empty one that is not the main boardghosty boards access siiqtec "Siiqtec - Ixmiquilpan"       # who sees it: the whole workspace or «only these people»ghosty boards access siiqtec main --add ana@x.com --until 14d   # add her to the list; removed automatically after 14 days (--remove takes her off, --everyone opens it to all)ghosty boards followups siiqtec main template      # submit the follow-up template to Meta (utility)ghosty boards followups siiqtec main on            # every quote gets touches at 2, 7 and 14 days; they stop on reply or paymentghosty cards ls <id> --q 7712                            # recent cards (folio, name, phone, column)ghosty cards ls <id> --paused --limit 200               # the ones the agent doesn't answer: paused (e.g. brought by history from Formmy) or manualghosty cards show <id> "#12"                             # the thread: who wrote, text, attachment and whether gs kept a copyghosty cards archive <id> --integration test --dry-run   # archive cards in bulk (reversible)ghosty cards archive <id> --column Lost --before 30d --yesghosty cards pause <id> "#12" --mode 2h                  # pause the agent in that conversation (30min | 2h | 24h | until_tomorrow | permanent)ghosty cards resume <id> "#12"                           # resume it; also lifts "operator only" (escalated)ghosty cards reply <id> "#12" --directive "offer delivery"   # "Ask for a reply": answers what the customer left pendingghosty cards pending <id> --since 2026-10-06T02:13Z      # the ones waiting for an answer, and why some can't be answeredghosty cards pending <id> --since 12h --reply --dry-run  # what it would answer; without --dry-run it answers them one by one (asks, or --yes)

resume doesn't answer by itself (the wake-up Formmy sends on resume is ignored); reply does, only on WhatsApp Business and only if that agent answers the number. pending flags and never answers: paused, escalated, outside WhatsApp's 24 h window (Meta only takes templates), only a reaction, not WhatsApp Business, and numbers answered by nobody. pause, resume and reply are logged.

The board belongs to the workspace: an agent shared with you doesn't give you its board; the owner has to add you to the workspace. At least one filter is required (--integration, --column or --before).

Credentials

bash
ghosty credentials ls                                # provider keys in your vault (last 4 only)ghosty credentials set elevenlabs                    # hidden prompt; or --from-env VAR, or through stdinghosty credentials rm elevenlabs

A key is never accepted as an argument: it would stay in your shell history. creds is an alias of credentials.

Connectors

bash
ghosty connectors ls --q shop                        # your connectors: connected / available / soonghosty connectors connect shopify                    # OAuth: opens the browser (--no-open only prints the URL)ghosty connectors connect stripe --from-env STRIPE_SECRET_KEY   # key-based: verified before it's savedghosty connectors disconnect shopify                 # revokes it at the provider and removes it from your accountghosty agents set <agent> --connect shopify          # then give it to an agent

The same as /app/connectors and the app. Key connectors with several fields (Odoo, WooCommerce…) are asked one by one; secrets without echo and never as an argument.

Confirmations

agents rm, files rm, skills rm, credentials rm, board archive, replacing rows with dbs import and channels whatsapp enable ask before acting. Without a terminal (a coding agent, CI) they never wait for an answer: add --yes, or they exit 2 with the exact command to retry.

Talk to an agent

Test turns

bash
# One test turn: waits for the full answer (up to 3 min)ghosty try <id> "what are your opening hours?"ghosty try <id> "turn it into a PDF" --media photo.jpg                # with attachments, as from the app (repeatable, up to 8)ghosty try <id> "hi" --waba --session 5210000000009               # the real WhatsApp path; prints what it WOULD send (the test card is archived afterwards; --keep leaves it)ghosty try <id> "quote this" --waba --session 5210000000009 --media list.jpgghosty try <id> "" --waba --session 5210000000009 --media note.ogg --as-formmy   # the attachment arrives as Formmy sends it (proxy with credential)ghosty try <id> "and shipping?" --waba --session 5210000000009 --history thread.json --resetghosty try <id> --replay sample.json --out ./replay --max 5     # real conversations; report on your diskghosty try <id> --replay sample.json --out ./replay --concurrency 4   # conversations at once (default 8, max 30)ghosty try <id> --reset                  # forget the test session

--waba goes through the same path as a real WhatsApp Business customer (inherited context, price rule, board, voice) and sends nothing: no message, no voice note, no payment link. It lists everything that would have gone out, including what tools send: 📍 location, 📄 files, 🎤 voice, ↩️ quotes, 🔘 buttons, 👤 contacts and reactions. With --as-formmy the attachment goes the way a real one does: proxy with credential, copy to gs and transcription; it says at the end whether the copy arrived. --replay runs from your machine and writes replay.json after every step; if Ghosty deploys mid-run it waits the Retry-After and continues, and --resume picks up an interrupted run.

Conversations

bash
ghosty chat <id> "summarize the last email"ghosty chat <id> "what does this contract say?" --media contract.pdfghosty chat <id>                         # interactive; Ctrl-C cancels the turn, Ctrl-D exitsghosty chat <id> "go on" --conversation <conversation-id>ghosty conversations ls <id>ghosty conversations show <id> <conversation> [--limit 20]   # what was said (0 = all)ghosty conversations continue <id> <conversation>    # a new linked conversation: the agent gets the end of this one on its first turnghosty conversations model <id> <conversation> gpt-5.6-luna   # that conversation's model, from the next turn (Ghosty · Lite and Goose)ghosty conversations permission <id> <conversation>  # what the turn is waiting for (id, title, options)ghosty conversations permission <id> <conversation> allow [--always] [--id PERMISSION]   # or deny, or an option idghosty conversations share <id> <conversation>       # read-only link without an account: /s/… (--off stops sharing)ghosty conversations subagents <id> <conversation>   # its native subagents: state, tokens, tools, minutesghosty conversations subagents <id> <conversation> stop <task-id>   # stops that one; the turn and the rest go on

When a Ghosty · Lite or Goose turn asks for permission (send an email, run a command) it stops until someone answers. chat prints the request with the command to answer it (--json: a permission line with id and options); only whoever started the turn can answer, from any terminal, the app or the web. A shared link is a window, not a snapshot: it also shows what's said later, and --off closes it.

try is for testing configuration; chat uses the agent's real conversations, the same ones you see in the dashboard and the app.

Schedule turns

The agent works on its own at the time you set: each run lands in a conversation and notifies your phone (iOS or Mac app). If its answer is exactly OK, it stays silent; use that for "check and tell me only if…".

bash
ghosty schedule add <id> "Check the campaign and summarize it" --at 2026-10-01T09:00-06:00 --every 12h --until 2026-10-25 --title "Campaign"ghosty schedule add <id> "Remind me to call Ana" --in 30mghosty schedule add <id> "Keep going with the report" --in 2h --conversation <conversation-id>ghosty schedule ls <id>                  # pending turns and recent runsghosty schedule rm <id> <schedule-id>

Without --conversation a new conversation is opened (named after --title if given). Rules: repeat every 15 minutes at least, --until is required when repeating, at most 30 days ahead, and up to 5 pending per conversation.

In a channel conversation (--conversation waba:…, wa:<jid> for personal WhatsApp —a group or a chat— or messenger:…) the answer goes out through that channel; an «OK» answer is not sent. On WABA only within the 24 h window; on personal WhatsApp, if the agent's number is connected.

In a Teams thread

bash
ghosty schedule add minighosty "Introduce yourself to the team" --teams descti#general/4812 --at 2026-10-01T09:00ghosty schedule ls minighosty --teams desctighosty schedule rm minighosty <id> --teams descti

At that time the agent answers in the room (or in the thread: the number is the id of the message that starts it) as if someone mentioned it, with that room's memory. It must be active in the workspace's Teams and you must be a member. Without a thread it posts in the room. --every doesn't work with --teams yet.

Watch pages

Give the agent the pages you check every day (competitor prices, a call for proposals, the status of a filing) and hear from it only when they change. The platform fetches the page every N hours without a model turn, so checking spends no balance; on a change, the agent gets a turn in that conversation with what changed and tells you through its channel. If, per your --instruction, the change doesn't matter, it answers OK and stays silent.

bash
ghosty watch add <id> https://competitor.com/pricing --every 12h --focus "Plans" --instruction "tell me if Pro gets cheaper" --title "Competitor"ghosty watch ls <id>                          # state, last change and conversationghosty watch check <id> <watch-id> --dry-run  # fetch and compare now; saves nothing, notifies nobodyghosty watch check <id> <watch-id>            # check it in the next sweepghosty watch rm <id> <watch-id>ghosty watch resume <id> <watch-id>           # resume a paused one or renew an expired one

Dates, times, "5 minutes ago", scripts, images and link URLs are ignored when comparing. --focus compares only one part: the text of a heading (until the next one of its level) or of a line. Rules: every 1 h minimum and 7 days maximum (default 24 h), expires after 90 days (--days, up to 365), 10 per agent and per account by plan (Free 2, Pro 10, Power 25, Max 50, team space 25). After 5 failed reads in a row it pauses and pushes you once.

No --conversation opens a new conversation; with --conversation wa:<jid> or waba:… the notice goes out through that channel, like a scheduled turn. The agent can do the same on its own with its watch_add, watch_list and watch_remove tools.

Morning brief

Every morning, at your time (7:30 by default, every day), a short summary lands in your latest personal chat with your main agent: what's in progress and what needs you, in 5 lines, with a voice note on top and a push. It comes on; it only arrives when there's something to tell.

bash
ghosty brief                                   # on/off, voice, time, days and the last one sentghosty brief off                               # turn it off (on turns it on)ghosty brief --at 8:15 --days 1-5              # at 8:15, Monday to Fridayghosty brief --voice off                       # no voice noteghosty brief pause 7                           # skip it for 7 days; it comes back on its own (or a date: 2026-11-20)ghosty brief resume                            # remove the pauseghosty brief run --dry-run                     # build today's and print it (with the audio link); sends nothingghosty brief run                               # send it to your chat now

--days takes all, weekdays, weekend or numbers 0 (Sunday) to 6 with commas and ranges (1-5, 0,6). The message footer («Useful? · Stop sending it») works with one tap, and you can also ask your agent to turn it on or off or pause it. A pause lasts 1 to 90 days, ends on its own on the set day, and turning the brief on or off clears it; ghosty brief run sends it even while paused. API: GET/PUT /api/v2/me/digest (pauseDays, or pausedUntil with a date or null).

Teams

Write in a room or thread as yourself, like in the composer: any @agent you mention answers (same multi-@ filter, thread auto-follow and relay cap). Without a thread it opens a new one, like the «Pedir» button.

bash
ghosty teams post business#mailmask "@plan make Deploy wait for ci with needs"ghosty teams post business#mailmask/5612 "@plan how is it going?" --wait

--wait waits until every mentioned agent finishes and prints their answers (--timeout in seconds, 600 by default; exits 1 when it runs out). You must be a member of the workspace's Teams, with your session: an agent token (gat_) can't write. Up to 30 messages per hour per person, and each one is in ghosty audit ls --action teams.post.

Your account

bash
ghosty me files ls --kind documentghosty me files ls --q contract                    # search by name (library + your threads), --cursor for the next pageghosty me files get <file-id> --out contract.pdf   # download it (no --out: the signed link)ghosty me files export --dry-run                   # how many files and MB there are, per folderghosty me files export --out backup/               # download ALL: documents/, conversations/, library/ (rerunning only brings what's new)ghosty chat <id> "summarize it" --file <file-id>   # attach from your files, no re-uploadghosty agents docs dedupe --dry-run                # documents with the same content: one stays with everyone's accessghosty me files upload ./contract.pdfghosty me files rm <file-id>[,<file-id>…]         # asks first; without a terminal it needs --yesghosty me files rm --q cookies --dry-run          # what it would delete, deleting nothingghosty me memories ls                              # what your agents remember about youghosty me memories add "I prefer short answers"   # app-wide: they apply to all your agentsghosty me memories edit <id> "new text"ghosty me memories rm <id>ghosty me docs ls                                  # editable docs your agents delivered (the ones you edit in /c)ghosty me docs get <doc>                           # title and versions (<doc> = id or the /app/docs/<id> link the agent gives)ghosty me docs export <doc> --format md > proposal.md   # without --out it prints; PDF (default) goes to a fileghosty me docs check <doc> --language en-US        # spelling and grammar per block (es, en-US, pt-BR, fr)ghosty me docs tts <doc> --block 0 --segment 1 --out sentence.wav   # one sentence (or the whole block) read aloudghosty me docs restore <doc> 2                     # version 2 back as a new version (--rev N in get/export/check/tts)ghosty docs                              # opens these docs

me docs are the editable docs an agent delivers in a thread (you open them in /c and the link reads /app/docs/<id>). Not the ones in agents docs (account files an agent reads) nor ghosty docs (opens these docs).

Usage

bash
ghosty usage                             # or: ghosty me usage# Plan Pro#   This week    42% used  resets 2026-10-05#   This month   18% used  resets 2026-11-01#   Top-ups     available
bash
ghosty usage --workspace descti --by agent,day --days 14   # turns, failed, tokens and «no balance» per agent and day (CDMX); owner or staffghosty usage --agent <id> --by model,day --cost   # one agent: tokens and USD at the provider's list price per model/day/canal (what it would cost on the API)ghosty usage --agent <id> --by visitor            # /c without an account: per visitor USD, messages, page/PDF and whether they created an account; USD per visitor and per new accountghosty usage --boxes --workspace siiqtec    # a workspace's boxes against its limit (spares, asleep) and per agentghosty plan open siiqtec                    # the workspace's plan page: pay, change plan, invoices (no workspace or personal: /c/uso)ghosty plan apply siiqtec --dry-run         # what changes if you apply the scheduled plan NOW (seats, parallel, hosting, tokens)

plan apply can be run by staff, or by the workspace owner when there's no subscription (with one, the new plan starts when the invoice is paid). Without a workspace, both use the one from ghosty use.

With --json it returns plan.name, week.pct and month.pct (0 to 1; month.pct is null if your plan has no monthly cap), their resetsAt, creditMxn (top-up balance) and exhausted (true when you have no usage left). Change plan or top up: .

Workspaces

Token bags, plan, renewal and slug of a workspace. The owner can read the bags; changing them, changing the plan, renewing and renaming is for Ghosty staff (logged in the workspace's audit).

bash
ghosty spaces ls                                             # your workspaces: role, plan, combo (staff: --user EMAIL, someone else's)ghosty spaces create mailmask --dry-run                      # new workspace owned by you (30-day trial, one per account; if you already used it, it starts closed, "closed": true, and opens when paid); drop --dry-run to create itghosty spaces join denik                                     # staff: enter a client's workspace (no seat; logged) · leave to get outghosty spaces set denik --combo sales --dry-run              # staff: teams | sales | both | none (without Sales its boards are invisible)ghosty spaces set mailmask --model-cap 4 --house-claude on  # staff: + house Claude (when the owner brings no key);: the most expensive model it can pick (0.25 | 1 | 4 | none = its plan's); a trial caps at 0.25 and Claude does not fitghosty bags ls descti                                        # bags, spend, whether they cut and which agents spend from eachghosty bags create descti "MiniGhosty" --tokens 20M --note "agreed 30-sep"ghosty bags set descti "Astra" --recurring off              # one-time: counts from today and never refillsghosty bags set descti "Astra" --tokens 30M                 # raise the capghosty agents set minighosty --bag "MiniGhosty"             # hang an agent on it (none = the workspace balance)ghosty bags rm descti "Old"                                 # only if no agent uses itghosty spaces renew descti --until 2026-11-01 --note "paid October"   # «paid until»; refuses with Stripeghosty spaces plan business pro --courtesy --dry-run       # staff: trial | pro | empresarial, same rules as /admin/tenants; shows plan, model cap, tokens and «paid until» before → after. No Stripe charge, no email to the customer; --until DATE moves «paid until», --note goes to the auditghosty spaces rename totequim siiqtec --dry-run             # slug only; id, board, Stripe and WhatsApp stayghosty spaces transfer siiqtec --to siiqtec@gmail.com --keep-as admin --copy-keys --dry-run   # new owner: copies the keys they lack, the previous one stays admin; ACP boxes move with their /data, pool boxes are recycledghosty spaces archive tests --dry-run                       # owner or staff: same as Settings → Archive (asks you to type the slug); leaves /app and spaces lsghosty spaces restore tests                                 # brings it backghosty spaces log siiqtec --since 30d                       # the log: transfers, staff in/out, renewalsghosty spaces members ls business                           # its people: role, whether they joined, and until when (owner, admin or staff)ghosty spaces members add business chrome-review@ghosty.studio --until 14d   # temporary seat, removed automatically (--role admin to invite and remove people)ghosty spaces members add business ana@x.com --role collaborator --room sales   # collaborator of ONE Teams room: no seat, no personal agentghosty spaces members rm business chrome-review@ghosty.studio --yesghosty access why chrome-review@ghosty.studio <id>          # why they see an agent: owner, seat, share, assigned staffghosty access why ana@x.com --workspace siiqtec --board main   # or a board: workspace role, Sales and the list

Collaborators of one room. --role collaborator --room <room> invites someone to ONE Teams room of the space: it takes no seat, gives no personal agent and, if their account has only that role, they go straight to that room on login. If they are already a member, admin or staff, the invite is rejected and the role is not changed; to move them to member, remove them and invite them again.

[blocked]Temporary access. --until (a date like 2026-10-28, which expires at the end of that day in Mexico City time, or 14d / 12h) is for reviewer accounts (Meta, Google, Apple) that come in for a few days: the seat or the board-list entry is removed automatically and logged (workspace.members.rm, board.access). Running add --until again on someone already in moves the date; add without --until makes it permanent. Removing someone from the workspace also takes them off its boards' lists.

A transfer only changes the owner: the space, its agents, their skills and history stay as they are. Documents, databases, boards and numbers its agents use move to the new account; anything an agent outside the space also uses stays, and the dry run says so. --copy-keys copies the provider keys and connectors (MercadoPago, Skydropx…) the new owner lacks.

Archiving deletes nothing: the workspace stops showing in /app and ghosty spaces ls, and its agents, data and history stay. The owner or staff can do it; it's logged (workspace.archive / workspace.restore) and ghosty spaces restore <workspace> undoes it.

A monthly bag (default) refills every workspace period; a one-time bag (--recurring off) counts everything spent since it was created and, when it runs out, it's over. With --hard-cap on (default) turns stop at 100% with «out of balance»; with off it only counts. An agent with no bag spends from the workspace balance.

Audit log

Who changed what: the agent page's Save, channel changes, pauses and replies from the CLI, prompt patches, transfers, staff in and out and «log in as». Ghosty staff see everything; anyone else, only their own workspaces and agents. A gat_ agent token can't read it.

bash
ghosty audit ls --workspace siiqtec --since 24hghosty audit ls --agent tania-0 --action agent         # agent.save, agent.prompt_patch…ghosty audit ls --actor brenda@siiqtec.com --since 2026-10-05T00:00Zghosty audit ls --action card --json                   # card.pause, card.resume, card.reply

Factory

Delegate from the terminal

Your coding agent (Claude Code, Codex) hands the long, self-contained work to the factory and keeps going. First, if the repo isn't in any room, set it up from the terminal:

bash
ghosty factory rooms connect blissito/ghosty-studio --room studio --create --workspace business# ✓ Created #studio and connected blissito/ghosty-studio#   factory: on · CI ws-business#   ready for agents: level 1/3 (5/9) · missing: ci, codeowners, dependabot, protectedghosty factory rooms ls --workspace business             # which rooms have a repo and work as a factoryghosty factory rooms repos --workspace business          # the repos your GitHub App sees and which room each one is inghosty factory sprints ls --workspace business           # the sprints @plan proposed (draft, active) and how many tickets mergedghosty factory sprints show 12 --workspace business      # its tickets in order, with dependencies, stage and runghosty factory sprints approve 12 --workspace business   # one signature for every included ticket

rooms connect checks that your GitHub App sees the repo (if not, it gives you the link to grant access). Disconnecting (rooms disconnect … --yes) is for whoever connected it or the owner.

factory run posts «@plan » in the room connected to the repo, under your name, as if you typed it in Teams: the same plan, approvals and card.

bash
ghosty factory run "Add a COLLABORATOR role: invited by room, lands in the room, no personal agent. Done when an invite to #factory logs in straight there" \  --repo blissito/ghosty-studio --wait --workspace business# ✓ Sent to @plan in #factory (thread 8812)# 10:42 @plan is writing the plan# 10:46 #31 plan ready, waiting for your approval# Read it: ghosty factory runs show 31 --full --workspace business# Approve: ghosty factory runs approve 31 --plan-version 1 --workspace business
ghosty factory runs approve 31 --plan-version 1 --workspace business --yesghosty factory runs watch 31 --workspace business      # returns with the PR ready (or when there's a decision)ghosty factory runs merge 31 --workspace business --yesghosty factory runs card 31 --workspace business       # brings the live card to the bottom of its thread
  • --wait and watch return when the run needs you (approve the plan, decide after an escalation, merge the PR) or ends, and print the next command. When --timeout runs out (1800 s by default) they exit with code 1.
  • approve needs the plan version you read: if @plan already delivered another one, it's rejected.
  • changes --note "…" sends the plan back to @plan with your note (or replans after an escalation).
  • Any workspace member can request, approve and merge. Everything is logged: factory.run, factory.run_approve, factory.run_merge.
  • One live card per run: card brings it down and the old one stays as a still footprint linking to the live one.

What to do with an escalated run

When @check stops a run three loops in a row, or it needs something @build can't provide, the run waits for a person. runs show tells you why it stopped and runs advise recommends what to do:

bash
ghosty factory runs advise 115 --workspace business# #115 Let @build fix it · confidence high · gpt-5.6-luna# The four points fit the signed plan; two are tests requested since loop 1.# Note for @build#   1. Filter activeMarketers with tieneAsiento and delete workspaceMarketer when removing someone#      campaign-permission.server.ts:34-36#   …# @check reviews only#   Those four points# Nothing was applied. To apply it (edit the note first if you want):#   ghosty factory runs approve 115 --note "1. …" --check-scope "…" --workspace business
  • It compares @check's findings against the signed plan. If what's missing fits the plan, it recommends letting @build fix it. If it contradicts the plan or wasn't foreseen, it recommends redoing it (changes).
  • Each point of the note cites the finding or plan step behind it.
  • It applies nothing. Approving with --note gives @build one more loop with that note, and --check-scope makes @check review only that: anything new it finds goes as a note, not a finding.

Preview variables

If @check escalates because the preview won't start (it's missing environment variables), another @build loop won't help: a person provides them. They live on your computer (your .env, your password manager), so the way is to ask your terminal agent: "set the factory's environment variables for this repo".

bash
ghosty factory env ls blissito/ghosty-studio --workspace business# blissito/ghosty-studio · #studio# saved: REVIEWER_EMAIL# missing: DATABASE_URL, SESSION_SECRET, PROVIDER_KEYS_MASTER# #125 is escalated because its preview doesn't start (DATABASE_URL, SESSION_SECRET, PROVIDER_KEYS_MASTER)
ghosty factory env push blissito/ghosty-studio .env.preview --gen SESSION_SECRET,PROVIDER_KEYS_MASTER --workspace business# ✓ blissito/ghosty-studio: 3 variables saved; its previews are rebuilding.# #125 was waiting for this: ghosty factory runs recheck 125 --workspace business
ghosty factory runs recheck 125 --workspace business --yes   # @check reviews the same PR, no @build loop

A run that stopped moving (the card says «Not moving») is handled like from the card: resume makes its role pick up where it left off, stop stops the running turn and cancel closes the run. If a role is working, resume does nothing and suggests stop. Ghosty staff can use these three even in a workspace they're not a member of (never approve or merge):

bash
ghosty factory runs resume 27 --workspace palmera-legal --yes# ✓ #27: its role is back on it (building).

When @check escalates a decision, it leaves 2–3 paths, each with its action. choose without a letter lists them; with a letter it applies one, and the choice reaches the next role word for word:

bash
ghosty factory runs choose 153 --workspace business#   a) Fix the permission on main (recheck)#   b) Merge as is (merge_as_is)ghosty factory runs choose 153 a --workspace business --yes

merge_as_is merges with CI as it is, red checks included. It's for when what's red isn't caused by the PR (a workflow permission, jobs GitHub never started). It asks for confirmation and is logged (merge_override).

  • ls tells you what's missing: what .env.example declares and what escalated-because-blocked runs name. Without a repo, it uses the GitHub origin of the folder it runs in.
  • push adds: it changes the keys it brings and keeps the rest (--replace replaces the whole .env). --gen generates random keys (32 bytes hex) right there for sessions and encryption.
  • Use disposable values (a test database, fresh keys), never production: the preview runs the repo's code and can read them. The ones that touch production are flagged.
  • Values go encrypted to the vault and never come back: the CLI only prints names. Any member who sees the repo can list; only the workspace owner can save. Logged (factory.env_set, with the names).

See and fix runs

A workspace's Software Factory runs (they live in its Teams). Reading needs membership; renaming needs owner, admin or staff (logged as factory.run_rename).

bash
ghosty factory runs ls --workspace business --room mailmaskghosty factory runs show 15 --workspace business       # stage, current plan, PR, preview, latest events and which role is working (--full: the plan)ghosty factory runs rename 15 "CLI docs up to date" --workspace business --dry-runghosty agents ls --handle build --workspace business   # who is @build (without --workspace: in all your workspaces)

runs ls shows how long each run took and what it cost. To see where one run's time and money went:

bash
ghosty factory runs show 13 --timing --workspace mercadito-verde# #13 · pr_review · loops 0 · red CI 0 · $4.32 USD# clock: 4.2 h = working 71.8 min · waiting for a person 3.0 h · other (CI, queues) 1.3 min# at     step           time      in tools  model     usd    state# 17:07  @plan (thread) 1.2 min   0.1 min   opus-5-5  $0.87  done# 17:09  @check (critic) 0.6 min  0.1 min   opus-5-5  $0.51  done# 17:10  @build         68.8 min  66 min    sonnet-5-5 $1.82 done# Slowest commands (≥ 60 s)#   17:23 @build 10.3 min  Bash: until grep -q "TC_EXIT…
  • Working: some role had a turn running. Waiting for a person: the plan or the PR to approve. Other: CI, queues, deploy.
  • Commands of 60 s or more come from each role's transcript. ACP engines don't keep one: they show minutes and cost, without commands.
  • The cost includes @plan's first turn in the thread, before the run existed.

Why it got stuck or failed (a healthy run doesn't call the model; the analysis is saved, --refresh redoes it, and it's redone on its own if the run had events afterwards). See :

bash
ghosty factory runs why 13 --workspace mercadito-verde

Before the stuck patterns, it checks the approved plan's criteria against the evidence: if @check approved a criterion "in the preview" without the preview ready, it was merged "without preview", the smoke failed on the merged commit, or a CI criterion was approved with CI none, it comes first as approved_unmet_criterion:

bash
ghosty factory runs why 96 --workspace business# #96 approved_unmet_criterion · impact high · gpt-5.6-luna# Unmet criterion, approved anyway#   16:10 approved_without_preview  «La reserva pública de un servicio se completa de punta a punta en la preview del PR»#     @check aprobó y el veredicto no trae preview lista; dice: «…se probó contra el build RR8 en la caja…, no en la preview»

And how the workspace's factory is doing:

bash
ghosty factory runs stats --since 7d --workspace mercadito-verde [--repo owner/repo]# runs: 11 · merged: 10 (91 %) · median to PR 29.6 min · to merge 30.3 min# @check→@build loops per run: 0.4 · red CI per run: 0# cost: $29.89 USD · per run $2.72 · per merged PR $2.99

Getting help

Support is by email: each case has its own reply address, so answering the email or writing here lands in the same case. You can also ask your agent in your chat: "report it to support". The case carries your account, your agents and their recent errors, so you don't have to repeat them.

bash
ghosty support open --title "My agent stopped answering on WhatsApp" --body "Since yesterday 6 pm…"ghosty support ls                                    # your cases and their statusghosty support show <id>                             # the threadghosty support reply <id> --body "I tried reconnecting"   # if it was resolved, it reopens

On the web: Support in the menu.

Support

For Ghosty staff (User.isAdmin): what used to be a script in the box for each report. Reading someone else's conversations is logged.

bash
ghosty agents ls --user ana@company.com --app android            # their list exactly as their app gets it (tone, space, last use; no tokens)ghosty usage --boxes --by template                                # the whole fleet by template: how many, real RAM and vCPU, awake and asleepghosty conversations ls --user david@company.com --since 7d          # their conversations in any agent (also --surface android)ghosty conversations show <agent> <conversation> --why               # the thread's kind, whose it is, and whether the owner / its user see it in their list or by linkghosty turns stats --since 14d                                       # real failure rate by engine, channel (Teams and A2A included) and error; without staff, the test channel or deleted agents (--all includes them)ghosty push log --user brenda@siiqtec.com --since 1d                 # which pushes were sent and what Apple/Google answeredghosty agents doctor --user quiroz@company.com                     # their agents: doctor, latest turns (and whether the app picked up each answer), plan/bag and boxes (flags duplicates)ghosty usage --images --plan free --since 7d --by user              # image charges vs the images agents delivered; real cost vs the price tableghosty conversations show <agent> <conversation> --tools            # every tool it ran (secrets masked) and the external domains it namedghosty novedades create --title "PDF and audio" --body "…" --image hero.png --link chats --publishghosty novedades set <id> --min-version 12                           # if their app is older, the button reads «Actualizar» (Play, in-app)ghosty novedades test <id>                                           # only to your phoneghosty novedades send <id> --at "2026-10-02T12:00"                   # scheduled, CDMX time (9–21 h)ghosty support ls --all --status open                        # the inbox; every case also reaches you by email and you answer from there (/resuelto on the 1st line closes it)ghosty support reply <id> --all --body "Done" --resolve      # emails the customerghosty support link <id> blissito/mailmask#52                # when the issue closes (or the PR merges), every tied case gets "fixed"

conversations archive|rm with --kind test|channel is for the agent's owner (or staff): rm never deletes customer threads (--kind channel), which are only archived because their memory is what keeps serving them. --kind personal is for anyone with access to the agent and only touches YOUR own chats with it, never someone else's. What you delete also disappears from the apps (iOS, Android) on their next sync. push log is recorded since 2026-10-01 and kept 30 days; since the same day it includes announcement pushes (kind: novedad), and novedades ls shows how many FCM delivered and rejected. agents ls --user --app also lists their phones with the app build, and the «fetched» column of agents doctor --user exists since 2026-10-01. --tools reads the transcript in Tigris (claude-worker) or the box history (goose, ghosty-lite); never while a turn is running in that thread.

Assigned staff

A Ghosty account executive assigned to a client's account sees and runs, with their own session, that account's agents (with and without a workspace), its documents, databases and boards. They don't see keys or tokens, don't touch plan or billing, and don't transfer or delete. Only staff assigns; the customer sees it as «Your Ghosty account executive» in their account. Every assignment and every write by the executive is logged.

bash
ghosty staff assign brenda@siiqtec.com siiqtec@gmail.com --reason "SIIQTEC migration"   # assign (no-op if already assigned)ghosty staff ls brenda@siiqtec.com                                    # who they serve (--all: also revoked)ghosty staff ls "" siiqtec@gmail.com                                  # who serves that accountghosty staff unassign brenda@siiqtec.com siiqtec@gmail.com --yes      # stops on their next click

In the panel, the executive picks «Atendiendo: » in Documents and databases and in Agents; it is a cookie revalidated on every request, never another session or «sign in as».

Settings

Platform switches Ghosty staff can flip without a deploy: which agent answers /c without an account in a box (ANON_NATIVE_AGENT_ID), which agents and surfaces have native subagents, the page builder for everyone. Every change is logged; switches that carry JSON stay in /admin/settings.

bash
ghosty settings ls                                                     # value, where it comes from (row, env or default) and what it isghosty settings set ANON_NATIVE_AGENT_ID cmu7pgbyr0001gee3ruk172mm      # /c without an account is answered by that agent in a boxghosty settings set NATIVE_SUBAGENT_AGENTS +cmu7pgbyr0001gee3ruk172mm   # in lists: +id adds, -id removesghosty settings unset ANON_NATIVE_AGENT_ID                              # back to the default (/c without a box)

App versions

The version gates of Ghosty's apps (iOS, Android and Notch, the Mac one), for staff only. suggestBuild shows older builds a dismissible "update" notice; minBuild stops older builds until they update. Raise suggestBuild once the new version is live in the store, never before: the notice sends people there. minBuild asks for confirmation and can never be above suggestBuild. Every change is logged; the emergency flags stay in /admin/settings.

bash
ghosty app ls                                  # minBuild and suggestBuild for iOS, Android and Notch, plus the flagsghosty app suggest 106                         # iOS: builds below 106 see the "update" noticeghosty app suggest 14 --platform android       # same on Android (its versionCode)ghosty app min 95 --yes                        # builds below 95 stop working until they update

Coupons

A coupon adds balance to a personal account (in cost pesos, like top-ups: a $99 top-up adds about $49.50) and can lend a plan (pro, power or max) until a date; a coupon never lowers the plan of someone already paying for a bigger one. One redemption per account; with --eligibility hackathon:<event> only emails from an accepted application to that event can redeem it; with --agent <id> every account that redeems it gets its own copy of that agent (personal: its spend comes from their plan and the coupon balance). It is created as a draft: nobody can redeem it until you turn it on with --on. Only staff creates and edits; anyone redeems.

bash
ghosty coupons create HACK2026 --credit 0 --plan pro --until 2026-11-13T05:59:00-06:00 --max 100   # draftghosty coupons set HACK2026 --credit 50 --on      # set the amount and turn it onghosty coupons ls                                  # amount, lent plan, validity, redemptions and stateghosty coupons set HACK2026 --plan pro --from 2026-11-12T00:00:00-06:00 --until 2026-11-27T00:00:00-06:00 --redeem-by 2026-11-12T23:59:59-06:00 --convert-promo HACK2026-50   # the plan starts on the event day, redeeming closes that night and when it ends it offers to continue with that Stripe codeghosty coupons show HACK2026                       # who redeemed it, their plan window and who already paysghosty coupons redeem HACK2026                     # redeem it for your account

People can also redeem it at ("Canjear cupón" field) or with the direct link https://www.ghosty.studio/canjear?codigo=HACK2026 (it asks to log in and returns to /c/uso with the result).

Campaign watch

Every hour it checks the connected Meta ad accounts (Ghosty Ads) and the ads-only WhatsApp numbers, and alerts staff (email, WhatsApp and Teams room) when an active campaign gets paused or Meta stops delivering it, the account has a payment pending, the Meta connection expires within 7 days, or a number goes 24 h without ad leads. Meta sends no webhook for any of this. Each alert goes out once.

bash
ghosty ads watch                  # watched accounts and numbers: last checked and last alertghosty ads watch run --dry-run    # what it would alert now, without alertingghosty ads watch run              # one pass now (alerts and saves)

Sites

The sites your agents publish, at <slug>.ghosty.page (nobody needs an account anywhere else). sites ls shows yours: live, paused, and unpublished ones that can still be recovered.

Apps with a backend, their database and checkpoints: .

Free plan: a site pauses after 30 days without changes (notice 7 days before; every change gives it another 30). While paused its link shows «This page is paused — Reactivate it» and nothing is deleted. After 30 days paused it is unpublished (the link stops working and the slug stays reserved) and its copy is kept 6 more months; then it is deleted for good. Reactivating it any time before that brings it back as it was, on the same link.

Pinned sites: $49 USD a year or $5 USD a month ($990 / $99 MXN), includes up to 3 sites. A pinned site never pauses and carries no «Made with Ghosty» banner. Need more? Each extra pack adds 3 sites for the same price. Releasing a site, cancelling or a failed payment send it back to the Free rule with notice: it never pauses at once.

bash
ghosty sites ls                                                      # your sites: state (pinned, paused, pauses on…) and linkghosty sites pin tacos-don-pepe                                      # pin it: with a free slot right away; otherwise a card-payment linkghosty sites pin tacos-don-pepe --interval month --currency mxn      # monthly, in pesos ($99 MXN a month)ghosty sites pin new-landing --add-pack                              # you already use your 3: add 3 more and pin this oneghosty sites unpin old-landing                                       # release its slot (back to the Free rule with notice)ghosty sites rm test-landing                                         # delete it: stops being served, can't be undone (--yes without a terminal)ghosty sites pins                                                    # your subscription, slots used and which sites hold themghosty sites pins --cancel                                           # cancel at period end (--resume undoes it)ghosty sites domain add agenda-perdix bookings.mydomain.com         # custom domain for an app: tells you the DNS record to addghosty sites domain verify agenda-perdix bookings.mydomain.com      # checks DNS again; done = https://bookings.mydomain.comghosty sites domain ls agenda-perdix                                 # the app's domains and their state (rm <slug> <domain> removes one)ghosty sites show agenda-perdix                                      # everything about the app: status (Ready/Starting/Asleep/Failed), domains, variable names, database, files, tasksghosty sites env set agenda-perdix STRIPE_SECRET_KEY=sk_live_…        # the app's variables (env ls gives names only; env rm <slug> NAME deletes one)ghosty sites cron pause agenda-perdix cm123                          # scheduled tasks: cron ls, pause|resume|rm <slug> <id>ghosty sites files rm agenda-perdix cm456                            # files the app stores: files ls, rm <slug> <id>ghosty sites errors agenda-perdix --since 6h                         # server and browser errors, grouped (--kind, --req-id)ghosty sites agent agenda-perdix create                              # the agent inside the app (Haiku 5.5); --agent <id> links yours, --model changes itghosty sites ls --house                                              # staff: the house sitesghosty sites publish ./melon.html --title "Gelatina de sandía" --slug gelatina-de-sandia   # staff: a single .html or a folder with index.htmlghosty sites publish ./landing/ --site gelatina-de-sandia            # staff: update that one (without --site a new one is always created)ghosty sites slug arbol-palpitante gelatina-de-sandia                # staff: change the slug of any live site

The slug: lowercase letters, digits and hyphens, 3 to 60, no hyphen at the start, at the end or doubled, and not reserved (api, admin, s, www, app, assets, static, dashboard, login). Errors with a code: slug_invalid, slug_taken and slug_unsupported (EasyBits does not accept choosing or changing the slug yet; nothing changes and it exits with 1). Limits: 1 MB per file, 8 MB and 40 files per site.

Browser

bash
ghosty browser logout          # signs the browser out: revokes the Ghosty for Chrome tokens of your terminal agents and disconnects the extension

Asks for confirmation (--yes for scripts). To reconnect the terminal, copy the new command from the extension panel. See .

Voice

ghosty tts says a text with the house voice (Kokoro, Mexican Spanish, with Ghosty's pronunciation lexicon) and saves it as a .wav. It is the same voice as the voice notes: use it to hear how something will sound before sending it.

sh
ghosty tts "Hola, gracias por escribir. Te aviso por WhatsApp."ghosty tts "Tu cita quedó el jueves a las cinco." --voice ef_dora --out cita.wav && afplay cita.wav

Voices: em_santa (man, the house voice, default), em_alex (man) and ef_dora (woman). Brand names (WhatsApp, Claude, GitHub, ghosty.studio…) are written normally: the lexicon fixes how they sound. Up to 400 characters and 60 sentences per minute.

Live streaming

ghosty events live sends the workspace's events to your YouTube channel and a Facebook Page without copying keys: connect them with OAuth, and "prepare" creates the event on each destination and loads the keys into the events room (do it with the room empty; it restarts it). The same lives in Teams: Room settings → Event (webinar mode) → "Live streaming".

sh
ghosty events live connect youtube --workspace my-space     # opens the browser; pick account and channelghosty events live connect facebook --workspace my-space    # pick the Pageghosty events live prepare --title "Hackathon" --privacy unlisted --at 2026-11-12T19:00ghosty events live check     # which destinations the room has loadedghosty events live ls        # where the workspace streams toghosty events live unlink facebook

Then, in the room, the host presses Record with "Live" checked and it goes on air by itself; YouTube ends the stream when it stops. --only youtube prepares just that destination. Facebook always goes out public on the Page.

Partners

ghosty partner gives an agent to each of your customers (one shared agent, memory per customer). It has its own page: .

Language

The CLI speaks Spanish if your system is in Spanish (LANG=es_MX…) and English otherwise; --lang es|en or GHOSTY_LANG forces it. It also translates the server's messages to English. With --json, keys and codes don't change.

Tab completion

bash
source <(ghosty completion zsh)          # in ~/.zshrc, after compiniteval "$(ghosty completion bash)"          # in ~/.bashrcghosty completion fish > ~/.config/fish/completions/ghosty.fish

It completes commands, subcommands and flags, plus your agents' and workspaces' names (cached for 5 minutes).

Global options

OptionWhat it does
--jsonMachine output: stdout carries JSON only. Notices and progress go to stderr.
--token <token>Use this token instead of the session. Also via the GHOSTY_TOKEN variable.
--profile <name>Use a separate saved session (also GHOSTY_PROFILE), e.g. one per account. Letters, digits, - and _.
-y, --yesSkip confirmations (required without a terminal).
-h, --helpHelp. ghosty help <command> too.
-v, --versionVersion.

An agent token (gat_…, generated on the agent's page) reaches only that agent: it works for agents get/set/restart, files, skills, mcp and try, but not for listing agents or chat.

Environment variables

VariableWhat it does
GHOSTY_TOKENToken instead of the session (like --token).
GHOSTY_PROFILESession profile (like --profile).
GHOSTY_URLAnother server (default https://www.ghosty.studio).
XDG_CONFIG_HOMEWhere the session is saved: $XDG_CONFIG_HOME/ghosty/config.json (default ~/.config). With a profile, config.<name>.json.
NO_COLORNo colors, no banner.
GHOSTY_NO_UPDATE_CHECKDon't ask npm for new versions (it also skips with CI). By default it checks once a day and notes it on stderr.
EASYBITS_API_KEYEasyBits key for dbs import --from easybits:….
GHOSTY_PARTNER_KEY · GHOSTY_PARTNER_KEY_SECRETSign partner commands with your server's credential (GHOSTY_PARTNER_SECRET still works). See .

Exit codes

CodeMeaning
0OK.
1API error (the message says which).
2Usage error: unknown command or option, missing argument.
3Not signed in. Run ghosty login.