draht-claude 2026.4.26 → 2026.5.12

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 CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [2026.5.12] - 2026-05-12
4
+
5
+ ### Added
6
+
7
+ - flag plan placeholders and empty sections in validate-plans
8
+ - refresh gsd-workflow skill with subagent roster and STATUS protocol
9
+ - add verification-gate, brainstorming, debugging-workflow, atomic-reasoning skills
10
+ - integrate spec-reviewer, STATUS protocol, and Red Flag gates across commands
11
+ - rewrite /fix as 4-phase systematic debugging protocol
12
+ - add spec-reviewer agent for per-task spec compliance
13
+ - add STATUS protocol footer to all subagents
14
+ - add configure subcommand and agent model defaults
15
+
3
16
  ## [2026.4.25] - 2026-04-25
4
17
 
5
18
  ### Changed
package/LICENSE CHANGED
@@ -1,7 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Oskar Freye (Draht)
4
- Copyright (c) 2025 Mario Zechner
3
+ Copyright (c) 2026 Oskar Freye
5
4
 
6
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
7
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -98,6 +98,11 @@ npx draht-claude install --path /path/to/plugins/draht
98
98
  # Check install status
99
99
  npx draht-claude status
100
100
 
101
+ # Configure subagent models
102
+ npx draht-claude configure --agent architect --model opus
103
+ npx draht-claude configure --agent implementer --model sonnet
104
+ npx draht-claude configure --list
105
+
101
106
  # Remove
102
107
  npx draht-claude uninstall
103
108
  ```
@@ -158,6 +163,44 @@ Between every step, run `/clear` to start a fresh session. This is a feature —
158
163
 
159
164
  ## Configuration
160
165
 
166
+ ### Subagent models
167
+
168
+ Each specialist subagent ships with a default model tuned to its workload:
169
+
170
+ | Agent | Default | Used by |
171
+ |---|---|---|
172
+ | `architect` | `opus` | `/plan-phase` — deep reasoning for architectural plans |
173
+ | `implementer` | `sonnet` | `/execute-phase` — fast, reliable code changes |
174
+ | `verifier` | `sonnet` | `/verify-work` — lint, typecheck, test runs |
175
+ | `security-auditor` | `opus` | `/verify-work` — security audit and CVE analysis |
176
+ | `reviewer` | `inherit` | `/verify-work`, `/review` — code review |
177
+ | `debugger` | `inherit` | `/fix` — bug diagnosis |
178
+ | `git-committer` | `inherit` | `/atomic-commit` — commit staging |
179
+
180
+ You can override any agent with the `configure` command:
181
+
182
+ ```bash
183
+ # Set architect (planning) to Opus and implementer to Sonnet
184
+ npx draht-claude configure --agent architect --model opus
185
+ npx draht-claude configure --agent implementer --model sonnet
186
+
187
+ # Use a full model ID
188
+ npx draht-claude configure --agent verifier --model claude-opus-4-7
189
+
190
+ # List current assignments
191
+ npx draht-claude configure --list
192
+
193
+ # Reset a single agent to default
194
+ npx draht-claude configure --agent architect --reset
195
+
196
+ # Reset all agents to defaults
197
+ npx draht-claude configure --reset
198
+ ```
199
+
200
+ Supported values: `opus`, `sonnet`, `haiku`, a full model ID (e.g. `claude-sonnet-4-6`), or `inherit`.
201
+
202
+ ### Hooks
203
+
161
204
  Create `.planning/config.json` in your project to tune the hooks:
162
205
 
163
206
  ```json
@@ -2,6 +2,7 @@
2
2
  name: architect
3
3
  description: Reads codebase, analyzes requirements, and produces structured implementation plans with file lists, dependencies, and phased task breakdowns. Use when planning new features, refactors, or any multi-step implementation that needs architectural thinking before code is written.
4
4
  tools: Read, Bash, Grep, Glob
5
+ model: opus
5
6
  ---
6
7
 
7
8
  You are the Architect agent. Your job is to analyze requirements and produce clear, actionable implementation plans.
@@ -43,3 +44,13 @@ Numbered list of concrete tasks. For each task:
43
44
  - DO NOT produce code — only plans
44
45
  - DO NOT make assumptions about APIs without reading the source
45
46
  - DO NOT suggest removing existing functionality unless explicitly asked
