@hybridlabor-api/aos 4.7.0 → 4.7.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.
Files changed (34) hide show
  1. package/.agents/agents.md +8 -3
  2. package/.agents/nodes.json +2 -1
  3. package/.agents/state.schema.json +24 -0
  4. package/.agents/vendor-manifest.json +6 -0
  5. package/.agents/workflows/startcycle-graph.md +2 -2
  6. package/.claude/agents/architect.md +5 -4
  7. package/.claude/agents/techlead.md +2 -0
  8. package/.claude/workflows/startcycle-dispatch.mjs +175 -17
  9. package/.opencode/agents/architect.md +5 -4
  10. package/.opencode/agents/techlead.md +2 -0
  11. package/THIRD_PARTY_NOTICES.md +9 -1
  12. package/bin/aos-doctor.mjs +366 -0
  13. package/bin/aos-store.mjs +167 -0
  14. package/docs/AUDIT_BRIEF_ECC_STORE.md +122 -0
  15. package/docs/PLAN_AOS_STORE_PHASE1.md +190 -0
  16. package/installer.js +41 -1
  17. package/lib/aos-archify-contract.mjs +277 -0
  18. package/lib/ecc-store-index.json +1 -0
  19. package/mcp_config.json +4 -0
  20. package/mcps/mcsc/packages/core/src/adapters/codex.js +160 -37
  21. package/package.json +6 -2
  22. package/scripts/build-ecc-store-index.mjs +147 -0
  23. package/skills/basic/startcycle-graph/SKILL.md +13 -0
  24. package/skills/global_config/agenttrail/bin/agenttrail.mjs +153 -42
  25. package/skills/global_config/agenttrail/public/index.html +5 -4
  26. package/skills/global_config/archify/examples/dataflow-product-analytics.html +15048 -0
  27. package/skills/global_config/archify/examples/lifecycle-agent-run.html +14983 -0
  28. package/skills/global_config/archify/examples/sequence-cache-miss-request.html +15063 -0
  29. package/skills/global_config/archify/examples/web-app-rendered.html +15012 -0
  30. package/skills/global_config/archify/examples/workflow-agent-tool-call-rendered.html +15054 -0
  31. package/skills/global_config/ask-tim/SKILL.md +10 -0
  32. package/skills/global_config/mcsc/SKILL.md +60 -0
  33. package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/server.js +31 -6
  34. package/skills/global_config/plan-canvas/scripts/plan-canvas.js +4 -2
package/.agents/agents.md CHANGED
@@ -21,8 +21,12 @@ next. This file defines *what each agent is*, not *what calls what*.
21
21
  - **MCP Servers**:
22
22
  - `openwiki-skill`
23
23
  - `memb_mcp`
24
- - **Output Artifact**: `production_artifacts/00_execution_plan.md`
25
- - **Reads**: `state.goal` · **Writes**: `state.artifacts.plan`, `state.phase: plan`
24
+ - **Output Artifacts**: `production_artifacts/00_execution_plan.md`, `production_artifacts/00_architecture.json` (editable Archify specification), `production_artifacts/00_architecture.html` (read-only `archify deliver` artifact)
25
+ - **Reads**: `state.goal` · **Writes**: `state.artifacts.plan`, `state.artifacts.architecture`, `state.phase: plan`
26
+ - The plan uses the agenttrail component convention (`## Name {#id}`, `needs:`, `files:`, tasks `- [ ] ... {#id}`).
27
+ - The Architect authors the architecture as Archify `architecture` JSON to `production_artifacts/00_architecture.json`, runs `aos-archify validate architecture <spec> --quality showcase --json` during repair and `aos-archify deliver architecture <spec> production_artifacts/00_architecture.html --quality showcase --json` once for final acceptance, and records `state.artifacts.architecture` only on a passing showcase receipt (9/9 checks, 0 errors). A failed validate/deliver preserves the previous HTML and escalates at the Architect→TechLead boundary instead of proceeding silently.
28
+ - The relevant plan component links the delivered diagram with a `url: production_artifacts/00_architecture.html` line so the live map opens it from the card.
29
+ - Plan-canvas reviews that HTML too via the existing path as fixed argv `aos-plan-canvas open production_artifacts/00_architecture.html --no-open` with `shell: false` from the repo root (no new port, single open, no shell interpolation). A missing or unavailable canvas never invalidates the verified architecture; the `url:` line and the `aos-trail . --plan production_artifacts/00_execution_plan.md --no-open` map stay authoritative.
26
30
 
