← CorezoidCONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to Corezoid
Snapshot Oct 9, 2026 · 00:04 UTC · version 3.9.0
Collection source: downloaded plugin package.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"description": "Iteratively edits an already-built messenger bot from corezoid-gen-bot — a Corezoid Communications Orchestrator serving Telegram, Viber, Apple Messages for Business and Facebook Messenger over a backend of Corezoid processes called with api_rpc. Runs a lean plan → confirm → apply → lint → push → smoke-test loop — see \"Modes\" for plan/execute/deploy. Trigger on \"измени/поправь бота\", \"добавь/убери/переименуй команду\", \"подключи ещё процесс\", \"поменяй текст/клавиатуру бота\", \"добавь язык боту\", \"добавь шаг в диалог\", \"бот отвечает пустым/дважды\", \"почему бот не отвечает\", \"edit/modify bot\", \"add command to bot\", \"wire another process into the bot\", \"change bot copy\", \"fix the bot\", \"задеплой бота\", \"promote stage\", or when the user references PLAN.md/CHANGE.md for a bot. Assumes CWD is the workspace corezoid-gen-bot built (`.corezoid-gen-bot/PLAN.md`, a `*.stage.json` marker, the pulled orchestrator folder). For a Smart Form web app over the same processes use `simulator-app-generator`.",
"included_files": [
{
"relative_path": "references/change_kinds.md",
"size_in_bytes": 11178
},
{
"relative_path": "references/invariants.md",
"size_in_bytes": 13754
},
{
"relative_path": "references/repair_loop.md",
"size_in_bytes": 6615
},
{
"relative_path": "references/rules.md",
"size_in_bytes": 8774
},
{
"relative_path": "references/step4_apply_change.md",
"size_in_bytes": 9290
},
{
"relative_path": "references/step5_lint_push.md",
"size_in_bytes": 2433
},
{
"relative_path": "references/step6_verify.md",
"size_in_bytes": 6512
},
{
"relative_path": "references/step7_report.md",
"size_in_bytes": 1355
}
],
"name": "corezoid-edit-bot",
"skill_md_contents": "---\nname: corezoid-edit-bot\ndescription: Iteratively edits an already-built messenger bot from corezoid-gen-bot — a Corezoid Communications Orchestrator serving Telegram, Viber, Apple Messages for Business and Facebook Messenger over a backend of Corezoid processes called with api_rpc. Runs a lean plan → confirm → apply → lint → push → smoke-test loop — see \"Modes\" for plan/execute/deploy. Trigger on \"измени/поправь бота\", \"добавь/убери/переименуй команду\", \"подключи ещё процесс\", \"поменяй текст/клавиатуру бота\", \"добавь язык боту\", \"добавь шаг в диалог\", \"бот отвечает пустым/дважды\", \"почему бот не отвечает\", \"edit/modify bot\", \"add command to bot\", \"wire another process into the bot\", \"change bot copy\", \"fix the bot\", \"задеплой бота\", \"promote stage\", or when the user references PLAN.md/CHANGE.md for a bot. Assumes CWD is the workspace corezoid-gen-bot built (`.corezoid-gen-bot/PLAN.md`, a `*.stage.json` marker, the pulled orchestrator folder). For a Smart Form web app over the same processes use `simulator-app-generator`.\n---\n\n# corezoid-edit-bot\n\nFollow-up skill to [[corezoid-gen-bot]]. Edits an orchestrator that already\nexists. Reuses the same PLAN.md as the architectural source of truth, layers a\nper-change `CHANGE.md` on top, and never re-audits the domain processes unless\nthe user asks for `corezoid-gen-bot refresh`.\n\nAn edit is riskier than a build, for one reason: **the bot is live and someone\nis talking to it.** A build that is wrong is a bot nobody has used yet; an edit\nthat is wrong breaks a working conversation, and most of the ways it breaks are\nsilent — nothing fails at push time, the chat just misbehaves. So this skill's\nweight is not in generation, it is in knowing what a request is allowed to\ntouch and in proving afterwards that the *user* sees the right thing, which is\nstrictly more than proving the graph ran.\n\nRead these before touching anything:\n\n| Document | What it settles |\n|---|---|\n| `${CLAUDE_PLUGIN_ROOT}/skills/corezoid-edit-bot/references/change_kinds.md` | what each request kind may touch, its verification, and what this skill deliberately cannot do |\n| `${CLAUDE_PLUGIN_ROOT}/skills/corezoid-edit-bot/references/invariants.md` | the send-side and dispatch invariants every change must preserve — all of them silent when broken |\n| `${CLAUDE_PLUGIN_ROOT}/skills/corezoid-edit-bot/references/repair_loop.md` | symptom → cause → the layer at fault, and when to stop looping and report |\n| `${CLAUDE_PLUGIN_ROOT}/skills/corezoid-gen-bot/references/template_map.md` | the orchestrator's own contracts (Router, Send Message, Localization, Attachments) |\n| `${CLAUDE_PLUGIN_ROOT}/skills/corezoid-gen-bot/references/contract_extraction.md` | how to read a domain process — needed for `wire-process` and `process-remap` |\n| `${CLAUDE_PLUGIN_ROOT}/skills/corezoid-gen-bot/references/rpc_call.nodes.json` | the `api_rpc` / `api_copy` / state-read fragments |\n| `${CLAUDE_PLUGIN_ROOT}/skills/corezoid-gen-bot/references/bot_reply.skeleton.json`, `bot_dialog.skeleton.json` | the two command shapes, for a new command |\n| `${CLAUDE_PLUGIN_ROOT}/skills/corezoid-gen-bot/references/attachments.seed.json`, `localization.seed.json` | per-channel attachment shapes, per-page caps, interpolation rules |\n\nLoad them with the `Read` tool. `${CLAUDE_PLUGIN_ROOT}` resolves to the\ninstalled plugin root; a bare `references/…` does **not** — this skill runs with\nthe Corezoid workspace as the working directory. Every short\n`references/<file>` named later in this document is under\n`${CLAUDE_PLUGIN_ROOT}/skills/corezoid-edit-bot/references/`, and every\n`corezoid-gen-bot/references/<file>` under\n`${CLAUDE_PLUGIN_ROOT}/skills/corezoid-gen-bot/references/`.\n\nSteps 4–7 (execute mode) are each detailed in their own reference file — load\nthe one for the step you're about to run, not all of them up front:\n\n| Document | Step |\n|---|---|\n| `${CLAUDE_PLUGIN_ROOT}/skills/corezoid-edit-bot/references/step4_apply_change.md` | Step 4 — apply the change |\n| `${CLAUDE_PLUGIN_ROOT}/skills/corezoid-edit-bot/references/step5_lint_push.md` | Step 5 — lint and push |\n| `${CLAUDE_PLUGIN_ROOT}/skills/corezoid-edit-bot/references/step6_verify.md` | Step 6 — verify (and Step 6b — deploy mode) |\n| `${CLAUDE_PLUGIN_ROOT}/skills/corezoid-edit-bot/references/step7_report.md` | Step 7 — update PLAN.md and report |\n| `${CLAUDE_PLUGIN_ROOT}/skills/corezoid-edit-bot/references/rules.md` | Full rule list — read before Step 4 |\n\n## When to use\n\n- CWD is a corezoid-gen-bot workspace: `.corezoid-gen-bot/PLAN.md` with a\n non-null `orchestrator.folder_id`, a `*.stage.json` marker, and the pulled\n orchestrator folder on disk.\n- User wants to add/remove/rename a command, wire in another Corezoid process,\n change copy or a keyboard, add a language, add or drop a dialog step, remap a\n command onto a different process or argument, fix a bug, or promote a stage.\n- **Not for adding or removing a messenger channel** — the wizard is not\n incremental. See `references/change_kinds.md`.\n- **Not for contract drift in the domain processes** — if a handed-in process\n changed (lost a reply node, got paused, gained an alternate outcome), run\n `/corezoid-gen-bot refresh` first so PLAN.md and `bot-contract.json` reflect\n reality, then come back.\n- **Not for building from scratch** — that is [[corezoid-gen-bot]], and running\n it again here would build a whole second orchestrator that steals the\n webhooks from this one.\n\n## 0. Preflight — the tools, and the three things none of them can do\n\nCorezoid MCP tools this skill uses directly: `pull-process`, `pull-folder`,\n`push-process`, `lint-process`, `layout-process`, `create-process`,\n`delete-process`, `pause-process`, `resume-process`, `create-alias`,\n`run-task`, `deploy-stage`.\n\nThe rest are **actions of a router tool** — call them as\n`<router> {\"action\": \"<action>\", \"args\": {…}}`, every argument inside `args`:\n\n| Action | Router |\n|--------|--------|\n| `show-task`, `modify-task`, `list-task-history`, `list-node-tasks` | `cz-tasks` |\n| `create-variable`, `modify-variable` | `cz-variables` |\n| `create-snapshot` | `cz-snapshots` |\n\nAdd `\"help\": true` to any of them to get its full argument schema back without\nrunning it. Missing → tell the user to install the Corezoid plugin and run\n`/corezoid-init`.\n\nThree things are **not possible** with this toolset. Say so plainly rather than\nimprovising something that looks like it worked:\n\n1. **An alias cannot be deleted, repointed or renamed.** `create-alias` is the\n only alias tool in the plugin — there is no delete, modify, unlink or list\n counterpart. So a name once taken is taken for good, a rename means\n *creating a second alias* and leaving the first one dangling, and removing a\n command does not free its name. Removing or repointing an alias needs raw\n Corezoid API calls — hand that to `corezoid:corezoid-alias-manager` with the\n user's agreement, and until it is done, describe the alias as still live.\n2. **A channel cannot be added to or removed from an existing orchestrator.**\n `create-communications-orchestrator` builds a whole folder including the\n per-channel receiver and API-method processes; there is nothing to graft onto.\n3. **An orchestrator build cannot be undone.** Which is why this skill never\n calls the wizard: a second build steals the webhook from the first and leaves\n ~150 dead processes behind.\n\n**Stage resolution: probe, do not refuse.** Most tools read the stage from the\n`<id>_<name>.stage.json` marker at the workspace root, but the MCP server also\nresolves it from `~/.corezoid/config.json` keyed by the working directory — so\na workspace that has been logged into but never pulled works with no marker.\nIf a marker is absent, try one `pull-process` before declaring a `login`\nproblem (see `corezoid-init`).\n\n## Modes\n\n| Invocation | Mode | What runs |\n|---|---|---|\n| `/corezoid-edit-bot plan <ask>` (or \"спланируй изменение\", \"just plan\") | **plan** | Steps 1–3: understand → write `.corezoid-gen-bot/CHANGE.md` → summary, stop |\n| `/corezoid-edit-bot execute` (or \"погнали\", \"execute\", \"сделай\") | **execute** | Steps 4–7: apply → lint → push → seed tasks → smoke-test → report |\n| `/corezoid-edit-bot <ask>` no subcommand | **full** | Plan, print summary, **pause**, continue to execute after the user confirms |\n| `/corezoid-edit-bot deploy` (or \"задеплой\", \"promote stage\") | **deploy** | Step 6b only: `deploy-stage` dry-run → confirm → apply → verify |\n\n## Preconditions (every mode)\n\nVerify before doing anything else. If any fails, stop and say what to run.\n\n- `.corezoid-gen-bot/PLAN.md` exists and `orchestrator.folder_id` is non-null.\n Missing or null → point at `/corezoid-gen-bot plan <process ids>` (or, if the\n folder exists in Corezoid but not in PLAN.md, ask for the folder id and fill\n the block in — do **not** call the wizard).\n- `template_ids` in PLAN.md is populated. If it is not, pull (below) and fill it\n in before planning anything — a change that guesses an id writes into another\n workspace's process.\n- `.corezoid-gen-bot/bot-contract.json` exists. It is the derived contract of\n every domain process the bot calls; without it any change to a domain call is\n a guess. Missing → run `/corezoid-gen-bot refresh` to regenerate it.\n- **The pulled mirror is current.** Pull before planning: someone may have\n edited the orchestrator in the Corezoid UI since the last pull, and\n `push-process` will block on the concurrency gate anyway — pulling first turns\n that block into a diff you can read.\n\n ```\n pull-folder folder_id: {obj_id from <stage_id>_<name>.stage.json} # the STAGE id\n ```\n\n **`folder_id` is a required argument, and the value must be the stage id — never\n the orchestrator's `folder_id`.** `pull-folder` unzips a server-produced archive\n into the **stage root** (the `RootPath` registered for this workspace, not the\n cwd) and picks the archive by what the id turns out to be: the stage id fetches\n the whole stage, a *sub*folder id fetches only that folder and still unzips it\n at the stage root. So passing the orchestrator's id spills its contents over\n the stage root, the `<folder_id>_Communications_Orchestrator/` directory never\n appears, and every id read afterwards comes from the wrong tree. (`folder_id: 0`\n is a third thing again — a workspace-root \"No Project\" pull.)\n\n After the pull, find the orchestrator by its `<folder_id>_` name prefix, where\n `folder_id` is `orchestrator.folder_id` from PLAN.md. If that directory is\n absent, stop and say so — do not plan against whatever else the pull produced.\n\n ```bash\n stage_root=\"$(dirname \"$(ls */*.stage.json *.stage.json 2>/dev/null | head -n1)\")\"\n orch=\"$stage_root/{orchestrator.folder_id}_Communications_Orchestrator\"\n ls -d \"$orch\" || { echo \"orchestrator folder not found — wrong pull scope or wrong stage\"; exit 1; }\n ```\n\n- **Re-read `template_ids` off that directory** rather than trusting PLAN.md's\n copy blindly: the wizard mints fresh ids per build and a stale id fails\n silently — the task simply never arrives. Ids in\n `corezoid-gen-bot/references/template_map.md` are examples from one build and\n must never be copied into a process.\n- If the workspace is a git repo, the working tree is clean **or** the only\n dirty files are ones the user is currently discussing. `pull-folder` and\n `pull-process` overwrite local files; a dirty file is somebody's unpushed work.\n\n## Step 1: Understand the ask\n\nParse the request into one kind from `references/change_kinds.md`. Ask at most\none `AskUserQuestion`, and only for a slot you genuinely cannot infer.\n\n| Kind | Mandatory slots | Inferable from PLAN.md |\n|---|---|---|\n| add-command | backing process, command name | shape, skeleton, texts, keyboard, menu position |\n| remove-command | command | dependent texts, buttons, alias (which survives) |\n| rename-command | old, new | process title, payloads, menu; the new alias |\n| copy | which text and the new wording | `text_id`, locales, which processes send it |\n| keyboard | which command, what changes | `attachment_id`, per-channel shapes |\n| add-locale | the new language code | every key needing a translation |\n| dialog-step | which command, what the new step asks | `text_id`, validation regex from the contract |\n| wire-process | process id, what the command should do with it | callability, inputs, outcomes — from `bot-contract.json`, or re-derived if absent |\n| process-remap | command, new process or new argument mapping | `api_rpc` `extra`, outcome mapping, whether namespacing is now required |\n| bugfix | symptom + one repro | root cause, the smoke test to add |\n| template-edit | the exact process and why no command-level change works | — (never inferred) |\n| deploy | source stage, target stage | project and workspace ids |\n\nCross-reference PLAN.md's `Commands`, `Coverage`, `Localization keys`,\n`Attachments`, `Menu wiring` and `template_ids`, plus `bot-contract.json`,\nbefore answering anything yourself — those are the contract. **Never re-extract\na domain contract for an edit** unless the user asks for `refresh`; use what\nPhase 2 captured.\n\n### 1.1 The blast radius is bigger than the request, in two specific ways\n\nWork both out here, not in Step 6 when the fix is expensive:\n\n- **New or changed copy that carries a `{{placeholder}}` is a process change,\n not a task change.** Send Message is called with `group: \"\"`, so it receives\n only the fields named in the calling node's `data`; a `{{var}}` in the\n resolved text that was not forwarded arrives in the chat as the literal\n `{{var}}`. So \"just change the wording\" stops being Localization-only the\n moment the new wording interpolates something the sending node does not\n already forward. Find every sender before promising a one-task change:\n\n ```bash\n grep -rln '\"text_id\": *\"balanceDone\"' \"$orch\" # who sends this text\n ```\n\n Then check the placeholders against that node's `data` and against the\n process's `success.keys` in `bot-contract.json`. Full rule in\n `references/invariants.md` §1.\n- **A shared key is a global change.** `mainMenu`, `mainKeyboard`,\n `serviceError`, `timeout`, `commandNotFound`, `selectError`, `yes`/`no` and\n `carouselPattern` are referenced by every command and by the Router itself.\n Editing one has a `template-edit`-sized regression scope even though it\n touches no process: set `regression_scope: all` in CHANGE.md and smoke-test\n every command.\n\n### 1.2 For `wire-process` and `process-remap`\n\nAnswer the callability question first (`contract_extraction.md` §2): a\n`process` with a reachable `api_rpc_reply` gets `api_rpc`; one without gets\n`api_copy` and a command that can only acknowledge; a `state` gets an inline\n`set_param`; a paused one gets nothing until the user says otherwise. An\n`api_rpc` into a paused or reply-less process parks the task until the semaphore\nfires — the user waits the full 30 s for an error, and `params` does not reveal\nit.\n\nTo answer it you need the process's file. **Look on disk before pulling:**\n`find \"$stage_root\" -name \"<id>_*.conv.json\"` — the workspace is an\nalready-pulled stage and the process is very likely there. Match the `<id>_`\nprefix exactly, so `1906756_` is not satisfied by `11906756_`. Only\n`pull-process(process_id=<id>)` when it is absent, and never over a file that is\ndirty in git without asking: `pull-process` overwrites, taking the unpushed edit\nwith it. Record in CHANGE.md whether the contract came from a reused file (with\nits mtime) or a fresh pull — a reused snapshot is of unknown age, and wiring\nagainst a stale contract is how a call starts sending an empty `extra` key.\n\n**Never probe a domain process automatically.** `run-task` against somebody\nelse's process can send a real SMS or charge a real card. Show the side-effect\nclassification from `bot-contract.json` and let the user authorise each probe.\nThe same caution applies to the smoke test in Step 6: a command whose side\neffects are `likely` or `unknown` fires them for real, so agree a safe test\ninput with the user first, or exercise only the dialog up to the confirm step.\n\n### 1.3 For `add-command` and `rename-command`, settle the alias now\n\nThe alias *is* the dispatch mechanism: the Router computes\n`commandAlias = command.replace(\"/\",\"\")` and calls `@{{commandAlias}}`. There is\nno registration table to edit, and no way to fix a bad name later — see §0.\n\n- `^/[a-z0-9][a-z0-9-]{2,}$` after the slash. A camelCase command deploys fine\n and is unreachable forever.\n- Never `/start`, `/end` or `/exit` — Main, Router and System Diagram consume\n them.\n- **Check the name against `_ALIASES_.json` at the stage root, which is the\n authoritative list** — a fresh orchestrator ships ~60 aliases. Do not work\n from a remembered list of sample-bot names.\n\n ```bash\n python3 - <<'EOF'\n import json\n taken = {a['short_name']: a.get('obj_to_id') for a in json.load(open('_ALIASES_.json'))}\n for c in ['order-status']: # candidate commands, minus the slash\n print(c, '->', 'FREE' if c not in taken else 'TAKEN by %s' % taken[c])\n EOF\n ```\n\n Watch for `obj_to_id: null`: a dangling row holds the name just as firmly as a\n live one, and `@name` currently resolves to nothing, so anything already\n dispatching there answers `commandNotFound`. You cannot reclaim it from the\n plugin — pick another name, or ask the owner to delete the row in the Corezoid\n UI, and say which you did. If `_ALIASES_.json` is not on disk, say the name is\n unverified rather than assuming it is free.\n- **A rename does not move the old name.** The new command needs a new alias;\n the old alias stays and keeps pointing at the (now renamed) process, so the\n old command keeps working unless its alias is deleted through the raw API.\n State that in CHANGE.md and in the report rather than claiming the old command\n is gone.\n\n## Step 2: Write `.corezoid-gen-bot/CHANGE.md`\n\nOverwrite (do not append):\n\n````markdown\n---\nkind: {add-command|remove-command|rename-command|wire-process|process-remap|copy|keyboard|add-locale|dialog-step|bugfix|template-edit|deploy}\ntitle: {one-line title}\nask: {verbatim user request, single paragraph}\ncommands_affected: [{/command}, …]\nprocesses_touched: [{path}, …]\nprocesses_created: [{name → folder}, …]\nprocesses_deleted: [{id, path}, …]\ntasks_touched: [{process: localization|attachments, ref: {ref}}, …]\ntext_ids_touched: [{text_id}, …]\nattachment_ids_touched: [{attachment_id}, …]\nforwarding_impact: [{process path → send node → keys that must now be forwarded}, …]\nenv_vars_touched: [{short_name}, …]\naliases_to_create: [{short_name → process}, …]\naliases_left_dangling: [{short_name → why it cannot be removed}, …]\ndomain_processes: [{id, title, callable: api_rpc|api_copy|state|paused, source: local <mtime>|pulled}, …]\nnamespacing_required: {true|false} # true once a command makes 2+ domain calls\nside_effects: {none|unlikely|unknown|likely} # of anything the smoke test will fire\nregression_scope: {touched|all} # all for a shared key or a template edit\nmirror_pulled: {ISO-8601}\nplan_impact: {sections of PLAN.md this change edits, or \"none\"}\ntemplate_edit_confirmed: {true|false|n/a}\ntimestamp: {ISO-8601}\n---\n\n## Scope\n- Processes to create: {name → folder — what it does}\n- Processes to edit: {path — which nodes, by title}\n- Processes to delete or pause: {path — which, and why that one}\n- Aliases to create: {short_name → process}\n- Aliases that will survive this change: {short_name → consequence}\n- Domain calls to add / change: {process id, wiring, extra keys, semaphore}\n- Tasks to write: {process, ref, which keys, deep_merge yes/no}\n- Send-side forwarding to add: {process → send node → keys}\n- Menu changes: {mainKeyboard buttons, mainMenu text}\n- Coverage impact: {which PLAN.md coverage rows change}\n\n## Out of scope\n{Anything adjacent the user did not ask for. Name it so the diff stays honest.}\n\n## Smoke test that proves this change\n- {command} — `run-task` on the Router with `{data}` → expect {observable result}\n- {command} — `run-task` on **Send Message** with `{channel, chat_id, text_id, attachment_id, + interpolated values}` → expect `data.text` == {rendered string} and `reply_markup` {shape}\n- {for dialogs} follow-up `modify` into `{process}` ref `{channel}_{chat_id}` → expect {next question}\n- {for copy/keyboard} `show-task` on `{process}` ref `{ref}` → expect {keys}\n\n## Verification checklist\n- [ ] no `{{UPPER_CASE}}` placeholders left in any touched process\n- [ ] no channel token anywhere in the tree\n- [ ] `lint-process` clean on every touched process\n- [ ] alias present and equal to the command minus its slash\n- [ ] every `api_rpc` into a domain process has a `time` semaphore ≥ 30 s routed to a node that tells the user and copies `/end`\n- [ ] namespacing `api_code` present after every call, if the command now makes 2+\n- [ ] every referenced `text_id` exists in every locale the wizard created\n- [ ] every `{{placeholder}}` in a text is (a) a key of the sending node's `data` **and** (b) a key the process actually produces\n- [ ] `{{t'key}}` written with no dot; no dotted `{{a.b}}` in any text\n- [ ] every referenced `attachment_id` has one key per channel in `channels` (`facebook`, not `fbmessenger`)\n- [ ] dynamic attachments: `items` + `currentPage` forwarded; empty path sends `items: \"\"`, not `[]`\n- [ ] every path ends `text_id: \"\"` + non-empty `attachment_id` into the Router, or the reply is sent twice\n- [ ] ask/confirm steps use a reply `keyboard`, not `inline_keyboard`\n- [ ] smoke test above observed green, including the Send Message render\n- [ ] regression per `regression_scope` observed green\n````\n\n### Chat summary format\n\nPrint this and stop:\n\n```\n📝 CHANGE.md готов — {kind}: {title}.\nКоманды: {commands_affected}.\nПроцессы: {N} ({add} новых, {edit} правок, {del} удалений/пауз).\nЗадачи: {tasks_touched summary}.\nПроброс значений: {forwarding_impact summary, or \"не требуется\"}.\nРегрессия: {touched commands | все команды — общий ключ/шаблон}.\nПроверка: {one line naming the smoke test}.\n{One bullet per risk, if any — dangling alias, live side effects, shared key.}\n\nПоправить или /corezoid-edit-bot execute?\n```\n\nDo not proceed to Step 4 until the user says `execute` / `погнали` / `go`. For\n`kind: template-edit`, the confirmation must name the process — a bare \"go\" is\nnot consent to edit Router. For a change whose smoke test fires `likely` side\neffects, the confirmation must name that too.\n\n## Step 3: Refining CHANGE.md\n\nSame rules as corezoid-gen-bot §3a: targeted `Edit`s, re-print the summary, one\nsentence of prose at most. Never widen the scope silently — if the user's\nfollow-up is a different change kind, rewrite CHANGE.md rather than appending\nto it. Never re-extract a domain contract for a CHANGE.md edit.\n\n## Step 4: Apply the change\n\nRead `references/step4_apply_change.md` before running this step.\n\nWork only inside `processes_touched`, `tasks_touched`, `env_vars_touched` and\nthe create/delete lists CHANGE.md named. Covers: `push-process` cannot create a\nprocess (create → pull for baseline → write → push); a new command starts from\nthe right skeleton with every `{{UPPER_CASE}}` placeholder substituted\n(`parent_id`/`user_id` are numeric, not string); edited commands are referenced\nby title, never a remembered id; removing a command prefers `pause-process` or\n`delete-process` over deletion, and the alias survives either way; a second\ndomain call in a command needs a namespacing `api_code`, not a `set_param`;\nevery new `{{var}}` in a text or a repointed call changes the Send Message\n`data` block too; and a handed-in domain process is never edited from this\nskill.\n\n## Step 5: Lint and push\n\nRead `references/step5_lint_push.md` before running this step.\n\nPer touched process: `layout-process` → `lint-process` → `push-process` →\n`create-alias` for new commands. Never `force=true` past a structural finding.\nA concurrent server change resolves with `merge=true` or a re-pull, never\n`overwrite_server_change` without showing the user the report first. A\nnever-deployed process is exempt from the snapshot gate; anything else that\nblocks on a snapshot should wait, not waive.\n\n## Step 6: Verify\n\nRead `references/step6_verify.md` before running this step.\n\nRun the CHANGE.md verification checklist in order, stopping at the first\nfailure: no leftover placeholders or tokens in the tree, clean lint, every\n`text_id`/`attachment_id` resolves in every seeded language and channel, the\nforwarding check (the one nothing else catches), the `/end` check, the touched\ncommand on its own via `run-task`, the message rendered through Send Message\n(not just the command's own task data), the CHANGE.md smoke test observed, and\nregression per `regression_scope`. `references/repair_loop.md` maps a symptom\nto the layer at fault. A clean lint is not a passing test.\n\n**Step 6b — deploy mode:** `deploy-stage` dry-run first, show the diff, then\n`apply: true` with the exact `confirm: \"<source>-><target>\"`. Re-run the Step 6\nsmoke test against the **target** stage afterward — aliases, env vars,\nLocalization/Attachments task data and domain processes are not guaranteed to\ncarry over, and a numeric `conv_id` promotes into a stage where it means\nsomething else or nothing. Full detail in `references/step6_verify.md`.\n\n## Step 7: Update PLAN.md and report\n\nRead `references/step7_report.md` before running this step.\n\nApply `plan_impact` to PLAN.md (`Commands`, `Coverage`, `Localization keys`,\n`Attachments`, `Menu wiring`, `locales`, `template_ids`) so it still describes\nthe live orchestrator, leave CHANGE.md as the record of this change, then\nreport: what changed, aliases left dangling, smoke-test results per command\nincluding the Send Message render, regression result, any waived gate, what\nthe user must do by hand, and `folder_url`.\n\n## Rules\n\nFull rule list, one per line with its reasoning: `references/rules.md`. Read it\nbefore Step 4 — it is a checklist to re-check against, not new material. The\nhandful that matter most, everywhere: never call\n`create-communications-orchestrator` from this skill (no undo, steals the\nwebhook from a live bot); `create-alias` is the only alias tool — an alias\ncannot be deleted, repointed or renamed; never hardcode a template process id,\nalways re-read `template_ids` from the pulled mirror; never rename a pulled\n`<ID>_<Title>.conv.json`; every `api_rpc` into a domain process needs a ≥30 s\n`time` semaphore and `group: \"\"` with an explicit `extra`; never edit a\nhanded-in domain process from this skill; never probe or smoke-test a\n`likely`/`unknown` side effect without the user's agreement; tokens and\ncredentials never touch a file; never call `EnterPlanMode`; cap the repair loop\nat about three passes per defect and report precisely what fails; report only\nwhat was observed — no command is green on the strength of a clean lint.\n"
}SHA-256 of public snapshot: 77882d52f66efe24d9ad96671fdf45564194eca3ad05a06827160378ccdc76d9