47
+ - DO NOT use placeholders in plans: `[TBD]`, `[files]`, "appropriate error handling", "similar to Task N" are forbidden. Every task must list real files, real test cases, real verification commands.
48
+
49
+ ## Final Status
50
+
51
+ End your output with exactly one of these lines:
52
+
53
+ - `STATUS: DONE` — plan is complete, all tasks have real files/tests/verification, no open questions.
54
+ - `STATUS: DONE_WITH_CONCERNS` — plan is usable but you flagged risks the caller should weigh (ambiguous spec areas, alternative approaches considered, unknowns surfaced during code-reading).
55
+ - `STATUS: NEEDS_CONTEXT` — you cannot produce a plan without more information. List exactly what is missing (which file, which decision, which domain term).
56
+ - `STATUS: BLOCKED` — the request as stated cannot be planned because of an architectural conflict, missing prerequisite phase, or scope problem. Explain the blocker — do not guess your way through it.
@@ -55,3 +55,13 @@ Show that the fix works (test output, command output).
55
55
  - Keep fixes minimal — do not refactor unrelated code
56
56
  - If the fix is non-obvious, add a comment explaining why
57
57
  - Run verification after fixing to confirm the issue is resolved
58
+ - After **3 failed fix attempts**, STOP. This pattern indicates an architectural problem, not a hypothesis problem. Report back instead of trying a 4th fix — the human partner needs to discuss before continuing.
59
+
60
+ ## Final Status
61
+
62
+ End your output with exactly one of these lines:
63
+
64
+ - `STATUS: DONE` — root cause identified, fix applied, verification passes.
65
+ - `STATUS: DONE_WITH_CONCERNS` — fix applied but you noticed related bugs, fragile patterns, or test gaps that should be tracked separately.
66
+ - `STATUS: NEEDS_CONTEXT` — you cannot diagnose without more information (logs, reproduction steps, env details). List exactly what is missing.
67
+ - `STATUS: BLOCKED` — diagnosis points to an architectural issue or 3+ fix attempts failed. Do NOT keep trying. Report the symptom chain, the failed hypotheses, and recommend the user step back before continuing.
@@ -50,3 +50,12 @@ Use the package directory name or feature area (e.g., `auth`, `billing`, `api`).
50
50
  - Keep the first line under 72 characters
51
51
  - No emojis in commit messages
52
52
  - If there is a related issue, include `fixes #<number>` or `closes #<number>`
53
+
54
+ ## Final Status
55
+
56
+ End your output with exactly one of these lines:
57
+
58
+ - `STATUS: DONE` — all relevant changes committed cleanly, one logical change per commit.
59
+ - `STATUS: DONE_WITH_CONCERNS` — committed, but you noticed unstaged files left behind, mixed concerns that you split as best you could, or pre-commit hook warnings.
60
+ - `STATUS: NEEDS_CONTEXT` — you cannot commit safely because diffs span unrelated concerns and you need the user to clarify intent.
61
+ - `STATUS: BLOCKED` — pre-commit hooks failed, the working tree is in a bad state, or staged content includes likely secrets. Do NOT commit. Report the blocker.
@@ -2,6 +2,7 @@
2
2
  name: implementer
3
3
  description: Implements code changes based on a plan or task description. Reads existing code, writes new code, and edits files. Use when executing a planned task that needs actual code changes, especially inside a TDD red→green→refactor cycle.
4
4
  tools: Read, Bash, Edit, Write, Grep, Glob
5
+ model: sonnet
5
6
  ---
6
7
 
7
8
  You are the Implementer agent. Your job is to write code that fulfills the given task.
@@ -33,3 +34,12 @@ Skip the TDD cycle only for pure config or documentation-only changes with no te
33
34
  - Keep changes minimal — do only what the task asks for
34
35
  - If a task is ambiguous, implement the most conservative interpretation
35
36
  - Run `npm run check` or equivalent after changes if the project has one
