odd-studio 3.6.0 → 3.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/hooks/odd-studio.sh +50 -2
- package/package.json +1 -1
- package/scripts/setup-hooks.js +2 -0
- package/skill/SKILL.md +12 -5
- package/skill/odd-debug/SKILL.md +120 -14
package/hooks/odd-studio.sh
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
#
|
|
18
18
|
# PostToolUse (exit 0 + stderr = coaching):
|
|
19
19
|
# session-save Bash — auto-save state after git commit
|
|
20
|
+
# state-dirty-mark Write|Edit — marks state.json edits as needing odd-flow store
|
|
20
21
|
# store-validate mcp__odd-flow__memory_store — creates ready marker
|
|
21
22
|
# sync-validate mcp__odd-flow__coordination_sync — creates agents-ready marker
|
|
22
23
|
# code-quality Write|Edit — code elegance check
|
|
@@ -176,6 +177,12 @@ swarm-write)
|
|
|
176
177
|
exit 2
|
|
177
178
|
fi
|
|
178
179
|
|
|
180
|
+
# Debug session bypass: orchestrator writes allowed when *debug mode is active
|
|
181
|
+
DEBUG_SESSION=$(get_state_field "debugSession")
|
|
182
|
+
if [ "$DEBUG_SESSION" = "true" ]; then
|
|
183
|
+
exit 0
|
|
184
|
+
fi
|
|
185
|
+
|
|
179
186
|
# Gate 2: Agent write token must be fresh (120s TTL)
|
|
180
187
|
# Only Task agents create this token — the orchestrator must NOT.
|
|
181
188
|
if ! marker_valid ".odd/.odd-flow-agent-token" 120; then
|
|
@@ -307,6 +314,10 @@ commit-gate)
|
|
|
307
314
|
swarm-guard)
|
|
308
315
|
[ "$CURRENT_PHASE" = "build" ] || exit 0
|
|
309
316
|
|
|
317
|
+
# Suppress all warnings during active debug session — reduced ceremony is the point
|
|
318
|
+
DEBUG_SESSION=$(get_state_field "debugSession")
|
|
319
|
+
[ "$DEBUG_SESSION" = "true" ] && exit 0
|
|
320
|
+
|
|
310
321
|
# Gate 1: Dirty state (commit without odd-flow store)
|
|
311
322
|
if [ -f ".odd/.odd-flow-state-dirty" ]; then
|
|
312
323
|
echo ""
|
|
@@ -433,6 +444,19 @@ plan-complete-gate)
|
|
|
433
444
|
exit 0
|
|
434
445
|
;;
|
|
435
446
|
|
|
447
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
448
|
+
# PostToolUse: Write|Edit state.json — mark dirty so swarm-guard nags until stored
|
|
449
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
450
|
+
# This catches the gap between commit-triggered dirty marking and actual edits.
|
|
451
|
+
# Any edit to state.json (by Claude or by another tool) sets the dirty marker.
|
|
452
|
+
# It's cleared only when mcp__odd-flow__memory_store key=odd-project-state succeeds.
|
|
453
|
+
state-dirty-mark)
|
|
454
|
+
[ "$TOOL_NAME" = "Write" ] || [ "$TOOL_NAME" = "Edit" ] || exit 0
|
|
455
|
+
echo "$FILE_PATH" | grep -q '\.odd/state\.json$' || exit 0
|
|
456
|
+
touch .odd/.odd-flow-state-dirty 2>/dev/null
|
|
457
|
+
exit 0
|
|
458
|
+
;;
|
|
459
|
+
|
|
436
460
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
437
461
|
# PostToolUse: mcp__odd-flow__memory_store — creates ready marker
|
|
438
462
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -442,12 +466,36 @@ store-validate)
|
|
|
442
466
|
|
|
443
467
|
KEY=$(echo "$INPUT" | jq -r '.tool_input.key // empty')
|
|
444
468
|
|
|
445
|
-
|
|
446
|
-
|
|
469
|
+
# MCP responses may be nested under tool_response or at root — check both
|
|
470
|
+
if ! echo "$INPUT" | grep -qE '"success"[[:space:]]*:[[:space:]]*true'; then
|
|
471
|
+
exit 0
|
|
472
|
+
fi
|
|
447
473
|
|
|
448
474
|
# Create the right marker based on what was stored
|
|
449
475
|
case "$KEY" in
|
|
450
476
|
odd-project-state)
|
|
477
|
+
# Reject partial snapshots — the value MUST contain the full state.json shape.
|
|
478
|
+
# Without this, callers can store {currentBuildPhase: "X"} and silently drift.
|
|
479
|
+
VALUE=$(echo "$INPUT" | jq -c '.tool_input.value // empty' 2>/dev/null)
|
|
480
|
+
if [ -n "$VALUE" ] && [ "$VALUE" != "null" ] && [ "$VALUE" != "empty" ]; then
|
|
481
|
+
MISSING=$(echo "$VALUE" | jq -r '
|
|
482
|
+
[
|
|
483
|
+
(if has("personas") then empty else "personas" end),
|
|
484
|
+
(if has("outcomes") then empty else "outcomes" end),
|
|
485
|
+
(if has("currentBuildPhase") then empty else "currentBuildPhase" end),
|
|
486
|
+
(if has("currentPhase") then empty else "currentPhase" end)
|
|
487
|
+
] | join(", ")
|
|
488
|
+
' 2>/dev/null)
|
|
489
|
+
if [ -n "$MISSING" ]; then
|
|
490
|
+
echo "" >&2
|
|
491
|
+
echo "ODD STUDIO [store-validate]: Partial odd-project-state rejected." >&2
|
|
492
|
+
echo "Missing required keys: $MISSING" >&2
|
|
493
|
+
echo "Store the FULL contents of .odd/state.json, not a hand-built object." >&2
|
|
494
|
+
echo "" >&2
|
|
495
|
+
# Do NOT clear the dirty marker — the next store must include the full file
|
|
496
|
+
exit 0
|
|
497
|
+
fi
|
|
498
|
+
fi
|
|
451
499
|
touch .odd/.odd-flow-state-ready 2>/dev/null
|
|
452
500
|
rm -f .odd/.odd-flow-state-dirty 2>/dev/null
|
|
453
501
|
;;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "odd-studio",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.1",
|
|
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",
|
package/scripts/setup-hooks.js
CHANGED
|
@@ -66,6 +66,7 @@ const GATES = [
|
|
|
66
66
|
matcher: 'Write',
|
|
67
67
|
gates: [
|
|
68
68
|
{ name: 'plan-complete-gate', timeout: 5, status: 'ODD plan complete gate...' },
|
|
69
|
+
{ name: 'state-dirty-mark', timeout: 5, status: 'ODD state dirty mark...' },
|
|
69
70
|
],
|
|
70
71
|
},
|
|
71
72
|
{
|
|
@@ -73,6 +74,7 @@ const GATES = [
|
|
|
73
74
|
matcher: 'Edit',
|
|
74
75
|
gates: [
|
|
75
76
|
{ name: 'plan-complete-gate', timeout: 5, status: 'ODD plan complete gate...' },
|
|
77
|
+
{ name: 'state-dirty-mark', timeout: 5, status: 'ODD state dirty mark...' },
|
|
76
78
|
],
|
|
77
79
|
},
|
|
78
80
|
{
|
package/skill/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "odd"
|
|
3
|
-
version: "3.
|
|
3
|
+
version: "3.7.1"
|
|
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
|
|
@@ -84,8 +84,15 @@ Before doing anything else, run this state check silently:
|
|
|
84
84
|
2. Check whether `docs/plan.md` exists.
|
|
85
85
|
3. Attempt to retrieve project state from odd-flow memory:
|
|
86
86
|
- Call `mcp__odd-flow__memory_retrieve` with key `odd-project-state`, namespace `odd-project`
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
4. **Reconciliation — strict, no silent merging.** If both local and odd-flow state exist, compare them field-by-field. Specifically check `currentBuildPhase`, `currentPhase`, `briefConfirmed`, `sessionBriefCount`, `personas.length`, and `outcomes.length`. If ANY of these disagree:
|
|
88
|
+
- **STOP.** Do not display the welcome or status message yet.
|
|
89
|
+
- Show the user a side-by-side diff of the disagreeing fields (local value vs odd-flow value).
|
|
90
|
+
- Ask explicitly: "Local state and odd-flow state have drifted. Which should I trust as authoritative? Type `local`, `odd-flow`, or `inspect` to see the full diff."
|
|
91
|
+
- On `local`: store the full local `state.json` to odd-flow with `mcp__odd-flow__memory_store` and proceed.
|
|
92
|
+
- On `odd-flow`: write the odd-flow value to `.odd/state.json` and proceed.
|
|
93
|
+
- On `inspect`: print the full diff and ask again.
|
|
94
|
+
- Do NOT use heuristics like "richer wins" or "later phase wins" — they hide bugs. The user decides.
|
|
95
|
+
5. If local exists and odd-flow does not: store local to odd-flow immediately. If odd-flow exists and local does not: write odd-flow to local immediately.
|
|
89
96
|
|
|
90
97
|
**If this is a new project** (no state found anywhere), display the welcome message below.
|
|
91
98
|
|
|
@@ -99,7 +106,7 @@ Display this when no existing state is found:
|
|
|
99
106
|
|
|
100
107
|
---
|
|
101
108
|
|
|
102
|
-
Welcome to ODD Studio v3.
|
|
109
|
+
Welcome to ODD Studio v3.7.1.
|
|
103
110
|
|
|
104
111
|
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:
|
|
105
112
|
|
|
@@ -123,7 +130,7 @@ Display this when existing state is found. Replace the bracketed values with act
|
|
|
123
130
|
|
|
124
131
|
---
|
|
125
132
|
|
|
126
|
-
Welcome back to ODD Studio v3.
|
|
133
|
+
Welcome back to ODD Studio v3.7.1.
|
|
127
134
|
|
|
128
135
|
**Project:** [project.name]
|
|
129
136
|
**Current Phase:** [state.currentPhase]
|
package/skill/odd-debug/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "odd-debug"
|
|
3
|
-
version: "
|
|
4
|
-
description: "ODD Studio debug command.
|
|
3
|
+
version: "2.0.0"
|
|
4
|
+
description: "ODD Studio debug command. Activates a lightweight debug session (no full swarm init required), selects the correct debug strategy, and routes back to verification instead of drifting outside the ODD flow."
|
|
5
5
|
metadata:
|
|
6
6
|
priority: 9
|
|
7
7
|
pathPatterns:
|
|
@@ -43,18 +43,124 @@ retrieval:
|
|
|
43
43
|
|
|
44
44
|
You are executing the ODD Studio `*debug` command.
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
1. `.claude/skills/odd/SKILL.md` — the full ODD Studio coach and build protocol
|
|
48
|
-
2. `.claude/skills/odd/docs/build/debug-protocol.md` — the Debug Protocol detail
|
|
46
|
+
## What this command does
|
|
49
47
|
|
|
50
|
-
|
|
48
|
+
`*debug` activates a lightweight build session optimised for debugging, hotfixes, and security remediation work. It bypasses the full 9-step swarm init that `*build` requires — there is no agent dispatch, no task creation, no swarm spawn. The orchestrator writes code directly.
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
- `ui-behaviour`
|
|
54
|
-
- `full-stack`
|
|
55
|
-
- `auth-security`
|
|
56
|
-
- `integration-contract`
|
|
57
|
-
- `background-process`
|
|
58
|
-
- `performance-state`
|
|
50
|
+
This is not a shortcut around ODD. The brief-gate, verify-gate, commit-gate, and outcome verification protocol are all still enforced. What is relaxed is the agent-token requirement in `swarm-write` — the requirement that forces every source write through a background Task agent. That requirement exists to enable parallel multi-agent outcome builds. For a single targeted fix it is pure ceremony.
|
|
59
51
|
|
|
60
|
-
|
|
52
|
+
**When to use `*debug` instead of `*build`:**
|
|
53
|
+
- Fixing a failing test suite
|
|
54
|
+
- Applying a security patch
|
|
55
|
+
- Investigating and resolving a verification failure
|
|
56
|
+
- Any single-file or few-file change that does not require parallel agent execution
|
|
57
|
+
|
|
58
|
+
**When to use `*build` instead:**
|
|
59
|
+
- Building a new outcome from scratch
|
|
60
|
+
- Work that benefits from parallel backend + UI + QA agents
|
|
61
|
+
- Phase transitions
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Session Activation
|
|
66
|
+
|
|
67
|
+
Execute these steps before any investigation or fix work. Do them in order.
|
|
68
|
+
|
|
69
|
+
### Step 1 — State check
|
|
70
|
+
|
|
71
|
+
Read `.odd/state.json`. Confirm:
|
|
72
|
+
- `currentPhase` is `"build"` — if not, explain that `*debug` requires an active build phase
|
|
73
|
+
- `planApproved` is `true` — if not, route to `*plan`
|
|
74
|
+
|
|
75
|
+
If either check fails, stop here and explain what is needed.
|
|
76
|
+
|
|
77
|
+
### Step 2 — Activate the debug session marker
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
touch .odd/.odd-flow-swarm-active
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
This creates or refreshes the 24-hour build session marker. The `swarm-write` gate will now allow direct orchestrator writes (because `debugSession: true` bypasses Gate 2).
|
|
84
|
+
|
|
85
|
+
### Step 3 — Set debug session state
|
|
86
|
+
|
|
87
|
+
Update `.odd/state.json`:
|
|
88
|
+
- `debugSession: true`
|
|
89
|
+
- `buildMode: "debug"`
|
|
90
|
+
- `verificationConfirmed: false`
|
|
91
|
+
- `debugStartedAt: <current ISO timestamp>`
|
|
92
|
+
- `debugSummary: <one-sentence description of the issue — or "unknown" if not yet classified>`
|
|
93
|
+
|
|
94
|
+
### Step 4 — Store state to odd-flow
|
|
95
|
+
|
|
96
|
+
Call `mcp__odd-flow__memory_store`:
|
|
97
|
+
- Key: `odd-project-state`
|
|
98
|
+
- Namespace: `odd-project`
|
|
99
|
+
- Value: full contents of `.odd/state.json`
|
|
100
|
+
- upsert: true
|
|
101
|
+
|
|
102
|
+
This single store call satisfies the `commit-gate` requirement (via `store-validate` hook) for subsequent commits in this session.
|
|
103
|
+
|
|
104
|
+
### Step 5 — Confirm to user
|
|
105
|
+
|
|
106
|
+
Display:
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
Debug session active.
|
|
111
|
+
|
|
112
|
+
Source writes are unlocked. No agent dispatch required.
|
|
113
|
+
Brief gate, verify gate, and commit gate remain enforced.
|
|
114
|
+
|
|
115
|
+
State stored to odd-flow. Ready to investigate.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
Then proceed immediately to Strategy Selection below.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Strategy Selection
|
|
124
|
+
|
|
125
|
+
Read `.odd/state.json` to identify the active outcome and the latest failure. If the failure was described in the user's message, use that. If not yet clear, ask for a one-sentence description.
|
|
126
|
+
|
|
127
|
+
Choose exactly one debug strategy before inspecting code. State the chosen strategy and the reason.
|
|
128
|
+
|
|
129
|
+
- Choose `ui-behaviour` when the problem is visible in the interface and you do not yet have evidence of a backend or data fault
|
|
130
|
+
- Choose `full-stack` when the failure crosses a user action, server boundary, and persisted state
|
|
131
|
+
- Choose `auth-security` when access, identity, trust, or validation boundaries might be wrong
|
|
132
|
+
- Choose `integration-contract` when one part of the system expects data or sequencing another part does not produce
|
|
133
|
+
- Choose `background-process` when the failure depends on async handoff, jobs, retries, or event delivery
|
|
134
|
+
- Choose `performance-state` when the issue depends on timing, staleness, cache invalidation, or repeated actions
|
|
135
|
+
|
|
136
|
+
If more than one strategy seems plausible, do not fix anything yet. Gather one more piece of evidence, then choose the narrowest strategy that still explains the failure.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Fix Protocol
|
|
141
|
+
|
|
142
|
+
After choosing the strategy, load `docs/build/debug-protocol.md` for the detailed investigation procedure for that strategy.
|
|
143
|
+
|
|
144
|
+
When the fix is complete:
|
|
145
|
+
|
|
146
|
+
1. Run the relevant automated checks (tests, lint)
|
|
147
|
+
2. Update `.odd/state.json`:
|
|
148
|
+
- `debugSession: false`
|
|
149
|
+
- `buildMode: "verify"`
|
|
150
|
+
- `debugStrategy: <chosen strategy>`
|
|
151
|
+
- `debugTarget: <affected file or surface>`
|
|
152
|
+
- `debugSummary: <resolved — one sentence>`
|
|
153
|
+
3. Call `mcp__odd-flow__memory_store` with key `odd-project-state` to store final state
|
|
154
|
+
4. Return to the verification walkthrough from step one
|
|
155
|
+
|
|
156
|
+
Setting `debugSession: false` re-enables Gate 2 for subsequent work, returning to full swarm protocol.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Non-negotiable rules
|
|
161
|
+
|
|
162
|
+
- Never mark an outcome verified during a debug session
|
|
163
|
+
- Never change multiple layers at once before reproducing the fault
|
|
164
|
+
- Never skip the reproduction step
|
|
165
|
+
- Never broaden the strategy after starting unless new evidence proves the original classification wrong
|
|
166
|
+
- Always clear `debugSession: false` when the fix is complete
|