@sabaiway/agent-workflow-kit 1.29.0 → 1.31.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 (43) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +7 -2
  3. package/SKILL.md +33 -519
  4. package/bridges/antigravity-cli-bridge/SKILL.md +1 -1
  5. package/bridges/antigravity-cli-bridge/bin/agy-review.sh +145 -4
  6. package/bridges/antigravity-cli-bridge/bin/agy-review.test.mjs +169 -1
  7. package/bridges/antigravity-cli-bridge/capability.json +3 -2
  8. package/bridges/codex-cli-bridge/SKILL.md +1 -1
  9. package/bridges/codex-cli-bridge/bin/codex-review.sh +120 -3
  10. package/bridges/codex-cli-bridge/bin/codex-review.test.mjs +132 -0
  11. package/bridges/codex-cli-bridge/capability.json +3 -2
  12. package/capability.json +1 -1
  13. package/launchers/windsurf-workflow.md +4 -2
  14. package/package.json +1 -1
  15. package/references/modes/agents.md +11 -0
  16. package/references/modes/backends.md +9 -0
  17. package/references/modes/bootstrap.md +49 -0
  18. package/references/modes/gates.md +17 -0
  19. package/references/modes/grounding.md +12 -0
  20. package/references/modes/help.md +7 -0
  21. package/references/modes/hook.md +24 -0
  22. package/references/modes/procedures.md +18 -0
  23. package/references/modes/recipes.md +18 -0
  24. package/references/modes/review-state.md +13 -0
  25. package/references/modes/set-recipe.md +23 -0
  26. package/references/modes/setup.md +30 -0
  27. package/references/modes/status.md +22 -0
  28. package/references/modes/uninstall.md +18 -0
  29. package/references/modes/upgrade.md +46 -0
  30. package/references/modes/velocity.md +18 -0
  31. package/references/shared/composition-handoff.md +39 -0
  32. package/references/shared/deploy-tail.md +61 -0
  33. package/references/shared/report-footer.md +116 -0
  34. package/references/templates/agent_rules.md +3 -2
  35. package/references/templates/handover.md +1 -0
  36. package/tools/commands.mjs +15 -1
  37. package/tools/detect-backends.mjs +2 -0
  38. package/tools/engine-source.mjs +2 -1
  39. package/tools/grounding.mjs +263 -0
  40. package/tools/procedures.mjs +50 -5
  41. package/tools/recipes.mjs +78 -12
  42. package/tools/review-state.mjs +395 -0
  43. package/tools/set-recipe.mjs +15 -5
@@ -8,6 +8,7 @@ import { tmpdir } from 'node:os';
8
8
  import { join, dirname, resolve } from 'node:path';
9
9
  import { fileURLToPath } from 'node:url';
10
10
  import { spawnSync } from 'node:child_process';
11
+ import { createHash } from 'node:crypto';
11
12
 
12
13
  const HERE = dirname(fileURLToPath(import.meta.url));
13
14
  const WRAPPER = join(HERE, 'codex-review.sh');
@@ -641,6 +642,12 @@ describe('codex-review.sh — --help contract (manifest-pinned)', () => {
641
642
  setEq(got, (REVIEW_CONTRACT.continue ?? []).map(norm), 'help continue ⟷ manifest continue');
642
643
  assert.deepEqual(REVIEW_CONTRACT.continue, [], 'codex-review is one-shot — no continue descriptor');
643
644
  });
645
+
646
+ it('Receipt renders the manifest receipt contract verbatim (AD-038 three-way lockstep)', () => {
647
+ const help = runHelp('--help').stdout;
648
+ assert.equal(norm(helpSection(help, 'Receipt:').join(' ')), norm(REVIEW_CONTRACT.receipt));
649
+ assert.match(REVIEW_CONTRACT.receipt, /sha256 over the canonical uncommitted-state payload/, 'the fingerprint definition lives in the manifest contract');
650
+ });
644
651
  });
645
652
 
646
653
  describe('codex-review.sh — source-level reverse guard (parser arms ⟷ manifest)', () => {
@@ -667,3 +674,128 @@ describe('codex-review.sh — source-level reverse guard (parser arms ⟷ manife
667
674
  }
668
675
  });
669
676
  });
