rafcode 2.1.1 → 2.3.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.
Files changed (135) hide show
  1. package/.claude/settings.local.json +4 -1
  2. package/CLAUDE.md +59 -11
  3. package/RAF/ahslfe-config-wizard/decisions.md +34 -0
  4. package/RAF/ahslfe-config-wizard/input.md +1 -0
  5. package/RAF/ahslfe-config-wizard/outcomes/01-define-config-schema.md +38 -0
  6. package/RAF/ahslfe-config-wizard/outcomes/02-refactor-codebase-to-use-config.md +67 -0
  7. package/RAF/ahslfe-config-wizard/outcomes/03-create-config-documentation.md +37 -0
  8. package/RAF/ahslfe-config-wizard/outcomes/04-implement-raf-config-command.md +47 -0
  9. package/RAF/ahslfe-config-wizard/outcomes/05-update-claude-md.md +26 -0
  10. package/RAF/ahslfe-config-wizard/plans/01-define-config-schema.md +73 -0
  11. package/RAF/ahslfe-config-wizard/plans/02-refactor-codebase-to-use-config.md +74 -0
  12. package/RAF/ahslfe-config-wizard/plans/03-create-config-documentation.md +57 -0
  13. package/RAF/ahslfe-config-wizard/plans/04-implement-raf-config-command.md +66 -0
  14. package/RAF/ahslfe-config-wizard/plans/05-update-claude-md.md +60 -0
  15. package/RAF/ahstvo-token-tracker/decisions.md +44 -0
  16. package/RAF/ahstvo-token-tracker/input.md +3 -0
  17. package/RAF/ahstvo-token-tracker/outcomes/01-full-model-id-support.md +43 -0
  18. package/RAF/ahstvo-token-tracker/outcomes/02-name-generation-no-session.md +33 -0
  19. package/RAF/ahstvo-token-tracker/outcomes/03-unify-stream-json-execution.md +48 -0
  20. package/RAF/ahstvo-token-tracker/outcomes/04-token-tracking-cost-calculation.md +53 -0
  21. package/RAF/ahstvo-token-tracker/outcomes/05-token-cost-console-reporting.md +57 -0
  22. package/RAF/ahstvo-token-tracker/outcomes/06-runtime-verbose-toggle.md +53 -0
  23. package/RAF/ahstvo-token-tracker/outcomes/07-readme-config-docs.md +36 -0
  24. package/RAF/ahstvo-token-tracker/plans/01-full-model-id-support.md +35 -0
  25. package/RAF/ahstvo-token-tracker/plans/02-name-generation-no-session.md +36 -0
  26. package/RAF/ahstvo-token-tracker/plans/03-unify-stream-json-execution.md +44 -0
  27. package/RAF/ahstvo-token-tracker/plans/04-token-tracking-cost-calculation.md +56 -0
  28. package/RAF/ahstvo-token-tracker/plans/05-token-cost-console-reporting.md +55 -0
  29. package/RAF/ahstvo-token-tracker/plans/06-runtime-verbose-toggle.md +48 -0
  30. package/RAF/ahstvo-token-tracker/plans/07-readme-config-docs.md +44 -0
  31. package/RAF/ahtahs-token-reaper/decisions.md +37 -0
  32. package/RAF/ahtahs-token-reaper/input.md +20 -0
  33. package/RAF/ahtahs-token-reaper/outcomes/01-extend-token-tracker-data-model.md +42 -0
  34. package/RAF/ahtahs-token-reaper/outcomes/02-accumulate-usage-in-retry-loop.md +31 -0
  35. package/RAF/ahtahs-token-reaper/outcomes/03-per-attempt-display-formatting.md +60 -0
  36. package/RAF/ahtahs-token-reaper/outcomes/04-add-model-name-to-claude-call-logs.md +57 -0
  37. package/RAF/ahtahs-token-reaper/outcomes/05-handle-invalid-config-in-raf-config.md +46 -0
  38. package/RAF/ahtahs-token-reaper/outcomes/06-fix-verbose-toggle-timer-display.md +38 -0
  39. package/RAF/ahtahs-token-reaper/plans/01-extend-token-tracker-data-model.md +36 -0
  40. package/RAF/ahtahs-token-reaper/plans/02-accumulate-usage-in-retry-loop.md +36 -0
  41. package/RAF/ahtahs-token-reaper/plans/03-per-attempt-display-formatting.md +43 -0
  42. package/RAF/ahtahs-token-reaper/plans/04-add-model-name-to-claude-call-logs.md +38 -0
  43. package/RAF/ahtahs-token-reaper/plans/05-handle-invalid-config-in-raf-config.md +36 -0
  44. package/RAF/ahtahs-token-reaper/plans/06-fix-verbose-toggle-timer-display.md +40 -0
  45. package/README.md +34 -0
  46. package/dist/commands/config.d.ts +3 -0
  47. package/dist/commands/config.d.ts.map +1 -0
  48. package/dist/commands/config.js +195 -0
  49. package/dist/commands/config.js.map +1 -0
  50. package/dist/commands/do.d.ts.map +1 -1
  51. package/dist/commands/do.js +55 -7
  52. package/dist/commands/do.js.map +1 -1
  53. package/dist/commands/plan.d.ts.map +1 -1
  54. package/dist/commands/plan.js +5 -3
  55. package/dist/commands/plan.js.map +1 -1
  56. package/dist/core/claude-runner.d.ts +19 -2
  57. package/dist/core/claude-runner.d.ts.map +1 -1
  58. package/dist/core/claude-runner.js +43 -96
  59. package/dist/core/claude-runner.js.map +1 -1
  60. package/dist/core/failure-analyzer.d.ts.map +1 -1
  61. package/dist/core/failure-analyzer.js +6 -3
  62. package/dist/core/failure-analyzer.js.map +1 -1
  63. package/dist/core/git.d.ts.map +1 -1
  64. package/dist/core/git.js +10 -3
  65. package/dist/core/git.js.map +1 -1
  66. package/dist/core/pull-request.d.ts +1 -1
  67. package/dist/core/pull-request.d.ts.map +1 -1
  68. package/dist/core/pull-request.js +9 -4
  69. package/dist/core/pull-request.js.map +1 -1
  70. package/dist/index.js +2 -0
  71. package/dist/index.js.map +1 -1
  72. package/dist/parsers/stream-renderer.d.ts +16 -1
  73. package/dist/parsers/stream-renderer.d.ts.map +1 -1
  74. package/dist/parsers/stream-renderer.js +34 -4
  75. package/dist/parsers/stream-renderer.js.map +1 -1
  76. package/dist/prompts/execution.d.ts.map +1 -1
  77. package/dist/prompts/execution.js +11 -1
  78. package/dist/prompts/execution.js.map +1 -1
  79. package/dist/types/config.d.ts +95 -4
  80. package/dist/types/config.d.ts.map +1 -1
  81. package/dist/types/config.js +63 -3
  82. package/dist/types/config.js.map +1 -1
  83. package/dist/utils/config.d.ts +65 -7
  84. package/dist/utils/config.d.ts.map +1 -1
  85. package/dist/utils/config.js +297 -21
  86. package/dist/utils/config.js.map +1 -1
  87. package/dist/utils/name-generator.d.ts +3 -7
  88. package/dist/utils/name-generator.d.ts.map +1 -1
  89. package/dist/utils/name-generator.js +75 -61
  90. package/dist/utils/name-generator.js.map +1 -1
  91. package/dist/utils/terminal-symbols.d.ts +25 -0
  92. package/dist/utils/terminal-symbols.d.ts.map +1 -1
  93. package/dist/utils/terminal-symbols.js +87 -0
  94. package/dist/utils/terminal-symbols.js.map +1 -1
  95. package/dist/utils/token-tracker.d.ts +55 -0
  96. package/dist/utils/token-tracker.d.ts.map +1 -0
  97. package/dist/utils/token-tracker.js +142 -0
  98. package/dist/utils/token-tracker.js.map +1 -0
  99. package/dist/utils/validation.d.ts +5 -5
  100. package/dist/utils/validation.d.ts.map +1 -1
  101. package/dist/utils/validation.js +10 -6
  102. package/dist/utils/validation.js.map +1 -1
  103. package/dist/utils/verbose-toggle.d.ts +33 -0
  104. package/dist/utils/verbose-toggle.d.ts.map +1 -0
  105. package/dist/utils/verbose-toggle.js +94 -0
  106. package/dist/utils/verbose-toggle.js.map +1 -0
  107. package/package.json +1 -1
  108. package/src/commands/config.ts +230 -0
  109. package/src/commands/do.ts +64 -6
  110. package/src/commands/plan.ts +5 -3
  111. package/src/core/claude-runner.ts +59 -115
  112. package/src/core/failure-analyzer.ts +6 -3
  113. package/src/core/git.ts +10 -3
  114. package/src/core/pull-request.ts +9 -4
  115. package/src/index.ts +2 -0
  116. package/src/parsers/stream-renderer.ts +54 -4
  117. package/src/prompts/config-docs.md +331 -0
  118. package/src/prompts/execution.ts +13 -1
  119. package/src/types/config.ts +156 -7
  120. package/src/utils/config.ts +357 -21
  121. package/src/utils/name-generator.ts +84 -71
  122. package/src/utils/terminal-symbols.ts +103 -0
  123. package/src/utils/token-tracker.ts +177 -0
  124. package/src/utils/validation.ts +15 -10
  125. package/src/utils/verbose-toggle.ts +103 -0
  126. package/tests/unit/claude-runner.test.ts +171 -7
  127. package/tests/unit/config-command.test.ts +242 -0
  128. package/tests/unit/config.test.ts +632 -30
  129. package/tests/unit/name-generator.test.ts +99 -75
  130. package/tests/unit/pull-request.test.ts +2 -0
  131. package/tests/unit/stream-renderer.test.ts +83 -0
  132. package/tests/unit/terminal-symbols.test.ts +245 -0
  133. package/tests/unit/timer-verbose-integration.test.ts +170 -0
  134. package/tests/unit/token-tracker.test.ts +685 -0
  135. package/tests/unit/verbose-toggle.test.ts +204 -0
