@sabaiway/agent-workflow-kit 1.3.0 → 1.5.0

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +70 -1
  2. package/README.md +15 -5
  3. package/SKILL.md +81 -9
  4. package/bin/install.mjs +59 -8
  5. package/bin/install.test.mjs +66 -0
  6. package/capability.json +21 -0
  7. package/migrations/1.1.0-communication-language.md +5 -5
  8. package/migrations/README.md +2 -1
  9. package/package.json +8 -5
  10. package/references/contracts.md +2 -2
  11. package/references/scripts/archive-changelog.mjs +1 -4
  12. package/references/templates/AGENTS.md +2 -2
  13. package/tools/delegation.mjs +109 -0
  14. package/tools/delegation.test.mjs +115 -0
  15. package/tools/detect-backends.mjs +310 -0
  16. package/tools/detect-backends.test.mjs +342 -0
  17. package/tools/inject-methodology.mjs +111 -0
  18. package/tools/inject-methodology.test.mjs +124 -0
  19. package/tools/manifest/fixtures/bad-available/SKILL.md +7 -0
  20. package/tools/manifest/fixtures/bad-available/capability.json +10 -0
  21. package/tools/manifest/fixtures/detect-array/SKILL.md +7 -0
  22. package/tools/manifest/fixtures/detect-array/capability.json +10 -0
  23. package/tools/manifest/fixtures/malformed-json/capability.json +1 -0
  24. package/tools/manifest/fixtures/metadata-version/SKILL.md +10 -0
  25. package/tools/manifest/fixtures/metadata-version/capability.json +9 -0
  26. package/tools/manifest/fixtures/missing-key/SKILL.md +7 -0
  27. package/tools/manifest/fixtures/missing-key/capability.json +8 -0
  28. package/tools/manifest/fixtures/missing-source/SKILL.md +7 -0
  29. package/tools/manifest/fixtures/missing-source/capability.json +11 -0
  30. package/tools/manifest/fixtures/nested-version-decoy/SKILL.md +10 -0
  31. package/tools/manifest/fixtures/nested-version-decoy/capability.json +9 -0
  32. package/tools/manifest/fixtures/null-root/capability.json +1 -0
  33. package/tools/manifest/fixtures/provides-roles-mismatch/SKILL.md +7 -0
  34. package/tools/manifest/fixtures/provides-roles-mismatch/bin/run.sh +2 -0
  35. package/tools/manifest/fixtures/provides-roles-mismatch/capability.json +11 -0
  36. package/tools/manifest/fixtures/stub/capability.json +10 -0
  37. package/tools/manifest/fixtures/traversal-source/SKILL.md +7 -0
  38. package/tools/manifest/fixtures/traversal-source/capability.json +11 -0
  39. package/tools/manifest/fixtures/unknown-schema/capability.json +9 -0
  40. package/tools/manifest/fixtures/valid/SKILL.md +10 -0
  41. package/tools/manifest/fixtures/valid/bin/run.sh +3 -0
  42. package/tools/manifest/fixtures/valid/capability.json +18 -0
  43. package/tools/manifest/fixtures/version-mismatch/SKILL.md +7 -0
  44. package/tools/manifest/fixtures/version-mismatch/capability.json +9 -0
  45. package/tools/manifest/fixtures/win-absolute-source/SKILL.md +7 -0
  46. package/tools/manifest/fixtures/win-absolute-source/capability.json +11 -0
  47. package/tools/manifest/schema.md +67 -0
  48. package/tools/manifest/validate.mjs +264 -0
  49. package/tools/manifest/validate.test.mjs +73 -0
  50. package/tools/methodology-slot.md +1 -0
  51. package/tools/release-scan.mjs +103 -0
  52. package/tools/release-scan.test.mjs +41 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,75 @@ Semantically versioned ([semver](https://semver.org)), newest first. The `versio
4
4
  is the current release. `upgrade` mode reads a project's `docs/ai/.workflow-version` and applies
5
5
  every `migrations/<version>-<slug>.md` newer than it, in semver order.
6
6
 
7
+ ## 1.5.0 — Backend detection (detect + guide)
8
+
9
+ The kit's onboarding can now **see the optional execution-backends** — the thin bridges to
10
+ subscription CLIs (`codex-cli-bridge` → `codex`, `antigravity-cli-bridge` → `agy`) — instead of
11
+ being blind to everything but the memory substrate. **Additive and read-only**: no `capability.json`
12
+ schema change, no validator change, no auto-install. Since nothing in the deployed `docs/ai/`
13
+ structure changes, **no migration is needed** and the deployment-lineage head stays `1.3.0`
14
+ (`upgrade` reconciles and re-stamps with nothing to apply).
15
+
16
+ - **`tools/detect-backends.mjs` — the read-only detector.** Pure, dependency-injectable,
17
+ dependency-free (Node ≥ 18), and already shipped (it lives under `tools/`, which is in the
18
+ package `files` + the installer `PAYLOAD`). It reports two **decoupled** axes so a healthy
19
+ manifest is never confused with a usable backend: `manifestState` (health of the bridge *skill*:
20
+ `not-installed | unsupported-schema | invalid-manifest | foreign | stub | ok`) and the readiness
21
+ signals `cli` / `credentials` / `wrappers`, probed **independently** for every registry entry even
22
+ when the skill is absent — so "the `codex` CLI is installed and signed in, but the bridge skill
23
+ isn't" reads as `needs-skill`, with the setup pointer. Every fs probe is wrapped → an explicit
24
+ `unknown` + reason, never a throw and never a nameless failure.
25
+ - **Detection is read-only — it never runs a subscription CLI.** "credentials present/missing" is
26
+ the existence of the credential-marker **file**, never a live `codex login status` / `agy` check
27
+ (which would spawn a paid, slow, networked CLI). The report deliberately never says
28
+ "authenticated" (a unit test asserts the word's absence).
29
+ - **Kit-owned registry (`KNOWN_BACKENDS`), not a schema change.** A missing bridge has no manifest
30
+ on disk and no `setup/README.md` in the kit tarball, so the per-backend facts (`bin`, credential
31
+ marker, stable setup URL) must live in the detector. A **drift-guard** test keeps the registry in
32
+ lockstep with the in-repo manifests (set equality with every `kind:execution-backend` dir, unique
33
+ names, `detect.installed` match, `setup/README.md` exists).
34
+ - **Two surfaces.** A new **`/agent-workflow-kit backends`** mode presents the table and, for any
35
+ backend that is not `ready`, points to its setup (local `setup/README.md` when installed, else the
36
+ setup URL). Bootstrap **step 11** also prints a one-line backends summary — read-only, and it
37
+ **never blocks the commit gate**. Honest about Windows: detection works, but the bridges' POSIX
38
+ `.sh` wrappers are not promised to run there.
39
+
40
+ ## 1.4.0 — Delegation-aware composition root (agent-workflow family, Plan 1)
41
+
42
+ The kit becomes the **composition root** of the new `agent-workflow` family. **Additive** — the
43
+ kit keeps its entire bundled substrate as a fallback, so the existing one-command install is
44
+ unchanged and **no migration is needed** (`upgrade` reconciles and re-stamps; the deployment
45
+ lineage head stays `1.3.0`). Published from the new `agent-workflow` monorepo.
46
+
47
+ - **Memory extracted to `@sabaiway/agent-workflow-memory`** — the memory substrate (`docs/ai/`,
48
+ the entry point, caps / archive / index, the three setup contracts) now also ships as its own
49
+ package. The kit **delegates** substrate deployment to it when a **kit-owned detector** finds it
50
+ valid, and otherwise uses its own bundled copy. Detection runs the kit's **own shipped**
51
+ `tools/manifest/validate.mjs` (never a validator shipped by the candidate) and requires
52
+ `kind: memory-substrate` **valid** plus all required assets present; unsupported / invalid /
53
+ unavailable / wrong-family / wrong-name → bundled fallback. The fallback decision is made
54
+ **before** any project write.
55
+ - **Family manifest contract** — every member ships a `capability.json` (`schema 1`, JSON,
56
+ dependency-free). The kit **owns and ships** the schema + validator at `tools/manifest/`
57
+ (in the tarball + installer `PAYLOAD`, so an installed kit can run the detector; root CI invokes
58
+ the same file). The kit's own manifest is `kind: composition-root`.
59
+ - **Methodology slot injection** — memory ships an **empty** delimited `workflow:methodology` slot
60
+ in `AGENTS.md`; the kit is its **only** writer, injecting a **bounded** summary + pointer
61
+ (`tools/inject-methodology.mjs` + `tools/methodology-slot.md`) that keeps `AGENTS.md` under its
62
+ ≤100-line cap. Marker contract: exactly one ordered pair → replace between; absent → no-op;
63
+ malformed → no-op with an error.
64
+ - **Two-stamp delegation hand-off** — delegated mode: memory writes `.memory-version`, the kit
65
+ injects + writes the fallback `.workflow-version` (→ both stamps); fallback mode: `.workflow-version`
66
+ only. Exactly **one** composition-level commit gate, owned by the kit, after injection. The
67
+ decision + hand-off matrix is codified and unit-tested in `tools/delegation.mjs`
68
+ (`detectMemory` + `handoffPlan`), so it does not depend on agent interpretation.
69
+ - **Release gate — attribution-off** — `tools/release-scan.mjs` fails on AI/reviewer attribution
70
+ (co-author trailers, "Generated with <AI>" footers) anywhere in the release tree, so no agent
71
+ attribution can ship by accident.
72
+ - **Hardened installer** — `copyRecursive` never writes *through* a destination symlink
73
+ (root / intermediate / leaf). `capability.json` + `tools/` added to `files` and the installer
74
+ `PAYLOAD`. `repository`/`homepage`/`bugs` repointed to the `agent-workflow` monorepo.
75
+
7
76
  ## 1.3.0 — Skill authoring aligned with Anthropic's Skills guidance
8
77
 
9
78
  Internal refinements to how the kernel itself is written — no change to what gets deployed into a
@@ -33,7 +102,7 @@ to apply). Drawn from [*Lessons from building Claude Code: how we use Skills*](h
33
102
  **Conversational language (dialogue only)**
34
103
 
35
104
  - **Bootstrap now asks the conversational language** — a new step 3 in `/agent-workflow-kit`, alongside the visibility question. The agent records the answer in a new *Communication language* block in the project's `AGENTS.md`, so every agent that reads the entry point talks to the user in that language and stops drifting between languages mid-session.
36
- - **Dialogue-only scope, by design** — the choice governs what the agent writes *for the user to read* (questions, explanations, summaries, status). Code, identifiers, file paths, shell commands, log output, and abbreviations stay in their source language; the deployed `docs/ai/` files and `AGENTS.md` stay English (the kernel stays English-only for cross-agent / cross-team portability). See the *Communication contract* in `SKILL.md`.
105
+ - **Dialogue-only scope, by design** — the choice governs what the agent writes *for the user to read* (questions, explanations, summaries, status). Code, identifiers, file paths, shell commands, log output, and abbreviations stay in their source language; the deployed `docs/ai/` files and `AGENTS.md` are not translated either (the conversational choice governs the chat, not the artifacts). See the *Communication contract* in `SKILL.md`.
37
106
  - **Existing deployments are covered** — `/agent-workflow-kit upgrade` backfills the block on a pre-1.1.0 project, asking the user their language. See `migrations/1.1.0-communication-language.md` (idempotent, additive).
38
107
 
39
108
  **Clearer install / upgrade guidance**
package/README.md CHANGED
@@ -12,7 +12,7 @@ instead of re-reading your whole repo.*
12
12
  [![license](https://img.shields.io/npm/l/@sabaiway/agent-workflow-kit)](./LICENSE)
13
13
  [![node](https://img.shields.io/node/v/@sabaiway/agent-workflow-kit)](https://nodejs.org)
14
14
 
15
- `v1.3.0` · `Node ≥ 18` · `kernel-only · English`
15
+ `v1.4.0` · `Node ≥ 18` · `kernel-only`
16
16
 
17
17
  **Works with any tool that reads `AGENTS.md`** — Claude Code · Codex · Cursor · Devin Desktop (formerly Windsurf) · GitHub Copilot · Gemini CLI · Cline · Aider · and 20+ more.
18
18
 
@@ -121,6 +121,12 @@ Then invoke it **inside a project** — first time vs. already-deployed use diff
121
121
 
122
122
  <sub>`/agent-workflow-kit` bootstraps a fresh deployment (and asks your **visibility**, **conversational language**, and whether the agent may **attribute work to itself / AI** — default off); `/agent-workflow-kit upgrade` migrates an existing one to the kit's current version. The `npx … init` above is a third, separate thing — it updates the **kit itself**, not any project.</sub>
123
123
 
124
+ > **New in 1.4.0 — optional memory substrate.** The memory layer is now also published
125
+ > standalone as [`@sabaiway/agent-workflow-memory`](https://www.npmjs.com/package/@sabaiway/agent-workflow-memory).
126
+ > If it is installed, the kit **delegates** substrate deployment to it and injects the workflow
127
+ > methodology; if not, the kit uses its **own bundled copy** — the one command above keeps
128
+ > working with no new dependency. Same `docs/ai/` either way.
129
+
124
130
  **Upgrade the kit itself** later — same command with `@latest`:
125
131
 
126
132
  ```bash
@@ -132,11 +138,12 @@ npx @sabaiway/agent-workflow-kit@latest init
132
138
  <details>
133
139
  <summary><b>Manual install</b> — no <code>npx</code></summary>
134
140
 
135
- The kit is a single self-contained folder. Clone it into a skill scope yourself, then run the launcher:
141
+ The kit is a single self-contained folder inside the `agent-workflow` monorepo. Clone the repo
142
+ and copy the kit into a skill scope yourself, then run the launcher:
136
143
 
137
144
  ```bash
138
- git clone https://github.com/sabaiway/agent-workflow-kit \
139
- ~/.claude/skills/agent-workflow-kit
145
+ git clone https://github.com/sabaiway/agent-workflow
146
+ cp -r agent-workflow/agent-workflow-kit ~/.claude/skills/agent-workflow-kit
140
147
  cd ~/.claude/skills/agent-workflow-kit
141
148
  bash launchers/install-launchers.sh
142
149
  ```
@@ -174,6 +181,7 @@ command is printed).
174
181
  |---------|------|--------------|
175
182
  | `/agent-workflow-kit` | new / empty project | recon → **asks visible-or-hidden** + **conversational language** + **agent attribution** (default off) → deploys `AGENTS.md` + `docs/ai/` filled with real recon data → installs enforcement → **asks before committing** |
176
183
  | `/agent-workflow-kit upgrade` | existing deployment | reads `docs/ai/.workflow-version`, shows the changelog diff, applies migrations, re-stamps |
184
+ | `/agent-workflow-kit backends` | any time | **read-only** check of the optional execution-backends (the `codex` / `agy` bridges): what's set up vs missing and the next step. Never writes, never commits, never runs a subscription CLI (credentials = marker-file presence, not a live login). |
177
185
 
178
186
  It **never auto-commits** and **never overwrites** an existing `AGENTS.md` without asking.
179
187
 
@@ -210,11 +218,13 @@ agent-workflow-kit/
210
218
  ├── README.md ← you are here
211
219
  ├── SKILL.md ← agent-facing algorithm
212
220
  ├── CHANGELOG.md ← version history
221
+ ├── capability.json ← agent-workflow family manifest (composition-root)
213
222
  ├── references/
214
223
  ├── templates/ ← AGENTS.md + every docs/ai file
215
224
  ├── scripts/ ← caps / archive / index + tests
216
225
  ├── contracts.md ← visibility / language / attribution rules
217
226
  └── planning.md ← plan lifecycle + continuity
227
+ ├── tools/ ← family tooling: manifest schema + validator, methodology-slot injection, backend detector (detect-backends)
218
228
  ├── launchers/ ← Codex / Devin Desktop / Cursor entries
219
229
  └── migrations/ ← per-version upgrade steps
220
230
  ```
@@ -222,5 +232,5 @@ agent-workflow-kit/
222
232
  ---
223
233
 
224
234
  <div align="center">
225
- <sub>Kernel-only · stack-agnostic · English · distilled from a multi-year-verified reference implementation.</sub>
235
+ <sub>Kernel-only · stack-agnostic · distilled from a multi-year-verified reference implementation.</sub>
226
236
  </div>
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: agent-workflow-kit
3
3
  description: Deploy or upgrade a portable AI-agent memory-and-workflow system in any project. Use when the user wants to bootstrap `docs/ai/` + an entry-point `AGENTS.md` (+ `CLAUDE.md` alias) + cap/archive/index enforcement in a new or existing repo, set up the Memory Map and session protocols, install the docs-rotation pre-commit hook, or run `/agent-workflow-kit` / `/agent-workflow-kit upgrade`. Triggers on phrases like "set up the memory system", "deploy the AI workflow here", "bootstrap docs/ai", "upgrade the workflow".
4
4
  disable-model-invocation: true
5
5
  metadata:
6
- version: '1.3.0'
6
+ version: '1.5.0'
7
7
  ---
8
8
 
9
9
  # agent-workflow-kit
@@ -12,18 +12,73 @@ Deploys a **portable AI-agent memory-and-workflow system** into a project, and u
12
12
 
13
13
  The kernel is **stack-agnostic workflow** — `docs/ai/` structure, entry-point doc, session protocols, plan lifecycle, frontmatter caps, 3-tier archive, index-freshness gate. Enforcement ships as **Node `.mjs` scripts** (the reference implementation; non-Node stacks follow the same policy manually).
14
14
 
15
- The kernel **artifacts** (this skill, the templates, the deployed `docs/ai/` files) are **English-only** — for cross-agent and cross-team portability. That is separate from the **conversational language**: the language the agent *talks to the user* in (questions, explanations, summaries, status). That is chosen once at bootstrap (step 3), recorded in the project's `AGENTS.md`, and applied to dialogue only — it never translates file contents, code, identifiers, paths, commands, or abbreviations.
15
+ The kernel **artifacts** (this skill, the templates, the deployed `docs/ai/` files) stay in their **source language** — for cross-agent and cross-team portability. That is separate from the **conversational language**: the language the agent *talks to the user* in (questions, explanations, summaries, status). That is chosen once at bootstrap (step 3), recorded in the project's `AGENTS.md`, and applied to dialogue only — it never translates file contents, code, identifiers, paths, commands, or abbreviations.
16
16
 
17
17
  This kernel is distilled from a canonical, battle-tested reference implementation. The skill is the single source of truth — projects deploy from it and upgrade against it.
18
18
 
19
19
  ---
20
20
 
21
- ## Two modes
21
+ ## Memory substrate: delegate or fall back (composition root)
22
+
23
+ This kit is the **composition root** of the `agent-workflow` family. The memory substrate
24
+ (`docs/ai/`, the entry-point doc, caps / archive / index, the setup contracts) is owned by
25
+ **`agent-workflow-memory`**. The kit **prefers to delegate** substrate deployment to that skill
26
+ when it is present and healthy, and otherwise uses its **own bundled copy** (`references/`,
27
+ `migrations/`) — so the existing one-command install keeps working with **no new dependency**.
28
+
29
+ **Detection (kit-owned, decided BEFORE any project write).** Run the kit's **own shipped**
30
+ validator — `node ${CLAUDE_SKILL_DIR}/tools/manifest/validate.mjs <memory-skill-dir>` — never a
31
+ validator shipped by the candidate (which could itself be broken). Delegate only when **all**
32
+ hold:
33
+ - result is **valid** and `kind` is `memory-substrate`;
34
+ - **every required asset is present** in the candidate, at its real path:
35
+ `references/templates/`, `references/contracts.md`, `references/scripts/`,
36
+ `scripts/stamp-takeover.mjs`, `migrations/`, `capability.json`. A partial install (manifest +
37
+ `SKILL.md` only) is treated as **invalid**.
38
+
39
+ On **unsupported** (unknown schema), **invalid**, **unavailable**, **wrong-family**, or
40
+ **wrong-name**, **use the bundled copy** — never block. The fallback decision is final once
41
+ made: a partial/broken memory install discovered mid-flow must not disable the working fallback.
42
+
43
+ > The **executable form** of this whole decision lives in
44
+ > [`tools/delegation.mjs`](tools/delegation.mjs): `detectMemory(<memory-dir>)` runs the validator +
45
+ > the required-asset check and returns `delegate` / fallback with a reason; `handoffPlan(delegate)`
46
+ > returns who writes what, which stamps end up present, and that the commit gate is kit-only. Both
47
+ > are unit-tested, so the contract below is pinned by code, not agent interpretation.
48
+
49
+ **Hand-off contract (explicit; tested independent of agent interpretation).**
50
+ - **Delegated** (memory valid): the kit passes the **target project dir** + the **three setup
51
+ answers** (visibility / language / attribution) to `agent-workflow-memory`, which writes
52
+ `docs/ai/` + `AGENTS.md` + **`.memory-version`**. The kit then **injects the bounded
53
+ methodology slot** (below) and writes the kit-fallback **`.workflow-version`**. → **both
54
+ stamps** present.
55
+ - **Fallback** (memory absent/invalid): the kit runs the bootstrap procedure below from its own
56
+ bundled assets and writes **`.workflow-version`** only. Softly suggest installing
57
+ `agent-workflow-memory` — never a prerequisite.
58
+
59
+ **Methodology injection (the kit is the ONLY writer of memory's slot).** After `AGENTS.md`
60
+ exists, inject the bounded methodology fragment into its `workflow:methodology` slot:
61
+ `node ${CLAUDE_SKILL_DIR}/tools/inject-methodology.mjs <project>/AGENTS.md`. It injects a short
62
+ summary + pointer (Phase-1 source: the kit's bundled `tools/methodology-slot.md`) — **not** the
63
+ full `references/planning.md` — and keeps `AGENTS.md` under its ≤100-line cap. Marker contract:
64
+ exactly one ordered `start → end` pair → replace only the bytes between them; markers absent →
65
+ no-op; any malformed state (single, reversed, nested, duplicate) → no-op **with an error**,
66
+ never edit.
67
+
68
+ **One composition-level commit gate.** The delegated memory mode performs **no** commit and
69
+ raises **no** "ask to commit". There is exactly **one** gate, owned by the kit, **after**
70
+ injection: report results and **ask before committing** — never auto-commit. No kit asset is
71
+ ever deleted.
72
+
73
+ ---
74
+
75
+ ## Modes
22
76
 
23
77
  Pick the mode from the user's invocation. Auto-detect an existing `docs/ai/` to guard against bootstrapping over a live system, but the user makes the final call.
24
78
 
25
79
  - **`/agent-workflow-kit`** (default) — bootstrap a new or empty project. If `docs/ai/` already exists, stop and ask whether they meant `upgrade`.
26
80
  - **`/agent-workflow-kit upgrade`** — upgrade an existing deployment to the skill's current `version`.
81
+ - **`/agent-workflow-kit backends`** — read-only environment check: which optional **execution-backends** (the `codex` / `agy` bridges) are set up vs missing. Never writes, never commits, never runs a subscription CLI.
27
82
 
28
83
  ### Mode: bootstrap
29
84
 
@@ -46,8 +101,13 @@ Pick the mode from the user's invocation. Auto-detect an existing `docs/ai/` to
46
101
  7. **Fill templates** per the table below.
47
102
  8. **Install enforcement (Node projects).** Copy `${CLAUDE_SKILL_DIR}/references/scripts/*.mjs` (+ `*.test.mjs`) into the project's `scripts/`. They self-configure (project name from `package.json`, hierarchical/on-demand sections auto-discovered). **If the project has no Node runtime** (step-1 recon), skip this step and the hook in step 9 — follow the cap/archive/index policy manually, or port the scripts to the project's language.
48
103
  9. **Wire / hide** per visibility (see contract). Install the pre-commit hook (Node projects): `node scripts/install-git-hooks.mjs`. If the installer reports a pre-existing non-marker hook, stop and ask the user to merge it manually rather than overwriting.
49
- 10. **Stamp version.** Write the skill's `version` into `docs/ai/.workflow-version` (one semver line).
50
- 11. **Report & ask.** Show `tree docs/ai/`, 2–3 lines on what was filled with real data vs left as TODO, then **ask before committing** never auto-commit.
104
+ 10. **Stamp the deployment lineage.** Write the **deployment-lineage head** into
105
+ `docs/ai/.workflow-version` (one semver line). The lineage head is **`1.3.0`**the shared
106
+ `agent-workflow` deployment lineage, **NOT** this kit's package version (`1.4.0`). The two are
107
+ independent axes: a packaging-only release bumps the package but leaves the lineage head until a
108
+ migration actually changes the deployed `docs/ai` structure. A stamp greater than the head →
109
+ STOP (never downgrade).
110
+ 11. **Report & ask.** Show `tree docs/ai/`, 2–3 lines on what was filled with real data vs left as TODO, then run the **backend detector** (`node ${CLAUDE_SKILL_DIR}/tools/detect-backends.mjs`) and print a one-line summary of the optional execution-backends (e.g. `backends: codex ✓ ready · antigravity ✗ needs-credentials — run /agent-workflow-kit backends`). This is **read-only and never blocks the commit gate**. Then **ask before committing** — never auto-commit.
51
111
 
52
112
  Fill strategy:
53
113
 
@@ -61,12 +121,22 @@ Fill strategy:
61
121
 
62
122
  ### Mode: upgrade
63
123
 
64
- 1. Read `docs/ai/.workflow-version` (the project's stamped version). If missing, treat as a pre-versioned deployment and offer to re-bootstrap conservatively.
65
- 2. Compare to this skill's `metadata.version` (frontmatter). If equal → report "up to date" and stop.
124
+ 1. Read `docs/ai/.workflow-version` (the project's stamped lineage). If missing, treat as a pre-versioned deployment and offer to re-bootstrap conservatively.
125
+ 2. Compare to the **deployment-lineage head** (`1.3.0` — NOT this kit's package version). If equal → report "up to date" and stop. If the stamp is **greater than the head** or unparseable → **STOP and report** (never downgrade).
66
126
  3. Show the relevant `${CLAUDE_SKILL_DIR}/CHANGELOG.md` diff (entries newer than the project's stamp).
67
127
  4. Apply `${CLAUDE_SKILL_DIR}/migrations/<version>-<slug>.md` in **semver order**, only those newer than the project's stamp. Migrations are **idempotent** — safe to re-run.
68
128
  5. Reconcile drift: add any kernel files/scripts the project is missing; never clobber project-authored content (their `decisions.md`, `known_issues.md`, page specs stay). Any user question a migration raises follows the same rule as bootstrap — **structured multiple-choice where supported** (`AskUserQuestion` in Claude Code), otherwise prose. If `AGENTS.md` has no *Communication language* block (pre-1.1.0 deployment), **ask the user their conversational language** and insert the block — see `migrations/1.1.0-communication-language.md`. If it has no *Attribution* block (pre-1.2.0 deployment), **ask whether the agent may attribute work to itself / AI** and insert the block (defaulting to `off`) — see `migrations/1.2.0-agent-attribution.md`.
69
- 6. Re-stamp `docs/ai/.workflow-version` to the skill's `version`. Report changes; **ask before committing**.
129
+ 6. Re-stamp `docs/ai/.workflow-version` to the **deployment-lineage head** (`1.3.0`, not the package version). Report changes; **ask before committing**.
130
+
131
+ ### Mode: backends
132
+
133
+ Read-only. Answers *"which optional execution-backends are set up vs missing, and what's the next step?"* — for the family's subscription-CLI bridges (`codex-cli-bridge` → `codex`, `antigravity-cli-bridge` → `agy`). It **never writes, never commits, and never runs a subscription CLI**.
134
+
135
+ 1. Run `node ${CLAUDE_SKILL_DIR}/tools/detect-backends.mjs` and present its table verbatim. Each row reports two **decoupled** axes: `manifestState` (health of the bridge *skill* — `not-installed | unsupported-schema | invalid-manifest | foreign | stub | ok`) and the readiness signals `cli` / `credentials` / `wrappers`, probed independently — so a CLI that is installed and signed in but whose bridge *skill* is absent reads `needs-skill`, not "missing".
136
+ 2. For any backend that is not `ready`, point to its setup: the local `setup/README.md` when the bridge is installed, otherwise the backend's setup URL (both are in the report).
137
+ 3. State plainly to the user that this is **detection only**:
138
+ - **"credentials present"** means the credential-marker **file** exists — it is **not** a live login check. The detector never runs `codex login status` / `agy` (that would spawn a paid, slow, networked subscription CLI).
139
+ - The bridges' wrappers are **POSIX `.sh`** scripts. On Windows the detector still works, but the bridges themselves are **not promised to run** — say so rather than implying they will.
70
140
 
71
141
  ---
72
142
 
@@ -80,7 +150,7 @@ The non-obvious traps — scan these before bootstrapping or upgrading. Each is
80
150
  - **`CLAUDE.md` is a symlink, not a copy.** `ln -s AGENTS.md CLAUDE.md` — single source, no duplication. A copy drifts; a symlink can't.
81
151
  - **Never overwrite an existing entry point or hook.** If `AGENTS.md` / `CLAUDE.md` already exist, or the installer reports a pre-existing non-marker git hook, **stop and ask** the user to merge vs replace — don't clobber.
82
152
  - **No Node runtime → skip enforcement.** If the project has no Node (recon step 1), skip bootstrap steps 8–9 (scripts + hook) and follow the cap/archive/index policy manually, or port the scripts to the project's language.
83
- - **Conversational language never translates artifacts.** It governs *dialogue only*. Code, identifiers, paths, commands, log output, abbreviations, and every deployed `docs/ai/` / `AGENTS.md` file stay English. See [Communication contract](references/contracts.md#communication-contract).
153
+ - **Conversational language never translates artifacts.** It governs *dialogue only*. Code, identifiers, paths, commands, log output, abbreviations, and every deployed `docs/ai/` / `AGENTS.md` file stay in their source language. See [Communication contract](references/contracts.md#communication-contract).
84
154
  - **Never auto-commit.** Report quality-gate results and wait for explicit approval — in both modes.
85
155
 
86
156
  ---
@@ -137,4 +207,6 @@ Deploy these into `AGENTS.md`; remove rows that don't apply to the stack.
137
207
  - [`references/scripts/`](references/scripts/) — the Node enforcement scripts (caps + staleness + index-freshness gate, 3-tier archive, hook installer) and their unit tests.
138
208
  - [`migrations/`](migrations/) — per-version upgrade steps; see `migrations/README.md`.
139
209
  - [`launchers/`](launchers/) — run the bootstrapper from non-Claude agents (`SKILL.md` is a native Codex skill; a Devin Desktop workflow launcher + install script). See `launchers/README.md`.
210
+ - [`tools/`](tools/) — the family-wide tooling the kit **owns and ships**: `manifest/{schema.md,validate.mjs}` (the `capability.json` schema + the validator the kit runs as the memory detector, and root CI invokes), `delegation.mjs` (the executable delegate/fallback decision + hand-off plan), `inject-methodology.mjs` + `methodology-slot.md` (the bounded slot injection), `detect-backends.mjs` (the read-only **backend detector** behind `/agent-workflow-kit backends`), and `release-scan.mjs` (the attribution-off release gate). See [`tools/manifest/schema.md`](tools/manifest/schema.md).
211
+ - [`capability.json`](capability.json) — the kit's own `agent-workflow` family manifest (`kind: composition-root`).
140
212
  - [`CHANGELOG.md`](CHANGELOG.md) — version history of this kernel.
package/bin/install.mjs CHANGED
@@ -19,8 +19,8 @@
19
19
  // Dependency-free, Node >= 18.
20
20
 
21
21
  import { readFile, mkdir, readdir, copyFile, lstat, readlink, symlink } from 'node:fs/promises';
22
- import { existsSync } from 'node:fs';
23
- import { dirname, join, resolve } from 'node:path';
22
+ import { existsSync, lstatSync } from 'node:fs';
23
+ import { dirname, join, resolve, relative, sep, isAbsolute } from 'node:path';
24
24
  import { fileURLToPath } from 'node:url';
25
25
  import { homedir } from 'node:os';
26
26
  import { spawnSync } from 'node:child_process';
@@ -29,7 +29,18 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
29
29
  const PKG_ROOT = resolve(__dirname, '..');
30
30
 
31
31
  // The deployable skill = everything except the npm wrapper (package.json, bin/).
32
- const PAYLOAD = ['SKILL.md', 'README.md', 'CHANGELOG.md', 'references', 'launchers', 'migrations'];
32
+ // capability.json (the family manifest) + tools/ (the family schema + validator the kit runs
33
+ // as the memory detector) must land in the installed skill dir too.
34
+ const PAYLOAD = [
35
+ 'SKILL.md',
36
+ 'README.md',
37
+ 'CHANGELOG.md',
38
+ 'capability.json',
39
+ 'references',
40
+ 'launchers',
41
+ 'migrations',
42
+ 'tools',
43
+ ];
33
44
 
34
45
  const tildify = (path) => path.replace(homedir(), '~');
35
46
 
@@ -42,7 +53,39 @@ const readVersion = async () => {
42
53
  }
43
54
  };
44
55
 
45
- const copyRecursive = async (src, dest) => {
56
+ // lstat without following symlinks; null when absent. existsSync FOLLOWS symlinks (so a
57
+ // *dangling* symlink reads as absent) — lstat is what lets the guard catch a dangling dest symlink.
58
+ const lstatNoFollow = (path) => {
59
+ try {
60
+ return lstatSync(path);
61
+ } catch (err) {
62
+ if (err && err.code === 'ENOENT') return null;
63
+ throw err; // EACCES/EIO etc. must NOT fail open (be read as "not a symlink")
64
+ }
65
+ };
66
+
67
+ // Symlink-traversal guard: refuse to write *through* any symlink at or above `dest` within
68
+ // `root` (root / intermediate dir / leaf, including a dangling one), or to a dest outside `root`.
69
+ const assertContainedRealPath = (root, dest) => {
70
+ const rel = relative(root, dest);
71
+ if (rel.startsWith('..') || isAbsolute(rel)) {
72
+ throw new Error(`[agent-workflow-kit] refusing to write outside the target dir: ${dest}`);
73
+ }
74
+ if (lstatNoFollow(root)?.isSymbolicLink()) {
75
+ throw new Error(`[agent-workflow-kit] refusing to install into a symlinked target dir: ${root}`);
76
+ }
77
+ const walk = (acc, part) => {
78
+ const cur = join(acc, part);
79
+ if (lstatNoFollow(cur)?.isSymbolicLink()) {
80
+ throw new Error(`[agent-workflow-kit] refusing to write through a symlink at ${cur} (would escape ${root}).`);
81
+ }
82
+ return cur;
83
+ };
84
+ rel.split(sep).filter(Boolean).reduce(walk, root);
85
+ };
86
+
87
+ const copyRecursive = async (src, dest, root) => {
88
+ assertContainedRealPath(root, dest); // never write through a dest symlink (root/intermediate/leaf)
46
89
  const stat = await lstat(src);
47
90
  if (stat.isSymbolicLink()) {
48
91
  if (existsSync(dest)) return; // additive: never delete/replace an existing entry
@@ -51,7 +94,7 @@ const copyRecursive = async (src, dest) => {
51
94
  } else if (stat.isDirectory()) {
52
95
  await mkdir(dest, { recursive: true });
53
96
  const entries = await readdir(src);
54
- await Promise.all(entries.map((entry) => copyRecursive(join(src, entry), join(dest, entry))));
97
+ await Promise.all(entries.map((entry) => copyRecursive(join(src, entry), join(dest, entry), root)));
55
98
  } else {
56
99
  await mkdir(dirname(dest), { recursive: true });
57
100
  await copyFile(src, dest);
@@ -105,17 +148,25 @@ const main = async () => {
105
148
  if (args.help) return printHelp(version);
106
149
  if (args.version) return console.log(version);
107
150
 
108
- if (!existsSync(resolve(PKG_ROOT, 'SKILL.md'))) {
109
- console.error('[agent-workflow-kit] package payload missing (no SKILL.md) corrupt install?');
151
+ // Critical payload must be present, or the install would silently ship a kit that can't run
152
+ // its own detector (tools/) or family contract (capability.json). Fail loudly, don't filter away.
153
+ const REQUIRED = ['SKILL.md', 'capability.json', 'references', 'tools', 'migrations'];
154
+ const missing = REQUIRED.filter((entry) => !existsSync(resolve(PKG_ROOT, entry)));
155
+ if (missing.length > 0) {
156
+ console.error(`[agent-workflow-kit] package payload incomplete — missing: ${missing.join(', ')} (corrupt install?)`);
110
157
  process.exit(1);
111
158
  }
112
159
 
113
160
  const target = resolveTarget(args.dir);
114
161
  const wasPresent = existsSync(resolve(target, 'SKILL.md'));
162
+ if (lstatNoFollow(target)?.isSymbolicLink()) {
163
+ console.error(`[agent-workflow-kit] target dir is a symlink — refusing to write through it: ${tildify(target)}`);
164
+ process.exit(1);
165
+ }
115
166
  await mkdir(target, { recursive: true });
116
167
  await Promise.all(
117
168
  PAYLOAD.filter((entry) => existsSync(resolve(PKG_ROOT, entry))).map((entry) =>
118
- copyRecursive(resolve(PKG_ROOT, entry), resolve(target, entry)),
169
+ copyRecursive(resolve(PKG_ROOT, entry), resolve(target, entry), target),
119
170
  ),
120
171
  );
121
172
  console.log(`[agent-workflow-kit] ${wasPresent ? 'updated the kit to' : 'installed'} v${version} -> ${tildify(target)}`);
@@ -0,0 +1,66 @@
1
+ import { describe, it, beforeEach, afterEach } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { spawnSync } from 'node:child_process';
4
+ import { mkdtemp, rm, mkdir, symlink, readdir } from 'node:fs/promises';
5
+ import { existsSync } from 'node:fs';
6
+ import { tmpdir } from 'node:os';
7
+ import { dirname, join } from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+
10
+ const INSTALLER = join(dirname(fileURLToPath(import.meta.url)), 'install.mjs');
11
+ // --no-launchers so the test never wires Codex/Devin on the host.
12
+ const runInstaller = (target) =>
13
+ spawnSync(process.execPath, [INSTALLER, '--dir', target, '--no-launchers'], { encoding: 'utf8' });
14
+
15
+ describe('kit installer — payload + symlink-traversal hardening', () => {
16
+ let dir;
17
+ beforeEach(async () => {
18
+ dir = await mkdtemp(join(tmpdir(), 'aw-kit-install-'));
19
+ });
20
+ afterEach(async () => {
21
+ await rm(dir, { recursive: true, force: true });
22
+ });
23
+
24
+ it('installs the critical payload (capability.json + tools/ + references/) and not the npm wrapper', () => {
25
+ const target = join(dir, 'agent-workflow-kit');
26
+ const res = runInstaller(target);
27
+ assert.equal(res.status, 0, res.stderr);
28
+ for (const f of ['SKILL.md', 'capability.json', 'tools/manifest/validate.mjs', 'tools/delegation.mjs', 'references']) {
29
+ assert.ok(existsSync(join(target, f)), `missing installed entry: ${f}`);
30
+ }
31
+ assert.equal(existsSync(join(target, 'bin/install.mjs')), false);
32
+ });
33
+
34
+ it('refuses to write through a symlinked INTERMEDIATE dest component (no leak)', async () => {
35
+ const target = join(dir, 'target');
36
+ const evil = join(dir, 'evil');
37
+ await mkdir(target, { recursive: true });
38
+ await mkdir(evil, { recursive: true });
39
+ await symlink(evil, join(target, 'references'));
40
+ const res = runInstaller(target);
41
+ assert.notEqual(res.status, 0);
42
+ assert.match(res.stderr, /symlink/i);
43
+ assert.deepEqual(await readdir(evil), []);
44
+ });
45
+
46
+ it('refuses a DANGLING destination symlink', async () => {
47
+ const target = join(dir, 'target');
48
+ await mkdir(target, { recursive: true });
49
+ await symlink(join(dir, 'nowhere'), join(target, 'references'));
50
+ const res = runInstaller(target);
51
+ assert.notEqual(res.status, 0);
52
+ assert.match(res.stderr, /symlink/i);
53
+ assert.equal(existsSync(join(dir, 'nowhere')), false);
54
+ });
55
+
56
+ it('refuses a symlinked TARGET root (no leak)', async () => {
57
+ const real = join(dir, 'real');
58
+ const root = join(dir, 'root');
59
+ await mkdir(real, { recursive: true });
60
+ await symlink(real, root);
61
+ const res = runInstaller(root);
62
+ assert.notEqual(res.status, 0);
63
+ assert.match(res.stderr, /symlink/i);
64
+ assert.deepEqual(await readdir(real), []);
65
+ });
66
+ });
@@ -0,0 +1,21 @@
1
+ {
2
+ "family": "agent-workflow",
3
+ "schema": 1,
4
+ "name": "agent-workflow-kit",
5
+ "kind": "composition-root",
6
+ "version": "1.5.0",
7
+ "provides": [],
8
+ "roles": {},
9
+ "detect": {
10
+ "installed": {
11
+ "env": "AGENT_WORKFLOW_KIT_DIR",
12
+ "default": "~/.claude/skills/agent-workflow-kit",
13
+ "file": "SKILL.md"
14
+ },
15
+ "deployed": { "file": "docs/ai/.workflow-version" }
16
+ },
17
+ "install": { "npm": "@sabaiway/agent-workflow-kit" },
18
+ "cost": "none",
19
+ "quota": null,
20
+ "provenance": { "author": "sabaiway", "source": "github:sabaiway/agent-workflow" }
21
+ }
@@ -10,8 +10,8 @@ language* block in the project's `AGENTS.md` so every agent that reads the entry
10
10
  honours it instead of drifting between languages. Pre-1.1.0 deployments have no such block.
11
11
 
12
12
  Scope is **dialogue only** — code, identifiers, paths, commands, log output, and
13
- abbreviations stay in their source language, and the `docs/ai/` files + `AGENTS.md` stay
14
- English (the kernel is English-only). This migration changes *one* doc block, nothing else.
13
+ abbreviations stay in their source language, and the `docs/ai/` files + `AGENTS.md` are not
14
+ translated either. This migration changes *one* doc block, nothing else.
15
15
 
16
16
  ## Steps
17
17
 
@@ -29,8 +29,8 @@ English (the kernel is English-only). This migration changes *one* doc block, no
29
29
  ## 🗣️ Communication language
30
30
 
31
31
  > **Talk to the user in <their language>** — every question, explanation, summary, and status update.
32
- > Keep code, identifiers, file paths, shell commands, log output, and abbreviations in their **source language** (usually English) — translating them breaks copy-paste, search, and tooling.
33
- > This sets the **dialogue** language only. The files in `docs/ai/` and this entry point stay in English (kernel is English-only, for cross-agent / cross-team portability).
32
+ > Keep code, identifiers, file paths, shell commands, log output, and abbreviations in their **source language** — translating them breaks copy-paste, search, and tooling.
33
+ > This sets the **dialogue** language only it does not translate the files in `docs/ai/` or this entry point, which stay in their source language (for cross-agent / cross-team portability).
34
34
  ```
35
35
 
36
36
  5. Keep `AGENTS.md` within its ≤100-line budget (the block is ~6 lines; it fits). Do **not**
@@ -43,7 +43,7 @@ English (the kernel is English-only). This migration changes *one* doc block, no
43
43
  - The docs cap-validator is still green (`node scripts/check-docs-size.mjs` for Node projects)
44
44
  — the entry point did not bust its line budget.
45
45
  - From now on the agent's replies are in the chosen language; paths/commands/identifiers
46
- remain English.
46
+ remain in their source language.
47
47
 
48
48
  ## Rollback
49
49
 
@@ -10,7 +10,8 @@ releases add files/templates, which `upgrade` reconciles without a migration.
10
10
  1. Read the project's stamped version from `docs/ai/.workflow-version`.
11
11
  2. Select every migration whose `<version>` is **strictly newer** than the stamp.
12
12
  3. Apply them in **ascending semver order**.
13
- 4. Re-stamp `docs/ai/.workflow-version` to the skill's current `version`.
13
+ 4. Re-stamp `docs/ai/.workflow-version` to the **deployment-lineage head** (`1.3.0` today — the
14
+ shared lineage, **not** this skill's package version `1.4.0`). A stamp greater than the head → STOP.
14
15
 
15
16
  ## Authoring rules
16
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sabaiway/agent-workflow-kit",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Portable, cross-agent memory & workflow for AI coding agents — Claude Code, Codex, Cursor, Devin Desktop. One command deploys an AGENTS.md entry point + docs/ai context with cap/archive/index enforcement into any repo.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -25,13 +25,14 @@
25
25
  "memory",
26
26
  "developer-tools"
27
27
  ],
28
- "homepage": "https://github.com/sabaiway/agent-workflow-kit#readme",
28
+ "homepage": "https://github.com/sabaiway/agent-workflow#readme",
29
29
  "bugs": {
30
- "url": "https://github.com/sabaiway/agent-workflow-kit/issues"
30
+ "url": "https://github.com/sabaiway/agent-workflow/issues"
31
31
  },
32
32
  "repository": {
33
33
  "type": "git",
34
- "url": "git+https://github.com/sabaiway/agent-workflow-kit.git"
34
+ "url": "git+https://github.com/sabaiway/agent-workflow.git",
35
+ "directory": "agent-workflow-kit"
35
36
  },
36
37
  "license": "MIT",
37
38
  "author": "sabaiway",
@@ -44,9 +45,11 @@
44
45
  "SKILL.md",
45
46
  "README.md",
46
47
  "CHANGELOG.md",
48
+ "capability.json",
47
49
  "references/",
48
50
  "launchers/",
49
- "migrations/"
51
+ "migrations/",
52
+ "tools/"
50
53
  ],
51
54
  "engines": {
52
55
  "node": ">=18"
@@ -33,8 +33,8 @@ reads the entry point honours it — and stops drifting between languages mid-se
33
33
  Scope — **dialogue only**:
34
34
 
35
35
  - **In the chosen language** — everything the agent produces *for the user to read*: questions, explanations, plan summaries, status updates, commit-message prose if asked, review notes.
36
- - **Always in their source language (usually English)** — code, identifiers, file paths, shell commands, log/console output, error strings, config keys, and abbreviations/acronyms. Translating these breaks copy-paste, search, and tooling.
37
- - **Files stay English** — the deployed `docs/ai/` files, `AGENTS.md`, and this kernel are English-only regardless of the chosen language (cross-agent / cross-team portability). The conversational language is about the *chat*, not the *artifacts*.
36
+ - **Always in their source language** — code, identifiers, file paths, shell commands, log/console output, error strings, config keys, and abbreviations/acronyms. Translating these breaks copy-paste, search, and tooling.
37
+ - **Files aren't translated** — the deployed `docs/ai/` files, `AGENTS.md`, and this kernel stay in their source language regardless of the chosen language (cross-agent / cross-team portability). The conversational language is about the *chat*, not the *artifacts*.
38
38
 
39
39
  Default to the language the user is already writing in; confirm rather than assume. On `upgrade`, a
40
40
  pre-1.1.0 deployment with no block gets one (the agent asks).
@@ -130,9 +130,6 @@ export const parseChangelogText = (text) => {
130
130
 
131
131
  const TRAILING_FOOTER_PATTERNS = [
132
132
  /^\*\*Last Updated:/i,
133
- // Legacy in-tree footer line from the deleted changelog-archive.md — match left in place
134
- // so a re-migration cannot leak the old marker into a freshly-rotated entry.
135
- /^> Записи старше/i,
136
133
  ];
137
134
 
138
135
  export const stripTrailingSeparator = (block) => {
@@ -149,7 +146,7 @@ export const stripTrailingSeparator = (block) => {
149
146
  export const stripBlockquoteHistoryNotice = (preamble) => {
150
147
  const filtered = preamble
151
148
  .split('\n')
152
- .filter((line) => !/changelog-archive\.md/i.test(line) && !/Записи старше/i.test(line));
149
+ .filter((line) => !/changelog-archive\.md/i.test(line));
153
150
 
154
151
  // Strip any previously-inserted "## History" section so re-running the rotator is idempotent.
155
152
  // A History section starts at `## History` and ends at the next `---` separator or end-of-file.
@@ -9,8 +9,8 @@
9
9
  ## 🗣️ Communication language
10
10
 
11
11
  > **Talk to the user in {{COMM_LANGUAGE}}** — every question, explanation, summary, and status update.
12
- > Keep code, identifiers, file paths, shell commands, log output, and abbreviations in their **source language** (usually English) — translating them breaks copy-paste, search, and tooling.
13
- > This sets the **dialogue** language only. The files in `docs/ai/` and this entry point stay in English (kernel is English-only, for cross-agent / cross-team portability).
12
+ > Keep code, identifiers, file paths, shell commands, log output, and abbreviations in their **source language** — translating them breaks copy-paste, search, and tooling.
13
+ > This sets the **dialogue** language only it does not translate the files in `docs/ai/` or this entry point, which stay in their source language (for cross-agent / cross-team portability).
14
14
 
15
15
  ---
16
16