Skip to content
Merged
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
2 changes: 1 addition & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ defaults:
baseRef: main # optional; auto-detected when unset (origin default branch, else main/master/develop/trunk, else current branch)
pipeline: quick # pipeline used when -p/--pipeline is not given
autoAcceptJudgeModel: anthropic/claude-haiku-4-5 # model for smart auto-accept (--smart); defaults to the run's model
branchNameModel: openrouter/deepseek/deepseek-v4-flash-0731 # proposes worktree branch names (may look up referenced issues); you confirm the name
branchNameModel: openrouter/deepseek/deepseek-v4.1-flash # proposes worktree branch names (may look up referenced issues); you confirm the name
commitMessageModel: openai/gpt-5.6-luna # writes the conventional commit message for automatic run compaction and close's squash-merge commit
worktree: true # force a new branch + worktree for every run; false always runs in the current tree. Unset decides per branch (isolate on a trunk, run in place on a branch)
worktreeLocation: ~/dev/worktrees/{repo}/{branch} # where isolated worktrees are created ({repo}/{branch} placeholders, ~ = home; the branch slug is appended when {branch} is missing). A marker line in the repo's AGENTS.md/README.md outranks this; default ~/.convoy/worktrees
Expand Down
12 changes: 6 additions & 6 deletions docs/pipelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ PRD → implementer → patterns → security → design → tests → measure
└ fix┘
```

All model IDs below are public provider IDs. The former local NAN models use their OpenRouter equivalents: `openrouter/deepseek/deepseek-v4-flash-0731#high` and `openrouter/z-ai/glm-5.3-flash#high`.
All model IDs below are public provider IDs. The former local NAN models use their OpenRouter equivalents: `openrouter/deepseek/deepseek-v4.1-flash#high` and `openrouter/z-ai/glm-5.3-flash#high`.

| Step | Model | Advisor |
|---|---|---|
| `implementer` | DeepSeek V4 Flash 0731 · high | GPT 6 Astra · xhigh |
| `patterns` | DeepSeek V4 Flash 0731 · high | GLM 5.3 · high |
| `implementer` | DeepSeek V4.1 Flash · high | GPT 6 Astra · xhigh |
| `patterns` | DeepSeek V4.1 Flash · high | GLM 5.3 · high |
| `security` | GLM 5.3 Flash · high | GLM 5.3 · high |
| `design` | GLM 5.3 Flash · high | GPT 6 Astra · xhigh |
| `tests` | DeepSeek V4 Flash 0731 · high | GLM 5.3 · high |
| `tests` | DeepSeek V4.1 Flash · high | GLM 5.3 · high |
| Goal: independent scorers | Grok 4.6 · high + GLM 5.3 · high | — |
| Goal: verified consensus | GPT 5.6 Sol · xhigh | — |
| Goal: targeted fixes | DeepSeek V4 Flash 0731 · high | GPT 6 Astra · xhigh |
| Goal: targeted fixes | DeepSeek V4.1 Flash · high | GPT 6 Astra · xhigh |

The goal measures first, then fixes only reported gaps. It stops at **90/100**, after **five fix rounds**, or on the configured plateau limit (three rounds by default). A run that hits a limit can finish below the target; inspect its final score. Scorers read the original requirements and current diff without previous reports; the consensus reads only the current scorer reports and verifies their claims.

Expand All @@ -41,7 +41,7 @@ Select one with `-p/--pipeline`; no project config is needed. `full-cycle` is th
| Pipeline | Changes code? | What it does |
|---|---|---|
| `full-cycle` | yes | Implement, audit, polish and test with the models above, then independently score and fix gaps up to five times to reach 90/100. |
| `implement` | yes | DeepSeek V4 Flash implements with Astra xhigh advice. Patterns and tests use DeepSeek; security and design use GLM Flash. Those later steps run unadvised. Closes with a read-only DeepSeek recap at `reports/run-report.md`; no scoring loop. |
| `implement` | yes | DeepSeek V4.1 Flash implements with Astra xhigh advice. Patterns and tests use DeepSeek; security and design use GLM Flash. Those later steps run unadvised. Closes with a read-only DeepSeek recap at `reports/run-report.md`; no scoring loop. |
| `ship` | yes | Sync with the base; scope and review the diff across DeepSeek and GLM Flash; report, adversarially triage and fix accepted findings with Astra advice; recap; then score with Grok and GLM, reconcile on GLM and fix gaps up to five times to reach 90/100. |
| `review` | no | The report-only review: DeepSeek scopes and reports; clean-code, security and bug audits each run on DeepSeek and GLM Flash. Grok and GLM score independently, then GLM verifies the consensus. Produces findings and a quality score. |
| `fixer` | yes | Prove supplied findings with regression tests, apply targeted fixes, then independently rerun the checks. Terra xhigh handles all three phases; Astra xhigh advises reproduction and fixes. |
Expand Down
2 changes: 1 addition & 1 deletion docs/worktrees.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ An isolated run gets a new branch checked out in a dedicated worktree, leaving y