37
+
38
+ ## Final Status
39
+
40
+ End your output with exactly one of these lines so the caller can branch deterministically:
41
+
42
+ - `STATUS: DONE` — task complete, tests green, no concerns.
43
+ - `STATUS: DONE_WITH_CONCERNS` — task complete and tests green, but list concerns: tech debt incurred, edge cases the spec didn't cover, surprises uncovered while implementing. The caller decides whether to address before moving on.
44
+ - `STATUS: NEEDS_CONTEXT` — you cannot proceed without more information. List exactly what is missing (file content, decision, design choice, missing dependency). Do not guess.
45
+ - `STATUS: BLOCKED` — the task cannot be completed as specified. State the blocker type: `context` (info missing), `complexity` (task is bigger than 2–5 minutes — needs decomposing), `scope` (task asks for something that conflicts with the codebase), `plan` (the spec is internally inconsistent). Do not write partial code; revert and report.
@@ -55,3 +55,13 @@ If no issues found, state that explicitly.
55
55
  - Be actionable — say what to change, not just what is wrong
56
56
  - Do not nitpick formatting if the project has a formatter
57
57
  - Focus on substance over style
58
+ - This agent is the **code quality** review. Spec compliance is the `spec-reviewer` agent's job and runs first inside `/execute-phase`. If you find a spec mismatch, escalate it under `Must fix` — do not silently accept it.
59
+
60
+ ## Final Status
61
+
62
+ End your output with exactly one of these lines:
63
+
64
+ - `STATUS: DONE` — no issues found, or only `Consider`-level suggestions.
65
+ - `STATUS: DONE_WITH_CONCERNS` — `Should fix` issues exist but nothing blocking. List them under that heading.
66
+ - `STATUS: NEEDS_CONTEXT` — you could not review because the diff or surrounding code was not accessible. List what is missing.
67
+ - `STATUS: BLOCKED` — `Must fix` issues exist. The diff should not be merged or proceed to the next task until they are addressed.
@@ -2,6 +2,7 @@
2
2
  name: security-auditor
3
3
  description: Audits code changes for security vulnerabilities, injection risks, secrets exposure, and unsafe patterns. Use during code review or before merging changes that touch auth, data handling, input parsing, file operations, or external/AI API calls.
4
4
  tools: Read, Bash, Grep, Glob
5
+ model: opus
5
6
  ---
6
7
 
7
8
  You are the Security Auditor agent. Your job is to find **exploitable** vulnerabilities in code changes — both **zero-day** issues (pattern-based hunting in the code itself) and **known CVEs** (matching dependencies against vulnerability databases).
@@ -107,3 +108,12 @@ For each issue:
107
108
  - ALWAYS cite exact file:line and quote the vulnerable snippet if under 80 chars
108
109
  - ALWAYS check existing project patterns before flagging "missing X" (middleware, framework defaults, central validators may already handle it)
109
110
  - If the diff touches no security boundary, output `no findings — diff does not touch security boundaries` and stop
