@sabaiway/agent-workflow-kit 1.44.0 → 1.45.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -0
- package/README.md +6 -3
- package/SKILL.md +9 -1
- package/bridges/antigravity-cli-bridge/SKILL.md +1 -1
- package/bridges/antigravity-cli-bridge/bin/agy-review.sh +87 -16
- package/bridges/antigravity-cli-bridge/bin/agy-review.test.mjs +3 -0
- package/bridges/antigravity-cli-bridge/bin/agy.test.mjs +4 -2
- package/bridges/antigravity-cli-bridge/capability.json +3 -2
- package/bridges/codex-cli-bridge/SKILL.md +7 -7
- package/bridges/codex-cli-bridge/bin/codex-exec.sh +3 -3
- package/bridges/codex-cli-bridge/bin/codex-exec.test.mjs +4 -1
- package/bridges/codex-cli-bridge/bin/codex-review.sh +93 -22
- package/bridges/codex-cli-bridge/bin/codex-review.test.mjs +4 -0
- package/bridges/codex-cli-bridge/capability.json +4 -3
- package/bridges/codex-cli-bridge/references/driving-codex.md +5 -4
- package/bridges/codex-cli-bridge/references/sandbox-and-flags.md +5 -4
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/modes/bootstrap.md +1 -1
- package/references/modes/bridge-settings.md +1 -1
- package/references/modes/grounding.md +8 -7
- package/references/modes/recommendations.md +14 -0
- package/references/modes/review-state.md +1 -1
- package/references/modes/sandbox-masks.md +15 -0
- package/references/modes/upgrade.md +10 -7
- package/references/modes/velocity.md +13 -2
- package/references/shared/composition-handoff.md +21 -16
- package/references/shared/report-footer.md +5 -1
- package/references/templates/AGENTS.md +2 -1
- package/references/templates/autonomy.json +3 -0
- package/tools/autonomy-config.mjs +13 -3
- package/tools/commands.mjs +15 -1
- package/tools/delegation.mjs +9 -5
- package/tools/detect-backends.mjs +2 -2
- package/tools/doc-parity.mjs +8 -0
- package/tools/engine-source.mjs +6 -0
- package/tools/family-registry.mjs +21 -7
- package/tools/fold-completeness-run.mjs +5 -0
- package/tools/grounding.mjs +139 -22
- package/tools/inject-methodology.mjs +117 -28
- package/tools/manifest/schema.md +20 -0
- package/tools/manifest/validate.mjs +26 -0
- package/tools/procedures.mjs +61 -8
- package/tools/recipes.mjs +94 -15
- package/tools/recommendations.mjs +469 -0
- package/tools/review-ledger-write.mjs +14 -0
- package/tools/review-ledger.mjs +3 -2
- package/tools/review-state.mjs +101 -24
- package/tools/run-gates.mjs +3 -0
- package/tools/sandbox-masks.mjs +370 -0
- package/tools/set-recipe.mjs +13 -1
- package/tools/velocity-profile.mjs +228 -22
|
@@ -4,7 +4,7 @@ The opt-in onboarding **velocity profile** — it seeds a fixed, audited **read-
|
|
|
4
4
|
|
|
5
5
|
**Version-status routing (like the other writer modes):** read `docs/ai/.workflow-version` first — not-deployed → bootstrap; stamp < `2.0.0` → `upgrade`; stamp > head / unparseable → STOP. The tool enforces this in code too (`--apply` STOPs unless the stamp is the lineage head).
|
|
6
6
|
|
|
7
|
-
Run `node ${CLAUDE_SKILL_DIR}/tools/velocity-profile.mjs [--dry-run | --apply] [--kit-tools] [--accept-edits] [--cwd <dir>]`:
|
|
7
|
+
Run `node ${CLAUDE_SKILL_DIR}/tools/velocity-profile.mjs [--dry-run | --apply] [--kit-tools] [--bridge-tier] [--accept-edits] [--cwd <dir>]`:
|
|
8
8
|
|
|
9
9
|
1. **`--dry-run` first, always** (the default — changes nothing). It prints: the fixed read-only core it would add; a **read-only advisory** that lists your `package.json` `scripts` as **unaudited candidates you may add BY HAND** (inspect each first) to `.claude/settings.json` / `settings.local.json` — the tool **never** writes them and flags obviously-mutating names as "do not add"; any **pre-existing non-read-only `Bash(...)` entries** to consider removing by hand; and the honest residual notice (below). It STOPs (zero writes) on a symlinked `.claude` / non-regular `settings.json`, malformed settings JSON, or an unsafe `permissions.defaultMode` — `bypassPermissions` or anything outside `default`/`acceptEdits`/`plan`, present in **either** `settings.json` or `settings.local.json`.
|
|
10
10
|
2. **Ask the opt-ins** via **`AskUserQuestion` where supported** — two separate choices, the safe option FIRST in each. First the **`--kit-tools` tier** (separate from `acceptEdits`; **"core only" remains the default answer** — seed the tier only on an explicit yes, then add `--kit-tools` to the `--apply` re-run). Then the `acceptEdits` opt-in:
|
|
@@ -21,6 +21,7 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/velocity-profile.mjs [--dry-run | --apply] [
|
|
|
21
21
|
- `node ${CLAUDE_SKILL_DIR}/tools/detect-backends.mjs` (wildcard)
|
|
22
22
|
- `node ${CLAUDE_SKILL_DIR}/tools/commands.mjs` (wildcard)
|
|
23
23
|
- `node ${CLAUDE_SKILL_DIR}/tools/review-state.mjs --check` (wildcard)
|
|
24
|
+
- `node ${CLAUDE_SKILL_DIR}/tools/recommendations.mjs --cwd ${PROJECT_ROOT}` (wildcard — the read-only deployment advisor; its rendered apply one-liners are writers and still prompt)
|
|
24
25
|
- `node ${CLAUDE_SKILL_DIR}/tools/manifest/validate.mjs --strict <skill-dir>` (wildcard)
|
|
25
26
|
- `node ${CLAUDE_SKILL_DIR}/tools/release-scan.mjs <path>` (wildcard)
|
|
26
27
|
- `node ${CLAUDE_SKILL_DIR}/tools/run-gates.mjs --cwd ${PROJECT_ROOT}` — **EXACT byte-string only**, and honestly **project-exec, not read-only**: it runs YOUR declared `docs/ai/gates.json` commands — the same trust boundary the opt-in hook grants byte-exact per-cmd. A wildcard would be BROADER than that boundary (`--cwd <dir>` executes another project's declared gates), so the bare cwd-defaulting form, any other `--cwd`, `--only`, and **`--record`** forms all still prompt (`--record` WRITES a gate-run record into the review ledger — a recording run is never auto-approved, AD-048).
|
|
@@ -30,6 +31,16 @@ Honesty notes: tier entries get **NO PreToolUse-hook residual coverage** — the
|
|
|
30
31
|
|
|
31
32
|
**Invariants:** creates `.claude/` if absent and writes **only** `.claude/settings.json` (no other file); **never** allowlists commit/push/publish; **never** writes `settings.local.json`; never commits; opt-in `acceptEdits`, never silent.
|
|
32
33
|
|
|
34
|
+
**The `--bridge-tier` (own opt-in, AD-044).** Seeds what a promptless council review run needs — BOTH surfaces: `permissions.allow` prefix rules AND the wrapper names in `sandbox.excludedCommands` (the harness runs an excluded command OUTSIDE the sandbox — the wrappers need network — so a plain allowlisted invocation triggers no sandbox-bypass approval). Both land in the **project** `.claude/settings.json` — the file this writer owns; an exclusion placed only in `settings.local.json` was live-observed NOT to route the command outside the sandbox (2026-07-11: the wrapper then starts sandboxed and dies on a read-only HOME + a network prompt), so hand-wiring the local file is not a working substitute for this tier. **Honesty note:** a session whose sandbox is imposed by the harness runtime itself (e.g. an IDE-managed session sandbox) may ignore settings-level exclusions entirely — there the wrappers need the session-level sandbox config (or a per-run consented bypass); the tier's seeded posture is correct for the settings-native sandbox and simply prompts again elsewhere (fail-safe, never a silent widening). Each bridge's observed egress hosts are declared in its `capability.json` `networkHosts` — the single documentation source (observed-minimal — a blocked host names itself at run time; read the manifests, this doc deliberately retypes no host list). The kit **never seeds** `sandbox.network.allowedDomains` or `sandbox.filesystem.allowWrite` (bridge council 2026-07-11, both backends concur): a network pre-allow widens egress for EVERY sandboxed command, and a write allowance on CLI state dirs (`~/.codex`, `~/.gemini/…`) would make credential dirs writable to every sandboxed command. Per-bridge picture under a harness-managed sandbox (live-observed 2026-07-11/12): an IDE-managed session sandbox ignores hand-applied `sandbox.network.allowedDomains` / `sandbox.filesystem.allowWrite` in BOTH settings scopes — its own per-host network consents govern egress; the durable zero-prompt lanes there are the session/host sandbox config (hosts from `networkHosts` + the CLI state-dir writes) or the per-run consented bypass. codex additionally needs a writable HOME (EROFS `~/.codex`); note the apex-vs-wildcard nuance — an apex domain is NOT covered by its `*.`-wildcard form, so the manifests carry both forms where observed (the blocked host names itself at run time). The upgrade Recommendations advisor renders exactly this as a HAND-APPLY item with the risk stated (`${CLAUDE_SKILL_DIR}/references/modes/recommendations.md`). Membership is the FROZEN review-wrapper constant, **never** the execution/probe wrappers (`codex-exec`, `agy-run` keep their human prompt — delegated execution is not covered by this consent), and only the **`code` review mode** — a `plan`/`diff` invocation takes a file argument that can point OUTSIDE the repo, so those modes keep their prompt; each wrapper entry derives ONLY when its bridge is **placed on PATH** (an absent bridge is a stated skip). The seeded byte-forms (this list IS the documented-invocation source for the bridge tier):
|
|
35
|
+
|
|
36
|
+
- `Bash(codex-review code:*)` — the code-mode prefix, args wildcard; plus `codex-review` in `sandbox.excludedCommands`
|
|
37
|
+
- `Bash(agy-review code:*)` — the code-mode prefix, args wildcard; plus `agy-review` in `sandbox.excludedCommands`
|
|
38
|
+
- `Bash(node "${CLAUDE_SKILL_DIR}/tools/grounding.mjs":*)` — the grounding pre-step, **double-quoted absolute path**: exactly the byte-form the `procedures` advisor renders, so the pasted pre-step matches the rule (seeded↔rendered byte-parity). It derives ONLY when `agy-review` is placed (the pre-step exists for agy's grounded reviews; codex grounds natively) — a codex-only install never auto-allows this writer. The quoted form is accepted for THIS one tool only — never a general quote allowance; an unseedable kit path (spaces/metacharacters) is a stated skip. Its writer surface is closed by the tool's own guard: `--out` accepts only system-temp scratch (rewritable) or a FRESH gitignored in-repo path (create-only, exclusive write) — tracked, in-repo-not-ignored, EXISTING in-repo (even gitignored), outside-repo non-temp, and symlink/non-regular destinations are all refused.
|
|
39
|
+
|
|
40
|
+
**Consented posture (printed on every `--bridge-tier` run, stated not pretended away):** an auto-allowed review wrapper runs **UNATTENDED** — it reads any repo file it is pointed at and sends the assembled payload to its **subscription backend**; prefix rules cannot inspect arguments, so a code-mode argument that names a readable file (agy's `--facts`/`--decided`) rides the same consent. That is the tier's purpose (unattended council review runs) and its residual. Tier entries get no PreToolUse-hook coverage — the same documented residual class as the autonomy red-line rules. The grounding entry's writer surface is bounded by `grounding.mjs`'s own scratch-destination guard (a tracked or in-repo-not-ignored `--out` is refused by the tool itself).
|
|
41
|
+
|
|
42
|
+
**Invocation shape (why a run still prompts):** a prefix allow rule matches only a **PLAIN invocation starting with the wrapper name** — `codex-review code`, `agy-review code --facts @f`. An env-var prefix (`AGY_PROBE=1 agy-review …`) or a compound chain (`agy-review … && …`; `;`-joined statements) can NEVER match a prefix rule (observed live); output redirects are fine. Drive the wrappers as plain single commands.
|
|
43
|
+
|
|
33
44
|
**Exit codes:** `0` done / dry-run; `1` a precondition STOP (stamp not current, unsafe mode, malformed settings, symlinked `.claude` / non-regular target); `2` bad arguments.
|
|
34
45
|
|
|
35
46
|
---
|
|
@@ -41,6 +52,6 @@ Honesty notes: tier entries get **NO PreToolUse-hook residual coverage** — the
|
|
|
41
52
|
1. **Preview by default** (writes nothing); **`--apply`** merges the render-owned blocks into `.claude/settings.json` (merge-don't-clobber — foreign top-level keys, existing `permissions.allow`, and foreign ask/deny entries preserved; a policy flip MOVES a red-line rule between ask/deny rather than duplicating it). It **refuses an absent policy** loudly (seed one first with `set-autonomy`). It **never writes `settings.local.json`**; a `settings.local.json` `defaultMode` that would mask the render is reported (local > project).
|
|
42
53
|
2. **`--autonomy --check`** is a **read-only drift gate**: it recomputes the render and compares against the live render-owned blocks — exit `0` in sync, exit `1` on drift (naming the exact key). A hand-edit OUTSIDE those blocks never flags.
|
|
43
54
|
3. **Version-sensitive (characterized against the real claude 2.1.185).** Sandbox keys are `sandbox.enabled` + `sandbox.autoAllowBashIfSandboxed`; `sandbox` level ⇒ auto-allow + `defaultMode: acceptEdits`, `prompt` level ⇒ auto-allow OFF + `defaultMode: default` (the sandbox stays enabled as a confine floor either way). Red-lines use the argument-matching `:*` wildcard (`Bash(git commit:*)` / `Bash(git push:*)` / `Bash(npm publish:*)`). Where 2.1.185 cannot express a red-line distinctly — a **network hard-block** (regular settings only prompt on egress), **credential denial** (`sandbox.credentials` is 2.1.187+ / mask 2.1.199+), or a **prompt-on-outside-write** — the render **DEGRADES LOUDLY** (never a silent allow, never pretend-security). A missing Linux dependency (`socat`/`bwrap`) or an unsupported platform degrades the WHOLE sandbox to unsandboxed — the render still lands the red-lines + `defaultMode` and caveats that ad-hoc scripts will still prompt.
|
|
44
|
-
4. **`--autonomy` cannot combine** with `--accept-edits
|
|
55
|
+
4. **`--autonomy` cannot combine** with `--accept-edits`, `--kit-tools`, or `--bridge-tier` (allowlist-mode flags) — a loud usage error.
|
|
45
56
|
|
|
46
57
|
**Autonomy invariants:** policy-only (never seeds the allowlist, leaves `permissions.allow` untouched) · writes only `.claude/settings.json` (never `settings.local.json`) · refuses an absent policy · merge-don't-clobber · degrades loudly where 2.1.185 can't enforce · previews by default · never commits.
|
|
@@ -3,40 +3,45 @@
|
|
|
3
3
|
**Hand-off contract (explicit; tested independent of agent interpretation).**
|
|
4
4
|
- **Delegated** (memory valid): the kit passes the **target project dir** + the **three setup
|
|
5
5
|
answers** (visibility / language / attribution) to `agent-workflow-memory`, which writes
|
|
6
|
-
`docs/ai/` + `AGENTS.md` (carrying the **
|
|
7
|
-
`workflow:orchestration`) + **`.memory-version`**. The kit then **reconciles
|
|
8
|
-
(below) and writes the kit-fallback **`.workflow-version`**. → **both stamps** present. In **hidden** mode the kit is the **single
|
|
6
|
+
`docs/ai/` + `AGENTS.md` (carrying the **three empty pointer pairs** — `workflow:methodology`,
|
|
7
|
+
`workflow:orchestration` and `workflow:autonomy`) + **`.memory-version`**. The kit then **reconciles
|
|
8
|
+
the bounded pointers** (below) and writes the kit-fallback **`.workflow-version`**. → **both stamps** present. In **hidden** mode the kit is the **single
|
|
9
9
|
hide authority**: after the hand-off it runs `tools/hide-footprint.mjs` (bootstrap step 9 — `${CLAUDE_SKILL_DIR}/references/modes/bootstrap.md`), which **absorbs
|
|
10
10
|
memory's project-local footprint lines** into the one canonical `.git/info/exclude` block and adds
|
|
11
11
|
the external footprint — so there is **no machine-global write** at any step (a stale memory's
|
|
12
12
|
residual global block is cleaned via the upgrade reconcile, below).
|
|
13
13
|
- **Fallback** (memory absent/invalid): the kit runs the bootstrap procedure (`${CLAUDE_SKILL_DIR}/references/modes/bootstrap.md`) from its own
|
|
14
|
-
bundled assets — whose entry-point template now ships **
|
|
15
|
-
+ `workflow:orchestration`) the kit reconciles + fills — and writes **`.workflow-version`** only.
|
|
14
|
+
bundled assets — whose entry-point template now ships **three empty pointer pairs** (`workflow:methodology`
|
|
15
|
+
+ `workflow:orchestration` + `workflow:autonomy`) the kit reconciles + fills — and writes **`.workflow-version`** only.
|
|
16
16
|
Softly suggest installing `agent-workflow-memory` — never a prerequisite.
|
|
17
17
|
|
|
18
18
|
**Bounded pointer reconciliation (the kit is the ONLY writer of these slots).** After `AGENTS.md`
|
|
19
19
|
exists, run ONE command — `node ${CLAUDE_SKILL_DIR}/tools/inject-methodology.mjs reconcile
|
|
20
|
-
<project>/AGENTS.md` — which reconciles **
|
|
21
|
-
**workflow-methodology** pointer (the plan → execute → review summary)
|
|
20
|
+
<project>/AGENTS.md` — which reconciles **three** bounded pointers in a single atomic write: the
|
|
21
|
+
**workflow-methodology** pointer (the plan → execute → review summary), the
|
|
22
22
|
**orchestration-recipes** pointer (the Solo / Reviewed / Council / Delegated vocabulary, routing to
|
|
23
|
-
`/agent-workflow-kit recipes`)
|
|
23
|
+
`/agent-workflow-kit recipes`) right below it, and the **autonomy-policy** pointer (the
|
|
24
|
+
`docs/ai/autonomy.json` read contract) below that. Each is **one atomic operation per slot**:
|
|
25
|
+
**ensure the slot exists**
|
|
24
26
|
(insert an empty marker pair at its anchor when a legacy entry point lacks one) → **inject the bounded
|
|
25
27
|
fragment ONLY IF the slot is empty** (a filled / user-customized slot is preserved verbatim) →
|
|
26
|
-
**cap-check** (
|
|
27
|
-
**combined** ≤100-line budget).
|
|
28
|
-
installed `agent-workflow-engine`** (`references/methodology-slot.md` + `references/orchestration-slot.md
|
|
28
|
+
**cap-check** (each chained pointer's check runs on the file *after* the previous one, so it guards the
|
|
29
|
+
**combined** ≤100-line budget). The fragments are short summary + pointer, read **live from the
|
|
30
|
+
installed `agent-workflow-engine`** (`references/methodology-slot.md` + `references/orchestration-slot.md`
|
|
31
|
+
+ `references/autonomy-slot.md`,
|
|
29
32
|
the family's one source of truth) — **not** a bundled mirror, and **not** the full references. The
|
|
30
33
|
live read is **lazy + fail-loud**: the engine is consulted **only when a slot actually needs filling**,
|
|
31
|
-
so a deployment
|
|
32
|
-
without the engine
|
|
34
|
+
so a deployment with **all three** pointers filled reconciles to a zero-diff no-op even on a host
|
|
35
|
+
without the engine (one still missing the autonomy pair needs the engine to gain it); when a fill
|
|
36
|
+
**is** needed and the engine is **absent/invalid**, reconcile
|
|
33
37
|
**STOPs** — report it in plain language with the one-line install command
|
|
34
38
|
`npx @sabaiway/agent-workflow-engine@latest init` (`npx @sabaiway/agent-workflow-kit@latest init`
|
|
35
39
|
installs the engine for you; translate, never leak tool internals). Contract per slot: exactly one
|
|
36
40
|
ordered `start → end` pair; a malformed slot (single, reversed, nested, duplicate) or a missing /
|
|
37
|
-
duplicate anchor → **STOP with an error**, never edit (the file is left byte-for-byte unchanged).
|
|
38
|
-
**
|
|
39
|
-
|
|
41
|
+
duplicate anchor → **STOP with an error**, never edit (the file is left byte-for-byte unchanged). A
|
|
42
|
+
**chained pointer is soft-skipped** (reported, never silent) when — and only when — adding it would
|
|
43
|
+
exceed the 100-line cap, the engine is too old to ship its fragment, or (autonomy only) its anchor
|
|
44
|
+
(the orchestration pair) is absent: every prior pointer still lands and the upgrade continues.
|
|
40
45
|
|
|
41
46
|
**Agent-rules lens refresh (runs in BOTH paths).** Its precondition is its own target file — run it
|
|
42
47
|
only after `<project>/docs/ai/agent_rules.md` exists: after the substrate deploy in the
|
|
@@ -9,7 +9,11 @@ The tool runs the backend detector and appends the recipe recommendation itself
|
|
|
9
9
|
recipe clause of its own, ever.
|
|
10
10
|
|
|
11
11
|
- **Placeholder template (structure only — never copy this example; paste the tool's line):**
|
|
12
|
-
`backends: <alias> <✓|✗> <readiness> · <alias> <✓|✗> <readiness> — run /agent-workflow-kit backends · recipes: <recommendation clause> — see /agent-workflow-kit recipes`
|
|
12
|
+
`backends: <alias> <✓|✗> <readiness> · <alias> <✓|✗> <readiness> — run /agent-workflow-kit backends · recipes: <recommendation clause> — see /agent-workflow-kit recipes · autonomy: <per-activity levels> (<policy state>)`
|
|
13
|
+
- The **`autonomy:` segment is appended by the composer itself** (`composeAutonomyFacts`, AD-044) —
|
|
14
|
+
per-activity levels + the policy state (computed defaults / declared / MALFORMED, loud) — the
|
|
15
|
+
agent never types it; the composer resolves the policy from the project root, so the line is
|
|
16
|
+
correct from any working directory inside the project.
|
|
13
17
|
- The **`recipes:` clause is appended after** the `— run /agent-workflow-kit backends` pointer (never
|
|
14
18
|
replacing it) and routes to the read-only `recipes` mode (`see /agent-workflow-kit recipes`). It is
|
|
15
19
|
**never blank**: both backends ready → *"Council available, Reviewed the everyday default"*; one
|
|
@@ -57,6 +57,8 @@ Start-of-session, during-work, and task-completion procedures live in [`docs/ai/
|
|
|
57
57
|
<!-- workflow:methodology:end -->
|
|
58
58
|
<!-- workflow:orchestration:start -->
|
|
59
59
|
<!-- workflow:orchestration:end -->
|
|
60
|
+
<!-- workflow:autonomy:start -->
|
|
61
|
+
<!-- workflow:autonomy:end -->
|
|
60
62
|
|
|
61
63
|
---
|
|
62
64
|
|
|
@@ -68,7 +70,6 @@ Start-of-session, during-work, and task-completion procedures live in [`docs/ai/
|
|
|
68
70
|
| No `any` / no unsafe casts | Linter / type-checker |
|
|
69
71
|
| Functional style (no mutation in app code) | Linter |
|
|
70
72
|
| Interactive elements semantic (button/link, not div+onClick) | Linter / a11y |
|
|
71
|
-
| No hardcoded colors — design tokens only | Code review |
|
|
72
73
|
| No business logic in components → hooks/services | Architecture review |
|
|
73
74
|
| No changes without tests (TDD) | Required |
|
|
74
75
|
| Check page docs before changes; update them after | Process |
|
|
@@ -236,6 +236,15 @@ export const resolveAutonomy = (config) => {
|
|
|
236
236
|
return { redlines, activities };
|
|
237
237
|
};
|
|
238
238
|
|
|
239
|
+
// isSparseSeedConfig(config) → true when the policy file is STRUCTURALLY the deploy seed: meta keys
|
|
240
|
+
// only (`_README` today) — no red-lines section, no activity entry. Seed detection must be
|
|
241
|
+
// structural, never resolved-equality: an EXPLICIT policy that declares exactly the default values
|
|
242
|
+
// is a real DECLARATION (its render — the red-line ask rules included — must not be suppressed as
|
|
243
|
+
// "just the seed"), while the seed declares nothing (codex, Segment B closing). Shared by every
|
|
244
|
+
// autonomy read surface (advisor / recipes / procedures / grounding) so the four can never diverge.
|
|
245
|
+
export const isSparseSeedConfig = (config) =>
|
|
246
|
+
isJsonObject(config) && Object.keys(config).every((k) => k.startsWith('_'));
|
|
247
|
+
|
|
239
248
|
// ── pure merge + canonical serialization ────────────────────────────────────────────
|
|
240
249
|
|
|
241
250
|
// A pure deep-equal over the JSON-ish policy shape (plain objects + string values). Used only for the
|
|
@@ -288,9 +297,10 @@ export const serializeAutonomy = (config) => {
|
|
|
288
297
|
|
|
289
298
|
// ── the canonical seed (Decision 5) ──────────────────────────────────────────────────
|
|
290
299
|
// AUTONOMY_README is the onboarding note; SEED_AUTONOMY is the Decision-5 fixture the set-autonomy
|
|
291
|
-
//
|
|
292
|
-
//
|
|
293
|
-
//
|
|
300
|
+
// WRITER seeds (opinionated sandbox levels) and the config tests copy/validate verbatim. DISTINCT
|
|
301
|
+
// from the Plan-4 deploy template `references/templates/autonomy.json` (bootstrap/upgrade ensure):
|
|
302
|
+
// that seed is SPARSE — `_README` only, defaults-equivalent by the template-parity pin
|
|
303
|
+
// (resolveAutonomy(template) ≡ resolveAutonomy(null)) — so deploying it never changes behavior.
|
|
294
304
|
export const AUTONOMY_README =
|
|
295
305
|
'Per-project autonomy policy: red-lines (always) + per-activity autonomy level. Hand-editable; or ' +
|
|
296
306
|
'use the set-autonomy writer (previews, then writes valid JSON). Strict JSON — no comments.';
|
package/tools/commands.mjs
CHANGED
|
@@ -98,6 +98,13 @@ const CATALOG = [
|
|
|
98
98
|
kind: READ_ONLY,
|
|
99
99
|
oneLine: 'List every command, grouped, marking each as read-only or as one that makes changes.',
|
|
100
100
|
},
|
|
101
|
+
{
|
|
102
|
+
key: 'recommendations',
|
|
103
|
+
invocation: invocationOf('recommendations'),
|
|
104
|
+
group: 'Inspect',
|
|
105
|
+
kind: READ_ONLY,
|
|
106
|
+
oneLine: 'See what in this deployment is configured sub-optimally — each item with a one-line benefit and the exact consent-gated command that applies it; renders even when everything is optimal.',
|
|
107
|
+
},
|
|
101
108
|
{
|
|
102
109
|
key: 'gates',
|
|
103
110
|
invocation: invocationOf('gates'),
|
|
@@ -147,6 +154,13 @@ const CATALOG = [
|
|
|
147
154
|
kind: GUARDED,
|
|
148
155
|
oneLine: 'Check whether this machine can run the Claude sandbox and, only with your explicit consent, install what is missing — privileged, preview-first, consent-per-run; it never auto-runs and never commits.',
|
|
149
156
|
},
|
|
157
|
+
{
|
|
158
|
+
key: 'sandbox-masks',
|
|
159
|
+
invocation: invocationOf('sandbox-masks'),
|
|
160
|
+
group: 'Configure',
|
|
161
|
+
kind: GUARDED,
|
|
162
|
+
oneLine: 'Hide the sandbox’s injected device masks from git status via one managed block in the repo’s local exclude file — probe-derived (never a frozen list), preview first, full-block replace on your yes; reviews already ignore the masks by construction.',
|
|
163
|
+
},
|
|
150
164
|
{
|
|
151
165
|
key: 'recipes',
|
|
152
166
|
invocation: invocationOf('recipes'),
|
|
@@ -187,7 +201,7 @@ const CATALOG = [
|
|
|
187
201
|
invocation: invocationOf('grounding'),
|
|
188
202
|
group: 'Orchestrate',
|
|
189
203
|
kind: WRITER,
|
|
190
|
-
oneLine: 'Assemble the verified-facts payload a grounded review runs against — the entry-point Hard Constraints plus a plan’s decision sections; prints it, or writes ONE scratch file with --out.',
|
|
204
|
+
oneLine: 'Assemble the verified-facts payload a grounded review runs against — the entry-point Hard Constraints, the effective autonomy policy, plus a plan’s decision sections; prints it, or writes ONE scratch file with --out.',
|
|
191
205
|
},
|
|
192
206
|
{
|
|
193
207
|
key: 'review-ledger',
|
package/tools/delegation.mjs
CHANGED
|
@@ -27,6 +27,10 @@ export const EXPECTED_MEMORY_NAME = 'agent-workflow-memory';
|
|
|
27
27
|
// DOES seed orchestration.json (Mode: upgrade step 3). This closes the stale-memory trap that the
|
|
28
28
|
// read-only family-registry note (MEMORY_ORCH_TEMPLATE_REL) only INFORMS about — the gate ACTS. The
|
|
29
29
|
// two key on the same asset; a cross-tool parity test pins them in lockstep.
|
|
30
|
+
// The autonomy seed (AD-044 Plan 4) is deliberately NOT here: the Plan-3 decision stands — no
|
|
31
|
+
// detectMemory autonomy-marker gate. A memory too old to ship references/templates/autonomy.json
|
|
32
|
+
// stays delegable; the kit-side upgrade ensure seeds the policy from the kit's own template twin,
|
|
33
|
+
// and the family-registry caveat INFORMS about the stale memory (inform, never gate).
|
|
30
34
|
export const REQUIRED_MEMORY_ASSETS = [
|
|
31
35
|
{ path: 'references/templates', type: 'dir' },
|
|
32
36
|
{ path: 'references/templates/orchestration.json', type: 'file' },
|
|
@@ -85,7 +89,7 @@ export const handoffPlan = (delegate) =>
|
|
|
85
89
|
memoryWrites: ['docs/ai/', 'AGENTS.md', 'docs/ai/.memory-version'],
|
|
86
90
|
// The lens region runs AFTER the substrate deploy (its own precondition: the file exists)
|
|
87
91
|
// — it converges a stale-memory seed to the installed engine's canon (AD-041).
|
|
88
|
-
kitWrites: ['AGENTS.md methodology
|
|
92
|
+
kitWrites: ['AGENTS.md pointer slots (methodology / orchestration / autonomy)', 'docs/ai/agent_rules.md lens region', 'docs/ai/.workflow-version'],
|
|
89
93
|
stampsPresent: ['.memory-version', '.workflow-version'],
|
|
90
94
|
memoryRaisesCommitGate: false,
|
|
91
95
|
commitGate: 'kit-only-after-injection',
|
|
@@ -93,11 +97,11 @@ export const handoffPlan = (delegate) =>
|
|
|
93
97
|
: {
|
|
94
98
|
mode: 'fallback',
|
|
95
99
|
memoryWrites: [],
|
|
96
|
-
// Fallback now ships the kit's OWN AGENTS.md carrying the EMPTY
|
|
97
|
-
// the kit reconciles
|
|
98
|
-
// path — so both paths end with
|
|
100
|
+
// Fallback now ships the kit's OWN AGENTS.md carrying the EMPTY pointer slots (Plan 2);
|
|
101
|
+
// the kit reconciles them (ensure-slot + inject-because-empty) exactly like the delegate
|
|
102
|
+
// path — so both paths end with FILLED slots, not inline methodology. The lens region
|
|
99
103
|
// runs after the fallback-template copy of docs/ai (same reconcile, both paths — AD-041).
|
|
100
|
-
kitWrites: ['docs/ai/', 'AGENTS.md', 'AGENTS.md methodology
|
|
104
|
+
kitWrites: ['docs/ai/', 'AGENTS.md', 'AGENTS.md pointer slots (methodology / orchestration / autonomy)', 'docs/ai/agent_rules.md lens region', 'docs/ai/.workflow-version'],
|
|
101
105
|
stampsPresent: ['.workflow-version'],
|
|
102
106
|
memoryRaisesCommitGate: false,
|
|
103
107
|
commitGate: 'kit-only-after-injection',
|
|
@@ -88,7 +88,7 @@ const RAW_BACKENDS = [
|
|
|
88
88
|
],
|
|
89
89
|
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',
|
|
90
90
|
continue: [],
|
|
91
|
-
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',
|
|
91
|
+
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; never-committable untracked paths — character/block devices, FIFOs, sockets — are excluded from the domain entirely, untracked symlinks/directories ride as name-only notes) 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',
|
|
92
92
|
},
|
|
93
93
|
},
|
|
94
94
|
bin: 'codex',
|
|
@@ -121,7 +121,7 @@ const RAW_BACKENDS = [
|
|
|
121
121
|
'agy-review --continue [--decided @f] [--focus "…"]',
|
|
122
122
|
'agy-review --conversation <id> [--decided @f] [--focus "…"]',
|
|
123
123
|
],
|
|
124
|
-
receipt: "side effect — a successful review appends one JSON receipt line to <git dir>/agent-workflow-review-receipts.jsonl (AW_REVIEW_RECEIPTS overrides; plan/diff outside a git tree: warn + skip unless overridden): 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/diff mode; verdict recorded verbatim from the mandated '### Verdict' section (SHIP / SHIP WITH NITS / REWORK); grounded = whether a NON-EMPTY --facts payload was supplied (an empty payload records grounded:false — fail-closed, the state gate rejects it), factsHash = sha256 of the facts payload; a continuation receipt is fresh:false (informational-only — it cannot attest the folded tree); a write failure warns, never fails the review",
|
|
124
|
+
receipt: "side effect — a successful review appends one JSON receipt line to <git dir>/agent-workflow-review-receipts.jsonl (AW_REVIEW_RECEIPTS overrides; plan/diff outside a git tree: warn + skip unless overridden): fingerprint = sha256 over the canonical uncommitted-state payload (staged diff + unstaged diff + untracked-not-ignored contents — the review-payload domain; never-committable untracked paths — character/block devices, FIFOs, sockets — are excluded from the domain entirely, untracked symlinks/directories ride as name-only notes) in code mode, the artifact-file sha256 in plan/diff mode; verdict recorded verbatim from the mandated '### Verdict' section (SHIP / SHIP WITH NITS / REWORK); grounded = whether a NON-EMPTY --facts payload was supplied (an empty payload records grounded:false — fail-closed, the state gate rejects it), factsHash = sha256 of the facts payload; a continuation receipt is fresh:false (informational-only — it cannot attest the folded tree); a write failure warns, never fails the review",
|
|
125
125
|
},
|
|
126
126
|
},
|
|
127
127
|
bin: 'agy',
|
package/tools/doc-parity.mjs
CHANGED
|
@@ -27,12 +27,15 @@ import { SCHEMA_VERSION, REVIEW_CAP, V4_CLASSES, V4_OVERRIDE_SCOPES } from './re
|
|
|
27
27
|
import { HARD_MAX, DEFAULT_DIFF_CAP } from './review-ledger-write.mjs';
|
|
28
28
|
import { RESULT_SCHEMA_VERSION } from './fold-completeness.mjs';
|
|
29
29
|
import { EXIT as DOCTOR_EXIT, STATUS as DOCTOR_STATUS, TRUSTED_DIRS as DOCTOR_TRUSTED_DIRS } from './autonomy-doctor.mjs';
|
|
30
|
+
import { RECOMMENDATIONS_SECTION_HEADER, RECOMMENDATIONS_EMPTY_LINE } from './recommendations.mjs';
|
|
30
31
|
|
|
31
32
|
const KIT_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
32
33
|
|
|
33
34
|
const REVIEW_LEDGER_DOC = 'references/modes/review-ledger.md';
|
|
34
35
|
const FOLD_DOC = 'references/modes/fold-completeness.md';
|
|
35
36
|
const AUTONOMY_DOCTOR_DOC = 'references/modes/autonomy-doctor.md';
|
|
37
|
+
const RECOMMENDATIONS_DOC = 'references/modes/recommendations.md';
|
|
38
|
+
const UPGRADE_DOC = 'references/modes/upgrade.md';
|
|
36
39
|
|
|
37
40
|
// A typed usage failure (exit 2) for the CLI parser — the codebase's typed-error idiom (no classes).
|
|
38
41
|
const usageFail = (message) => Object.assign(new Error(message), { exitCode: 2 });
|
|
@@ -72,6 +75,11 @@ export const BINDINGS = Object.freeze([
|
|
|
72
75
|
.filter((token) => token !== DOCTOR_STATUS.usage)
|
|
73
76
|
.map((token) => valueBinding(`doctor-status:${token}`, token, token, [AUTONOMY_DOCTOR_DOC])),
|
|
74
77
|
valueBinding('doctor-trusted-dirs', DOCTOR_TRUSTED_DIRS.join(':'), DOCTOR_TRUSTED_DIRS.join(':'), [AUTONOMY_DOCTOR_DOC]),
|
|
78
|
+
// The upgrade Recommendations section contract (AD-044 Plan 4): the section header and the
|
|
79
|
+
// exact empty-state line must render in BOTH the mode doc and upgrade.md (both exits reference
|
|
80
|
+
// them) — a reworded doc would silently break the paste-verbatim contract.
|
|
81
|
+
valueBinding('recommendations-header', RECOMMENDATIONS_SECTION_HEADER, RECOMMENDATIONS_SECTION_HEADER, [RECOMMENDATIONS_DOC, UPGRADE_DOC]),
|
|
82
|
+
valueBinding('recommendations-empty-line', RECOMMENDATIONS_EMPTY_LINE, RECOMMENDATIONS_EMPTY_LINE, [RECOMMENDATIONS_DOC, UPGRADE_DOC]),
|
|
75
83
|
].map((b) => Object.freeze(b)));
|
|
76
84
|
|
|
77
85
|
// ── the pure checker (readText is injectable for hermetic tests) ────────────────────────
|
package/tools/engine-source.mjs
CHANGED
|
@@ -31,6 +31,12 @@ export const ORCHESTRATION_FRAGMENT_REL = 'references/orchestration-slot.md';
|
|
|
31
31
|
// CLI fail loudly on — an engine too old to ship it. readEngineFragment accepts an arbitrary `rel`
|
|
32
32
|
// (no whitelist), so no further plumbing is needed beyond this constant.
|
|
33
33
|
export const PROCEDURES_FRAGMENT_REL = 'references/procedures.md';
|
|
34
|
+
// The autonomy-policy slot fragment — the THIRD bounded fragment the kit injects (AD-044 Plan 3),
|
|
35
|
+
// the cross-agent read contract for docs/ai/autonomy.json. An engine released before it does not
|
|
36
|
+
// ship it; detectEngine({ rel }) lets the chained reconcile soft-skip that too-old engine (and
|
|
37
|
+
// `status` caveat it) instead of discarding the methodology/orchestration fills. readEngineFragment
|
|
38
|
+
// accepts an arbitrary `rel`, so no further plumbing is needed beyond this constant.
|
|
39
|
+
export const AUTONOMY_FRAGMENT_REL = 'references/autonomy-slot.md';
|
|
34
40
|
// The agent-rules lens pair — the canonical lens block + its append-only prior store (engine
|
|
35
41
|
// >= 1.13.0; an older engine ships neither). The kit's lens-region reconcile live-reads BOTH via
|
|
36
42
|
// readEngineFragment({ rel }); detectEngine({ rel }) lets it soft-skip a too-old engine (and
|
|
@@ -26,7 +26,7 @@ import { resolveDir, detectBackends, findOnPath } from './detect-backends.mjs';
|
|
|
26
26
|
import { parseSemver, compareSemver } from './semver-lite.mjs';
|
|
27
27
|
import { validateManifest, readAuthoritativeVersion, UNSUPPORTED, INVALID } from './manifest/validate.mjs';
|
|
28
28
|
import { START_MARKER, excludePath, inferVisibility } from './hide-footprint.mjs';
|
|
29
|
-
import { readEngineFragment, ORCHESTRATION_FRAGMENT_REL, PROCEDURES_FRAGMENT_REL, LENS_FRAGMENT_REL, LENS_PRIORS_REL } from './engine-source.mjs';
|
|
29
|
+
import { readEngineFragment, ORCHESTRATION_FRAGMENT_REL, PROCEDURES_FRAGMENT_REL, AUTONOMY_FRAGMENT_REL, LENS_FRAGMENT_REL, LENS_PRIORS_REL } from './engine-source.mjs';
|
|
30
30
|
import { ACTIVITIES, resolveActivityRecipe } from './recipes.mjs';
|
|
31
31
|
// The config reader lives in orchestration-config.mjs (the single config contract). The read-only status
|
|
32
32
|
// settings-survey reuses THIS reader (one strict-JSON + loud-on-malformed contract), not a second copy.
|
|
@@ -182,6 +182,7 @@ export const classifyMember = (member, deps = {}) => {
|
|
|
182
182
|
// caveat keys on both — an engine missing only the prior store must never report healthy.
|
|
183
183
|
const ENGINE_FRAGMENT_CAVEATS = [
|
|
184
184
|
{ rels: [ORCHESTRATION_FRAGMENT_REL], caveat: 'engine present but does not supply the recipes pointer (too old / incomplete) — run `npx @sabaiway/agent-workflow-engine@latest init`' },
|
|
185
|
+
{ rels: [AUTONOMY_FRAGMENT_REL], caveat: 'engine present but does not supply the autonomy pointer (too old / incomplete) — run `npx @sabaiway/agent-workflow-engine@latest init`' },
|
|
185
186
|
{ rels: [PROCEDURES_FRAGMENT_REL], caveat: 'engine present but does not ship the activity-procedures canon (too old / incomplete) — run `npx @sabaiway/agent-workflow-engine@latest init`' },
|
|
186
187
|
{ rels: [LENS_FRAGMENT_REL, LENS_PRIORS_REL], caveat: 'engine present but does not ship the agent-rules lens canon (the fragment + its prior store; too old / incomplete — engine >= 1.13.0) — run `npx @sabaiway/agent-workflow-engine@latest init`' },
|
|
187
188
|
];
|
|
@@ -192,10 +193,16 @@ const ENGINE_FRAGMENT_CAVEATS = [
|
|
|
192
193
|
// adds a parity drift-guard tying this path to that required-asset set, so the note and the gate can
|
|
193
194
|
// never key on different files (until then they are kept in lockstep by review).
|
|
194
195
|
export const MEMORY_ORCH_TEMPLATE_REL = 'references/templates/orchestration.json';
|
|
196
|
+
// The autonomy-policy seed (AD-044 Plan 4) gets the SAME inform-never-gate treatment: the
|
|
197
|
+
// delegation gate deliberately does NOT key on it (the Plan-3 decision), so this caveat is the
|
|
198
|
+
// discovery mechanism — the recommendations advisor surfaces it via surveyFamily.
|
|
199
|
+
export const MEMORY_AUTONOMY_TEMPLATE_REL = 'references/templates/autonomy.json';
|
|
195
200
|
// Worded as an honest OBSERVATION, not a diagnosis (absence can mean old OR incomplete), and it makes
|
|
196
201
|
// NO claim about an orchestration.json seeding outcome (that depends on delegate-vs-fallback).
|
|
197
202
|
const MEMORY_BEHIND_NOTE =
|
|
198
203
|
"the memory installed here doesn't include the current orchestration template — refresh it with `npx @sabaiway/agent-workflow-memory@latest init`, then restart the session.";
|
|
204
|
+
const MEMORY_AUTONOMY_BEHIND_NOTE =
|
|
205
|
+
"the memory installed here doesn't include the current autonomy-policy template — refresh it with `npx @sabaiway/agent-workflow-memory@latest init`, then restart the session.";
|
|
199
206
|
|
|
200
207
|
// ── the bridge freshness probe (deterministic-first — INV-A / INV-B) ─────────────
|
|
201
208
|
// The bridges are not npm packages: their ONLY delivery channel is the copy bundled inside this kit
|
|
@@ -261,12 +268,19 @@ export const surveyFamily = (deps = {}) =>
|
|
|
261
268
|
// Only attach when it is provably ABSENT (a non-ENOENT probe error → 'unknown' → skip, never a
|
|
262
269
|
// false "missing" claim). Mirrors the engine-caveat SHAPE; keyed on the Step-2.4 required asset.
|
|
263
270
|
if (row.kind === 'memory-substrate' && row.manifestState === OK && row.skillDir) {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
271
|
+
// Two required-template probes, same shape: orchestration (Step 2.4) + autonomy (AD-044
|
|
272
|
+
// Plan 4 — inform, never gate). Each attaches its own caveat on provable absence only.
|
|
273
|
+
for (const [rel, note] of [
|
|
274
|
+
[MEMORY_ORCH_TEMPLATE_REL, MEMORY_BEHIND_NOTE],
|
|
275
|
+
[MEMORY_AUTONOMY_TEMPLATE_REL, MEMORY_AUTONOMY_BEHIND_NOTE],
|
|
276
|
+
]) {
|
|
277
|
+
const templateProbe = probeMarker(join(row.skillDir, rel), deps);
|
|
278
|
+
if (templateProbe === 'absent') {
|
|
279
|
+
row.caveats = [...(row.caveats ?? []), note];
|
|
280
|
+
} else if (templateProbe === 'unknown') {
|
|
281
|
+
// Could not verify → this row must not be counted "checked, current" by the verdict (INV-B).
|
|
282
|
+
row.freshness = FRESH_UNKNOWN;
|
|
283
|
+
}
|
|
270
284
|
}
|
|
271
285
|
}
|
|
272
286
|
// Bridge freshness probe (INV-A / INV-B): only for a provably-OURS placed bridge (manifestState
|
|
@@ -1029,6 +1029,11 @@ loud advisory failure) but leaves --check unaffected.
|
|
|
1029
1029
|
|
|
1030
1030
|
The read-only gate is a SEPARATE tool: node fold-completeness.mjs --check / --status / --json.
|
|
1031
1031
|
|
|
1032
|
+
Sandbox-safe: the RUNNER itself needs no network and writes only repo-local state (the D4 sandbox
|
|
1033
|
+
lane). The spawned suite/bound commands are COMMAND-SHAPE dependent — --suite / AW_FOLD_SUITE_CMD /
|
|
1034
|
+
AW_FOLD_BOUND_CMD / the verification profile can name project-defined commands; the default
|
|
1035
|
+
(node --test on stdout TAP) is plain and no-network — keep overrides sandbox-safe by shape.
|
|
1036
|
+
|
|
1032
1037
|
Exit codes: 0 written / advisory printed; 1 a typed STOP (loop derivation / suite discovery / a --red
|
|
1033
1038
|
or --reattest refusal / a malformed SARIF on --findings / malformed record / fs error); 2 usage.`;
|
|
1034
1039
|
|