The branch is always agreed with you first, in a **Branch** step between Options and Review:

- An `Intended Branch Name` (or `git checkout -b …`) in the prompt is used as-is — the model is not asked to reinvent it. A short prompt that is just a path to a plan file is read first, so pasting `docs/plans/foo.md` still picks up the name inside. Otherwise `defaults.branchNameModel` (DeepSeek V4 Flash 0731 via OpenRouter by default) reads the prompt and proposes a conventional name — `feat/runtime-guard-limits`, `fix/login-redirect` — always in English, even when the prompt is not, keeping the document's own words rather than paraphrasing them. Prompts that only reference an issue (`#123`, `DEV-1339`, a URL) are looked up first, so the branch is named after what the issue is about.
- An `Intended Branch Name` (or `git checkout -b …`) in the prompt is used as-is — the model is not asked to reinvent it. A short prompt that is just a path to a plan file is read first, so pasting `docs/plans/foo.md` still picks up the name inside. Otherwise `defaults.branchNameModel` (DeepSeek V4.1 Flash via OpenRouter by default) reads the prompt and proposes a conventional name — `feat/runtime-guard-limits`, `fix/login-redirect` — always in English, even when the prompt is not, keeping the document's own words rather than paraphrasing them. Prompts that only reference an issue (`#123`, `DEV-1339`, a URL) are looked up first, so the branch is named after what the issue is about.
- The proposed name is shown in an editable field together with the worktree path it would take. Enter accepts it and moves on to Review; nothing is created until you confirm the run there.
- `tab` moves to the **hint** box: describe how you want it named ("name it after the budget limits") and press Enter or `ctrl+R` to re-name it. This is also what you get when the prompt is too thin to name anything, or when the naming model is unavailable — the step still opens, with a name derived from the prompt, ready to be edited.
- Names already taken by a branch or an existing worktree are suffixed (`-2`, `-3`) instead of failing `git worktree add` after the run has been confirmed.
Expand Down
2 changes: 1 addition & 1 deletion src/config-tui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2133,7 +2133,7 @@ export function describeDefault(key: keyof ConvoyDefaults): string {
case "autoAcceptJudgeModel":
return "Model the smart auto-accept judge uses (falls back to the run's model)."
case "branchNameModel":
return "Model that names worktree branches (default: openrouter/deepseek/deepseek-v4-flash-0731)."
return "Model that names worktree branches (default: openrouter/deepseek/deepseek-v4.1-flash)."
case "commitMessageModel":
return "Model that writes the conventional commit message for automatic run compaction and close (default: anthropic/claude-haiku-4-5)."
case "worktree":
Expand Down
4 changes: 2 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ defaults:
# maxConcurrentAgents: 30 # optional: cap agents running at once within a parallel group
# baseRef: main # optional: when unset, convoy auto-detects (origin default branch, else main/master/develop/trunk, else current branch)
# pipeline: full-cycle
# branchNameModel: openrouter/deepseek/deepseek-v4-flash-0731 # optional: model that names worktree branches
# branchNameModel: openrouter/deepseek/deepseek-v4.1-flash # optional: model that names worktree branches
# commitMessageModel: openai/gpt-5.6-luna # optional: model that writes the conventional commit message for automatic run compaction and close's squash-merge commit
# worktree: true # optional: force a fresh branch + worktree for every run; false always runs in the current tree. Unset decides per branch: isolate on a trunk (main/master/develop/trunk or the detected base), run in place on any other branch
# worktreeLocation: ~/dev/worktrees/{repo}/{branch} # optional: where isolated worktrees are created ({repo}/{branch} placeholders, ~ = home; the branch slug is appended when {branch} is missing). A marker in the repo's AGENTS.md/README.md outranks this; unusable locations fall back to ~/.convoy/worktrees
Expand Down Expand Up @@ -347,7 +347,7 @@ defaults:
# The \`implement\` pipeline is inlined below as an editable starting point; redefining a name here overrides the built-in.
pipelines:
implement:
description: Advised implementation on DeepSeek V4 Flash consulting Astra 6, then pattern/security audits, design polish, tests, and a one-page run recap
description: Advised implementation on DeepSeek V4.1 Flash consulting Astra 6, then pattern/security audits, design polish, tests, and a one-page run recap
# defaultPrompt and suggestedPrompts are optional. A defaultPrompt is used
# when the pipeline runs without an explicit prompt — the launcher prefills
# its field and \`convoy -p <pipeline>\` falls back to it — and the
Expand Down
14 changes: 7 additions & 7 deletions src/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ const opusViaOpenRouter = "openrouter/anthropic/claude-opus-5"
/** Grok 4.6 high: the review and ship scoring, plus one hunter audit track. */
const grokModel = "openrouter/x-ai/grok-4.6#high"
const kimiModel = "openrouter/moonshotai/kimi-k3"
/** DeepSeek V4 Flash 0731 on OpenRouter: the writer for `implement`, review's report, and the goal fixers. */
const deepseekModel = "openrouter/deepseek/deepseek-v4-flash-0731"
/** DeepSeek V4 Flash on OpenRouter with reasoning raised: used for writing, flash audits and run recaps. */
/** DeepSeek V4.1 Flash on OpenRouter: the writer for `implement`, review's report, and the goal fixers. */
const deepseekModel = "openrouter/deepseek/deepseek-v4.1-flash"
/** DeepSeek V4.1 Flash on OpenRouter with reasoning raised: used for writing, flash audits and run recaps. */
const deepseekHighModel = `${deepseekModel}#high`
/** GPT 5.6 Sol: the consensus reporter for full-cycle and the hunter pipelines at xhigh. */
const solModel = "openai/gpt-5.6-sol"
Expand Down Expand Up @@ -462,7 +462,7 @@ export const builtInPipelines: Record<string, PipelineSpec> = {
// Implementation follows the same model choices as full-cycle, but closes
// with a recap instead of running the quality loop. Only the writer is advised.
implement: {
description: "Advised implementation on DeepSeek V4 Flash consulting Astra 6, then pattern/security audits, design polish, tests, and a one-page run recap",
description: "Advised implementation on DeepSeek V4.1 Flash consulting Astra 6, then pattern/security audits, design polish, tests, and a one-page run recap",
steps: [
{ agent: "implementer", model: defaultImplementerModel, advisor: defaultImplementAdvisorModel, reports: "none" },
{ agent: "patterns", model: defaultImplementAuditModel, advisor: false },
Expand All @@ -475,7 +475,7 @@ export const builtInPipelines: Record<string, PipelineSpec> = {
// The default combines implementation with a terminal, independently scored goal loop.
"full-cycle": {
description:
"Implement with DeepSeek V4 Flash and GLM 5.3 Flash, advised by Astra 6 and GLM 5.3, then measure with Grok and GLM and a verified Sol consensus; fix gaps up to five times to reach 90/100.",
"Implement with DeepSeek V4.1 Flash and GLM 5.3 Flash, advised by Astra 6 and GLM 5.3, then measure with Grok and GLM and a verified Sol consensus; fix gaps up to five times to reach 90/100.",
steps: [
{ agent: "implementer", model: deepseekHighModel, advisor: astraXhighModel, reports: "none" },
{ agent: "patterns", model: deepseekHighModel, advisor: glm53HighModel },
Expand All @@ -489,7 +489,7 @@ export const builtInPipelines: Record<string, PipelineSpec> = {
improve: {
briefStep: "fix",
steps: [
// The directed fixer, on DeepSeek V4 Flash advised by Astra 6 (extra
// The directed fixer, on DeepSeek V4.1 Flash advised by Astra 6 (extra
// high). It alone receives the score brief (by step name). diff:
// true is load-bearing: as the fragment's first step it would
// otherwise default to no diff.
Expand Down Expand Up @@ -520,7 +520,7 @@ export const builtInPipelines: Record<string, PipelineSpec> = {
// Report-only audits on two flash models, followed by independent scoring.
review: {
description:
"Report-only PR review on ultra-cheap models: scope, parallel audits (DeepSeek V4 Flash + GLM 5.3 Flash) and report on flash models; the scoring uses GLM 5.3 high + Grok 4.6 high and the score consensus stays on GLM 5.3 high. Makes no changes.",
"Report-only PR review on ultra-cheap models: scope, parallel audits (DeepSeek V4.1 Flash + GLM 5.3 Flash) and report on flash models; the scoring uses GLM 5.3 high + Grok 4.6 high and the score consensus stays on GLM 5.3 high. Makes no changes.",
defaultPrompt: "Review the current branch against its base and report prioritized findings with a verified quality score.",
suggestedPrompts: ["Review the open PR for this branch", "Review only the last commit's diff"],
steps: [
Expand Down
2 changes: 1 addition & 1 deletion src/worktree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export type BranchNameProposal = {
}

/** Cheap, fast model used to synthesize a branch name from the prompt. */
export const defaultBranchNameModel = "openrouter/deepseek/deepseek-v4-flash-0731"
export const defaultBranchNameModel = "openrouter/deepseek/deepseek-v4.1-flash"

/** Registered so the namer replaces opencode's default coding agent instead of merely appending to it. */
const namerAgentName = "convoy-branch-namer"
Expand Down
4 changes: 2 additions & 2 deletions test/agents.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,12 +277,12 @@ describe("throughput routing in the opencode config", () => {
], undefined, {
throughputModels: [
{ providerID: "openrouter", modelID: "z-ai/glm-5.3" },
{ providerID: "openrouter", modelID: "deepseek/deepseek-v4-flash-0731" },
{ providerID: "openrouter", modelID: "deepseek/deepseek-v4.1-flash" },
],
})

expect(config.provider?.openrouter?.models?.["z-ai/glm-5.3"]).toEqual({ options: { provider: { sort: "throughput" } } })
expect(config.provider?.openrouter?.models?.["deepseek/deepseek-v4-flash-0731"]).toEqual({ options: { provider: { sort: "throughput" } } })
expect(config.provider?.openrouter?.models?.["deepseek/deepseek-v4.1-flash"]).toEqual({ options: { provider: { sort: "throughput" } } })
// Options-only entries: no name or limit is invented over the catalog's real model.
expect(config.provider?.openrouter?.models?.["z-ai/glm-5.3"]?.name).toBeUndefined()
expect(config.provider?.openrouter?.models?.["z-ai/glm-5.3"]?.limit).toBeUndefined()
Expand Down
6 changes: 3 additions & 3 deletions test/attach.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,11 @@ describe("reconstructedPhases", () => {
"pre-hook-1",
"sync",
"scope",
"clean-code__openrouter-deepseek-deepseek-v4-flash-0731-high",
"clean-code__openrouter-deepseek-deepseek-v4-1-flash-high",
"clean-code__openrouter-z-ai-glm-5-3-flash-high",
"security__openrouter-deepseek-deepseek-v4-flash-0731-high",
"security__openrouter-deepseek-deepseek-v4-1-flash-high",
"security__openrouter-z-ai-glm-5-3-flash-high",
"bugs__openrouter-deepseek-deepseek-v4-flash-0731-high",
"bugs__openrouter-deepseek-deepseek-v4-1-flash-high",
"bugs__openrouter-z-ai-glm-5-3-flash-high",
"report",
"triage",
Expand Down
2 changes: 1 addition & 1 deletion test/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1156,7 +1156,7 @@ describe("default config init", () => {
expect(body).toContain("# maxConcurrentAgents: 30")
expect(body).toContain("# baseRef: main")
expect(body).toContain("# pipeline: full-cycle")
expect(body).toContain("# branchNameModel: openrouter/deepseek/deepseek-v4-flash-0731")
expect(body).toContain("# branchNameModel: openrouter/deepseek/deepseek-v4.1-flash")
expect(body).toContain("# hooks:")
expect(body).toContain("# command: gh pr create --fill")
expect(body).toContain("# agents:")
Expand Down
6 changes: 3 additions & 3 deletions test/coordinate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,15 +294,15 @@ describe("runCoordinateBoot", () => {
const unresolved = advisedImplementerStep()
const resolved = {
...unresolved,
model: "openrouter/deepseek/deepseek-v4-flash-0731",
model: "openrouter/deepseek/deepseek-v4.1-flash",
resolvedModel: {
configured: "nan/deepseek-v4-flash#high",
logical: "nan/deepseek-v4-flash#high",
gateway: "nitro" as const,
providerID: "openrouter",
modelID: "deepseek/deepseek-v4-flash-0731",
modelID: "deepseek/deepseek-v4.1-flash",
variant: "high",
target: "openrouter/deepseek/deepseek-v4-flash-0731#high",
target: "openrouter/deepseek/deepseek-v4.1-flash#high",
},
resolvedAdvisor: {
configured: "openrouter/x-ai/grok-4.6#high",
Expand Down
10 changes: 5 additions & 5 deletions test/launch-tui.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ describe("launch TUI narrow-width row budgets", () => {
{ stepName: "score-report", groupId: "g2", kind: "agent" as const, modelLabel: "x-ai-grok-5", advisorLabel: "" },
],
improve: [
{ stepName: "fix", groupId: "g3", kind: "agent" as const, modelLabel: "deepseek-v4-flash", advisorLabel: "x-ai-grok-5 advisor ×3" },
{ stepName: "fix", groupId: "g3", kind: "agent" as const, modelLabel: "deepseek-v4.1-flash", advisorLabel: "x-ai-grok-5 advisor ×3" },
],
} satisfies GoalPreview
for (const width of widths) {
Expand Down Expand Up @@ -713,7 +713,7 @@ describe("launch TUI pipeline preview", () => {
{ stepName: "score-report", groupId: "g2", kind: "agent", modelLabel: "x-ai-grok-5", advisorLabel: "" },
],
improve: [
{ stepName: "fix", groupId: "g3", kind: "agent", modelLabel: "deepseek-v4-flash", advisorLabel: "x-ai-grok-5 advisor ×3" },
{ stepName: "fix", groupId: "g3", kind: "agent", modelLabel: "deepseek-v4.1-flash", advisorLabel: "x-ai-grok-5 advisor ×3" },
],
} satisfies GoalPreview

Expand All @@ -736,7 +736,7 @@ describe("launch TUI pipeline preview", () => {
// relationship, with their resolved models.
expect(lines).toContain(" ○ score · 2 models")
expect(lines).toContain(" ○ score-report · x-ai-grok-5")
expect(lines).toContain(" ○ fix · deepseek-v4-flash → x-ai-grok-5 advisor ×3")
expect(lines).toContain(" ○ fix · deepseek-v4.1-flash → x-ai-grok-5 advisor ×3")
})

test("goalLines collapses policy chips and fragment roles when the panel is narrow", () => {
Expand Down Expand Up @@ -1569,7 +1569,7 @@ describe("launch TUI goal classification", () => {
{ stepName: "score", groupId: "g1", kind: "agent", modelLabel: "glm-5.3-high", advisorLabel: "" },
{ stepName: "score-report", groupId: "g2", kind: "agent", modelLabel: "x-ai-grok-5", advisorLabel: "" },
],
improve: [{ stepName: "fix", groupId: "g3", kind: "agent", modelLabel: "deepseek-v4-flash", advisorLabel: "" }],
improve: [{ stepName: "fix", groupId: "g3", kind: "agent", modelLabel: "deepseek-v4.1-flash", advisorLabel: "" }],
},
}],
"configured",
Expand All @@ -1587,7 +1587,7 @@ describe("launch TUI goal classification", () => {
expect(detail).not.toContain("4 measurements")
expect(detail).toContain("measure · score ← score-report")
expect(detail).toContain("improve · brief → fix · then re-measure")
expect(detail).toContain("○ fix · deepseek-v4-flash")
expect(detail).toContain("○ fix · deepseek-v4.1-flash")
} finally {
await closeLauncher(launcher)
}
Expand Down
Loading