Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions internal/orchestrator/orchestrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -711,12 +711,23 @@ func (o *Orchestrator) PlanPrompt(task *tasks.Task) string {
return o.buildPlanPrompt(task)
}

func taskSpecificPlanGuidance(task *tasks.Task) string {
switch task.Type {
case tasks.TaskCommitNormalize:
return "\n7. For commit normalization tasks, inspect recent commit subjects plus any release or changelog expectations, infer the local convention if none is documented, preserve Nightshift or other required trailers, and keep the scope to the active work branch or PR without rewriting unrelated history or installing git hooks."
default:
return ""
}
}

func (o *Orchestrator) buildPlanPrompt(task *tasks.Task) string {
branchInstruction := ""
if o.runMeta != nil && o.runMeta.Branch != "" {
branchInstruction = fmt.Sprintf("\n Create your feature branch from `%s`.", o.runMeta.Branch)
}

taskGuidance := taskSpecificPlanGuidance(task)

return fmt.Sprintf(`You are a planning agent. Create a detailed execution plan for this task.

## Task
Expand All @@ -733,15 +744,24 @@ Description: %s
Nightshift-Ref: https://github.com/marcus/nightshift
4. Analyze the task requirements
5. Identify files that need to be modified
6. Create step-by-step implementation plan
6. Create step-by-step implementation plan%s
7. Output only valid JSON (no markdown, no extra text). The output is read by a machine. Use this schema:

{
"steps": ["step1", "step2", ...],
"files": ["file1.go", "file2.go", ...],
"description": "overall approach"
}
`, task.ID, task.Title, task.Description, branchInstruction, task.Type)
`, task.ID, task.Title, task.Description, branchInstruction, task.Type, taskGuidance)
}

func taskSpecificImplementGuidance(task *tasks.Task) string {
switch task.Type {
case tasks.TaskCommitNormalize:
return "\n5. For commit normalization tasks, inspect recent commit subjects plus any release or changelog expectations, infer the local convention if none is documented, normalize only the relevant branch or PR commit messages, preserve Nightshift or other required trailers, avoid destructive rewrites beyond the task scope, and report assumptions if the target commit range is ambiguous."
default:
return ""
}
}

func (o *Orchestrator) buildImplementPrompt(task *tasks.Task, plan *PlanOutput, iteration int) string {
Expand All @@ -755,6 +775,8 @@ func (o *Orchestrator) buildImplementPrompt(task *tasks.Task, plan *PlanOutput,
branchInstruction = fmt.Sprintf("\n Checkout `%s` before creating your feature branch.", o.runMeta.Branch)
}

taskGuidance := taskSpecificImplementGuidance(task)

return fmt.Sprintf(`You are an implementation agent. Execute the plan for this task.

## Task
Expand All @@ -776,14 +798,14 @@ Description: %s
Nightshift-Ref: https://github.com/marcus/nightshift
2. Implement the plan step by step
3. Make all necessary code changes
4. Ensure tests pass
4. Ensure tests pass%s
5. Output a summary as JSON:

{
"files_modified": ["file1.go", ...],
"summary": "what was done"
}
`, task.ID, task.Title, task.Description, plan.Description, plan.Steps, iterationNote, branchInstruction, task.Type)
`, task.ID, task.Title, task.Description, plan.Description, plan.Steps, iterationNote, branchInstruction, task.Type, taskGuidance)
}

func (o *Orchestrator) buildReviewPrompt(task *tasks.Task, impl *ImplementOutput) string {
Expand Down
61 changes: 61 additions & 0 deletions internal/orchestrator/orchestrator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,67 @@ func TestBuildImplementPrompt_WithoutBranch(t *testing.T) {
}
}

func TestBuildPlanPrompt_CommitNormalizeIncludesRepoAwareGuidance(t *testing.T) {
o := New()

task := &tasks.Task{
ID: "commit-normalize:/tmp/nightshift",
Title: "Commit Message Normalizer",
Description: "Standardize commit message format",
Type: tasks.TaskCommitNormalize,
}

prompt := o.buildPlanPrompt(task)

expected := []string{
"recent commit subjects",
"release or changelog expectations",
"infer the local convention if none is documented",
"preserve Nightshift or other required trailers",
"active work branch or PR",
"without rewriting unrelated history or installing git hooks",
}

for _, want := range expected {
if !strings.Contains(prompt, want) {
t.Errorf("plan prompt missing %q\nGot:\n%s", want, prompt)
}
}
}

func TestBuildImplementPrompt_CommitNormalizeIncludesRepoAwareGuidance(t *testing.T) {
o := New()

task := &tasks.Task{
ID: "commit-normalize:/tmp/nightshift",
Title: "Commit Message Normalizer",
Description: "Standardize commit message format",
Type: tasks.TaskCommitNormalize,
}
plan := &PlanOutput{
Steps: []string{"Inspect recent commits", "Normalize active branch commits"},
Description: "Use the repo's recent commits to normalize the branch message style.",
}

prompt := o.buildImplementPrompt(task, plan, 1)

expected := []string{
"recent commit subjects",
"release or changelog expectations",
"infer the local convention if none is documented",
"normalize only the relevant branch or PR commit messages",
"preserve Nightshift or other required trailers",
"avoid destructive rewrites beyond the task scope",
"report assumptions if the target commit range is ambiguous",
}

for _, want := range expected {
if !strings.Contains(prompt, want) {
t.Errorf("implement prompt missing %q\nGot:\n%s", want, prompt)
}
}
}

func TestBuildMetadataBlock_WithBranch(t *testing.T) {
o := New()
o.SetRunMetadata(&RunMetadata{
Expand Down
Loading