@sabaiway/agent-workflow-kit 1.33.0 → 1.35.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 +99 -0
- package/README.md +2 -1
- package/SKILL.md +6 -2
- package/bin/install.mjs +37 -1
- package/bridges/antigravity-cli-bridge/SKILL.md +13 -1
- package/bridges/antigravity-cli-bridge/bin/agy-review.sh +96 -1
- package/bridges/antigravity-cli-bridge/bin/agy-review.test.mjs +204 -1
- package/bridges/antigravity-cli-bridge/bin/agy.sh +94 -0
- package/bridges/antigravity-cli-bridge/bin/agy.test.mjs +245 -1
- package/bridges/antigravity-cli-bridge/capability.json +17 -1
- package/bridges/codex-cli-bridge/SKILL.md +15 -1
- package/bridges/codex-cli-bridge/bin/codex-exec.sh +113 -0
- package/bridges/codex-cli-bridge/bin/codex-exec.test.mjs +288 -0
- package/bridges/codex-cli-bridge/bin/codex-review.sh +114 -1
- package/bridges/codex-cli-bridge/bin/codex-review.test.mjs +229 -1
- package/bridges/codex-cli-bridge/capability.json +29 -1
- package/capability.json +1 -1
- package/launchers/windsurf-workflow.md +3 -1
- package/package.json +1 -1
- package/references/contracts.md +3 -2
- package/references/modes/bootstrap.md +11 -6
- package/references/modes/bridge-settings.md +29 -0
- package/references/modes/gates.md +4 -2
- package/references/modes/review-state.md +1 -1
- package/references/modes/status.md +2 -0
- package/references/modes/upgrade.md +11 -5
- package/references/shared/deploy-tail.md +1 -1
- package/references/shared/report-footer.md +11 -4
- package/tools/atomic-write.mjs +144 -0
- package/tools/bridge-settings-read.mjs +221 -0
- package/tools/bridge-settings.mjs +288 -0
- package/tools/commands.mjs +22 -1
- package/tools/family-registry.mjs +45 -2
- package/tools/manifest/schema.md +31 -0
- package/tools/manifest/validate.mjs +85 -0
- package/tools/orchestration-write.mjs +8 -78
- package/tools/presentation.mjs +1 -0
- package/tools/procedures.mjs +26 -4
- package/tools/recipes.mjs +16 -6
- package/tools/renderers.mjs +17 -2
- package/tools/review-state.mjs +4 -2
- package/tools/seed-gates.mjs +413 -0
- package/tools/setup-backends.mjs +107 -9
- package/tools/velocity-profile.mjs +4 -0
- package/tools/view-model.mjs +20 -0
|
@@ -679,7 +679,7 @@ describe('codex-review.sh — source-level reverse guard (parser arms ⟷ manife
|
|
|
679
679
|
// The normative fixture (docs: the AD-038 plan Decisions — copied verbatim; field VALUES with
|
|
680
680
|
// dynamic content are asserted by shape):
|
|
681
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.
|
|
682
|
+
'{"schema":1,"artifact":"code","fresh":true,"fingerprint":"<sha256hex>","backend":"codex","verdict":"revise","grounded":true,"factsHash":null,"wrapperVersion":"2.3.0","timestamp":"2026-07-03T12:00:00Z"}',
|
|
683
683
|
);
|
|
684
684
|
const RECEIPTS_REL = join('.git', 'agent-workflow-review-receipts.jsonl');
|
|
685
685
|
const readReceipts = (repo) => {
|
|
@@ -799,3 +799,231 @@ describe('codex-review.sh — review receipts (AD-038)', () => {
|
|
|
799
799
|
assert.equal(receipts.length, 0, 'no review ran — no receipt');
|
|
800
800
|
});
|
|
801
801
|
});
|
|
802
|
+
|
|
803
|
+
// ── bridge settings file + service tier knob (bridges 2.3.0) ─────────────────────
|
|
804
|
+
// Same contract as codex-exec.test.mjs: KEY=VALUE lines under
|
|
805
|
+
// ${XDG_CONFIG_HOME:-$HOME/.config}/agent-workflow/bridge-settings.conf, parsed never
|
|
806
|
+
// sourced; explicit env (even empty) > file > built-in default. HOME is the sandbox
|
|
807
|
+
// repo, so the default settings path is hermetic per test.
|
|
808
|
+
|
|
809
|
+
const writeSettings = (sb, text) => {
|
|
810
|
+
const dir = join(sb.repo, '.config', 'agent-workflow');
|
|
811
|
+
mkdirSync(dir, { recursive: true });
|
|
812
|
+
const file = join(dir, 'bridge-settings.conf');
|
|
813
|
+
writeFileSync(file, text);
|
|
814
|
+
return file;
|
|
815
|
+
};
|
|
816
|
+
const isRoot = typeof process.getuid === 'function' && process.getuid() === 0;
|
|
817
|
+
|
|
818
|
+
describe('codex-review.sh — service tier knob (bridges 2.3.0)', () => {
|
|
819
|
+
it('default: no env, no file → NO service_tier flag in codex argv', () => {
|
|
820
|
+
const sb = makeSandbox();
|
|
821
|
+
const r = run(sb);
|
|
822
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
823
|
+
assert.equal(r.status, 0, r.stderr);
|
|
824
|
+
assert.doesNotMatch(r.argv, /service_tier/, 'default OFF: the flag must be absent');
|
|
825
|
+
assert.doesNotMatch(r.stderr, /bridge settings/, 'no file → no settings chatter');
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
it('env CODEX_SERVICE_TIER=priority → -c service_tier=priority reaches codex argv', () => {
|
|
829
|
+
const sb = makeSandbox();
|
|
830
|
+
const r = run(sb, { env: { CODEX_SERVICE_TIER: 'priority' } });
|
|
831
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
832
|
+
assert.equal(r.status, 0, r.stderr);
|
|
833
|
+
assert.match(r.argv, /(^|\n)service_tier=priority(\n|$)/);
|
|
834
|
+
});
|
|
835
|
+
|
|
836
|
+
it('a file-set tier lands (file wins over the built-in default)', () => {
|
|
837
|
+
const sb = makeSandbox();
|
|
838
|
+
writeSettings(sb, 'CODEX_SERVICE_TIER=priority\n');
|
|
839
|
+
const r = run(sb);
|
|
840
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
841
|
+
assert.equal(r.status, 0, r.stderr);
|
|
842
|
+
assert.match(r.argv, /(^|\n)service_tier=priority(\n|$)/);
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
it('an EXPLICITLY EMPTY env (CODEX_SERVICE_TIER=) disables a file-set tier for one run', () => {
|
|
846
|
+
const sb = makeSandbox();
|
|
847
|
+
writeSettings(sb, 'CODEX_SERVICE_TIER=priority\n');
|
|
848
|
+
const r = run(sb, { env: { CODEX_SERVICE_TIER: '' } });
|
|
849
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
850
|
+
assert.equal(r.status, 0, r.stderr);
|
|
851
|
+
assert.doesNotMatch(r.argv, /service_tier/, 'env wins over file — empty means knob off');
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
it('an invalid env tier warns and reviews on the standard tier (never passed to codex)', () => {
|
|
855
|
+
const sb = makeSandbox();
|
|
856
|
+
const r = run(sb, { env: { CODEX_SERVICE_TIER: 'turbo' } });
|
|
857
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
858
|
+
assert.equal(r.status, 0, r.stderr);
|
|
859
|
+
assert.match(r.stderr, /not a supported service tier/);
|
|
860
|
+
assert.doesNotMatch(r.argv, /service_tier/, 'an unvalidated value must never reach codex');
|
|
861
|
+
});
|
|
862
|
+
});
|
|
863
|
+
|
|
864
|
+
describe('codex-review.sh — bridge settings file semantics (bridges 2.3.0)', () => {
|
|
865
|
+
it('a file-set CODEX_REVIEW_MAX_TOTAL_BYTES is effective (switches to the temp-file path)', () => {
|
|
866
|
+
const sb = makeSandbox();
|
|
867
|
+
writeFileSync(join(sb.repo, 'big.txt'), 'B'.repeat(5000));
|
|
868
|
+
writeSettings(sb, 'CODEX_REVIEW_MAX_TOTAL_BYTES=100\n');
|
|
869
|
+
const r = run(sb);
|
|
870
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
871
|
+
assert.equal(r.status, 0, r.stderr);
|
|
872
|
+
assert.match(r.capStdin, /codex-review-diff\./, 'the tiny file cap must force the temp-file path');
|
|
873
|
+
assert.doesNotMatch(r.capStdin, /ASSEMBLED CHANGE SET:/, 'the payload must not ALSO ride inline');
|
|
874
|
+
});
|
|
875
|
+
|
|
876
|
+
it('env overrides file: a large env cap keeps the payload inline', () => {
|
|
877
|
+
const sb = makeSandbox();
|
|
878
|
+
writeFileSync(join(sb.repo, 'big.txt'), 'B'.repeat(5000));
|
|
879
|
+
writeSettings(sb, 'CODEX_REVIEW_MAX_TOTAL_BYTES=100\n');
|
|
880
|
+
const r = run(sb, { env: { CODEX_REVIEW_MAX_TOTAL_BYTES: '5000000' } });
|
|
881
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
882
|
+
assert.equal(r.status, 0, r.stderr);
|
|
883
|
+
assert.match(r.capStdin, /ASSEMBLED CHANGE SET:/, 'the env cap (large) must win over the file cap (100)');
|
|
884
|
+
assert.doesNotMatch(r.capStdin, /codex-review-diff\./);
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
it('duplicate key → the LAST occurrence wins (100 then 5000000 → inline)', () => {
|
|
888
|
+
const sb = makeSandbox();
|
|
889
|
+
writeFileSync(join(sb.repo, 'big.txt'), 'B'.repeat(5000));
|
|
890
|
+
writeSettings(sb, 'CODEX_REVIEW_MAX_TOTAL_BYTES=100\nCODEX_REVIEW_MAX_TOTAL_BYTES=5000000\n');
|
|
891
|
+
const r = run(sb);
|
|
892
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
893
|
+
assert.equal(r.status, 0, r.stderr);
|
|
894
|
+
assert.match(r.capStdin, /ASSEMBLED CHANGE SET:/);
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
it("another wrapper's / another bridge's valid key is skipped silently", () => {
|
|
898
|
+
const sb = makeSandbox();
|
|
899
|
+
writeSettings(sb, 'AGY_HARD_TIMEOUT=30m\nAGY_REVIEW_ALLOW_ADDDIR=1\n');
|
|
900
|
+
const r = run(sb);
|
|
901
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
902
|
+
assert.equal(r.status, 0, r.stderr);
|
|
903
|
+
assert.doesNotMatch(r.stderr, /bridge settings/, 'a recognized non-applied key earns NO warning');
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
it('a truly unknown key warns ONCE naming the file; the review is unaffected', () => {
|
|
907
|
+
const sb = makeSandbox();
|
|
908
|
+
writeSettings(sb, 'TOTALLY_UNKNOWN=1\nTOTALLY_UNKNOWN=2\n');
|
|
909
|
+
const r = run(sb);
|
|
910
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
911
|
+
assert.equal(r.status, 0, r.stderr);
|
|
912
|
+
const warns = r.stderr.match(/unknown key 'TOTALLY_UNKNOWN'/g) ?? [];
|
|
913
|
+
assert.equal(warns.length, 1, `exactly one warning per unknown key, got ${warns.length}`);
|
|
914
|
+
assert.match(r.stderr, /bridge-settings\.conf/, 'the warning must name the settings file');
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
it('malformed lines warn and are ignored; comments and blank lines are silent', () => {
|
|
918
|
+
const sb = makeSandbox();
|
|
919
|
+
writeSettings(sb, '# a comment\n\nNOT A KEY VALUE LINE\nCODEX_SERVICE_TIER=priority\n');
|
|
920
|
+
const r = run(sb);
|
|
921
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
922
|
+
assert.equal(r.status, 0, r.stderr);
|
|
923
|
+
const malformed = r.stderr.match(/malformed line/g) ?? [];
|
|
924
|
+
assert.equal(malformed.length, 1, 'comments/blank lines must NOT count as malformed');
|
|
925
|
+
assert.match(r.argv, /(^|\n)service_tier=priority(\n|$)/, 'valid lines still apply');
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
it('an existing-but-unreadable file warns loudly and falls back to built-ins', { skip: isRoot }, () => {
|
|
929
|
+
// The settings file goes OUTSIDE the repo (XDG_CONFIG_HOME): an unreadable file INSIDE the
|
|
930
|
+
// work tree would fail the review-payload assembly itself (untracked contents are cat'ed),
|
|
931
|
+
// which is pre-existing behaviour unrelated to the settings reader.
|
|
932
|
+
const sb = makeSandbox();
|
|
933
|
+
const xdg = join(sb.root, 'xdg');
|
|
934
|
+
mkdirSync(join(xdg, 'agent-workflow'), { recursive: true });
|
|
935
|
+
const file = join(xdg, 'agent-workflow', 'bridge-settings.conf');
|
|
936
|
+
writeFileSync(file, 'CODEX_SERVICE_TIER=priority\n');
|
|
937
|
+
chmodSync(file, 0o000);
|
|
938
|
+
const r = run(sb, { env: { XDG_CONFIG_HOME: xdg } });
|
|
939
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
940
|
+
assert.equal(r.status, 0, r.stderr);
|
|
941
|
+
assert.match(r.stderr, /unreadable/);
|
|
942
|
+
assert.doesNotMatch(r.argv, /service_tier/, 'an unreadable file must yield built-in defaults');
|
|
943
|
+
});
|
|
944
|
+
|
|
945
|
+
it('a settings line can NEVER execute code (command-substitution payload inert)', () => {
|
|
946
|
+
const sb = makeSandbox();
|
|
947
|
+
const pwned = join(sb.repo, 'pwned');
|
|
948
|
+
const pwned2 = join(sb.repo, 'pwned2');
|
|
949
|
+
writeSettings(
|
|
950
|
+
sb,
|
|
951
|
+
`CODEX_SERVICE_TIER=$(touch ${pwned})\nEVIL_KEY=\`touch ${pwned2}\`\n`,
|
|
952
|
+
);
|
|
953
|
+
const r = run(sb);
|
|
954
|
+
const executed = existsSync(pwned) || existsSync(pwned2);
|
|
955
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
956
|
+
assert.equal(r.status, 0, r.stderr);
|
|
957
|
+
assert.equal(executed, false, 'file content must be parsed, never evaluated');
|
|
958
|
+
assert.doesNotMatch(r.argv, /service_tier/, 'the payload value must fail validation');
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
it('a DIRECTORY at the settings path warns loudly and falls back to built-ins (no crash)', () => {
|
|
962
|
+
// Outside the repo (XDG) — an unreadable path INSIDE the work tree would fail the
|
|
963
|
+
// review-payload assembly itself (pre-existing behaviour, unrelated to the reader).
|
|
964
|
+
const sb = makeSandbox();
|
|
965
|
+
const xdg = join(sb.root, 'xdg');
|
|
966
|
+
mkdirSync(join(xdg, 'agent-workflow', 'bridge-settings.conf'), { recursive: true });
|
|
967
|
+
const r = run(sb, { env: { XDG_CONFIG_HOME: xdg } });
|
|
968
|
+
rmSync(sb.root, { recursive: true, force: true });
|
|
969
|
+
assert.equal(r.status, 0, `a directory must degrade honestly, not kill the run: ${r.stderr}`);
|
|
970
|
+
assert.match(r.stderr, /unreadable or not a regular file/);
|
|
971
|
+
assert.doesNotMatch(r.stderr, /Is a directory/, 'no raw bash error may leak');
|
|
972
|
+
});
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
// ── settings surface ⟷ manifest (drift guard, D6) — same contract as codex-exec ──
|
|
976
|
+
const SETTINGS_HEADER = 'Settings file (KEY=VALUE, parsed never sourced; env wins over file, file wins over built-in default):';
|
|
977
|
+
const SIBLING_MANIFEST = JSON.parse(readFileSync(join(HERE, '..', '..', 'antigravity-cli-bridge', 'capability.json'), 'utf8'));
|
|
978
|
+
const ALL_SETTINGS = [...(MANIFEST.settings ?? []), ...(SIBLING_MANIFEST.settings ?? [])];
|
|
979
|
+
const SETTINGS_CMD = 'codex-review';
|
|
980
|
+
|
|
981
|
+
describe('codex-review.sh — settings surface ⟷ manifest (D6, manifest-pinned)', () => {
|
|
982
|
+
it('--help Settings section keys set-EQUAL the manifest appliesTo subset', () => {
|
|
983
|
+
const help = runHelp('--help').stdout;
|
|
984
|
+
const section = helpSection(help, SETTINGS_HEADER);
|
|
985
|
+
const got = section.filter((l) => /^[A-Z][A-Z0-9_]+ —/.test(l)).map((l) => l.split(' ')[0]);
|
|
986
|
+
const want = (MANIFEST.settings ?? []).filter((s) => s.appliesTo.includes(SETTINGS_CMD)).map((s) => s.key);
|
|
987
|
+
assert.ok(want.length > 0, 'the manifest must declare settings for this wrapper');
|
|
988
|
+
setEq(got, want, 'help Settings keys ⟷ manifest settings.appliesTo');
|
|
989
|
+
assert.ok(section.some((l) => l.includes('agent-workflow/bridge-settings.conf')), 'the section names the settings file');
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
const source = readFileSync(WRAPPER, 'utf8');
|
|
993
|
+
|
|
994
|
+
it('aw_settings_known carries exactly the UNION of both bridges settings keys', () => {
|
|
995
|
+
const m = source.match(/aw_settings_known\(\) \{\n case " ([^"]+) " in/);
|
|
996
|
+
assert.ok(m, 'aw_settings_known registry case not found');
|
|
997
|
+
assert.ok(ALL_SETTINGS.length >= 5, 'both manifests must contribute settings');
|
|
998
|
+
setEq(m[1].trim().split(/\s+/), ALL_SETTINGS.map((s) => s.key), 'shell registry ⟷ manifest union');
|
|
999
|
+
});
|
|
1000
|
+
|
|
1001
|
+
it('AW_SETTINGS_APPLIED equals the manifest appliesTo subset for this wrapper', () => {
|
|
1002
|
+
const m = source.match(/^AW_SETTINGS_APPLIED="([^"]*)"$/m);
|
|
1003
|
+
assert.ok(m, 'AW_SETTINGS_APPLIED not found');
|
|
1004
|
+
const want = ALL_SETTINGS.filter((s) => s.appliesTo.includes(SETTINGS_CMD)).map((s) => s.key);
|
|
1005
|
+
assert.ok(want.length > 0);
|
|
1006
|
+
setEq(m[1].trim().split(/\s+/), want, 'applied subset ⟷ manifest appliesTo');
|
|
1007
|
+
});
|
|
1008
|
+
|
|
1009
|
+
it('aw_settings_valid arms carry the manifest typed constants per key', () => {
|
|
1010
|
+
const body = source.match(/aw_settings_valid\(\) \{[\s\S]*?\n\}/);
|
|
1011
|
+
assert.ok(body, 'aw_settings_valid not found');
|
|
1012
|
+
const armKeys = [...body[0].matchAll(/^ ([A-Z][A-Z0-9_]*)\)/gm)].map((x) => x[1]);
|
|
1013
|
+
setEq(armKeys, ALL_SETTINGS.map((s) => s.key), 'validation arms ⟷ manifest keys');
|
|
1014
|
+
for (const s of ALL_SETTINGS) {
|
|
1015
|
+
const arm = body[0].match(new RegExp(`^ ${s.key}\\) (.*) ;;$`, 'm'));
|
|
1016
|
+
assert.ok(arm, `no validation arm for ${s.key}`);
|
|
1017
|
+
if (s.kind === 'enum') for (const v of s.values) assert.ok(arm[1].includes(`"${v}"`), `${s.key}: enum value '${v}' not pinned`);
|
|
1018
|
+
if (s.kind === 'integer') {
|
|
1019
|
+
assert.match(arm[1], new RegExp(`>= ${s.min}\\b`), `${s.key}: min ${s.min} not pinned`);
|
|
1020
|
+
assert.match(arm[1], new RegExp(`<= ${s.max}\\b`), `${s.key}: max ${s.max} not pinned`);
|
|
1021
|
+
}
|
|
1022
|
+
if (s.kind === 'boolean') assert.ok(arm[1].includes('"0"') && arm[1].includes('"1"'), `${s.key}: boolean 0/1 not pinned`);
|
|
1023
|
+
if (s.kind === 'duration') {
|
|
1024
|
+
assert.ok(arm[1].includes('$dur_re'), `${s.key}: duration grammar not pinned`);
|
|
1025
|
+
assert.ok(arm[1].includes('$zero_re'), `${s.key}: zero-duration rejection not pinned (timeout 0 disables the cap)`);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
});
|
|
1029
|
+
});
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"schema": 1,
|
|
4
4
|
"name": "codex-cli-bridge",
|
|
5
5
|
"kind": "execution-backend",
|
|
6
|
-
"version": "2.
|
|
6
|
+
"version": "2.3.0",
|
|
7
7
|
"provides": ["execute", "review"],
|
|
8
8
|
"roles": {
|
|
9
9
|
"execute": {
|
|
@@ -43,6 +43,34 @@
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
|
+
"settings": [
|
|
47
|
+
{
|
|
48
|
+
"key": "CODEX_SERVICE_TIER",
|
|
49
|
+
"kind": "enum",
|
|
50
|
+
"values": ["priority"],
|
|
51
|
+
"default": null,
|
|
52
|
+
"appliesTo": ["codex-exec", "codex-review"],
|
|
53
|
+
"effect": "codex service tier; 'priority' (catalog display name Fast) = ~1.5x token speed at a 2.5x credit rate on gpt-5.5 — quality-neutral (same model), live-probed 2026-07-05. Unset/empty ⇒ no service_tier flag (standard tier). SPEND KNOB: enabling it is a consented per-host act, never a default. codex itself accepts any -c service_tier string silently, so the wrapper validates the value."
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"key": "CODEX_HARD_TIMEOUT",
|
|
57
|
+
"kind": "integer",
|
|
58
|
+
"min": 1,
|
|
59
|
+
"max": 86400,
|
|
60
|
+
"default": null,
|
|
61
|
+
"appliesTo": ["codex-exec", "codex-review"],
|
|
62
|
+
"effect": "hard wall-clock cap in seconds via timeout(1); built-in default 3600 (codex-exec) / 1800 (codex-review)."
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"key": "CODEX_REVIEW_MAX_TOTAL_BYTES",
|
|
66
|
+
"kind": "integer",
|
|
67
|
+
"min": 1,
|
|
68
|
+
"max": 100000000,
|
|
69
|
+
"default": "1500000",
|
|
70
|
+
"appliesTo": ["codex-review"],
|
|
71
|
+
"effect": "codex-review code: above this assembled-payload size (bytes) the diff rides via a git-dir temp file instead of inline — never truncated."
|
|
72
|
+
}
|
|
73
|
+
],
|
|
46
74
|
"detect": {
|
|
47
75
|
"installed": {
|
|
48
76
|
"env": "CODEX_CLI_BRIDGE_DIR",
|
package/capability.json
CHANGED
|
@@ -22,7 +22,9 @@ reinvent any of it here; the kit's `SKILL.md` is the single source of truth.
|
|
|
22
22
|
- No `docs/ai/` in this project → **bootstrap**.
|
|
23
23
|
- `docs/ai/` already exists → ask the user whether to run **upgrade** instead.
|
|
24
24
|
3. Execute every step from `SKILL.md` for THIS repository:
|
|
25
|
-
- Recon (read-only) → **ask the
|
|
25
|
+
- Recon (read-only) → **ask the three setup questions (visible-or-hidden / language /
|
|
26
|
+
attribution) as ONE structured multi-question prompt; record each answer individually,
|
|
27
|
+
write nothing until ALL are answered** →
|
|
26
28
|
create `AGENTS.md` (+ `CLAUDE.md` symlink) from `<KIT_DIR>/references/templates/` →
|
|
27
29
|
deploy `docs/ai/` → copy `<KIT_DIR>/references/scripts/*.mjs` (Node projects) →
|
|
28
30
|
wire/hide per visibility → install the pre-commit hook → stamp `docs/ai/.workflow-version`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sabaiway/agent-workflow-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.35.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",
|
package/references/contracts.md
CHANGED
|
@@ -5,8 +5,9 @@ language**, and **agent attribution** — each have a contract below. `SKILL.md`
|
|
|
5
5
|
main procedure stays lean; load this file when you need the full rule for a contract (e.g. while
|
|
6
6
|
filling the matching `AGENTS.md` block, or when an `upgrade` migration touches it).
|
|
7
7
|
|
|
8
|
-
Ask
|
|
9
|
-
in Claude Code
|
|
8
|
+
Ask the three as **ONE structured multi-question prompt where your agent supports it**
|
|
9
|
+
(`AskUserQuestion` in Claude Code, up to 4 questions per call), otherwise in prose; record each
|
|
10
|
+
answer individually — and write nothing until ALL are answered.
|
|
10
11
|
|
|
11
12
|
---
|
|
12
13
|
|
|
@@ -4,7 +4,7 @@ Requires: ${CLAUDE_SKILL_DIR}/references/shared/report-footer.md · ${CLAUDE_SKI
|
|
|
4
4
|
|
|
5
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
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
|
|
7
|
+
> The three setup questions (steps 2–4) are decisions only the user can make and are hard to reverse after a commit. Ask them as **ONE structured multi-question prompt where your agent supports it** (`AskUserQuestion` in Claude Code — up to 4 questions per call, one option per choice, recommended one first), otherwise in prose; **record each answer individually** — and **write nothing until ALL are answered**.
|
|
8
8
|
|
|
9
9
|
1. **Recon (read-only).** Before writing anything:
|
|
10
10
|
- `package.json` / `pyproject.toml` / `go.mod` / `Cargo.toml` → stack, package manager, scripts.
|
|
@@ -13,10 +13,10 @@ Requires: ${CLAUDE_SKILL_DIR}/references/shared/report-footer.md · ${CLAUDE_SKI
|
|
|
13
13
|
- `src/` (or equivalent) 2–3 levels deep → modules, routes/pages, components, services, types.
|
|
14
14
|
- Tests (framework, location, E2E?) and linter rules.
|
|
15
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
|
|
17
|
-
2. **Choose visibility —
|
|
18
|
-
3. **Choose conversational language —
|
|
19
|
-
4. **Choose agent attribution —
|
|
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 three setup questions (the step-2 batched prompt).
|
|
17
|
+
2. **Choose visibility — ask the batched prompt NOW (all three questions, per the preamble above) and wait until every answer is in.** 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 — answered in the step-2 batch.** 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 — answered in the step-2 batch.** 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
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
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
22
|
7. **Fill templates** per the table below.
|
|
@@ -36,7 +36,12 @@ Requires: ${CLAUDE_SKILL_DIR}/references/shared/report-footer.md · ${CLAUDE_SKI
|
|
|
36
36
|
independent axes: a packaging-only release bumps the package but leaves the lineage head until a
|
|
37
37
|
migration actually changes the deployed `docs/ai` structure. A stamp greater than the head →
|
|
38
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
|
|
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 closes on **one** caveat-aware next step (a behind member first, else `setup` / `recipes` / `velocity` / `agents` / `hook`). **After the footer, present ONE compact optional-accelerators block** — every entry preview-first, a one-line why each, nothing runs without a yes:
|
|
40
|
+
- `/agent-workflow-kit velocity` — routine read-only commands stop prompting (incl. the `--kit-tools` tier for the kit's own read-only tools; `${CLAUDE_SKILL_DIR}/references/modes/velocity.md`);
|
|
41
|
+
- `/agent-workflow-kit agents` — cheap-model subagents take the mechanical work (sweeps, changelog skeletons, gate triage; `${CLAUDE_SKILL_DIR}/references/modes/agents.md`);
|
|
42
|
+
- **gates seeding + hook** — offer to seed `docs/ai/gates.json` from the commands recon already recorded (step 1), via the consent-gated preview in `${CLAUDE_SKILL_DIR}/references/modes/gates.md` — this block is where that offer fires; then, once gates are declared, `/agent-workflow-kit hook` auto-approves exactly those declared commands (`${CLAUDE_SKILL_DIR}/references/modes/hook.md`);
|
|
43
|
+
- `/agent-workflow-kit set-recipe` — put a ready review backend to work on plans and diffs (`${CLAUDE_SKILL_DIR}/references/modes/set-recipe.md`).
|
|
44
|
+
Then **ask before committing** — never auto-commit.
|
|
40
45
|
|
|
41
46
|
Fill strategy:
|
|
42
47
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
### Mode: bridge-settings
|
|
2
|
+
|
|
3
|
+
The reader + consent-gated **writer** for the **host-level** bridge settings file — the answer to *"turn on the codex Fast tier (or another bridge knob) once, predictably, so it survives kit upgrades."* The four bridge wrappers read `${XDG_CONFIG_HOME:-~/.config}/agent-workflow/bridge-settings.conf` (`KEY=VALUE` lines, **parsed never sourced**); this is the ONLY writer for it. The file lives **outside every kit-managed tree**, so a kit refresh never writes or clobbers it — upgrade-survival is structural (D2). It **previews by default**; `--apply` writes. Hand-editing the file stays fully supported — this is an offered convenience, never a lock.
|
|
4
|
+
|
|
5
|
+
**The knobs are the bundled bridges' own `settings` blocks** (manifest-as-source, D6) — the tool never invents a key or a value rule, and what it writes always passes the wrappers' own validation. Model/effort are **NOT** settable here (the wrappers' quality-first guard is untouched, D4). Run **`node ${CLAUDE_SKILL_DIR}/tools/bridge-settings.mjs`** to see the live list; today:
|
|
6
|
+
|
|
7
|
+
| key | bridge | values | note |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| `CODEX_SERVICE_TIER` | codex | `priority` | **SPEND KNOB** — the "Fast" tier: ~1.5× token speed at a **2.5× credit rate** on gpt-5.5, quality-neutral (same model). Default unset ⇒ standard tier. |
|
|
10
|
+
| `CODEX_HARD_TIMEOUT` | codex | integer `1..86400` | hard wall-clock cap (seconds) via `timeout(1)`. |
|
|
11
|
+
| `CODEX_REVIEW_MAX_TOTAL_BYTES` | codex | integer `1..100000000` | codex-review payload size above which the diff rides a temp file (never truncated). |
|
|
12
|
+
| `AGY_HARD_TIMEOUT` | agy | duration `5m`/`30m`/`90s` (unit required, nonzero) | hard wall-clock cap via `timeout(1)`. |
|
|
13
|
+
| `AGY_REVIEW_ALLOW_ADDDIR` | agy | `0` \| `1` | `1` re-enables the oversized-review `--add-dir` offload (Issue-001 stall risk, bounded by the timeout). |
|
|
14
|
+
|
|
15
|
+
**Invocations:**
|
|
16
|
+
|
|
17
|
+
1. **Read** — `node ${CLAUDE_SKILL_DIR}/tools/bridge-settings.mjs [--json]` prints every knob's **effective value + source** (`env` / `file` / `default`) and flags any unknown/duplicate/malformed lines. Read-only.
|
|
18
|
+
2. **Preview a change** — `--set KEY=VALUE` (or `--unset KEY`) prints `before → after` and writes **nothing**. Re-run with **`--apply`** to write. Multiple `--set`/`--unset` ops apply in one atomic write.
|
|
19
|
+
3. **`--apply`** writes via the hardened out-of-tree atomic writer (creates the dir + file on first use; symlink/parent/TOCTOU-safe; last-writer-wins). It touches **only** the `KEY=` line it owns — every comment / blank / other line is preserved verbatim.
|
|
20
|
+
|
|
21
|
+
**Precedence at run time:** explicit env (even empty — `KEY=` disables the knob for one run) **>** this file **>** the wrapper's built-in default. So an operator can always override one run without editing the file; the reader shows which source wins.
|
|
22
|
+
|
|
23
|
+
**Refusals (the guarded contract):** an **unknown key** or an **invalid / out-of-range value** → exit `2` (nothing read of the file, nothing written). A file that already carries **duplicate keys** → exit `1`, named and left **byte-untouched** (fix the duplicates by hand first — the writer never edits blindly around them). A **symlinked / non-regular / unreadable** settings file → exit `1` (refuses to write through it). `--apply` with `--dry-run`, a duplicate op for one key, or a malformed `--set` → usage exit `2`.
|
|
24
|
+
|
|
25
|
+
**Spend consent (D4):** enabling `CODEX_SERVICE_TIER=priority` costs a **2.5× credit rate** — a per-host, consented act, never a default. The preview shows the caveat (from the manifest `effect`); confirm with the user before `--apply`. The tool also warns when an env var currently shadows the key you are writing (the env value wins for that session until unset).
|
|
26
|
+
|
|
27
|
+
Output is **English/structured** — **localize it to the user's conversational language** when you narrate.
|
|
28
|
+
|
|
29
|
+
**Invariants:** writer (writes only the host settings file — outside any project/kit tree) · never commits · never runs a subscription CLI · previews by default · allowlist + value rules from the bundled manifests · model/effort never settable · the host file survives every kit refresh.
|
|
@@ -12,6 +12,8 @@ The declaration is **seeded at bootstrap** (the template loop, `${CLAUDE_SKILL_D
|
|
|
12
12
|
|
|
13
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
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
|
|
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, or through the consent-gated seeder below (AD-042).
|
|
16
16
|
|
|
17
|
-
**
|
|
17
|
+
**Consent-gated seeding — a separate WRITER CLI, not part of the runner (AD-042).** Bootstrap recon already records the project's own daily commands; the seeder turns them into a preview of `{ id, title, cmd }` entries. Protocol: run `node ${CLAUDE_SKILL_DIR}/tools/seed-gates.mjs --cwd <project>` (dry-run by default — prints the derived entries and **writes NOTHING**; declining leaves the file byte-identical), show the user the EXACT entries (`AskUserQuestion` preview where supported, prose otherwise), and only on an explicit yes run it again with `--apply [--only <id>]…` — it **appends exactly the consented entries** (append-only: existing entries are never modified or removed; an id collision is refused loudly; a malformed declaration is never written over). Only terminating verification commands are offered (test / lint / type-check / build — never dev/watch/serve, never a formatter write-mode, never a release/publish/deploy script), commands are package-manager-aware, and the review-state candidate above is included automatically when the project's orchestration config declares reviewed/council on `plan-execution.review`. **Disclose before the yes** (the preview prints it): once the approval hook is wired, it auto-approves byte-exact declared gate commands — seeding and hook wiring are two separate consents.
|
|
18
|
+
|
|
19
|
+
**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 · the seeder is a separate consent-per-run CLI — preview-first, append-only, never pre-approved by any velocity tier.
|
|
@@ -6,7 +6,7 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/review-state.mjs [--check] [--json]`:
|
|
|
6
6
|
|
|
7
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
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
|
|
9
|
+
3. **Wire it as a gate by hand OR via the explicit-consent seeder — never without consent (AD-021/AD-042).** 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, QUOTED so a path with spaces survives, executable from the project root. The consent-gated seeder (`${CLAUDE_SKILL_DIR}/references/modes/gates.md`, consent-seed section) offers exactly this entry — path resolved and quoted — ONLY when your `docs/ai/orchestration.json` declares `reviewed`/`council` on `plan-execution.review` (the slot this checker enforces); it writes nothing without your explicit yes. Once declared, the opt-in `${CLAUDE_SKILL_DIR}/references/modes/hook.md` auto-approves it like any other declared gate.
|
|
10
10
|
|
|
11
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
12
|
|
|
@@ -14,6 +14,8 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/family-registry.mjs --json [--dir <project>]
|
|
|
14
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
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
16
|
- **velocity** — the effective `permissions.defaultMode` + whether an allowlist is seeded (detail → `/agent-workflow-kit velocity`).
|
|
17
|
+
- **cheap agents** — how many of the kit's cheap-lane subagent vehicles are placed (`agents.placed` of `agents.bundled`; zero placed → the optional `/agent-workflow-kit agents` opt-in).
|
|
18
|
+
- **gate hook** — wired / hook file placed / declaration present, plus **`hook.declaredGates`** (0 = absent or an empty list; `null` = present but unreadable → say *couldn't be counted*, never a number; detail → `/agent-workflow-kit hook` and the gates guide).
|
|
17
19
|
- Any area's **`error`** field → surface it **loudly** in plain language; the rest of `status` still renders (never a crash).
|
|
18
20
|
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
21
|
|
|
@@ -45,12 +45,18 @@ Requires: ${CLAUDE_SKILL_DIR}/references/shared/report-footer.md · ${CLAUDE_SKI
|
|
|
45
45
|
file's line cap — refused** (trim the file, re-run). The section is found by its heading — no
|
|
46
46
|
markers; a renamed heading is preserved + noted. A fully absent/invalid engine is the same hard
|
|
47
47
|
STOP as (c). Exit 0 covers every soft outcome; only the STOP is non-zero.
|
|
48
|
+
|
|
49
|
+
**Bridge settings reconcile — stamp-independent, same gate, BEFORE the equal-head short-circuit.**
|
|
50
|
+
Run `node ${CLAUDE_SKILL_DIR}/tools/bridge-settings.mjs --reconcile` and **paste its outcome line
|
|
51
|
+
verbatim**: it validates the deployed host settings file's keys against the bundled manifests and
|
|
52
|
+
**NEVER writes** it (the file lives outside every kit tree — D2), so an unknown/retired key is
|
|
53
|
+
flagged + preserved, never edited. Runs on **every** upgrade; exit 0 covers every outcome.
|
|
48
54
|
4. **Equal-head exit — a real successful-exit report, not a bare stop.** If the stamp **equals** the head, the lineage is up to date — but step 3 (the stamp-independent reconciles) ran first and may have changed things, so this is a proper exit report, not a no-op:
|
|
49
|
-
- **Report step 3's outcome in plain language** — for **each** pointer (workflow-methodology and orchestration-recipes) whether it was *added*, was *already present* (nothing changed), or was *skipped because the entry point is over its line limit* (the cap-refusal soft-skip from step 3, with its reason); whether the `docs/ai/orchestration.json` config was *seeded* (created from the template), had its onboarding note *refreshed*, was *already current*, or carried a *customized note that was preserved* (a user edit is never clobbered); whether the `docs/ai/gates.json` gate declaration was *seeded* or was *already present* (preserved byte-for-byte); whether the enforcement-script ensure *added* the `archive-decisions` pair to `scripts/` or found it *already present*; the **placed-bridge refresh** outcome — paste the tool's per-bridge lines verbatim (they are already plain: *refreshed* / *already current* / *skipped — not placed* / *could not refresh* + recovery); the **agent-rules lens** outcome (*refreshed* / *already current* / *custom edit preserved + note* / *file absent* / *engine too old* / *over the line cap*); and, for a hidden deployment, whether the hidden-mode footprint was *moved to project-local*, was *already project-local* (nothing changed), or needed a question (ambiguous visibility / a leftover machine-wide block). Plain wording only — never the reconcile/slot/anchor/marker terms (the never-leak-kit-internals Gotcha — `${CLAUDE_SKILL_DIR}/references/shared/deploy-tail.md`).
|
|
55
|
+
- **Report step 3's outcome in plain language** — for **each** pointer (workflow-methodology and orchestration-recipes) whether it was *added*, was *already present* (nothing changed), or was *skipped because the entry point is over its line limit* (the cap-refusal soft-skip from step 3, with its reason); whether the `docs/ai/orchestration.json` config was *seeded* (created from the template), had its onboarding note *refreshed*, was *already current*, or carried a *customized note that was preserved* (a user edit is never clobbered); whether the `docs/ai/gates.json` gate declaration was *seeded* or was *already present* (preserved byte-for-byte); whether the enforcement-script ensure *added* the `archive-decisions` pair to `scripts/` or found it *already present*; the **placed-bridge refresh** outcome — paste the tool's per-bridge lines verbatim (they are already plain: *refreshed* / *already current* / *skipped — not placed* / *could not refresh* + recovery); the **agent-rules lens** outcome (*refreshed* / *already current* / *custom edit preserved + note* / *file absent* / *engine too old* / *over the line cap*); the **bridge-settings reconcile** outcome (paste the tool's line verbatim); and, for a hidden deployment, whether the hidden-mode footprint was *moved to project-local*, was *already project-local* (nothing changed), or needed a question (ambiguous visibility / a leftover machine-wide block). Plain wording only — never the reconcile/slot/anchor/marker terms (the never-leak-kit-internals Gotcha — `${CLAUDE_SKILL_DIR}/references/shared/deploy-tail.md`).
|
|
50
56
|
- **Never surface the structure number on this exit.** Whatever step 3 did, do **not** recite the `docs/ai` structure version, the internal versioning vocabulary, or the two-axes note here — the number is inert on an equal-head exit; it belongs to *Version disclosure* in `${CLAUDE_SKILL_DIR}/references/shared/report-footer.md` (shown at the never-downgrade STOP, the explicit status view, or on an explicit ask). Frame the success itself per the final bullet: if step 3 changed anything, say **what changed** in plain human terms; only a pure zero-diff no-op is *settings already current — no update needed*.
|
|
51
|
-
- **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 closes on **one** caveat-aware next step (a behind member first, else `setup` / `recipes` / `velocity`).
|
|
57
|
+
- **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 closes on **one** caveat-aware next step (a behind member first, else `setup` / `recipes` / `velocity` / `agents` / `hook`).
|
|
52
58
|
- **Then ask before committing — never auto-commit.** If step 3 added the slot (or anything else changed), report it and ask. If step 3 was a pure zero-diff no-op and nothing else changed, give the plain **settings already current — no update needed** message (the *Success state* contract in `${CLAUDE_SKILL_DIR}/references/shared/report-footer.md`) and still print the read-only version block (installed package versions) + backend line — but **no `docs/ai` structure version and no two-axes note** (nothing changed, so the number is inert here).
|
|
53
59
|
5. Show the relevant `${CLAUDE_SKILL_DIR}/CHANGELOG.md` diff (entries newer than the project's stamp).
|
|
54
|
-
6.
|
|
55
|
-
7. Reconcile drift: add any kernel files/scripts the project is missing; never clobber project-authored content (their `decisions.md`, `known_issues.md`, page specs stay). Any user question a migration raises follows the same rule as bootstrap — **structured multiple-choice where supported** (`AskUserQuestion` in Claude Code), otherwise prose. If `AGENTS.md` has no *Communication language* block (pre-1.1.0 deployment), **ask the user their conversational language** and insert the block — see `migrations/1.1.0-communication-language.md`. If it has no *Attribution* block (pre-1.2.0 deployment), **ask whether the agent may attribute work to itself / AI** and insert the block (defaulting to `off`) — see `migrations/1.2.0-agent-attribution.md`.
|
|
56
|
-
8. Re-stamp `docs/ai/.workflow-version` to the **deployment-lineage head** (`1.3.0`, not the package version — mechanics unchanged: the atomic write to the stamp file). In the report, **describe what the upgrade changed in plain human terms** — which parts of their `docs/ai` are now different (the migrations that ran), plus the step-3 **placed-bridge refresh** lines (pasted verbatim)
|
|
60
|
+
6. **Collect the migration answers FIRST, then apply.** If `AGENTS.md` is missing BOTH the *Communication language* and *Attribution* blocks — i.e. both blocks are missing (a pre-1.1.0 deployment) — ask the two questions as ONE structured multi-question prompt; record each answer individually, write nothing until ALL are answered, and carry the answers into the migrations below: a migration whose answer was already collected never re-asks (its own "Ask the user" step is the standalone fallback); a single missing block keeps its single ask (step 7). Then apply `${CLAUDE_SKILL_DIR}/migrations/<version>-<slug>.md` in **semver order**, only those newer than the project's stamp. Migrations are **idempotent** — safe to re-run.
|
|
61
|
+
7. Reconcile drift: add any kernel files/scripts the project is missing; never clobber project-authored content (their `decisions.md`, `known_issues.md`, page specs stay). Any user question a migration raises follows the same rule as bootstrap — **structured multiple-choice where supported** (`AskUserQuestion` in Claude Code), otherwise prose. If `AGENTS.md` has no *Communication language* block (pre-1.1.0 deployment), **ask the user their conversational language** and insert the block — see `migrations/1.1.0-communication-language.md`. If it has no *Attribution* block (pre-1.2.0 deployment), **ask whether the agent may attribute work to itself / AI** and insert the block (defaulting to `off`) — see `migrations/1.2.0-agent-attribution.md`. (An answer already collected by the step-6 batched prompt is carried in — never re-asked here.)
|
|
62
|
+
8. Re-stamp `docs/ai/.workflow-version` to the **deployment-lineage head** (`1.3.0`, not the package version — mechanics unchanged: the atomic write to the stamp file). In the report, **describe what the upgrade changed in plain human terms** — which parts of their `docs/ai` are now different (the migrations that ran), plus the step-3 **placed-bridge refresh** lines (pasted verbatim), the step-3 **agent-rules lens** outcome (same outcome set as step 4), and the step-3 **bridge-settings reconcile** outcome — rather than reciting a version number; **omit the raw structure number**, and do **not** print the two-axes note here (it belongs to *Version disclosure* in `${CLAUDE_SKILL_DIR}/references/shared/report-footer.md`, on demand only). 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 closes on one caveat-aware next step). Then **ask before committing**.
|
|
@@ -19,7 +19,7 @@ The non-obvious traps — scan these before bootstrapping or upgrading. Each is
|
|
|
19
19
|
|
|
20
20
|
## Setup contracts
|
|
21
21
|
|
|
22
|
-
The three setup choices — **visibility** (step 2), **conversational language** (step 3), and **agent attribution** (step 4) — each have a full contract in [`references/contracts.md`](${CLAUDE_SKILL_DIR}/references/contracts.md). Load it when you need the complete rule (e.g. while filling the matching `AGENTS.md` block, or when an `upgrade` migration touches one). Defaults, in brief: visibility = `visible` (committed); language = whatever the user is already writing in; attribution = `off`. Ask
|
|
22
|
+
The three setup choices — **visibility** (step 2), **conversational language** (step 3), and **agent attribution** (step 4) — each have a full contract in [`references/contracts.md`](${CLAUDE_SKILL_DIR}/references/contracts.md). Load it when you need the complete rule (e.g. while filling the matching `AGENTS.md` block, or when an `upgrade` migration touches one). Defaults, in brief: visibility = `visible` (committed); language = whatever the user is already writing in; attribution = `off`. Ask the three as ONE structured multi-question prompt where supported (`AskUserQuestion` in Claude Code, up to 4 questions per call), otherwise in prose; record each answer individually — and write nothing until ALL are answered.
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
@@ -74,8 +74,9 @@ the rest of the report — and the commit gate — proceeds.
|
|
|
74
74
|
|
|
75
75
|
**Welcome mat — the last line(s) of the footer.** After the version block and the backend-status
|
|
76
76
|
line, print *"Run `/agent-workflow-kit help` to see every command."* then **one** recommended next
|
|
77
|
-
step, chosen **caveat-aware** from signals already in hand (the version block's notes
|
|
78
|
-
backend-status line — no new helper call) in this
|
|
77
|
+
step, chosen **caveat-aware** from signals already in hand (the version block's notes, the settings
|
|
78
|
+
areas of the same `--json` envelope, and the backend-status line — no new helper call) in this
|
|
79
|
+
priority order:
|
|
79
80
|
1. a member is **behind** (a behind-class `installed[].notes` caveat fired — any member, the bridges
|
|
80
81
|
included) → *refresh the behind member first*, quoting **that note's own recovery command
|
|
81
82
|
verbatim** (a memory/engine note carries its `npx …@latest init` + restart the session; a bridge
|
|
@@ -87,8 +88,14 @@ backend-status line — no new helper call) in this priority order:
|
|
|
87
88
|
3. else **a backend is ready but the orchestration config is still all-Solo** (no `reviewed` /
|
|
88
89
|
`council` / `delegated` slot anywhere — inspect `docs/ai/orchestration.json`, or read the
|
|
89
90
|
procedures advisor's resolved recipes) → *put it to work with `/agent-workflow-kit recipes`*;
|
|
90
|
-
4. else
|
|
91
|
-
*`/agent-workflow-kit velocity`* opt-in (never run it without a
|
|
91
|
+
4. else **the velocity allowlist is not yet seeded** (the envelope's velocity settings show zero
|
|
92
|
+
allow entries) → the optional *`/agent-workflow-kit velocity`* opt-in (never run it without a
|
|
93
|
+
yes);
|
|
94
|
+
5. else **the cheap-lane agent vehicles are not placed** (the envelope's agents settings show zero
|
|
95
|
+
placed) → the optional *`/agent-workflow-kit agents`* opt-in (never run it without a yes);
|
|
96
|
+
6. else **gates are declared but the approval hook is not wired** (the envelope's hook settings:
|
|
97
|
+
at least one declared gate, wired = no) → the optional *`/agent-workflow-kit hook`* opt-in
|
|
98
|
+
(never run it without a yes). If no rung applies, the help line above stands alone.
|
|
92
99
|
|
|
93
100
|
Keep it compact — a few short lines, plain language, no kit-internal terms.
|
|
94
101
|
|