@sabaiway/agent-workflow-kit 1.21.0 → 1.23.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.
- package/CHANGELOG.md +39 -0
- package/SKILL.md +1 -1
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/templates/agent_rules.md +11 -2
- package/tools/detect-backends.mjs +18 -5
- package/tools/procedures.mjs +46 -8
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,45 @@ Semantically versioned ([semver](https://semver.org)), newest first. The `versio
|
|
|
4
4
|
is the current release. `upgrade` mode reads a project's `docs/ai/.workflow-version` and applies
|
|
5
5
|
every `migrations/<version>-<slug>.md` newer than it, in semver order.
|
|
6
6
|
|
|
7
|
+
## 1.23.0 — Surface the review-loop economics + the resolved backend set in the procedures advisor
|
|
8
|
+
|
|
9
|
+
A **feature** release. `/agent-workflow-kit procedures <activity>` now makes the review-loop discipline
|
|
10
|
+
mechanical at the point of use:
|
|
11
|
+
|
|
12
|
+
- **Backend-set aid.** Each resolved recipe prints its EXPLICIT wrapper set beside the recipe name
|
|
13
|
+
(`review: council → run every backend every round: codex-review + agy-review`; `reviewed → codex-review`;
|
|
14
|
+
`delegated → codex-exec`; solo prints none), so recipe fidelity is visible where the advisor is invoked.
|
|
15
|
+
Sourced from `planRecipe().dispatch` + a new role-keyed `detect-backends.wrapperCmdFor` (reading
|
|
16
|
+
`KNOWN_BACKENDS[].roleCmds`, now the source of truth; the deduped `wrapperCmds` readiness list is derived
|
|
17
|
+
from it). Drift-guarded against each bridge manifest `roles[role].cmd`.
|
|
18
|
+
- **Review-loop economics block.** For a review slot resolving reviewed|council (omitted for solo) the
|
|
19
|
+
advisor prints the ≤2-round cap, the bar-met-by-raising-a-major rule, the backend-divergence crossover
|
|
20
|
+
stop, the thin-plan/diff-review carve-out, a self-consistency read, and the required per-round emission
|
|
21
|
+
{round N · finding-origin · per-backend verdict}. `--json` carries per-slot `backends` + a top-level
|
|
22
|
+
`reviewLoop`.
|
|
23
|
+
- The fallback `agent_rules.md` **§2.5** lens mirror gains the same review-loop disciplines (byte-identical
|
|
24
|
+
to memory's §2.6).
|
|
25
|
+
|
|
26
|
+
Read-only; no resolution behaviour change. Deployment-lineage head stays `1.3.0`.
|
|
27
|
+
|
|
28
|
+
## 1.22.0 — Harden the planning canon: two-set lens drift guard + the deployed lens
|
|
29
|
+
|
|
30
|
+
A **feature** release. The kit's fallback `agent_rules.md` **§2.5** lens is generalized from *Right-altitude
|
|
31
|
+
& code-grounded* to **Planning, review & process-fidelity invariants** (byte-identical to memory's §2.6
|
|
32
|
+
block) and now carries all **seven** methodology invariants. The cross-package **`test/lens-mirror.test.mjs`**
|
|
33
|
+
is extended to **two scoped, non-vacuous token sets**:
|
|
34
|
+
|
|
35
|
+
- **Set 1 (cross-all-four)** pins the §9-native review/fold + convergence disciplines in EVERY region —
|
|
36
|
+
planning §9, procedures (`## plan-authoring` onward), and both template lens blocks: `0 blockers + 0
|
|
37
|
+
majors`, `test-as-spec`, `no code-mechanics`, `at the diff`, `characterize-first` (alongside the
|
|
38
|
+
existing `fold by code` / `file:line` / `altitude`).
|
|
39
|
+
- **Set 2 (template-scoped)** pins the process-fidelity invariants A1/A2 (`ExitPlanMode`, recipe-fidelity
|
|
40
|
+
`every round`) PRESENT in both template lens blocks — closing the gap the byte-identical check alone
|
|
41
|
+
cannot (it only proves the two templates AGREE, so both could drop A1/A2 and stay green).
|
|
42
|
+
|
|
43
|
+
The lens heading + the `extractLensBlock` regex move in lockstep. The deployment-lineage head stays
|
|
44
|
+
**`1.3.0`** (no `docs/ai` structural change, no migration); the kit **package** version is a separate axis.
|
|
45
|
+
|
|
7
46
|
## 1.21.0 — Ships the antigravity-cli-bridge 2.0.0 mirror (grounded agy-review)
|
|
8
47
|
|
|
9
48
|
A **feature** release. The kit now bundles the **antigravity-cli-bridge 2.0.0** byte-identical mirror —
|
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: agent-workflow-kit
|
|
|
3
3
|
description: Deploy or upgrade a portable AI-agent memory-and-workflow system in any project. Use when the user wants to bootstrap `docs/ai/` + an entry-point `AGENTS.md` (+ `CLAUDE.md` alias) + cap/archive/index enforcement in a new or existing repo, set up the Memory Map and session protocols, install the docs-rotation pre-commit hook, or run `/agent-workflow-kit` / `/agent-workflow-kit upgrade`. Triggers on phrases like "set up the memory system", "deploy the AI workflow here", "bootstrap docs/ai", "upgrade the workflow".
|
|
4
4
|
disable-model-invocation: true
|
|
5
5
|
metadata:
|
|
6
|
-
version: '1.
|
|
6
|
+
version: '1.23.0'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# agent-workflow-kit
|
package/capability.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sabaiway/agent-workflow-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.23.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",
|
|
@@ -61,10 +61,19 @@ Before proposing changes or committing, review against:
|
|
|
61
61
|
### 2.4. Quality Gates
|
|
62
62
|
- Always run type-checker, linter, and all tests before committing.
|
|
63
63
|
|
|
64
|
-
### 2.5.
|
|
64
|
+
### 2.5. Planning, review & process-fidelity invariants
|
|
65
|
+
Apply these when authoring a plan, reviewing, folding a finding, or editing code — the layer read **before any code change**. (Full canon: the project's planning / workflow-methodology + orchestration canon.)
|
|
65
66
|
- **Fold by code, not prose.** Before folding a code-touching finding into a plan or change, read the cited `file:line` and cite it — a prose fold drifts from the code and seeds the next bug.
|
|
66
67
|
- **Right altitude.** Pin intent + invariants + acceptance criteria (named tests); leave fine code-mechanics to Execute, where prose cannot diverge from reality.
|
|
67
|
-
- **
|
|
68
|
+
- **No code-mechanics in the plan.** A Step still carries its exact paths + commands (the plan-structure / self-review canon); the ceiling is on *fold-bred* detail — a review fold must not push fine code-mechanics (`cd`, an env default, a flag) into prose. A fold that needs a mechanic is the trigger to write the test instead.
|
|
69
|
+
- **Test-as-spec.** Fold a code-touching finding into a red→green TEST, not a prose paragraph — the gate is the only deterministic checker; a paragraph cannot self-check.
|
|
70
|
+
- **Characterize-first.** Before editing UNCOVERED code, pin its current behavior in a green test, then edit — any unintended change goes red. Never edit what has no checker; first give it one. Keep edits atomic/reversible; prefer SUBTRACTIVE folds.
|
|
71
|
+
- **Fold minimally — prose has no checker.** An ephemeral, gitignored plan is prose with no executable checker; fold **minimally, in ONE place** and run a **self-consistency** read across the plan before every re-review — a fold that drifts several prose spots is what turns a 2-round review into churn.
|
|
72
|
+
- **Heavy review at the diff.** Plan-review settles architecture only (≤2 rounds, stop at the pre-existing→fold-induced crossover); the exhaustive per-Step review runs against real compiling code + the full suite, where a regression fails a gate immediately. **Backend divergence** (one backend grounded-ships while another keeps revising mechanics) IS that crossover — resolve at altitude, don't exhaust the strictest backend; route an all-mechanics/CI or prose-only artifact to a **thin plan + diff-review**.
|
|
73
|
+
- **Convergence bar.** A review loop is CLEAN only when one round returns **0 blockers + 0 majors** from EVERY backend the recipe names (nits + a ship verdict is the stop). Folding ≠ convergence — re-review after folding.
|
|
74
|
+
- **Per-round emission.** Every review round emits **{round N · finding-origin tally · per-backend verdict}** so the crossover is a computed, visible signal, not a remembered rule.
|
|
75
|
+
- **Recipe fidelity.** Council runs every backend the recipe names, **every round**; silently dropping a ready backend for quota/convenience is a forbidden downgrade — an unavailable backend is a LOUD, stated degrade, never a quiet drop.
|
|
76
|
+
- **ExitPlanMode ≠ execute.** A harness "approved — start coding" prompt authorizes the PLAN only; this methodology overrides it. Continue into execution only as a DELIBERATE transition after the plan + cold-start prompt exist, never an implicit slide.
|
|
68
77
|
|
|
69
78
|
---
|
|
70
79
|
|
|
@@ -51,13 +51,15 @@ const EXPECTED_KIND = 'execution-backend';
|
|
|
51
51
|
// The kit-owned registry: the per-backend facts the detector needs even when a bridge is NOT
|
|
52
52
|
// installed (no manifest on disk to read). Kept in lockstep with the in-repo manifests by the
|
|
53
53
|
// drift-guard test. `credential.env: null` → no env override exists (do not invent one).
|
|
54
|
-
// `
|
|
55
|
-
//
|
|
56
|
-
|
|
54
|
+
// `roleCmds` is the role-keyed source of truth (role → the PATH wrapper cmd), mirroring each bridge
|
|
55
|
+
// manifest `roles[role].cmd`, drift-guarded. Two derivations ride on it, both drift-guarded against the
|
|
56
|
+
// manifests: `wrapperCmds` (the deduped set the readiness probe checks — a stale install missing one
|
|
57
|
+
// surfaces DEGRADED) and `wrapperCmdFor(backend, role)` (which concrete wrapper the backend-set aid prints).
|
|
58
|
+
const RAW_BACKENDS = [
|
|
57
59
|
{
|
|
58
60
|
name: 'codex-cli-bridge',
|
|
59
61
|
installed: { env: 'CODEX_CLI_BRIDGE_DIR', default: '~/.claude/skills/codex-cli-bridge', file: 'SKILL.md' },
|
|
60
|
-
|
|
62
|
+
roleCmds: { execute: 'codex-exec', review: 'codex-review' },
|
|
61
63
|
bin: 'codex',
|
|
62
64
|
credential: { env: 'CODEX_HOME', default: '~/.codex', file: 'auth.json' },
|
|
63
65
|
setupUrl: 'https://github.com/sabaiway/agent-workflow/blob/main/codex-cli-bridge/setup/README.md',
|
|
@@ -69,7 +71,7 @@ export const KNOWN_BACKENDS = [
|
|
|
69
71
|
{
|
|
70
72
|
name: 'antigravity-cli-bridge',
|
|
71
73
|
installed: { env: 'ANTIGRAVITY_CLI_BRIDGE_DIR', default: '~/.claude/skills/antigravity-cli-bridge', file: 'SKILL.md' },
|
|
72
|
-
|
|
74
|
+
roleCmds: { review: 'agy-review', probe: 'agy-run' },
|
|
73
75
|
bin: 'agy',
|
|
74
76
|
credential: { env: null, default: '~/.gemini/antigravity-cli', file: 'antigravity-oauth-token' },
|
|
75
77
|
setupUrl: 'https://github.com/sabaiway/agent-workflow/blob/main/antigravity-cli-bridge/setup/README.md',
|
|
@@ -78,6 +80,17 @@ export const KNOWN_BACKENDS = [
|
|
|
78
80
|
},
|
|
79
81
|
];
|
|
80
82
|
|
|
83
|
+
// The deduped roles[].cmd set the CURRENT kit bundles, derived from roleCmds in first-seen order — one
|
|
84
|
+
// source, so the readiness-probe list can never drift from the role-keyed map.
|
|
85
|
+
const wrapperCmdsFromRoles = (roleCmds) => [...new Set(Object.values(roleCmds ?? {}))];
|
|
86
|
+
export const KNOWN_BACKENDS = RAW_BACKENDS.map((entry) => ({ ...entry, wrapperCmds: wrapperCmdsFromRoles(entry.roleCmds) }));
|
|
87
|
+
|
|
88
|
+
// Resolve a dispatched (backend manifest name, role) to its concrete PATH wrapper cmd (e.g.
|
|
89
|
+
// codex-cli-bridge + review → "codex-review") from the role-keyed registry — the backend-set aid
|
|
90
|
+
// consumes this to print WHICH wrapper each dispatched backend runs. `null` when the pair is unknown.
|
|
91
|
+
export const wrapperCmdFor = (backendName, role) =>
|
|
92
|
+
KNOWN_BACKENDS.find((b) => b.name === backendName)?.roleCmds?.[role] ?? null;
|
|
93
|
+
|
|
81
94
|
// ── pure helpers ─────────────────────────────────────────────────────────────
|
|
82
95
|
|
|
83
96
|
// Expand a leading "~" / "~/x" against home; absolute and relative paths pass through untouched.
|
package/tools/procedures.mjs
CHANGED
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
import { readFileSync, lstatSync } from 'node:fs';
|
|
20
20
|
import { homedir } from 'node:os';
|
|
21
21
|
import { pathToFileURL } from 'node:url';
|
|
22
|
-
import { detectBackends } from './detect-backends.mjs';
|
|
23
|
-
import { ACTIVITIES, resolveActivityRecipe } from './recipes.mjs';
|
|
22
|
+
import { detectBackends, wrapperCmdFor } from './detect-backends.mjs';
|
|
23
|
+
import { ACTIVITIES, resolveActivityRecipe, planRecipe } from './recipes.mjs';
|
|
24
24
|
import { resolveEngineDir, readEngineFragment, PROCEDURES_FRAGMENT_REL } from './engine-source.mjs';
|
|
25
25
|
// The config schema/read core lives in orchestration-config.mjs (the single config contract). procedures
|
|
26
26
|
// is READ-ONLY: it imports the reader + the SHARED slot/recipe validity, never the fs-writer
|
|
@@ -126,10 +126,16 @@ export const extractSection = (text, activity) => {
|
|
|
126
126
|
// ── resolution + rendering ─────────────────────────────────────────────────────────
|
|
127
127
|
|
|
128
128
|
const resolveAllSlots = ({ activity, config, detection, overrides }) =>
|
|
129
|
-
Object.keys(ACTIVITIES[activity].slots).map((slot) =>
|
|
130
|
-
slot,
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
Object.keys(ACTIVITIES[activity].slots).map((slot) => {
|
|
130
|
+
const resolved = resolveActivityRecipe({ config: config ?? {}, readiness: detection, activity, slot, override: overrides[slot] });
|
|
131
|
+
// The concrete wrapper set this slot's EFFECTIVE recipe dispatches (empty for solo). Reuse
|
|
132
|
+
// planRecipe's drift-guarded dispatch for WHICH backends, then resolve each (backend, role) to its
|
|
133
|
+
// manifest wrapper cmd via the bridge registry — no wrapper name is hand-composed here.
|
|
134
|
+
const backends = planRecipe(resolved.recipe, detection).dispatch
|
|
135
|
+
.map((d) => wrapperCmdFor(d.backend, d.role))
|
|
136
|
+
.filter(Boolean);
|
|
137
|
+
return { slot, ...resolved, backends };
|
|
138
|
+
});
|
|
133
139
|
|
|
134
140
|
// An unsatisfiable EXPLICIT override is the only "warning" (loud, flagged for the agent to relay). A
|
|
135
141
|
// graceful config/default degradation is reported as a per-slot reason, not a warning.
|
|
@@ -147,6 +153,35 @@ const SOURCE_LABEL = {
|
|
|
147
153
|
override: 'from --override',
|
|
148
154
|
};
|
|
149
155
|
|
|
156
|
+
// The explicit wrapper set a review/execute recipe dispatches, printed beside the recipe name so the A2
|
|
157
|
+
// recipe-fidelity obligation ("run every named backend, every round") is mechanical at the point of use.
|
|
158
|
+
// ≥2 backends (Council) → the every-round reminder; exactly 1 → the lone wrapper; Solo dispatches none → ''.
|
|
159
|
+
const backendSetLabel = (backends) =>
|
|
160
|
+
!backends || backends.length === 0
|
|
161
|
+
? ''
|
|
162
|
+
: backends.length >= 2
|
|
163
|
+
? ` → run every backend every round: ${backends.join(' + ')}`
|
|
164
|
+
: ` → ${backends[0]}`;
|
|
165
|
+
|
|
166
|
+
// The review-loop economics block (M1 + M6's firing half) — printed when the activity engages a review
|
|
167
|
+
// backend (a slot resolving reviewed | council) and OMITTED for solo. It paraphrases the §9 +
|
|
168
|
+
// orchestration §4 canon (no rival rule): the ≤2-round architecture cap, the bar met by RAISING a
|
|
169
|
+
// surviving major to an acceptance invariant (not exhausting prose), backend divergence = the crossover
|
|
170
|
+
// stop, the thin-plan/diff-review carve-out, a self-consistency read before every re-review, and the
|
|
171
|
+
// REQUIRED per-round structured emission {round N · finding-origin tally · per-backend verdict}. Only a
|
|
172
|
+
// review slot can resolve reviewed|council (execute floors at solo|delegated), so gate on the recipe.
|
|
173
|
+
const REVIEW_RECIPES = new Set(['reviewed', 'council']);
|
|
174
|
+
const reviewLoopAdvice = (slots) =>
|
|
175
|
+
slots.some((s) => REVIEW_RECIPES.has(s.recipe))
|
|
176
|
+
? [
|
|
177
|
+
'Review-loop economics (planning.md §9 · orchestration.md §4) — the review this recipe runs:',
|
|
178
|
+
' • Cap architecture plan-review at ≤2 rounds; the bar is met by RAISING a surviving major to an acceptance invariant (or handing it to Execute/diff-review), never by exhausting the strictest backend.',
|
|
179
|
+
' • Backend divergence (one backend grounded-ships while another keeps revising mechanics) IS the crossover stop.',
|
|
180
|
+
' • Route an all-mechanics/CI or prose-only artifact to a thin plan + diff-review; run a self-consistency read before every re-review.',
|
|
181
|
+
' • Each round MUST emit {round N · finding-origin tally (first-draft / fold-induced / mechanics) · per-backend verdict} so the crossover is a computed signal.',
|
|
182
|
+
]
|
|
183
|
+
: [];
|
|
184
|
+
|
|
150
185
|
const formatHuman = ({ activity, section, slots, warnings }) => {
|
|
151
186
|
const lines = [
|
|
152
187
|
section,
|
|
@@ -155,9 +190,11 @@ const formatHuman = ({ activity, section, slots, warnings }) => {
|
|
|
155
190
|
];
|
|
156
191
|
for (const s of slots) {
|
|
157
192
|
const arrow = s.degradedFrom ? ` (requested ${s.degradedFrom} → degraded)` : '';
|
|
158
|
-
lines.push(` ${s.slot}: ${s.recipe} — ${SOURCE_LABEL[s.source]}${arrow}`);
|
|
193
|
+
lines.push(` ${s.slot}: ${s.recipe} — ${SOURCE_LABEL[s.source]}${arrow}${backendSetLabel(s.backends)}`);
|
|
159
194
|
if (s.reason) lines.push(` ↳ ${s.reason}`);
|
|
160
195
|
}
|
|
196
|
+
const advice = reviewLoopAdvice(slots);
|
|
197
|
+
if (advice.length) lines.push('', ...advice);
|
|
161
198
|
if (warnings.length) {
|
|
162
199
|
lines.push('', 'warnings:');
|
|
163
200
|
for (const w of warnings) lines.push(` ⚠ ${w}`);
|
|
@@ -169,8 +206,9 @@ const buildJson = ({ activity, section, slots, configSource, warnings }) => ({
|
|
|
169
206
|
activity,
|
|
170
207
|
section,
|
|
171
208
|
slots: Object.fromEntries(
|
|
172
|
-
slots.map((s) => [s.slot, { recipe: s.recipe, source: s.source, degradedFrom: s.degradedFrom, reason: s.reason }]),
|
|
209
|
+
slots.map((s) => [s.slot, { recipe: s.recipe, source: s.source, degradedFrom: s.degradedFrom, reason: s.reason, backends: s.backends }]),
|
|
173
210
|
),
|
|
211
|
+
reviewLoop: reviewLoopAdvice(slots),
|
|
174
212
|
configSource,
|
|
175
213
|
warnings,
|
|
176
214
|
});
|