27
31
  ---
28
32
 
@@ -36,7 +40,8 @@ next. This file defines *what each agent is*, not *what calls what*.
36
40
  - **MCP Servers**:
37
41
  - `memb_mcp`
38
42
  - **Output Artifact**: capability-map approval recorded in `state.json` (no separate markdown file — this is a gate, not a deliverable)
39
- - **Reads**: `state.artifacts.plan` · **Writes**: plan-approval decision, `state.phase: build` (or back to `plan`)
43
+ - **Reads**: `state.artifacts.plan`, `state.artifacts.architecture` · **Writes**: plan-approval decision, `state.phase: build` (or back to `plan`)
44
+ - TechLead rejects the plan when the architecture gate fails: `production_artifacts/00_architecture.json` and `production_artifacts/00_architecture.html` are missing, the `url: production_artifacts/00_architecture.html` link is absent from the plan, or the deliver receipt is not a passing showcase receipt (9/9 checks, 0 errors). A failed receipt preserves the previous HTML and sends the run back to Architect.
40
45
 
41
46
  ---
42
47
 
@@ -14,7 +14,8 @@
14
14
  "skills": [
15
15
  "bdbrainstorm",
16
16
  "planning-with-files",
17
- "concise-planning"
17
+ "concise-planning",
18
+ "archify"
18
19
  ],
19
20
  "instructions": null
20
21
  },
@@ -24,6 +24,7 @@
24
24
  "description": "Paths to the human-readable markdown artifacts nodes produce. state.json is what edges evaluate; these stay the readable payload. Known keys are documented below; additionalProperties stays a typed string-or-null (not fully open) so a registry-driven build domain beyond these can validate without making this object permissive to arbitrary JSON.",
25
25
  "properties": {
26
26
  "plan": { "type": ["string", "null"] },
27
+ "architecture": { "type": ["string", "null"] },
27
28
  "frontend": { "type": ["string", "null"] },
28
29
  "backend": { "type": ["string", "null"] },
29
30
  "media": { "type": ["string", "null"] },
@@ -96,6 +97,29 @@
96
97
  "default": [],
97
98
  "description": "Skill names the user required via /startcycle-graph's --skill=<name> flag (repeatable), validated to exist before the run proceeds. Empty when the user didn't ask for one. Build nodes (and Architect) are told to actually apply these, not just have them available; Reviewer checks the resulting artifacts for evidence they were used and flags a contract-misread finding if not. See .agents/graph.md's 'Mandatory Skill Injection' section."
98
99
  },
100
+ "pipeline": {
101
+ "type": "string",
102
+ "description": "AO scaffold metadata: which pipeline bootstrapped this run, e.g. startcycle-graph."
103
+ },
104
+ "planCanvasRequired": {
105
+ "type": "boolean",
106
+ "description": "AO scaffold metadata: whether the plan-canvas review is required before build."
107
+ },
108
+ "roles": {
109
+ "type": "object",
110
+ "description": "AO scaffold metadata: per-role enablement flags.",
111
+ "additionalProperties": { "type": "boolean" }
112
+ },
113
+ "models": {
114
+ "type": "object",
115
+ "description": "AO scaffold metadata: per-role model routing labels.",
116
+ "additionalProperties": { "type": "string" }
117
+ },
118
+ "harnesses": {
119
+ "type": "object",
120
+ "description": "AO scaffold metadata: per-role harness assignments.",
121
+ "additionalProperties": { "type": "string" }
122
+ },
99
123
  "needs_human": {
100
124
  "type": "boolean",
101
125
  "default": false,
@@ -45,6 +45,12 @@
45
45
  "pinned_commit": "739512a8588b28ff3b554e669391c22508602878",
46
46
  "purpose": "Defensive audit heuristics and vulnerability checklists (offensive exploits stripped)",
47
47
  "target_skill": "bdb-security-audit, security-reviewer"
48
+ },
49
+ "ecc-store": {
50
+ "upstream": "https://github.com/affaan-m/ECC",
51
+ "pinned_commit": "e482e579415fde18357cafce70f177ae19fd7f03",
52
+ "purpose": "Markdown-only fallback store for skills and auxiliary subagents",
53
+ "target": "lib/ecc-store-index.json"
48
54
  }
49
55
  }
50
56
  }
@@ -58,8 +58,8 @@ agents calling agents; see `audit-agents.md` F-17 for why that's corrected.
58
58
 
