odd-studio 3.7.6 → 3.7.8

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "odd-studio",
3
- "version": "3.7.6",
3
+ "version": "3.7.8",
4
4
  "description": "Outcome-Driven Development planning and build harness for domain experts building serious software with AI.",
5
5
  "author": {
6
6
  "name": "ODD Studio"
@@ -149,8 +149,8 @@ build-gate)
149
149
  fi
150
150
 
151
151
  if ! marker_valid ".odd/.odd-flow-agents-ready" 7200; then
152
- echo "ODD STUDIO [build-gate]: Task agents blocked — odd-flow swarm not initialised." >&2
153
- echo "Run the full 9-step swarm init sequence (see *build protocol step 7)." >&2
152
+ echo "ODD STUDIO [build-gate]: Executor agents blocked — odd-flow swarm not initialised." >&2
153
+ echo "Run the full swarm init sequence before dispatching Agent tool work." >&2
154
154
  exit 2
155
155
  fi
156
156
  exit 0
@@ -161,10 +161,10 @@ build-gate)
161
161
  # ─────────────────────────────────────────────────────────────────────────────
162
162
  # Two-marker system:
163
163
  # 1. .odd/.odd-flow-swarm-active — created by *build, 24h TTL (session marker)
164
- # 2. .odd/.odd-flow-agent-token — created by Task agents before each write batch, 120s TTL
164
+ # 2. .odd/.odd-flow-agent-token — created by hooks for active executor agents, 30m TTL
165
165
  #
166
166
  # The orchestrator (main conversation) can read files and coordinate, but CANNOT
167
- # write source code. Only Task agents can, and only after creating the agent token.
167
+ # write source code. Only executor agents can, and only after a fresh agent token exists.
168
168
  # This prevents the LLM from bypassing swarm coordination by editing files directly.
169
169
  swarm-write)
170
170
  [ "$TOOL_NAME" = "Write" ] || [ "$TOOL_NAME" = "Edit" ] || exit 0
@@ -192,11 +192,11 @@ swarm-write)
192
192
  exit 0
193
193
  fi
194
194
 
195
- # Gate 2: Agent write token must be fresh (120s TTL)
196
- # Only Task agents create this token the orchestrator must NOT.
197
- if ! marker_valid ".odd/.odd-flow-agent-token" 120; then
195
+ # Gate 2: Agent write token must be fresh (30m TTL).
196
+ # The hooks mint and refresh this token for active executor agents.
197
+ if ! marker_valid ".odd/.odd-flow-agent-token" 1800; then
198
198
  echo "ODD STUDIO [swarm-write]: Source writes blocked — no agent write token." >&2
199
- echo "Only Task agents can write source code. The orchestrator must dispatch work, not write code directly." >&2
199
+ echo "Dispatch build work with the Agent tool after swarm init. odd-flow agent_spawn only sets coordination metadata." >&2
200
200
  echo "File blocked: $FILE_PATH" >&2
201
201
  exit 2
202
202
  fi
@@ -391,15 +391,16 @@ store-validate)
391
391
  # ─────────────────────────────────────────────────────────────────────────────
392
392
  # PostToolUse: mcp__odd-flow__coordination_sync — completes swarm init
393
393
  # ─────────────────────────────────────────────────────────────────────────────
394
- # coordination_sync is the LAST step of the 9-step swarm init sequence.
394
+ # coordination_sync is the LAST step of the swarm init sequence.
395
395
  # When it fires successfully in build phase, the swarm is initialised — so we
396
- # create all three markers atomically rather than relying on the orchestrator
396
+ # create all required markers atomically rather than relying on the orchestrator
397
397
  # to remember a stray Bash `touch` step buried in a numbered list.
398
398
  #
399
399
  # Markers created:
400
400
  # .odd-flow-swarm-active — gates source writes (24h TTL)
401
- # .odd-flow-agents-ready — unblocks build-gate for Task agents
401
+ # .odd-flow-agents-ready — unblocks build-gate for executor agents
402
402
  # .odd-flow-phase-synced — confirms agents have phase context
403
+ # .odd-flow-agent-token — unlocks source writes for active executor agents
403
404
  sync-validate)
404
405
  [ "$TOOL_NAME" = "mcp__odd-flow__coordination_sync" ] || exit 0
405
406
  [ "$CURRENT_PHASE" = "build" ] || exit 0
@@ -407,6 +408,36 @@ sync-validate)
407
408
  touch .odd/.odd-flow-swarm-active 2>/dev/null
408
409
  touch .odd/.odd-flow-agents-ready 2>/dev/null
