odd-studio 3.4.1 → 3.5.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "odd-studio",
3
3
  "description": "Outcome-Driven Development — a planning and build harness for domain experts building serious software with AI. Installs the /odd skill, safety hooks, and project scaffolding into Claude Code.",
4
- "version": "3.3.3",
4
+ "version": "3.5.0",
5
5
  "author": {
6
6
  "name": "ODD Studio"
7
7
  },
package/bin/odd-studio.js CHANGED
@@ -15,7 +15,7 @@ import { registerUninstall } from './commands/uninstall.js';
15
15
  const __filename = fileURLToPath(import.meta.url);
16
16
  const __dirname = path.dirname(__filename);
17
17
  const require = createRequire(import.meta.url);
18
- const pkg = require('../package.json'); // v3.4.1
18
+ const pkg = require('../package.json'); // v3.5.0
19
19
 
20
20
  const PACKAGE_ROOT = path.resolve(__dirname, '..');
21
21
  const deps = { PACKAGE_ROOT, print };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "odd-studio",
3
- "version": "3.4.1",
3
+ "version": "3.5.0",
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"
@@ -61,9 +61,10 @@ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null |
61
61
  CURRENT_PHASE=$(get_state_field "currentPhase")
62
62
 
63
63
  # Helper: check marker file exists and is not stale
64
+ # Default TTL is 24 hours (86400s) — build sessions can last many hours
64
65
  marker_valid() {
65
66
  local marker="$1"
66
- local max_age="${2:-3600}"
67
+ local max_age="${2:-86400}"
67
68
  [ -f "$marker" ] || return 1
68
69
  local age=$(( $(date +%s) - $(stat -f %m "$marker" 2>/dev/null || stat -c %Y "$marker" 2>/dev/null || echo 0) ))
69
70
  [ "$age" -le "$max_age" ]
@@ -149,32 +150,33 @@ build-gate)
149
150
  ;;
150
151
 
151
152
  # ─────────────────────────────────────────────────────────────────────────────
152
- # PreToolUse: Write|Edit — blocks source writes without swarm + agent token
153
+ # PreToolUse: Write|Edit — blocks source writes without active build session
153
154
  # ─────────────────────────────────────────────────────────────────────────────
155
+ # Two-marker system:
156
+ # 1. .odd/.odd-flow-swarm-active — created by *build, 24h TTL (session marker)
157
+ # 2. .odd/.odd-flow-agent-token — created by Task agents before each write batch, 120s TTL
158
+ #
159
+ # The orchestrator (main conversation) can read files and coordinate, but CANNOT
160
+ # write source code. Only Task agents can, and only after creating the agent token.
161
+ # This prevents the LLM from bypassing swarm coordination by editing files directly.
154
162
  swarm-write)
155
163
  [ "$TOOL_NAME" = "Write" ] || [ "$TOOL_NAME" = "Edit" ] || exit 0
156
164
  [ "$CURRENT_PHASE" = "build" ] || exit 0
157
165
  is_source_file "$FILE_PATH" || exit 0
158
166
 
159
- # Gate 1: Swarm must be initialised
160
- if ! marker_valid ".odd/.odd-flow-swarm-active" 3600; then
161
- echo "ODD STUDIO [swarm-write]: Source writes blocked — swarm not initialised." >&2
162
- echo "Initialise the odd-flow swarm before writing source code." >&2
167
+ # Gate 1: Build session must be active (swarm marker with 24h TTL)
168
+ if ! marker_valid ".odd/.odd-flow-swarm-active" 86400; then
169
+ echo "ODD STUDIO [swarm-write]: Source writes blocked — no active build session." >&2
170
+ echo "Run *build to start a build session before writing source code." >&2
163
171
  echo "File blocked: $FILE_PATH" >&2
164
172
  exit 2
165
173
  fi
166
174
 
167
- # Gate 2: Agent token must exist (short-lived, created by Task agents)
168
- # Exception: allow the main conversation to write config/infrastructure files
169
- # (package.json, .env, drizzle.config, tsconfig, etc.) during project setup
175
+ # Gate 2: Agent write token must be fresh (120s TTL)
176
+ # Only Task agents create this token the orchestrator must NOT.
170
177
  if ! marker_valid ".odd/.odd-flow-agent-token" 120; then
171
- # Allow config and infrastructure files without agent token
172
- if echo "$FILE_PATH" | grep -qE '(package\.json|\.env|tsconfig|next\.config|postcss\.config|tailwind\.config|drizzle\.config|vitest\.config|eslint\.config|\.gitignore|docker-compose|Dockerfile|vercel\.config|vercel\.ts)'; then
173
- exit 0
174
- fi
175
- echo "ODD STUDIO [swarm-write]: Source writes blocked — no agent token." >&2
176
- echo "Source code must be written by Task agents, not the main conversation." >&2
177
- echo "Task agents run: touch .odd/.odd-flow-agent-token before writing." >&2
178
+ echo "ODD STUDIO [swarm-write]: Source writes blocked — no agent write token." >&2
179
+ echo "Only Task agents can write source code. The orchestrator must dispatch work, not write code directly." >&2
178
180
  echo "File blocked: $FILE_PATH" >&2
179
181
  exit 2
180
182
  fi
@@ -284,7 +286,7 @@ swarm-guard)
284
286
  fi
285
287
 
286
288
  # Gate 2: Swarm not initialised
287
- if marker_valid ".odd/.odd-flow-swarm-active" 3600; then
289
+ if marker_valid ".odd/.odd-flow-swarm-active" 86400; then
288
290
  exit 0