59
59
  | Node | Role | Reads | Writes |
60
60
  |---|---|---|---|
61
- | **Architect** | Turns the goal into a system plan | `state.goal` | `state.artifacts.plan` |
62
- | **TechLead** | Approves/rejects the plan's capability map | `state.artifacts.plan` | plan approval, `state.phase` |
61
+ | **Architect** | Turns the goal into a system plan | `state.goal` | `state.artifacts.plan`, `state.artifacts.architecture` (`production_artifacts/00_architecture.json` + `production_artifacts/00_architecture.html` via `aos-archify deliver`, linked with a `url:` line) |
62
+ | **TechLead** | Approves/rejects the plan's capability map | `state.artifacts.plan` | plan approval, `state.phase` (rejects on a failed architecture gate: missing spec/HTML, missing `url:` link, or no passing showcase receipt) |
63
63
  | **Godmode_UI_UX** | Frontend implementation | plan, own findings | `state.artifacts.frontend` |
64
64
  | **Godmode_Engineering** | Backend implementation | plan, own findings | `state.artifacts.backend` |
65
65
  | **Godmode_Media_EventTech** | Media/show-control implementation (if the goal needs it) | plan, own findings | `state.artifacts.media` |
@@ -5,12 +5,13 @@ model: opus
5
5
  ---
6
6
  Turns the user's goal (or `/bdbrainstorm` / `/grill-me` output) into a system plan. Reads existing architecture before proposing changes. Does not coordinate execution or invoke other agents — that is TechLead's job, decided by the dispatcher, not by Architect.
7
7
 
8
- **Primary skills:** bdbrainstorm, planning-with-files, concise-planning
8
+ **Primary skills:** bdbrainstorm, planning-with-files, concise-planning, archify
9
9
 
10
10
  **MCP servers used:** openwiki-skill, memb_mcp
11
11
 
12
- **Output artifact(s):** `production_artifacts/00_execution_plan.md`
12
+ **Output artifact(s):** `production_artifacts/00_execution_plan.md`, `production_artifacts/00_architecture.json`, `production_artifacts/00_architecture.html`
13
13
 
14
14
  - The plan uses the agenttrail component convention (`## Name {#id}`, `needs:`, `files:`, tasks `- [ ] ... {#id}`).
15
- - The Architect renders the architecture with `aos-archify` to `production_artifacts/00_architecture.html` and links it from the relevant component with a `url:` line.
16
- - Plan-canvas can review that HTML too.
15
+ - The Architect authors the architecture as Archify `architecture` JSON to `production_artifacts/00_architecture.json`, runs `aos-archify validate architecture <spec> --quality showcase --json` during repair and `aos-archify deliver architecture <spec> production_artifacts/00_architecture.html --quality showcase --json` once for final acceptance, and records `state.artifacts.architecture` only on a passing showcase receipt (9/9 checks, 0 errors). A failed validate/deliver preserves the previous HTML and escalates at the Architect→TechLead boundary.
16
+ - The relevant plan component links the delivered diagram with a `url: production_artifacts/00_architecture.html` line so the live map opens it from the card.
17
+ - Plan-canvas reviews that HTML too via the existing path as fixed argv `aos-plan-canvas open production_artifacts/00_architecture.html --no-open` with `shell: false` from the repo root (no new port, single open, no shell interpolation). A missing or unavailable canvas never invalidates the verified architecture; the `url:` line and the `aos-trail . --plan production_artifacts/00_execution_plan.md --no-open` map stay authoritative.
@@ -10,3 +10,5 @@ Reviews Architect's plan for a capability map (module boundaries, dependency dir
10
10
  **MCP servers used:** memb_mcp
11
11
 
12
12
  **Output artifact(s):** capability-map approval recorded in `state.json` (no separate markdown file — this is a gate, not a deliverable)
13
+
14
+ - TechLead rejects the plan when the architecture gate fails: `production_artifacts/00_architecture.json` and `production_artifacts/00_architecture.html` are missing, the `url: production_artifacts/00_architecture.html` link is absent from the plan, or the deliver receipt is not a passing showcase receipt (9/9 checks, 0 errors). A failed receipt preserves the previous HTML and sends the run back to Architect.
@@ -92,6 +92,21 @@ if (!fs && typeof process !== 'undefined') {
92
92
  } catch {}
93
93
  }
94
94
 