409
410
  touch .odd/.odd-flow-phase-synced 2>/dev/null
411
+ touch .odd/.odd-flow-agent-token 2>/dev/null
412
+ exit 0
413
+ ;;
414
+
415
+ # ─────────────────────────────────────────────────────────────────────────────
416
+ # PreToolUse: Agent — mint write token for active executor dispatches
417
+ # ─────────────────────────────────────────────────────────────────────────────
418
+ agent-token-mint)
419
+ [ "$TOOL_NAME" = "Agent" ] || exit 0
420
+ [ "$CURRENT_PHASE" = "build" ] || exit 0
421
+
422
+ AGENT_PROMPT=$(echo "$INPUT" | jq -r '.tool_input.prompt // empty' | head -c 400 | tr '[:upper:]' '[:lower:]')
423
+ if echo "$AGENT_PROMPT" | grep -qiE '(session.brief|session-brief|generate.*brief|write.*brief|odd-sync|fix.*hook|update.*hook)'; then
424
+ exit 0
425
+ fi
426
+
427
+ marker_valid ".odd/.odd-flow-agents-ready" 7200 || exit 0
428
+ touch .odd/.odd-flow-agent-token 2>/dev/null
429
+ exit 0
430
+ ;;
431
+
432
+ # ─────────────────────────────────────────────────────────────────────────────
433
+ # PostToolUse: Write|Edit — refresh write token after successful source writes
434
+ # ─────────────────────────────────────────────────────────────────────────────
435
+ agent-token-refresh)
436
+ [ "$TOOL_NAME" = "Write" ] || [ "$TOOL_NAME" = "Edit" ] || exit 0
437
+ [ "$CURRENT_PHASE" = "build" ] || exit 0
438
+ is_source_file "$FILE_PATH" || exit 0
439
+
440
+ touch .odd/.odd-flow-agent-token 2>/dev/null
410
441
  exit 0
411
442
  ;;
412
443
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "odd-studio",
3
- "version": "3.7.6",
3
+ "version": "3.7.8",
4
4
  "description": "Outcome-Driven Development for AI coding agents — a planning and build harness for domain experts building serious software with AI. Works with Claude Code, OpenCode, and Codex.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -20,7 +20,7 @@ const HALF_HOUR = 1800000;
20
20
  const TWO_HOURS = 7200000;
21
21
  const ONE_DAY = 86400000;
22
22
  const ONE_HOUR = 3600000;
23
- const TWO_MINUTES = 120000;
23
+ const THIRTY_MINUTES = 1800000;
24
24
 
