@jaimevalasek/aioson 1.17.2 → 1.18.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.
Files changed (65) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +85 -51
  3. package/docs/en/3-recipes/full-feature-with-sheldon.md +1 -1
  4. package/docs/en/5-reference/cli-reference.md +4 -4
  5. package/docs/en/5-reference/qa-browser.md +2 -2
  6. package/docs/en/README.md +1 -1
  7. package/docs/en/deyvin-subtask-scout/how-to-use.md +2 -2
  8. package/docs/en/deyvin-subtask-scout/sub-task-scout.md +3 -3
  9. package/docs/en/deyvin-subtask-scout/troubleshooting.md +1 -1
  10. package/docs/pt/3-receitas/publicar-no-aioson-com.md +17 -0
  11. package/docs/pt/5-referencia/comandos-cli.md +2 -2
  12. package/docs/pt/5-referencia/inteligencia-adaptativa.md +3 -3
  13. package/docs/pt/5-referencia/skills.md +1 -1
  14. package/docs/pt/5-referencia/web3.md +3 -3
  15. package/docs/pt/README.md +1 -1
  16. package/docs/pt/_arquivo/README.md +1 -1
  17. package/docs/pt/_arquivo/cenarios.md +31 -31
  18. package/docs/pt/_arquivo/design-hybrid-forge.md +5 -5
  19. package/docs/pt/_arquivo/guia-engineer.md +1 -1
  20. package/docs/pt/_arquivo/profiler-system.md +1 -1
  21. package/docs/pt/_arquivo/site-forge.md +16 -16
  22. package/docs/pt/_arquivo/squad-genome.md +2 -2
  23. package/docs/pt/agentes.md +37 -37
  24. package/docs/pt/deyvin-subtask-scout/como-usar.md +2 -2
  25. package/docs/pt/deyvin-subtask-scout/sub-task-scout.md +1 -1
  26. package/docs/pt/deyvin-subtask-scout/troubleshooting.md +1 -1
  27. package/docs/pt/living-memory/README.md +1 -1
  28. package/docs/pt/living-memory/memoria-viva.md +2 -2
  29. package/docs/pt/living-memory/reflexao-in-harness.md +1 -1
  30. package/docs/pt/living-memory/troubleshooting.md +6 -6
  31. package/package.json +4 -2
  32. package/src/commands/gate-approve.js +56 -1
  33. package/src/commands/live.js +81 -54
  34. package/src/commands/op-capture.js +27 -2
  35. package/src/commands/op-list.js +33 -1
  36. package/src/commands/store-system.js +104 -12
  37. package/src/commands/tool-capabilities.js +14 -10
  38. package/src/commands/workflow-heal.js +47 -1
  39. package/src/i18n/messages/en.js +6 -5
  40. package/src/i18n/messages/pt-BR.js +6 -5
  41. package/src/lib/dev-resume.js +6 -1
  42. package/src/lib/tool-capabilities.js +64 -37
  43. package/src/operator-memory/decision.js +11 -4
  44. package/src/operator-memory/proposal.js +11 -7
  45. package/src/session-handoff.js +52 -1
  46. package/template/.aioson/agents/analyst.md +34 -2
  47. package/template/.aioson/agents/architect.md +33 -1
  48. package/template/.aioson/agents/briefing.md +26 -1
  49. package/template/.aioson/agents/copywriter.md +1 -1
  50. package/template/.aioson/agents/dev.md +2 -2
  51. package/template/.aioson/agents/deyvin.md +12 -12
  52. package/template/.aioson/agents/neo.md +74 -74
  53. package/template/.aioson/agents/orchestrator.md +26 -0
  54. package/template/.aioson/agents/pentester.md +66 -14
  55. package/template/.aioson/agents/pm.md +18 -1
  56. package/template/.aioson/agents/product.md +12 -1
  57. package/template/.aioson/agents/qa.md +3 -3
  58. package/template/.aioson/agents/sheldon.md +24 -4
  59. package/template/.aioson/agents/tester.md +115 -2
  60. package/template/.aioson/docs/briefing/briefing-craft.md +16 -0
  61. package/template/.aioson/docs/deyvin/runtime-handoffs.md +1 -1
  62. package/template/.aioson/docs/handoff-persistence.md +7 -7
  63. package/template/.aioson/docs/pentester/browser-dast-playbook.md +398 -0
  64. package/template/.aioson/rules/agent-structural-contract.md +139 -0
  65. package/template/.aioson/skills/process/decision-presentation/SKILL.md +2 -2
@@ -217,7 +217,7 @@ module.exports = {
217
217
  help_runtime_emit:
218
218
  'aioson runtime:emit [path] --agent=<nome> [--type=<evento>] [--summary=<texto>] [--title=<texto>] [--refs=<arquivo[,arquivo2]>] [--plan-step=<id>] [--meta=<json>] [--json] [--locale=pt-BR]',
219
219
  help_live_start:
220
- 'aioson live:start [path] --tool=codex|claude|gemini|opencode --agent=<nome> [--tool-bin=<binario>] [--tool-args=<args>] [--title=<texto>] [--goal=<texto>] [--plan=<arquivo>] [--session=<chave>] [--message=<texto>] [--attach] [--no-launch] [--tmux] [--json] [--locale=pt-BR]',
220
+ 'aioson live:start [path] --tool=codex|claude|gemini|opencode --agent=<nome> [--tool-bin=<binario>] [--permission-mode=default|yolo] [--tool-args=<args>] [--title=<texto>] [--goal=<texto>] [--plan=<arquivo>] [--session=<chave>] [--message=<texto>] [--attach] [--no-launch] [--tmux] [--json] [--locale=pt-BR]',
221
221
  help_live_status:
222
222
  'aioson live:status [path] [--agent=<nome>] [--limit=8] [--watch=2] [--format=compact|tmux-bar] [--json] [--locale=pt-BR]',
223
223
  help_live_handoff:
@@ -1116,10 +1116,11 @@ module.exports = {
1116
1116
  plan_not_found: 'Arquivo de plano nao encontrado: {plan}',
1117
1117
  no_active_session: 'Nenhuma sessao live ativa encontrada para {agent}.',
1118
1118
  session_not_active: 'A sessao live de {agent} nao esta ativa.',
1119
- json_requires_no_launch: '--json requer --no-launch para live:start porque o lancamento em primeiro plano e interativo.',
1120
- tool_binary_not_found: 'Binario da ferramenta nao encontrado no PATH: {binary}',
1121
- tool_mismatch: 'A sessao ativa usa a ferramenta "{existing}" mas --tool={requested} foi informado. Encerre a sessao primeiro ou use a mesma ferramenta.',
1122
- micro_task_already_open: 'Uma micro-tarefa live ja esta aberta para {agent}. Emita task_completed antes de task_started novamente.',
1119
+ json_requires_no_launch: '--json requer --no-launch para live:start porque o lancamento em primeiro plano e interativo.',
1120
+ tool_binary_not_found: 'Binario da ferramenta nao encontrado no PATH: {binary}',
1121
+ tool_mismatch: 'A sessao ativa usa a ferramenta "{existing}" mas --tool={requested} foi informado. Encerre a sessao primeiro ou use a mesma ferramenta.',
1122
+ tool_mismatch_auto_closed: 'A sessao live anterior usava "{existing}" e foi fechada automaticamente. Iniciando nova sessao com "{requested}".',
1123
+ micro_task_already_open: 'Uma micro-tarefa live ja esta aberta para {agent}. Emita task_completed antes de task_started novamente.',
1123
1124
  handoff_same_agent: 'live:handoff requer valores diferentes para --agent e --to.',
1124
1125
  handoff_agent_mismatch: 'Nenhuma sessao live ativa encontrada para {agent}.',
1125
1126
  watch_json_conflict: '--watch nao pode ser combinado com --json.',
@@ -121,6 +121,10 @@ async function buildDevResumeData(projectPath) {
121
121
  ? lastHandoff.artifact_uris
122
122
  : [];
123
123
 
124
+ const decisionRationale = Array.isArray(lastHandoff && lastHandoff.decision_rationale)
125
+ ? lastHandoff.decision_rationale
126
+ : [];
127
+
124
128
  return {
125
129
  feature_slug: featureSlug,
126
130
  classification,
@@ -128,7 +132,8 @@ async function buildDevResumeData(projectPath) {
128
132
  artifacts_consumed: artifactsConsumed,
129
133
  code_map_paths: extractCodeMapPaths(dossierRaw),
130
134
  sheldon_plan: sheldonPlan,
131
- next_step: devStateNext || deriveNextStepFromPlan(planRaw)
135
+ next_step: devStateNext || deriveNextStepFromPlan(planRaw),
136
+ decision_rationale: decisionRationale.length > 0 ? decisionRationale : undefined
132
137
  };
133
138
  }
134
139
 
@@ -5,10 +5,11 @@
5
5
  // "continue last conversation" is achieved by passing the right resume flag
6
6
  // at spawn time — AIOSON never has to track an internal session ID.
7
7
  //
8
- // Used by:
9
- // - `aioson live:start --resume[=last|<id>]` to map to the correct argv
10
- // - `aioson tool:capabilities` to expose this map as JSON to UI clients
11
- // (e.g. AIOSON Play) so they don't duplicate the lookup.
8
+ // Used by:
9
+ // - `aioson live:start --resume[=last|<id>]` to map to the correct argv
10
+ // - `aioson live:start --permission-mode=yolo` to map to the correct argv
11
+ // - `aioson tool:capabilities` to expose this map as JSON to UI clients
12
+ // (e.g. AIOSON Play) so they don't duplicate the lookup.
12
13
  //
13
14
  // Keep entries minimal and source-of-truth here. Adding a new CLI = one entry.
14
15
  const TOOL_CAPS = {
@@ -17,42 +18,50 @@ const TOOL_CAPS = {
17
18
  binary: 'claude',
18
19
  supports_resume: true,
19
20
  resume_last: ['--continue'],
20
- supports_session_id: true,
21
- resume_session_id: ['--resume', '<id>'],
22
- supports_session_picker: true,
23
- session_picker: ['--resume'],
24
- },
25
- codex: {
21
+ supports_session_id: true,
22
+ resume_session_id: ['--resume', '<id>'],
23
+ supports_session_picker: true,
24
+ session_picker: ['--resume'],
25
+ supports_yolo: true,
26
+ yolo_args: ['--dangerously-skip-permissions'],
27
+ },
28
+ codex: {
26
29
  install_command: 'npm install -g @openai/codex',
27
30
  binary: 'codex',
28
31
  supports_resume: true,
29
32
  resume_last: ['resume', '--last'],
30
- supports_session_id: true,
31
- resume_session_id: ['resume', '<id>'],
32
- supports_session_picker: true,
33
- session_picker: ['resume'],
34
- },
35
- opencode: {
33
+ supports_session_id: true,
34
+ resume_session_id: ['resume', '<id>'],
35
+ supports_session_picker: true,
36
+ session_picker: ['resume'],
37
+ supports_yolo: true,
38
+ yolo_args: ['--dangerously-bypass-approvals-and-sandbox'],
39
+ },
40
+ opencode: {
36
41
  install_command: 'npm install -g opencode-ai',
37
42
  binary: 'opencode',
38
43
  supports_resume: true,
39
44
  resume_last: ['--continue'],
40
- supports_session_id: true,
41
- resume_session_id: ['--session', '<id>'],
42
- supports_session_picker: false,
43
- session_picker: null,
44
- },
45
- gemini: {
45
+ supports_session_id: true,
46
+ resume_session_id: ['--session', '<id>'],
47
+ supports_session_picker: false,
48
+ session_picker: null,
49
+ supports_yolo: false,
50
+ yolo_args: null,
51
+ },
52
+ gemini: {
46
53
  install_command: 'npm install -g @google/gemini-cli',
47
54
  binary: 'gemini',
48
55
  supports_resume: false,
49
56
  resume_last: null,
50
- supports_session_id: false,
51
- resume_session_id: null,
52
- supports_session_picker: false,
53
- session_picker: null,
54
- },
55
- };
57
+ supports_session_id: false,
58
+ resume_session_id: null,
59
+ supports_session_picker: false,
60
+ session_picker: null,
61
+ supports_yolo: false,
62
+ yolo_args: null,
63
+ },
64
+ };
56
65
 
57
66
  function getToolCapabilities(tool) {
58
67
  const key = String(tool || '').trim().toLowerCase();
@@ -71,7 +80,7 @@ function listSupportedTools() {
71
80
  // - '' / undefined / null / false → no resume
72
81
  // - any other string → treat as session id
73
82
  // Returns [] when the tool doesn't support resume or resumeOpt is falsy.
74
- function resolveResumeArgs(tool, resumeOpt) {
83
+ function resolveResumeArgs(tool, resumeOpt) {
75
84
  if (resumeOpt === undefined || resumeOpt === null || resumeOpt === '' || resumeOpt === false) {
76
85
  return [];
77
86
  }
@@ -92,11 +101,29 @@ function resolveResumeArgs(tool, resumeOpt) {
92
101
  }
93
102
 
94
103
  return Array.isArray(caps.resume_last) ? [...caps.resume_last] : [];
95
- }
96
-
97
- module.exports = {
98
- TOOL_CAPS,
99
- getToolCapabilities,
100
- listSupportedTools,
101
- resolveResumeArgs,
102
- };
104
+ }
105
+
106
+ function resolvePermissionModeArgs(tool, permissionMode) {
107
+ const mode = String(permissionMode || '').trim().toLowerCase();
108
+ if (!mode || mode === 'default') return [];
109
+ if (mode !== 'yolo') {
110
+ throw new Error(`permission_mode_unknown:${permissionMode}`);
111
+ }
112
+
113
+ const caps = getToolCapabilities(tool);
114
+ if (!caps) {
115
+ throw new Error(`tool_unknown:${tool}`);
116
+ }
117
+ if (!caps.supports_yolo || !Array.isArray(caps.yolo_args)) {
118
+ throw new Error(`permission_mode_unsupported:${tool}:yolo`);
119
+ }
120
+ return [...caps.yolo_args];
121
+ }
122
+
123
+ module.exports = {
124
+ TOOL_CAPS,
125
+ getToolCapabilities,
126
+ listSupportedTools,
127
+ resolveResumeArgs,
128
+ resolvePermissionModeArgs,
129
+ };
@@ -81,7 +81,7 @@ function deriveTitle(proposal) {
81
81
  function serializeDecision(data) {
82
82
  const body = String(data.body || data.proposal || '').slice(0, MAX_BODY_CHARS);
83
83
  const title = deriveTitle(data.title || data.proposal);
84
- return [
84
+ const lines = [
85
85
  '---',
86
86
  `slug: ${data.slug}`,
87
87
  `signal_type: ${data.signal_type}`,
@@ -93,8 +93,13 @@ function serializeDecision(data) {
93
93
  `source_agent: ${data.source_agent}`,
94
94
  `quotes:${quotesToYaml(data.quotes)}`,
95
95
  `version_schema: "${SCHEMA_VERSION}"`,
96
- `deprecated_by: ${data.deprecated_by ?? 'null'}`,
97
- '---',
96
+ `deprecated_by: ${data.deprecated_by ?? 'null'}`
97
+ ];
98
+ if (data.feature_slug) lines.push(`feature_slug: ${escapeYamlString(data.feature_slug)}`);
99
+ if (data.session_id) lines.push(`session_id: ${escapeYamlString(data.session_id)}`);
100
+ lines.push('---');
101
+ return [
102
+ ...lines,
98
103
  '',
99
104
  `# ${title}`,
100
105
  '',
@@ -178,7 +183,9 @@ function promoteProposal({ identity, proposal: proposalData }) {
178
183
  quotes: proposalData.quotes || [],
179
184
  body,
180
185
  title: proposalData.proposal,
181
- deprecated_by: null
186
+ deprecated_by: null,
187
+ feature_slug: proposalData.feature_slug || null,
188
+ session_id: proposalData.session_id || null
182
189
  };
183
190
 
184
191
  const decFilePath = decisionPath(identity, decision.slug);
@@ -46,7 +46,7 @@ function quotesToYaml(quotes) {
46
46
  }
47
47
 
48
48
  function serializeProposal(data) {
49
- return [
49
+ const lines = [
50
50
  '---',
51
51
  `slug: ${data.slug}`,
52
52
  `signal_type: ${data.signal_type}`,
@@ -56,10 +56,12 @@ function serializeProposal(data) {
56
56
  `quotes:${quotesToYaml(data.quotes)}`,
57
57
  `proposal: ${escapeYamlString(data.proposal)}`,
58
58
  `source_agent: ${data.source_agent}`,
59
- `proposal_fingerprint: ${data.proposal_fingerprint}`,
60
- '---',
61
- ''
62
- ].join('\n');
59
+ `proposal_fingerprint: ${data.proposal_fingerprint}`
60
+ ];
61
+ if (data.feature_slug) lines.push(`feature_slug: ${escapeYamlString(data.feature_slug)}`);
62
+ if (data.session_id) lines.push(`session_id: ${escapeYamlString(data.session_id)}`);
63
+ lines.push('---', '');
64
+ return lines.join('\n');
63
65
  }
64
66
 
65
67
  function parseProposalFrontmatter(content) {
@@ -130,7 +132,7 @@ function deleteProposal(identity, slug) {
130
132
  return false;
131
133
  }
132
134
 
133
- function captureSignal({ identity, slug, signal_type, quote, proposal, source_agent }) {
135
+ function captureSignal({ identity, slug, signal_type, quote, proposal, source_agent, feature_slug, session_id }) {
134
136
  if (!VALID_SIGNAL_TYPES.includes(signal_type)) {
135
137
  throw new Error(`Invalid signal_type '${signal_type}'. Must be one of: ${VALID_SIGNAL_TYPES.join(', ')}`);
136
138
  }
@@ -160,7 +162,9 @@ function captureSignal({ identity, slug, signal_type, quote, proposal, source_ag
160
162
  quotes: quote ? [String(quote).trim()].filter(Boolean) : [],
161
163
  proposal,
162
164
  source_agent: source_agent || 'unknown',
163
- proposal_fingerprint: fingerprintProposal(proposal)
165
+ proposal_fingerprint: fingerprintProposal(proposal),
166
+ feature_slug: feature_slug || null,
167
+ session_id: session_id || null
164
168
  };
165
169
  writeProposal(identity, fresh);
166
170
  return { proposal: fresh, isNew: true };
@@ -6,6 +6,8 @@ const { exists, ensureDir } = require('./utils');
6
6
 
7
7
  const HANDOFF_RELATIVE_PATH = '.aioson/context/last-handoff.json';
8
8
  const HANDOFF_PROTOCOL_RELATIVE_PATH = '.aioson/context/handoff-protocol.json';
9
+ const CONFIRMATIONS_JSONL = '.aioson/runtime/session-confirmations.jsonl';
10
+ const DECISION_RATIONALE_MAX = 5;
9
11
 
10
12
  // handoff-protocol.json schema_version for `artifact_uris`:
11
13
  // v1 (legacy) — array of strings; v2 — array of {path, kind, agent, added_at}.
@@ -63,10 +65,52 @@ function coerceArtifactUris(uris, fallbackAgent) {
63
65
  .filter(Boolean);
64
66
  }
65
67
 
68
+ async function collectDecisionRationale(targetDir) {
69
+ const accPath = path.join(targetDir, CONFIRMATIONS_JSONL);
70
+ try {
71
+ const raw = await fs.readFile(accPath, 'utf8');
72
+ const lines = raw.trim().split('\n').filter(Boolean);
73
+ const entries = [];
74
+ for (const line of lines) {
75
+ try {
76
+ const obj = JSON.parse(line);
77
+ entries.push({
78
+ agent: obj.agent || 'unknown',
79
+ decision: obj.decision || '',
80
+ alternatives_considered: null,
81
+ rationale: obj.quote || null,
82
+ confidence: 'confirmed'
83
+ });
84
+ } catch {
85
+ // skip malformed lines
86
+ }
87
+ }
88
+ // BR-AO-04: FIFO — keep only the last N entries
89
+ return entries.slice(-DECISION_RATIONALE_MAX);
90
+ } catch {
91
+ return [];
92
+ }
93
+ }
94
+
95
+ async function clearConfirmationsAccumulator(targetDir) {
96
+ const accPath = path.join(targetDir, CONFIRMATIONS_JSONL);
97
+ try {
98
+ await fs.unlink(accPath);
99
+ } catch {
100
+ // file may not exist
101
+ }
102
+ }
103
+
66
104
  async function writeHandoff(targetDir, payload) {
67
105
  const handoffPath = path.join(targetDir, HANDOFF_RELATIVE_PATH);
68
106
  const protocolPath = path.join(targetDir, HANDOFF_PROTOCOL_RELATIVE_PATH);
69
107
  await ensureDir(path.dirname(handoffPath));
108
+
109
+ // M2: collect decision rationale from session confirmations
110
+ const sessionRationale = await collectDecisionRationale(targetDir);
111
+ const existingRationale = Array.isArray(payload.decisionRationale) ? payload.decisionRationale : [];
112
+ const mergedRationale = [...existingRationale, ...sessionRationale].slice(-DECISION_RATIONALE_MAX);
113
+
70
114
  const handoff = {
71
115
  version: 1,
72
116
  session_ended_at: new Date().toISOString(),
@@ -79,10 +123,14 @@ async function writeHandoff(targetDir, payload) {
79
123
  context_files_updated: Array.isArray(payload.contextFilesUpdated) ? payload.contextFilesUpdated : [],
80
124
  workflow_mode: payload.workflowMode || null,
81
125
  classification: payload.classification || null,
82
- feature_slug: payload.featureSlug || null
126
+ feature_slug: payload.featureSlug || null,
127
+ decision_rationale: mergedRationale.length > 0 ? mergedRationale : undefined
83
128
  };
84
129
  await fs.writeFile(handoffPath, `${JSON.stringify(handoff, null, 2)}\n`, 'utf8');
85
130
 
131
+ // Clear accumulator after writing to handoff
132
+ await clearConfirmationsAccumulator(targetDir);
133
+
86
134
  const protocol = payload.protocol || buildBasicHandoffProtocol(payload);
87
135
  await fs.writeFile(protocolPath, `${JSON.stringify(protocol, null, 2)}\n`, 'utf8');
88
136
 
@@ -283,9 +331,12 @@ function buildRuntimeLogHandoff(agentName, message, summary) {
283
331
  module.exports = {
284
332
  HANDOFF_RELATIVE_PATH,
285
333
  HANDOFF_PROTOCOL_RELATIVE_PATH,
334
+ CONFIRMATIONS_JSONL,
335
+ DECISION_RATIONALE_MAX,
286
336
  ARTIFACT_KINDS,
287
337
  coerceArtifactUri,
288
338
  coerceArtifactUris,
339
+ collectDecisionRationale,
289
340
  writeHandoff,
290
341
  readHandoff,
291
342
  readHandoffProtocol,
@@ -34,6 +34,8 @@ Before any manual checks, run these commands if the `aioson` CLI is available:
34
34
  ```bash
35
35
  aioson workflow:status . # confirm current stage and what is expected
36
36
  aioson context:validate . # validate project.context.md; detects brownfield state
37
+ aioson preflight . --agent=analyst --feature={slug} # unified pre-session check: loads rules, design governance, and context
38
+ aioson classify . # auto-detect project classification (MICRO/SMALL/MEDIUM) for cross-reference
37
39
  ```
38
40
 
39
41
  For feature mode with existing requirements, run before the synchronization gate:
@@ -331,7 +333,7 @@ Generate `.aioson/context/discovery.md` with the following sections:
331
333
 
332
334
  ## Dev handoff producer
333
335
 
334
- Before the final `agent:done` call, when the next agent in the workflow is `@dev`, produce `dev-state.md` so the next `/dev` session auto-resumes on cold start instead of pinging the user for context:
336
+ Before the final `agent:done` call, when the next agent in the workflow is `@dev`, produce `dev-state.md` so the next `/aioson:agent:dev` session auto-resumes on cold start instead of pinging the user for context:
335
337
 
336
338
  ```bash
337
339
  aioson dev:state:write . --feature={slug} --phase=1 \
@@ -341,5 +343,35 @@ aioson dev:state:write . --feature={slug} --phase=1 \
341
343
 
342
344
  `--context` accepts canonical tokens (`prd`, `requirements`, `spec`, `architecture`, `impl-plan`, `sheldon`, `design-doc`, `dossier`), max 4 entries total; missing files emit a warning and are skipped. Always include the artifacts @dev will need to start the first slice — typically `spec` + `requirements` for SMALL features. Idempotent: re-running with the same args does not duplicate state.
343
345
 
346
+ **Handoff message:**
347
+ ```
348
+ Requirements written: .aioson/context/requirements-{slug}.md
349
+ Spec skeleton: .aioson/context/spec-{slug}.md
350
+ Gate A: approved
351
+ Next agent: @architect (MEDIUM) or @dev (SMALL — skip architecture)
352
+ Why: Requirements and spec ready — @architect defines system design, or @dev starts implementation for SMALL features.
353
+ Action: /architect or /dev
354
+ ```
355
+ > Recommended: `/clear` before activating — fresh context window.
356
+
357
+ ## Strategic commands (use during session)
358
+
359
+ - Search memory before web research: `aioson memory:search . --query="<topic>" 2>/dev/null || true`
360
+ - Search context files: `aioson context:search . --query="<term>" 2>/dev/null || true`
361
+ - Compress context before handoff: `aioson context:pack . 2>/dev/null || true`
362
+ - Create spec checkpoint before changes: `aioson spec:checkpoint . --feature={slug} 2>/dev/null || true`
363
+
344
364
  ## Observability
345
- At session end, register: `aioson agent:done . --agent=analyst --summary="Discovery <slug>: <N> entities, <N> rules" 2>/dev/null || true`
365
+
366
+ At strategic milestones during execution, emit progress signals:
367
+ ```bash
368
+ aioson runtime:emit . --agent=analyst --type=milestone --summary="Requirements written: {slug}, {N} BRs, {N} ECs" 2>/dev/null || true
369
+ aioson runtime:emit . --agent=analyst --type=milestone --summary="Spec skeleton created: {slug}" 2>/dev/null || true
370
+ ```
371
+
372
+ At session end, register:
373
+ ```bash
374
+ aioson gate:approve . --feature={slug} --gate=A 2>/dev/null || true
375
+ aioson pulse:update . --agent=analyst --feature={slug} --action="Discovery completed: {N} entities, {N} rules" --next="<next agent recommendation>" 2>/dev/null || true
376
+ aioson agent:done . --agent=analyst --summary="Discovery <slug>: <N> entities, <N> rules" 2>/dev/null || true
377
+ ```
@@ -124,6 +124,20 @@ Before handing off to `@dev`:
124
124
  - If a relevant spec file exists and design is still pending, do not claim Gate B passed.
125
125
  - Tell the user explicitly whether Gate B passed or is blocked before handoff.
126
126
 
127
+ When Gate B passes, register it via CLI:
128
+ ```bash
129
+ aioson gate:approve . --feature={slug} --gate=B 2>/dev/null || true
130
+ ```
131
+
132
+ **Handoff message:**
133
+ ```
134
+ Architecture defined: .aioson/context/architecture.md
135
+ Gate B: {approved|blocked}
136
+ Next agent: @pm (MEDIUM — implementation planning) or @dev (SMALL — direct implementation)
137
+ Action: /pm or /dev
138
+ ```
139
+ > Recommended: `/clear` before activating — fresh context window.
140
+
127
141
  ## Rules
128
142
  - Do not redesign entities produced by `@analyst`. Consume the data design as-is.
129
143
  - Keep architecture proportional to classification. Never apply MEDIUM patterns to a MICRO project.
@@ -321,5 +335,23 @@ Keep architecture.md proportional — verbose output costs tokens without adding
321
335
  - Do not introduce patterns that do not exist in the chosen stack's conventions.
322
336
  - Do not copy content from discovery.md into architecture.md. Reference sections by name: "see discovery.md § Entities". The document chain is already in context.
323
337
 
338
+ ## Strategic commands (use during session)
339
+
340
+ - Search context for existing decisions: `aioson context:search . --query="<architectural term>" 2>/dev/null || true`
341
+ - Validate artifacts against spec: `aioson artifact:validate . --feature={slug} 2>/dev/null || true`
342
+ - Compress context before handoff: `aioson context:pack . 2>/dev/null || true`
343
+ - Audit dossier completeness: `aioson dossier:audit . --check=coverage 2>/dev/null || true`
344
+
324
345
  ## Observability
325
- At session end, register: `aioson agent:done . --agent=architect --summary="Architecture <slug>: <stack>, <N> modules" 2>/dev/null || true`
346
+
347
+ At strategic milestones during execution, emit progress signals:
348
+ ```bash
349
+ aioson runtime:emit . --agent=architect --type=milestone --summary="Architecture decided: {slug}, {stack}" 2>/dev/null || true
350
+ aioson runtime:emit . --agent=architect --type=gate_check --summary="Gate B: {approved|blocked} for {slug}" 2>/dev/null || true
351
+ ```
352
+
353
+ At session end, register:
354
+ ```bash
355
+ aioson pulse:update . --agent=architect --feature={slug} --action="Architecture defined: {stack}, {N} modules" --next="<next agent recommendation>" 2>/dev/null || true
356
+ aioson agent:done . --agent=architect --summary="Architecture <slug>: <stack>, <N> modules" 2>/dev/null || true
357
+ ```
@@ -66,6 +66,7 @@ After the user selects which plans to use:
66
66
  - Read each selected `plans/*.md` file fully.
67
67
  - Read `project.context.md` for project context.
68
68
  - Scan `.aioson/context/` for existing PRDs (`prd*.md`) — load titles/summaries only to avoid duplicating committed work.
69
+ - Also read `.aioson/context/done/MANIFEST.md` if present — it lists delivered (archived) features so you can dedupe against completed work without globbing the archive. Do NOT load the archived files themselves unless the user explicitly requests history.
69
70
 
70
71
  **2. Enrich**
71
72
 
@@ -91,6 +92,16 @@ Wait for confirmation.
91
92
  Write `.aioson/briefings/{slug}/briefings.md` and update `.aioson/briefings/config.md`.
92
93
  See **Output contract** below for exact formats.
93
94
 
95
+ After writing the briefing draft, emit a milestone:
96
+ ```bash
97
+ aioson runtime:emit . --agent=briefing --type=milestone --summary="Briefing draft written: {slug}" 2>/dev/null || true
98
+ ```
99
+
100
+ If a feature dossier exists for the target slug, record the briefing:
101
+ ```bash
102
+ aioson dossier:add-finding . --slug={slug} --agent=briefing --section="Agent Trail" --content="Briefing created: {N} themes, {N} risks, {N} open questions" 2>/dev/null || true
103
+ ```
104
+
94
105
  ## Mode: Conversational (no plans)
95
106
 
96
107
  When `plans/` is empty or the user wants to plan via conversation:
@@ -221,14 +232,27 @@ Always register additional files with a note at the bottom of `briefings.md`:
221
232
  - `{specific-theme}.md` — {one line description}
222
233
  ```
223
234
 
235
+ ## Feature dossier
236
+
237
+ Check `.aioson/context/features/{slug}/dossier.md` before writing the briefing — if present, read it for prior agent context.
238
+
239
+ **After writing the briefing**, record in the dossier:
240
+ ```
241
+ aioson dossier:add-finding . --slug={slug} --agent=briefing --section="Agent Trail" --content="Briefing created: {N} themes, {N} risks, {N} open questions" 2>/dev/null || true
242
+ ```
243
+
244
+ Skip silently when the dossier is absent.
245
+
224
246
  ## Rules
225
247
 
226
248
  - **Never modify `plans/`** — they are read-only. Plans belong to the user.
227
249
  - **Never access `.aioson/briefings/` from @dev** — briefings are pre-production. @dev receives the PRD already built.
228
250
  - **Never create a PRD** — that is `@product`'s responsibility.
229
251
  - **Never approve a briefing automatically** — approval requires explicit user action via CLI.
252
+ - When a briefing is approved (via CLI), emit: `aioson runtime:emit . --agent=briefing --type=milestone --summary="Briefing approved: {slug}" 2>/dev/null || true`
230
253
  - **Never overwrite an existing briefing** without confirming with the user first.
231
254
  - **Slug must be confirmed** by the user before any file is written.
255
+ - **Never recommend `@sheldon` (or any post-PRD agent) as the next step.** The only handoff from `@briefing` is `@product`. If the briefing surfaces a need for `@sheldon` / `@architect` / `@analyst` expertise, record that need inside the briefing (Risks / Open questions) as a *recommendation for `@product`'s enrichment phase*. `@product` decides when to invoke specialists after the PRD exists. See `briefing-craft.md` §1 "Mitigating weak markers" for examples.
232
256
  - Use `interaction_language` (fallback: `conversation_language`) from `project.context.md` for all interaction and output.
233
257
 
234
258
  ## Responsibility boundary
@@ -250,6 +274,7 @@ Always register additional files with a note at the bottom of `briefings.md`:
250
274
  - `config.md` frontmatter must be valid YAML — verify after writing.
251
275
  - All 8 sections must appear in `briefings.md` even when empty (`TBD`).
252
276
  - At session end, update `.aioson/context/project-pulse.md` if it exists: set `last_agent: briefing`, `updated_at`, add entry to "Recent activity".
277
+ - At session end, update pulse: `aioson pulse:update . --agent=briefing --feature={slug} --action="<summary>" --next="<next agent recommendation>" 2>/dev/null || true`
253
278
  - At session end, register: `aioson agent:done . --agent=briefing --summary="<one-line summary>" 2>/dev/null || true`
254
279
  - If `aioson` CLI is not available, write a devlog following the "Devlog" section in `.aioson/config.md`.
255
280
 
@@ -259,6 +284,6 @@ Always register additional files with a note at the bottom of `briefings.md`:
259
284
  ```bash
260
285
  aioson briefing:approve # mark as approved
261
286
  ```
262
- Then: activate `/product` — it will detect the approved briefing automatically.
287
+ Then: activate `/aioson:agent:product` — it will detect the approved briefing automatically.
263
288
  > Recommended: `/clear` first — fresh context window
264
289
  ---
@@ -25,7 +25,7 @@ understood, eliminates objections, and drives one clear action.
25
25
  ## When to activate
26
26
 
27
27
  @copywriter can be invoked:
28
- - **Standalone:** `/copywriter` or `@copywriter <context>` — write copy for a page, campaign, or feature
28
+ - **Standalone:** `/aioson:agent:copywriter` or `@copywriter <context>` — write copy for a page, campaign, or feature
29
29
  - **From @ux-ui:** automatically when `project_type=site` and copy is missing (copy gate)
30
30
  - **From @squad:** squad executors can route copy requests here
31
31
  - **From @squad executor:** a copywriter squad executor is a specialization of this agent
@@ -34,7 +34,7 @@ Use output to orient; load listed `rules`/`design_governance` before structural
34
34
 
35
35
  **Step 0.1 — Bootstrap gate (Living Memory):** read `aioson memory:status .` output. If `Bootstrap < 4/4` or the bootstrap files are older than 30 days, emit a warning at the top of your response:
36
36
 
37
- > ⚠ [bootstrap] coverage <N>/4 (or stale <D>d). Run `/discover` (or `aioson memory:refresh`) before continuing on broad work.
37
+ > ⚠ [bootstrap] coverage <N>/4 (or stale <D>d). Run `/aioson:agent:discover` (or `aioson memory:refresh`) before continuing on broad work.
38
38
 
39
39
  This is advisory — proceed with the user's task, but the warning surfaces the gap so the next session can fix it. Skip when bootstrap/ does not exist (greenfield).
40
40
 
@@ -264,7 +264,7 @@ Run `aioson` CLI yourself to keep the workflow moving:
264
264
 
265
265
  ## Auto-cycle return to @qa (corrections mode)
266
266
 
267
- If `.aioson/runtime/qa-dev-cycle.json` exists and its `slug` matches the active feature, you're in an auto-correction cycle started by `@qa`. After applying the plan in `last_plan` and tests pass: (1) update dossier + spec, (2) mark plan `status: resolved`, (3) auto-invoke `Skill(aioson:qa)` with `"re-verify after applying <plan path>"`. No user prompt — Ctrl+C interrupts. If the file is absent or slug differs, manual handoff as before.
267
+ If `.aioson/runtime/qa-dev-cycle.json` exists and its `slug` matches the active feature, you're in an auto-correction cycle started by `@qa`. After applying the plan in `last_plan` and tests pass: (1) update dossier + spec, (2) mark plan `status: resolved`, (3) auto-invoke `Skill(aioson:agent:qa)` with `"re-verify after applying <plan path>"`. No user prompt — Ctrl+C interrupts. If the file is absent or slug differs, manual handoff as before.
268
268
 
269
269
  ## Security findings consumption
270
270
 
@@ -7,14 +7,14 @@ Act as the continuity-first pair programming agent for AIOSON. Your codename is
7
7
 
8
8
  **Bootstrap gate (Living Memory) — MANDATORY first action:**
9
9
 
10
- Before any other action on `/deyvin` activation, check Living Memory coverage:
10
+ Before any other action on `/aioson:agent:deyvin` activation, check Living Memory coverage:
11
11
 
12
12
  1. **If `aioson` CLI is available**: run `aioson memory:status .` and read the output.
13
13
  2. **If `aioson` CLI is not available**: read `.aioson/context/bootstrap/*.md` directly via filesystem. Count present files (max 4: `what-is.md`, `what-it-does.md`, `how-it-works.md`, `current-state.md`) and the oldest modification date.
14
14
 
15
15
  If `Bootstrap < 4/4` OR files are older than 30 days, prefix your first reply with:
16
16
 
17
- > ⚠ [bootstrap] coverage <N>/4 (or stale <D>d). Recommend `/discover` (or `aioson memory:refresh`) before broad work.
17
+ > ⚠ [bootstrap] coverage <N>/4 (or stale <D>d). Recommend `/aioson:agent:discover` (or `aioson memory:refresh`) before broad work.
18
18
 
19
19
  This is advisory — continue with the user's task. Skip the gate only when `.aioson/context/bootstrap/` does not exist (greenfield project).
20
20
 
@@ -110,14 +110,14 @@ Apply this table deterministically after reading the user's request and consulti
110
110
  | Small slice of well-bounded code change; code already partially understood | Handle here (pair execution) |
111
111
  | Bug fix with failing test attached, or clear error message + reproducer | Handle here via `debugging-escalation.md` |
112
112
  | Diagnosis ambiguous; needs survey of >5 files or tracing a runtime flow | **Spawn sub-task scout** via `aioson scout:prep` (or CLI-less fallback — see "Sub-task scout invocation" below) |
113
- | New feature, new module, or cross-product surface | Handoff `/product` |
114
- | Decision affects multiple modules / system-wide architecture | Handoff `/architect` |
115
- | Missing domain rules, entities, or brownfield knowledge gap | Handoff `/analyst` |
116
- | PRD exists for the feature but is thin / sized wrong | Handoff `/sheldon` |
117
- | Visual direction unclear or UI system not defined | Handoff `/ux-ui` |
118
- | Vague scope, unclear readiness, contradictions | Handoff `/discovery-design-doc` |
119
- | Larger structured implementation batch that no longer fits pair conversation | Handoff `/dev` |
120
- | Formal QA / risk review or test pass requested | Handoff `/qa` |
113
+ | New feature, new module, or cross-product surface | Handoff `/aioson:agent:product` |
114
+ | Decision affects multiple modules / system-wide architecture | Handoff `/aioson:agent:architect` |
115
+ | Missing domain rules, entities, or brownfield knowledge gap | Handoff `/aioson:agent:analyst` |
116
+ | PRD exists for the feature but is thin / sized wrong | Handoff `/aioson:agent:sheldon` |
117
+ | Visual direction unclear or UI system not defined | Handoff `/aioson:agent:ux-ui` |
118
+ | Vague scope, unclear readiness, contradictions | Handoff `/aioson:agent:discovery-design-doc` |
119
+ | Larger structured implementation batch that no longer fits pair conversation | Handoff `/aioson:agent:dev` |
120
+ | Formal QA / risk review or test pass requested | Handoff `/aioson:agent:qa` |
121
121
 
122
122
  **Tie-breakers when two rows apply:**
123
123
  1. If the request is ambiguous, escalate (handoff) instead of handling.
@@ -136,7 +136,7 @@ When the rubric routes here ("Diagnosis ambiguous; needs survey of >5 files or t
136
136
  - **Claude Code**: Agent tool with `tools: [Read, Grep]`, `disallowedTools: [Bash, Edit, Write]`, `prompt = <returned string>`. Sub-agent writes JSON to the returned `output_path`.
137
137
  - **Codex MultiAgentV2**: spawn subagent with the prompt; collect JSON from `output_path`.
138
138
  - **Other harnesses lacking isolated sub-agent**: use the CLI-less fallback below.
139
- 4. `aioson scout:validate . --json --input=<output_path>`. On `schema_invalid`, re-prompt the sub-agent with `error.details`. On `retry_exhausted`, surface to user and offer manual `/architect` or `/dev` handoff.
139
+ 4. `aioson scout:validate . --json --input=<output_path>`. On `schema_invalid`, re-prompt the sub-agent with `error.details`. On `retry_exhausted`, surface to user and offer manual `/aioson:agent:architect` or `/aioson:agent:dev` handoff.
140
140
  5. `aioson scout:commit . --json --input=<output_path>` — telemetry emitted, cap counter decremented.
141
141
  6. Read `findings`/`recommendation` from the persisted JSON; fold into your reply. Parent context grew ~500 tokens (the report) instead of 5000+ (the surveyed files).
142
142
 
@@ -172,7 +172,7 @@ Dispatch via harness sub-agent with the tool whitelist `[Read, Grep]`. Read the
172
172
 
173
173
  ### Cap discipline (both paths)
174
174
 
175
- - Default: max **3 scouts per parent session**. If you've dispatched 3 and still need more, the rubric's next row applies — handoff to `/architect`.
175
+ - Default: max **3 scouts per parent session**. If you've dispatched 3 and still need more, the rubric's next row applies — handoff to `/aioson:agent:architect`.
176
176
  - Default: max **20 files per scout scope**. If a survey naturally needs more, split into two scouts with disjoint scopes.
177
177
  - Defaults are tunable in `.aioson/config/scout-engine.json`.
178
178