677
+
678
+ // ── review receipts (AD-038) ─────────────────────────────────────────────────────
679
+ // The normative fixture (docs: the AD-038 plan Decisions — copied verbatim; field VALUES with
680
+ // dynamic content are asserted by shape):
681
+ const RECEIPT_FIXTURE = JSON.parse(
682
+ '{"schema":1,"artifact":"code","fresh":true,"fingerprint":"<sha256hex>","backend":"codex","verdict":"revise","grounded":true,"factsHash":null,"wrapperVersion":"2.2.0","timestamp":"2026-07-03T12:00:00Z"}',
683
+ );
684
+ const RECEIPTS_REL = join('.git', 'agent-workflow-review-receipts.jsonl');
685
+ const readReceipts = (repo) => {
686
+ const p = join(repo, RECEIPTS_REL);
687
+ if (!existsSync(p)) return [];
688
+ return readFileSync(p, 'utf8').trim().split('\n').filter(Boolean).map((l) => JSON.parse(l));
689
+ };
690
+ const sha256Hex = (buf) => createHash('sha256').update(buf).digest('hex');
691
+
692
+ describe('codex-review.sh — review receipts (AD-038)', () => {
693
+ it('a successful code review appends ONE fixture-shaped receipt (text-mode verdict parse)', () => {
694
+ const sb = makeSandbox();
695
+ const r = run(sb, { env: { CODEX_FAKE_FINAL: '[major] — a.txt:1 — x — y\nVerdict: revise' } });
696
+ const receipts = readReceipts(sb.repo);
697
+ rmSync(sb.root, { recursive: true, force: true });
698
+ assert.equal(r.status, 0, r.stderr);
699
+ assert.equal(receipts.length, 1, 'exactly one receipt line');
700
+ const receipt = receipts[0];
701
+ assert.deepEqual(Object.keys(receipt), Object.keys(RECEIPT_FIXTURE), 'fixture key set + order');
702
+ assert.equal(receipt.schema, 1);
703
+ assert.equal(receipt.artifact, 'code');
704
+ assert.equal(receipt.fresh, true, 'every codex run is a fresh one-shot');
705
+ assert.match(receipt.fingerprint, /^[0-9a-f]{64}$/, 'a real sha256 hex fingerprint');
706
+ assert.equal(receipt.backend, 'codex');
707
+ assert.equal(receipt.verdict, 'revise', 'the mandated literal verdict line is parsed');
708
+ assert.equal(receipt.grounded, true, 'codex is grounded by construction');
709
+ assert.equal(receipt.factsHash, null, 'native grounding — no separate facts payload');
710
+ assert.equal(receipt.wrapperVersion, MANIFEST.version, 'receipt version ⟷ capability.json version');
711
+ assert.match(receipt.timestamp, /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/);
712
+ });
713
+
714
+ it('the code-mode fingerprint tracks the uncommitted state (same tree → same hash; edit → different)', () => {
715
+ const sb = makeSandbox();
716
+ // Route the fake-codex capture files to /dev/null so the runs themselves leave the repo
717
+ // byte-identical (the default capture files land inside the repo and would change the tree).
718
+ const quiet = { CODEX_FAKE_ARGV: '/dev/null', CODEX_FAKE_ENV: '/dev/null', CODEX_FAKE_STDIN: '/dev/null', CODEX_FAKE_FINAL: 'Verdict: ship' };
719
+ run(sb, { env: quiet });
720
+ run(sb, { env: quiet });
721
+ writeFileSync(join(sb.repo, 'pending.txt'), 'edited after the first two reviews\n');
722
+ run(sb, { env: quiet });
723
+ const receipts = readReceipts(sb.repo);
724
+ rmSync(sb.root, { recursive: true, force: true });
725
+ assert.equal(receipts.length, 3);
726
+ assert.equal(receipts[0].fingerprint, receipts[1].fingerprint, 'an unchanged tree re-fingerprints identically');
727
+ assert.notEqual(receipts[1].fingerprint, receipts[2].fingerprint, 'an edited tree changes the fingerprint');
728
+ });
729
+
730
+ it('CODEX_REVIEW_SCHEMA=1 reads the schema verdict field', () => {
731
+ const sb = makeSandbox();
732
+ const r = run(sb, {
733
+ env: { CODEX_REVIEW_SCHEMA: '1', CODEX_FAKE_FINAL: '{"findings":[],"verdict":"ship","notes":"ok"}' },
734
+ });
735
+ const receipts = readReceipts(sb.repo);
736
+ rmSync(sb.root, { recursive: true, force: true });
737
+ assert.equal(r.status, 0, r.stderr);
738
+ assert.equal(receipts[0].verdict, 'ship');
739
+ });
740
+
741
+ it('no parseable verdict → recorded as "unknown", never guessed', () => {
742
+ const sb = makeSandbox();
743
+ const r = run(sb, { env: { CODEX_FAKE_FINAL: 'looks fine to me overall' } });
744
+ const receipts = readReceipts(sb.repo);
745
+ rmSync(sb.root, { recursive: true, force: true });
746
+ assert.equal(r.status, 0, r.stderr);
747
+ assert.equal(receipts[0].verdict, 'unknown');
748
+ });
749
+
750
+ it('plan mode: artifact "plan", fingerprint = the artifact-file sha256', () => {
751
+ const sb = makeSandbox();
752
+ const planBytes = readFileSync(join(sb.repo, 'plan.md'));
753
+ const r = run(sb, { args: ['plan', 'plan.md'], env: { CODEX_FAKE_FINAL: 'Verdict: ship' } });
754
+ const receipts = readReceipts(sb.repo);
755
+ rmSync(sb.root, { recursive: true, force: true });
756
+ assert.equal(r.status, 0, r.stderr);
757
+ assert.equal(receipts[0].artifact, 'plan');
758
+ assert.equal(receipts[0].fingerprint, sha256Hex(planBytes), 'plan fingerprint = file sha256');
759
+ });
760
+
761
+ it('AW_REVIEW_RECEIPTS overrides the receipt destination', () => {
762
+ const sb = makeSandbox();
763
+ const override = join(sb.root, 'my-receipts.jsonl');
764
+ const r = run(sb, { env: { AW_REVIEW_RECEIPTS: override, CODEX_FAKE_FINAL: 'Verdict: ship' } });
765
+ const inGitDir = readReceipts(sb.repo);
766
+ const atOverride = existsSync(override) ? readFileSync(override, 'utf8') : '';
767
+ rmSync(sb.root, { recursive: true, force: true });
768
+ assert.equal(r.status, 0, r.stderr);
769
+ assert.equal(inGitDir.length, 0, 'nothing written to the default path');
770
+ assert.match(atOverride, /"backend":"codex"/);
771
+ });
772
+
773
+ it('a receipt write failure warns loudly but never fails the review (fail-safe direction)', () => {
774
+ const sb = makeSandbox();
775
+ const r = run(sb, {
776
+ env: { AW_REVIEW_RECEIPTS: join(sb.repo, 'no-such-dir', 'r.jsonl'), CODEX_FAKE_FINAL: 'Verdict: ship' },
777
+ });
778
+ rmSync(sb.root, { recursive: true, force: true });
779
+ assert.equal(r.status, 0, 'the review run itself succeeds');
780
+ assert.match(r.stderr, /could not append the review receipt/);
781
+ assert.match(r.stdout, /Verdict: ship/, 'the findings still reach stdout');
782
+ });
783
+
784
+ it('a failed codex run writes NO receipt (only a successful review attests)', () => {
785
+ const sb = makeSandbox();
786
+ const r = run(sb, { env: { CODEX_FAKE_EXIT: '5' } });
787
+ const receipts = readReceipts(sb.repo);
788
+ rmSync(sb.root, { recursive: true, force: true });
789
+ assert.notEqual(r.status, 0);
790
+ assert.equal(receipts.length, 0);
791
+ });
792
+
793
+ it('the clean-tree preflight exits before any receipt is written', () => {
794
+ const sb = makeSandbox({ clean: true });
795
+ const r = run(sb);
796
+ const receipts = readReceipts(sb.repo);
797
+ rmSync(sb.root, { recursive: true, force: true });
798
+ assert.equal(r.status, 0);
799
+ assert.equal(receipts.length, 0, 'no review ran — no receipt');
800
+ });
801
+ });
@@ -3,7 +3,7 @@
3
3
  "schema": 1,
4
4
  "name": "codex-cli-bridge",
5
5
  "kind": "execution-backend",
6
- "version": "2.1.0",
6
+ "version": "2.2.0",
7
7
  "provides": ["execute", "review"],
8
8
  "roles": {
9
9
  "execute": {
@@ -38,7 +38,8 @@
38
38
  "codex-review code [extra focus...]"
39
39
  ],
40
40
  "grounding": "automatic — the wrapper precomputes the full working-tree change set (repo map, status, diffs, untracked contents) and codex auto-merges the root AGENTS.md; no grounding flags",
41
- "continue": []
41
+ "continue": [],
42
+ "receipt": "side effect — a successful review appends one JSON receipt line to <git dir>/agent-workflow-review-receipts.jsonl (AW_REVIEW_RECEIPTS overrides): fingerprint = sha256 over the canonical uncommitted-state payload (staged diff + unstaged diff + untracked-not-ignored contents — the review-payload domain) in code mode, the artifact-file sha256 in plan mode; verdict parsed from the mandated literal verdict line (schema mode: the verdict field); always fresh:true (one-shot) + grounded:true (native AGENTS.md auto-merge, factsHash null); a write failure warns, never fails the review"
42
43
  }
43
44
  }
44
45
  },
package/capability.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "schema": 1,
4
4
  "name": "agent-workflow-kit",
5
5
  "kind": "composition-root",
6
- "version": "1.29.0",
6
+ "version": "1.31.0",
7
7
  "provides": [],
8
8
  "roles": {},