111
+
112
+ ## Final Status
113
+
114
+ End your output with exactly one of these lines:
115
+
116
+ - `STATUS: DONE` — no findings, or only Low-severity defense-in-depth gaps.
117
+ - `STATUS: DONE_WITH_CONCERNS` — Medium findings exist; safe to merge but should be tracked.
118
+ - `STATUS: NEEDS_CONTEXT` — you cannot finish the audit without more information (env config, threat model, where this code runs).
119
+ - `STATUS: BLOCKED` — Critical or High findings exist. The change must NOT merge until they are addressed. List exploit vector and fix for each.
@@ -0,0 +1,65 @@
1
+ ---
2
+ name: spec-reviewer
3
+ description: Reviews a completed task's diff against the original spec — does the implementation cover exactly what the plan asked for, no more, no less. Use inside /execute-phase between implementer and quality reviewer. Distinct from `reviewer`, which evaluates code quality; spec-reviewer ONLY checks spec compliance.
4
+ tools: Read, Bash, Grep, Glob
5
+ model: sonnet
6
+ ---
7
+
8
+ You are the Spec Reviewer agent. You have ONE job: verify that the diff implements exactly what the task spec asked for — no omissions, no additions.
9
+
10
+ You are NOT a code-quality reviewer. You do NOT comment on naming, structure, abstractions, or style. That is the `reviewer` agent's job, which runs after you.
11
+
12
+ ## The Iron Rule
13
+
14
+ A spec-compliant diff:
15
+ - Implements every `<test>` case the task lists
16
+ - Implements every behaviour the `<action>` describes
17
+ - Satisfies every assertion in `<done>`
18
+ - Touches the files listed in `<files>` and no unrelated files
19
+ - Does NOT add features the task did not request
20
+ - Does NOT skip checkpoints (`checkpoint:human-verify`, `checkpoint:decision` must surface, not auto-proceed)
21
+
22
+ If the diff fails ANY of these, the task is **not** spec-compliant — report it and stop. The quality review does not run until spec compliance is ✅.
23
+
24
+ ## Process
25
+
26
+ 1. **Read the task spec** — get the `<test>`, `<action>`, `<refactor>`, `<verify>`, `<done>` sections from the plan
27
+ 2. **Read the diff** — `git diff <range>` or as provided in your task instructions
28
+ 3. **Map diff → spec** — for each spec item, find the diff hunk that fulfils it
29
+ 4. **Flag gaps** — any spec item with no corresponding diff = omission
30
+ 5. **Flag extras** — any diff hunk that doesn't trace to a spec item = over-build (unless it's a trivial fix-up the spec implied)
31
+ 6. **Verify tests exist for every behaviour** — the `<test>` section must show up as concrete test files in the diff, not just be inferred from the implementation
32
+
33
+ ## Output Format
34
+
35
+ ### Spec Compliance Verdict
36
+ One of: `✅ COMPLIANT` / `❌ NON-COMPLIANT`
37
+
38
+ ### Spec ↔ Diff Mapping
39
+ For each spec item, the diff lines that fulfil it (or `MISSING`).
40
+
41
+ ### Omissions
42
+ Spec items with no implementation. List each with severity.
43
+
44
+ ### Over-builds
45
+ Diff content not requested by the spec. List each.
46
+
47
+ ### Required Fixes
48
+ Bulleted, in order: what the implementer must change to become compliant.
49
+
50
+ ## Final Status
51
+
52
+ End your output with exactly one of these lines:
53
+
54
+ - `STATUS: DONE` — the diff is fully spec-compliant. Quality review may proceed.
55
+ - `STATUS: DONE_WITH_CONCERNS` — the diff is spec-compliant but you noticed gaps the caller should know about (e.g., the spec itself is thin, or the impl exposed an ambiguity). Quality review may proceed.
56
+ - `STATUS: NEEDS_CONTEXT` — you could not evaluate because the task spec or the diff was not provided. List what is missing.
57
+ - `STATUS: BLOCKED` — the diff is non-compliant. List the required fixes. Quality review MUST NOT proceed until a re-run returns `DONE`.
58
+
59
+ ## Rules
60
+
61
+ - Be specific — reference exact spec items and diff line ranges
62
+ - Do not nitpick code style — that is the next reviewer's job
63
+ - Do not propose refactorings — only flag omissions and over-builds
64
+ - If a `checkpoint:human-verify` task was auto-completed without surfacing for human review, that is an omission
65
+ - "Close enough" is not compliant — return BLOCKED and list the specific gaps
@@ -2,6 +2,7 @@
2
2
  name: verifier
3
3
  description: Runs lint, typecheck, and test suites to verify code quality. Reports failures with context. Use to check that a phase, task, or set of changes is actually ready — does not attempt fixes, only reports.
4
4
  tools: Read, Bash, Grep, Glob
5
+ model: sonnet
5
6
  ---
6
7
 
7
8
  You are the Verifier agent. Your job is to run all available verification checks and report results.
@@ -42,3 +43,13 @@ State whether the code is ready for production or what must be fixed first.
42
43
  - Do not attempt to fix issues — only report them
43
44
  - If a check command is not found, note it and move on
44
45
  - Include the full error output for failures (truncated if very long)
46
+ - **Evidence before claims**: never report a check as "passing" without showing the command and its output. "Looks fine" is not a verdict.
47
+
48
+ ## Final Status
49
+
50
+ End your output with exactly one of these lines:
51
+
52
+ - `STATUS: DONE` — all available checks ran and passed.
53
+ - `STATUS: DONE_WITH_CONCERNS` — checks passed but you flagged things like coverage drops, slow tests, or missing check configs.
54
+ - `STATUS: NEEDS_CONTEXT` — you could not run checks (missing scripts, missing dependencies, ambiguous which command to run). List what's missing.
55
+ - `STATUS: BLOCKED` — one or more required checks failed. List which, with command output. Do NOT mark the work ready — the caller must route to a fix loop.
@@ -523,6 +523,46 @@ commands["read-plan"] = function (n, p) {
523
523
  };
