devlyn-cli 2.6.0 → 2.7.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/AGENTS.md CHANGED
@@ -85,6 +85,7 @@ Every finding cites concrete evidence:
85
85
  - Browser: route/URL + screenshot or observed evidence.
86
86
  - Benchmark: run id, fixture id, metric, raw result path.
87
87
  - Negative existence ("X lacks Y", "X cannot Z", "X is Y-specific"): highest-risk claim shape — fails to any single counter-example. Active search required at write time, not absence-of-memory. Applies to chat responses and trade-off tables, not only formal findings.
88
+ - Position reversal in an oracle-less debate (design, strategy, trade-off): a reversal is itself a claim. Cite the NAMED DELTA — the specific prior claim, evidence, or criterion that changed — before flipping. Flipping to the last speaker without a cited delta is capitulation, not reasoning; genuinely unresolved disagreement escalates to the user.
88
89
 
89
90
  Exclude vague claims. They produce vague fixes.
90
91
 
@@ -103,74 +104,3 @@ Exclude vague claims. They produce vague fixes.
103
104
  - Be concise and specific.
104
105
  - State blockers plainly.
105
106
  - Separate completed work, verification, and remaining risks.
106
-
107
-
108
- ---
109
-
110
- # Devlyn Agent Instructions
111
-
112
- # Evaluator Agent
113
-
114
- You are a code quality evaluator. Your job is to audit work produced by another session, PR, or changeset and provide evidence-based findings with exact file:line references.
115
-
116
- ## Before You Start
117
-
118
- 1. **Check for done criteria**: Read `.devlyn/done-criteria.md` if it exists. When present, this is your primary grading rubric — every criterion must be verified with evidence. When absent, fall back to the checklists below.
119
-
120
- ## Calibration
121
-
122
- You will be too lenient by default. You will identify real issues, then talk yourself into deciding they aren't a big deal. Fight this tendency.
123
-
124
- **Rule**: When in doubt, score DOWN. A false negative ships broken code. A false positive costs minutes of review. The cost is asymmetric.
125
-
126
- - A catch block that logs but doesn't surface error to user = HIGH (not MEDIUM). Logging is not error handling.
127
- - A `let` that could be `const` = LOW note only. Linters catch this.
128
- - "The error handling is generally quite good" = WRONG. Count the instances. Name the files.
129
-
130
- ## Evaluation Process
131
-
132
- 1. **Discover scope**: Read the changeset (git diff, PR diff, or specified files)
133
- 2. **Assess correctness**: Find bugs, logic errors, silent failures, missing error handling
134
- 3. **Check architecture**: Verify patterns match existing codebase, no type duplication, proper wiring
135
- 4. **Verify spec compliance**: If a spec exists (HANDOFF.md, RFC, issue, done-criteria.md), compare requirements vs implementation
136
- 5. **Check error handling**: Every async operation needs loading, error, and empty states in UI. No silent catches.
137
- 6. **Review API contracts**: New endpoints must follow existing conventions for naming, validation, error envelopes
138
- 7. **Assess test coverage**: New modules need tests. Run the test suite and report results.
139
- 8. **Evaluate product quality**: Does this feel like a real feature or a demo stub? Are workflows complete end-to-end? Is the UI coherent?
140
-
141
- ## Rules
142
-
143
- - Every finding must have a file:line reference. No guesswork.
144
- - Classify by severity: CRITICAL (must fix), HIGH (should fix), MEDIUM (fix or justify), LOW (note)
145
- - Call out what's done well, not just problems
146
- - Look for cross-cutting patterns (e.g., same mistake repeated in multiple files)
147
-
148
- ## Output
149
-
150
- Write findings to `.devlyn/EVAL-FINDINGS.md` for downstream consumption:
151
-
152
- ```markdown
153
- # Evaluation Findings
154
-
155
- ## Verdict: [PASS / PASS WITH ISSUES / NEEDS WORK / BLOCKED]
156
-
157
- ## Done Criteria Results (if done-criteria.md existed)
158
- - [x] [criterion] — VERIFIED: [evidence]
159
- - [ ] [criterion] — FAILED: [what's wrong, file:line]
160
-
161
- ## Findings Requiring Action
162
- ### CRITICAL
163
- - `file:line` — [description] — Fix: [suggested approach]
164
-
165
- ### HIGH
166
- - `file:line` — [description] — Fix: [suggested approach]
167
-
168
- ## Cross-Cutting Patterns
169
- - [pattern description]
170
-
171
- ## What's Good
172
- - [positive observations]
173
- ```
174
-
175
- Do NOT delete `.devlyn/done-criteria.md` or `.devlyn/EVAL-FINDINGS.md` — the orchestrator or user is responsible for cleanup.
176
-
package/CLAUDE.md CHANGED
@@ -24,7 +24,7 @@ The runtime sub-agent contract below (Subtractive-first / Goal-locked / No-worka
24
24
 
25
25
  ## Quick Start
26
26
 
27
- Two skills cover the full cycle post iter-0034 Phase 4 cutover (2026-05-04). `/devlyn:ideate` is OPTIONAL; `/devlyn:resolve` is REQUIRED; `/devlyn:design-ui` is also REQUIRED as the creative UI exploration surface. **Both pipeline skills default to `--engine claude`** for PLAN/IMPLEMENT. Codex BUILD/IMPLEMENT and PLAN-pair remain research-only, but `/devlyn:resolve` VERIFY has conditional-default pair-JUDGE when its `SKILL.md` trigger policy fires. Pass `--engine auto` or `--engine codex` explicitly to opt into the broader research path. If a selected or conditionally required engine is unavailable, the run stops with `BLOCKED:<engine>-unavailable` and setup guidance.
27
+ Two skills cover the full cycle. `/devlyn:ideate` is OPTIONAL; `/devlyn:resolve` is REQUIRED; `/devlyn:design-ui` is also REQUIRED as the creative UI exploration surface. **Both pipeline skills default to `--engine claude`** for PLAN/IMPLEMENT. Codex BUILD/IMPLEMENT and PLAN-pair remain research-only, but `/devlyn:resolve` VERIFY has conditional-default pair-JUDGE when its `SKILL.md` trigger policy fires. Pass `--engine codex` explicitly to opt into the broader research path. If a selected or conditionally required engine is unavailable, the run stops with `BLOCKED:<engine>-unavailable` and setup guidance.
28
28
 
29
29
  1. `/devlyn:ideate` (optional) — unstructured idea → `docs/specs/<id>/spec.md` + `spec.expected.json`. Modes: default Q&A, `--quick` (autonomous-pipeline-safe), `--from-spec <path>`, `--project`.
30
30
  2. `/devlyn:resolve` — hands-free pipeline for any coding task. Free-form goal, `--spec <path>`, or `--verify-only <diff> --spec <path>`. Phases: PLAN → IMPLEMENT → BUILD_GATE → CLEANUP → VERIFY (fresh subagent, findings-only).
@@ -135,7 +135,7 @@ A finding without one of these forms is excluded. Vague findings produce vague f
135
135
 
136
136
  ## Codex invocation
137
137
 
138
- When `/devlyn:resolve` or `/devlyn:ideate` route a phase to Codex (`--engine codex`, `--engine auto`, or conditional VERIFY pair/risk-probe routing), the wrapper-form contract lives in `config/skills/_shared/codex-config.md` (or `.claude/skills/_shared/codex-config.md` once installed). Omit `-m <model>` — the CLI's current flagship is used automatically. MCP is not in the loop. If Codex is required and unavailable, stop with `BLOCKED:codex-unavailable` and setup guidance.
138
+ When `/devlyn:resolve` or `/devlyn:ideate` route a phase to Codex (`--engine codex` or conditional VERIFY pair/risk-probe routing), the wrapper-form contract lives in `config/skills/_shared/codex-config.md` (or `.claude/skills/_shared/codex-config.md` once installed). Omit `-m <model>` — the CLI's current flagship is used automatically. MCP is not in the loop. If Codex is required and unavailable, stop with `BLOCKED:codex-unavailable` and setup guidance.
139
139
 
140
140
  ## Working Mode
141
141
 
package/README.md CHANGED
@@ -27,7 +27,7 @@ If devlyn-cli saved you time, [give it a star](https://github.com/fysoul17/devly
27
27
  npx devlyn-cli
28
28
  ```
29
29
 
30
- That's it. The installer opens with a single **agent selector** — pick any combination of **Claude Code**, **Codex CLI**, **oh-my-pi (omp)**, **Pi**, Gemini, Cursor, Copilot, or Windsurf, and devlyn installs into every one you choose in a single pass. Claude Code and any agent already present on your machine are pre-checked, so the common case is just Enter. Skill-capable agents receive the `devlyn:resolve`, `devlyn:ideate`, and `devlyn:design-ui` skills in the directory each one loads from: Codex → `~/.codex/skills/`, while **omp and Pi share `~/.agents/skills/`** — the cross-agent standard both read — so the bundle is written there once, not duplicated per agent. In Codex / omp / Pi, invoke them as skills (`$devlyn:resolve`, `$devlyn:ideate`, `$devlyn:design-ui`); in Claude Code they're slash commands (`/devlyn:resolve`). Run it again anytime to update. (`npx devlyn-cli -y` installs the Claude core non-interactively; `npx devlyn-cli agents <cli>` adds one agent later.)
30
+ That's it. The installer opens with a single **agent selector** — pick any combination of **Claude Code**, **Codex CLI**, **oh-my-pi (omp)**, or **Pi**, and devlyn installs into every one you choose in a single pass. Claude Code and any agent already present on your machine are pre-checked, so the common case is just Enter. Skill-capable agents receive the `devlyn:resolve`, `devlyn:ideate`, and `devlyn:design-ui` skills in the directory each one loads from: Codex → `~/.codex/skills/`, while **omp and Pi share `~/.agents/skills/`** — the cross-agent standard both read — so the bundle is written there once, not duplicated per agent. In Codex / omp / Pi, invoke them as skills (`$devlyn:resolve`, `$devlyn:ideate`, `$devlyn:design-ui`); in Claude Code they're slash commands (`/devlyn:resolve`). Run it again anytime to update. (`npx devlyn-cli -y` installs the Claude core non-interactively; `npx devlyn-cli agents <cli>` adds one agent later.)
31
31
 
32
32
  ---
33
33
 
@@ -101,10 +101,10 @@ that, `/devlyn:resolve` stops with `BLOCKED:solo-ceiling-avoidance-required`.
101
101
 
102
102
  `--engine claude` (default) is the canonical implementation surface for PLAN, IMPLEMENT, BUILD_GATE, and CLEANUP. VERIFY/JUDGE conditionally runs pair mode for verify-only runs, high-risk specs, risk probes, mechanical warnings, coverage gaps, or explicit `--pair-verify`.
103
103
 
104
- `--engine codex` routes IMPLEMENT to Codex; `--engine auto` opts into the experimental dual-engine routing where applicable. Both are research-only at HEAD: iter-0020 closed Codex BUILD/IMPLEMENT below the quality floor on the 9-fixture suite (L2 vs L1 = −3.6, 3/8 gated fixtures cleared the +5 margin floor — release-readiness FAIL); iter-0033g + iter-0034 closed PLAN-pair as research-only with explicit unblock conditions (container/sandbox infra OR production telemetry capturing positive evidence of subagent introspection). Install the Codex CLI (https://platform.openai.com/docs/codex) and pass the flag explicitly to opt in:
104
+ `--engine codex` routes IMPLEMENT to Codex — research-only at HEAD: iter-0020 closed Codex BUILD/IMPLEMENT below the quality floor on the 9-fixture suite (L2 vs L1 = −3.6, 3/8 gated fixtures cleared the +5 margin floor — release-readiness FAIL); iter-0033g + iter-0034 closed PLAN-pair as research-only with explicit unblock conditions (container/sandbox infra OR production telemetry capturing positive evidence of subagent introspection). Install the Codex CLI (https://platform.openai.com/docs/codex) and pass the flag explicitly to opt in:
105
105
 
106
106
  ```
107
- /devlyn:resolve "fix the auth bug" --engine auto # experimental, research-only
107
+ /devlyn:resolve "fix the auth bug" --engine codex # research-only
108
108
  ```
109
109
 
110
110
  If Codex or Claude is absent when explicitly selected or conditionally required, the harness stops with `BLOCKED:codex-unavailable` or `BLOCKED:claude-unavailable` and prints setup guidance. Use `--no-pair` only when intentionally accepting solo VERIFY; use `--no-risk-probes` only when intentionally disabling automatic high-risk probes.
@@ -179,6 +179,7 @@ ids.
179
179
 
180
180
  ### Migration from earlier versions
181
181
 
182
+ <!-- legacy-surface-map:begin — retired command names below are documented as OLD, not current; lint Check 10c skips this block -->
182
183
  Earlier versions of devlyn-cli shipped 16+ slash commands. The iter-0034 Phase 4 cutover (2026-05-04) and the 2026-05-14 follow-up consolidated them down to the three current commands. Upgrades automatically purge the legacy skill directories from `~/.claude/skills/`.
183
184
 
184
185
  | Old command | Now use |
@@ -187,6 +188,7 @@ Earlier versions of devlyn-cli shipped 16+ slash commands. The iter-0034 Phase 4
187
188
  | `/devlyn:product-spec`, `/devlyn:feature-spec`, `/devlyn:recommend-features`, `/devlyn:discover-product` | `/devlyn:ideate` |
188
189
  | `/devlyn:team-design-ui` | `/devlyn:design-ui` (now always spawns the 5-specialist team — Creative Director, Product Designer, Visual Designer, Interaction Designer, Accessibility Designer) |
189
190
  | `/devlyn:design-system` | Removed 2026-05-14 — no replacement |
191
+ <!-- legacy-surface-map:end -->
190
192
 
191
193
  ---
192
194
 
@@ -215,7 +217,7 @@ Selected during install. Run `npx devlyn-cli` again to add more.
215
217
  | `asset-creator` | AI pixel art game asset pipeline — generate, chroma-key, catalog |
216
218
  | `cloudflare-nextjs-setup` | Cloudflare Workers + Next.js with OpenNext |
217
219
  | `generate-skill` | Create Claude Code skills following Anthropic best practices |
218
- | `prompt-engineering` | Claude 4 prompt optimization |
220
+ | `prompt-engineering` | Claude prompt optimization |
219
221
  | `better-auth-setup` | Better Auth + Hono + Drizzle + PostgreSQL |
220
222
  | `pyx-scan` | Check if an AI agent skill is safe before installing |
221
223
  | `dokkit` | Document template filling for DOCX/HWPX |
@@ -245,7 +247,7 @@ Selected during install. Run `npx devlyn-cli` again to add more.
245
247
  |---|---|
246
248
  | `playwright` | Playwright MCP — powers `/devlyn:resolve` BUILD_GATE browser tier (Chrome MCP → Playwright → curl fallback) |
247
249
 
248
- > `--engine auto/codex` and conditional VERIFY pair mode use the local `codex` CLI binary, not MCP. Install from https://platform.openai.com/docs/codex, run the current Codex auth/login flow, verify `codex --version`, then rerun.
250
+ > `--engine codex` and conditional VERIFY pair mode use the local `codex` CLI binary, not MCP. Install from https://platform.openai.com/docs/codex, run the current Codex auth/login flow, verify `codex --version`, then rerun.
249
251
 
250
252
  </details>
251
253
 
package/bin/devlyn.js CHANGED
@@ -7,7 +7,6 @@ const readline = require('readline');
7
7
  const { execSync } = require('child_process');
8
8
 
9
9
  const CONFIG_SOURCE = path.join(__dirname, '..', 'config');
10
- const AGENTS_SOURCE = path.join(__dirname, '..', 'agents-config');
11
10
  const OPTIONAL_SKILLS_SOURCE = path.join(__dirname, '..', 'optional-skills');
12
11
  const PKG = require('../package.json');
13
12
 
@@ -31,7 +30,6 @@ const CLI_TARGETS = {
31
30
  name: 'Codex CLI (OpenAI)',
32
31
  instructionsFile: 'AGENTS.md',
33
32
  baseInstructionsFile: 'AGENTS.md',
34
- configDir: null, // Codex uses AGENTS.md at project root
35
33
  // Codex auto-loads skills from ~/.codex/skills/ (user-global). Same
36
34
  // SKILL.md format as Claude Code; descriptions must stay ≤1024 chars.
37
35
  skillsDir: path.join(os.homedir(), '.codex', 'skills'),
@@ -42,7 +40,6 @@ const CLI_TARGETS = {
42
40
  name: 'oh-my-pi (omp)',
43
41
  instructionsFile: 'AGENTS.md',
44
42
  baseInstructionsFile: 'AGENTS.md',
45
- configDir: null, // omp discovers AGENTS.md at project root + user home
46
43
  // omp loads skills from ~/.agents/skills (user home) — shared with Pi.
47
44
  skillsDir: SHARED_AGENTS_SKILLS_DIR,
48
45
  skillsToInstall: DEVLYN_CORE_SKILLS,
@@ -54,37 +51,12 @@ const CLI_TARGETS = {
54
51
  name: 'Pi (earendil-works)',
55
52
  instructionsFile: 'AGENTS.md',
56
53
  baseInstructionsFile: 'AGENTS.md',
57
- configDir: null, // Pi reads AGENTS.md / CLAUDE.md walking up from cwd
58
54
  // Pi loads skills from ~/.agents/skills — shared with oh-my-pi.
59
55
  skillsDir: SHARED_AGENTS_SKILLS_DIR,
60
56
  skillsToInstall: DEVLYN_CORE_SKILLS,
61
57
  // Project-scoped only (see omp): machine-level ~/.pi must not auto-trigger.
62
58
  detect: () => fs.existsSync(path.join(process.cwd(), '.pi')) || fs.existsSync(path.join(process.cwd(), '.agents')),
63
59
  },
64
- gemini: {
65
- name: 'Gemini CLI (Google)',
66
- instructionsFile: 'GEMINI.md',
67
- configDir: null, // Gemini uses GEMINI.md at project root
68
- detect: () => fs.existsSync(path.join(process.cwd(), 'GEMINI.md')) || fs.existsSync(path.join(process.cwd(), '.gemini')),
69
- },
70
- cursor: {
71
- name: 'Cursor',
72
- instructionsFile: '.cursorrules',
73
- configDir: '.cursor/rules',
74
- detect: () => fs.existsSync(path.join(process.cwd(), '.cursorrules')) || fs.existsSync(path.join(process.cwd(), '.cursor')),
75
- },
76
- copilot: {
77
- name: 'GitHub Copilot',
78
- instructionsFile: '.github/copilot-instructions.md',
79
- configDir: '.github/copilot/agents',
80
- detect: () => fs.existsSync(path.join(process.cwd(), '.github', 'copilot-instructions.md')) || fs.existsSync(path.join(process.cwd(), '.github', 'copilot')),
81
- },
82
- windsurf: {
83
- name: 'Windsurf',
84
- instructionsFile: '.windsurfrules',
85
- configDir: '.windsurf/rules',
86
- detect: () => fs.existsSync(path.join(process.cwd(), '.windsurfrules')) || fs.existsSync(path.join(process.cwd(), '.windsurf')),
87
- },
88
60
  };
89
61
 
90
62
  // Files removed in previous versions that should be cleaned up on upgrade
@@ -214,7 +186,7 @@ const OPTIONAL_ADDONS = [
214
186
  { name: 'asset-creator', desc: 'AI pixel art game asset pipeline — generate, chroma-key, catalog', type: 'local' },
215
187
  { name: 'cloudflare-nextjs-setup', desc: 'Cloudflare Workers + Next.js deployment with OpenNext', type: 'local' },
216
188
  { name: 'generate-skill', desc: 'Create well-structured Claude Code skills following Anthropic best practices', type: 'local' },
217
- { name: 'prompt-engineering', desc: 'Claude 4 prompt optimization using Anthropic best practices', type: 'local' },
189
+ { name: 'prompt-engineering', desc: 'Claude prompt optimization using Anthropic best practices', type: 'local' },
218
190
  { name: 'better-auth-setup', desc: 'Production-ready Better Auth + Hono + Drizzle + PostgreSQL auth setup', type: 'local' },
219
191
  { name: 'polar-billing-setup', desc: 'Polar usage-based / metered billing — correct setup + diagnose silent $0-billing failures', type: 'local' },
220
192
  { name: 'pyx-scan', desc: 'Check whether an AI agent skill is safe before installing', type: 'local' },
@@ -596,15 +568,13 @@ function installSkillsForCLI(cliKey) {
596
568
  return copied;
597
569
  }
598
570
 
599
- // Strip devlyn's previously-appended "# Devlyn Agent Instructions" block from an
600
- // instruction file (or the packaged base) before re-appending, so installs stay
601
- // idempotent and never duplicate the block. Anchors on the LAST marker, not the
602
- // first: the packaged AGENTS.md ships its own "# Devlyn Agent Instructions"
603
- // section, so indexOf would truncate that real content — lastIndexOf targets the
604
- // devlyn-appended block (always last) and preserves everything above it.
571
+ // Strip the legacy "# Devlyn Agent Instructions" block (the retired evaluator
572
+ // agent) that earlier installs appended to instruction files, so upgrades scrub
573
+ // it instead of carrying it forever. Anchors on the LAST marker so user content
574
+ // above a stray copy of the block is preserved.
575
+ const DEVLYN_AGENTS_MARKER = '# Devlyn Agent Instructions';
605
576
  function stripManagedBlock(content) {
606
- const marker = '# Devlyn Agent Instructions';
607
- const markerIdx = content.lastIndexOf(marker);
577
+ const markerIdx = content.lastIndexOf(DEVLYN_AGENTS_MARKER);
608
578
  if (markerIdx > 0) {
609
579
  const sepIdx = content.lastIndexOf('\n---', markerIdx);
610
580
  return content.slice(0, sepIdx > 0 ? sepIdx : markerIdx).trimEnd();
@@ -613,63 +583,40 @@ function stripManagedBlock(content) {
613
583
  }
614
584
 
615
585
  // One-line description of exactly what selecting a CLI target installs, so the
616
- // unified selector stays honest — "Gemini" (instructions only) must not look
617
- // identical to "Codex" (instructions + skills).
586
+ // unified selector stays honest.
618
587
  function targetDesc(cli) {
619
588
  if (cli.skillsDir) {
620
589
  return `${cli.instructionsFile} + devlyn skills → ${cli.skillsDir.replace(os.homedir(), '~')}`;
621
590
  }
622
- if (cli.configDir) return `Agent instructions → ${cli.configDir}/`;
623
591
  return `${cli.instructionsFile} instructions only`;
624
592
  }
625
593
 
626
- // Install only the instruction file(s) for a CLI (no skills). Returns true when
627
- // instruction content was written. Split from skills so the de-dup driver can
628
- // write a shared destination (e.g. project AGENTS.md for codex/omp/pi) once.
594
+ // Install the packaged base instruction file for a CLI (project AGENTS.md for
595
+ // codex/omp/pi). Creates it from the packaged base when missing; on existing
596
+ // files, scrubs the legacy appended block and otherwise leaves user content
597
+ // untouched. Returns true when the destination was written.
629
598
  function installInstructionsForCLI(cliKey) {
630
599
  const cli = CLI_TARGETS[cliKey];
631
- if (!cli) return false;
632
-
633
- const agents = fs.existsSync(AGENTS_SOURCE)
634
- ? fs.readdirSync(AGENTS_SOURCE).filter((f) => f.endsWith('.md'))
635
- : [];
636
- if (agents.length === 0) return false;
637
-
638
- log(`\n🤖 Installing agent instructions for ${cli.name}...`, 'cyan');
639
-
640
- if (cli.configDir) {
641
- // CLI supports an agents directory — copy agent files there
642
- const destDir = path.join(process.cwd(), cli.configDir);
643
- if (!fs.existsSync(destDir)) {
644
- fs.mkdirSync(destDir, { recursive: true });
645
- }
646
- for (const file of agents) {
647
- const src = path.join(AGENTS_SOURCE, file);
648
- const dest = path.join(destDir, file);
649
- fs.copyFileSync(src, dest);
650
- log(` → ${cli.configDir}/${file}`, 'dim');
600
+ if (!cli || !cli.baseInstructionsFile) return false;
601
+
602
+ const destFile = path.join(process.cwd(), cli.instructionsFile);
603
+ let content = null;
604
+ if (fs.existsSync(destFile)) {
605
+ const current = fs.readFileSync(destFile, 'utf8');
606
+ if (current.includes(DEVLYN_AGENTS_MARKER)) {
607
+ content = stripManagedBlock(current) + '\n';
651
608
  }
652
609
  } else {
653
- // CLI uses a single instructions file — append agent content
654
- const destFile = path.join(process.cwd(), cli.instructionsFile);
655
- const separator = '\n\n---\n\n# Devlyn Agent Instructions\n\n';
656
- const agentContent = agents.map((file) => {
657
- return fs.readFileSync(path.join(AGENTS_SOURCE, file), 'utf8');
658
- }).join('\n\n---\n\n');
659
-
660
- let existing = '';
661
- if (fs.existsSync(destFile)) {
662
- existing = stripManagedBlock(fs.readFileSync(destFile, 'utf8'));
663
- } else if (cli.baseInstructionsFile) {
664
- const baseInstructionsSrc = path.join(__dirname, '..', cli.baseInstructionsFile);
665
- if (fs.existsSync(baseInstructionsSrc)) {
666
- existing = stripManagedBlock(fs.readFileSync(baseInstructionsSrc, 'utf8'));
667
- }
610
+ const baseInstructionsSrc = path.join(__dirname, '..', cli.baseInstructionsFile);
611
+ if (fs.existsSync(baseInstructionsSrc)) {
612
+ content = fs.readFileSync(baseInstructionsSrc, 'utf8');
668
613
  }
669
-
670
- fs.writeFileSync(destFile, existing + separator + agentContent + '\n');
671
- log(` → ${cli.instructionsFile} (agent instructions appended)`, 'dim');
672
614
  }
615
+ if (content === null) return false;
616
+
617
+ log(`\n🤖 Installing instructions for ${cli.name}...`, 'cyan');
618
+ fs.writeFileSync(destFile, content);
619
+ log(` → ${cli.instructionsFile}`, 'dim');
673
620
  return true;
674
621
  }
675
622
 
@@ -696,7 +643,7 @@ function installSelectedCLITargets(cliKeys) {
696
643
  for (const cliKey of cliKeys) {
697
644
  const cli = CLI_TARGETS[cliKey];
698
645
  if (!cli) continue;
699
- const instrKey = cli.configDir ? `dir:${cli.configDir}` : `file:${cli.instructionsFile}`;
646
+ const instrKey = cli.instructionsFile;
700
647
  if (!instrDone.has(instrKey)) {
701
648
  installInstructionsForCLI(cliKey);
702
649
  instrDone.add(instrKey);
@@ -1,10 +1,10 @@
1
- # Claude Opus adapter
1
+ # Claude adapter
2
2
 
3
3
  > Source: <https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices>
4
4
 
5
5
  ## Identity
6
6
 
7
- You are Claude Opus by Anthropic. Anthropic's prompt-engineering guide for this model governs your behavior on top of the canonical phase prompt below. When the canonical body and this header conflict on tactics, the canonical body wins on what to deliver; this header wins on how to deliver it.
7
+ You are Claude by Anthropic. Anthropic's prompt-engineering guide for this model governs your behavior on top of the canonical phase prompt below. When the canonical body and this header conflict on tactics, the canonical body wins on what to deliver; this header wins on how to deliver it.
8
8
 
9
9
  ## Output discipline
10
10
 
@@ -125,14 +125,14 @@ Top-level wrapper:
125
125
  "status": "sign | block",
126
126
  "blocked_ids": [],
127
127
  "signed_plan_sha256": "...", // canonical pre-stamp sha (see below)
128
- "model": "claude-opus-4-7",
128
+ "model": "<exact claude model id>",
129
129
  "timestamp": "2026-04-29T..."
130
130
  },
131
131
  "codex": {
132
132
  "status": "sign | block",
133
133
  "blocked_ids": [],
134
134
  "signed_plan_sha256": "...",
135
- "model": "gpt-5.5",
135
+ "model": "<exact codex model id>",
136
136
  "timestamp": "..."
137
137
  }
138
138
  }
@@ -28,7 +28,7 @@ Every phase reads `_shared/runtime-principles.md` (Subtractive-first / Goal-lock
28
28
  </harness_principles>
29
29
 
30
30
  <engine_routing>
31
- Each phase routes to an engine and prepends the per-engine adapter header from `_shared/adapters/<engine>.md` (e.g. `claude.md`, `codex.md`) to the canonical phase body. Adapter is the per-model delta (Anthropic's Opus prompt-engineering guide for Claude, OpenAI's GPT-5.5 guide for Codex). Canonical body is engine-agnostic.
31
+ Each phase routes to an engine and prepends the per-engine adapter header from `_shared/adapters/<engine>.md` (e.g. `claude.md`, `codex.md`) to the canonical phase body. Adapter is the per-model delta (Anthropic's prompt-engineering guide for Claude, OpenAI's prompt guidance for Codex). Canonical body is engine-agnostic.
32
32
 
33
33
  - Claude phases: spawn `Agent` (`mode: "bypassPermissions"`); prompt = adapter-header + canonical-body + task-context.
34
34
  - Codex phases: shell out via `bash _shared/codex-monitored.sh` with the same compounded prompt. The wrapper closes stdin and emits a heartbeat. No MCP.
@@ -39,7 +39,7 @@ Each phase routes to an engine and prepends the per-engine adapter header from `
39
39
  <modes>
40
40
  Three input shapes:
41
41
 
42
- 1. **Free-form**: `/devlyn:resolve "fix the login bug"`. PHASE 0 runs the complexity classifier and either proceeds with an internal mini-spec (trivial), drafts focused questions for in-prompt resolution (medium), or escalates to `/devlyn:ideate` (large/ambiguous). No mid-pipeline prompts in any branch.
42
+ 1. **Free-form**: `/devlyn:resolve "fix the login bug"` (inline goal) or `/devlyn:resolve --goal-file <path>` (goal text read from a file — the devlynd `ResolveAdapter` launcher path, injection-safe). PHASE 0 runs the complexity classifier and either proceeds with an internal mini-spec (trivial), drafts focused questions for in-prompt resolution (medium), or escalates to `/devlyn:ideate` (large/ambiguous). No mid-pipeline prompts in any branch.
43
43
  2. **Spec**: `/devlyn:resolve --spec docs/roadmap/phase-N/X.md`. Spec is read-only. Stage verification commands from sibling `spec.expected.json`; if absent, use the legacy `## Verification` JSON block.
44
44
  3. **Verify-only**: `/devlyn:resolve --verify-only <diff-or-PR-ref> --spec <path>`. Skips PHASE 1-4. Runs PHASE 5 (VERIFY) on the supplied diff against the spec.
45
45
  </modes>
@@ -58,6 +58,7 @@ Once `state.implement_passed_sha` is non-null (PHASE 2 returned and produced a d
58
58
  - `--engine MODE` (default `claude`) — picks the adapter for IMPLEMENT, CLEANUP, and the primary VERIFY judge. It does not disable VERIFY pair-mode; when a VERIFY pair trigger fires, the second judge uses the OTHER engine.
59
59
  - `--spec <path>` — switches to spec mode.
60
60
  - `--verify-only <ref>` — switches to verify-only mode. Requires `--spec`.
61
+ - `--goal-file <path>` — free-form mode: read the goal text from `<path>` (relative to cwd) instead of an inline positional goal. Used by the devlynd `ResolveAdapter` launcher (goal written to `.devlyn/goal.txt`, referenced by path — never inlined as argv). The file content is opaque goal text fed to the complexity classifier, **never re-parsed as flags**. Mutually exclusive with `--spec`, `--verify-only`, and an inline positional goal.
61
62
  - `--pair-verify` — force pair-mode JUDGE in PHASE 5 even when not auto-triggered.
62
63
  - `--no-pair` — disable conditional VERIFY pair-JUDGE for this run. Record `pair_trigger.skipped_reason: "user_no_pair"` whenever a trigger would otherwise fire.
63
64
  - `--risk-probes` — insert PHASE 1.5 cross-engine probe derivation. The OTHER engine converts visible `## Verification` bullets into bounded executable probes before IMPLEMENT; BUILD_GATE and VERIFY replay them mechanically.
@@ -67,12 +68,12 @@ Once `state.implement_passed_sha` is non-null (PHASE 2 returned and produced a d
67
68
 
68
69
  2. Engine pre-flight: follow `_shared/engine-preflight.md`. If a required engine is unavailable, halt with a BLOCKED verdict and setup instructions instead of downgrading.
69
70
 
70
- `--pair-verify` and `--no-pair` are mutually exclusive; if both are present, stop with `BLOCKED:invalid-flags`.
71
+ `--pair-verify` and `--no-pair` are mutually exclusive; if both are present, stop with `BLOCKED:invalid-flags`. Likewise `--goal-file` combined with `--spec`, `--verify-only`, or an inline positional goal — or a missing/repeated `--goal-file` value — stops with `BLOCKED:invalid-flags`. (These `BLOCKED:<reason>` strings are report-level only; the JSON `phases.*.verdict` carrier in `pipeline.state.json` always stays the bare enum `"BLOCKED"`.)
71
72
 
72
73
  3. Initialize `.devlyn/pipeline.state.json` per `references/state-schema.md`. Set `state.run_id`, `started_at`, `engine`, `pair_verify: true` only when `--pair-verify` was passed and `false` otherwise, `base_ref.{branch, sha}`, `rounds.{max_rounds, global: 0}`, `bypasses`, empty `phases`, empty `criteria`, and `risk_profile: { high_risk: false, reasons: [], risk_probes_enabled: false, pair_default_enabled: true }`. `risk_profile` is strict typed state: keep it an object, keep the three flags as JSON booleans, and keep `reasons` as a string array; never serialize booleans as strings.
73
74
 
74
75
  4. **Mode-specific init**:
75
- - **Free-form**: read `references/free-form-mode.md`. Run the complexity classifier deterministically (rules over keyword density / file count / spec-shape signals, plus pair-evidence intent). Set `state.complexity ∈ {trivial, medium, large}`. Trivial: write internal mini-spec to `.devlyn/criteria.generated.md` and proceed. Medium: synthesize a minimal spec from the goal + add 1-2 context anchors from the codebase, write to `.devlyn/criteria.generated.md`, proceed. Every free-form branch that writes criteria must set `state.source.type = "generated"`, `state.source.criteria_path = ".devlyn/criteria.generated.md"`, and `state.source.criteria_sha256` from the raw file bytes. Large: log `recommend: /devlyn:ideate first` in the final report and either halt (default) or proceed with assumed defaults if `--continue-on-large` flag set, except pair-evidence intent without an actionable solo-headroom hypothesis must halt with `BLOCKED:solo-headroom-hypothesis-required`, and unmeasured pair-candidate intent without solo ceiling avoidance must halt with `BLOCKED:solo-ceiling-avoidance-required`.
76
+ - **Free-form**: first resolve `goal_text` — the inline positional goal, OR (when `--goal-file <path>` was passed) the raw UTF-8 content of `<path>`, read as opaque goal text (never re-parsed as flags). Fail closed before classifying: empty/whitespace-only file → `BLOCKED:goal-file-empty`; missing/unreadable/not-a-regular-file/invalid-UTF-8 → `BLOCKED:goal-file-unreadable`; an absolute path, a `..` segment, or a path that canonicalizes outside cwd → `BLOCKED:goal-file-invalid-path`. (Like all PHASE-0 halts these are report-level `BLOCKED:<reason>` strings — no `phases.*.verdict` is written, so the bare-enum carrier rule is never violated.) Then read `references/free-form-mode.md` and run the complexity classifier deterministically on `goal_text` (rules over keyword density / file count / spec-shape signals, plus pair-evidence intent). Set `state.complexity ∈ {trivial, medium, large}`. Trivial: write internal mini-spec to `.devlyn/criteria.generated.md` and proceed. Medium: synthesize a minimal spec from the goal + add 1-2 context anchors from the codebase, write to `.devlyn/criteria.generated.md`, proceed. Every free-form branch that writes criteria must set `state.source.type = "generated"`, `state.source.criteria_path = ".devlyn/criteria.generated.md"`, and `state.source.criteria_sha256` from the raw file bytes. Large: log `recommend: /devlyn:ideate first` in the final report and either halt (default) or proceed with assumed defaults if `--continue-on-large` flag set, except pair-evidence intent without an actionable solo-headroom hypothesis must halt with `BLOCKED:solo-headroom-hypothesis-required`, and unmeasured pair-candidate intent without solo ceiling avoidance must halt with `BLOCKED:solo-ceiling-avoidance-required`.
76
77
  - **Spec**: validate spec exists. If sibling `spec.expected.json` exists, run `--check-expected <expected-path>` to validate both the expected contract, sibling spec `complexity` frontmatter, and any present actionable solo-headroom hypothesis; if the spec has a solo-headroom hypothesis, its observable command must match `spec.expected.json.verification_commands[].cmd`. Then stage `.devlyn/spec-verify.json` from `verification_commands`. Otherwise run `--check <spec-path>` to validate the legacy inline carrier plus supported `complexity` frontmatter and any present actionable solo-headroom hypothesis; if the spec uses an inline `## Verification` JSON carrier, any solo-headroom hypothesis command must match that carrier's `verification_commands[].cmd`. Then stage from the legacy inline carrier. Compute `state.source.spec_sha256`.
77
78
  - **Verify-only**: skip to PHASE 5 with `state.source.spec_path` set, the supplied diff captured at `.devlyn/external-diff.patch`.
78
79
 
@@ -1,6 +1,6 @@
1
1
  # Free-form mode — complexity classifier
2
2
 
3
- When `/devlyn:resolve` is invoked with a free-form goal (no `--spec`), PHASE 0 runs this classifier to set `state.complexity ∈ {trivial, medium, large}` and either proceeds with an internal mini-spec, drafts focused questions for in-prompt resolution, or recommends `/devlyn:ideate` first.
3
+ When `/devlyn:resolve` is invoked with a free-form goal (no `--spec`) — whether the goal is the inline positional text or the content of `--goal-file <path>` (PHASE 0 resolves `goal_text` from either source before classifying) — PHASE 0 runs this classifier to set `state.complexity ∈ {trivial, medium, large}` and either proceeds with an internal mini-spec, drafts focused questions for in-prompt resolution, or recommends `/devlyn:ideate` first.
4
4
 
5
5
  The classifier is rules-based / deterministic — not an LLM judgment call. Decision rules below.
6
6
 
@@ -71,7 +71,7 @@ Each entry under `phases.<name>` (for `plan`, `probe_derive`, `implement`, `buil
71
71
  "triggered_by": null,
72
72
  "verdict": "PASS",
73
73
  "engine": "claude",
74
- "model": "claude-opus-4-7",
74
+ "model": "<exact model id that ran this phase>",
75
75
  "pre_sha": null,
76
76
  "artifacts": { "findings_file": null, "log_file": null },
77
77
  "sub_verdicts": null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devlyn-cli",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "description": "AI development toolkit for Claude Code — ideate, resolve, and ship with context engineering and agent orchestration",
5
5
  "homepage": "https://github.com/fysoul17/devlyn-cli#readme",
6
6
  "bin": {
@@ -17,7 +17,6 @@
17
17
  "!config/skills/devlyn:auto-resolve-workspace/**",
18
18
  "!config/skills/roadmap-archival-workspace",
19
19
  "!config/skills/roadmap-archival-workspace/**",
20
- "agents-config",
21
20
  "optional-skills",
22
21
  "benchmark/auto-resolve/BENCHMARK-DESIGN.md",
23
22
  "benchmark/auto-resolve/BENCHMARK-RESULTS.md",
@@ -196,10 +196,11 @@ else
196
196
  fi
197
197
 
198
198
  # ---------------------------------------------------------------------------
199
- # 4. No stale Opus 4.6 benchmark references (should be 4.7 after P1).
199
+ # 4. No model-pinned Claude references, any generation. Engine-scope docs say
200
+ # "Claude"; exact model ids belong in run metadata only.
200
201
  # ---------------------------------------------------------------------------
201
- section "Check 4: No stale 'Claude Opus 4.6' in routing table"
202
- offenders=$(grep -RIln 'Claude Opus 4\.6' \
202
+ section "Check 4: No model-pinned Claude references"
203
+ offenders=$(grep -RIlnE 'Claude (Opus|Sonnet|Haiku|Fable)|claude-(opus|sonnet|haiku|fable)-[0-9]' \
203
204
  config/skills 2>/dev/null \
204
205
  | grep -v 'config/skills/roadmap-archival-workspace/' \
205
206
  | grep -v 'config/skills/devlyn:auto-resolve-workspace/' \
@@ -207,7 +208,7 @@ offenders=$(grep -RIln 'Claude Opus 4\.6' \
207
208
  | grep -v 'config/skills/preflight-workspace/' \
208
209
  || true)
209
210
  if [ -z "$offenders" ]; then
210
- ok "routing table on Opus 4.7"
211
+ ok "no model-pinned Claude references"
211
212
  else
212
213
  while IFS= read -r f; do bad "$f"; done <<< "$offenders"
213
214
  fi
@@ -1566,7 +1567,8 @@ fi
1566
1567
  section "Check 10c: User-facing current docs avoid retired skill surfaces"
1567
1568
  offenders=$(
1568
1569
  {
1569
- grep -nE '/devlyn:auto-resolve|ideate CHALLENGE|--with-codex|Quick Start pointing to ideate → auto-resolve → preflight|auto-resolve'\''s build agent|Core pipeline skills \(`ideate`, `auto-resolve`, `preflight`\)' README.md 2>/dev/null || true
1570
+ sed '/<!-- legacy-surface-map:begin/,/<!-- legacy-surface-map:end/s/.*//' README.md 2>/dev/null \
1571
+ | grep -nE '/devlyn:auto-resolve|ideate CHALLENGE|--with-codex|Quick Start pointing to ideate → auto-resolve → preflight|auto-resolve'\''s build agent|Core pipeline skills \(`ideate`, `auto-resolve`, `preflight`\)' || true
1570
1572
  grep -nE '"description": .*auto-resolve|"description": .*preflight' package.json 2>/dev/null || true
1571
1573
  grep -nE 'so auto-resolve doesn'\''t prompt' bin/devlyn.js 2>/dev/null || true
1572
1574
  grep -nE 'devlyn:auto-resolve|phase-1-build\.md|phase-2-evaluate\.md|phase-3-critic\.md' scripts/static-ab.sh 2>/dev/null || true
@@ -1,64 +0,0 @@
1
- # Evaluator Agent
2
-
3
- You are a code quality evaluator. Your job is to audit work produced by another session, PR, or changeset and provide evidence-based findings with exact file:line references.
4
-
5
- ## Before You Start
6
-
7
- 1. **Check for done criteria**: Read `.devlyn/runs/<run_id>/spec/expected.json` if a structured done-criteria source exists for the current run. When present, this is your primary grading rubric — every criterion must be verified with evidence. When absent, fall back to the checklists below.
8
-
9
- ## Calibration
10
-
11
- You will be too lenient by default. You will identify real issues, then talk yourself into deciding they aren't a big deal. Fight this tendency.
12
-
13
- **Rule**: When in doubt, score DOWN. A false negative ships broken code. A false positive costs minutes of review. The cost is asymmetric.
14
-
15
- - A catch block that logs but doesn't surface error to user = HIGH (not MEDIUM). Logging is not error handling.
16
- - A `let` that could be `const` = LOW note only. Linters catch this.
17
- - "The error handling is generally quite good" = WRONG. Count the instances. Name the files.
18
-
19
- ## Evaluation Process
20
-
21
- 1. **Discover scope**: Read the changeset (git diff, PR diff, or specified files)
22
- 2. **Assess correctness**: Find bugs, logic errors, silent failures, missing error handling
23
- 3. **Check architecture**: Verify patterns match existing codebase, no type duplication, proper wiring
24
- 4. **Verify spec compliance**: If a spec exists (HANDOFF.md, RFC, issue, done-criteria.md), compare requirements vs implementation
25
- 5. **Check error handling**: Every async operation needs loading, error, and empty states in UI. No silent catches.
26
- 6. **Review API contracts**: New endpoints must follow existing conventions for naming, validation, error envelopes
27
- 7. **Assess test coverage**: New modules need tests. Run the test suite and report results.
28
- 8. **Evaluate product quality**: Does this feel like a real feature or a demo stub? Are workflows complete end-to-end? Is the UI coherent?
29
-
30
- ## Rules
31
-
32
- - Every finding must have a file:line reference. No guesswork.
33
- - Classify by severity: CRITICAL (must fix), HIGH (should fix), MEDIUM (fix or justify), LOW (note)
34
- - Call out what's done well, not just problems
35
- - Look for cross-cutting patterns (e.g., same mistake repeated in multiple files)
36
-
37
- ## Output
38
-
39
- Write findings to `.devlyn/runs/<run_id>/eval-findings.md` for downstream consumption:
40
-
41
- ```markdown
42
- # Evaluation Findings
43
-
44
- ## Verdict: [PASS / PASS WITH ISSUES / NEEDS WORK / BLOCKED]
45
-
46
- ## Done Criteria Results (if a done-criteria source existed)
47
- - [x] [criterion] — VERIFIED: [evidence]
48
- - [ ] [criterion] — FAILED: [what's wrong, file:line]
49
-
50
- ## Findings Requiring Action
51
- ### CRITICAL
52
- - `file:line` — [description] — Fix: [suggested approach]
53
-
54
- ### HIGH
55
- - `file:line` — [description] — Fix: [suggested approach]
56
-
57
- ## Cross-Cutting Patterns
58
- - [pattern description]
59
-
60
- ## What's Good
61
- - [positive observations]
62
- ```
63
-
64
- Do NOT delete the run-directory artifacts (`spec/expected.json`, `eval-findings.md`) — the orchestrator or user is responsible for cleanup.