9
9
  "detect": {
@@ -14,8 +14,10 @@ reinvent any of it here; the kit's `SKILL.md` is the single source of truth.
14
14
 
15
15
  ## Steps
16
16
 
17
- 1. Read the kit instructions in full: `<KIT_DIR>/SKILL.md`, plus the `references/` files it
18
- points to. Wherever it says `${CLAUDE_SKILL_DIR}`, read that as `<KIT_DIR>`.
17
+ 1. Read the kit instructions in full: `<KIT_DIR>/SKILL.md` (the thin router), plus the
18
+ `references/` files it points to the chosen mode's `<KIT_DIR>/references/modes/<mode>.md`
19
+ and any `references/shared/` files that mode's `Requires:` line names. Wherever it says
20
+ `${CLAUDE_SKILL_DIR}`, read that as `<KIT_DIR>`.
19
21
  2. Pick the mode:
20
22
  - No `docs/ai/` in this project → **bootstrap**.
21
23
  - `docs/ai/` already exists → ask the user whether to run **upgrade** instead.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sabaiway/agent-workflow-kit",
3
- "version": "1.29.0",
3
+ "version": "1.31.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",
@@ -0,0 +1,11 @@
1
+ ### Mode: agents
2
+
3
+ The opt-in **cheap-lane subagent writer** — the family's second `.claude/` writer, on the velocity discipline. It places the bundled cheap-lane subagent definitions (`references/agents/*.md`) into the project's `.claude/agents/` so mechanical work — extraction sweeps, changelog fact-skeletons, gate-failure triage — runs on a **cheap model** (`model: haiku`, `effort: low`, bounded read-only tools) instead of the frontier main lane. **Claude-Code-specific** (like velocity): other agent hosts ignore `.claude/agents/`. Judgment, review, real code, and user-facing copy never move to these vehicles — they are extraction/drafting only, and the orchestrator verifies their output.
4
+
5
+ Run `node ${CLAUDE_SKILL_DIR}/tools/cheap-agents.mjs [--dry-run | --apply] [--cwd <dir>]`:
6
+
7
+ 1. **`--dry-run` first, always** (the default — changes nothing). It previews, per bundled vehicle, whether it **would place** the file, finds it **already current**, or finds a **customized** file (different content) that will be **preserved, never overwritten** (delete the file to reseed it from the bundle).
8
+ 2. **Only on an explicit yes**, re-run with `--apply`. It writes **only** under `.claude/agents/` — never `settings.json` / `settings.local.json`, never a commit. `--apply` is deployment-gated (the stamp must be at the lineage head) and symlink-safe (a symlinked `.claude` / `.claude/agents` / target file is a STOP).
9
+ 3. **Hidden-mode deployments:** after apply, run the hide-footprint reconcile (`node ${CLAUDE_SKILL_DIR}/tools/hide-footprint.mjs --dir <project> --reconcile`) so the placed files stay invisible to `git status` — `/.claude/agents/` is in the known-footprint registry; the apply report reminds you.
10
+
11
+ **Invariants:** writer (writes only `.claude/agents/`) · preview by default · a diverged existing file is reported and preserved, never clobbered · never touches settings · never commits · vehicles are pinned to `model: haiku` + `effort: low` + read-only tools (content-tested).
@@ -0,0 +1,9 @@
1
+ ### Mode: backends
2
+
3
+ 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**.
4
+
5
+ 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".
6
+ 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).
7
+ 3. State plainly to the user that this is **detection only**:
8
+ - **"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).
9
+ - 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.
@@ -0,0 +1,49 @@
1
+ ### Mode: bootstrap
2
+
3
+ Requires: ${CLAUDE_SKILL_DIR}/references/shared/report-footer.md · ${CLAUDE_SKILL_DIR}/references/shared/composition-handoff.md · ${CLAUDE_SKILL_DIR}/references/shared/deploy-tail.md
4
+
5
+ > Bundled sources below (templates, scripts) live in **this skill's own directory** — `${CLAUDE_SKILL_DIR}/` in Claude Code, or the folder containing this `SKILL.md` in Codex / other agents. Use that as the copy/read source; the working directory is the **target project**, not the skill.
6
+
7
+ > The three setup questions (steps 2–4) are decisions only the user can make and are hard to reverse after a commit. Ask each as a **structured multiple-choice prompt where your agent supports it** (`AskUserQuestion` in Claude Code — one option per choice, recommended one first), otherwise in prose — and **wait for the answer before writing anything**.
8
+
9
+ 1. **Recon (read-only).** Before writing anything:
10
+ - `package.json` / `pyproject.toml` / `go.mod` / `Cargo.toml` → stack, package manager, scripts.
11
+ - `ls -la` root → `README`, existing `AGENTS.md`/`CLAUDE.md`, CI configs, linter/formatter configs.
12
+ - `git log --oneline -30` + `git status` → recent activity, branch, uncommitted changes.
13
+ - `src/` (or equivalent) 2–3 levels deep → modules, routes/pages, components, services, types.
14
+ - Tests (framework, location, E2E?) and linter rules.
15
+ - Record: stack, package manager, daily commands (`dev`/`test`/`lint`/`type-check`), routes/pages, architecture layers.
16
+ - **First-contact orientation — say this before the first question (read-only).** In 1–2 plain lines, tell the user what this is — a portable memory & workflow system for this repo, so future sessions boot from a small structured memory instead of re-reading everything — and that they can run **`/agent-workflow-kit help`** any time to see every command. This is the "start here"; keep it to a sentence or two, then ask the visibility question.
17
+ 2. **Choose visibility — ASK the user explicitly and wait for the answer, before writing anything.** This decides what gets tracked and is hard to reverse after a commit, so never assume the default silently: `visible` (committed — canonical, recommended) or `hidden` (in-tree, git-ignored via the **project-local** `.git/info/exclude` — one managed block covering the full AI/agent footprint, never the machine-global excludes). See [Visibility contract](${CLAUDE_SKILL_DIR}/references/contracts.md#visibility-contract).
18
+ 3. **Choose conversational language — ASK the user explicitly and wait for the answer.** Which language should the agent *talk to them* in — questions, explanations, summaries, status updates? Offer the language they're already writing in as the default. Carry the answer into the `{{COMM_LANGUAGE}}` slot of the *Communication language* block when `AGENTS.md` is created (step 5). See [Communication contract](${CLAUDE_SKILL_DIR}/references/contracts.md#communication-contract). This sets the **dialogue** language only — never the files.
19
+ 4. **Choose agent attribution — ASK the user explicitly and wait for the answer.** May the agent attribute work to itself / to AI — `Co-Authored-By` trailers, "Generated with …" footers, "AI"/agent/model mentions in code, comments, commit messages, PR titles/bodies, or docs? **Default to `off`** (no agent/AI mention anywhere) unless they opt in — people are routinely surprised to find an AI listed as a repo contributor. Carry the answer into the `{{AGENT_ATTRIBUTION}}` slot of the *Attribution* block when `AGENTS.md` is created (step 5). **If `off` and the project uses Claude Code**, also set `"includeCoAuthoredBy": false` in the project's `.claude/settings.json` (create it if absent) — the trailer is added by the harness, so a doc directive alone won't stop it. See [Attribution contract](${CLAUDE_SKILL_DIR}/references/contracts.md#attribution-contract).
20
+ 5. **Entry-point doc.** If `AGENTS.md` / `CLAUDE.md` already exist (step-1 recon), do **not** overwrite — show the user and ask whether to merge or replace. Otherwise create `AGENTS.md` (the cross-agent standard — Codex / Cursor / Devin Desktop / Copilot read it natively) from `${CLAUDE_SKILL_DIR}/references/templates/AGENTS.md`, and symlink `CLAUDE.md -> AGENTS.md` (`ln -s AGENTS.md CLAUDE.md`) for Claude Code — single source, no duplication. For nested context, add a subdir `AGENTS.md` (+ a `CLAUDE.md` symlink beside it for Claude Code).
21
+ 6. **Deploy `docs/ai/`.** Create every `docs/ai/` file + `pages/` from `${CLAUDE_SKILL_DIR}/references/templates/` (the template loop deploys each non-`AGENTS.md` template — the `.md` docs **and** the two seeded, user-editable strict-JSON configs: **`docs/ai/orchestration.json`** (the per-project recipe defaults the `procedures` advisor reads) and **`docs/ai/gates.json`** (the project's gate declaration — an empty list to fill with its own verification commands, consumed by `${CLAUDE_SKILL_DIR}/references/modes/gates.md`)). Keep each `.md` file's frontmatter (`type / lastUpdated / scope / staleAfter / owner / maxLines`); the `.json` seeds carry no frontmatter (the docs cap-validator globs `*.md` only, so they are inherently skipped).
22
+ 7. **Fill templates** per the table below.
23
+ 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.
24
+ 9. **Wire / hide** per visibility (see [Visibility contract](${CLAUDE_SKILL_DIR}/references/contracts.md#visibility-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.
25
+ - **visible** — wire the `package.json` scripts + add the minimal `.gitignore`. **Do not run the hide tool.**
26
+ - **hidden** — run the kit's hide writer (one managed block in the **project-local** `.git/info/exclude`, covering the kit's own artifacts **and** every known AI/agent tool's footprint — never the machine-global excludes): `node ${CLAUDE_SKILL_DIR}/tools/hide-footprint.mjs --dir <project> --dry-run` **first** (changes nothing, prints the plan), then the same without `--dry-run`. Handle what it surfaces, in plain language (never the tool's internal terms):
27
+ - A path it reports as **already committed** can't be hidden by ignoring it and is **never un-tracked silently** — show the user the printed `git rm --cached <path>`, let them decide, then opt it in with `--include=<path>`.
28
+ - A **present file with a generic name** it flags (e.g. `GEMINI.md`) → ask before `--include=<path>`.
29
+ - If it reports a **leftover machine-wide ignore block** from an older deployment, **ask before removing it** — it could affect another of the user's repos that relies on the same machine-wide rules; on a yes, re-run with `--remove-global` (prints a restorable backup). Otherwise it is kept (harmless — the project-local rules win).
30
+ - Report the result plainly (what is now hidden). **No Node on the agent host** → write the one managed block into `.git/info/exclude` by hand from the contract's path list, and report the manual step. **Windows is supported.**
31
+ - **Do not edit `package.json`** in hidden mode — a tracked change leaks the whole system.
32
+ 10. **Stamp the deployment lineage.** Write the **deployment-lineage head** into
33
+ `docs/ai/.workflow-version` (one semver line). The lineage head is **`1.3.0`** — the shared
34
+ `agent-workflow` deployment lineage, **NOT** this kit's npm package version (see
35
+ `package.json` / `CHANGELOG.md`). The two are
36
+ independent axes: a packaging-only release bumps the package but leaves the lineage head until a
37
+ migration actually changes the deployed `docs/ai` structure. A stamp greater than the head →
38
+ STOP (never downgrade).
39
+ 11. **Report & ask.** Show `tree docs/ai/`, 2–3 lines on what was filled with real data vs left as TODO, then print the **report footer** in the canonical order (version block → one-line backend-status line → welcome mat — the shared contracts in `${CLAUDE_SKILL_DIR}/references/shared/report-footer.md`, rendered from the helpers, same host-can't-run skip-with-reason). The welcome mat ends on **one** recommended next step — including the optional, opt-in `/agent-workflow-kit velocity` (a read-only allowlist so routine read-only commands stop prompting; `${CLAUDE_SKILL_DIR}/references/modes/velocity.md`) or, once gates are declared, `/agent-workflow-kit hook` (auto-approve your own declared gate commands; `${CLAUDE_SKILL_DIR}/references/modes/hook.md`) when nothing more pressing applies, never run without a yes. Then **ask before committing** — never auto-commit.
40
+
41
+ Fill strategy:
42
+
43
+ | File | Strategy |
44
+ |------|----------|
45
+ | `current_state.md`, `architecture.md`, `env_commands.md`, `technical_specification.md`, `pages/index.md` | Fill with **real** recon data (stack, scripts, layers, routes). |
46
+ | `tech_reference.md` | Carry over real configs/patterns found in deps. |
47
+ | `active_plan.md`, `handover.md` | TODO seed (e.g. "Bootstrap session — fill domain sections after first real work"). |
48
+ | `decisions.md` | Seed `AD-001` (adopting this memory system). |
49
+ | `known_issues.md`, `changelog.md`, `pages/shared-patterns.md` | Empty template / first bootstrap entry. |
@@ -0,0 +1,17 @@
1
+ ### Mode: gates
2
+
3
+ The **generic project gate runner** — it batches the project's OWN declared verification commands into one run. The runner itself **writes nothing, never commits, and never runs a subscription CLI**; what it EXECUTES is the project's own declaration, with the caller's privileges (trust posture: a batching convenience over commands the project already runs by hand — **not a sandbox**).
4
+
5
+ Run `node ${CLAUDE_SKILL_DIR}/tools/run-gates.mjs [--cwd <project>] [--only <id>]…`:
6
+
7
+ 1. **Reads `docs/ai/gates.json`** (strict JSON, hand-editable; seeded from `references/templates/gates.json`). Each gate is `{ id, title, cmd }` — `id` a unique kebab handle, `cmd` **ONE bash command line** (brace/glob expansion works; a host without bash gets a loud preflight error, exit 6 — never a silent reinterpretation under another shell). The declaration names **WHAT to check, never who executes it** — the schema has no lane/model/routing fields and rejects unknown keys loudly.
8
+ 2. **Runs each gate from the project root** and prints a per-gate **PASS/FAIL table** plus **one machine-readable summary line** as the last line (`[run-gates] status=… gates=… passed=… failed=… failed_ids=…`). A failing gate's own output is preserved **verbatim** (triage without re-running); a green gate's output is not echoed; gates after a failure still run. **Exit 0 iff all selected gates are green.**
9
+ 3. **Honest outcomes, each distinct — never a silent green:** a **missing** declaration (exit 3 — the report names the recovery: create `docs/ai/gates.json` from the template; `upgrade` re-seeds a missing one), an **empty** `gates` list (exit 4), a **malformed/invalid** declaration (exit 5, loud `path: reason`). Repeatable **`--only <id>`** re-runs a subset; an unknown id is a loud usage error (exit 2).
10
+
11
+ The declaration is **seeded at bootstrap** (the template loop, `${CLAUDE_SKILL_DIR}/references/modes/bootstrap.md` step 6) and **ensured-if-missing on upgrade** from THIS kit's own template twin (`${CLAUDE_SKILL_DIR}/references/modes/upgrade.md` step 3) — independent of the installed memory substrate's age; an existing file is always **preserved byte-for-byte**. It is deliberately **not** a delegation-required memory asset: gates are optional, and absence is an honest runner outcome, not a deployment failure.
12
+
13
+ Declared gates can also be **auto-approved** (no permission prompt on a byte-exact invocation from the project root) via the opt-in PreToolUse hook — `${CLAUDE_SKILL_DIR}/references/modes/hook.md`: the SAME declaration, a second consumer; editing gates.json needs no re-wiring.
14
+
15
+ **Candidate line — the review-receipt gate (opt-in, never auto-seeded; AD-021).** Projects that configure a reviewed/council `plan-execution.review` recipe can declare the AD-038 review-state check as one more gate — the exact candidate `{ id, title, cmd }` line and its contract live under `${CLAUDE_SKILL_DIR}/references/modes/review-state.md` (step 3). The template `gates.json` stays EMPTY; adding the line is the maintainer's explicit consent, by hand.
16
+
17
+ **Invariants:** the runner writes nothing · never commits · never runs a subscription CLI · executes only the project's OWN declared commands (never a kit-invented one) · the bash contract fails loud, never reinterprets.
@@ -0,0 +1,12 @@
1
+ ### Mode: grounding
2
+
3
+ The **grounded-review facts assembler** (AD-038) — an ungrounded `agy` review GUESSES, and while the grounding contract is mechanized (`agy-review code --facts @f`), populating the facts file was a manual chore. This mode emits the two **mechanical** halves of a facts payload; the orchestrator still owns any judgment-bearing additions. **Catalogued honestly as a WRITER** — `--out <path>` writes one file — with the invariant: `--out` accepts **only gitignored / out-of-repo scratch destinations** and REFUSES a tracked path AND an in-repo not-ignored path (a new untracked file would itself move the review fingerprint the facts are about to ground); **stdout is the default**. It never commits and never runs a subscription CLI.
4
+
5
+ Run `node ${CLAUDE_SKILL_DIR}/tools/grounding.mjs [--constraints] [--plan <path>] [--reserve-bytes <n>] [--out <path>]`:
6
+
7
+ 1. **`--constraints`** — slice the root `AGENTS.md` **Hard Constraints** section, verbatim and whole (exactly ONE matching heading; zero or several is a loud STOP, never a guess — the marker-slot discipline).
8
+ 2. **`--plan <path>`** — extract the plan's decision-bearing canonical sections, verbatim + whole: `## Approach` (REQUIRED — its "What we are NOT doing" text rides inside; it is not a heading in canon) and `## Verification` (REQUIRED — STOP if missing), plus `## Decisions (locked)` when present (the optional engine §7 heading); a DUPLICATE heading is always a STOP.
9
+ 3. **Byte budget** — the output honors the same `AGY_MAX_PROMPT_BYTES` contract the agy wrapper enforces (override may only tighten; the OS argv ceiling is rejected), MINUS **`--reserve-bytes <n>`** — the artifact share the caller expects `agy-review` to add around these facts. Overflow is trimmed tail-first with a loud in-band marker + stderr report — never a silent cut.
10
+ 4. Feed the result to the wrapper: `agy-review code --facts @<out>`. The `procedures` advisor renders this invocation as a concrete pre-step whenever the resolved review dispatch includes agy — populated with the in-flight plan path when exactly one plan is in flight.
11
+
12
+ **Invariants:** writer (writes at most the ONE `--out` scratch file — gitignored / out-of-repo only) · never commits · never runs a subscription CLI · verbatim slices only (assembly is mechanical; facts judgment stays with the orchestrator).
@@ -0,0 +1,7 @@
1
+ ### Mode: help
2
+
3
+ Read-only. The single discoverable **command index** — it answers *"what can `/agent-workflow-kit` do, and which commands change things?"* It **never writes, never commits, and never runs a subscription CLI**.
4
+
5
+ Run `node ${CLAUDE_SKILL_DIR}/tools/commands.mjs` (add `--json` for the machine-readable catalog) and present its grouped index — **Inspect / Configure / Orchestrate / Lifecycle**, each command tagged **read-only / writer / guarded / runs-project-commands** (the last: the kit writes nothing, but the mode executes the project's OWN declared commands — the `gates` runner) — in the user's conversational language. That catalog is the **single source of truth** for the command surface (the same one the bootstrap / upgrade report footers point at); `routeInvocation(token)` in the same file is the executable contract for which invocation maps to which mode.
6
+
7
+ `help` is also the landing spot for any **unrecognized or ambiguous** invocation — and that path is **always read-only** (the safe-routing rule under *Version status & the two axes*). When you arrive here that way, render the index and, in plain language, note that the invocation wasn't recognized so nothing was changed.
@@ -0,0 +1,24 @@
1
+ ### Mode: hook
2
+
3
+ The opt-in **gate-approval PreToolUse hook** — the family's third `.claude/` writer (velocity discipline), and the shipped closure of the velocity trust-posture residual (**AD-021 scope C, probe-proven in AD-037**). It places a **self-contained** hook runtime at `.claude/hooks/agent-workflow-gates.mjs` (no kit imports — it keeps working if the kit is uninstalled) and wires ONE `PreToolUse` `"Bash"` entry into `.claude/settings.json`. Per Bash call the hook then walks a decision ladder, first match wins:
4
+
5
+ - **Auto-approve** a command **byte-identical** (leading/trailing trim only — no whitespace collapsing, no quote/glob/variable interpretation, no prefix or pattern matching, ever: patterns are what made AD-021 auto-seeding rejected) to a gate `cmd` declared in `docs/ai/gates.json` — read **LIVE on every call** (editing gates.json never needs re-wiring; one declaration, two consumers with `${CLAUDE_SKILL_DIR}/references/modes/gates.md`) — invoked **from the project root** (gates run from the root by contract; the same bytes from a subdirectory are NOT approved) and under `default`/`acceptEdits` permission mode (an approval never loosens `plan`/`bypassPermissions`).
6
+ - **Ask** on a command whose leading tokens match the velocity **seeded read-only core** when it carries the documented runtime residual — output redirection, command substitution, or the bounded `--output` write-flag family — surfacing a human prompt even where a seeded allow rule would have silently approved (**hook `ask` overrides an allow rule — proven live**: on Claude Code 2.1.185 a seeded `Bash(git log:*)` silently wrote a file via `git log --output=…`; with the hook wired the same call prompts). Detection is string-level and conservative: a quoted metacharacter may over-ask, never under-allow.
7
+ - **Stay silent otherwise** — the normal permission flow proceeds unchanged. The hook **never emits `deny`**; nothing is hard-blocked.
8
+
9
+ **Honest residual status (AD-037):** current engine builds already intercept `>` redirection and `$()` substitution upstream (observed headless on 2.1.185); the **`--output` family was proven open** and is the seam this hook demonstrably closes. The guard still covers all three documented classes (defense-in-depth — engine behavior may vary across surfaces/versions). **Fail-safe, decoupled:** a missing/broken/invalid `gates.json` disables ONLY gate auto-approval — the residual guard keeps running; every anomaly path exits 0 (the hook is never the blocker or the noise — the `gates` runner reports a broken declaration at its own point of use). **Not a sandbox:** it closes the named residual for the seeded core and auto-approves declared gates; it does not police arbitrary commands or user-added rules.
10
+
11
+ **Trust posture (state it plainly when asking consent):** the hook removes the PROMPT only for commands the human already declared in `docs/ai/gates.json` — the same trust boundary as the `gates` runner, which executes them with the caller's privileges. **gates.json thereby becomes a privileged file**: whoever can edit it can get its commands auto-approved. An invalid declaration approves NOTHING (strict parse, exact validation parity with the runner).
12
+
13
+ **Version-status routing** like the other writer modes (stamp head `1.3.0`; `--apply` enforces it in code).
14
+
15
+ Run `node ${CLAUDE_SKILL_DIR}/tools/gate-hook.mjs [--dry-run | --apply] [--cwd <dir>]`:
16
+
17
+ 1. **`--dry-run` first, always** (the default — changes nothing): previews the placement and the exact settings entry it would merge. It STOPs (zero writes) on: a symlinked `.claude` / `.claude/hooks` / target file / non-regular `settings.json`; malformed settings JSON; a **malformed existing `hooks` shape** (never a merge-through-clobber); an unsafe `permissions.defaultMode` in **either** settings file; or a target hook file with **different** content while our entry is not wired (**it refuses to wire an unknown script as a PreToolUse hook** — the recovery is named: delete the file to reseed from the bundle).
18
+ 2. **Ask consent** via **`AskUserQuestion` where supported**, the no-change option first: keep prompting for gate commands, or place + wire the hook — presenting the trust posture above in plain language.
19
+ 3. **Only on an explicit yes**, re-run with `--apply`. It places the file FIRST, then wires settings (a wired-but-missing entry would error on every Bash call); merge-don't-clobber (foreign hooks/matchers/keys and existing permissions preserved; re-apply never duplicates); **settings hot-reload — the hook is active for new Bash calls, no session restart needed**. An identical existing file is *already current*; a diverged-but-already-wired file is reported, never clobbered or unwired.
20
+ 4. **Hidden-mode deployments:** after apply, run the hide-footprint reconcile (`node ${CLAUDE_SKILL_DIR}/tools/hide-footprint.mjs --dir <project> --reconcile`) — `/.claude/hooks/` is in the known-footprint registry; the apply report reminds you.
21
+
22
+ **Invariants:** writes ONLY `.claude/hooks/agent-workflow-gates.mjs` + `.claude/settings.json` · never `settings.local.json` · never commits · exact-match approval only (no patterns) · never `deny` · never auto-wired by `init`/`upgrade` (placement stays opt-in — the AD-011/AD-034 boundary: init/upgrade may refresh placed things, never place new ones).
23
+
24
+ **Exit codes:** `0` done / dry-run (incl. the reported diverged-but-wired state); `1` a precondition STOP; `2` bad arguments.
@@ -0,0 +1,18 @@
1
+ ### Mode: procedures
2
+
3
+ Read-only **activity-procedures advisor**. Answers *"what are the steps of this named activity, and which recipe applies at each slot here?"* It composes the orchestration recipes (`${CLAUDE_SKILL_DIR}/references/modes/recipes.md`) into **named activities** with **typed recipe slots**. It **never writes, never commits, never runs a subscription CLI** — the deterministic resolution lives in the kit; the orchestrator runs the resolved recipe via the bridge skills and **owns any commit when the activity has a commit boundary** (a backend never commits). Not every activity commits: `plan-authoring` ends at approval and produces no commit (plans are ephemeral, never committed); `plan-execution` commits per Step.
4
+
5
+ The two v1 activities (canon in the **installed engine**, `references/procedures.md`):
6
+
7
+ - **`plan-authoring`** (slot: `review`) — research → draft → self-review → **review {recipe}** → fold/loop → present for approval; enforce the mandatory Cleanup.
8
+ - **`plan-execution`** (slots: `execute`, `review`) — per Step: resolve the recipe → if Delegated, dispatch execution first → implement → self-review → **review {recipe}** → gates → commit boundary.
9
+
10
+ Run **`node ${CLAUDE_SKILL_DIR}/tools/procedures.mjs <activity> [--override <slot>=<recipe>]… [--json]`**. It reads the activity's steps live from the engine and prints them **verbatim**, then the **resolved effective recipe per slot** from the per-project config + the read-only backend detector:
11
+
12
+ 1. **Config = `docs/ai/orchestration.json`** — strict JSON, **agent-writable via `/agent-workflow-kit set-recipe` (`${CLAUDE_SKILL_DIR}/references/modes/set-recipe.md`) OR hand-edited** (the kit reads + validates it; `procedures`/`recipes` stay read-only — the writer is `set-recipe`). Shape: `{ "<activity>": { "<slot>": "<recipe>" } }`; all slots optional (an absent slot → its computed default, stated); an optional `"_README"` string is allowed + ignored. `review` accepts `solo|reviewed|council`; `execute` accepts `solo|delegated`. Seeded by `init` (a user-editable template) — see `${CLAUDE_SKILL_DIR}/references/modes/bootstrap.md`.
13
+ 2. **Default resolution (config silent):** `review` → Reviewed if any review-capable backend is `ready`, else Solo (never Council by default); `execute` → Solo (Delegated is opt-in). **Degradation:** a config/computed default degrades **gracefully with a stated reason** (Council → Reviewed → Solo; Delegated → Solo); a per-run **`--override <slot>=<recipe>`** that can't be satisfied degrades **loudly** (a flagged warning, so you tell the user) — but is **still exit 0** (a valid request that gracefully degraded).
14
+ 3. **Exit codes:** `0` success; `2` usage (unknown `<activity>` / bad `--override` — a bare `--override <recipe>`, an unknown slot, an invalid recipe-for-slot, or a duplicate slot); `1` config error (malformed / schema-invalid / unreadable `orchestration.json`) **or** engine error (the installed engine is absent / invalid / **too old** to ship `references/procedures.md` — upgrade it with `npx @sabaiway/agent-workflow-engine@latest init`). A `1`/`2` failure is loud (`path: reason`), never a silent fallback.
15
+
16
+ **Cap-soft-skip degradation (the feature's only AUTO route).** The activity procedures are auto-discoverable only through the one-line **`workflow:methodology`** pointer (this kit + the engine carry `disable-model-invocation:true`, so NL like "write a plan" does **not** auto-load this skill). On a deployment whose methodology pointer was cap-soft-skipped — or whose pre-existing customized pointer lacks the procedures clause — the procedures are still reachable by **explicitly** invoking `/agent-workflow-kit procedures`; surface that plainly rather than treating it as a gap.
17
+
18
+ **Invariants:** read-only · never writes · never commits · never runs a subscription CLI · the deterministic resolution is the kit's, the recipe execution is the orchestrator's.
@@ -0,0 +1,18 @@
1
+ ### Mode: recipes
2
+
3
+ Read-only **orchestration advisor**. Answers *"how should I compose the optional execution-backends into plan → execute → review here, and which recipe fits?"* It **never writes, never commits, never runs a subscription CLI, and never executes a recipe** — the orchestrator (you) runs the chosen recipe through the bridge skills and makes the single commit; a backend is advisory or delegated, never autonomous.
4
+
5
+ The four recipes (defined over each bridge's `provides` roles — `codex`: execute + review; `agy`: review + probe), canonical narrative in the **installed engine** (`references/orchestration.md`):
6
+
7
+ - **Solo** — you plan, execute, and self-review; no backend (always available; the floor).
8
+ - **Reviewed** — you execute; **one** backend reviews the result (advisory). Prefers `codex` when both are ready (`agy` carries a standing health caveat).
9
+ - **Council** — **both** backends review independently; you synthesize the two opinions.
10
+ - **Delegated** — you hand a **bounded** execution sub-task to a backend (`codex exec`), then review the returned diff and commit.
11
+
12
+ 1. Run **`node ${CLAUDE_SKILL_DIR}/tools/recipes.mjs`** (the read-only planner; `--json` for the structured form). It runs the backend detector, lists the four recipes, and prints — for the current environment — a **per-recipe dispatch plan that degrades with a stated reason** when a backend isn't `ready` (Council → Reviewed → Solo; Delegated → Solo), plus advisory **quota/health notes** (prefer the cheapest model; Council spends two backends' quota; `agy` may stall on substantive prompts — Issue-001, prefer `codex`).
13
+ 2. **Offer the choice** via **`AskUserQuestion` where your agent supports it** (`AskUserQuestion` in Claude Code) — one option per recipe, the `recommendRecipe` choice listed **first** — otherwise in prose. Then print `planRecipe(chosen, detection)` (the per-stage dispatch + degradation reasons + quota/health notes) so the user sees exactly what running it entails.
14
+ 3. **Availability = `readiness === ready`, full stop.** Every other readiness supplies the human reason (needs-skill → "not installed — `/agent-workflow-kit setup`"; needs-cli → "install the CLI"; needs-credentials → "log in"; degraded → "wrapper not on PATH — `/agent-workflow-kit setup`"). This is set-up state only — **never** a claim that a backend's service is responsive (the detector cannot observe a runtime stall; `agy`'s Issue-001 is a *standing advisory*, not a readiness signal).
15
+
16
+ **The configured-recipe line (`--active-line`, read-only).** `node ${CLAUDE_SKILL_DIR}/tools/recipes.mjs --active-line` prints exactly **one** machine-composed line: the **CONFIGURED** recipe of every activity/slot, resolved from the target project's `docs/ai/orchestration.json` (read from the current directory) + live readiness — each slot with its source (configured vs computed default), its degradation stated, and its dispatched wrapper set — explicitly contrasted with the readiness **recommendation** (which is informational; the configured recipes are what runs). Paste it verbatim: it fills the session-start discovery step (the deployed `agent_rules.md` §1.1) and the handover "Active recipes:" slot; `set-recipe` echoes the same line after every successful write. A malformed config fails loud (exit 1), never a silent fallback.
17
+
18
+ **Invariants:** read-only · never runs a subscription CLI · never commits · the orchestrator executes the recipe via the bridge skills, not the kit.
@@ -0,0 +1,13 @@
1
+ ### Mode: review-state
2
+
3
+ Read-only **review-receipt checker** (AD-038) — it makes *"reviewed ≠ shipped"* mechanically detectable. The bridge review wrappers (`codex-review` / `agy-review`, from bridge version 2.2.0) append one receipt line per **successful** review to a file **inside the git dir** (`<git dir>/agent-workflow-review-receipts.jsonl` — never committable by construction; `AW_REVIEW_RECEIPTS` overrides). This mode resolves the effective `plan-execution.review` recipe (the SAME config + read-only detector the `procedures` advisor reads), recomputes the canonical **uncommitted-state fingerprint** (staged + unstaged + untracked-not-ignored contents — exactly the review-payload domain; the prose definition lives in each bridge's `capability.json` review contract, implementations cross-checked by the kit's fingerprint-parity test), and reports, per recipe-named backend, whether a **fresh, grounded, current-fingerprint** receipt exists. It **never writes, never commits, never runs a subscription CLI**; it does spawn **read-only `git` queries** to compute the fingerprint — stated honestly (that is still read-only, but it is a subprocess).
4
+
5
+ Run `node ${CLAUDE_SKILL_DIR}/tools/review-state.mjs [--check] [--json]`:
6
+
7
+ 1. Plain run → the human report: resolved recipe + source, plan-in-flight, tree fingerprint, per-backend receipt state (current / stale / ungrounded / missing) with verdict + grounding + timestamp.
8
+ 2. **`--check`** → the gate exit code. The **normative exit contract lives in the tool header** (the single home — do not re-enumerate it elsewhere): exit 0 for a solo-resolved recipe (configured, or degraded there — no ready reviewer), no plan in flight (the `docs/plans` naming convention: `queue.md` and `EXECUTE-`/`FEEDBACK-`-prefixed or `PROMPT`/`prompt`/`handoff`-carrying names are scratch), a clean tree, a non-git cwd, or every recipe-named backend receipted **current + grounded**; exit 1 when a backend is missing, **stale** (ANY edit after its review moves the fingerprint), or grounded:false under reviewed/council. **Presence, not unanimity:** verdict adjudication (ship/revise, the divergence crossover) stays orchestrator judgment — the gate only proves the configured backends really reviewed THIS tree. Plan/diff receipts and continuations (`agy-review --continue`) are **informational-only**: after a fold, only a **fresh grounded re-run** (`codex-review code`; `agy-review code --facts @f`) restores green.
9
+ 3. **Wire it as a gate by hand — never auto-seeded (AD-021).** The candidate line for your own `docs/ai/gates.json`: `{ "id": "review-state", "title": "Review receipts current for the uncommitted tree", "cmd": "node <path-to-this-skill>/tools/review-state.mjs --check" }` — with the path your project actually reaches the kit by. Once declared, the opt-in `${CLAUDE_SKILL_DIR}/references/modes/hook.md` auto-approves it like any other declared gate.
10
+
11
+ **Human residual (stated, accepted):** `git commit --no-verify` and receipt-file deletion/forgery remain possible — this is a self-discipline mechanism against silent process drift, not a security boundary.
12
+
13
+ **Invariants:** read-only · never writes · never commits · never runs a subscription CLI · spawns read-only `git` queries only · the receipt writers are the bridge review wrappers, never the kit.
@@ -0,0 +1,23 @@
1
+ ### Mode: set-recipe
2
+
3
+ The **config writer** for `docs/ai/orchestration.json` — the answer to *"set my standing recipe preference without hand-editing JSON."* **Division of labor (AD-025):** YOU turn the user's plain language into explicit ops; the KIT does the deterministic validate → merge → preview → write. It **previews by default** (writes nothing); `--write` applies. It **never runs a backend and never commits**. Hand-editing `docs/ai/orchestration.json` stays fully supported — this is an offered convenience, never a lock.
4
+
5
+ **Map the user's plain language → explicit ops** (the kit ships no NL parser; it performs no `all`-magic, so you expand scope explicitly, asking when unclear):
6
+
7
+ | user says (RU/EN) | op | scope |
8
+ |---|---|---|
9
+ | "оба ревьюят" / "both review" | `--set <activity>.review=council` | **disambiguate**: which activity? If both, pass `--set plan-authoring.review=council --set plan-execution.review=council`. |
10
+ | "один ревьюер" / "one reviewer" | `--set <activity>.review=reviewed` | per the named activity, else ask |
11
+ | "делегируй исполнение" / "delegate execution" | `--set plan-execution.execute=delegated` | execution only |
12
+ | "верни как было / сам" / "revert / do it myself" | `--unset <activity>.<slot>` | the named slot → its computed default |
13
+
14
+ Run **`node ${CLAUDE_SKILL_DIR}/tools/set-recipe.mjs [--set <activity>.<slot>=<recipe>]… [--unset <activity>.<slot>]… [--write] [--json]`**:
15
+
16
+ 1. **Grammar — always fully-qualified `<activity>.<slot>`** (the kit never guesses the activity; a bare `review=council` is rejected). `review` accepts `solo|reviewed|council`; `execute` accepts `solo|delegated`. Activities/slots: `plan-authoring.review`, `plan-execution.execute`, `plan-execution.review`.
17
+ 2. **Preview by default** — prints `current → proposed` for the **changed** slots only, plus the **effective recipe resolved against live backend readiness** (degradation stated honestly, e.g. *council requested, 1 ready reviewer → runs reviewed until a 2nd backend is ready*). It writes **nothing**. Re-run with **`--write`** to apply (same effective/degradation note — a direct `--write` is never quieter than the preview). `--unset` returns a slot to its computed default (reverting needs no hand-edit either). A no-op `--set` (slot already equals) writes nothing and never re-seeds the onboarding note.
18
+ 3. **`--write`** applies via a hardened, atomic write (deployment-gated — refuses to scatter a config into a repo with no `docs/ai`; exclusive-create temp + rename; symlink/TOCTOU-safe; last-writer-wins). It preserves the onboarding note + every untouched slot, normalizing to canonical 2-space JSON.
19
+ 4. **Exit codes:** `0` success (an explicit recipe that gracefully degrades is still `0`); `2` usage (a bare/duplicate op, or `--write` with no ops); `1` config error (malformed/unreadable config — the file is left **untouched**, never clobbered) or a write STOP (no deployment / a symlinked config). A `1`/`2` failure is loud; on a malformed config, offer to show the parse error so you can help the user fix the JSON.
20
+
21
+ Output is **English/structured** — **localize it to the user's conversational language** when you narrate. Surface the effective-recipe/degradation note plainly.
22
+
23
+ **Invariants:** writer (writes only `docs/ai/orchestration.json`) · never commits · never runs a subscription CLI · previews by default · degradation honesty on preview AND `--write` · hand-edit stays first-class.
@@ -0,0 +1,30 @@
1
+ ### Mode: setup
2
+
3
+ The **only writer** among the backend modes, and **opt-in / in-agent only** — **placement** is **never** part of `init`. The npx installer deploys the *kit* and bundles the bridge skills in its tarball, but **does not place** them (that honesty claim is load-bearing — see `decisions.md` AD-009 / AD-011); **once placed** by `setup`, `init` and `${CLAUDE_SKILL_DIR}/references/modes/upgrade.md` keep the placed copy fresh via the refresh-only `--refresh-placed` (below) — **never a first placement, never a downgrade**. `setup` owns exactly the two deterministic, secret-free steps and **guides** the rest. It **never commits and never runs a subscription CLI**.
4
+
5
+ Run `node ${CLAUDE_SKILL_DIR}/tools/setup-backends.mjs [<backend>] [--bindir <path>] [--dry-run]`:
6
+
7
+ - `<backend>` — `codex` | `agy` | `antigravity` | `codex-cli-bridge` | `antigravity-cli-bridge`; omit for **all**.
8
+ - `--bindir <path>` — where to link the wrappers (default `~/.local/bin`).
9
+ - `--dry-run` — print the per-backend plan and change **nothing** (run this first).
10
+ - `--refresh-placed` — the **refresh-only** mode (what `init` runs automatically and `${CLAUDE_SKILL_DIR}/references/modes/upgrade.md`
11
+ runs as its fourth stamp-independent reconcile): refresh every bridge `setup` **already placed**
12
+ from the kit's bundled copies + re-link its wrappers; an absent bridge is a stated skip (**never**
13
+ placed), a placed bridge newer than the bundle is a stated skip naming the kit update (**never**
14
+ downgraded), and every outcome line is composed by the tool — paste verbatim. Does not combine
15
+ with `--dry-run`.
16
+ - `--help`, `-h` — usage.
17
+
18
+ For each backend it:
19
+ 1. **Places / refreshes the bundled bridge skill** (from the kit's `bridges/<name>/` mirror) into its canonical dir — but only when that dir is **absent / empty / proven-managed** (valid manifest, matching `name`+`kind`). A `stub` / `foreign` / `invalid` / `unsupported` dir, a marker fs-error, or a symlinked dir → **STOP**, never overwritten. Refresh re-runs on a proven-managed dir so re-running `setup` delivers bundled fixes.
20
+ 2. **Links its wrappers** (`codex-exec` / `codex-review`; `agy-review` / `agy-run`) onto `--bindir` via **managed symlinks** — replacing only a symlink that already points at our source. A non-symlink or a foreign symlink → **STOP**; it **preflights every target first**, so a conflict on one wrapper makes **zero** changes. If `--bindir` is not on `PATH`, it prints the one-line `export PATH=…` to add — it never edits a shell rc.
21
+ 3. **Guides the manual, secret-bearing steps it will NOT automate** — the binary install (each bridge's `setup/README.md` §1) and the one-time interactive subscription login (`codex login` / `agy`) — printing the exact command for whichever axis is still missing (axis-aware: it can ask for both the CLI and the login at once).
22
+
23
+ **Close-the-loop output (surface both, localized).** The tool prints, after the per-backend report:
24
+ - a **bridge version** on each skill line — `(vX)` for a fresh place / equal refresh, `(vOld → vNew)` when a refresh bumps the bridge (never `vnull → …`);
25
+ - a **status pointer** — the full family + deployment version view lives in `/agent-workflow-kit status`;
26
+ - a **proactive recipe offer** when a setup just made a review backend ready (re-detected AFTER apply, so it reflects the real new state): it prints `/agent-workflow-kit set-recipe --set plan-authoring.review=<depth>` **and** `…plan-execution.review=<depth>` (Council when both are ready, else Reviewed). Relay it in plain language: offer to set the review recipe for **both** planning and execution review (preview first; you'll write it via `${CLAUDE_SKILL_DIR}/references/modes/set-recipe.md`, or they can hand-edit) — never offer only `plan-execution`. Ask if the scope is unclear.
27
+
28
+ **Windows:** the wrappers are POSIX `.sh`; on `win32` it reports *unsupported — use WSL* and mutates nothing.
29
+
30
+ **Exit codes:** `0` = done / already set up / only manual steps remain (guidance is never a failure); **non-zero** = a STOP (a dir/symlink it refuses to clobber), a bad argument, a missing bundle, or a native fs error (the underlying reason is preserved in the message).
@@ -0,0 +1,22 @@
1
+ ### Mode: status
2
+
3
+ Requires: ${CLAUDE_SKILL_DIR}/references/shared/report-footer.md
4
+
5
+ Read-only. The **single answer to "versions + deployment + settings + bridges"** across the whole family — `tools/family-registry.mjs` aggregates every member's `capability.json` and surveys the project. It **never writes, never commits, and never runs a subscription CLI**.
6
+
7
+ Run `node ${CLAUDE_SKILL_DIR}/tools/family-registry.mjs --json [--dir <project>]` and render it **compact**, in the user's conversational language — **never paste the JSON or any internal field name** (no-leak rule). Map the **`installed[].state`** token via the value→plain-language map under *The version block + welcome mat* in `${CLAUDE_SKILL_DIR}/references/shared/report-footer.md` (the `visibility` and wrapper states have their own phrasings, below). Present, each area on its own line(s), routing detail to its domain mode:
8
+
9
+ 1. **Versions — a status-only render from `installed[]` + `deploymentHead`** (this is **NOT** the shared notes-based version block — see the separation note below): the **`docs/ai` structure version** (named as such, never "lineage head"), then each member by its `display` showing its `version` (or, when there is no version, the plain phrase for its `state`, mapped above), plus the two-axes disambiguation. **Freshness comes from `installed[].refresh`, not from `notes`:** for each member whose **`refresh.behind`** is `true`, show a **localized "needs refresh"** label and the **verbatim `refresh.recommend`** command **exactly once** (the command/package name stays source-language; **do not also paste the English `notes` caveats** — `refresh.recommend` is the single source of the recovery step, so the command is never duplicated on this surface). A member whose **`refresh.freshness`** is **`unknown`** is surfaced too — a localized *"couldn't be checked"* label; it is **never counted as current and never as behind** (its `notes` caveat carries the detail on the notes-based surfaces; here the label is enough). Lead with a one-line **headline count** derived from `installed[].state` + `refresh.behind` + `refresh.freshness` (e.g. *"5 members installed · 1 needs a refresh · 1 couldn't be checked"* — omit a zero count).
10
+
11
+ > **Status reads `refresh`; the shared version block + the bootstrap/upgrade footers stay `notes`-based (unchanged this release).** `${CLAUDE_SKILL_DIR}/references/modes/status.md` has its OWN status-only render (above), keyed on `installed[].refresh.behind` / `refresh.recommend`. The shared **version block** (under *The version block + welcome mat* in `${CLAUDE_SKILL_DIR}/references/shared/report-footer.md`) and the bootstrap (step 11) + every upgrade (steps 4 / 8) report footer still consume `installed[].notes` verbatim — that wiring is deliberately **untouched** here (their migration onto `refresh` is deferred). Do not rewrite those footers onto `refresh`.
12
+ 2. **Deployment (`--dir`)** (from `project`): whether `docs/ai/` is deployed + the deploy stamps by `display`; and **visibility** — render `project.visibility.state` in **user-safe words only**: *visible (tracked)* / *hidden (git-ignored, local-only)* / *unclear (uncommitted or partially set up)* — **never** the words "hidden fence" or any marker term. A `visibility.error` → surface it plainly.
13
+ 3. **Settings (`--dir`, one line each)** (from `project.settings`):
14
+ - **recipes** — the effective recipe per slot (detail → `/agent-workflow-kit procedures` / `recipes`); a `recipes.detectError` → say the backends couldn't be checked, so recipes floored at solo.
15
+ - **attribution** — `includeCoAuthoredBy` effective; call out a **local override** only when `local` is non-null **and** differs from `project` (a `null` `local` means the key is absent there, so the project value stands — that is not an override).
16
+ - **velocity** — the effective `permissions.defaultMode` + whether an allowlist is seeded (detail → `/agent-workflow-kit velocity`).
17
+ - Any area's **`error`** field → surface it **loudly** in plain language; the rest of `status` still renders (never a crash).
18
+ 4. **Bridges (host, one line)** (from `bridges[]`): per bridge — readiness + wrapper PATH-presence; render each wrapper's `state` as *on PATH* (`present`) / *not on PATH* (`missing`) / *couldn't check* (`unknown`) (detail → `/agent-workflow-kit backends` / `setup`). **No default-model claim.** "credentials present" means a marker file exists, not a live login.
19
+
20
+ Restate the **two-axes honesty** — an installed *package* version is not the project's **`docs/ai` structure version** (see *Version disclosure* in `${CLAUDE_SKILL_DIR}/references/shared/report-footer.md`); the installed version is whatever is on disk under `~/.claude/skills/…`, so a stale install shows its real (older) version, honestly. A host that can't run the helper → **skip with the concrete reason** (the helper-failure contract), never silently.
21
+
22
+ **Invariants:** read-only · never writes · never commits · never runs a subscription CLI · plain language only, no leaked internal terms.
@@ -0,0 +1,18 @@
1
+ ### Mode: uninstall
2
+
3
+ The **guarded teardown** — the inverse of `init` (the kit + engine skills) + `setup` (the bridges) + a hidden deploy. **In-agent, opt-in**, and built around one hard rule: **it never deletes user-authored content.** Run **`--dry-run` first, always**, show the user the classified plan in plain language, get explicit consent, then re-run with `--yes`. It **never commits**.
4
+
5
+ Run `node ${CLAUDE_SKILL_DIR}/tools/uninstall.mjs [<member>] [--dir <project>] [--bindir <path>] [--dry-run | --yes]`:
6
+
7
+ - `<member>` — limit the skill axis to one member (`agent-workflow-kit` / `-memory` / `-engine` / a bridge); omit for the **whole family**.
8
+ - `--dir <project>` — also reverse the **project-deployment** surfaces in `<project>`.
9
+ - `--bindir <path>` — where the bridge wrappers were linked (default `~/.local/bin`, mirrors `setup`).
10
+ - `--dry-run` — print the plan and change **nothing** (run this first). `--yes` — apply the **auto-removable** set.
11
+
12
+ It classifies every surface into four classes and acts accordingly:
13
+
14
+ - **remove** (safe) — an installed skill dir that is **provably ours** (valid manifest, `name`+`kind` match). A dir present but **not provably ours** (`foreign`/`stub`/`invalid`/unreadable) → **STOP**: left untouched **and reported**, while the teardown still removes the members that ARE ours (a not-ours surface is never clobbered, and never blocks removing the rest — the per-item `setup` posture). **Preflight-then-mutate:** if a mutable surface **changed since the dry-run** (a skill no longer ours, a wrapper turned foreign, a hook that lost our marker, a malformed fence), the run **aborts with zero changes**.
15
+ - **reverse** (managed-marker) — a bridge **wrapper symlink that points at our source** (a foreign/non-symlink one → STOP); the hidden-mode **managed fence** (via the existing `--unhide` path — only the fenced lines); a **pre-commit hook carrying our marker** (an unmarked / user hook → left + reported).
16
+ - **KEEP — never deleted** (report-only) — `docs/ai`, `AGENTS.md`, `CLAUDE.md`, `docs/plans`, and `.claude/settings.json` (the `includeCoAuthoredBy` edit **and** any `permissions.defaultMode`/`permissions.allow` the velocity profile may have seeded). The tool **prints the exact `rm` / `git rm --cached`** for the docs/entry files and an **edit** instruction for `settings.json` (never an `rm` — it may hold your own settings); the **user** runs them. Surface this in plain language; never delete on their behalf.
17
+
18
+ **Shared globals:** removing `agent-workflow-memory` / `agent-workflow-engine` / a bridge removes a **global** skill that another project on the machine may use — say so before applying. **Windows:** the wrappers are POSIX; the skill-dir + project arms still work, the wrapper arm reports *use WSL*.