25
25
  function readMarker(name) {
26
26
  return resolve(process.cwd(), '.odd', name);
@@ -62,6 +62,7 @@ export function createBeforeHook(readState) {
62
62
 
63
63
  if (toolName === 'Agent' && state.currentPhase === 'build') {
64
64
  const prompt = (event.input?.prompt || '').slice(0, 300).toLowerCase();
65
+ const isSupportDispatch = prompt.match(/session.brief|session-brief|generate.*brief|write.*brief|odd-sync|fix.*hook|update.*hook/);
65
66
 
66
67
  if (!state.briefConfirmed && !prompt.match(/session.brief|session-brief|generate.*brief|write.*brief/)) {
67
68
  return { blocked: true, message: 'ODD BRIEF GATE: Build agents blocked — session brief not confirmed. Generate and confirm the brief first.' };
@@ -76,9 +77,13 @@ export function createBeforeHook(readState) {
76
77
  if (
77
78
  state.briefConfirmed &&
78
79
  !markerValid(readMarker('.odd-flow-agents-ready'), TWO_HOURS) &&
79
- !prompt.match(/session.brief|session-brief|generate.*brief|odd-sync|fix.*hook|update.*hook/)
80
+ !isSupportDispatch
80
81
  ) {
81
- return { blocked: true, message: 'ODD BUILD GATE: Task agents blocked — odd-flow swarm not initialised. Run the full swarm init sequence.' };
82
+ return { blocked: true, message: 'ODD BUILD GATE: Executor agents blocked — odd-flow swarm not initialised. Run the full swarm init sequence before dispatching Agent tool work.' };
83
+ }
84
+
85
+ if (state.briefConfirmed && !isSupportDispatch && markerValid(readMarker('.odd-flow-agents-ready'), TWO_HOURS)) {
86
+ touchMarker('.odd-flow-agent-token');
82
87
  }
83
88
  }
84
89
 
@@ -89,8 +94,8 @@ export function createBeforeHook(readState) {
89
94
 
90
95
  if (state.debugSession || markerValid(readMarker('.odd-quick-fix'), ONE_HOUR)) return;
91
96
 
92
- if (!markerValid(readMarker('.odd-flow-agent-token'), TWO_MINUTES)) {
93
- return { blocked: true, message: `ODD SWARM WRITE GATE: Source writes blocked — no agent write token. Only Task agents can write source code, not the orchestrator. File: ${filePath}` };
97
+ if (!markerValid(readMarker('.odd-flow-agent-token'), THIRTY_MINUTES)) {
98
+ return { blocked: true, message: `ODD SWARM WRITE GATE: Source writes blocked — no agent write token. Dispatch build work with the Agent tool after swarm init. odd-flow agent_spawn only sets coordination metadata. File: ${filePath}` };
94
99
  }
95
100
  }
96
101
 
@@ -127,6 +132,7 @@ export function createAfterHook(readState, readLastCommit, writeState) {
127
132
  if (toolName === 'Write' && isOutcomeFile(filePath)) warnings.push(...checkOutcomeQuality(filePath));
128
133
  if (toolName === 'Write' && isPersonaFile(filePath)) warnings.push(...checkPersonaQuality(filePath));
129
134
  if ((toolName === 'Write' || toolName === 'Edit') && isSrcFile(filePath)) {
135
+ if (state?.currentPhase === 'build') touchMarker('.odd-flow-agent-token');
130
136
  warnings.push(...checkCodeElegance(filePath));
131
137
  warnings.push(...checkSecurityBaseline(filePath));
132
138
  }
@@ -153,6 +159,7 @@ export function createAfterHook(readState, readLastCommit, writeState) {
153
159
  touchMarker('.odd-flow-swarm-active');
154
160
  touchMarker('.odd-flow-agents-ready');
155
161
  touchMarker('.odd-flow-phase-synced');
162
+ touchMarker('.odd-flow-agent-token');
156
163
  }
157
164
 
158
165
  if (warnings.length > 0) return { warnings };
@@ -7,6 +7,7 @@ export const HOOK_GROUPS = [
7
7
  gates: [
8
8
  { name: 'brief-gate', timeout: 5, status: 'ODD brief gate...' },
9
9
  { name: 'build-gate', timeout: 5, status: 'ODD build gate...' },
10
+ { name: 'agent-token-mint', timeout: 5, status: 'ODD agent token...' },
10
11
  ],
11
12
  },
12
13
  {
@@ -38,6 +39,7 @@ export const HOOK_GROUPS = [
38
39
  event: 'PostToolUse',
39
40
  matcher: 'Write',
40
41
  gates: [
42
+ { name: 'agent-token-refresh', timeout: 5, status: 'ODD agent token refresh...' },
41
43
  { name: 'plan-complete-gate', timeout: 5, status: 'ODD plan complete gate...' },
42
44
  ],
43
45
  },
@@ -45,6 +47,7 @@ export const HOOK_GROUPS = [
45
47
  event: 'PostToolUse',
46
48
  matcher: 'Edit',
47
49
  gates: [
50
+ { name: 'agent-token-refresh', timeout: 5, status: 'ODD agent token refresh...' },
48
51
  { name: 'plan-complete-gate', timeout: 5, status: 'ODD plan complete gate...' },
49
52
  ],
50
53
  },
@@ -47,13 +47,7 @@ export default async function installCommands(packageRoot, targetDir, options =
47
47
  const skillSource = path.join(packageRoot, 'skill');
48
48
  await fs.copy(skillSource, oddKnowledge, { overwrite: true });
49
49
 
50
- // Rewrite the main SKILL.md path references for OpenCode
51
- const mainSkill = path.join(oddKnowledge, 'SKILL.md');
52
- if (fs.existsSync(mainSkill)) {
53
- let content = await fs.readFile(mainSkill, 'utf8');
54
- content = content.replace(/~\/\.claude\/skills\/odd\//g, '.opencode/odd/');
55
- await fs.writeFile(mainSkill, content);
56
- }
50
+ await rewriteSkillPaths(oddKnowledge);
57
51
 
58
52
  // Generate the /odd command that loads the main skill
59
53
  const oddCmd = [
@@ -76,3 +70,13 @@ export default async function installCommands(packageRoot, targetDir, options =
76
70
 
77
71
  return { destination: OC_COMMANDS, commandCount: COMMANDS.length };
78
72
  }
73
+
74
+ async function rewriteSkillPaths(rootDir) {
75
+ const skillFiles = await fs.glob(path.join(rootDir, '**', 'SKILL.md'));
76
+ for (const filePath of skillFiles) {
77
+ let content = await fs.readFile(filePath, 'utf8');
78
+ content = content.replace(/~\/\.claude\/skills\/odd\//g, '.opencode/odd/');
79
+ content = content.replace(/\.claude\/skills\/odd\//g, '.opencode/odd/');
80
+ await fs.writeFile(filePath, content);
81
+ }
82
+ }
package/skill/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: "odd"
3
- version: "3.7.6"
3
+ version: "3.7.8"
4
4
  description: "Outcome-Driven Development planning and build coach. Use /odd to start or resume an ODD project — building personas, writing outcomes, mapping contracts, creating a Master Implementation Plan, and directing a odd-flow-powered build. Designed for domain experts who are not developers. Works with Claude Code, OpenCode, and Codex."
5
5
  metadata:
6
6
  priority: 10
@@ -30,6 +30,57 @@ ODD Studio briefs the build AI with the full six-field specification, the releva
30
30
 
31
31
  The domain expert does not re-brief the AI, paste context, identify shared infrastructure, or check dependencies. ODD Studio handles all of that from odd-flow memory.
32
32
 
33
+ ### Step 2a — Build Execution Loop
34
+
35
+ The orchestrator must execute the build. Do not stop at odd-flow swarm setup, and do not treat `mcp__odd-flow__agent_spawn` as the code-writing step. Those calls only register coordination metadata.
36
+
37
+ After `coordination_sync` succeeds, run this loop:
38
+
39
+ 1. Read the active session brief and identify the outcomes in scope for this build session.
40
+ 2. For each in-scope outcome, break the work into concrete implementation stages. Use the smallest set that fits the outcome:
41
+ - data/contracts
42
+ - business logic/services
43
+ - UI/screens
44
+ - tests
45
+ - verification fixes
46
+ 3. Dispatch the real implementation work with the runtime executor agent tool. In Claude/Codex-style runtimes, this is the `Agent` tool. Use implementation agents for code changes and wait for each one to finish before moving to the next dependent stage.
47
+ 4. After each agent completes, inspect the returned summary, review the changed files, and decide the next stage:
48
+ - if the stage is complete, dispatch the next dependent stage
49
+ - if the stage exposed a gap or regression, dispatch a follow-up fix agent before continuing
50
+ - if stages are independent, you may dispatch them in parallel only when they do not write the same files
51
+ 5. Continue until the outcome implementation and tests are complete, then run the test gate below.
52
+
53
+ **Executor prompt template**
54
+
55
+ Use this shape for each implementation dispatch:
56
+
57
+ ```text
58
+ You are implementing Stage [stage name] for Outcome [number]: [outcome name].
59
+
60
+ Read first:
61
+ - docs/plan.md
62
+ - docs/outcomes/[active outcome file]
63
+ - docs/session-brief-[n].md
64
+ - docs/contract-map.md (if this stage produces or consumes contracts)
65
+ - docs/ui/design-system.md (if this stage touches UI)
66
+ - docs/build/code-excellence.md
67
+
68
+ Rules:
69
+ - Stay inside this stage and the active outcome only.
70
+ - Design it twice: first working pass, then minimal pass.
71
+ - Do not broaden scope or edit unrelated files.
72
+ - Write or update tests for any pure business logic you introduce.
73
+ - Report any spec gap in plain language before guessing.
74
+
75
+ Deliver:
76
+ - implement the stage
77
+ - summarise files changed
78
+ - report tests run and results
79
+ - call out any follow-up stage the orchestrator should run next
80
+ ```
81
+
82
+ For `*swarm`, run the same loop per independent outcome. Keep one executor agent per outcome track, then converge on QA and verification after implementation agents finish.
83
+
33
84
  ---
34
85
 
35
86
  ### Step 2b — Test
@@ -60,5 +60,13 @@ When `coordination_sync` succeeds in build phase, the hook activates:
60
60
  - `.odd/.odd-flow-swarm-active`
61
61
  - `.odd/.odd-flow-agents-ready`
62
62
  - `.odd/.odd-flow-phase-synced`
63
+ - `.odd/.odd-flow-agent-token`
63
64
 
64
65
  Do not manually touch these markers.
66
+
67
+ **Important:** the odd-flow `agent_spawn` calls above are coordination metadata only. They register roles, contracts, and phase context in odd-flow, but they do not execute code changes themselves.
68
+
69
+ After swarm initialisation completes, dispatch the actual build work with your runtime's executor agent tool:
70
+ - In Claude/Codex-style runtimes, use the `Agent` tool for implementation work.
71
+ - Treat odd-flow as the coordination layer and the `Agent` tool as the code-writing executor.
72
+ - Do not stop after `coordination_sync`. The next action is to start the Build Execution Loop in `docs/build/build-protocol.md`.
@@ -20,7 +20,7 @@ If this is a new project, display this welcome message:
20
20
 
21
21
  ---
22
22
 
23
- Welcome to ODD Studio v3.7.6.
23
+ Welcome to ODD Studio v3.7.8.
24
24
 
25
25
  You are about to plan and build something real — using a methodology called Outcome-Driven Development. Before we write a single line of code, we are going to get precise about three things:
26
26
 
@@ -42,7 +42,7 @@ If this is a returning project, display this status message with real values fro
42
42
 
43
43
  ---
44
44
 
45
- Welcome back to ODD Studio v3.7.6.
45
+ Welcome back to ODD Studio v3.7.8.
46
46
 
47
47
  **Project:** [project.name]
48
48
  **Current Phase:** [state.currentPhase]
@@ -43,8 +43,8 @@ You are executing the ODD Studio `*build` command.
43
43
 
44
44
  Execute this flow:
45
45
 
46
- 1. Read `docs/runtime/build-entry.md` from this ODD skill tree.
46
+ 1. Read `.claude/skills/odd/docs/runtime/build-entry.md`.
47
47
  2. Execute the build-entry checks exactly as written.
48
- 3. Then read `docs/build/build-protocol.md` from this ODD skill tree and execute the build flow exactly as written.
48
+ 3. Then read `.claude/skills/odd/docs/build/build-protocol.md` and execute the build flow exactly as written.
49
49
 
50
50
  Do not spawn build agents or write source code before the brief gate passes.
@@ -137,7 +137,7 @@ If more than one strategy seems plausible, do not fix anything yet. Gather one m
137
137
 
138
138
  ## Fix Protocol
139
139
 
140
- After choosing the strategy, load `docs/build/debug-protocol.md` for the detailed investigation procedure for that strategy.
140
+ After choosing the strategy, load `.claude/skills/odd/docs/build/debug-protocol.md` for the detailed investigation procedure for that strategy.
141
141
 
142
142
  When the fix is complete:
143
143
 
@@ -47,10 +47,10 @@ Execute this flow:
47
47
 
48
48
  1. Read `.odd/state.json`.
49
49
  2. Route to the next incomplete planning stage:
50
- - no personas: `docs/planning/persona-architect.md`
51
- - personas exist, no outcomes: `docs/planning/outcome-writer.md`
52
- - outcomes exist, contracts not mapped: `docs/planning/systems-mapper.md`
53
- - contracts mapped, plan not approved: `docs/planning/build-planner.md`
54
- - plan approved, architecture/design docs incomplete: `docs/planning/build-planner.md`
50
+ - no personas: `.claude/skills/odd/docs/planning/persona-architect.md`
51
+ - personas exist, no outcomes: `.claude/skills/odd/docs/planning/outcome-writer.md`
52
+ - outcomes exist, contracts not mapped: `.claude/skills/odd/docs/planning/systems-mapper.md`
53
+ - contracts mapped, plan not approved: `.claude/skills/odd/docs/planning/build-planner.md`
54
+ - plan approved, architecture/design docs incomplete: `.claude/skills/odd/docs/planning/build-planner.md`
55
55
  3. Announce the stage and why it is next before loading the stage document.
56
56
  4. Follow the selected planning document exactly.
@@ -42,5 +42,5 @@ You are executing the ODD Studio `*status` command.
42
42
 
43
43
  Execute this flow:
44
44
 
45
- 1. Read `docs/runtime/status-protocol.md` from this ODD skill tree.
45
+ 1. Read `.claude/skills/odd/docs/runtime/status-protocol.md`.
46
46
  2. Execute the status protocol exactly as written.
@@ -10,7 +10,7 @@ You are executing the ODD Studio `*swarm` command.
10
10
 
11
11
  Execute this flow:
12
12
 
13
- 1. Read `docs/runtime/build-entry.md` from this ODD skill tree.
13
+ 1. Read `.claude/skills/odd/docs/runtime/build-entry.md`.
14
14
  2. Execute the build-entry checks and swarm initialisation exactly as written.
15
- 3. Then read `docs/build/build-protocol.md` from this ODD skill tree.
15
+ 3. Then read `.claude/skills/odd/docs/build/build-protocol.md`.
16
16
  4. Execute the swarm build path for independent outcomes in the current phase.