ghosty-acp 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -180,3 +180,10 @@ flujo JSON-RPC, porque cualquier otra cosa ahí rompe al editor.
180
180
  | `cwd … → …` | Se remapeó la ruta del proyecto a una que el agente sí ve |
181
181
 
182
182
  Necesita Node 22 o superior. MIT.
183
+
184
+ ## Agent skills inside
185
+
186
+ The package ships the Ghosty Studio agent skills under `skills/` (`ghosty-agent`, `ghosty-acp`,
187
+ `ghosty-docs`, `ghosty-recipe`), in the [Agent Skills](https://agentskills.io) format. Tools that
188
+ load skills from installed dependencies (e.g. TanStack Intent) pick them up; anyone else can
189
+ install them with `npx skills add https://ghosty.studio` or `npx skills add blissito/ghosty-skills`.
package/bridge.mjs CHANGED
@@ -48,8 +48,11 @@ const ws = new WebSocket(target);
48
48
  // sueltan en orden al abrir.
49
49
  let cola = [];
50
50
 
51
+ let abierto = false;
52
+
51
53
  ws.onopen = () => {
52
54
  clearTimeout(avisoLento);
55
+ abierto = true;
53
56
  diag("listo");
54
57
  for (const linea of cola) ws.send(linea + "\n");
55
58
  cola = [];
@@ -66,7 +69,9 @@ ws.onclose = (e) => {
66
69
  clearTimeout(avisoLento);
67
70
  // 1006 sin motivo es lo que se ve cuando el servidor rechaza el upgrade: casi siempre
68
71
  // el token. Decirlo aquí evita el rato de mirar el editor pensando que es cosa suya.
69
- if (e.code === 1006 && !e.reason) {
72
+ // Sólo es un rechazo si nunca llegó a abrir: un 1006 tras «listo» es la caja o la red
73
+ // cortando una conexión que sí autenticó, y mandar a revisar el token ahí despista.
74
+ if (e.code === 1006 && !e.reason && !abierto) {
70
75
  diag(token ? "rechazado (1006): revisa el token de este agente" : "rechazado (1006): falta GHOSTY_ACP_TOKEN");
71
76
  } else {
72
77
  diag(`conexión cerrada (${e.code}${e.reason ? `: ${e.reason}` : ""})`);
package/package.json CHANGED
@@ -1,13 +1,38 @@
1
1
  {
2
2
  "name": "ghosty-acp",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "Conecta tu editor a un agente ACP remoto. Puente entre entrada/salida estándar y WebSocket, sin dependencias.",
5
5
  "type": "module",
6
- "bin": { "ghosty-acp": "bridge.mjs" },
7
- "files": ["bridge.mjs", "README.md"],
8
- "engines": { "node": ">=22" },
9
- "keywords": ["acp", "agent-client-protocol", "zed", "vscode", "neovim", "agent"],
6
+ "bin": {
7
+ "ghosty-acp": "bridge.mjs"
8
+ },
9
+ "files": [
10
+ "bridge.mjs",
11
+ "README.md",
12
+ "skills"
13
+ ],
14
+ "engines": {
15
+ "node": ">=22"
16
+ },
17
+ "keywords": [
18
+ "acp",
19
+ "agent-client-protocol",
20
+ "zed",
21
+ "vscode",
22
+ "neovim",
23
+ "agent",
24
+ "agent-skills",
25
+ "skills",
26
+ "ghosty"
27
+ ],
10
28
  "license": "MIT",
11
- "repository": { "type": "git", "url": "git+https://github.com/blissito/ghosty-studio.git", "directory": "packages/acp-bridge" },
12
- "homepage": "https://www.ghosty.studio/docs/acp"
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/blissito/ghosty-studio.git",
32
+ "directory": "packages/acp-bridge"
33
+ },
34
+ "homepage": "https://www.ghosty.studio/docs/acp",
35
+ "scripts": {
36
+ "prepack": "rm -rf skills && cp -R ../../public/skills skills && rm -f skills/*.tar.gz skills/index.json skills/index.legacy.json"
37
+ }
13
38
  }
@@ -0,0 +1,20 @@
1
+ # Ghosty Studio agent skills
2
+
3
+ Skills in the [Agent Skills](https://agentskills.io) format for coding agents (Claude Code, Cursor,
4
+ Codex, Copilot…). Install one or all:
5
+
6
+ ```bash
7
+ npx skills add blissito/ghosty-skills
8
+ # or straight from the site (same skills, discovered via /.well-known/agent-skills):
9
+ npx skills add https://ghosty.studio
10
+ ```
11
+
12
+ | Skill | What for |
13
+ |---|---|
14
+ | `ghosty-agent` | configure a Ghosty Studio agent through its API: identity, model, files, skills, MCP servers |
15
+ | `ghosty-docs` | read the Ghosty docs from an agent: markdown pages, `llms.txt`, the docs MCP server |
16
+ | `ghosty-acp` | connect Zed, VS Code, JetBrains or Neovim to the agent over ACP |
17
+ | `ghosty-recipe` | write or review an agent recipe (`.recipe.yaml`) to upload in the creator |
18
+
19
+ This directory is mirrored from `public/skills/` in
20
+ [blissito/ghosty-studio](https://github.com/blissito/ghosty-studio). Docs: https://www.ghosty.studio/docs/configurar
@@ -0,0 +1,78 @@
1
+ ---
2
+ name: ghosty-acp
3
+ description: Connect a code editor (Zed, VS Code, JetBrains, Neovim) to a Ghosty Studio agent over ACP (Agent Client Protocol) using the ghosty-acp bridge and the agent token. Use when the user wants to talk to their Ghosty agent from their editor, pastes an acp.agents or agent_servers config, or mentions ghosty-acp or ACP with ghosty.studio.
4
+ license: MIT
5
+ compatibility: Node 22+ on the user's machine (npx downloads the bridge); network access to the agent's wss:// address
6
+ metadata:
7
+ author: ghosty-studio
8
+ version: "1.0"
9
+ ---
10
+
11
+ # Connect an editor to a Ghosty agent over ACP
12
+
13
+ A Ghosty Studio agent runs on its own machine behind a WebSocket. Editors launch a
14
+ **command** and speak ACP over stdio, so a bridge swaps the cable: `npx -y ghosty-acp <wss-url>`.
15
+ It has no dependencies and carries no secret; the token travels in an environment variable.
16
+
17
+ ## What you need from the user
18
+
19
+ Both come from Ghosty Studio → **Agentes → their agent → "Desde tu editor (ACP)"** (a collapsed
20
+ section under the token card):
21
+
22
+ - the agent's ACP address: `wss://acp-<agentId>.<host>/acp`
23
+ - the token `gat_…` (the same token the `ghosty-agent` skill uses)
24
+
25
+ Never put the token in `args`: any process on the machine can read another process's
26
+ arguments. It goes in `env.GHOSTY_ACP_TOKEN`.
27
+
28
+ ## Write the config for their editor
29
+
30
+ **Zed** — `Settings → settings.json`:
31
+
32
+ ```json
33
+ {
34
+ "agent_servers": {
35
+ "Ghosty": {
36
+ "type": "custom",
37
+ "command": "npx",
38
+ "args": ["-y", "ghosty-acp", "wss://acp-AGENT.../acp"],
39
+ "env": { "GHOSTY_ACP_TOKEN": "gat_…" }
40
+ }
41
+ }
42
+ }
43
+ ```
44
+
45
+ **VS Code** — install the *ACP Client* extension, then `settings.json`:
46
+
47
+ ```json
48
+ {
49
+ "acp.agents": {
50
+ "Ghosty": {
51
+ "command": "npx",
52
+ "args": ["-y", "ghosty-acp", "wss://acp-AGENT.../acp"],
53
+ "env": { "GHOSTY_ACP_TOKEN": "gat_…" }
54
+ }
55
+ }
56
+ }
57
+ ```
58
+
59
+ Do not use VS Code's "Add Agent" wizard: it asks for command and args only, never the env
60
+ var, and the agent ends up without its key.
61
+
62
+ **JetBrains / Neovim** use the same triple (command, args, env) in their own ACP client
63
+ settings. `GHOSTY_ACP_CWD` optionally sets the remote working directory.
64
+
65
+ ## When it does not connect
66
+
67
+ | Symptom | Meaning | Do |
68
+ |---|---|---|
69
+ | `rejected (1006)` right away | token mismatch (rotated?) | ask the user to copy the block again from the panel |
70
+ | slow first start (5–15 s) | the agent's machine was asleep; the first connection wakes it | wait, do not change anything |
71
+ | `preview host not found` | the machine was recycled; the platform recreates it on demand | retry once after ~5 s |
72
+ | `already serving N conversations` | every open session takes a slot | close a session in another client |
73
+
74
+ ## Rules
75
+
76
+ - Node 22+ is required for `npx -y ghosty-acp`; check `node -v` if it fails to start.
77
+ - Read `ghosty-acp` in the user's editor config as the bridge, not as this skill.
78
+ - Never print the token back or commit the settings file with it inside.
@@ -0,0 +1,62 @@
1
+ ---
2
+ name: ghosty-agent
3
+ description: Configure a Ghosty Studio agent (identity/system prompt, model, knowledge files in its machine, skills, custom MCP servers) through its REST API using the agent token. Use when the user asks to set up, tune, teach, or connect their Ghosty agent, or mentions ghosty.studio.
4
+ license: MIT
5
+ compatibility: Needs curl or any HTTP client and network access to https://www.ghosty.studio
6
+ metadata:
7
+ author: ghosty-studio
8
+ version: "1.1"
9
+ ---
10
+
11
+ # Configure a Ghosty Studio agent
12
+
13
+ A Ghosty Studio agent runs on its own isolated machine (disk, terminal, memory). You configure it
14
+ over HTTPS with **its own token**; nothing runs on the user's computer.
15
+
16
+ ## Setup (once)
17
+
18
+ 1. Ask the user for the agent id and token. Both are in Ghosty Studio → **Agentes → their agent →
19
+ Conexión con tu editor → Generar token** (token looks like `gat_…`; id is in the page URL
20
+ `/app/agents/<id>`).
21
+ 2. Keep them in env vars, never in command arguments or committed files:
22
+
23
+ ```bash
24
+ export GHOSTY_AGENT_ID="<id>"
25
+ export GHOSTY_AGENT_TOKEN="gat_…"
26
+ ```
27
+
28
+ Base URL: `https://www.ghosty.studio/api/v2/agents/$GHOSTY_AGENT_ID`. Every call:
29
+ `-H "Authorization: Bearer $GHOSTY_AGENT_TOKEN"`. Wrong token or id → `404` (do not retry).
30
+
31
+ ## What you can do
32
+
33
+ | User asks | Do |
34
+ |---|---|
35
+ | "set its identity / persona / system prompt" | `PATCH` with `{"prompt": "..."}` then `POST …/restart` |
36
+ | "change the model" | `GET` first (lists `models`), then `PATCH {"model": "<id>"}` (restarts by itself) |
37
+ | "give it these files / documents / knowledge" | `PUT …/files/<name>` with raw bytes, one call per file |
38
+ | "install / teach it a skill" | `PUT …/skills/<slug>` with the SKILL.md markdown (+ assets), then `POST …/restart` |
39
+ | "connect it to this MCP server" | `PUT …/mcp` with the full list of servers (it replaces; restarts by itself) |
40
+ | "what does it have?" | `GET …?full=1` → prompt, model, files, skills, mcp |
41
+
42
+ Read `references/api.md` for exact request/response shapes before calling.
43
+
44
+ ## Rules
45
+
46
+ - **Read before write.** `GET` first; `PATCH` only the fields the user asked to change.
47
+ - **Write the prompt in the user's language** and in second person ("Eres…", "You are…"). Keep it
48
+ under ~3,000 characters: it is prepended to every conversation.
49
+ - **Skills follow the Agent Skills format**: a `SKILL.md` with YAML frontmatter `name` and
50
+ `description`, body in markdown. Slug = lowercase, digits and hyphens.
51
+ - **MCP `PUT` replaces the whole list.** `GET …/mcp` first and send back the existing servers plus
52
+ the new one. Only `https://` URLs for HTTP servers; stdio servers need the binary to exist in the
53
+ agent's machine (Node and Python are there).
54
+ - **Engines without their own machine** (Claude, DeepSeek, Codex) accept `GET`/`PATCH` (identity, model) only; files, skills, MCP and restart answer `409 agente_sin_maquina`. Tell the user and stop; do not retry.
55
+ - **Restart is not free**: it cuts a turn in progress. Batch changes, restart once at the end.
56
+ - Files go to the agent's working directory; tell the user the agent can `ls` them. Max 10 MB each.
57
+ - Never print the token back to the user or into logs.
58
+
59
+ ## After changes
60
+
61
+ Tell the user in one line what changed and suggest a test message for the agent, e.g.
62
+ "Ask it: *¿qué archivos tienes en tu workspace?*".
@@ -0,0 +1,58 @@
1
+ # Ghosty Studio — agent configuration API
2
+
3
+ Base: `https://www.ghosty.studio/api/v2/agents/{id}` · Auth: `Authorization: Bearer gat_…`
4
+ (agent token) or an owner OAuth2 bearer with `agents:write`. JSON unless noted.
5
+ Full spec: https://www.ghosty.studio/openapi.yaml · Docs: https://www.ghosty.studio/docs/configurar
6
+
7
+ ## GET /
8
+ Returns `{ id, name, engine, model, models: [{id,label}], prompt, channels, webSearch, mcp }`.
9
+ Add `?full=1` to also get `files: [{path,size}]` and `skills: [{slug,description,files}]`
10
+ (wakes the machine if asleep).
11
+
12
+ ```bash
13
+ curl -s "$B" -H "Authorization: Bearer $GHOSTY_AGENT_TOKEN"
14
+ ```
15
+
16
+ ## PATCH /
17
+ Body: any of `{ "name", "model", "prompt", "webSearch": bool, "channels": { "teams": bool } }`.
18
+ Response: the same as GET plus `aplicado: ["set-prompt", …]`. `model` restarts the agent.
19
+
20
+ ```bash
21
+ curl -s -X PATCH "$B" -H "Authorization: Bearer $GHOSTY_AGENT_TOKEN" \
22
+ -H "Content-Type: application/json" \
23
+ -d '{"prompt":"Eres Nora, asistente de la clínica Dental Sur. Contestas en español, corto, y nunca das diagnósticos."}'
24
+ ```
25
+
26
+ ## PUT /files/{path} · DELETE /files/{path} · GET /files[/dir]
27
+ Raw bytes in the body (no multipart, no base64). Max 10 MB. `path` is relative, no `..`.
28
+
29
+ ```bash
30
+ curl -s -X PUT "$B/files/precios-2026.pdf" -H "Authorization: Bearer $GHOSTY_AGENT_TOKEN" \
31
+ -H "Content-Type: application/pdf" --data-binary @precios-2026.pdf
32
+ ```
33
+ → `{ path, bytes, en: "/data/work/precios-2026.pdf" }`
34
+
35
+ ## PUT /skills/{slug} · DELETE /skills/{slug} · GET /skills
36
+ Body: `{ "markdown": "<SKILL.md content>", "assets": [{ "name": "scripts/x.py", "contentBase64": "…" }] }`.
37
+ Max 25 MB total. Then `POST /restart` so the agent loads it.
38
+
39
+ ```bash
40
+ jq -n --rawfile md SKILL.md '{markdown:$md}' | \
41
+ curl -s -X PUT "$B/skills/cotizaciones" -H "Authorization: Bearer $GHOSTY_AGENT_TOKEN" \
42
+ -H "Content-Type: application/json" -d @-
43
+ ```
44
+
45
+ ## GET /mcp · PUT /mcp
46
+ Body: `{ "servers": [ …full list… ] }`. Each server is one of:
47
+ - `{ "name": "notion", "type": "http", "url": "https://mcp.notion.com/mcp", "headers": { "Authorization": "Bearer …" } }`
48
+ - `{ "name": "fs", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/data/work"], "env": {} }`
49
+
50
+ Names: `a-z 0-9 - _`, max 20 servers. The agent restarts automatically.
51
+
52
+ ## POST /restart
53
+ → `{ reiniciado: true }`. Cuts a running turn; disk survives.
54
+
55
+ ## Errors
56
+ `400` invalid body (message in `error`) · `404` unknown id/token · `405` wrong method ·
57
+ `409 agente_sin_maquina` files, skills, MCP and restart need an engine with its own machine (Ghosty · Lite or Goose); `GET`/`PATCH` work on every engine ·
58
+ `413` too big · `502` saved but the machine did not take it (retry `POST /restart`).
@@ -0,0 +1,55 @@
1
+ ---
2
+ name: ghosty-docs
3
+ description: Read the Ghosty Studio documentation from an agent without scraping — every page as raw markdown, llms.txt, the docs MCP server (search_docs, read_doc, list_docs, openapi) and the OpenAPI spec. Use when the user asks how something works in Ghosty Studio, Ghosty Teams or ghosty.studio, or before calling its API.
4
+ license: MIT
5
+ compatibility: Network access to https://www.ghosty.studio
6
+ metadata:
7
+ author: ghosty-studio
8
+ version: "1.0"
9
+ ---
10
+
11
+ # Read the Ghosty Studio docs
12
+
13
+ Ghosty Studio publishes its documentation for agents first. Never scrape the HTML: every
14
+ page has a machine-readable twin.
15
+
16
+ ## Pick the cheapest source
17
+
18
+ | Need | Fetch |
19
+ |---|---|
20
+ | The map of every page (title + URL) | `https://www.ghosty.studio/llms.txt` |
21
+ | Everything at once (large) | `https://www.ghosty.studio/llms-full.txt` |
22
+ | One page as markdown | append `.md` to its URL: `https://www.ghosty.studio/docs/configurar.md` (English: `/en/docs/configure.md`) |
23
+ | A page when you only have the HTML URL | `GET` it with `Accept: text/markdown` — the server negotiates and returns markdown |
24
+ | The public API contract | `https://www.ghosty.studio/openapi.yaml` (OpenAPI 3.1) |
25
+
26
+ Spanish is the source language (`/docs/...`); English lives under `/en/docs/...`. Both are
27
+ kept in sync; prefer the user's language.
28
+
29
+ ## Use the MCP server when you can
30
+
31
+ `https://www.ghosty.studio/mcp/docs` is a Streamable HTTP MCP server, no auth, JSON-RPC over
32
+ `POST`. Tools:
33
+
34
+ - `search_docs { query, locale? }` — lexical search, up to 8 pages with slug and snippet. Call this first.
35
+ - `read_doc { slug, locale? }` — a whole page as markdown (slug like `api/autenticacion`).
36
+ - `list_docs { locale? }` — all pages grouped by section.
37
+ - `openapi {}` — the OpenAPI YAML.
38
+
39
+ Claude Code: `claude mcp add --transport http ghosty-docs https://www.ghosty.studio/mcp/docs`.
40
+
41
+ Without MCP, the same tools in plain HTTP:
42
+
43
+ ```bash
44
+ curl -s https://www.ghosty.studio/mcp/docs -H 'Content-Type: application/json' \
45
+ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_docs","arguments":{"query":"whatsapp"}}}'
46
+ ```
47
+
48
+ ## Rules
49
+
50
+ - Search, then read one page. Do not read `llms-full.txt` for a single question.
51
+ - Quote the page URL you used when you answer; the user may want to open it.
52
+ - JSON field names in the API (`agentes`, `enCola`, `reemplazoAnterior`…) are the contract and
53
+ are the same in both languages: do not translate them.
54
+ - To *change* an agent (identity, files, skills, MCPs) use the `ghosty-agent` skill, which has
55
+ the token flow. This skill is read-only.
@@ -0,0 +1,71 @@
1
+ ---
2
+ name: ghosty-recipe
3
+ description: Write, review or convert a Ghosty Studio agent recipe (the portable .recipe.yaml with title, instructions, model and channels) so it can be uploaded in "Nuevo agente → Plantilla". Use when the user wants to create a Ghosty agent from a spec, turn a persona or job description into an agent, export/share an agent, or mentions a Ghosty recipe or recipe.yaml.
4
+ license: MIT
5
+ compatibility: No network needed to write a recipe; uploading it happens in the Ghosty Studio panel
6
+ metadata:
7
+ author: ghosty-studio
8
+ version: "1.0"
9
+ ---
10
+
11
+ # Ghosty agent recipes
12
+
13
+ A recipe is a YAML file that fully describes an agent **without secrets**: who it is, how it
14
+ talks, which model, which channels. It is what Ghosty Studio exports from an agent
15
+ (`/app/agents/<id>/recipe.yaml`) and what "Nuevo agente → Plantilla → sube una receta"
16
+ imports. The format is Goose-compatible plus an `x-ghosty` block.
17
+
18
+ ## Write one
19
+
20
+ ```yaml
21
+ version: "1.0.0"
22
+ title: Nora, recepción de Dental Sur # ≤ 60 chars, shown as the agent's name
23
+ description: Agenda citas y resuelve dudas de la clínica por WhatsApp. # ≤ 200 chars, one line
24
+ instructions: |
25
+ Eres Nora, asistente de la clínica Dental Sur.
26
+
27
+ ## Cómo hablas
28
+ Español de México, corto, sin diagnósticos.
29
+
30
+ ## Qué sabes hacer
31
+ - Agendar, mover y cancelar citas.
32
+ - Explicar precios de la lista que tienes en tu workspace.
33
+
34
+ ## Qué NO haces
35
+ - No das diagnósticos ni recetas.
36
+
37
+ ## Cuándo preguntas
38
+ Sólo cuando la respuesta cambia el resultado.
39
+ settings:
40
+ goose_model: claude-sonnet-5
41
+ x-ghosty:
42
+ engine: ghosty-lite
43
+ channels: { teams: true, whatsapp: true }
44
+ ```
45
+
46
+ Field-by-field rules are in `references/schema.md`. Read it before validating a recipe.
47
+
48
+ ## Rules
49
+
50
+ - **`title` is required**; everything else is optional but a recipe without `instructions` is
51
+ useless. Write instructions in the user's language and in second person.
52
+ - **Never a colon followed by a space inside `description`** unless the value is quoted
53
+ (`description: "Ventas: WhatsApp"`): unquoted it is a YAML parse error and the whole
54
+ recipe is skipped.
55
+ - Structure `instructions` with the four headings the house templates use: *Cómo hablas*,
56
+ *Qué sabes hacer*, *Qué NO haces*, *Cuándo preguntas* (plus *Formato* for Teams agents).
57
+ Keep it under ~3,000 characters: it is prepended to every conversation.
58
+ - Engines: `ghosty-lite` or `goose` when the agent needs its own machine (files, skills,
59
+ MCPs); `claude`, `codex`, `deepseek` for prompt-only agents. Models must be one the engine
60
+ offers (`claude-sonnet-5`, `claude-opus-5`, `claude-haiku-4-5-20251001`…); when unsure,
61
+ omit `settings` and let the panel pick.
62
+ - No tokens, keys, phone numbers or URLs with credentials in a recipe: it is meant to be
63
+ pasted in an email.
64
+ - Prefer converting what the user already has (a job description, an old system prompt)
65
+ over inventing; ask only for what changes the result.
66
+
67
+ ## Deliver
68
+
69
+ Give the YAML in a fenced block and tell the user: save it as `<name>.recipe.yaml`, then in
70
+ Ghosty Studio → **Agentes → Nuevo agente → Plantilla → sube una receta**. To tune it after
71
+ creation, use the `ghosty-agent` skill (needs the agent token).
@@ -0,0 +1,30 @@
1
+ # Recipe schema (v1.0.0)
2
+
3
+ Source of truth: `parseRecipe` in Ghosty Studio. Unknown keys are ignored, never rejected.
4
+
5
+ | Key | Type | Required | Notes |
6
+ |---|---|---|---|
7
+ | `version` | string | no | defaults to `"1.0.0"` |
8
+ | `title` | string | **yes** | trimmed, cut at 60 chars; becomes the agent's name |
9
+ | `description` | string | no | trimmed, cut at 200 chars; one line, quote it if it contains `: ` |
10
+ | `instructions` | string | no | the system prompt; use a block scalar (`|`) |
11
+ | `settings.goose_provider` | string | no | Goose-compatible; usually omitted |
12
+ | `settings.goose_model` | string | no | model id; must exist for the chosen engine |
13
+ | `extensions` | list | no | Goose extensions; kept as-is, Ghosty ignores them today |
14
+ | `x-ghosty.engine` | string | no | `ghosty-lite` · `goose` · `claude` · `codex` · `deepseek` |
15
+ | `x-ghosty.model` | string \| null | no | same as `settings.goose_model`; the panel reads either |
16
+ | `x-ghosty.channels` | object | no | `{ teams?: bool, web?: bool, whatsapp?: bool }`; default `{ teams: true }` |
17
+ | `x-ghosty.creatorVersion` | string | no | written by exports; do not set by hand |
18
+
19
+ ## Validation checklist
20
+
21
+ 1. Parses as YAML (no unquoted `: ` in scalars, consistent indentation, block scalar for `instructions`).
22
+ 2. `title` present and non-empty.
23
+ 3. `instructions` in second person, in the user's language, with the four headings.
24
+ 4. No secrets.
25
+ 5. If `settings.goose_model` is set, it is a real model id for that engine.
26
+
27
+ ## Exporting an existing agent
28
+
29
+ `GET https://www.ghosty.studio/app/agents/<id>/recipe.yaml` (logged-in browser) downloads
30
+ `<name>.recipe.yaml` with the same shape, secrets stripped.