This repository was archived by the owner on Aug 1, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
feat(plan): brief the feat, not the method, and discover its context once #89
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -61,7 +61,7 @@ func runPlan(args []string, templates embed.FS) int { | |||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| func planRun(args []string, templates embed.FS) int { | ||||||||||||||||||||||||||||||||||||||||||
| fs := flag.NewFlagSet("plan run", flag.ContinueOnError) | ||||||||||||||||||||||||||||||||||||||||||
| var root, model, effort string | ||||||||||||||||||||||||||||||||||||||||||
| var root, model, effort, enrichModel string | ||||||||||||||||||||||||||||||||||||||||||
| var autonomous, assumeYes, noTelegram bool | ||||||||||||||||||||||||||||||||||||||||||
| var sessionBudget float64 | ||||||||||||||||||||||||||||||||||||||||||
| var maxIterations, stall, featAttempts, maxRetries, maxRepairs, squadLimit int | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -72,6 +72,7 @@ func planRun(args []string, templates embed.FS) int { | |||||||||||||||||||||||||||||||||||||||||
| fs.BoolVar(&autonomous, "autonomous", false, "Deprecated no-op: plan run always runs bypass-mode (--dangerously-skip-permissions).") | ||||||||||||||||||||||||||||||||||||||||||
| fs.StringVar(&model, "model", "opus", "Model the orchestrating session runs on (claude --model): sonnet|opus|haiku|fable or a full model ID. It reviews and decides the spec; spec authoring is delegated to the `spec-author` sub-agent (sonnet) and task implementation to the `implementer` sub-agent (each on its own, cheaper model). Empty inherits the ambient default.") | ||||||||||||||||||||||||||||||||||||||||||
| fs.StringVar(&effort, "effort", "medium", "Reasoning effort the orchestrating session runs at (claude --effort): low|medium|high|xhigh|max. Empty inherits the ambient default.") | ||||||||||||||||||||||||||||||||||||||||||
| fs.StringVar(&enrichModel, "enrich-model", "sonnet", "Model the per-feat context pass runs on (claude --model). Before each feat is dispatched it reads the worktree once and records what the feat touches, what governs it and what is already there, so the orchestrator does not rediscover it every attempt. `none` turns the pass off and briefs from the plan alone.") | ||||||||||||||||||||||||||||||||||||||||||
| fs.Float64Var(&sessionBudget, "session-budget", 0, "Per-session cap in USD (claude --max-budget-usd). Default 0 = no cap; the session runs under the Claude account's own limits.") | ||||||||||||||||||||||||||||||||||||||||||
| fs.IntVar(&maxIterations, "max-iterations", 30, "Sessions the run may spend; one iteration is one claude session.") | ||||||||||||||||||||||||||||||||||||||||||
| fs.IntVar(&stall, "stall", 10, "Stop early after this many consecutive sessions without a step advancing.") | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -100,6 +101,11 @@ func planRun(args []string, templates embed.FS) int { | |||||||||||||||||||||||||||||||||||||||||
| render.Err(fmt.Sprintf("--squad-limit must be between 1 and %d (got %d)", planSquadLimitMax, squadLimit)) | ||||||||||||||||||||||||||||||||||||||||||
| return 1 | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| // `none` is how a human spells "no enrichment pass"; the runner reads an empty | ||||||||||||||||||||||||||||||||||||||||||
| // model as disabled. | ||||||||||||||||||||||||||||||||||||||||||
| if strings.EqualFold(strings.TrimSpace(enrichModel), "none") { | ||||||||||||||||||||||||||||||||||||||||||
| enrichModel = "" | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| if autonomous { | ||||||||||||||||||||||||||||||||||||||||||
| render.Warn("--autonomous is deprecated and now a no-op: plan run always runs bypass-mode") | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -136,6 +142,7 @@ func planRun(args []string, templates embed.FS) int { | |||||||||||||||||||||||||||||||||||||||||
| FeatAttempts: featAttempts, | ||||||||||||||||||||||||||||||||||||||||||
| SessionIdle: sessionIdle, | ||||||||||||||||||||||||||||||||||||||||||
| SquadLimit: squadLimit, | ||||||||||||||||||||||||||||||||||||||||||
| EnrichModel: enrichModel, | ||||||||||||||||||||||||||||||||||||||||||
| WorktreeEntry: planEntryDoc(templates), | ||||||||||||||||||||||||||||||||||||||||||
| Out: os.Stdout, | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -516,15 +523,18 @@ func planNext(args []string) int { | |||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| func planBrief(args []string) int { | ||||||||||||||||||||||||||||||||||||||||||
| fs := flag.NewFlagSet("plan brief", flag.ContinueOnError) | ||||||||||||||||||||||||||||||||||||||||||
| var root, feat string | ||||||||||||||||||||||||||||||||||||||||||
| var root, feat, enrichModel string | ||||||||||||||||||||||||||||||||||||||||||
| var refresh bool | ||||||||||||||||||||||||||||||||||||||||||
| addRoot(fs, &root) | ||||||||||||||||||||||||||||||||||||||||||
| fs.StringVar(&feat, "feat", "", "Feat to brief (default: the sequencer's next feat).") | ||||||||||||||||||||||||||||||||||||||||||
| fs.BoolVar(&refresh, "refresh", false, "Re-run the context pass for this feat before printing, replacing its stored pack. This is the same pass `plan run` makes before dispatching a feat, so it is how you review — and, by editing .csdd/plan/<slug>/briefs/<feat>.json, correct — what a session will be handed.") | ||||||||||||||||||||||||||||||||||||||||||
| fs.StringVar(&enrichModel, "enrich-model", "sonnet", "Model --refresh runs the context pass on (claude --model).") | ||||||||||||||||||||||||||||||||||||||||||
| positionals, err := parseFlags(fs, args) | ||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||
| return failOnFlagParse(err) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| if len(positionals) < 1 { | ||||||||||||||||||||||||||||||||||||||||||
| render.Err("usage: " + prog() + " plan brief SLUG [--feat F]") | ||||||||||||||||||||||||||||||||||||||||||
| render.Err("usage: " + prog() + " plan brief SLUG [--feat F] [--refresh]") | ||||||||||||||||||||||||||||||||||||||||||
| return 1 | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| r, doc, code := resolvePlan(root, positionals[0]) | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -551,6 +561,26 @@ func planBrief(args []string) int { | |||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| target = f | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| // --refresh runs the pass against the workspace itself rather than a worktree: | ||||||||||||||||||||||||||||||||||||||||||
| // there is no run in flight to have cut one, and the tree a human is looking at | ||||||||||||||||||||||||||||||||||||||||||
| // is the tree they are asking about. Diagnostics go to stderr so the brief on | ||||||||||||||||||||||||||||||||||||||||||
| // stdout stays a clean artifact to pipe or diff. | ||||||||||||||||||||||||||||||||||||||||||
| if refresh { | ||||||||||||||||||||||||||||||||||||||||||
| if err := plan.RemovePack(r, doc.Slug, target.Slug); err != nil { | ||||||||||||||||||||||||||||||||||||||||||
| render.Err(err.Error()) | ||||||||||||||||||||||||||||||||||||||||||
| return 1 | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| hook := plan.EnrichHook(enrichModel) | ||||||||||||||||||||||||||||||||||||||||||
| if hook == nil { | ||||||||||||||||||||||||||||||||||||||||||
| render.Err("--refresh needs a model: pass --enrich-model") | ||||||||||||||||||||||||||||||||||||||||||
| return 1 | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+568
to
+577
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
With 🔧 Proposed reorder if refresh {
+ hook := plan.EnrichHook(enrichModel)
+ if hook == nil {
+ render.Err("--refresh needs a model: pass --enrich-model")
+ return 1
+ }
if err := plan.RemovePack(r, doc.Slug, target.Slug); err != nil {
render.Err(err.Error())
return 1
}
- hook := plan.EnrichHook(enrichModel)
- if hook == nil {
- render.Err("--refresh needs a model: pass --enrich-model")
- return 1
- }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
| if plan.EnsurePack(r, doc, target, r, hook, func(format string, a ...any) { | ||||||||||||||||||||||||||||||||||||||||||
| render.Warn(strings.TrimSpace(fmt.Sprintf(format, a...))) | ||||||||||||||||||||||||||||||||||||||||||
| }) == nil { | ||||||||||||||||||||||||||||||||||||||||||
| render.Warn("the context pass produced nothing for " + target.Slug + "; briefing from the plan alone") | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| out, err := plan.FeatBrief(r, doc, target) | ||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||
| render.Err(err.Error()) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Align this section with the canonical plan-session contract.
The surrounding text still says the session owns branches and opens PRs, while
internal/templater/templates/plan/CLAUDE.md.tmplsays it must not create or switch branches, push, or open a PR. It also says the process lives in bothCLAUDE.mdandplan-dev, conflicting with the stated centralization inCLAUDE.md. Update this section so users and autonomous sessions receive one consistent contract.🤖 Prompt for AI Agents