95
+ let archifyContractPromise;
96
+ async function loadArchifyContract() {
97
+ if (!archifyContractPromise) {
98
+ archifyContractPromise = (async () => {
99
+ if (typeof process === 'undefined') return null;
100
+ try {
101
+ return await import(new URL('../../lib/aos-archify-contract.mjs', import.meta.url).href);
102
+ } catch {
103
+ return null;
104
+ }
105
+ })();
106
+ }
107
+ return archifyContractPromise;
108
+ }
109
+
95
110
  function readStdinSync() {
96
111
  const chunks = [];
97
112
  const buffer = Buffer.alloc(64 * 1024);
@@ -346,12 +361,54 @@ if (typeof globalThis.agent === 'undefined') {
346
361
  return { phase: 'escalated' };
347
362
  }
348
363
 
364
+ if (label.startsWith('archify-verify')) {
365
+ const failVerify = (error) => ({ validateOk: false, deliverOk: false, checksPassed: 0, checkCount: 9, error: String(error).slice(0, 400) });
366
+ if (!fs || !path || !child_process) return failVerify('archify verify has no process runtime in this environment');
367
+ const contract = await loadArchifyContract();
368
+ if (!contract || typeof contract.runArchifyBoundary !== 'function') return failVerify('archify contract unavailable');
369
+ const repoRoot = process.cwd();
370
+ const spec = contract.ARCHITECTURE_SPEC_PATH;
371
+ const html = contract.ARCHITECTURE_HTML_PATH;
372
+ const localBin = typeof contract.resolveArchifyBin === 'function' ? contract.resolveArchifyBin(repoRoot) : null;
373
+ const run = (args, options) => child_process.spawnSync(
374
+ localBin ? process.execPath : 'aos-archify',
375
+ [...(localBin ? [localBin] : []), ...args],
376
+ {
377
+ cwd: options.cwd,
378
+ encoding: 'utf8',
379
+ timeout: options.timeoutMs,
380
+ maxBuffer: options.maxBuffer,
381
+ shell: false,
382
+ }
383
+ );
384
+ try {
385
+ const result = await contract.runArchifyBoundary({
386
+ bin: localBin,
387
+ cwd: repoRoot,
388
+ specPath: spec,
389
+ htmlPath: html,
390
+ run,
391
+ });
392
+ if (!result || result.ok !== true) return failVerify((result && result.error) || 'archify boundary failed');
393
+ return {
394
+ validateOk: result.validate?.status === 0,
395
+ deliverOk: result.deliver?.status === 0,
396
+ checksPassed: result.receipt?.checksPassed ?? 0,
397
+ checkCount: result.receipt?.checkCount ?? contract.ARCHITECTURE_CHECK_COUNT ?? 9,
398
+ error: '',
399
+ };
400
+ } catch (error) {
401
+ return failVerify((error && error.message) || 'archify boundary executor failed');
402
+ }
403
+ }
404
+
349
405
  // LLM Agent Steps: runner adapter / graceful execution
350
406
  if (child_process) {
351
407
  try {
352
408
  const agyRes = child_process.spawnSync('agy', ['--print', prompt, '--output-format', 'json', '--print-timeout', '30s'], {
353
409
  encoding: 'utf8',
354
410
  timeout: 35000,
411
+ shell: false,
355
412
  });
356
413
  if (agyRes.status === 0 && agyRes.stdout) {
357
414
  const jsonMatch = agyRes.stdout.match(/\{[\s\S]*\}/);
@@ -571,6 +628,38 @@ async function mergeStateD() {
571
628
  );
572
629
  }
573
630
 
631
+ async function verifyArchifyArtifacts() {
632
+ return await agent(
633
+ 'You are the dedicated /startcycle-graph archify-verify step -- a deterministic check, not a reasoning task. ' +
634
+ 'Working directory is the repository root. Run exactly these two commands in this order, ' +
635
+ 'each as an argument array with no shell and no string interpolation: ' +
636
+ 'first ["validate", "architecture", "production_artifacts/00_architecture.json", "--quality", "showcase", "--json"], ' +
637
+ 'then ["deliver", "architecture", "production_artifacts/00_architecture.json", "production_artifacts/00_architecture.html", "--quality", "showcase", "--json"], ' +
638
+ 'both via the node archify binary at skills/global_config/archify/bin/archify.mjs with a 120 second timeout each. ' +
639
+ 'Only run deliver when validate exits 0. Read at most 65536 bytes of each command output. ' +
640
+ 'Deliver passes only on a showcase receipt with 9 of 9 checks and 0 errors plus sha256 evidence for specification and artifact. ' +
641
+ 'On any non-zero exit, oversized output, or invalid receipt, report failure and preserve the previous HTML artifact untouched -- ' +
642
+ 'never invent success and never write state.artifacts.architecture yourself. ' +
643
+ 'Keep any logged output bounded to 400 characters with home directories and long hashes redacted.\n\n' +
644
+ 'Return only: { "validateOk": boolean, "deliverOk": boolean, "checksPassed": number, "checkCount": number, "error": string }.',
645
+ {
646
+ label: `archify-verify-${iteration}`,
647
+ model: 'haiku',
648
+ schema: {
649
+ type: 'object',
650
+ required: ['validateOk', 'deliverOk', 'checksPassed', 'checkCount', 'error'],
651
+ properties: {
652
+ validateOk: { type: 'boolean' },
653
+ deliverOk: { type: 'boolean' },
654
+ checksPassed: { type: 'number' },
655
+ checkCount: { type: 'number' },
656
+ error: { type: 'string' },
657
+ },
658
+ },
659
+ }
660
+ );
661
+ }
662
+
574
663
  // ---------------------------------------------------------------------
575
664
  // Load the node registry. First thing this run does, per comment block
576
665
  // item #4 -- everything below is derived from this, nothing is hardcoded.
@@ -706,20 +795,22 @@ if (mandatorySkillNames.length > 0) {
706
795
  'this workflow may be driven from a harness whose directory is not ~/.claude. ' +
707
796
  'If this project has its own skills/ directory, also accept skills/<name>/SKILL.md or skills/<container>/<name>/SKILL.md. ' +
708
797
  'This is a read-only lookup, not a reasoning task -- do not invent a path that does not exist, and never report a close match as `found`.\n\n' +
709
- 'For any name that does NOT resolve, list up to five installed skills whose directory names are plausible near-misses ' +
798
+ 'For any name that does NOT resolve, read lib/ecc-store-index.json and list exact available store item names in `store_matches`. ' +
799
+ 'Also list up to five installed skills whose directory names are plausible near-misses ' +
710
800
  '(substring, obvious typo, or the same words in another order) in `suggestions`. Read the real directory listing to do this -- ' +
711
801
  'suggest only names that actually exist on disk. `--skill=` requires an exact directory name, and a user who mistyped one ' +
712
802
  'has no way to discover the right spelling from an error that only says "not found".\n\n' +
713
- 'Return only: { "found": string[], "missing": string[], "suggestions": string[] }.',
803
+ 'Return only: { "found": string[], "missing": string[], "store_matches": string[], "suggestions": string[] }.',
714
804
  {
715
805
  label: 'validate-mandatory-skills',
716
806
  model: 'haiku',
717
807
  schema: {
718
808
  type: 'object',
719
- required: ['found', 'missing'],
809
+ required: ['found', 'missing', 'store_matches'],
720
810
  properties: {
721
811
  found: { type: 'array', items: { type: 'string' } },
722
812
  missing: { type: 'array', items: { type: 'string' } },
813
+ store_matches: { type: 'array', items: { type: 'string' } },
723
814
  suggestions: { type: 'array', items: { type: 'string' } },
724
815
  },
725
816
  },
@@ -727,15 +818,21 @@ if (mandatorySkillNames.length > 0) {
727
818
  );
728
819
  const missing = skillCheckResult?.missing ?? [];
729
820
  if (missing.length > 0) {
821
+ const storeMatches = skillCheckResult?.store_matches ?? [];
730
822
  const near = skillCheckResult?.suggestions ?? [];
731
- return await escalate(
732
- `--skill named skill(s) that could not be found on this machine: ${missing.join(', ')}. ` +
733
- (near.length
734
- ? `Did you mean: ${near.join(', ')}? `
735
- : 'No installed skill has a similar name. ') +
736
- '--skill= takes the exact skill directory name; run /ask-tim to find the one you want. ' +
737
- 'Refusing to silently proceed without a mandated skill.'
738
- );
823
+ let message = `--skill named skill(s) that could not be found on this machine: ${missing.join(', ')}. `;
824
+ if (storeMatches.length > 0) {
825
+ message += `Found in the AOS / ECC Store: ${storeMatches.join(', ')}. ` +
826
+ `Run: aos store install ${storeMatches.join(' ')} ` +
827
+ 'Then re-run your startcycle command. ';
828
+ } else if (near.length > 0) {
829
+ message += `Did you mean: ${near.join(', ')}? `;
830
+ } else {
831
+ message += 'No installed or store skill has a similar name. ';
832
+ }
833
+ message += '--skill= takes the exact skill directory name; run /ask-tim to find the one you want. ' +
834
+ 'Refusing to silently proceed without a mandated skill.';
835
+ return await escalate(message);
739
836
  }
740
837
  mandatorySkills = skillCheckResult?.found ?? mandatorySkillNames;
741
838
  }
@@ -759,9 +856,14 @@ while (!approved) {
759
856
  : '') +
760
857
  `Turn this goal into a system plan with an explicit capability map (module boundaries, ` +
761
858
  `dependency direction, build order). Write it to production_artifacts/00_execution_plan.md. ` +
762
- `Set state.goal, state.phase = "plan", state.artifacts.plan to that path, and state.mandatory_skills to ${JSON.stringify(mandatorySkills)}. ` +
859
+ `Author the architecture as Archify architecture JSON to production_artifacts/00_architecture.json, ` +
860
+ `run aos-archify validate architecture production_artifacts/00_architecture.json --quality showcase --json during repair and ` +
861
+ `aos-archify deliver architecture production_artifacts/00_architecture.json production_artifacts/00_architecture.html --quality showcase --json once for final acceptance, ` +
862
+ `link it from the relevant plan component with a url: production_artifacts/00_architecture.html line, ` +
863
+ `and set state.goal, state.phase = "plan", state.artifacts.plan to the plan path, state.artifacts.architecture to production_artifacts/00_architecture.html only on a passing showcase receipt (9/9 checks, 0 errors), and state.mandatory_skills to ${JSON.stringify(mandatorySkills)}. ` +
864
+ `On a failed validate/deliver preserve the previous HTML and report deliverOk false instead of proceeding silently. ` +
763
865
  `Decide whether the goal needs the Media_EventTech build node (TouchDesigner/show-control/3D/media work) -- most goals don't.\n\n` +
764
- `Return only: { "planPath": string, "needsMedia": boolean }.`,
866
+ `Return only: { "planPath": string, "needsMedia": boolean, "architectureSpec": string, "architectureHtml": string, "deliverOk": boolean }.`,
765
867
  {
766
868
  label: `architect-${iteration}`,
767
869
  agentType: architectNode.agentType,
@@ -769,22 +871,78 @@ while (!approved) {
769
871
  schema: {
770
872
  type: 'object',
771
873
  required: ['planPath', 'needsMedia'],
772
- properties: { planPath: { type: 'string' }, needsMedia: { type: 'boolean' } },
874
+ properties: {
875
+ planPath: { type: 'string' },
876
+ needsMedia: { type: 'boolean' },
877
+ architectureSpec: { type: 'string' },
878
+ architectureHtml: { type: 'string' },
879
+ deliverOk: { type: 'boolean' },
880
+ },
773
881
  },
774
882
  }
775
883
  );
776
884
 
777
885
  planPath = architectResult?.planPath;
778
886
  needsMedia = !!architectResult?.needsMedia;
887
+ const architectureSpec = architectResult?.architectureSpec || 'production_artifacts/00_architecture.json';
888
+ const architectureHtml = architectResult?.architectureHtml || 'production_artifacts/00_architecture.html';
889
+ const deliverOk = architectResult?.deliverOk !== false;
779
890
 
780
891
  if (!planPath) {
781
892
  return await escalate('Architect did not return a plan path.');
782
893
  }
894
+ if (!deliverOk) {
895
+ iteration++;
896
+ if (iteration >= MAX_ITERATIONS) {
897
+ return await escalate(
898
+ 'Archify deliver reported failure at the Architect step; previous HTML preserved.',
899
+ { planPath }
900
+ );
901
+ }
902
+ lastRejectionReason = 'Archify deliver/validate failed; previous HTML preserved. Repair the spec and deliver again.';
903
+ continue;
904
+ }
905
+ if (architectureSpec !== 'production_artifacts/00_architecture.json' || architectureHtml !== 'production_artifacts/00_architecture.html') {
906
+ iteration++;
907
+ if (iteration >= MAX_ITERATIONS) {
908
+ return await escalate(
909
+ 'Archify boundary rejected untrusted artifact paths; previous HTML preserved.',
910
+ { planPath }
911
+ );
912
+ }
913
+ lastRejectionReason = 'Archify boundary rejected untrusted artifact paths; previous HTML preserved. Use production_artifacts/00_architecture.json and production_artifacts/00_architecture.html.';
914
+ continue;
915
+ }
916
+ const boundaryResult = await verifyArchifyArtifacts();
917
+ if (!boundaryResult || boundaryResult.validateOk !== true || boundaryResult.deliverOk !== true) {
918
+ iteration++;
919
+ const boundaryError = typeof boundaryResult?.error === 'string' && boundaryResult.error
920
+ ? boundaryResult.error.slice(0, 400)
921
+ : 'archify validate/deliver failed';
922
+ if (iteration >= MAX_ITERATIONS) {
923
+ return await escalate(
924
+ `Archify boundary verification failed; previous HTML preserved: ${boundaryError}`,
925
+ { planPath }
926
+ );
927
+ }
928
+ lastRejectionReason = `Archify boundary verification failed; previous HTML preserved: ${boundaryError}. Repair the spec and deliver again.`;
929
+ continue;
930
+ }
931
+ try {
932
+ if (fs && fs.existsSync && fs.existsSync(architectureHtml) && child_process) {
933
+ const canvas = child_process.spawn('aos-plan-canvas', ['open', architectureHtml, '--no-open'], { cwd: process.cwd(), timeout: 15000, stdio: 'ignore', shell: false, detached: true });
934
+ if (canvas && typeof canvas.on === 'function') canvas.on('error', () => {});
935
+ if (canvas && typeof canvas.unref === 'function') canvas.unref();
936
+ }
937
+ } catch {}
783
938
 
784
939
  const techLeadResult = await agent(
785
940
  `You are acting as the ${techleadNode.label} agent (${techleadNode.personaFile}). ${dispatchNote(techleadNode)}${skillsNote(techleadNode)}\n\n` +
786
941
  `Read the plan at ${planPath}. Approve it only if it has an explicit capability map: ` +
787
942
  `module boundaries, dependency direction, and build order are all stated, not implicit. ` +
943
+ `Apply the architecture gate: reject unless ${architectureSpec} and ${architectureHtml} both exist, ` +
944
+ `the plan links the diagram with a url: ${architectureHtml} line, ` +
945
+ `and the deliver receipt is a passing showcase receipt (9/9 checks, 0 errors, failure preserves the previous HTML). ` +
788
946
  (mandatorySkills.length > 0
789
947
  ? `The user also required this run to use the following skill(s) via /startcycle-graph's --skill flag: ${mandatorySkills.join(', ')}. ` +
790
948
  `Reject the plan if it does not actually account for them — catching that here costs one planning round, ` +
@@ -843,7 +1001,7 @@ const NODE_NAMES = humanList(NODE_ENUM);
843
1001
  // aos-trail exits on its own when a map for this repo is already running.
844
1002
  try {
845
1003
  child_process?.spawn('aos-trail', [process.cwd(), '--plan', 'production_artifacts/00_execution_plan.md', '--no-open'],
846
- { detached: true, stdio: 'ignore', shell: process.platform === 'win32' }).on('error', () => {}).unref();
1004
+ { detached: true, stdio: 'ignore', shell: false }).on('error', () => {}).unref();
847
1005
  } catch { /* no child_process in this runtime: run without the map */ }
848
1006
 
849
1007
  let findings = [];
@@ -1011,7 +1169,7 @@ while (!reviewedClean) {
1011
1169
  // state.d + merge treatment as the build/review loop above.
1012
1170
  // ---------------------------------------------------------------------
1013
1171
 
1014
- const GATE_KEYS = ['lint', 'typecheck', 'tests', 'a11y', 'seo'];
1172
+ const GATE_KEYS = ['lint', 'typecheck', 'tests', 'a11y', 'seo', 'security'];
1015
1173
  const GATE_VALUE_ENUM = ['pass', 'fail', 'skip'];
1016
1174
  let allGatesPass = false;
1017
1175
  let lastGate = null;
@@ -1020,7 +1178,7 @@ while (!allGatesPass) {
1020
1178
  const shipResult = await agent(
1021
1179
  `You are acting as the ${shippingNode.label} agent (${shippingNode.personaFile}). ${dispatchNote(shippingNode)}${skillsNote(shippingNode)}\n\n` +
1022
1180
  `Run the automated quality gate against the artifacts from the plan at ${planPath}: lint, typecheck, ` +
1023
- `tests, a11y, seo. Use the repository's own commands (npm test / pytest / tsc --noEmit / etc -- detect ` +
1181
+ `tests, a11y, seo, security. Use the repository's own commands (npm test / pytest / tsc --noEmit / etc -- detect ` +
1024
1182
  `which apply; use "skip" only for a check that genuinely doesn't apply to this repo, not for one you didn't run). ` +
1025
1183
  `Write production_artifacts/04_release_report.md and update state.gate. ` +
1026
1184
  `If every gate check is 'pass' or 'skip', you must also set state.phase = "ready_to_ship" in state.json.\n\n` +
@@ -5,12 +5,13 @@ model: opus
5
5
  ---
6
6
  Turns the user's goal (or `/bdbrainstorm` / `/grill-me` output) into a system plan. Reads existing architecture before proposing changes. Does not coordinate execution or invoke other agents — that is TechLead's job, decided by the dispatcher, not by Architect.
7
7
 
8
- **Primary skills:** bdbrainstorm, planning-with-files, concise-planning
8
+ **Primary skills:** bdbrainstorm, planning-with-files, concise-planning, archify
9
9
 
10
10
  **MCP servers used:** openwiki-skill, memb_mcp
11
11
 
12
- **Output artifact(s):** `production_artifacts/00_execution_plan.md`
12
+ **Output artifact(s):** `production_artifacts/00_execution_plan.md`, `production_artifacts/00_architecture.json`, `production_artifacts/00_architecture.html`
13
13
 
14
14
  - The plan uses the agenttrail component convention (`## Name {#id}`, `needs:`, `files:`, tasks `- [ ] ... {#id}`).
15
- - The Architect renders the architecture with `aos-archify` to `production_artifacts/00_architecture.html` and links it from the relevant component with a `url:` line.
16
- - Plan-canvas can review that HTML too.
15
+ - The Architect authors the architecture as Archify `architecture` JSON to `production_artifacts/00_architecture.json`, runs `aos-archify validate architecture <spec> --quality showcase --json` during repair and `aos-archify deliver architecture <spec> production_artifacts/00_architecture.html --quality showcase --json` once for final acceptance, and records `state.artifacts.architecture` only on a passing showcase receipt (9/9 checks, 0 errors). A failed validate/deliver preserves the previous HTML and escalates at the Architect→TechLead boundary.
16
+ - The relevant plan component links the delivered diagram with a `url: production_artifacts/00_architecture.html` line so the live map opens it from the card.
17
+ - Plan-canvas reviews that HTML too via the existing path as fixed argv `aos-plan-canvas open production_artifacts/00_architecture.html --no-open` with `shell: false` from the repo root (no new port, single open, no shell interpolation). A missing or unavailable canvas never invalidates the verified architecture; the `url:` line and the `aos-trail . --plan production_artifacts/00_execution_plan.md --no-open` map stay authoritative.
@@ -10,3 +10,5 @@ Reviews Architect's plan for a capability map (module boundaries, dependency dir
10
10
  **MCP servers used:** memb_mcp
11
11
 
12
12
  **Output artifact(s):** capability-map approval recorded in `state.json` (no separate markdown file — this is a gate, not a deliverable)
13
+
14
+ - TechLead rejects the plan when the architecture gate fails: `production_artifacts/00_architecture.json` and `production_artifacts/00_architecture.html` are missing, the `url: production_artifacts/00_architecture.html` link is absent from the plan, or the deliver receipt is not a passing showcase receipt (9/9 checks, 0 errors). A failed receipt preserves the previous HTML and sends the run back to Architect.
@@ -99,7 +99,15 @@ browser-internal identifiers private to the served page
99
99
  No ECC tests, hooks (`scripts/hooks/plan-canvas-*.js`), or the
100
100
  `commands/plan-canvas.md` wrapper were ported.
101
101
 
102
- ### License text
102
+ ### 3. Store index
103
+
104
+ The AOS Store exposes selected ECC Markdown capabilities through
105
+ `lib/ecc-store-index.json` at pinned commit
106
+ `e482e579415fde18357cafce70f177ae19fd7f03`. The index contains only
107
+ `skills/**/SKILL.md` and `agents/*.md` metadata. Installation verifies the raw
108
+ Markdown SHA-256 before writing it. Scripts, hooks, rules, and non-entrypoint
109
+ Markdown files are excluded from the Phase 1 store.
110
+
103
111
 
104
112
  ```
105
113
  MIT License