Command reference
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
Agents
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
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.
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 .
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
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.
- 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}. WithNAMEin your environment it changes; otherwise today's value stays. - Before applying, the agent's current version is saved (Versions, in the web).
applydoesn'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
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.
- 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 doctorflags it (prompt.base). --dry-runtells whether every edit applies (--out FILEwrites the result).--prompt-base noneunlinks 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:
- It applies on the server, on the prompt as it is at that moment: no need to download it with
get --prompt-outand upload it again. - If an edit doesn't find its place, nothing changes (409 saying which one).
--prompt-patchand--prompt-appendtogether: 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
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
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:
- If the call sends
iva_pct, that one for everything. - With
solo-factura=trueand nofactura: trueon the quote: 0. - If the line's category has a rule (
iva.GRANEL=16): that one. - With
iva-incluido=true(prices already include it): 0. - 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
queryis read only;--writeallowsINSERT/UPDATE/DELETE/DDL.--arg Vgives the value of each?, in order (repeatable).exportdownloads a copy: without--table, the whole database as SQLite (every table with its rows); with--table, that table as UTF-8 CSV.--outsays where to save it. It uses your session, not the agent'sgat_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).importreplaces each table's rows (idempotent);--appendadds them instead and--tables a,bcopies only those.--dry-runprints 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.dbis an alias ofdbs, anddbs sqlofdbs 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.
importwarns when replacing a table would turn permanent links back into external ones, and gives you the exact flag.photos putonly takes JPEG, PNG or WebP up to 10 MB;--dry-runlists keys with no row and files that aren't images. The column isimagen_urlunless--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
<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
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
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.
<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:
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 .
Bring a number from somewhere else
To migrate an agent from EasyBits (or a droplet) without signing the number up again:
--answerhas no default:onanswers real customers;offonly records. Formmy only forwards when its channel is on:onturns it on; withoff, 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.
historygoes afterlinkand never duplicates: run it before the cutover and again right at it. It fires no "new lead" alerts.historyalso 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-runit 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
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
A key is never accepted as an argument: it would stay in your shell history. creds is an alias of credentials.
Connectors
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
--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
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…".
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
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.
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.
--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.
--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
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
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).
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.
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:
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.
--waitandwatchreturn when the run needs you (approve the plan, decide after an escalation, merge the PR) or ends, and print the next command. When--timeoutruns out (1800 s by default) they exit with code 1.approveneeds 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:
cardbrings 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:
- It compares
@check's findings against the signed plan. If what's missing fits the plan, it recommends letting@buildfix 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
--notegives@buildone more loop with that note, and--check-scopemakes@checkreview 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".
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):
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:
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).
lstells you what's missing: what.env.exampledeclares and what escalated-because-blocked runs name. Without a repo, it uses the GitHuboriginof the folder it runs in.pushadds: it changes the keys it brings and keeps the rest (--replacereplaces the whole.env).--gengenerates 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).
runs ls shows how long each run took and what it cost. To see where one run's time and money went:
- 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 :
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:
And how the workspace's factory is doing:
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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".
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
It completes commands, subcommands and flags, plus your agents' and workspaces' names (cached for 5 minutes).
Global options
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.