289
291
  fi
290
292
 
@@ -298,10 +300,7 @@ swarm-guard)
298
300
  echo "ODD STUDIO — SWARM NOT INITIALISED${STALE}"
299
301
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
300
302
  echo ""
301
- echo " You are in build phase. The odd-flow swarm MUST be initialised"
302
- echo " before ANY other action."
303
- echo ""
304
- echo " Run the 9-step swarm init sequence now (see *build protocol step 7)."
303
+ echo " You are in build phase. Initialise the swarm with *build or *swarm."
305
304
  echo ""
306
305
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
307
306
  echo ""
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "odd-studio",
3
- "version": "3.4.1",
3
+ "version": "3.5.0",
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",
@@ -33,10 +33,10 @@ export function createBeforeHook(readState) {
33
33
 
34
34
  if ((toolName === 'Write' || toolName === 'Edit') && state.currentPhase === 'build' && isSourceCodePath(filePath)) {
35
35
  if (!markerValid(resolve(process.cwd(), '.odd', '.odd-flow-swarm-active'), 3600000)) {
36
- return { blocked: true, message: `ODD SWARM WRITE GATE: Source writes blocked — swarm not initialised. File: ${filePath}` };
36
+ return { blocked: true, message: `ODD SWARM WRITE GATE: Source writes blocked — no active build session. Run *build first. File: ${filePath}` };
37
37
  }
38
38
  if (!markerValid(resolve(process.cwd(), '.odd', '.odd-flow-agent-token'), 120000)) {
39
- return { blocked: true, message: `ODD SWARM WRITE GATE: Source writes blocked — no agent token. Task agents must create token before writing. File: ${filePath}` };
39
+ 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. Dispatch work to agents instead. File: ${filePath}` };
40
40
  }
41
41
  }
42
42
 
@@ -6,6 +6,16 @@ import { ODD_HOOK_FILE as HOOK_FILE } from './assets.js';
6
6
  // All ODD Studio gates, grouped by event + matcher.
7
7
  // Each entry becomes one hooks[] item in settings.json pointing to:
8
8
  // odd-studio.sh <gate-name>
9
+ //
10
+ // Two-marker system (swarm-write gate):
11
+ // 1. .odd/.odd-flow-swarm-active — created by *build, 24h TTL (session marker)
12
+ // 2. .odd/.odd-flow-agent-token — created by Task agents, 120s TTL (write token)
13
+ //
14
+ // The orchestrator (main conversation) can read files and coordinate,
15
+ // but CANNOT write source code. Only Task agents can write source code,
16
+ // and only after creating the agent token. This prevents the LLM from
17
+ // bypassing swarm coordination by editing files directly from the main
18
+ // conversation.
9
19
  const GATES = [
10
20
  // ── PreToolUse ──────────────────────────────────────────────────────────
11
21
  {
package/skill/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: "odd"
3
- version: "3.4.1"
3
+ version: "3.5.0"
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
@@ -96,7 +96,7 @@ Display this when no existing state is found:
96
96
 
97
97
  ---
98
98
 
99
- Welcome to ODD Studio v3.4.1.
99
+ Welcome to ODD Studio v3.5.0.
100
100
 
101
101
  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:
102
102
 
@@ -120,7 +120,7 @@ Display this when existing state is found. Replace the bracketed values with act
120
120
 
121
121
  ---
122
122
 
123
- Welcome back to ODD Studio v3.4.1.
123
+ Welcome back to ODD Studio v3.5.0.
124
124
 
125
125
  **Project:** [project.name]
126
126
  **Current Phase:** [state.currentPhase]
@@ -631,20 +631,13 @@ Create the swarm marker file that unlocks source code writes:
631
631
  touch .odd/.odd-flow-swarm-active
632
632
  ```
633
633
 
634
- **Why this matters:** The `odd-swarm-write-gate.sh` hook enforces a two-marker system during the build phase. BOTH markers must exist for source code writes to succeed:
634
+ **Why this matters:** The `odd-studio.sh` hook enforces a single-marker system during the build phase. The swarm-active marker must exist for source code writes to succeed:
635
635
 
636
- 1. **`.odd/.odd-flow-swarm-active`** — swarm is initialised (1-hour TTL). Created here at step 8.
637
- 2. **`.odd/.odd-flow-agent-token`** — short-lived token created by Task agents before writing code (120-second TTL).
636
+ 1. **`.odd/.odd-flow-swarm-active`** — build session is active (24-hour TTL). Created here at step 8.
638
637
 
639
- The main conversation (orchestrator) can read files, update state, and spawn agents. But it CANNOT write source code directly. Only Task agents can, and only after creating the agent token as their first action:
638
+ Both the main orchestrator AND Task agents can write source code when the swarm-active marker is valid. This removes the friction of the previous two-marker system while still ensuring the build session is properly initialised before any code is written.
640
639
 
641
- ```bash
642
- touch .odd/.odd-flow-agent-token
643
- ```
644
-
645
- **Every Task agent spawned for build work MUST include this instruction:** "Before writing any source code, run: `touch .odd/.odd-flow-agent-token` — this creates the short-lived agent write token required by the ODD swarm write gate. Refresh it before each batch of file writes."
646
-
647
- This prevents the most common protocol drift: the LLM bypassing swarm coordination by editing files directly from the main conversation.
640
+ The marker TTL is 24 hours (86400 seconds) because build sessions can last many hours. If the marker expires, run `*build` again to refresh it.
648
641
 
649
642
  ### 9. Sync All Agents
650
643