@sabaiway/agent-workflow-kit 5.0.0 → 5.1.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 +29 -0
- package/SKILL.md +1 -1
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/modes/procedures.md +2 -2
- package/tools/doc-parity.mjs +14 -2
- package/tools/orchestration-config.mjs +26 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,35 @@ 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
|
+
## 5.1.0 — the config learns to carry the flow block before anything writes one (AD-085)
|
|
8
|
+
|
|
9
|
+
**Upgrade this before any flow feature arrives — that ordering IS the release.** The shared
|
|
10
|
+
`docs/ai/orchestration.json` is read by every collaborator's kit, and the validator is strict on
|
|
11
|
+
purpose: an unknown top-level key fails the config load loudly (exit 1) and reddens that machine's
|
|
12
|
+
entire gate matrix. The upcoming orchestration-flow feature adds a `flow` block to that file, so
|
|
13
|
+
the fleet has to tolerate the block before the first writer exists. This release is that
|
|
14
|
+
tolerance, shipped first and alone.
|
|
15
|
+
|
|
16
|
+
- `orchestration.json` may now carry a reserved `"flow"` object whose `"schema"` is the NUMBER
|
|
17
|
+
`1` (`FLOW_SCHEMA_VERSION`, exported — flow-aware releases import it, never re-type it). Every
|
|
18
|
+
other byte of the block is deliberately uninterpreted: nothing in 5.1.0 reads it, nothing
|
|
19
|
+
writes it (the writer arrives with the flow store).
|
|
20
|
+
- Refusals stay loud and name the contract: a non-object `flow`, an absent or unknown `schema`,
|
|
21
|
+
and the STRING form `"1"` each fail with the accepted version in the message; every other
|
|
22
|
+
unknown top-level key refuses exactly as before.
|
|
23
|
+
- No writer change was needed for safety: `set-recipe` runs and the `_README` refresh carry a
|
|
24
|
+
present `flow` block through JSON-value-equal (content-preserving, not byte-preserving —
|
|
25
|
+
characterized for no-op runs, real slot changes, and all three README-refresh arms).
|
|
26
|
+
- Honest limit, doc-parity-bound so it cannot be reworded away: this release enforces NO version
|
|
27
|
+
floor against a pre-flow reader — a kit older than 5.1.0 that meets a `flow` block still fails
|
|
28
|
+
loudly. Tolerate-first ordering is the only mitigation until enforcement arms on the
|
|
29
|
+
`set-flow` path (a later release); `references/modes/procedures.md` states both halves on its
|
|
30
|
+
contract lines, pinned by two new doc-parity bindings.
|
|
31
|
+
- Groundwork pinned green: the floor mechanics the rollout leans on (the four `semver-lite`
|
|
32
|
+
consumers, including the installer's never-downgrade lane) are characterized, and the
|
|
33
|
+
characterization surfaced a `null >= 0` coercion trap the future arming floor must guard —
|
|
34
|
+
queued, with the guarded comparison shape documented in the test.
|
|
35
|
+
|
|
7
36
|
## 5.0.0 — the deployed rotation gates fail closed (memory 4.0.0 mirrored; AD-084)
|
|
8
37
|
|
|
9
38
|
> ### ⚠ BREAKING — inherited from memory 4.0.0
|
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: '5.
|
|
6
|
+
version: '5.1.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": "5.
|
|
3
|
+
"version": "5.1.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",
|
|
@@ -11,9 +11,9 @@ The two v1 activities (canon in the **installed engine**, `references/procedures
|
|
|
11
11
|
|
|
12
12
|
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:
|
|
13
13
|
|
|
14
|
-
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`.
|
|
14
|
+
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; a reserved `"flow"` object is tolerated + carried uninterpreted when it carries the NUMERIC `"schema": 1` (the kit's accepted flow schema version — any other form or value refuses loudly). `review` accepts `solo|reviewed|council`; `execute` accepts `solo|delegated`. Seeded by `init` (a user-editable template) — see `${CLAUDE_SKILL_DIR}/references/modes/bootstrap.md`.
|
|
15
15
|
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).
|
|
16
|
-
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.
|
|
16
|
+
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. **Lagging-kit honesty:** a kit predating the `"flow"` key that reads a config carrying one fails this config load loudly (exit `1`, reddening its full gate matrix); this kit release enforces NO version floor against such a pre-flow reader — tolerate-first ordering is the only mitigation until a flow-aware release arms enforcement on the `set-flow` path.
|
|
17
17
|
|
|
18
18
|
**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.
|
|
19
19
|
|
package/tools/doc-parity.mjs
CHANGED
|
@@ -35,6 +35,9 @@ import {
|
|
|
35
35
|
import { SKIPPED_READONLY } from './setup-backends.mjs';
|
|
36
36
|
import { LATENT_ARM_NOTICE } from './review-state.mjs';
|
|
37
37
|
import { QUEUE_SHARED_RULE, LANDING_FROM_MAIN, NO_DEPENDENCIES_POSTURE, CLEANUP_OWNERSHIP_RULE, INCLUDE_IDENTITY_RULE, RESUME_VERIFY_RULE } from './worktrees.mjs';
|
|
38
|
+
// The flow tolerate contract (tolerate-only release): the accepted schema version + the honest
|
|
39
|
+
// lagging-kit sentence, both owned by the config validator and pinned into procedures.md.
|
|
40
|
+
import { FLOW_SCHEMA_VERSION, FLOW_LAGGING_KIT_CONTRACT } from './orchestration-config.mjs';
|
|
38
41
|
|
|
39
42
|
const KIT_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
40
43
|
|
|
@@ -45,6 +48,7 @@ const VELOCITY_DOC = 'references/modes/velocity.md';
|
|
|
45
48
|
const SETUP_DOC = 'references/modes/setup.md';
|
|
46
49
|
const REVIEW_STATE_DOC = 'references/modes/review-state.md';
|
|
47
50
|
const WORKTREES_DOC = 'references/modes/worktrees.md';
|
|
51
|
+
const PROCEDURES_DOC = 'references/modes/procedures.md';
|
|
48
52
|
|
|
49
53
|
// A typed usage failure (exit 2) for the CLI parser — the codebase's typed-error idiom (no classes).
|
|
50
54
|
const usageFail = (message) => Object.assign(new Error(message), { exitCode: 2 });
|
|
@@ -116,6 +120,13 @@ export const BINDINGS = Object.freeze([
|
|
|
116
120
|
// a reworded mode doc dropping the per-owned-path × session-never-probed contract fails this pin
|
|
117
121
|
// plus the gate.
|
|
118
122
|
valueBinding('resume-verify-rule', RESUME_VERIFY_RULE, RESUME_VERIFY_RULE, [WORKTREES_DOC]),
|
|
123
|
+
// The flow tolerate contract: (a) the accepted NUMERIC `flow` schema version renders into the
|
|
124
|
+
// procedures.md allowed-shape contract line — a bumped constant with an unchanged doc fails this
|
|
125
|
+
// pin plus the gate; (b) the honest lagging-kit sentence — what a pre-flow kit does on meeting a
|
|
126
|
+
// `flow` block, and that this release enforces nothing against such a reader — renders as the
|
|
127
|
+
// exact exported sentence into the exit-1 contract line, so the admission cannot be reworded away.
|
|
128
|
+
valueBinding('flow-schema-version', FLOW_SCHEMA_VERSION, `\`"schema": ${FLOW_SCHEMA_VERSION}\``, [PROCEDURES_DOC]),
|
|
129
|
+
valueBinding('flow-lagging-kit', FLOW_LAGGING_KIT_CONTRACT, FLOW_LAGGING_KIT_CONTRACT, [PROCEDURES_DOC]),
|
|
119
130
|
].map((b) => Object.freeze(b)));
|
|
120
131
|
|
|
121
132
|
// ── the pure checker (readText is injectable for hermetic tests) ────────────────────────
|
|
@@ -164,8 +175,9 @@ table, the status tokens, the trusted-dir allowlist), the recommendations/upgrad
|
|
|
164
175
|
contract (section header, empty line, verdict templates), the acks-store path, the setup refresh
|
|
165
176
|
degrade token, the review-state clean-tree latent-arm notice, the worktrees provision-record
|
|
166
177
|
orientation contract (shared-queue rule, landing-from-main, no-dependencies install posture), the
|
|
167
|
-
worktrees cleanup-ownership rule, the worktrees include-identity rule,
|
|
168
|
-
resume-verify rule
|
|
178
|
+
worktrees cleanup-ownership rule, the worktrees include-identity rule, the worktrees
|
|
179
|
+
resume-verify rule, and the flow tolerate contract (the accepted flow schema version + the
|
|
180
|
+
lagging-kit sentence, procedures.md) — to
|
|
169
181
|
the exact token its references/modes/*.md contract must carry, and
|
|
170
182
|
asserts the CURRENT value renders into every bound file. A drifted doc, an unreadable bound file,
|
|
171
183
|
or an absent token FAILS CLOSED.
|
|
@@ -113,10 +113,24 @@ export const parseOp = (kind, token) => {
|
|
|
113
113
|
|
|
114
114
|
// ── config validation (config errors → exit 1) ──────────────────────────────────────
|
|
115
115
|
|
|
116
|
+
// The accepted `flow` schema version — the SINGLE source both the acceptance check and the refusal
|
|
117
|
+
// message use; future flow-aware releases IMPORT this constant, never re-type it. The wire value is
|
|
118
|
+
// pinned NUMERIC (the string form is a named refusal case).
|
|
119
|
+
export const FLOW_SCHEMA_VERSION = 1;
|
|
120
|
+
|
|
121
|
+
// The honest lagging-kit contract sentence (tolerate-first ordering): what a kit WITHOUT the flow
|
|
122
|
+
// branch does when it meets a `flow` block, and that this release enforces nothing against such a
|
|
123
|
+
// reader. doc-parity binds it VERBATIM into the procedures mode doc's exit-1 contract line, so the
|
|
124
|
+
// doc can never soften the admission while the gap is real (enforcement arms with `set-flow`).
|
|
125
|
+
export const FLOW_LAGGING_KIT_CONTRACT =
|
|
126
|
+
'a kit predating the `"flow"` key that reads a config carrying one fails this config load loudly (exit `1`, reddening its full gate matrix); this kit release enforces NO version floor against such a pre-flow reader — tolerate-first ordering is the only mitigation until a flow-aware release arms enforcement on the `set-flow` path';
|
|
127
|
+
|
|
116
128
|
// Validate a parsed orchestration.json object against the schema. Strict: an unknown top-level
|
|
117
129
|
// activity, an unknown slot for an activity, or a recipe invalid-for-slot is an error. All slots are
|
|
118
|
-
// optional. An optional "_README" string key is allowed + ignored (self-documentation).
|
|
119
|
-
//
|
|
130
|
+
// optional. An optional "_README" string key is allowed + ignored (self-documentation). A versioned
|
|
131
|
+
// "flow" object key is TOLERATED when its `schema` strict-equals FLOW_SCHEMA_VERSION — every other
|
|
132
|
+
// byte of the block is deliberately uninterpreted here (nothing in this kit reads or writes it yet).
|
|
133
|
+
// Never a silent fallback — every rejection is a loud `path: reason` (exit 1). Returns the config on success.
|
|
120
134
|
export const validateConfig = (config) => {
|
|
121
135
|
if (config === null || typeof config !== 'object' || Array.isArray(config)) {
|
|
122
136
|
throw fail(1, `${CONFIG_REL}: must be a JSON object of activity → { slot: recipe }`);
|
|
@@ -126,6 +140,16 @@ export const validateConfig = (config) => {
|
|
|
126
140
|
if (typeof val !== 'string') throw fail(1, `${CONFIG_REL}: "_README" must be a string`);
|
|
127
141
|
continue;
|
|
128
142
|
}
|
|
143
|
+
if (key === 'flow') {
|
|
144
|
+
if (val === null || typeof val !== 'object' || Array.isArray(val)) {
|
|
145
|
+
throw fail(1, `${CONFIG_REL}: "flow" must be a JSON object carrying { "schema": ${FLOW_SCHEMA_VERSION} }`);
|
|
146
|
+
}
|
|
147
|
+
if (val.schema !== FLOW_SCHEMA_VERSION) {
|
|
148
|
+
const got = 'schema' in val ? JSON.stringify(val.schema) : 'absent';
|
|
149
|
+
throw fail(1, `${CONFIG_REL}: "flow".schema must be the number ${FLOW_SCHEMA_VERSION} (got ${got})`);
|
|
150
|
+
}
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
129
153
|
const activityDef = ACTIVITIES[key];
|
|
130
154
|
if (!activityDef) {
|
|
131
155
|
throw fail(1, `${CONFIG_REL}: unknown activity "${key}" (known: ${KNOWN_ACTIVITIES()})`);
|