@@ -28,7 +28,10 @@
28
28
  "Bash(git stash:*)",
29
29
  "Bash(git checkout:*)",
30
30
  "WebFetch(domain:docs.anthropic.com)",
31
- "WebFetch(domain:news.ycombinator.com)"
31
+ "WebFetch(domain:news.ycombinator.com)",
32
+ "Bash(chmod:*)",
33
+ "Bash(bash:*)",
34
+ "Bash(git add:*)"
32
35
  ]
33
36
  }
34
37
  }
package/CLAUDE.md CHANGED
@@ -17,9 +17,10 @@ RAF (Ralph's Automation Framework) is a Node.js CLI tool that orchestrates task
17
17
  ```
18
18
  src/
19
19
  ├── index.ts # CLI entry point
20
- ├── commands/ # CLI commands (plan, do, status)
20
+ ├── commands/ # CLI commands (plan, do, status, config)
21
21
  ├── core/ # Core business logic
22
22
  ├── prompts/ # System prompts for Claude
23
+ │ └── config-docs.md # Full config reference (used by raf config)
23
24
  ├── parsers/ # Output parsing utilities
24
25
  ├── utils/ # Utility functions
25
26
  └── types/ # TypeScript type definitions
@@ -133,6 +134,38 @@ npm run lint # Type check without emit
133
134
  - Failure reports include: Failure Reason, Analysis, Suggested Fix, Relevant Output
134
135
  - All failure outcomes end with `<promise>FAILED</promise>` marker
135
136
 
137
+ ### Configurable by Default
138
+ - If a feature or setting can be configurable, it should be configurable through the config system
139
+ - Built-in defaults in `DEFAULT_CONFIG` (`src/types/config.ts`) provide sensible out-of-the-box behavior
140
+ - Global config at `~/.raf/raf.config.json` overrides defaults
141
+ - CLI flags override config values
142
+ - Three-tier precedence: **CLI flag > global config > built-in defaults**
143
+ - When adding new features, add corresponding config keys to the schema
144
+
145
+ ### Configuration System
146
+ - **Config file**: `~/.raf/raf.config.json` (optional — missing file uses all defaults)
147
+ - **Schema** (defined in `src/types/config.ts`):
148
+ - `models.*` — Claude model per scenario (`execute`, `plan`, `nameGeneration`, `failureAnalysis`, `prGeneration`, `config`)
149
+ - `effort.*` — effort level per scenario (same scenarios as models)
150
+ - `timeout` — task timeout in seconds
151
+ - `maxRetries` — max retry attempts per task
152
+ - `autoCommit` — whether Claude auto-commits on task completion
153
+ - `worktree` — default worktree mode for plan/do commands
154
+ - `commitFormat.*` — commit message templates (`task`, `plan`, `amend`, `prefix`)
155
+ - `claudeCommand` — path/name of the Claude CLI binary
156
+ - **Validation**: strict — unknown keys rejected at every nesting level (`src/utils/config.ts`)
157
+ - **Deep-merge**: partial overrides merge with defaults (only specify keys you want to change)
158
+ - **Helper accessors**: `getModel()`, `getEffort()`, `getCommitFormat()`, `getCommitPrefix()`, `getTimeout()`, `getMaxRetries()`, `getAutoCommit()`, `getWorktreeDefault()`, `getClaudeCommand()` (all in `src/utils/config.ts`)
159
+ - **Full reference**: `src/prompts/config-docs.md` (also serves as system prompt for `raf config`)
160
+
161
+ ### `raf config` Command
162
+ - `raf config` — launches interactive Claude session for viewing/editing config
163
+ - `raf config "use haiku for name generation"` — session with initial prompt
164
+ - `raf config --reset` — deletes config file after confirmation prompt
165
+ - Session uses config documentation as system prompt and shows current config state
166
+ - Post-session validation checks the config file for errors and warns on issues
167
+ - Implementation: `src/commands/config.ts`
168
+
136
169
  ### Project Naming Convention
137
170
  - Format: `XXXXXX-project-name` where `XXXXXX` is a 6-character base26 ID (a-z only)
138
171
  - ID is generated from `(current_unix_seconds - RAF_EPOCH)` encoded as base26, left-padded with 'a' to 6 characters
@@ -159,26 +192,36 @@ Support multiple identifier formats in commands:
159
192
 
160
193
  Use `resolveProjectIdentifierWithDetails()` from `src/utils/paths.ts`
161
194
 
195
+ ### Token Usage Tracking
196
+ - After each task, RAF displays a per-task token summary (input/output tokens, cache tokens, estimated cost)
197
+ - After all tasks complete, RAF displays a grand total summary block
198
+ - Token data comes from Claude's `--output-format stream-json --verbose` result events
199
+ - Cost calculation uses configurable per-model pricing (`pricing.*` config keys)
200
+ - `TokenTracker` class (`src/utils/token-tracker.ts`) accumulates usage across tasks
201
+ - Formatting utilities in `src/utils/terminal-symbols.ts`: `formatTaskTokenSummary()`, `formatTokenTotalSummary()`, `formatNumber()`, `formatCost()`
202
+ - Failed tasks with partial usage data are still tracked in totals
203
+ - Tasks with no usage data (timeout, crash) are silently skipped
204
+
162
205
  ### Git Commit Schema
163
206
 
164
207
  All git commits are made by Claude during task execution. RAF does not create any automated commits.
165
208
 
166
- **Commit format** (Claude-generated during task execution):
167
- ```
168
- RAF[<project-number>:<task>] <description>
169
- ```
170
- Claude writes a concise description of what was accomplished, focusing on the actual change rather than the task name.
209
+ **Commit format** is configurable via `commitFormat.*` config keys. The default templates use `{placeholder}` syntax:
210
+ - `commitFormat.task`: `"{prefix}[{projectId}:{taskId}] {description}"` — task completion commits
211
+ - `commitFormat.plan`: `"{prefix}[{projectId}] Plan: {projectName}"` — plan commits
212
+ - `commitFormat.amend`: `"{prefix}[{projectId}] Amend: {projectName}"` — amendment commits
213
+ - `commitFormat.prefix`: `"RAF"` prefix token used in all templates
171
214
 
172
- Examples:
215
+ Default output example:
173
216
  ```
174
217
  RAF[abcdef:01] Add validation for user input fields
175
218
  RAF[abcdef:02] Fix null pointer in auth handler
176
- RAF[abaaba:03] Refactor database connection pooling
177
219
  ```
178
220
 
179
221
  - Claude commits code changes and outcome file together in one commit per task
180
222
  - No commits on failure (changes are stashed instead)
181
223
  - Handle "not in git repo" gracefully (warning, no crash)
224
+ - Template rendering: `renderCommitMessage()` in `src/utils/config.ts`
182
225
 
183
226
  ### Amendment Mode
184
227
  - `raf plan --amend <identifier>` adds tasks to existing projects
@@ -279,6 +322,11 @@ When working in a worktree, use absolute paths to the worktree directory for all
279
322
 
280
323
  ## Important Reminders
281
324
 
282
- 1. After task completion update README.md (user facing) and CLAUDE.md (internal)
283
- 2. Cover changes with tests - use TDD approach
284
- 3. Use Clean Architecture principles (SOLID)
325
+ 1. **Keep README.md updated** — Update the user-facing README when:
326
+ - A new CLI command is added (add usage section + Command Reference entry)
327
+ - Existing command flags or behavior change
328
+ - Important features are added (e.g., worktrees, config, token tracking)
329
+ - The Features list needs a new bullet point
330
+ 2. **Keep CLAUDE.md updated** — Update internal docs when architectural decisions, config keys, or conventions change
331
+ 3. Cover changes with tests - use TDD approach
332
+ 4. Use Clean Architecture principles (SOLID)
@@ -0,0 +1,34 @@
1
+ # Project Decisions
2
+
3
+ ## Config scope: should ALL hardcoded values become configurable, or only user-facing settings?
4
+ User-facing only. Only settings users care about: models, effort, timeouts, retries, worktree, commit format. Internal poll intervals, grace periods, and char limits stay hardcoded.
5
+
6
+ ## Model configuration: per-scenario or simpler approach?
7
+ Per-scenario models. Each scenario gets its own model key, e.g. models.plan: 'opus', models.execute: 'opus', models.nameGeneration: 'sonnet', etc.
8
+
9
+ ## Commit format: how configurable?
10
+ Template string. A template like `{prefix}[{projectId}:{taskId}] {description}` where users can change the prefix ('RAF') and structure.
11
+
12
+ ## `raf config` with no arguments: Claude session or editor?
13
+ Claude session. Always start an interactive Claude Sonnet session. User describes what they want in natural language, Claude edits config.
14
+
15
+ ## Reasoning effort: per-scenario or single global?
16
+ Per-scenario effort. Each scenario gets its own effort level, e.g. effort.plan: 'high', effort.execute: 'medium', effort.nameGeneration: 'low'.
17
+
18
+ ## Worktree default behavior?
19
+ Default off (current). Worktree is opt-in via --worktree flag. Config can flip this to make it default-on.
20
+
21
+ ## Config validation after changes?
22
+ Strict validation. Validate schema, reject unknown keys and invalid values. Show errors and don't save bad config.
23
+
24
+ ## Config file name?
25
+ raf.config.json — keep current name. Path: ~/.raf/raf.config.json
26
+
27
+ ## `raf config` Claude session mode?
28
+ Interactive TTY. Spawn an interactive Claude Sonnet session (like planning mode). User can have a conversation, ask questions, make multiple changes.
29
+
30
+ ## Config documentation location?
31
+ Bundled in package. Ship as part of the npm package (e.g., src/prompts/config-docs.md). Versioned with the code, injected at runtime.
32
+
33
+ ## Should there be a `raf config --reset`?
34
+ Yes, with confirmation prompt before deleting the config file (falling back to defaults).
@@ -0,0 +1 @@
1
+ - [ ] introduce config. go through the codebase and come up with config structure, ask me if something needs to be configured or not. also introduce "raf config [prompt]" that will take prompt and uses sonnet to make changes in raf config. make it json. store config in ~/.raf. create a .md doc with documentation and use it in instructions for "raf config [prompt or no prompt]" to start interactive session with claude (sonnet) to update config (claude will have appended system prompt with all the knowledge about config and how and where to change it). put in config stuff like reasoning, model choice per scenario (plan, do, project name generation etc.), worktree or not worktree by default, put there max setting you find in the repo (like commit format)
@@ -0,0 +1,38 @@
1
+ # Outcome: Define Config Schema & Defaults
2
+
3
+ ## Summary
4
+
5
+ Defined the comprehensive JSON config schema with all user-facing configurable values, validation, deep-merge, and typed helper accessors.
6
+
7
+ ## Key Changes
8
+
9
+ ### `src/types/config.ts`
10
+ - Replaced the old flat `RafConfig` interface with a comprehensive nested schema: `models`, `effort`, `commitFormat` sub-objects plus scalar fields (`timeout`, `maxRetries`, `autoCommit`, `worktree`, `claudeCommand`)
11
+ - Added `DEFAULT_CONFIG` constant with all defaults per the plan
12
+ - Added utility types: `ClaudeModelName`, `EffortLevel`, `ModelScenario`, `EffortScenario`, `CommitFormatType`, `DeepPartial<T>`, `UserConfig`
13
+ - Exported `VALID_MODELS` and `VALID_EFFORTS` arrays for validation
14
+ - Kept backward-compat `DEFAULT_RAF_CONFIG` export (deprecated) so existing consumers don't break
15
+
16
+ ### `src/utils/config.ts`
17
+ - Added `validateConfig()` — strict validation that rejects unknown keys at every nesting level, validates model names, effort levels, number ranges, and types
18
+ - Added `ConfigValidationError` class for typed error handling
19
+ - Added `resolveConfig(configPath?)` — loads from `~/.raf/raf.config.json`, validates, and deep-merges with defaults
20
+ - Added `saveConfig(configPath, userConfig)` — writes partial user config with directory creation
21
+ - Added helper accessors: `getModel()`, `getEffort()`, `getCommitFormat()`, `getCommitPrefix()`, `getTimeout()`, `getMaxRetries()`, `getAutoCommit()`, `getWorktreeDefault()`, `getClaudeCommand()`
22
+ - Added `getResolvedConfig()` with caching and `resetConfigCache()` for tests
23
+ - Kept backward-compat `loadConfig()`, `getConfig()`, `getEditor()`, `getClaudeModel()` functions
24
+
25
+ ### `tests/unit/config.test.ts`
26
+ - 50 tests covering: validation (unknown keys, invalid values, edge cases), deep-merge (partial nested overrides), resolveConfig (file loading, defaults, immutability), saveConfig, helper accessors, DEFAULT_CONFIG completeness
27
+
28
+ ## Acceptance Criteria
29
+
30
+ - [x] Comprehensive TypeScript types defined for the full config schema
31
+ - [x] DEFAULT_CONFIG constant covers all settings with sensible defaults
32
+ - [x] Validation rejects unknown keys, invalid model names, invalid effort levels, wrong types
33
+ - [x] Deep-merge works correctly (partial overrides, nested objects)
34
+ - [x] Config loads from `~/.raf/raf.config.json`
35
+ - [x] Helper functions provide typed access to config values
36
+ - [x] All tests pass (50/50; 1 pre-existing failure in unrelated test)
37
+
38
+ <promise>COMPLETE</promise>
@@ -0,0 +1,67 @@
1
+ # Outcome: Refactor Codebase to Use Config
2
+
3
+ ## Summary
4
+
5
+ Replaced all hardcoded settings throughout the codebase with config lookups using the schema from task 01. Every model name, effort level, commit format, and worktree default now reads from the centralized config system. CLI flags still take precedence over config values.
6
+
7
+ ## Key Changes
8
+
9
+ ### `src/utils/config.ts`
10
+ - Added `renderCommitMessage(template, variables)` utility that replaces `{placeholder}` tokens in commit format templates
11
+
12
+ ### `src/utils/name-generator.ts`
13
+ - Replaced hardcoded `SONNET_MODEL` constant with `getModel('nameGeneration')` from config
14
+ - Replaced hardcoded `'claude'` command with `getClaudeCommand()` from config
15
+ - Updated JSDoc comments to be model-agnostic
16
+
17
+ ### `src/core/failure-analyzer.ts`
18
+ - Replaced hardcoded `'haiku'` model with `getModel('failureAnalysis')` from config
19
+ - Uses `getClaudeCommand()` for CLI path resolution
20
+
21
+ ### `src/core/pull-request.ts`
22
+ - Replaced hardcoded `'sonnet'` model with `getModel('prGeneration')` from config
23
+ - Uses `getClaudeCommand()` for CLI path resolution
24
+
25
+ ### `src/core/claude-runner.ts`
26
+ - Replaced hardcoded `'opus'` default with `getModel('execute')` from config
27
+ - Uses `getClaudeCommand()` for CLI path resolution
28
+
29
+ ### `src/utils/validation.ts`
30
+ - `resolveModelOption()` now accepts a `scenario` parameter (defaults to `'execute'`)
31
+ - Default model comes from `getModel(scenario)` instead of hardcoded `'opus'`
32
+
33
+ ### `src/commands/plan.ts`
34
+ - Passes `'plan'` scenario to `resolveModelOption()` for correct model default
35
+ - Worktree mode default reads from `getWorktreeDefault()` config
36
+
37
+ ### `src/commands/do.ts`
38
+ - Passes `'execute'` scenario to `resolveModelOption()` for correct model default
39
+ - Replaced hardcoded `'medium'` effort with `getEffort('execute')` from config
40
+ - Worktree mode default reads from `getWorktreeDefault()` config
41
+
42
+ ### `src/prompts/execution.ts`
43
+ - Commit format in execution prompt dynamically generated from `getCommitFormat('task')` + `getCommitPrefix()` + `renderCommitMessage()`
44
+
45
+ ### `src/core/git.ts`
46
+ - Plan/amend commit messages use `getCommitFormat('plan')`/`getCommitFormat('amend')` + `getCommitPrefix()` + `renderCommitMessage()`
47
+
48
+ ### `tests/unit/pull-request.test.ts`
49
+ - Added `homedir` to the `node:os` mock (needed because `config.ts` is now imported transitively)
50
+
51
+ ### `tests/unit/config.test.ts`
52
+ - Added 20 new tests:
53
+ - 7 tests for `renderCommitMessage()` (basic replacement, unknown placeholders, all format types, custom prefix)
54
+ - 10 tests verifying defaults match previous hardcoded values (models, effort, timeout, maxRetries, autoCommit, worktree, claudeCommand, commit formats)
55
+ - 3 tests verifying config overrides work (custom models, effort, commit format)
56
+
57
+ ## Acceptance Criteria
58
+
59
+ - [x] No hardcoded model names remain in execution paths (only in DEFAULT_CONFIG)
60
+ - [x] No hardcoded effort levels remain in execution paths
61
+ - [x] Commit format uses templates from config
62
+ - [x] CLI flags override config values (resolveModelOption passes CLI value first, falls back to config)
63
+ - [x] Behavior is identical to before when no config file exists (defaults match current hardcoded values)
64
+ - [x] All existing tests still pass (1040/1041; 1 pre-existing failure in unrelated test)
65
+ - [x] New tests verify config integration (20 new tests)
66
+
67
+ <promise>COMPLETE</promise>
@@ -0,0 +1,37 @@
1
+ # Outcome: Create Config Documentation
2
+
3
+ ## Summary
4
+
5
+ Created comprehensive config documentation at `src/prompts/config-docs.md` that serves as both user-facing reference and system prompt for the `raf config` Claude session.
6
+
7
+ ## Key Changes
8
+
9
+ ### `src/prompts/config-docs.md` (new file)
10
+ - **Overview** section explaining config location (`~/.raf/raf.config.json`), caching, and optional-key semantics
11
+ - **File format** section explaining JSON format and deep-merge behavior with examples
12
+ - **Config reference** documenting every key:
13
+ - `models.*` (6 scenarios) — type, valid values (`sonnet`/`haiku`/`opus`), defaults, descriptions
14
+ - `effort.*` (6 scenarios) — type, valid values (`low`/`medium`/`high`), defaults, descriptions
15
+ - `timeout` — positive number, default 60
16
+ - `maxRetries` — non-negative integer, default 3
17
+ - `autoCommit` — boolean, default true
18
+ - `worktree` — boolean, default false
19
+ - `commitFormat.*` (4 keys) — template strings with `{placeholder}` syntax
20
+ - `claudeCommand` — non-empty string, default "claude"
21
+ - **Commit format template variables** documented per template type (task, plan, amend) with all available placeholders
22
+ - **Validation rules** section listing all rejection conditions (unknown keys, invalid values, type checks)
23
+ - **CLI precedence** section explaining flag > config > default order
24
+ - **4 example configs**: minimal (single override), common (cost-conscious), full (all defaults explicit), team branding (custom prefix)
25
+ - **Reset instructions** for full reset (delete file) and single-key reset (remove key)
26
+ - **Claude session instructions** covering: reading config, making changes (partial writes, validation, preserving keys), explaining changes, showing current config, common user requests
27
+
28
+ ## Acceptance Criteria
29
+
30
+ - [x] Every config key from the schema is documented with type, default, valid values, and description
31
+ - [x] Commit format template variables are fully documented
32
+ - [x] At least 3 example configs included (minimal, common, full, + team branding)
33
+ - [x] Claude session instructions are clear and complete
34
+ - [x] File is readable standalone as user documentation
35
+ - [x] File is at `src/prompts/config-docs.md`
36
+
37
+ <promise>COMPLETE</promise>
@@ -0,0 +1,47 @@
1
+ # Outcome: Implement `raf config` Command
2
+
3
+ ## Summary
4
+
5
+ Implemented the `raf config` CLI command that launches an interactive Claude Sonnet TTY session for viewing and editing RAF configuration, with `--reset` support and post-session validation.
6
+
7
+ ## Key Changes
8
+
9
+ ### `src/commands/config.ts` (new file)
10
+ - `createConfigCommand()` — Commander.js command definition with variadic `[prompt...]` argument and `--reset` flag
11
+ - `runConfigSession(initialPrompt?)` — Spawns interactive Claude TTY session with:
12
+ - Config documentation from `src/prompts/config-docs.md` as system prompt
13
+ - Current config file contents (or "no config file" message)
14
+ - Model from `config.models.config` (default: sonnet)
15
+ - Effort level from `config.effort.config` (default: medium) via `CLAUDE_CODE_EFFORT_LEVEL` env var
16
+ - `--dangerously-skip-permissions` so Claude can write to `~/.raf/raf.config.json`
17
+ - `handleReset()` — Prompts for confirmation via readline, deletes config file on confirm
18
+ - `postSessionValidation()` — After Claude session ends, reads and validates config file, reports success/warnings
19
+ - `loadConfigDocs()` — Reads the .md file at runtime using `import.meta.url` path resolution
20
+ - `getCurrentConfigState()` — Returns config file contents or "no config file" message
21
+ - `buildConfigSystemPrompt()` — Combines config docs and current state into system prompt
22
+
23
+ ### `src/index.ts`
24
+ - Registered `createConfigCommand()` so `raf config` appears in CLI help
25
+
26
+ ### `tests/unit/config-command.test.ts` (new file)
27
+ - 20 tests covering:
28
+ - Command setup (5): name, description, variadic argument, --reset option, parent registration
29
+ - Post-session validation (7): valid configs, unknown keys, invalid models/efforts, non-object, empty config
30
+ - Reset flow (2): file deletion, non-existent file handling
31
+ - Config file round-trip (3): write/read valid, invalid JSON detection, validation error detection
32
+ - System prompt construction (2): no-file state, existing config state
33
+
34
+ ## Acceptance Criteria
35
+
36
+ - [x] `raf config` starts an interactive Claude Sonnet session with config knowledge
37
+ - [x] `raf config "use haiku for name generation"` starts session with that prompt
38
+ - [x] `raf config --reset` prompts for confirmation and deletes config file
39
+ - [x] Claude session has full config documentation as system prompt
40
+ - [x] Claude session shows current config state
41
+ - [x] Post-session validation checks the config file
42
+ - [x] `~/.raf/` directory is created if it doesn't exist (Claude instructed to create it)
43
+ - [x] Command is registered and appears in `raf --help`
44
+ - [x] Tests cover command setup and reset flow (20 tests)
45
+ - [x] All tests pass (1060/1061; 1 pre-existing failure in unrelated test)
46
+
47
+ <promise>COMPLETE</promise>
@@ -0,0 +1,26 @@
1
+ # Outcome: Update CLAUDE.md with Config Architecture
2
+
3
+ ## Summary
4
+
5
+ Updated CLAUDE.md to document the new config system, the "configurable by default" principle, and the `raf config` command.
6
+
7
+ ## Key Changes
8
+
9
+ ### `CLAUDE.md`
10
+ - **Directory structure**: Updated commands comment to include `config`, added `config-docs.md` under `prompts/`
11
+ - **Configurable by Default** (new architectural decision): Documents the principle that all settings should be configurable, with three-tier precedence (CLI flag > global config > built-in defaults)
12
+ - **Configuration System** (new section): Documents config file location, schema overview, validation, deep-merge, helper accessors, and pointer to full reference
13
+ - **`raf config` Command** (new section): Documents all three usage modes (`raf config`, `raf config <prompt>`, `raf config --reset`)
14
+ - **Git Commit Schema**: Updated to reference configurable `commitFormat.*` templates with `{placeholder}` syntax instead of hardcoded format, added `renderCommitMessage()` reference
15
+
16
+ ## Acceptance Criteria
17
+
18
+ - [x] "Configurable by Default" principle documented as architectural decision
19
+ - [x] Config system fully documented (location, schema overview, precedence, validation)
20
+ - [x] `raf config` command documented
21
+ - [x] Directory structure updated
22
+ - [x] Old config references updated (commit format now references templates)
23
+ - [x] Commit format section references templates
24
+ - [x] CLAUDE.md remains well-organized and concise
25
+
26
+ <promise>COMPLETE</promise>
@@ -0,0 +1,73 @@
1
+ # Task: Define Config Schema & Defaults
2
+
3
+ ## Objective
4
+ Define the comprehensive JSON config schema with all user-facing configurable values and their defaults.
5
+
6
+ ## Context
7
+ RAF currently has a minimal config in `src/types/config.ts` with only `defaultTimeout`, `defaultMaxRetries`, `autoCommit`, and `claudeCommand`. Many values are hardcoded across the codebase. This task creates the complete schema that all subsequent tasks will use.
8
+
9
+ ## Requirements
10
+ - Config file: `~/.raf/raf.config.json`
11
+ - Built-in defaults embedded in code, global config in `~/.raf/` overrides them
12
+ - Strict validation: reject unknown keys and invalid values
13
+ - All values are optional in the file (defaults used for anything not specified)
14
+
15
+ ### Config structure (user-facing settings only):
16
+
17
+ **Models** (per-scenario):
18
+ - `models.plan` — model for planning sessions (default: `'opus'`)
19
+ - `models.execute` — model for task execution (default: `'opus'`)
20
+ - `models.nameGeneration` — model for project name generation (default: `'sonnet'`)
21
+ - `models.failureAnalysis` — model for analyzing failures (default: `'haiku'`)
22
+ - `models.prGeneration` — model for PR body generation (default: `'sonnet'`)
23
+ - `models.config` — model for config editing sessions (default: `'sonnet'`)
24
+ - Valid values: `'sonnet'`, `'haiku'`, `'opus'`
25
+
26
+ **Reasoning effort** (per-scenario):
27
+ - `effort.plan` — effort for planning (default: `'high'`)
28
+ - `effort.execute` — effort for task execution (default: `'medium'`)
29
+ - `effort.nameGeneration` — effort for name gen (default: `'low'`)
30
+ - `effort.failureAnalysis` — effort for failure analysis (default: `'low'`)
31
+ - `effort.prGeneration` — effort for PR gen (default: `'medium'`)
32
+ - `effort.config` — effort for config sessions (default: `'medium'`)
33
+ - Valid values: `'low'`, `'medium'`, `'high'`
34
+
35
+ **Execution**:
36
+ - `timeout` — default task timeout in minutes (default: `60`)
37
+ - `maxRetries` — max retry attempts per task (default: `3`)
38
+ - `autoCommit` — auto-commit on task success (default: `true`)
39
+
40
+ **Worktree**:
41
+ - `worktree` — use worktree by default for plan/do (default: `false`)
42
+
43
+ **Commit format**:
44
+ - `commitFormat.task` — template for task commits (default: `'{prefix}[{projectId}:{taskId}] {description}'`)
45
+ - `commitFormat.plan` — template for plan commits (default: `'{prefix}[{projectId}] Plan: {projectName}'`)
46
+ - `commitFormat.amend` — template for amend commits (default: `'{prefix}[{projectId}] Amend: {projectName}'`)
47
+ - `commitFormat.prefix` — the prefix used in templates (default: `'RAF'`)
48
+
49
+ **CLI**:
50
+ - `claudeCommand` — path/name of claude CLI binary (default: `'claude'`)
51
+
52
+ ## Implementation Steps
53
+ 1. Replace the existing `RafConfig` type in `src/types/config.ts` with the new comprehensive schema (nested objects for `models`, `effort`, `commitFormat`)
54
+ 2. Define a `DEFAULT_CONFIG` constant with all default values
55
+ 3. Create a validation function that checks every key against the schema: valid model names, valid effort levels, number ranges, string formats, no unknown keys
56
+ 4. Create a `resolveConfig()` function that deep-merges the default config with the user's partial config from `~/.raf/raf.config.json` — user values override defaults at the leaf level
57
+ 5. Update `src/utils/config.ts` to use the new schema — `loadConfig()` should read from `~/.raf/raf.config.json` (not project-local), validate, and merge with defaults
58
+ 6. Export helpers: `getModel(scenario)`, `getEffort(scenario)`, `getCommitFormat(type)`, `getTimeout()`, etc. for easy consumption
59
+ 7. Write tests for validation (unknown keys rejected, invalid values rejected, partial configs merged correctly, defaults returned when no config file exists)
60
+
61
+ ## Acceptance Criteria
62
+ - [ ] Comprehensive TypeScript types defined for the full config schema
63
+ - [ ] DEFAULT_CONFIG constant covers all settings with sensible defaults
64
+ - [ ] Validation rejects unknown keys, invalid model names, invalid effort levels, wrong types
65
+ - [ ] Deep-merge works correctly (partial overrides, nested objects)
66
+ - [ ] Config loads from `~/.raf/raf.config.json`
67
+ - [ ] Helper functions provide typed access to config values
68
+ - [ ] All tests pass
69
+
70
+ ## Notes
71
+ - The existing `RafConfig` type and `loadConfig`/`saveConfig` in `src/utils/config.ts` need to be replaced, not extended — they currently load from project-local dirs
72
+ - The commit format template uses `{placeholder}` syntax — the rendering will happen in task 02 when code is refactored
73
+ - Keep `src/types/config.ts` as the single source of truth for config types
@@ -0,0 +1,74 @@
1
+ # Task: Refactor Codebase to Use Config
2
+
3
+ ## Objective
4
+ Replace all hardcoded settings throughout the codebase with config lookups using the schema from task 01.
5
+
6
+ ## Context
7
+ The codebase has hardcoded model names, effort levels, timeouts, commit formats, and other settings scattered across many files. This task wires everything up to use the centralized config system.
8
+
9
+ ## Dependencies
10
+ 01
11
+
12
+ ## Requirements
13
+ - Every previously hardcoded user-facing setting must read from config
14
+ - CLI flags (--model, --timeout, etc.) still override config values
15
+ - Precedence: CLI flag > `~/.raf/raf.config.json` > built-in defaults
16
+ - No behavioral changes — existing defaults preserved, just sourced from config now
17
+
18
+ ### Files and values to refactor:
19
+
20
+ **Model references:**
21
+ - `src/utils/name-generator.ts` — hardcoded `'sonnet'` → `config.models.nameGeneration`
22
+ - `src/core/failure-analyzer.ts` — hardcoded `'haiku'` → `config.models.failureAnalysis`
23
+ - `src/core/pull-request.ts` — hardcoded `'sonnet'` → `config.models.prGeneration`
24
+ - `src/core/claude-runner.ts` — default `'opus'` → `config.models.execute`
25
+ - `src/utils/validation.ts` — default model `'opus'` → `config.models.plan` or `config.models.execute` depending on context
26
+ - `src/commands/plan.ts` — model resolution → config.models.plan as default
27
+ - `src/commands/do.ts` — model resolution → config.models.execute as default
28
+
29
+ **Effort levels:**
30
+ - `src/commands/do.ts` — hardcoded `'medium'` → `config.effort.execute`
31
+ - Pass effort to name-generator, failure-analyzer, PR-generator from config
32
+
33
+ **Timeouts:**
34
+ - `src/commands/do.ts` — default `'60'` → `config.timeout`
35
+ - `src/utils/name-generator.ts` — `30000` timeout
36
+ - `src/core/failure-analyzer.ts` — `60000` timeout
37
+ - `src/core/pull-request.ts` — `120000` timeout
38
+
39
+ **Commit formats:**
40
+ - `src/prompts/execution.ts` — task commit format → `config.commitFormat.task` template
41
+ - `src/core/git.ts` — plan/amend commit formats → `config.commitFormat.plan` / `config.commitFormat.amend` templates
42
+ - Implement a `renderCommitMessage(template, vars)` utility that replaces `{placeholder}` tokens
43
+
44
+ **Worktree default:**
45
+ - `src/commands/plan.ts` — default worktree flag → `config.worktree`
46
+ - `src/commands/do.ts` — default worktree flag → `config.worktree`
47
+
48
+ **Other:**
49
+ - `src/commands/do.ts` — maxRetries, autoCommit → config values
50
+ - `src/utils/config.ts` — `claudeCommand` → config value
51
+
52
+ ## Implementation Steps
53
+ 1. Identify all call sites that need config access — use the file/line references above
54
+ 2. Create a `renderCommitMessage(template, variables)` utility for commit format templates
55
+ 3. Update each file to import and use config helpers instead of hardcoded values
56
+ 4. Ensure CLI flags take precedence: where a CLI flag is provided, use it; otherwise fall back to config
57
+ 5. Update the planning system prompt to include the configured commit format (so Claude knows what format to use)
58
+ 6. Update the execution system prompt similarly
59
+ 7. Write tests verifying that config values are respected and CLI flags override them
60
+ 8. Test that default behavior is unchanged when no config file exists
61
+
62
+ ## Acceptance Criteria
63
+ - [ ] No hardcoded model names remain in execution paths (only in DEFAULT_CONFIG)
64
+ - [ ] No hardcoded effort levels remain in execution paths
65
+ - [ ] Commit format uses templates from config
66
+ - [ ] CLI flags override config values
67
+ - [ ] Behavior is identical to before when no config file exists (defaults match current hardcoded values)
68
+ - [ ] All existing tests still pass
69
+ - [ ] New tests verify config integration
70
+
71
+ ## Notes
72
+ - Be careful with the precedence chain — some values go through multiple layers (CLI → command → runner)
73
+ - The commit format in system prompts needs to be dynamically generated, not static strings
74
+ - Don't change internal constants (poll intervals, grace periods, char limits) — those stay hardcoded per the decisions
@@ -0,0 +1,57 @@
1
+ # Task: Create Config Documentation
2
+
3
+ ## Objective
4
+ Create a comprehensive config documentation file bundled in the package that serves as both user-facing docs and the system prompt for the `raf config` Claude session.
5
+
6
+ ## Context
7
+ The `raf config` command will spawn an interactive Claude session that needs full knowledge of the config schema, valid values, defaults, and how to edit the file. This documentation serves double duty: it's readable by users and injected as a system prompt for Claude during config sessions.
8
+
9
+ ## Dependencies
10
+ 01
11
+
12
+ ## Requirements
13
+ - File location: `src/prompts/config-docs.md` (bundled in package, versioned with code)
14
+ - Must be comprehensive enough for Claude to edit config without any other context
15
+ - Must be readable by humans as standalone documentation
16
+ - Must cover every config key, its type, valid values, default, and what it controls
17
+
18
+ ### Content structure:
19
+ 1. **Overview** — what the config is, where it lives (`~/.raf/raf.config.json`), how it works
20
+ 2. **File format** — JSON, all keys optional, deep-merge with defaults
21
+ 3. **Config reference** — every key documented:
22
+ - Key path (e.g., `models.plan`)
23
+ - Type and valid values
24
+ - Default value
25
+ - What it controls and when it's used
26
+ - Example
27
+ 4. **Commit format templates** — explain the `{placeholder}` syntax, available variables per template type
28
+ 5. **Validation rules** — what gets rejected (unknown keys, invalid values)
29
+ 6. **Examples** — complete example configs for common scenarios (minimal, full, team-specific)
30
+ 7. **CLI precedence** — explain that CLI flags override config values
31
+ 8. **Reset instructions** — how to reset to defaults
32
+
33
+ ### Claude-specific instructions (for when used as system prompt):
34
+ - How to read the current config file
35
+ - How to validate changes before saving
36
+ - How to explain changes to the user
37
+ - Never remove keys the user didn't ask to change
38
+
39
+ ## Implementation Steps
40
+ 1. Write the documentation file at `src/prompts/config-docs.md` covering all sections above
41
+ 2. Reference the actual config schema types from task 01 to ensure completeness — every key in the schema must be documented
42
+ 3. Include practical examples showing partial configs (users only set what they want to change)
43
+ 4. Add a "For Claude" section at the end with instructions for the config editing session (read file, validate, explain, write)
44
+ 5. Ensure the file can be imported/read at runtime by the config command (task 04 will handle the actual import)
45
+
46
+ ## Acceptance Criteria
47
+ - [ ] Every config key from the schema is documented with type, default, valid values, and description
48
+ - [ ] Commit format template variables are fully documented
49
+ - [ ] At least 3 example configs included (minimal, common, full)
50
+ - [ ] Claude session instructions are clear and complete
51
+ - [ ] File is readable standalone as user documentation
52
+ - [ ] File is at `src/prompts/config-docs.md`
53
+
54
+ ## Notes
55
+ - This file will be read by Claude at runtime during `raf config` sessions — keep it clear and unambiguous
56
+ - The documentation must stay in sync with the schema — if schema changes, docs must update too
57
+ - Keep the tone practical and direct — this is a reference document, not a tutorial