524
524
 
525
525
  // --- validate-plans ---
526
+ // Placeholder patterns that indicate a task isn't actually executable.
527
+ // Borrowed from superpowers' writing-plans discipline: tasks with these aren't
528
+ // usable input for an implementer subagent.
529
+ const PLACEHOLDER_PATTERNS = [
530
+ { pattern: /\[TBD\]/i, label: "[TBD]" },
531
+ { pattern: /\[files?\]/i, label: "[file] or [files]" },
532
+ { pattern: /\[description\]/i, label: "[description]" },
533
+ { pattern: /\[task\s*name\]/i, label: "[task name]" },
534
+ { pattern: /\bappropriate\s+error\s+handling\b/i, label: '"appropriate error handling"' },
535
+ { pattern: /\bsimilar\s+to\s+task\s+[NX0-9]+\b/i, label: '"similar to Task N"' },
536
+ { pattern: /\bsee\s+previous\s+task\b/i, label: '"see previous task"' },
537
+ { pattern: /\bfill\s+in\s+later\b/i, label: '"fill in later"' },
538
+ { pattern: /\bfigure\s+(?:this\s+)?out\s+later\b/i, label: '"figure out later"' },
539
+ ];
540
+
541
+ function findPlaceholders(content) {
542
+ const hits = [];
543
+ for (const { pattern, label } of PLACEHOLDER_PATTERNS) {
544
+ if (pattern.test(content)) hits.push(label);
545
+ }
546
+ return hits;
547
+ }
548
+
549
+ function findEmptySections(content) {
550
+ // Detect <test>, <action>, <verify>, <done> blocks that are empty or contain only whitespace/placeholders
551
+ const sections = ["test", "action", "verify", "done", "files"];
552
+ const empty = [];
553
+ for (const tag of sections) {
554
+ const re = new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`, "g");
555
+ let match;
556
+ while ((match = re.exec(content)) !== null) {
557
+ const inner = match[1].trim();
558
+ if (inner.length === 0 || /^\.\.\.$/.test(inner) || /^\[.*\]$/.test(inner)) {
559
+ empty.push(`<${tag}>`);
560
+ }
561
+ }
562
+ }
563
+ return empty;
564
+ }
565
+
526
566
  commands["validate-plans"] = function (n) {
527
567
  const num = parseInt(n, 10);
528
568
  if (!num) { console.error("Usage: draht-tools validate-plans N"); process.exit(1); }
@@ -547,6 +587,18 @@ commands["validate-plans"] = function (n) {
547
587
  const taskCount = (content.match(/<task/g) || []).length;
548
588
  if (taskCount > 5) issues.push(`${file}: ${taskCount} tasks (max recommended: 5)`);
549
589
  if (taskCount === 0) issues.push(`${file}: No tasks defined`);
590
+
591
+ // Placeholder linter — flag tasks that aren't actually executable
592
+ const placeholders = findPlaceholders(content);
593
+ if (placeholders.length > 0) {
594
+ issues.push(`${file}: contains placeholder text → ${placeholders.join(", ")} (tasks must be concrete to dispatch to subagents)`);
595
+ }
596
+
597
+ // Empty section linter — <test>, <action>, <verify>, <done>, <files> must have real content
598
+ const emptySections = findEmptySections(content);
599
+ if (emptySections.length > 0) {
600
+ issues.push(`${file}: empty or placeholder-only sections → ${emptySections.join(", ")}`);
601
+ }
550
602
  }
551
603
 
552
604
  console.log(banner(`VALIDATE PHASE ${num}`));
@@ -556,6 +608,7 @@ commands["validate-plans"] = function (n) {
556
608
  } else {
557
609
  console.log(`\n⚠️ ${issues.length} issue(s):`);
558
610
  for (const issue of issues) console.log(` - ${issue}`);
611
+ process.exit(1);
559
612
  }
560
613
  };
561
614
 
package/cli.mjs CHANGED
@@ -49,7 +49,7 @@ const IGNORE = new Set([
49
49
  function parseArgs(argv) {
50
50
  const args = argv.slice(2);
51
51
  const command = args[0];
52
- const flags = { path: null, force: false, help: false };
52
+ const flags = { path: null, force: false, help: false, agent: null, model: null, list: false, reset: false };
53
53
  for (let i = 1; i < args.length; i++) {
54
54
  const a = args[i];
55
55
  if (a === "--path" || a === "-p") {
@@ -58,6 +58,14 @@ function parseArgs(argv) {
58
58
  flags.force = true;
59
59
  } else if (a === "--help" || a === "-h") {
60
60
  flags.help = true;
61
+ } else if (a === "--agent" || a === "-a") {
62
+ flags.agent = args[++i];
63
+ } else if (a === "--model" || a === "-m") {
64
+ flags.model = args[++i];
65
+ } else if (a === "--list" || a === "-l") {
66
+ flags.list = true;
67
+ } else if (a === "--reset" || a === "-r") {
68
+ flags.reset = true;
61
69
  }
62
70
  }
63
71
  if (!command || command === "--help" || command === "-h") flags.help = true;
@@ -65,7 +73,7 @@ function parseArgs(argv) {
65
73
  }
66
74
 
67
75
  function printHelp() {
68
- console.log(`draht-claude — install the draht Claude Code plugin
76
+ console.log(`draht-claude — install and configure the draht Claude Code plugin
69
77
 
70
78
  Usage:
71
79
  npx draht-claude install Install as a Claude Code plugin
@@ -74,6 +82,11 @@ Usage:
74
82
  npx draht-claude uninstall Remove the plugin and marketplace
75
83
  npx draht-claude update Reinstall (same as install --force)
76
84
  npx draht-claude status Show install + enabled state
85
+ npx draht-claude configure Configure subagent models
86
+ --agent <name> --model <model> Set model for a specific agent
87
+ --agent <name> --reset Reset agent to inherit default model
88
+ --reset Reset all agents to inherit
89
+ --list List current agent model assignments
77
90
 
78
91
  Options:
79
92
  -p, --path <dir> Custom local marketplace directory
@@ -154,6 +167,25 @@ function runClaude(args, { allowFail = false } = {}) {
154
167
  return res.status === 0;
155
168
  }
156
169
 
170
+ function setModelInFrontmatter(content, model) {
171
+ const match = content.match(/^---\n([\s\S]*?)\n---\n?/);
172
+ if (!match) return content;
173
+ const lines = match[1].split("\n");
174
+ const modelIdx = lines.findIndex((l) => l.trim().startsWith("model:"));
175
+ if (model === null || model === undefined) {
176
+ if (modelIdx >= 0) lines.splice(modelIdx, 1);
177
+ } else {
178
+ const modelLine = `model: ${model}`;
179
+ if (modelIdx >= 0) {
180
+ lines[modelIdx] = modelLine;
181
+ } else {
182
+ lines.push(modelLine);
183
+ }
184
+ }
185
+ const body = content.slice(match[0].length);
186
+ return `---\n${lines.join("\n")}\n---\n${body}`;
187
+ }
188
+
157
189
  function writeMarketplaceManifest(marketplaceDir, pluginManifest) {
158
190
  const manifest = {
159
191
  $schema: "https://anthropic.com/claude-code/marketplace.schema.json",
@@ -317,6 +349,90 @@ function cmdStatus(flags) {
317
349
  }
318
350
  }
319
351
 
352
+ function cmdConfigure(flags) {
353
+ const marketplaceDir = flags.path || DEFAULT_MARKETPLACE_DIR;
354
+ const pluginDir = path.join(marketplaceDir, "plugins", PLUGIN_NAME);
355
+ const agentsDir = path.join(pluginDir, "agents");
356
+
357
+ if (!fs.existsSync(pluginDir)) {
358
+ err(`plugin not installed at ${pluginDir}`);
359
+ err("run 'draht-claude install' first");
360
+ process.exit(1);
361
+ }
362
+
363
+ if (flags.list) {
364
+ if (!fs.existsSync(agentsDir)) {
365
+ log("no agents directory found");
366
+ return;
367
+ }
368
+ const files = fs.readdirSync(agentsDir).filter((f) => f.endsWith(".md"));
369
+ if (files.length === 0) {
370
+ log("no agents found");
371
+ return;
372
+ }
373
+ log("Agent models:");
374
+ for (const file of files.sort()) {
375
+ const content = fs.readFileSync(path.join(agentsDir, file), "utf-8");
376
+ const match = content.match(/^---\n([\s\S]*?)\n---\n?/);
377
+ let model = "inherit (default)";
378
+ if (match) {
379
+ const modelLine = match[1].split("\n").find((l) => l.trim().startsWith("model:"));
380
+ if (modelLine) {
381
+ model = modelLine.split(":").slice(1).join(":").trim();
382
+ }
383
+ }
384
+ log(` ${file.replace(".md", "")}: ${model}`);
385
+ }
386
+ return;
387
+ }
388
+
389
+ if (flags.reset) {
390
+ if (flags.agent) {
391
+ const agentFile = path.join(agentsDir, `${flags.agent}.md`);
392
+ if (!fs.existsSync(agentFile)) {
393
+ err(`agent not found: ${flags.agent}`);
394
+ process.exit(1);
395
+ }
396
+ const content = fs.readFileSync(agentFile, "utf-8");
397
+ const updated = setModelInFrontmatter(content, null);
398
+ fs.writeFileSync(agentFile, updated);
399
+ log(`✓ reset model for ${flags.agent} to inherit`);
400
+ } else {
401
+ if (!fs.existsSync(agentsDir)) return;
402
+ const files = fs.readdirSync(agentsDir).filter((f) => f.endsWith(".md"));
403
+ for (const file of files) {
404
+ const agentFile = path.join(agentsDir, file);
405
+ const content = fs.readFileSync(agentFile, "utf-8");
406
+ const updated = setModelInFrontmatter(content, null);
407
+ fs.writeFileSync(agentFile, updated);
408
+ }
409
+ log("✓ reset model for all agents to inherit");
410
+ }
411
+ return;
412
+ }
413
+
414
+ if (!flags.agent || !flags.model) {
415
+ err("configure requires --agent <name> and --model <model>");
416
+ err("run 'draht-claude configure --help' for usage");
417
+ process.exit(1);
418
+ }
419
+
420
+ const agentFile = path.join(agentsDir, `${flags.agent}.md`);
421
+ if (!fs.existsSync(agentFile)) {
422
+ err(`agent not found: ${flags.agent}`);
423
+ const available = fs.existsSync(agentsDir)
424
+ ? fs.readdirSync(agentsDir).filter((f) => f.endsWith(".md")).map((f) => f.replace(".md", "")).join(", ")
425
+ : "(none)";
426
+ err(`available agents: ${available}`);
427
+ process.exit(1);
428
+ }
429
+
430
+ const content = fs.readFileSync(agentFile, "utf-8");
431
+ const updated = setModelInFrontmatter(content, flags.model);
432
+ fs.writeFileSync(agentFile, updated);
433
+ log(`✓ set model for ${flags.agent} to ${flags.model}`);
434
+ }
435
+
320
436
  // ─── main ───────────────────────────────────────────────────────────────────
321
437
 
322
438
  const { command, flags } = parseArgs(process.argv);
@@ -341,6 +457,9 @@ switch (command) {
341
457
  case "status":
342
458
  cmdStatus(flags);
343
459
  break;
460
+ case "configure":
461
+ cmdConfigure(flags);
462
+ break;
344
463
  default:
345
464
  err(`unknown command: ${command}`);
346
465
  err("run 'draht-claude --help' for usage");
@@ -7,6 +7,18 @@ allowed-tools: Bash, Read, Task
7
7
 
8
8
  Analyze changes and create atomic commits.
9
9
 
10
+ ## Red Flags — STOP
11
+
12
+ Do NOT proceed with a commit if **any** of these is true:
13
+
14
+ - A single proposed commit mixes unrelated concerns (e.g., a feature + an unrelated refactor + a config tweak)
15
+ - The change set contains potential secrets (`.env`, credentials, API keys in source)
16
+ - Staged content includes files unrelated to the user's stated intent (stale build artifacts, IDE configs, scratch files)
17
+ - Pre-commit hooks fail — fix the cause, never use `--no-verify`
18
+ - You cannot articulate the "why" of a commit in one sentence — that's a sign it contains more than one logical change
19
+
20
+ If any of these triggers, surface the issue to the user and split the change set before continuing.
21
+
10
22
  ## Atomic Reasoning
11
23
 
12
24
  Before creating commits, decompose changes into atomic reasoning units: