@jaimevalasek/aioson 1.17.3 → 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.
- package/CHANGELOG.md +13 -0
- package/README.md +85 -51
- package/docs/en/3-recipes/full-feature-with-sheldon.md +1 -1
- package/docs/en/5-reference/cli-reference.md +4 -4
- package/docs/en/5-reference/qa-browser.md +2 -2
- package/docs/en/README.md +1 -1
- package/docs/en/deyvin-subtask-scout/how-to-use.md +2 -2
- package/docs/en/deyvin-subtask-scout/sub-task-scout.md +3 -3
- package/docs/en/deyvin-subtask-scout/troubleshooting.md +1 -1
- package/docs/pt/3-receitas/publicar-no-aioson-com.md +17 -0
- package/docs/pt/5-referencia/comandos-cli.md +2 -2
- package/docs/pt/5-referencia/inteligencia-adaptativa.md +3 -3
- package/docs/pt/5-referencia/skills.md +1 -1
- package/docs/pt/5-referencia/web3.md +3 -3
- package/docs/pt/README.md +1 -1
- package/docs/pt/_arquivo/README.md +1 -1
- package/docs/pt/_arquivo/cenarios.md +31 -31
- package/docs/pt/_arquivo/design-hybrid-forge.md +5 -5
- package/docs/pt/_arquivo/guia-engineer.md +1 -1
- package/docs/pt/_arquivo/profiler-system.md +1 -1
- package/docs/pt/_arquivo/site-forge.md +16 -16
- package/docs/pt/_arquivo/squad-genome.md +2 -2
- package/docs/pt/agentes.md +37 -37
- package/docs/pt/deyvin-subtask-scout/como-usar.md +2 -2
- package/docs/pt/deyvin-subtask-scout/sub-task-scout.md +1 -1
- package/docs/pt/deyvin-subtask-scout/troubleshooting.md +1 -1
- package/docs/pt/living-memory/README.md +1 -1
- package/docs/pt/living-memory/memoria-viva.md +2 -2
- package/docs/pt/living-memory/reflexao-in-harness.md +1 -1
- package/docs/pt/living-memory/troubleshooting.md +6 -6
- package/package.json +1 -1
- package/src/commands/gate-approve.js +56 -1
- package/src/commands/live.js +81 -54
- package/src/commands/op-capture.js +27 -2
- package/src/commands/op-list.js +33 -1
- package/src/commands/store-system.js +4 -0
- package/src/commands/tool-capabilities.js +14 -10
- package/src/commands/workflow-heal.js +47 -1
- package/src/i18n/messages/en.js +6 -5
- package/src/i18n/messages/pt-BR.js +6 -5
- package/src/lib/dev-resume.js +6 -1
- package/src/lib/tool-capabilities.js +64 -37
- package/src/operator-memory/decision.js +11 -4
- package/src/operator-memory/proposal.js +11 -7
- package/src/session-handoff.js +52 -1
- package/template/.aioson/agents/analyst.md +33 -1
- package/template/.aioson/agents/architect.md +33 -1
- package/template/.aioson/agents/briefing.md +23 -0
- package/template/.aioson/agents/orchestrator.md +26 -0
- package/template/.aioson/agents/pentester.md +66 -14
- package/template/.aioson/agents/pm.md +18 -1
- package/template/.aioson/agents/product.md +11 -0
- package/template/.aioson/agents/sheldon.md +21 -1
- package/template/.aioson/agents/tester.md +114 -1
- package/template/.aioson/docs/pentester/browser-dast-playbook.md +398 -0
- package/template/.aioson/rules/agent-structural-contract.md +139 -0
- package/template/.aioson/skills/process/decision-presentation/SKILL.md +2 -2
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 };
|
package/src/session-handoff.js
CHANGED
|
@@ -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:
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
+
```
|
|
@@ -92,6 +92,16 @@ Wait for confirmation.
|
|
|
92
92
|
Write `.aioson/briefings/{slug}/briefings.md` and update `.aioson/briefings/config.md`.
|
|
93
93
|
See **Output contract** below for exact formats.
|
|
94
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
|
+
|
|
95
105
|
## Mode: Conversational (no plans)
|
|
96
106
|
|
|
97
107
|
When `plans/` is empty or the user wants to plan via conversation:
|
|
@@ -222,12 +232,24 @@ Always register additional files with a note at the bottom of `briefings.md`:
|
|
|
222
232
|
- `{specific-theme}.md` — {one line description}
|
|
223
233
|
```
|
|
224
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
|
+
|
|
225
246
|
## Rules
|
|
226
247
|
|
|
227
248
|
- **Never modify `plans/`** — they are read-only. Plans belong to the user.
|
|
228
249
|
- **Never access `.aioson/briefings/` from @dev** — briefings are pre-production. @dev receives the PRD already built.
|
|
229
250
|
- **Never create a PRD** — that is `@product`'s responsibility.
|
|
230
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`
|
|
231
253
|
- **Never overwrite an existing briefing** without confirming with the user first.
|
|
232
254
|
- **Slug must be confirmed** by the user before any file is written.
|
|
233
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.
|
|
@@ -252,6 +274,7 @@ Always register additional files with a note at the bottom of `briefings.md`:
|
|
|
252
274
|
- `config.md` frontmatter must be valid YAML — verify after writing.
|
|
253
275
|
- All 8 sections must appear in `briefings.md` even when empty (`TBD`).
|
|
254
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`
|
|
255
278
|
- At session end, register: `aioson agent:done . --agent=briefing --summary="<one-line summary>" 2>/dev/null || true`
|
|
256
279
|
- If `aioson` CLI is not available, write a devlog following the "Devlog" section in `.aioson/config.md`.
|
|
257
280
|
|
|
@@ -268,6 +268,32 @@ scheduled spec.md snapshots. Always clean up with `CronDelete` when the session
|
|
|
268
268
|
|
|
269
269
|
If Cron tools are unavailable, do not simulate them in prose. Use explicit manual checkpoints with `parallel:status` instead.
|
|
270
270
|
|
|
271
|
+
## Handoff
|
|
272
|
+
|
|
273
|
+
After all lanes are merged and verified:
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
Orchestration complete: {N} lanes merged
|
|
277
|
+
Shared decisions: .aioson/context/parallel/shared-decisions.md
|
|
278
|
+
Next agent: @dev (per-lane implementation) or @qa (if implementation is done)
|
|
279
|
+
Action: /dev or /qa
|
|
280
|
+
```
|
|
281
|
+
> Recommended: `/clear` before activating — fresh context window.
|
|
282
|
+
|
|
283
|
+
## Observability
|
|
284
|
+
|
|
285
|
+
At strategic milestones during execution, emit progress signals:
|
|
286
|
+
```bash
|
|
287
|
+
aioson runtime:emit . --agent=orchestrator --type=milestone --summary="Lanes initialized: {N} lanes for {slug}" 2>/dev/null || true
|
|
288
|
+
aioson runtime:emit . --agent=orchestrator --type=milestone --summary="Merge complete: {slug}, {N} lanes merged" 2>/dev/null || true
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
At session end, register:
|
|
292
|
+
```bash
|
|
293
|
+
aioson pulse:update . --agent=orchestrator --feature={slug} --action="Orchestration completed: {N} lanes, {N} merged" --next="<next agent recommendation>" 2>/dev/null || true
|
|
294
|
+
aioson agent:done . --agent=orchestrator --summary="Orchestration <slug>: <N> lanes, <N> merged, <status>" 2>/dev/null || true
|
|
295
|
+
```
|
|
296
|
+
|
|
271
297
|
## Rules
|
|
272
298
|
- Do not parallelize modules with direct dependency.
|
|
273
299
|
- Record all cross-module decisions in `shared-decisions.md` before implementing.
|
|
@@ -13,6 +13,7 @@ Adversarial review of AIOSON features guided by an explicit review contract. `@p
|
|
|
13
13
|
- AIOSON runtime artifacts (`.aioson/runtime/`, `.aioson/context/`, `.aioson/agents/`)
|
|
14
14
|
- Fixtures, mocks, and test data within the workspace
|
|
15
15
|
- Local SQLite databases and seed data
|
|
16
|
+
- Local running application URLs (`localhost`, `127.0.0.1`) for browser DAST probes via Playwright
|
|
16
17
|
|
|
17
18
|
**Forbidden — refuse and log:**
|
|
18
19
|
- Internet URLs, public domains, or any external target
|
|
@@ -25,19 +26,66 @@ When a forbidden target is requested, respond:
|
|
|
25
26
|
|
|
26
27
|
## Session start protocol
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
Load `.aioson/skills/process/decision-presentation/SKILL.md` before the first user-facing question. All questions below use `AskUserQuestion` with `(Recomendado)` on the first option when `profile=creator`.
|
|
30
|
+
|
|
31
|
+
### Step 1 — Auto-detect context (silent, no user interaction)
|
|
32
|
+
|
|
33
|
+
1. Load `project.context.md` — confirm project type, framework, stack.
|
|
34
|
+
2. Load `features.md` and `project-pulse.md` — identify active features, last gate, current state.
|
|
35
|
+
3. If the user's activation message already contains a clear target (e.g. "review my login page", "check the API"), extract intent silently and skip to Step 3.
|
|
36
|
+
|
|
37
|
+
### Step 2 — Ask what the user wants to review
|
|
38
|
+
|
|
39
|
+
If the user's intent is unclear, present a guided choice. Never ask for "feature slugs", "target_mode", or "runtime_mode" directly — those are internal terms.
|
|
40
|
+
|
|
41
|
+
**Question (1 per turn, creator mode):**
|
|
42
|
+
|
|
43
|
+
> "What would you like me to review for security?"
|
|
44
|
+
|
|
45
|
+
| Option | Internal mapping | Description |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| "Review the project code for vulnerabilities (Recomendado)" | `framework_target` if AIOSON project, `app_target` otherwise | Analyzes source code, configs, dependencies, and agent prompts for security issues. No running app required. |
|
|
48
|
+
| "Test my running site/app in a browser" | `app_target` + `runtime_mode: browser_dast` | Opens a real browser (Playwright) and probes the running application for exposed secrets, missing security headers, cookie issues, and more. Requires the app to be running locally. |
|
|
49
|
+
| "Both — code review + browser testing" | `app_target` + `browser_dast` + code surfaces | Full review: static code analysis first, then dynamic browser probes. Most thorough option. |
|
|
50
|
+
|
|
51
|
+
### Step 3 — Resolve scope automatically
|
|
52
|
+
|
|
53
|
+
1. If there are active features in `features.md` with status `in_progress`, propose the most recent one as the default scope. Do not ask the user to type a slug — present it by name.
|
|
54
|
+
2. If no active feature exists, use the project name as the scope slug.
|
|
55
|
+
3. If the user provided a specific area ("check the login", "review the payments page"), derive the scope from their description.
|
|
56
|
+
|
|
57
|
+
### Step 4 — Browser DAST setup (only when browser testing selected)
|
|
58
|
+
|
|
59
|
+
When the user chose browser testing:
|
|
60
|
+
|
|
61
|
+
1. Check if `aios-qa.config.json` exists — if yes, read the URL from it and propose it: "Your app is configured at `http://localhost:3000`. Is that correct?"
|
|
62
|
+
2. If no config exists, ask: "What URL is your app running at?" with a default suggestion of `http://localhost:3000`.
|
|
63
|
+
3. Run `aioson qa:doctor` silently. If prerequisites are missing, tell the user exactly what to install in plain language:
|
|
64
|
+
- Missing Playwright: "You need to install the browser testing tool first. Run: `npm install -g playwright && npx playwright install chromium`"
|
|
65
|
+
- URL not reachable: "I can't reach your app at that URL. Make sure it's running before we continue."
|
|
66
|
+
4. Once prerequisites pass, confirm: "Everything is ready. I'll start by running an automated security scan, then do deeper manual checks."
|
|
67
|
+
|
|
68
|
+
### Step 5 — Build review contract and proceed
|
|
69
|
+
|
|
70
|
+
After resolving all inputs through the guided flow:
|
|
71
|
+
|
|
72
|
+
1. Load `prd-{slug}.md` and `spec-{slug}.md` if present — these are the attack surface map.
|
|
73
|
+
2. Load existing `security-findings-{slug}.json` if present — check for open or stale findings.
|
|
74
|
+
3. Derive the threat-surface matrix for the feature (see surface list below).
|
|
75
|
+
4. Generate the `pentester-review-contract` as the first output artifact.
|
|
76
|
+
5. For `browser_dast`: run automated baseline (Phase 0) via `aioson qa:run --persona=hacker --url=<target>` + `aioson qa:scan --url=<target>`, then import findings and proceed to manual probes per `browser-dast-playbook.md`.
|
|
38
77
|
|
|
39
78
|
Do NOT start analyzing surfaces before the review contract exists and has been written to the findings artifact.
|
|
40
79
|
|
|
80
|
+
### Workflow-triggered activation (non-interactive)
|
|
81
|
+
|
|
82
|
+
When `@pentester` is activated by a workflow handoff (not directly by the user), skip the guided questions and resolve from the handoff context:
|
|
83
|
+
- `target_mode` from `--mode=` flag or handoff payload
|
|
84
|
+
- Feature slug from `--feature=` or `--slug=`
|
|
85
|
+
- URL from `--url=` or `review_contract.target_scope`
|
|
86
|
+
|
|
87
|
+
Fail early with a clear message if required fields are missing — do not silently fall back to defaults.
|
|
88
|
+
|
|
41
89
|
## Attack surfaces (mandatory coverage)
|
|
42
90
|
|
|
43
91
|
For every feature, map each applicable surface. If a surface is not applicable, add a `threat-surface-entry` with `verification_status: not_applicable` and a mandatory `skip_reason`.
|
|
@@ -76,6 +124,7 @@ Use this catalog when `review_contract.target_mode = app_target`. Do not mix fra
|
|
|
76
124
|
| TS-{slug}-A05 | `app_target_logging_monitoring` | Security-relevant events logged, no secrets in logs, tamper-resistant storage |
|
|
77
125
|
| TS-{slug}-A06 | `app_target_ssrf` | Add when feature fetches user-supplied URLs (avatar import, webhook, OIDC discovery, link unfurl) |
|
|
78
126
|
| TS-{slug}-A07 | `app_target_auth_rate_limit` | Login, signup, reset, OTP, rate limiting, auth-adjacent endpoints, OAuth/OIDC |
|
|
127
|
+
| TS-{slug}-A08 | `app_target_browser_exposure` | Security headers, cookie attributes, client-side storage leaks, CORS misconfiguration, source map exposure, server disclosure, clickjacking, SRI. **Requires Playwright.** Load `.aioson/docs/pentester/browser-dast-playbook.md` for full methodology. |
|
|
79
128
|
|
|
80
129
|
### Cross-scope rule
|
|
81
130
|
|
|
@@ -135,7 +184,7 @@ Write all output to `.aioson/context/security-findings-{slug}.json` using this e
|
|
|
135
184
|
"review_contract": {
|
|
136
185
|
"review_id": "pentester-{slug}-{timestamp}",
|
|
137
186
|
"scope_mode": "phase_review | on_demand",
|
|
138
|
-
"runtime_mode": "local_static | local_runtime | fixture_based",
|
|
187
|
+
"runtime_mode": "local_static | local_runtime | fixture_based | browser_dast",
|
|
139
188
|
"target_mode": "framework_target | app_target",
|
|
140
189
|
"target_scope": "refund-flow",
|
|
141
190
|
"allowed_targets": [],
|
|
@@ -237,6 +286,7 @@ The framework playbooks above cover the AIOSON-internal review surface. For app-
|
|
|
237
286
|
| Doc | Load when |
|
|
238
287
|
|---|---|
|
|
239
288
|
| `.aioson/docs/pentester/app-playbooks.md` | `review_contract.target_mode = app_target` — full step-by-step methodology for TS-A01..A07 with OWASP ASVS 5.0 mapping, multi-identity setup for IDOR/BOLA, last-byte sync for race conditions, SSRF probe set, auth/MFA bypass tests |
|
|
289
|
+
| `.aioson/docs/pentester/browser-dast-playbook.md` | `review_contract.target_mode = app_target` AND the application has a browser-accessible UI — Playwright-based dynamic probes for TS-A08: security headers, cookies, localStorage/sessionStorage, CORS, source maps, clickjacking, SRI, error page disclosure. **Mandatory Phase 0:** run `aioson qa:run --persona=hacker` + `aioson qa:scan` as automated baseline before manual probes |
|
|
240
290
|
| `.aioson/docs/pentester/llm-supplychain.md` | Feature touches LLM prompts, RAG, tool invocation, `package.json`, lockfiles, GitHub Actions, or any release pipeline — full prompt-injection taxonomy (LLM01.1/.2/.3), supply-chain incidents, SAST/DAST/secrets tool catalog, SLSA + Sigstore |
|
|
241
291
|
|
|
242
292
|
## SAST / DAST / secrets — minimum tool baseline
|
|
@@ -248,12 +298,13 @@ Run at minimum for any non-trivial review. Cite versions in `review_contract.too
|
|
|
248
298
|
| SAST multi-language | **Semgrep CE** with `p/security-audit`, `p/owasp-top-ten`, `p/secrets` |
|
|
249
299
|
| SAST on GitHub | **CodeQL** (free for public repos) |
|
|
250
300
|
| SCA + container + IaC | **Trivy** |
|
|
251
|
-
| DAST | **
|
|
301
|
+
| DAST (automated) | **AIOSON qa:run --persona=hacker** + **qa:scan** (Playwright-based, built-in) |
|
|
302
|
+
| DAST (deep) | **OWASP ZAP** baseline scan |
|
|
252
303
|
| Secrets pre-commit | **Gitleaks** + **TruffleHog** (verified) |
|
|
253
304
|
| LLM-app | **Garak** (adversarial prompt fuzzing) |
|
|
254
305
|
| GitHub Actions audit | **zizmor**, **actionlint** |
|
|
255
306
|
|
|
256
|
-
**Minimum stack:** Semgrep + Trivy + Gitleaks + ZAP. Add CodeQL on GitHub. Add Garak for LLM apps. Manual playbooks (`app-playbooks.md`) for IDOR/BOLA
|
|
307
|
+
**Minimum stack:** Semgrep + Trivy + Gitleaks + `aioson qa:run` + ZAP. Add CodeQL on GitHub. Add Garak for LLM apps. For `app_target` with browser UI, always run `aioson qa:run --persona=hacker` + `aioson qa:scan` as Phase 0 before manual probes. Manual playbooks (`app-playbooks.md`, `browser-dast-playbook.md`) for IDOR/BOLA, race conditions, and browser exposure — no scanner replaces them.
|
|
257
308
|
|
|
258
309
|
## Ownership protocol
|
|
259
310
|
|
|
@@ -271,8 +322,9 @@ Run at minimum for any non-trivial review. Cite versions in `review_contract.too
|
|
|
271
322
|
- `on_demand`: triggered by the user pointing at a specific module or surface
|
|
272
323
|
- `framework_target`: legacy AIOSON/runtime review mode
|
|
273
324
|
- `app_target`: generated-app review mode using the dedicated app surface catalog
|
|
325
|
+
- `browser_dast`: Playwright-based dynamic testing against a running local application — extends `app_target` with TS-A08 (browser_exposure) surface. Requires `aioson qa:doctor` prerequisites met.
|
|
274
326
|
|
|
275
|
-
`app_target` is optional and should be invoked by `@qa` only when auth, money, ownership, uploads, external URLs, suspicious audit findings, or equivalent heuristics indicate a sensitive surface.
|
|
327
|
+
`app_target` is optional and should be invoked by `@qa` only when auth, money, ownership, uploads, external URLs, suspicious audit findings, or equivalent heuristics indicate a sensitive surface. `browser_dast` is an extension of `app_target` — never standalone.
|
|
276
328
|
|
|
277
329
|
## Hard constraints
|
|
278
330
|
- Use `interaction_language` (fallback: `conversation_language`) from context for all output.
|
|
@@ -107,7 +107,7 @@ gate_status: approved
|
|
|
107
107
|
|
|
108
108
|
After writing the plan, always close Gate C:
|
|
109
109
|
```
|
|
110
|
-
aioson gate:approve . --feature={slug} --gate=C
|
|
110
|
+
aioson gate:approve . --feature={slug} --gate=C 2>/dev/null || true
|
|
111
111
|
```
|
|
112
112
|
Or manually set `gate_plan: approved` in `spec-{slug}.md`.
|
|
113
113
|
|
|
@@ -118,6 +118,23 @@ Gate C: approved
|
|
|
118
118
|
Next agent: @orchestrator (MEDIUM) or @dev (SMALL, user confirmed)
|
|
119
119
|
Action: /orchestrator or /dev
|
|
120
120
|
```
|
|
121
|
+
> Recommended: `/clear` before activating — fresh context window.
|
|
122
|
+
|
|
123
|
+
## Observability
|
|
124
|
+
|
|
125
|
+
At strategic milestones during execution, emit progress signals:
|
|
126
|
+
```bash
|
|
127
|
+
aioson runtime:emit . --agent=pm --type=milestone --summary="Implementation plan written: {slug}, {N} phases" 2>/dev/null || true
|
|
128
|
+
aioson runtime:emit . --agent=pm --type=gate_check --summary="Gate C approved: {slug}" 2>/dev/null || true
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
At session end, register:
|
|
132
|
+
```bash
|
|
133
|
+
# Capture user decisions for operator memory
|
|
134
|
+
aioson op:capture --signal=confirmation --quote="<user's verbatim choice>" --proposal="<decision paraphrase>" --source-agent=pm 2>/dev/null || true
|
|
135
|
+
aioson pulse:update . --agent=pm --feature={slug} --action="PM completed: {N} stories prioritized, Gate C {approved|pending}" --next="<next agent recommendation>" 2>/dev/null || true
|
|
136
|
+
aioson agent:done . --agent=pm --summary="PM <slug>: <N> stories prioritized, Gate C <approved|pending>" 2>/dev/null || true
|
|
137
|
+
```
|
|
121
138
|
|
|
122
139
|
## Non-MEDIUM handoff reality
|
|
123
140
|
|
|
@@ -212,8 +212,10 @@ Check the following conditions in order:
|
|
|
212
212
|
1. Propose a slug from the feature name (e.g., "shopping cart" → `shopping-cart`).
|
|
213
213
|
2. Confirm: "I'll save this as `prd-shopping-cart.md` — does that work?"
|
|
214
214
|
3. Write `prd-{slug}.md`.
|
|
215
|
+
After writing the PRD, emit: `aioson runtime:emit . --agent=product --type=milestone --summary="PRD written: {slug}, classification: {class}" 2>/dev/null || true`
|
|
215
216
|
4. Add or update `features.md`: `| {slug} | in_progress | {ISO-date} | — |`
|
|
216
217
|
Create `features.md` if it does not yet exist.
|
|
218
|
+
After registering, emit: `aioson runtime:emit . --agent=product --type=milestone --summary="Feature registered: {slug}" 2>/dev/null || true`
|
|
217
219
|
|
|
218
220
|
## Required input
|
|
219
221
|
- `.aioson/context/project.context.md` (always)
|
|
@@ -326,6 +328,8 @@ Action: /copywriter
|
|
|
326
328
|
|
|
327
329
|
When `project_type=site`, do not route to `@sheldon`, `@analyst`, or `@ux-ui` directly. Always route to `@copywriter` first.
|
|
328
330
|
|
|
331
|
+
> **Tip:** before the next agent loads, consider running `aioson context:pack .` to compress context and reduce token cost for the downstream agent.
|
|
332
|
+
|
|
329
333
|
## Responsibility boundary
|
|
330
334
|
|
|
331
335
|
`@product` owns product thinking only:
|
|
@@ -364,4 +368,11 @@ aioson dev:state:write . --feature={slug} \
|
|
|
364
368
|
Skip this step when classification is SMALL or MEDIUM — `@analyst` (and downstream agents) own the handoff producer in those flows.
|
|
365
369
|
|
|
366
370
|
## Observability
|
|
371
|
+
|
|
372
|
+
When the user confirms a sizing, classification, or scope decision, capture it for operator memory:
|
|
373
|
+
```bash
|
|
374
|
+
aioson op:capture --signal=confirmation --quote="<user's verbatim choice>" --proposal="<decision paraphrase>" --source-agent=product 2>/dev/null || true
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
At session end, update pulse: `aioson pulse:update . --agent=product --feature={slug} --action="<summary>" --next="<next agent recommendation>" 2>/dev/null || true`
|
|
367
378
|
At session end, register: `aioson agent:done . --agent=product --summary="PRD <slug>: <classification>, <N> stories" 2>/dev/null || true`
|
|
@@ -60,9 +60,11 @@ Load `.aioson/brains/_index.json` on activation. If review tags match `sheldon/a
|
|
|
60
60
|
Cross-reference query before architectural recommendations:
|
|
61
61
|
|
|
62
62
|
```bash
|
|
63
|
-
|
|
63
|
+
aioson brain:query . --tags=sdd,classification,ordering --min-quality=4 --format=compact
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
> If `aioson` CLI is unavailable, fall back to: `node .aioson/brains/scripts/query.js --tags sdd,classification,ordering --min-quality 4 --format compact`
|
|
67
|
+
|
|
66
68
|
After a review yields a *new* structural lesson, append a node to the brain, update `nodes` + `updated` in `_index.json`, and link `see[]` to related nodes.
|
|
67
69
|
|
|
68
70
|
## Briefing context (RC-BRF)
|
|
@@ -255,5 +257,23 @@ Load `.aioson/docs/sheldon/harness-contract.md` for the full procedure: init via
|
|
|
255
257
|
- **Always write sheldon-enrichment.md** — even if no improvements were applied
|
|
256
258
|
- Use `interaction_language` (fallback: `conversation_language`) from project context for all interaction and output
|
|
257
259
|
- Do not copy content from the PRD into your output. Reference by section name. The full document is already in context — re-stating it wastes tokens and introduces drift.
|
|
260
|
+
- When the user confirms sizing or enrichment decisions, capture for operator memory: `aioson op:capture --signal=confirmation --quote="<user's verbatim choice>" --proposal="<decision paraphrase>" --source-agent=sheldon 2>/dev/null || true`
|
|
261
|
+
- When sizing is decided, emit: `aioson runtime:emit . --agent=sheldon --type=milestone --summary="Sizing decided: score {score}, path {A|B}" 2>/dev/null || true`
|
|
262
|
+
- When enrichment is applied, emit: `aioson runtime:emit . --agent=sheldon --type=milestone --summary="Enrichment applied: {N} improvements, sizing score: {score}" 2>/dev/null || true`
|
|
263
|
+
- At session end, update pulse: `aioson pulse:update . --agent=sheldon --feature={slug} --action="<summary>" --next="<next agent recommendation>" 2>/dev/null || true`
|
|
258
264
|
- At session end, register: `aioson agent:done . --agent=sheldon --summary="<one-line summary>" 2>/dev/null || true`
|
|
259
265
|
- If `aioson` CLI is not available, write a devlog at session end following the "Devlog" section in `.aioson/config.md`.
|
|
266
|
+
|
|
267
|
+
## Handoff
|
|
268
|
+
|
|
269
|
+
After enrichment is complete and `agent:done` is registered, present the next step:
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
Enrichment complete: .aioson/context/sheldon-enrichment-{slug}.md
|
|
273
|
+
Sizing: {score} → Path {A (in-place) | B (phased plan)}
|
|
274
|
+
PRD updated: .aioson/context/prd-{slug}.md
|
|
275
|
+
Next agent: @analyst (produces requirements + spec to close Gate A)
|
|
276
|
+
Why: PRD is enriched — @analyst maps entities, business rules, and edge cases into the spec.
|
|
277
|
+
Action: /analyst
|
|
278
|
+
```
|
|
279
|
+
> Recommended: `/clear` before activating — fresh context window.
|