Merge remote-tracking branch 'origin/dev' into fix/cli-run-premature-exit-with-background-tasks

This commit is contained in:
柯杨
2026-04-22 09:45:56 +08:00
390 changed files with 49705 additions and 41270 deletions
@@ -0,0 +1,7 @@
bun test v1.3.12 (700fc117)
1 pass
3 filtered out
0 fail
1 expect() calls
Ran 1 test across 1 file. [64.00ms]
@@ -0,0 +1,7 @@
bun test v1.3.12 (700fc117)
1 pass
3 filtered out
0 fail
1 expect() calls
Ran 1 test across 1 file. [65.00ms]
@@ -0,0 +1,7 @@
bun test v1.3.12 (700fc117)
1 pass
3 filtered out
0 fail
3 expect() calls
Ran 1 test across 1 file. [69.00ms]
@@ -0,0 +1,7 @@
bun test v1.3.12 (700fc117)
1 pass
3 filtered out
0 fail
12 expect() calls
Ran 1 test across 1 file. [61.00ms]
+10
View File
@@ -0,0 +1,10 @@
## 2026-04-18 Task 2: types module
- `MemberSchema` needs `.strict()` on the base shape so the discriminatedUnion rejects members that mix `category` and `subagent_type`.
- `backendType` and `isActive` defaults are part of the schema contract, so tests should use `toMatchObject` instead of exact object equality.
- The eligibility registry must preserve the plan strings verbatim, especially the hard-reject messages for Momus verification.
## Task 12 learnings
- `git worktree remove` can leave prunable entries behind, so pruning after removal keeps the repo index tidy.
- For testability, a tiny git command runner hook made git-unavailable coverage simpler than mocking Bun directly.
- Detached worktrees need unique temp paths in tests to avoid cross-run collisions.
+4 -4
View File
@@ -1,17 +1,17 @@
# oh-my-opencode — OpenCode Plugin # oh-my-opencode — OpenCode Plugin
**Generated:** 2026-04-11 | **Commit:** f5dc1c0e | **Branch:** dev **Generated:** 2026-04-18 | **Commit:** 2892ca4a | **Branch:** dev
## OVERVIEW ## OVERVIEW
OpenCode plugin (npm: `oh-my-opencode`) extending Claude Code with multi-agent orchestration, 52 lifecycle hooks, 26 tools, skill/command/MCP systems, Hashline edit tool, IntentGate classifier, and Claude Code compatibility. ~1600 TypeScript source files. Dual-published as `oh-my-opencode` + `oh-my-openagent` during transition. OpenCode plugin (npm: `oh-my-opencode`, dual-published as `oh-my-openagent` during transition) extending Claude Code with 11 agents, 52 lifecycle hooks, 26 tools, 3-tier MCP system (built-in + .mcp.json + skill-embedded), Hashline LINE#ID edit tool, IntentGate classifier, and Claude Code compatibility. 1766 TypeScript source files, 377k LOC, 104 barrel index.ts files. Entry: `src/index.ts` → 5-step init (loadConfig → createManagers → createTools → createHooks → createPluginInterface).
## STRUCTURE ## STRUCTURE
``` ```
oh-my-opencode/ oh-my-opencode/
├── src/ ├── src/
│ ├── index.ts # Plugin entry: loadConfig → createManagers → createTools → createHooks → createPluginInterface │ ├── index.ts # Plugin entry: default export `pluginModule`, shape `{ id, server }`
│ ├── plugin-config.ts # JSONC multi-level config: user → project → defaults (Zod v4) │ ├── plugin-config.ts # JSONC multi-level config: user → project → defaults (Zod v4)
│ ├── agents/ # 11 agents (Sisyphus, Hephaestus, Oracle, Librarian, Explore, Atlas, Prometheus, Metis, Momus, Multimodal-Looker, Sisyphus-Junior) │ ├── agents/ # 11 agents (Sisyphus, Hephaestus, Oracle, Librarian, Explore, Atlas, Prometheus, Metis, Momus, Multimodal-Looker, Sisyphus-Junior)
│ ├── hooks/ # 52 lifecycle hooks across dedicated modules and standalone files │ ├── hooks/ # 52 lifecycle hooks across dedicated modules and standalone files
@@ -33,7 +33,7 @@ oh-my-opencode/
## INITIALIZATION FLOW ## INITIALIZATION FLOW
``` ```
OhMyOpenCodePlugin(ctx) pluginModule.server(input, options)
├─→ loadPluginConfig() # JSONC parse → project/user merge → Zod validate → migrate ├─→ loadPluginConfig() # JSONC parse → project/user merge → Zod validate → migrate
├─→ createManagers() # TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler ├─→ createManagers() # TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler
├─→ createTools() # SkillContext + AvailableCategories + ToolRegistry (26 tools) ├─→ createTools() # SkillContext + AvailableCategories + ToolRegistry (26 tools)
+2 -2
View File
@@ -109,7 +109,7 @@ After making changes, you can test your local build in OpenCode:
``` ```
oh-my-opencode/ oh-my-opencode/
├── src/ ├── src/
│ ├── index.ts # Plugin entry (OhMyOpenCodePlugin) │ ├── index.ts # Plugin entry (V1 PluginModule, default export)
│ ├── plugin-config.ts # JSONC multi-level config (Zod v4) │ ├── plugin-config.ts # JSONC multi-level config (Zod v4)
│ ├── agents/ # 11 agents (Sisyphus, Hephaestus, Oracle, Librarian, Explore, Atlas, Prometheus, Metis, Momus, Multimodal-Looker, Sisyphus-Junior) │ ├── agents/ # 11 agents (Sisyphus, Hephaestus, Oracle, Librarian, Explore, Atlas, Prometheus, Metis, Momus, Multimodal-Looker, Sisyphus-Junior)
│ ├── hooks/ # 52 lifecycle hooks across 55 dedicated modules │ ├── hooks/ # 52 lifecycle hooks across 55 dedicated modules
@@ -183,7 +183,7 @@ import type { AgentConfig } from "./types";
export const myAgent: AgentConfig = { export const myAgent: AgentConfig = {
name: "my-agent", name: "my-agent",
model: "anthropic/claude-opus-4-6", model: "anthropic/claude-opus-4-7",
description: "Description of what this agent does", description: "Description of what this agent does",
prompt: `Your agent's system prompt here`, prompt: `Your agent's system prompt here`,
temperature: 0.1, temperature: 0.1,
+2 -2
View File
@@ -170,11 +170,11 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu
<td align="center"><img src=".github/assets/hephaestus.png" height="300" /></td> <td align="center"><img src=".github/assets/hephaestus.png" height="300" /></td>
</tr></table> </tr></table>
**Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) はあなたのメインのオーケストレーターです。計画を立て、専門家に委任し、攻撃的な並列実行でタスクを完了まで推進します。途中で投げ出すことはありません。 **Sisyphus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) はあなたのメインのオーケストレーターです。計画を立て、専門家に委任し、攻撃的な並列実行でタスクを完了まで推進します。途中で投げ出すことはありません。
**Hephaestus** (`gpt-5.4`) はあなたの自律的なディープワーカーです。レシピではなく、目標を与えてください。手取り足取り教えなくても、コードベースを探索し、パターンを研究し、端から端まで実行します。*正当なる職人 (The Legitimate Craftsman).* **Hephaestus** (`gpt-5.4`) はあなたの自律的なディープワーカーです。レシピではなく、目標を与えてください。手取り足取り教えなくても、コードベースを探索し、パターンを研究し、端から端まで実行します。*正当なる職人 (The Legitimate Craftsman).*
**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) はあなたの戦略プランナーです。インタビューモードで動作し、コードに触れる前に質問をしてスコープを特定し、詳細な計画を構築します。 **Prometheus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) はあなたの戦略プランナーです。インタビューモードで動作し、コードに触れる前に質問をしてスコープを特定し、詳細な計画を構築します。
すべてのエージェントは、それぞれのモデルの強みに合わせてチューニングされています。手動でモデルを切り替える必要はありません。[詳しくはこちら →](docs/guide/overview.md) すべてのエージェントは、それぞれのモデルの強みに合わせてチューニングされています。手動でモデルを切り替える必要はありません。[詳しくはこちら →](docs/guide/overview.md)
+2 -2
View File
@@ -164,11 +164,11 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu
<td align="center"><img src=".github/assets/hephaestus.png" height="300" /></td> <td align="center"><img src=".github/assets/hephaestus.png" height="300" /></td>
</tr></table> </tr></table>
**Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 메인 오케스트레이터입니다. 공격적인 병렬 실행으로 계획을 세우고, 전문가들에게 위임하며, 완료될 때까지 밀어붙입니다. 중간에 포기하는 법이 없습니다. **Sisyphus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 메인 오케스트레이터입니다. 공격적인 병렬 실행으로 계획을 세우고, 전문가들에게 위임하며, 완료될 때까지 밀어붙입니다. 중간에 포기하는 법이 없습니다.
**Hephaestus** (`gpt-5.4`)는 당신의 자율 딥 워커입니다. 레시피가 아니라 목표를 주세요. 베이비시터 없이 알아서 코드베이스를 탐색하고, 패턴을 연구하며, 끝에서 끝까지 전부 해냅니다. *진정한 장인(The Legitimate Craftsman).* **Hephaestus** (`gpt-5.4`)는 당신의 자율 딥 워커입니다. 레시피가 아니라 목표를 주세요. 베이비시터 없이 알아서 코드베이스를 탐색하고, 패턴을 연구하며, 끝에서 끝까지 전부 해냅니다. *진정한 장인(The Legitimate Craftsman).*
**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 전략 플래너입니다. 인터뷰 모드로 작동합니다. 코드 한 줄 만지기 전에 질문을 던져 스코프를 파악하고 상세한 계획부터 세웁니다. **Prometheus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 전략 플래너입니다. 인터뷰 모드로 작동합니다. 코드 한 줄 만지기 전에 질문을 던져 스코프를 파악하고 상세한 계획부터 세웁니다.
모든 에이전트는 해당 모델의 특장점에 맞춰 튜닝되어 있습니다. 수동으로 모델 바꿔가며 뻘짓하지 마세요. [더 알아보기 →](docs/guide/overview.md) 모든 에이전트는 해당 모델의 특장점에 맞춰 튜닝되어 있습니다. 수동으로 모델 바꿔가며 뻘짓하지 마세요. [더 알아보기 →](docs/guide/overview.md)
+2 -2
View File
@@ -166,11 +166,11 @@ Even only with following subscriptions, ultrawork will work well (this project i
<td align="center"><img src=".github/assets/hephaestus.png" height="300" /></td> <td align="center"><img src=".github/assets/hephaestus.png" height="300" /></td>
</tr></table> </tr></table>
**Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`** ) is your main orchestrator. He plans, delegates to specialists, and drives tasks to completion with aggressive parallel execution. He does not stop halfway. **Sisyphus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`** ) is your main orchestrator. He plans, delegates to specialists, and drives tasks to completion with aggressive parallel execution. He does not stop halfway.
**Hephaestus** (`gpt-5.4`) is your autonomous deep worker. Give him a goal, not a recipe. He explores the codebase, researches patterns, and executes end-to-end without hand-holding. *The Legitimate Craftsman.* **Hephaestus** (`gpt-5.4`) is your autonomous deep worker. Give him a goal, not a recipe. He explores the codebase, researches patterns, and executes end-to-end without hand-holding. *The Legitimate Craftsman.*
**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`** ) is your strategic planner. Interview mode: it questions, identifies scope, and builds a detailed plan before a single line of code is touched. **Prometheus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`** ) is your strategic planner. Interview mode: it questions, identifies scope, and builds a detailed plan before a single line of code is touched.
Every agent is tuned to its model's specific strengths. No manual model-juggling. [Learn more →](docs/guide/overview.md) Every agent is tuned to its model's specific strengths. No manual model-juggling. [Learn more →](docs/guide/overview.md)
+2 -2
View File
@@ -154,11 +154,11 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu
<table><tr> <td align="center"><img src=".github/assets/sisyphus.png" height="300" /></td> <td align="center"><img src=".github/assets/hephaestus.png" height="300" /></td> </tr></table> <table><tr> <td align="center"><img src=".github/assets/sisyphus.png" height="300" /></td> <td align="center"><img src=".github/assets/hephaestus.png" height="300" /></td> </tr></table>
**Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) — главный оркестратор. Он планирует, делегирует задачи специалистам и доводит их до завершения с агрессивным параллельным выполнением. Он не останавливается на полпути. **Sisyphus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) — главный оркестратор. Он планирует, делегирует задачи специалистам и доводит их до завершения с агрессивным параллельным выполнением. Он не останавливается на полпути.
**Hephaestus** (`gpt-5.4`) — автономный глубокий исполнитель. Дайте ему цель, а не рецепт. Он исследует кодовую базу, изучает паттерны и выполняет задачи сквозным образом без лишних подсказок. *Законный Мастер.* **Hephaestus** (`gpt-5.4`) — автономный глубокий исполнитель. Дайте ему цель, а не рецепт. Он исследует кодовую базу, изучает паттерны и выполняет задачи сквозным образом без лишних подсказок. *Законный Мастер.*
**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) — стратегический планировщик. Режим интервью: задаёт вопросы, определяет объём работ и формирует детальный план до того, как написана хотя бы одна строка кода. **Prometheus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) — стратегический планировщик. Режим интервью: задаёт вопросы, определяет объём работ и формирует детальный план до того, как написана хотя бы одна строка кода.
Каждый агент настроен под сильные стороны своей модели. Никакого ручного переключения между моделями. Подробнее → Каждый агент настроен под сильные стороны своей модели. Никакого ручного переключения между моделями. Подробнее →
+2 -2
View File
@@ -171,11 +171,11 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu
<td align="center"><img src=".github/assets/hephaestus.png" height="300" /></td> <td align="center"><img src=".github/assets/hephaestus.png" height="300" /></td>
</tr></table> </tr></table>
**Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) 是你的主指挥官。他负责制定计划、分配任务给专家团队,并以极其激进的并行策略推动任务直至完成。他从不半途而废。 **Sisyphus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) 是你的主指挥官。他负责制定计划、分配任务给专家团队,并以极其激进的并行策略推动任务直至完成。他从不半途而废。
**Hephaestus** (`gpt-5.4`) 是你的自主深度工作者。你只需要给他目标,不要给他具体做法。他会自动探索代码库模式,从头到尾独立执行任务,绝不会中途要你当保姆。*名副其实的正牌工匠。* **Hephaestus** (`gpt-5.4`) 是你的自主深度工作者。你只需要给他目标,不要给他具体做法。他会自动探索代码库模式,从头到尾独立执行任务,绝不会中途要你当保姆。*名副其实的正牌工匠。*
**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) 是你的战略规划师。他通过访谈模式,在动一行代码之前,先通过提问确定范围并构建详尽的执行计划。 **Prometheus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) 是你的战略规划师。他通过访谈模式,在动一行代码之前,先通过提问确定范围并构建详尽的执行计划。
每一个 Agent 都针对其底层模型的特点进行了专门调优。你无需手动来回切换模型。[阅读背景设定了解更多 →](docs/guide/overview.md) 每一个 Agent 都针对其底层模型的特点进行了专门调优。你无需手动来回切换模型。[阅读背景设定了解更多 →](docs/guide/overview.md)
-5
View File
@@ -5673,11 +5673,6 @@
"minimum": 1, "minimum": 1,
"maximum": 9007199254740991 "maximum": 9007199254740991
}, },
"maxDescendants": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
"staleTimeoutMs": { "staleTimeoutMs": {
"type": "number", "type": "number",
"minimum": 60000 "minimum": 60000
+26 -23
View File
@@ -21,26 +21,29 @@
"picomatch": "^4.0.2", "picomatch": "^4.0.2",
"posthog-node": "^5.29.2", "posthog-node": "^5.29.2",
"vscode-jsonrpc": "^8.2.0", "vscode-jsonrpc": "^8.2.0",
"zod": "^4.3.0",
}, },
"devDependencies": { "devDependencies": {
"@types/js-yaml": "^4.0.9", "@types/js-yaml": "^4.0.9",
"@types/picomatch": "^3.0.2", "@types/picomatch": "^3.0.2",
"bun-types": "1.3.11", "bun-types": "1.3.11",
"typescript": "^5.7.3", "typescript": "^5.7.3",
"zod": "^4.3.0",
}, },
"optionalDependencies": { "optionalDependencies": {
"oh-my-opencode-darwin-arm64": "3.17.2", "oh-my-opencode-darwin-arm64": "3.17.4",
"oh-my-opencode-darwin-x64": "3.17.2", "oh-my-opencode-darwin-x64": "3.17.4",
"oh-my-opencode-darwin-x64-baseline": "3.17.2", "oh-my-opencode-darwin-x64-baseline": "3.17.4",
"oh-my-opencode-linux-arm64": "3.17.2", "oh-my-opencode-linux-arm64": "3.17.4",
"oh-my-opencode-linux-arm64-musl": "3.17.2", "oh-my-opencode-linux-arm64-musl": "3.17.4",
"oh-my-opencode-linux-x64": "3.17.2", "oh-my-opencode-linux-x64": "3.17.4",
"oh-my-opencode-linux-x64-baseline": "3.17.2", "oh-my-opencode-linux-x64-baseline": "3.17.4",
"oh-my-opencode-linux-x64-musl": "3.17.2", "oh-my-opencode-linux-x64-musl": "3.17.4",
"oh-my-opencode-linux-x64-musl-baseline": "3.17.2", "oh-my-opencode-linux-x64-musl-baseline": "3.17.4",
"oh-my-opencode-windows-x64": "3.17.2", "oh-my-opencode-windows-x64": "3.17.4",
"oh-my-opencode-windows-x64-baseline": "3.17.2", "oh-my-opencode-windows-x64-baseline": "3.17.4",
},
"peerDependencies": {
"zod": "^4.0.0",
}, },
}, },
}, },
@@ -238,27 +241,27 @@
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
"oh-my-opencode-darwin-arm64": ["oh-my-opencode-darwin-arm64@3.17.2", "", { "os": "darwin", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-GcEMpe2Q9ocbXtJgcdY1ZnINdpyp+FU6lHeuhqSMaFj9Eba3QTZ7p87PKpV0rwHvQ2q4nyb47Am+JheKVptRhg=="], "oh-my-opencode-darwin-arm64": ["oh-my-opencode-darwin-arm64@3.17.4", "", { "os": "darwin", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-N135KhfHom/qiP3lgMHfY8DvRNVyOzZMuUs6p6uYTekLduSg3i72Pnc2WyNTZEKFX2yehaLjC5ireY8SnRCbdg=="],
"oh-my-opencode-darwin-x64": ["oh-my-opencode-darwin-x64@3.17.2", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-KEHAOljGrKMWlUWXLfcUiw32nVM2HhcxTYmjtoLdveiLUBEIidokFyCrXHZPU45BKIs1jVVGx4Q3qQrboAx7nA=="], "oh-my-opencode-darwin-x64": ["oh-my-opencode-darwin-x64@3.17.4", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-LSh5o4oC7ItuIoqd7s1UCAVZ5I7JftEBgeLoatUeto/8by1O6MYvm12ljjP8HIXLsnfi3nJfipqLyXAiiHDHPQ=="],
"oh-my-opencode-darwin-x64-baseline": ["oh-my-opencode-darwin-x64-baseline@3.17.2", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-BJhPlaQlAVDfGeCPY1fLe0UNVVSdYFq53ZYb61WVvhSgHnvakJGS6wSG+Al69RvAJx5qZ4i76Aw7CZWnLvDVLw=="], "oh-my-opencode-darwin-x64-baseline": ["oh-my-opencode-darwin-x64-baseline@3.17.4", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-caGra13pBdRoV/jCdRWZNeu8XUHUgIxBVn9guAJfT9bZ7AoBurqwO0wgJHUFghOydTdFxPBOGbSOYzJY3Hco5Q=="],
"oh-my-opencode-linux-arm64": ["oh-my-opencode-linux-arm64@3.17.2", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-AYE6gCM9uMbzf83Sja0qBpxvN4JZzOHpY0MbZGEN/zfzgAVF+9Xh0bx2zKDVWA6GHhgtTJKO7xIUal8f9mUgtQ=="], "oh-my-opencode-linux-arm64": ["oh-my-opencode-linux-arm64@3.17.4", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-P9BAlcybNmJn7ZEq4pKI/qeeP6eUJd0/M/unP+FCjKJE/UwY0YJTYS/Jf9PPZbLCgwbJErPglZe2Ku6t/NXAxQ=="],
"oh-my-opencode-linux-arm64-musl": ["oh-my-opencode-linux-arm64-musl@3.17.2", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-l4mRpCbx6ccFY1am6hD9qsrJxbwPVelHOplEdSdfvgPWiOIlDXoV5dsiGSOn5TbpjA7a3KNKXmctBK9utmkJwA=="], "oh-my-opencode-linux-arm64-musl": ["oh-my-opencode-linux-arm64-musl@3.17.4", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-F7HNYc/DygFsrraMbvXSQjb16NnC9EgtBsbWgHNkRm6UbxVHkWGIuVdHFEUJ1CqHPm2C/9xIuKJ5jiZrtEXqaA=="],
"oh-my-opencode-linux-x64": ["oh-my-opencode-linux-x64@3.17.2", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-0mqEN73FFAsk+CmvHR/FiOV0AavaNp7CI5c5W/57remxxY4bEfhs2Q+idhv6hbmraEvM/vxoTYMBhExogpo75A=="], "oh-my-opencode-linux-x64": ["oh-my-opencode-linux-x64@3.17.4", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-WgDiowJBI7nXxqFZDo3FbR0lRkxURrFbBjDVfpqj7jxRQfUrVtwedNjkgxCF8eBOQwoBrijTmxG40GiF4z219g=="],
"oh-my-opencode-linux-x64-baseline": ["oh-my-opencode-linux-x64-baseline@3.17.2", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-hNYG8laRQAS6akx3zKY8YXZ0kObseXjlU5gKe/7z0uAtSMgQhvyXn/uA68gwuU5eXNCDICwTJgxJOcI1vnYIFA=="], "oh-my-opencode-linux-x64-baseline": ["oh-my-opencode-linux-x64-baseline@3.17.4", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-BVJR1qiFe1WykrTBGYmd9XT387yR6VY8jupS/Pu0pqamRYBjeSlER4HQjOcrMY1XHJ/ygsspOcaWKJbSQ8Wcvw=="],
"oh-my-opencode-linux-x64-musl": ["oh-my-opencode-linux-x64-musl@3.17.2", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-3tPJ9INHwhAI24Guqi3p7LKbY+zKalQ7vPj5AhTWrWCCt7Lcr7zsTg0Atz2nMVl0UJ8xbBa2jNjn/dmFg1cDng=="], "oh-my-opencode-linux-x64-musl": ["oh-my-opencode-linux-x64-musl@3.17.4", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-qbLyLSc6bMAys6AwQnD4a3PR9KJNSDaMvA9DA9ARz9+yZ1tb7aA2JdEA24xAoxwct7k2EzxnQI+gssJJM4VUoQ=="],
"oh-my-opencode-linux-x64-musl-baseline": ["oh-my-opencode-linux-x64-musl-baseline@3.17.2", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-0TvudUyQvAcw6PM4wcZX7NY+xcyOIObJ9+kxYUU8e/saWYKVvkISBowzKDBjFuptbX4gVOvz6JVEfPaiCJxYNA=="], "oh-my-opencode-linux-x64-musl-baseline": ["oh-my-opencode-linux-x64-musl-baseline@3.17.4", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-ETqpbPN4HHc0wKfNSeAI2f0NE4nzUq+x85APomPRitVfTPxjdZbQd0TSc0O85vjT+kWj6cXjnHtviHB2BtxHog=="],
"oh-my-opencode-windows-x64": ["oh-my-opencode-windows-x64@3.17.2", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-LKr8v+o9KByFUhIvzc6MGLr7/k9hZjHfYnFfcdbiAPCwsIvr8j2RLcl0LhUg1OQD6/U5JikjVYPYGqKanD44QA=="], "oh-my-opencode-windows-x64": ["oh-my-opencode-windows-x64@3.17.4", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-RC34rbTJGtJeOvp2WTY4ZgVmtkjrduVmXCVMcIdgvQ53yNmNqx79nDITm9FVBA8Id02AHJbYmXGxKvr+XpHbNA=="],
"oh-my-opencode-windows-x64-baseline": ["oh-my-opencode-windows-x64-baseline@3.17.2", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-zVHptYD3Jzpah2301NAW7eNQ3WgW43cz4mGNrmj0jDpFQVeLy+UwXoGgFuYdZS8kuG9ARYtRA8e5M+0iAWnmbQ=="], "oh-my-opencode-windows-x64-baseline": ["oh-my-opencode-windows-x64-baseline@3.17.4", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-pi43bhDpt6l1fnxkqYYkWCsec1RNxsWL7FZDXoLOGJq/0y3bobWiTNDhbEWNr+uJvOrMs/Sv3qpF1TmYeTvdiA=="],
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
+1 -1
View File
@@ -8,7 +8,7 @@
// Primary orchestrator: aggressive parallel delegation // Primary orchestrator: aggressive parallel delegation
"sisyphus": { "sisyphus": {
"model": "kimi-for-coding/k2p5", "model": "kimi-for-coding/k2p5",
"ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" },
"prompt_append": "Delegate heavily to hephaestus for implementation. Parallelize exploration.", "prompt_append": "Delegate heavily to hephaestus for implementation. Parallelize exploration.",
}, },
+3 -3
View File
@@ -7,8 +7,8 @@
"agents": { "agents": {
// Main orchestrator: handles delegation and drives tasks to completion // Main orchestrator: handles delegation and drives tasks to completion
"sisyphus": { "sisyphus": {
"model": "anthropic/claude-opus-4-6", "model": "anthropic/claude-opus-4-7",
"ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" },
}, },
// Deep autonomous worker: end-to-end implementation // Deep autonomous worker: end-to-end implementation
@@ -50,7 +50,7 @@
"categories": { "categories": {
"quick": { "model": "opencode/gpt-5-nano" }, "quick": { "model": "opencode/gpt-5-nano" },
"unspecified-low": { "model": "anthropic/claude-sonnet-4-6" }, "unspecified-low": { "model": "anthropic/claude-sonnet-4-6" },
"unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, "unspecified-high": { "model": "anthropic/claude-opus-4-7", "variant": "max" },
"writing": { "model": "google/gemini-3-flash" }, "writing": { "model": "google/gemini-3-flash" },
"visual-engineering": { "model": "google/gemini-3.1-pro", "variant": "high" }, "visual-engineering": { "model": "google/gemini-3.1-pro", "variant": "high" },
"deep": { "model": "openai/gpt-5.4" }, "deep": { "model": "openai/gpt-5.4" },
+5 -5
View File
@@ -7,8 +7,8 @@
"agents": { "agents": {
// Orchestrator: delegates to planning agents first // Orchestrator: delegates to planning agents first
"sisyphus": { "sisyphus": {
"model": "anthropic/claude-opus-4-6", "model": "anthropic/claude-opus-4-7",
"ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" },
"prompt_append": "Always consult prometheus and atlas for planning. Never rush to implementation.", "prompt_append": "Always consult prometheus and atlas for planning. Never rush to implementation.",
}, },
@@ -20,7 +20,7 @@
// Primary planner: deep interview mode // Primary planner: deep interview mode
"prometheus": { "prometheus": {
"model": "anthropic/claude-opus-4-6", "model": "anthropic/claude-opus-4-7",
"thinking": { "type": "enabled", "budgetTokens": 160000 }, "thinking": { "type": "enabled", "budgetTokens": 160000 },
"prompt_append": "Interview extensively. Question assumptions. Build exhaustive plans with milestones, risks, and contingencies. Use deep & quick agents heavily in parallel for research.", "prompt_append": "Interview extensively. Question assumptions. Build exhaustive plans with milestones, risks, and contingencies. Use deep & quick agents heavily in parallel for research.",
}, },
@@ -43,7 +43,7 @@
// Plan review and refinement: heavily utilized // Plan review and refinement: heavily utilized
"metis": { "metis": {
"model": "anthropic/claude-opus-4-6", "model": "anthropic/claude-opus-4-7",
"prompt_append": "Critically evaluate plans. Identify gaps, risks, and improvements. Be thorough.", "prompt_append": "Critically evaluate plans. Identify gaps, risks, and improvements. Be thorough.",
}, },
@@ -98,7 +98,7 @@
"openai": 3, "openai": 3,
}, },
"modelConcurrency": { "modelConcurrency": {
"anthropic/claude-opus-4-6": 2, "anthropic/claude-opus-4-7": 2,
"openai/gpt-5.4": 2, "openai/gpt-5.4": 2,
}, },
}, },
+19 -19
View File
@@ -64,8 +64,8 @@ These agents have Claude-optimized prompts — long, detailed, mechanics-driven.
| Agent | Role | Fallback Chain | Notes | | Agent | Role | Fallback Chain | Notes |
| ------------ | ----------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------- | | ------------ | ----------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------- |
| **Sisyphus** | Main orchestrator | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → opencode-go\|vercel/kimi-k2.5 → kimi-for-coding/k2p5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix\|vercel/kimi-k2.5 → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (medium) → zai-coding-plan\|opencode\|vercel/glm-5 → opencode/big-pickle | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Sisyphus** | Main orchestrator | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → opencode-go\|vercel/kimi-k2.5 → kimi-for-coding/k2p5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix\|vercel/kimi-k2.5 → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (medium) → zai-coding-plan\|opencode\|vercel/glm-5 → opencode/big-pickle | Exact runtime chain from `src/shared/model-requirements.ts`. |
| **Metis** | Plan gap analyzer | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → opencode-go\|vercel/glm-5 → kimi-for-coding/k2p5 | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Metis** | Plan gap analyzer | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → opencode-go\|vercel/glm-5 → kimi-for-coding/k2p5 | Exact runtime chain from `src/shared/model-requirements.ts`. |
### Dual-Prompt Agents → Claude preferred, GPT supported ### Dual-Prompt Agents → Claude preferred, GPT supported
@@ -73,7 +73,7 @@ These agents ship separate prompts for Claude and GPT families. They auto-detect
| Agent | Role | Fallback Chain | Notes | | Agent | Role | Fallback Chain | Notes |
| -------------- | ----------------- | -------------------------------------- | -------------------------------------------------------------------- | | -------------- | ----------------- | -------------------------------------- | -------------------------------------------------------------------- |
| **Prometheus** | Strategic planner | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → opencode-go\|vercel/glm-5 → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Prometheus** | Strategic planner | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → opencode-go\|vercel/glm-5 → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro | Exact runtime chain from `src/shared/model-requirements.ts`. |
| **Atlas** | Todo orchestrator | anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → opencode-go\|vercel/kimi-k2.5 → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (medium) → opencode-go\|vercel/minimax-m2.7 | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Atlas** | Todo orchestrator | anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → opencode-go\|vercel/kimi-k2.5 → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (medium) → opencode-go\|vercel/minimax-m2.7 | Exact runtime chain from `src/shared/model-requirements.ts`. |
### Deep Specialists → GPT ### Deep Specialists → GPT
@@ -83,8 +83,8 @@ These agents are built for GPT's principle-driven style. Their prompts assume au
| Agent | Role | Fallback Chain | Notes | | Agent | Role | Fallback Chain | Notes |
| -------------- | ----------------------- | -------------------------------------- | ------------------------------------------------ | | -------------- | ----------------------- | -------------------------------------- | ------------------------------------------------ |
| **Hephaestus** | Autonomous deep worker | openai\|github-copilot\|venice\|opencode\|vercel/gpt-5.4 (medium) | Single-entry chain. Requires one of those providers. The craftsman. | | **Hephaestus** | Autonomous deep worker | openai\|github-copilot\|venice\|opencode\|vercel/gpt-5.4 (medium) | Single-entry chain. Requires one of those providers. The craftsman. |
| **Oracle** | Architecture consultant | openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → opencode-go\|vercel/glm-5 | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Oracle** | Architecture consultant | openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → opencode-go\|vercel/glm-5 | Exact runtime chain from `src/shared/model-requirements.ts`. |
| **Momus** | Ruthless reviewer | openai\|github-copilot\|opencode\|vercel/gpt-5.4 (xhigh) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → opencode-go\|vercel/glm-5 | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Momus** | Ruthless reviewer | openai\|github-copilot\|opencode\|vercel/gpt-5.4 (xhigh) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → opencode-go\|vercel/glm-5 | Exact runtime chain from `src/shared/model-requirements.ts`. |
### Utility Runners → Speed over Intelligence ### Utility Runners → Speed over Intelligence
@@ -92,8 +92,8 @@ These agents do grep, search, and retrieval. They intentionally use the fastest,
| Agent | Role | Fallback Chain | Notes | | Agent | Role | Fallback Chain | Notes |
| --------------------- | ------------------ | ---------------------------------------------- | ----------------------------------------------------- | | --------------------- | ------------------ | ---------------------------------------------- | ----------------------------------------------------- |
| **Explore** | Fast codebase grep | github-copilot\|xai\|vercel/grok-code-fast-1 → opencode-go\|vercel/minimax-m2.7-highspeed → opencode\|vercel/minimax-m2.7 → anthropic\|opencode\|vercel/claude-haiku-4-5 → opencode\|vercel/gpt-5-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Explore** | Fast codebase grep | openai/gpt-5.4-mini-fast → opencode-go\|vercel/minimax-m2.7-highspeed → opencode-go\|vercel/minimax-m2.7 → anthropic\|opencode\|vercel/claude-haiku-4-5 → openai\|opencode\|vercel/gpt-5.4-nano | Exact runtime chain from `src/shared/model-requirements.ts`. |
| **Librarian** | Docs/code search | opencode-go\|vercel/minimax-m2.7 → opencode\|vercel/minimax-m2.7-highspeed → anthropic\|opencode\|vercel/claude-haiku-4-5 → opencode\|vercel/gpt-5-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Librarian** | Docs/code search | openai/gpt-5.4-mini-fast → opencode-go\|vercel/minimax-m2.7-highspeed → opencode-go\|vercel/minimax-m2.7 → anthropic\|opencode\|vercel/claude-haiku-4-5 → openai\|opencode\|vercel/gpt-5.4-nano | Exact runtime chain from `src/shared/model-requirements.ts`. |
| **Multimodal Looker** | Vision/screenshots | openai\|opencode\|vercel/gpt-5.4 (medium) → opencode-go\|vercel/kimi-k2.5 → zai-coding-plan\|vercel/glm-4.6v → openai\|github-copilot\|opencode\|vercel/gpt-5-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Multimodal Looker** | Vision/screenshots | openai\|opencode\|vercel/gpt-5.4 (medium) → opencode-go\|vercel/kimi-k2.5 → zai-coding-plan\|vercel/glm-4.6v → openai\|github-copilot\|opencode\|vercel/gpt-5-nano | Exact runtime chain from `src/shared/model-requirements.ts`. |
| **Sisyphus-Junior** | Category executor | anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → opencode-go\|vercel/kimi-k2.5 → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (medium) → opencode-go\|vercel/minimax-m2.7 → opencode/big-pickle | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Sisyphus-Junior** | Category executor | anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → opencode-go\|vercel/kimi-k2.5 → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (medium) → opencode-go\|vercel/minimax-m2.7 → opencode/big-pickle | Exact runtime chain from `src/shared/model-requirements.ts`. |
@@ -107,7 +107,7 @@ Communicative, instruction-following, structured output. Best for agents that ne
| Model | Strengths | | Model | Strengths |
| --------------------- | ---------------------------------------------------------------------------- | | --------------------- | ---------------------------------------------------------------------------- |
| **Claude Opus 4.6** | Best overall. Highest compliance with complex prompts. Default for Sisyphus. | | **Claude Opus 4.7** | Best overall. Highest compliance with complex prompts. Default for Sisyphus. |
| **Claude Sonnet 4.6** | Faster, cheaper. Good balance for everyday tasks. | | **Claude Sonnet 4.6** | Faster, cheaper. Good balance for everyday tasks. |
| **Claude Haiku 4.5** | Fast and cheap. Good for quick tasks and utility work. | | **Claude Haiku 4.5** | Fast and cheap. Good for quick tasks and utility work. |
| **Kimi K2.5** | Behaves very similarly to Claude. Great all-rounder at lower cost. | | **Kimi K2.5** | Behaves very similarly to Claude. Great all-rounder at lower cost. |
@@ -130,7 +130,7 @@ Principle-driven, explicit reasoning, deep technical capability. Best for agents
| -------------------- | ------------------------------------------------------------------------------------------------------------ | | -------------------- | ------------------------------------------------------------------------------------------------------------ |
| **Gemini 3.1 Pro** | Excels at visual/frontend tasks. Different reasoning style. Default for `visual-engineering` and `artistry`. | | **Gemini 3.1 Pro** | Excels at visual/frontend tasks. Different reasoning style. Default for `visual-engineering` and `artistry`. |
| **Gemini 3 Flash** | Fast. Good for doc search and light tasks. | | **Gemini 3 Flash** | Fast. Good for doc search and light tasks. |
| **Grok Code Fast 1** | Blazing fast code grep. Default for Explore agent. | | **GPT-5.4 Mini Fast** | Default for Explore and Librarian agents. Blazing-fast reasoning-capable mini model. |
| **MiniMax M2.7** | Fast and smart. Used in OpenCode Go and OpenCode Zen utility fallback chains. | | **MiniMax M2.7** | Fast and smart. Used in OpenCode Go and OpenCode Zen utility fallback chains. |
| **MiniMax M2.7 Highspeed** | High-speed OpenCode catalog entry used in utility fallback chains that prefer the fastest available MiniMax path. | | **MiniMax M2.7 Highspeed** | High-speed OpenCode catalog entry used in utility fallback chains that prefer the fastest available MiniMax path. |
@@ -144,8 +144,8 @@ A premium subscription tier ($10/month) that provides reliable access to Chinese
| ------------------------ | --------------------------------------------------------------------- | | ------------------------ | --------------------------------------------------------------------- |
| **opencode-go/kimi-k2.5** | Vision-capable, Claude-like reasoning. Used by Sisyphus, Atlas, Sisyphus-Junior, Multimodal Looker. | | **opencode-go/kimi-k2.5** | Vision-capable, Claude-like reasoning. Used by Sisyphus, Atlas, Sisyphus-Junior, Multimodal Looker. |
| **opencode-go/glm-5** | Text-only orchestration model. Used by Oracle, Prometheus, Metis, Momus. | | **opencode-go/glm-5** | Text-only orchestration model. Used by Oracle, Prometheus, Metis, Momus. |
| **opencode-go/minimax-m2.7** | Ultra-cheap, fast responses. Used by Librarian, Atlas, and Sisyphus-Junior for utility work. | | **opencode-go/minimax-m2.7** | Ultra-cheap, fast responses. Used by Atlas, Sisyphus-Junior, Explore and Librarian fallbacks for utility work. |
| **opencode-go/minimax-m2.7-highspeed** | Even faster OpenCode Go MiniMax entry used by Explore when the high-speed catalog entry is available. | | **opencode-go/minimax-m2.7-highspeed** | Even faster OpenCode Go MiniMax entry used as a secondary fallback for Explore and Librarian when GPT-5.4 Mini Fast is unavailable. |
**When It Gets Used:** **When It Gets Used:**
@@ -169,12 +169,12 @@ When agents delegate work, they don't pick a model name — they pick a **catego
| Category | When Used | Fallback Chain | | Category | When Used | Fallback Chain |
| -------------------- | -------------------------- | -------------------------------------------- | | -------------------- | -------------------------- | -------------------------------------------- |
| `visual-engineering` | Frontend, UI, CSS, design | google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → zai-coding-plan\|opencode\|vercel/glm-5 → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → opencode-go\|vercel/glm-5 → kimi-for-coding/k2p5 | | `visual-engineering` | Frontend, UI, CSS, design | google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → zai-coding-plan\|opencode\|vercel/glm-5 → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → opencode-go\|vercel/glm-5 → kimi-for-coding/k2p5 |
| `ultrabrain` | Maximum reasoning needed | openai\|opencode\|vercel/gpt-5.4 (xhigh) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → opencode-go\|vercel/glm-5 | | `ultrabrain` | Maximum reasoning needed | openai\|opencode\|vercel/gpt-5.4 (xhigh) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → opencode-go\|vercel/glm-5 |
| `deep` | Deep coding, complex logic | openai\|github-copilot\|venice\|opencode\|vercel/gpt-5.4 (medium) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) | | `deep` | Deep coding, complex logic | openai\|github-copilot\|venice\|opencode\|vercel/gpt-5.4 (medium) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) |
| `artistry` | Creative, novel approaches | google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 | | `artistry` | Creative, novel approaches | google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 |
| `quick` | Simple, fast tasks | openai\|github-copilot\|opencode\|vercel/gpt-5.4-mini → anthropic\|github-copilot\|opencode\|vercel/claude-haiku-4-5 → google\|github-copilot\|opencode\|vercel/gemini-3-flash → opencode-go\|vercel/minimax-m2.7 → opencode\|vercel/gpt-5-nano | | `quick` | Simple, fast tasks | openai\|github-copilot\|opencode\|vercel/gpt-5.4-mini → anthropic\|github-copilot\|opencode\|vercel/claude-haiku-4-5 → google\|github-copilot\|opencode\|vercel/gemini-3-flash → opencode-go\|vercel/minimax-m2.7 → opencode\|vercel/gpt-5-nano |
| `unspecified-high` | General complex work | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → zai-coding-plan\|opencode\|vercel/glm-5 → kimi-for-coding/k2p5 → opencode-go\|vercel/glm-5 → opencode\|vercel/kimi-k2.5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix\|vercel/kimi-k2.5 | | `unspecified-high` | General complex work | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → zai-coding-plan\|opencode\|vercel/glm-5 → kimi-for-coding/k2p5 → opencode-go\|vercel/glm-5 → opencode\|vercel/kimi-k2.5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix\|vercel/kimi-k2.5 |
| `unspecified-low` | General standard work | anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → openai\|opencode\|vercel/gpt-5.3-codex (medium) → opencode-go\|vercel/kimi-k2.5 → google\|github-copilot\|opencode\|vercel/gemini-3-flash → opencode-go\|vercel/minimax-m2.7 | | `unspecified-low` | General standard work | anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → openai\|opencode\|vercel/gpt-5.3-codex (medium) → opencode-go\|vercel/kimi-k2.5 → google\|github-copilot\|opencode\|vercel/gemini-3-flash → opencode-go\|vercel/minimax-m2.7 |
| `writing` | Text, docs, prose | google\|github-copilot\|opencode\|vercel/gemini-3-flash → opencode-go\|vercel/kimi-k2.5 → anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → opencode-go\|vercel/minimax-m2.7 | | `writing` | Text, docs, prose | google\|github-copilot\|opencode\|vercel/gemini-3-flash → opencode-go\|vercel/kimi-k2.5 → anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → opencode-go\|vercel/minimax-m2.7 |
@@ -198,7 +198,7 @@ See the [Orchestration System Guide](./orchestration.md) for how agents dispatch
// Main orchestrator: Claude Opus or Kimi K2.5 work best // Main orchestrator: Claude Opus or Kimi K2.5 work best
"sisyphus": { "sisyphus": {
"model": "kimi-for-coding/k2p5", "model": "kimi-for-coding/k2p5",
"ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" },
}, },
// Research agents: cheaper models are fine // Research agents: cheaper models are fine
@@ -217,7 +217,7 @@ See the [Orchestration System Guide](./orchestration.md) for how agents dispatch
"categories": { "categories": {
"quick": { "model": "opencode/gpt-5-nano" }, "quick": { "model": "opencode/gpt-5-nano" },
"unspecified-low": { "model": "anthropic/claude-sonnet-4-6" }, "unspecified-low": { "model": "anthropic/claude-sonnet-4-6" },
"unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, "unspecified-high": { "model": "anthropic/claude-opus-4-7", "variant": "max" },
"visual-engineering": { "visual-engineering": {
"model": "google/gemini-3.1-pro", "model": "google/gemini-3.1-pro",
"variant": "high", "variant": "high",
@@ -234,7 +234,7 @@ See the [Orchestration System Guide](./orchestration.md) for how agents dispatch
"zai-coding-plan": 10, "zai-coding-plan": 10,
}, },
"modelConcurrency": { "modelConcurrency": {
"anthropic/claude-opus-4-6": 2, "anthropic/claude-opus-4-7": 2,
"opencode/gpt-5-nano": 20, "opencode/gpt-5-nano": 20,
}, },
}, },
+10 -10
View File
@@ -225,7 +225,7 @@ When GitHub Copilot is the best available provider, install-time defaults are ag
| Agent | Model | | Agent | Model |
| ------------- | ---------------------------------- | | ------------- | ---------------------------------- |
| **Sisyphus** | `github-copilot/claude-opus-4.6` | | **Sisyphus** | `github-copilot/claude-opus-4.7` |
| **Oracle** | `github-copilot/gpt-5.4` | | **Oracle** | `github-copilot/gpt-5.4` |
| **Explore** | `github-copilot/grok-code-fast-1` | | **Explore** | `github-copilot/grok-code-fast-1` |
| **Atlas** | `github-copilot/claude-sonnet-4.6` | | **Atlas** | `github-copilot/claude-sonnet-4.6` |
@@ -247,13 +247,13 @@ If Z.ai is your main provider, the most important fallbacks are:
#### OpenCode Zen #### OpenCode Zen
OpenCode Zen provides access to `opencode/` prefixed models including `opencode/claude-opus-4-6`, `opencode/gpt-5.4`, `opencode/gpt-5.3-codex`, `opencode/gpt-5-nano`, `opencode/glm-5`, `opencode/big-pickle`, `opencode/minimax-m2.7`, and `opencode/minimax-m2.7-highspeed`. OpenCode Zen provides access to `opencode/` prefixed models including `opencode/claude-opus-4-7`, `opencode/gpt-5.4`, `opencode/gpt-5.3-codex`, `opencode/gpt-5-nano`, `opencode/glm-5`, `opencode/big-pickle`, `opencode/minimax-m2.7`, and `opencode/minimax-m2.7-highspeed`.
When OpenCode Zen is the best available provider, these are the most relevant source-backed examples: When OpenCode Zen is the best available provider, these are the most relevant source-backed examples:
| Agent | Model | | Agent | Model |
| ------------- | ---------------------------------------------------- | | ------------- | ---------------------------------------------------- |
| **Sisyphus** | `opencode/claude-opus-4-6` | | **Sisyphus** | `opencode/claude-opus-4-7` |
| **Oracle** | `opencode/gpt-5.4` | | **Oracle** | `opencode/gpt-5.4` |
| **Explore** | `opencode/minimax-m2.7` | | **Explore** | `opencode/minimax-m2.7` |
@@ -287,7 +287,7 @@ Not all models behave the same way. Understanding which models are "similar" hel
| Model | Provider(s) | Notes | | Model | Provider(s) | Notes |
| ------------------------ | ----------------------------------- | ----------------------------------------------------------------------- | | ------------------------ | ----------------------------------- | ----------------------------------------------------------------------- |
| **Claude Opus 4.6** | anthropic, github-copilot, opencode | Best overall. Default for Sisyphus. | | **Claude Opus 4.7** | anthropic, github-copilot, opencode | Best overall. Default for Sisyphus. |
| **Claude Sonnet 4.6** | anthropic, github-copilot, opencode | Faster, cheaper. Good balance. | | **Claude Sonnet 4.6** | anthropic, github-copilot, opencode | Faster, cheaper. Good balance. |
| **Claude Haiku 4.5** | anthropic, opencode | Fast and cheap. Good for quick tasks. | | **Claude Haiku 4.5** | anthropic, opencode | Fast and cheap. Good for quick tasks. |
| **Kimi K2.5** | kimi-for-coding, opencode-go, opencode, moonshotai, moonshotai-cn, firmware, ollama-cloud, aihubmix | Behaves very similarly to Claude. Great all-rounder that appears in several orchestration fallback chains. | | **Kimi K2.5** | kimi-for-coding, opencode-go, opencode, moonshotai, moonshotai-cn, firmware, ollama-cloud, aihubmix | Behaves very similarly to Claude. Great all-rounder that appears in several orchestration fallback chains. |
@@ -330,8 +330,8 @@ Based on your subscriptions, here's how the agents were configured:
| Agent | Role | Default Chain | What It Does | | Agent | Role | Default Chain | What It Does |
| ------------ | ---------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------- | | ------------ | ---------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------- |
| **Sisyphus** | Main ultraworker | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → opencode-go/kimi-k2.5 → kimi-for-coding/k2p5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5 → openai\|github-copilot\|opencode/gpt-5.4 (medium) → zai-coding-plan\|opencode/glm-5 → opencode/big-pickle | Primary coding agent. Exact runtime chain from `src/shared/model-requirements.ts`. | | **Sisyphus** | Main ultraworker | anthropic\|github-copilot\|opencode/claude-opus-4-7 (max) → opencode-go/kimi-k2.5 → kimi-for-coding/k2p5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5 → openai\|github-copilot\|opencode/gpt-5.4 (medium) → zai-coding-plan\|opencode/glm-5 → opencode/big-pickle | Primary coding agent. Exact runtime chain from `src/shared/model-requirements.ts`. |
| **Metis** | Plan review | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → kimi-for-coding/k2p5 | Reviews Prometheus plans for gaps. Exact runtime chain from `src/shared/model-requirements.ts`. | | **Metis** | Plan review | anthropic\|github-copilot\|opencode/claude-opus-4-7 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → kimi-for-coding/k2p5 | Reviews Prometheus plans for gaps. Exact runtime chain from `src/shared/model-requirements.ts`. |
**Dual-Prompt Agents** (auto-switch between Claude and GPT prompts): **Dual-Prompt Agents** (auto-switch between Claude and GPT prompts):
@@ -341,7 +341,7 @@ Priority: **Claude > GPT > Claude-like models**
| Agent | Role | Default Chain | GPT Prompt? | | Agent | Role | Default Chain | GPT Prompt? |
| -------------- | ----------------- | ---------------------------------------------------------- | ---------------------------------------------------------------- | | -------------- | ----------------- | ---------------------------------------------------------- | ---------------------------------------------------------------- |
| **Prometheus** | Strategic planner | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → google\|github-copilot\|opencode/gemini-3.1-pro | Yes — XML-tagged, principle-driven (~300 lines vs ~1,100 Claude) | | **Prometheus** | Strategic planner | anthropic\|github-copilot\|opencode/claude-opus-4-7 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → google\|github-copilot\|opencode/gemini-3.1-pro | Yes — XML-tagged, principle-driven (~300 lines vs ~1,100 Claude) |
| **Atlas** | Todo orchestrator | anthropic\|github-copilot\|opencode/claude-sonnet-4-6 → opencode-go/kimi-k2.5 → openai\|github-copilot\|opencode/gpt-5.4 (medium) → opencode-go/minimax-m2.7 | Yes - GPT-optimized todo management | | **Atlas** | Todo orchestrator | anthropic\|github-copilot\|opencode/claude-sonnet-4-6 → opencode-go/kimi-k2.5 → openai\|github-copilot\|opencode/gpt-5.4 (medium) → opencode-go/minimax-m2.7 | Yes - GPT-optimized todo management |
**GPT-Native Agents** (built for GPT, don't override to Claude): **GPT-Native Agents** (built for GPT, don't override to Claude):
@@ -349,8 +349,8 @@ Priority: **Claude > GPT > Claude-like models**
| Agent | Role | Default Chain | Notes | | Agent | Role | Default Chain | Notes |
| -------------- | ---------------------- | -------------------------------------- | ------------------------------------------------------ | | -------------- | ---------------------- | -------------------------------------- | ------------------------------------------------------ |
| **Hephaestus** | Deep autonomous worker | GPT-5.4 (medium) only | "Codex on steroids." No fallback. Requires GPT access. | | **Hephaestus** | Deep autonomous worker | GPT-5.4 (medium) only | "Codex on steroids." No fallback. Requires GPT access. |
| **Oracle** | Architecture/debugging | openai\|github-copilot\|opencode/gpt-5.4 (high) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → opencode-go/glm-5 | High-IQ strategic backup. GPT preferred. | | **Oracle** | Architecture/debugging | openai\|github-copilot\|opencode/gpt-5.4 (high) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode/claude-opus-4-7 (max) → opencode-go/glm-5 | High-IQ strategic backup. GPT preferred. |
| **Momus** | High-accuracy reviewer | openai\|github-copilot\|opencode/gpt-5.4 (xhigh) → anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → opencode-go/glm-5 | Verification agent. GPT preferred. | | **Momus** | High-accuracy reviewer | openai\|github-copilot\|opencode/gpt-5.4 (xhigh) → anthropic\|github-copilot\|opencode/claude-opus-4-7 (max) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → opencode-go/glm-5 | Verification agent. GPT preferred. |
**Utility Agents** (speed over intelligence): **Utility Agents** (speed over intelligence):
@@ -463,7 +463,7 @@ gh api --silent --method PUT /user/starred/code-yeongyu/oh-my-openagent >/dev/nu
Tell the user of following: Tell the user of following:
1. **Sisyphus agent strongly recommends Opus 4.6 model. Using other models may result in significantly degraded experience.** 1. **Sisyphus agent strongly recommends Opus 4.7 model. Using other models may result in significantly degraded experience.**
2. **Feeling lazy?** Just include `ultrawork` (or `ulw`) in your prompt. That's it. The agent figures out the rest. 2. **Feeling lazy?** Just include `ultrawork` (or `ulw`) in your prompt. That's it. The agent figures out the rest.
+14 -14
View File
@@ -35,9 +35,9 @@ The orchestration system uses a three-layer architecture that solves context ove
flowchart TB flowchart TB
subgraph Planning["Planning Layer (Human + Prometheus)"] subgraph Planning["Planning Layer (Human + Prometheus)"]
User[(" User")] User[(" User")]
Prometheus[" Prometheus<br/>(Planner)<br/>claude-opus-4-6 / gpt-5.4 / glm-5"] Prometheus[" Prometheus<br/>(Planner)<br/>claude-opus-4-7 / gpt-5.4 / glm-5"]
Metis[" Metis<br/>(Consultant)<br/>claude-opus-4-6 / gpt-5.4 / glm-5"] Metis[" Metis<br/>(Consultant)<br/>claude-opus-4-7 / gpt-5.4 / glm-5"]
Momus[" Momus<br/>(Reviewer)<br/>gpt-5.4 / claude-opus-4-6 / gemini-3.1-pro / glm-5"] Momus[" Momus<br/>(Reviewer)<br/>gpt-5.4 / claude-opus-4-7 / gemini-3.1-pro / glm-5"]
end end
subgraph Execution["Execution Layer (Orchestrator)"] subgraph Execution["Execution Layer (Orchestrator)"]
@@ -46,10 +46,10 @@ flowchart TB
subgraph Workers["Worker Layer (Specialized Agents)"] subgraph Workers["Worker Layer (Specialized Agents)"]
Junior[" Sisyphus-Junior<br/>(Task Executor)<br/>claude-sonnet-4-6 / kimi-k2.5 / gpt-5.4 / minimax-m2.7"] Junior[" Sisyphus-Junior<br/>(Task Executor)<br/>claude-sonnet-4-6 / kimi-k2.5 / gpt-5.4 / minimax-m2.7"]
Oracle[" Oracle<br/>(Architecture)<br/>gpt-5.4 / gemini-3.1-pro / claude-opus-4-6 / glm-5"] Oracle[" Oracle<br/>(Architecture)<br/>gpt-5.4 / gemini-3.1-pro / claude-opus-4-7 / glm-5"]
Explore[" Explore<br/>(Codebase Grep)<br/>grok-code-fast-1 / minimax-m2.7-highspeed / claude-haiku-4-5"] Explore[" Explore<br/>(Codebase Grep)<br/>gpt-5.4-mini-fast / minimax-m2.7-highspeed / claude-haiku-4-5"]
Librarian[" Librarian<br/>(Docs/OSS)<br/>minimax-m2.7 / minimax-m2.7-highspeed / claude-haiku-4-5"] Librarian[" Librarian<br/>(Docs/OSS)<br/>gpt-5.4-mini-fast / minimax-m2.7-highspeed / claude-haiku-4-5"]
Frontend[" visual-engineering<br/>(category + frontend-ui-ux)<br/>gemini-3.1-pro / glm-5 / claude-opus-4-6"] Frontend[" visual-engineering<br/>(category + frontend-ui-ux)<br/>gemini-3.1-pro / glm-5 / claude-opus-4-7"]
end end
User -->|"Describe work"| Prometheus User -->|"Describe work"| Prometheus
@@ -282,7 +282,7 @@ This "boulder pushing" mechanism is why the system is named after Sisyphus.
```typescript ```typescript
// OLD: Model name creates distributional bias // OLD: Model name creates distributional bias
task({ agent: "gpt-5.4", prompt: "..." }); // Model knows its limitations task({ agent: "gpt-5.4", prompt: "..." }); // Model knows its limitations
task({ agent: "claude-opus-4-6", prompt: "..." }); // Different self-perception task({ agent: "claude-opus-4-7", prompt: "..." }); // Different self-perception
``` ```
**The Solution: Semantic Categories:** **The Solution: Semantic Categories:**
@@ -298,13 +298,13 @@ task({ category: "quick", prompt: "..." }); // "Just get it done fast"
| Category | Default config | Runtime fallback order | When to Use | | Category | Default config | Runtime fallback order | When to Use |
| -------------------- | ------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------- | | -------------------- | ------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| `visual-engineering` | `google/gemini-3.1-pro high` | `gemini-3.1-pro``glm-5``claude-opus-4-6``glm-5``k2p5` | Frontend, UI/UX, design, styling, animation | | `visual-engineering` | `google/gemini-3.1-pro high` | `gemini-3.1-pro``glm-5``claude-opus-4-7``glm-5``k2p5` | Frontend, UI/UX, design, styling, animation |
| `ultrabrain` | `openai/gpt-5.4 xhigh` | `gpt-5.4``gemini-3.1-pro``claude-opus-4-6``glm-5` | Deep logical reasoning, complex architecture decisions | | `ultrabrain` | `openai/gpt-5.4 xhigh` | `gpt-5.4``gemini-3.1-pro``claude-opus-4-7``glm-5` | Deep logical reasoning, complex architecture decisions |
| `deep` | `openai/gpt-5.4 medium` | `gpt-5.4``claude-opus-4-6``gemini-3.1-pro` | Goal-oriented autonomous problem-solving, thorough research | | `deep` | `openai/gpt-5.4 medium` | `gpt-5.4``claude-opus-4-7``gemini-3.1-pro` | Goal-oriented autonomous problem-solving, thorough research |
| `artistry` | `google/gemini-3.1-pro high` | `gemini-3.1-pro``claude-opus-4-6``gpt-5.4` | Highly creative or artistic tasks, novel ideas | | `artistry` | `google/gemini-3.1-pro high` | `gemini-3.1-pro``claude-opus-4-7``gpt-5.4` | Highly creative or artistic tasks, novel ideas |
| `quick` | `openai/gpt-5.4-mini` | `gpt-5.4-mini``claude-haiku-4-5``gemini-3-flash``minimax-m2.7``gpt-5-nano` | Trivial tasks, single file changes, typo fixes | | `quick` | `openai/gpt-5.4-mini` | `gpt-5.4-mini``claude-haiku-4-5``gemini-3-flash``minimax-m2.7``gpt-5-nano` | Trivial tasks, single file changes, typo fixes |
| `unspecified-low` | `anthropic/claude-sonnet-4-6` | `claude-sonnet-4-6``gpt-5.3-codex``kimi-k2.5``gemini-3-flash``minimax-m2.7` | Tasks that don't fit other categories, low effort | | `unspecified-low` | `anthropic/claude-sonnet-4-6` | `claude-sonnet-4-6``gpt-5.3-codex``kimi-k2.5``gemini-3-flash``minimax-m2.7` | Tasks that don't fit other categories, low effort |
| `unspecified-high` | `anthropic/claude-opus-4-6 max` | `claude-opus-4-6``gpt-5.4``glm-5``k2p5``kimi-k2.5` | Tasks that don't fit other categories, high effort | | `unspecified-high` | `anthropic/claude-opus-4-7 max` | `claude-opus-4-7``gpt-5.4``glm-5``k2p5``kimi-k2.5` | Tasks that don't fit other categories, high effort |
| `writing` | `kimi-for-coding/k2p5` | `gemini-3-flash``kimi-k2.5``claude-sonnet-4-6``minimax-m2.7` | Documentation, prose, technical writing | | `writing` | `kimi-for-coding/k2p5` | `gemini-3-flash``kimi-k2.5``claude-sonnet-4-6``minimax-m2.7` | Documentation, prose, technical writing |
### Skills: Domain-Specific Instructions ### Skills: Domain-Specific Instructions
@@ -423,7 +423,7 @@ Atlas is automatically activated when you run `/start-work`. You don't need to m
| Aspect | Hephaestus | Sisyphus + `ulw` / `ultrawork` | | Aspect | Hephaestus | Sisyphus + `ulw` / `ultrawork` |
| --------------- | ------------------------------------------ | ---------------------------------------------------- | | --------------- | ------------------------------------------ | ---------------------------------------------------- |
| **Model** | `gpt-5.4` (`medium`) | `claude-opus-4-6` / `kimi-k2.5` / `gpt-5.4` / `glm-5` depending on setup | | **Model** | `gpt-5.4` (`medium`) | `claude-opus-4-7` / `kimi-k2.5` / `gpt-5.4` / `glm-5` depending on setup |
| **Approach** | Autonomous deep worker | Keyword-activated ultrawork mode | | **Approach** | Autonomous deep worker | Keyword-activated ultrawork mode |
| **Best For** | Complex architectural work, deep reasoning | General complex tasks, "just do it" scenarios | | **Best For** | Complex architectural work, deep reasoning | General complex tasks, "just do it" scenarios |
| **Planning** | Self-plans during execution | Uses Prometheus plans if available | | **Planning** | Self-plans during execution | Uses Prometheus plans if available |
+6 -6
View File
@@ -82,11 +82,11 @@ Sisyphus is your main orchestrator. He plans, delegates to specialists, and driv
**Recommended models:** **Recommended models:**
- **Claude Opus 4.6** — Best overall experience. Sisyphus was built with Claude-optimized prompts. - **Claude Opus 4.7** — Best overall experience. Sisyphus was built with Claude-optimized prompts.
- **Kimi K2.5** — Great Claude-like alternative. Many users run this combo exclusively. - **Kimi K2.5** — Great Claude-like alternative. Many users run this combo exclusively.
- **GLM 5** — Solid option, especially via Z.ai. - **GLM 5** — Solid option, especially via Z.ai.
Sisyphus works best on Claude Opus 4.6, Kimi K2.5, and GLM 5. GPT-5.4 now has a dedicated prompt path, but older GPT models are still a poor fit and should route to Hephaestus instead. Sisyphus works best on Claude Opus 4.7, Kimi K2.5, and GLM 5. GPT-5.4 now has a dedicated prompt path, but older GPT models are still a poor fit and should route to Hephaestus instead.
### Hephaestus: The Legitimate Craftsman ### Hephaestus: The Legitimate Craftsman
@@ -173,7 +173,7 @@ You can override specific agents or categories in your config:
// Main orchestrator: Claude Opus or Kimi K2.5 work best // Main orchestrator: Claude Opus or Kimi K2.5 work best
"sisyphus": { "sisyphus": {
"model": "kimi-for-coding/k2p5", "model": "kimi-for-coding/k2p5",
"ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" },
}, },
// Research agents: cheaper models are fine // Research agents: cheaper models are fine
@@ -207,10 +207,10 @@ You can override specific agents or categories in your config:
"unspecified-low": { "model": "openai/gpt-5.4-mini" }, "unspecified-low": { "model": "openai/gpt-5.4-mini" },
// High-effort fallback: best available // High-effort fallback: best available
"unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, "unspecified-high": { "model": "anthropic/claude-opus-4-7", "variant": "max" },
// Prose and documentation // Prose and documentation
"writing": { "model": "anthropic/claude-opus-4-6", "variant": "high" }, "writing": { "model": "anthropic/claude-opus-4-7", "variant": "high" },
}, },
} }
``` ```
@@ -219,7 +219,7 @@ You can override specific agents or categories in your config:
**Claude-like models** (instruction-following, structured output): **Claude-like models** (instruction-following, structured output):
- Claude Opus 4.6, Claude Haiku 4.5 - Claude Opus 4.7, Claude Haiku 4.5
- Kimi K2.5 — behaves very similarly to Claude - Kimi K2.5 — behaves very similarly to Claude
- GLM 5 — Claude-like behavior, good for broad tasks - GLM 5 — Claude-like behavior, good for broad tasks
+22 -22
View File
@@ -78,7 +78,7 @@ Here's a practical starting configuration:
// Main orchestrator: Claude Opus or Kimi K2.5 work best // Main orchestrator: Claude Opus or Kimi K2.5 work best
"sisyphus": { "sisyphus": {
"model": "kimi-for-coding/k2p5", "model": "kimi-for-coding/k2p5",
"ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" },
}, },
// Research agents: cheap fast models are fine // Research agents: cheap fast models are fine
@@ -102,7 +102,7 @@ Here's a practical starting configuration:
"unspecified-low": { "model": "anthropic/claude-sonnet-4-6" }, "unspecified-low": { "model": "anthropic/claude-sonnet-4-6" },
// unspecified-high - complex work // unspecified-high - complex work
"unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, "unspecified-high": { "model": "anthropic/claude-opus-4-7", "variant": "max" },
// writing - docs/prose // writing - docs/prose
"writing": { "model": "google/gemini-3-flash" }, "writing": { "model": "google/gemini-3-flash" },
@@ -130,7 +130,7 @@ Here's a practical starting configuration:
"zai-coding-plan": 10, "zai-coding-plan": 10,
}, },
"modelConcurrency": { "modelConcurrency": {
"anthropic/claude-opus-4-6": 2, "anthropic/claude-opus-4-7": 2,
"opencode/gpt-5-nano": 20, "opencode/gpt-5-nano": 20,
}, },
}, },
@@ -229,7 +229,7 @@ Control what tools an agent can use:
{ {
"agents": { "agents": {
"sisyphus": { "sisyphus": {
"model": "anthropic/claude-opus-4-6", "model": "anthropic/claude-opus-4-7",
"fallback_models": [ "fallback_models": [
// Simple string fallback // Simple string fallback
"openai/gpt-5.4", "openai/gpt-5.4",
@@ -293,7 +293,7 @@ Domain-specific model delegation used by the `task()` tool. When Sisyphus delega
| `artistry` | `google/gemini-3.1-pro` (high) | Creative/unconventional approaches | | `artistry` | `google/gemini-3.1-pro` (high) | Creative/unconventional approaches |
| `quick` | `openai/gpt-5.4-mini` | Trivial tasks, typo fixes, single-file changes | | `quick` | `openai/gpt-5.4-mini` | Trivial tasks, typo fixes, single-file changes |
| `unspecified-low` | `anthropic/claude-sonnet-4-6` | General tasks, low effort | | `unspecified-low` | `anthropic/claude-sonnet-4-6` | General tasks, low effort |
| `unspecified-high` | `anthropic/claude-opus-4-6` (max) | General tasks, high effort | | `unspecified-high` | `anthropic/claude-opus-4-7` (max) | General tasks, high effort |
| `writing` | `google/gemini-3-flash` | Documentation, prose, technical writing | | `writing` | `google/gemini-3-flash` | Documentation, prose, technical writing |
> **Note**: Built-in defaults only apply if the category is present in your config. Otherwise the system default model is used. > **Note**: Built-in defaults only apply if the category is present in your config. Otherwise the system default model is used.
@@ -355,28 +355,28 @@ Capability data comes from provider runtime metadata first. OmO also ships bundl
| Agent | Default Model | Provider Priority | | Agent | Default Model | Provider Priority |
| --------------------- | ------------------- | ---------------------------------------------------------------------------- | | --------------------- | ------------------- | ---------------------------------------------------------------------------- |
| **Sisyphus** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``opencode-go/kimi-k2.5``kimi-for-coding/k2p5``opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5``openai\|github-copilot\|opencode/gpt-5.4 (medium)``zai-coding-plan\|opencode/glm-5``opencode/big-pickle` | | **Sisyphus** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)``opencode-go/kimi-k2.5``kimi-for-coding/k2p5``opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5``openai\|github-copilot\|opencode/gpt-5.4 (medium)``zai-coding-plan\|opencode/glm-5``opencode/big-pickle` |
| **Hephaestus** | `gpt-5.4` | `gpt-5.4 (medium)` | | **Hephaestus** | `gpt-5.4` | `gpt-5.4 (medium)` |
| **oracle** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (high)``google\|github-copilot\|opencode/gemini-3.1-pro (high)``anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``opencode-go/glm-5` | | **oracle** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (high)``google\|github-copilot\|opencode/gemini-3.1-pro (high)``anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)``opencode-go/glm-5` |
| **librarian** | `minimax-m2.7` | `opencode-go/minimax-m2.7``opencode/minimax-m2.7-highspeed``anthropic\|opencode/claude-haiku-4-5``opencode/gpt-5-nano` | | **librarian** | `gpt-5.4-mini-fast` | `openai/gpt-5.4-mini-fast` `opencode-go\|vercel/minimax-m2.7-highspeed``opencode-go\|vercel/minimax-m2.7``anthropic\|opencode\|vercel/claude-haiku-4-5``openai\|opencode\|vercel/gpt-5.4-nano` |
| **explore** | `grok-code-fast-1` | `github-copilot\|xai/grok-code-fast-1``opencode-go/minimax-m2.7-highspeed``opencode/minimax-m2.7``anthropic\|opencode/claude-haiku-4-5``opencode/gpt-5-nano` | | **explore** | `gpt-5.4-mini-fast` | `openai/gpt-5.4-mini-fast``opencode-go\|vercel/minimax-m2.7-highspeed``opencode-go\|vercel/minimax-m2.7``anthropic\|opencode\|vercel/claude-haiku-4-5``openai\|opencode\|vercel/gpt-5.4-nano` |
| **multimodal-looker** | `gpt-5.4` | `openai\|opencode/gpt-5.4 (medium)``opencode-go/kimi-k2.5``zai-coding-plan/glm-4.6v``openai\|github-copilot\|opencode/gpt-5-nano` | | **multimodal-looker** | `gpt-5.4` | `openai\|opencode/gpt-5.4 (medium)``opencode-go/kimi-k2.5``zai-coding-plan/glm-4.6v``openai\|github-copilot\|opencode/gpt-5-nano` |
| **Prometheus** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``openai\|github-copilot\|opencode/gpt-5.4 (high)``opencode-go/glm-5``google\|github-copilot\|opencode/gemini-3.1-pro` | | **Prometheus** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)``openai\|github-copilot\|opencode/gpt-5.4 (high)``opencode-go/glm-5``google\|github-copilot\|opencode/gemini-3.1-pro` |
| **Metis** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``openai\|github-copilot\|opencode/gpt-5.4 (high)``opencode-go/glm-5``kimi-for-coding/k2p5` | | **Metis** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)``openai\|github-copilot\|opencode/gpt-5.4 (high)``opencode-go/glm-5``kimi-for-coding/k2p5` |
| **Momus** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (xhigh)``anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``google\|github-copilot\|opencode/gemini-3.1-pro (high)``opencode-go/glm-5` | | **Momus** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (xhigh)``anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)``google\|github-copilot\|opencode/gemini-3.1-pro (high)``opencode-go/glm-5` |
| **Atlas** | `claude-sonnet-4-6` | `anthropic\|github-copilot\|opencode/claude-sonnet-4-6``opencode-go/kimi-k2.5``openai\|github-copilot\|opencode/gpt-5.4 (medium)``opencode-go/minimax-m2.7` | | **Atlas** | `claude-sonnet-4-6` | `anthropic\|github-copilot\|opencode/claude-sonnet-4-6``opencode-go/kimi-k2.5``openai\|github-copilot\|opencode/gpt-5.4 (medium)``opencode-go/minimax-m2.7` |
#### Category Provider Chains #### Category Provider Chains
| Category | Default Model | Provider Priority | | Category | Default Model | Provider Priority |
| ---------------------- | ------------------- | -------------------------------------------------------------- | | ---------------------- | ------------------- | -------------------------------------------------------------- |
| **visual-engineering** | `gemini-3.1-pro` | `google\|github-copilot\|opencode/gemini-3.1-pro (high)``zai-coding-plan\|opencode/glm-5``anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``opencode-go/glm-5``kimi-for-coding/k2p5` | | **visual-engineering** | `gemini-3.1-pro` | `google\|github-copilot\|opencode/gemini-3.1-pro (high)``zai-coding-plan\|opencode/glm-5``anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)``opencode-go/glm-5``kimi-for-coding/k2p5` |
| **ultrabrain** | `gpt-5.4` | `openai\|opencode/gpt-5.4 (xhigh)``google\|github-copilot\|opencode/gemini-3.1-pro (high)``anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``opencode-go/glm-5` | | **ultrabrain** | `gpt-5.4` | `openai\|opencode/gpt-5.4 (xhigh)``google\|github-copilot\|opencode/gemini-3.1-pro (high)``anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)``opencode-go/glm-5` |
| **deep** | `gpt-5.4` | `openai\|github-copilot\|venice\|opencode/gpt-5.4 (medium)``anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``google\|github-copilot\|opencode/gemini-3.1-pro (high)` | | **deep** | `gpt-5.4` | `openai\|github-copilot\|venice\|opencode/gpt-5.4 (medium)``anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)``google\|github-copilot\|opencode/gemini-3.1-pro (high)` |
| **artistry** | `gemini-3.1-pro` | `google\|github-copilot\|opencode/gemini-3.1-pro (high)``anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``openai\|github-copilot\|opencode/gpt-5.4` | | **artistry** | `gemini-3.1-pro` | `google\|github-copilot\|opencode/gemini-3.1-pro (high)``anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)``openai\|github-copilot\|opencode/gpt-5.4` |
| **quick** | `gpt-5.4-mini` | `openai\|github-copilot\|opencode/gpt-5.4-mini``anthropic\|github-copilot\|opencode/claude-haiku-4-5``google\|github-copilot\|opencode/gemini-3-flash``opencode-go/minimax-m2.7``opencode/gpt-5-nano` | | **quick** | `gpt-5.4-mini` | `openai\|github-copilot\|opencode/gpt-5.4-mini``anthropic\|github-copilot\|opencode/claude-haiku-4-5``google\|github-copilot\|opencode/gemini-3-flash``opencode-go/minimax-m2.7``opencode/gpt-5-nano` |
| **unspecified-low** | `claude-sonnet-4-6` | `anthropic\|github-copilot\|opencode/claude-sonnet-4-6``openai\|opencode/gpt-5.3-codex (medium)``opencode-go/kimi-k2.5``google\|github-copilot\|opencode/gemini-3-flash``opencode-go/minimax-m2.7` | | **unspecified-low** | `claude-sonnet-4-6` | `anthropic\|github-copilot\|opencode/claude-sonnet-4-6``openai\|opencode/gpt-5.3-codex (medium)``opencode-go/kimi-k2.5``google\|github-copilot\|opencode/gemini-3-flash``opencode-go/minimax-m2.7` |
| **unspecified-high** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``openai\|github-copilot\|opencode/gpt-5.4 (high)``zai-coding-plan\|opencode/glm-5``kimi-for-coding/k2p5``opencode-go/glm-5``opencode/kimi-k2.5``opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` | | **unspecified-high** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)``openai\|github-copilot\|opencode/gpt-5.4 (high)``zai-coding-plan\|opencode/glm-5``kimi-for-coding/k2p5``opencode-go/glm-5``opencode/kimi-k2.5``opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` |
| **writing** | `gemini-3-flash` | `google\|github-copilot\|opencode/gemini-3-flash``opencode-go/kimi-k2.5``anthropic\|github-copilot\|opencode/claude-sonnet-4-6``opencode-go/minimax-m2.7` | | **writing** | `gemini-3-flash` | `google\|github-copilot\|opencode/gemini-3-flash``opencode-go/kimi-k2.5``anthropic\|github-copilot\|opencode/claude-sonnet-4-6``opencode-go/minimax-m2.7` |
Run `bunx oh-my-opencode doctor --verbose` to see effective model resolution for your config. Run `bunx oh-my-opencode doctor --verbose` to see effective model resolution for your config.
@@ -395,7 +395,7 @@ Control parallel agent execution and concurrency limits.
"defaultConcurrency": 5, "defaultConcurrency": 5,
"staleTimeoutMs": 180000, "staleTimeoutMs": 180000,
"providerConcurrency": { "anthropic": 3, "openai": 5, "google": 10 }, "providerConcurrency": { "anthropic": 3, "openai": 5, "google": 10 },
"modelConcurrency": { "anthropic/claude-opus-4-6": 2 } "modelConcurrency": { "anthropic/claude-opus-4-7": 2 }
} }
} }
``` ```
@@ -678,7 +678,7 @@ Define `fallback_models` per agent or category:
{ {
"agents": { "agents": {
"sisyphus": { "sisyphus": {
"model": "anthropic/claude-opus-4-6", "model": "anthropic/claude-opus-4-7",
"fallback_models": [ "fallback_models": [
"openai/gpt-5.4", "openai/gpt-5.4",
{ {
@@ -697,7 +697,7 @@ Define `fallback_models` per agent or category:
{ {
"agents": { "agents": {
"sisyphus": { "sisyphus": {
"model": "anthropic/claude-opus-4-6", "model": "anthropic/claude-opus-4-7",
"fallback_models": [ "fallback_models": [
"openai/gpt-5.4", "openai/gpt-5.4",
{ {
@@ -798,7 +798,7 @@ Mix string entries and object entries when only some fallback models need specia
{ {
"agents": { "agents": {
"sisyphus": { "sisyphus": {
"model": "anthropic/claude-opus-4-6", "model": "anthropic/claude-opus-4-7",
"fallback_models": [ "fallback_models": [
"openai/gpt-5.4", "openai/gpt-5.4",
{ {
@@ -832,7 +832,7 @@ Mix string entries and object entries when only some fallback models need specia
"maxTokens": 12000 "maxTokens": 12000
}, },
{ {
"model": "anthropic/claude-opus-4-6", "model": "anthropic/claude-opus-4-7",
"variant": "max", "variant": "max",
"temperature": 0.2 "temperature": 0.2
}, },
+10 -10
View File
@@ -10,19 +10,19 @@ Core-agent tab cycling is deterministic via injected runtime order field. The fi
| Agent | Model | Purpose | | Agent | Model | Purpose |
| --------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | --------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Sisyphus** | `claude-opus-4-6` | The default orchestrator. Plans, delegates, and executes complex tasks using specialized subagents with aggressive parallel execution. Todo-driven workflow with extended thinking (32k budget). Fallback: `opencode-go/kimi-k2.5``kimi-for-coding/k2p5``opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5``openai\|github-copilot\|opencode/gpt-5.4 (medium)``zai-coding-plan\|opencode/glm-5``opencode/big-pickle`. | | **Sisyphus** | `claude-opus-4-7` | The default orchestrator. Plans, delegates, and executes complex tasks using specialized subagents with aggressive parallel execution. Todo-driven workflow with extended thinking (32k budget). Fallback: `opencode-go/kimi-k2.5``kimi-for-coding/k2p5``opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5``openai\|github-copilot\|opencode/gpt-5.4 (medium)``zai-coding-plan\|opencode/glm-5``opencode/big-pickle`. |
| **Hephaestus** | `gpt-5.4` | The Legitimate Craftsman. Autonomous deep worker inspired by AmpCode's deep mode. Goal-oriented execution with thorough research before action. Explores codebase patterns, completes tasks end-to-end without premature stopping. Named after the Greek god of forge and craftsmanship. Requires a GPT-capable provider. | | **Hephaestus** | `gpt-5.4` | The Legitimate Craftsman. Autonomous deep worker inspired by AmpCode's deep mode. Goal-oriented execution with thorough research before action. Explores codebase patterns, completes tasks end-to-end without premature stopping. Named after the Greek god of forge and craftsmanship. Requires a GPT-capable provider. |
| **Oracle** | `gpt-5.4` | Architecture decisions, code review, debugging. Read-only consultation with stellar logical reasoning and deep analysis. Inspired by AmpCode. Fallback: `google\|github-copilot\|opencode/gemini-3.1-pro (high)``anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``opencode-go/glm-5`. | | **Oracle** | `gpt-5.4` | Architecture decisions, code review, debugging. Read-only consultation with stellar logical reasoning and deep analysis. Inspired by AmpCode. Fallback: `google\|github-copilot\|opencode/gemini-3.1-pro (high)``anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)``opencode-go/glm-5`. |
| **Librarian** | `minimax-m2.7` | Multi-repo analysis, documentation lookup, OSS implementation examples. Deep codebase understanding with evidence-based answers. Fallback: `opencode/minimax-m2.7-highspeed``anthropic\|opencode/claude-haiku-4-5``opencode/gpt-5-nano`. | | **Librarian** | `gpt-5.4-mini-fast` | Multi-repo analysis, documentation lookup, OSS implementation examples. Deep codebase understanding with evidence-based answers. Fallback: `opencode-go/minimax-m2.7-highspeed` `opencode-go/minimax-m2.7` `anthropic\|opencode/claude-haiku-4-5``openai\|opencode/gpt-5.4-nano`. |
| **Explore** | `grok-code-fast-1` | Fast codebase exploration and contextual grep. Fallback: `opencode-go/minimax-m2.7-highspeed``opencode/minimax-m2.7``anthropic\|opencode/claude-haiku-4-5``opencode/gpt-5-nano`. | | **Explore** | `gpt-5.4-mini-fast` | Fast codebase exploration and contextual grep. Fallback: `opencode-go/minimax-m2.7-highspeed``opencode-go/minimax-m2.7``anthropic\|opencode/claude-haiku-4-5``openai\|opencode/gpt-5.4-nano`. |
| **Multimodal-Looker** | `gpt-5.4` | Visual content specialist. Analyzes PDFs, images, diagrams to extract information. Fallback: `opencode-go/kimi-k2.5``zai-coding-plan/glm-4.6v``openai\|github-copilot\|opencode/gpt-5-nano`. | | **Multimodal-Looker** | `gpt-5.4` | Visual content specialist. Analyzes PDFs, images, diagrams to extract information. Fallback: `opencode-go/kimi-k2.5``zai-coding-plan/glm-4.6v``openai\|github-copilot\|opencode/gpt-5-nano`. |
### Planning Agents ### Planning Agents
| Agent | Model | Purpose | | Agent | Model | Purpose |
| -------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | -------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Prometheus** | `claude-opus-4-6` | Strategic planner with interview mode. Creates detailed work plans through iterative questioning. Fallback: `openai\|github-copilot\|opencode/gpt-5.4 (high)``opencode-go/glm-5``google\|github-copilot\|opencode/gemini-3.1-pro`. | | **Prometheus** | `claude-opus-4-7` | Strategic planner with interview mode. Creates detailed work plans through iterative questioning. Fallback: `openai\|github-copilot\|opencode/gpt-5.4 (high)``opencode-go/glm-5``google\|github-copilot\|opencode/gemini-3.1-pro`. |
| **Metis** | `claude-opus-4-6` | Plan consultant — pre-planning analysis. Identifies hidden intentions, ambiguities, and AI failure points. Fallback: `openai\|github-copilot\|opencode/gpt-5.4 (high)``opencode-go/glm-5``kimi-for-coding/k2p5`. | | **Metis** | `claude-opus-4-7` | Plan consultant — pre-planning analysis. Identifies hidden intentions, ambiguities, and AI failure points. Fallback: `openai\|github-copilot\|opencode/gpt-5.4 (high)``opencode-go/glm-5``kimi-for-coding/k2p5`. |
| **Momus** | `gpt-5.4` | Plan reviewer — validates plans against clarity, verifiability, and completeness standards. Fallback: `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``google\|github-copilot\|opencode/gemini-3.1-pro (high)``opencode-go/glm-5`. | | **Momus** | `gpt-5.4` | Plan reviewer — validates plans against clarity, verifiability, and completeness standards. Fallback: `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)``google\|github-copilot\|opencode/gemini-3.1-pro (high)``opencode-go/glm-5`. |
### Orchestration Agents ### Orchestration Agents
@@ -115,7 +115,7 @@ By combining these two concepts, you can generate optimal agents through `task`.
| `artistry` | `google/gemini-3.1-pro` (high) | Highly creative/artistic tasks, novel ideas | | `artistry` | `google/gemini-3.1-pro` (high) | Highly creative/artistic tasks, novel ideas |
| `quick` | `openai/gpt-5.4-mini` | Trivial tasks - single file changes, typo fixes, simple modifications | | `quick` | `openai/gpt-5.4-mini` | Trivial tasks - single file changes, typo fixes, simple modifications |
| `unspecified-low` | `anthropic/claude-sonnet-4-6` | Tasks that don't fit other categories, low effort required | | `unspecified-low` | `anthropic/claude-sonnet-4-6` | Tasks that don't fit other categories, low effort required |
| `unspecified-high` | `anthropic/claude-opus-4-6` (max) | Tasks that don't fit other categories, high effort required | | `unspecified-high` | `anthropic/claude-opus-4-7` (max) | Tasks that don't fit other categories, high effort required |
| `writing` | `google/gemini-3-flash` | Documentation, prose, technical writing | | `writing` | `google/gemini-3-flash` | Documentation, prose, technical writing |
### Usage ### Usage
@@ -138,7 +138,7 @@ You can define custom categories in your plugin config file. During the rename t
| Field | Type | Description | | Field | Type | Description |
| ------------------- | ------- | --------------------------------------------------------------------------- | | ------------------- | ------- | --------------------------------------------------------------------------- |
| `description` | string | Human-readable description of the category's purpose. Shown in task prompt. | | `description` | string | Human-readable description of the category's purpose. Shown in task prompt. |
| `model` | string | AI model ID to use (e.g., `anthropic/claude-opus-4-6`) | | `model` | string | AI model ID to use (e.g., `anthropic/claude-opus-4-7`) |
| `variant` | string | Model variant (e.g., `max`, `xhigh`) | | `variant` | string | Model variant (e.g., `max`, `xhigh`) |
| `temperature` | number | Creativity level (0.0 ~ 2.0). Lower is more deterministic. | | `temperature` | number | Creativity level (0.0 ~ 2.0). Lower is more deterministic. |
| `top_p` | number | Nucleus sampling parameter (0.0 ~ 1.0) | | `top_p` | number | Nucleus sampling parameter (0.0 ~ 1.0) |
@@ -170,7 +170,7 @@ You can define custom categories in your plugin config file. During the rename t
// 3. Configure thinking model and restrict tools // 3. Configure thinking model and restrict tools
"deep-reasoning": { "deep-reasoning": {
"model": "anthropic/claude-opus-4-6", "model": "anthropic/claude-opus-4-7",
"thinking": { "thinking": {
"type": "enabled", "type": "enabled",
"budgetTokens": 32000, "budgetTokens": 32000,
+22 -18
View File
@@ -1,12 +1,13 @@
{ {
"name": "oh-my-opencode", "name": "oh-my-opencode",
"version": "3.17.3", "version": "3.17.4",
"description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools", "description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"type": "module", "type": "module",
"bin": { "bin": {
"oh-my-opencode": "bin/oh-my-opencode.js" "oh-my-opencode": "bin/oh-my-opencode.js",
"oh-my-openagent": "bin/oh-my-opencode.js"
}, },
"files": [ "files": [
"dist", "dist",
@@ -21,7 +22,7 @@
"./schema.json": "./dist/oh-my-opencode.schema.json" "./schema.json": "./dist/oh-my-opencode.schema.json"
}, },
"scripts": { "scripts": {
"build": "bun build src/index.ts --outdir dist --target bun --format esm --external @ast-grep/napi && tsc --emitDeclarationOnly && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm --external @ast-grep/napi && bun run build:schema", "build": "bun build src/index.ts --outdir dist --target bun --format esm --external @ast-grep/napi --external zod && tsc --emitDeclarationOnly && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm --external @ast-grep/napi && bun run build:schema",
"build:all": "bun run build && bun run build:binaries", "build:all": "bun run build && bun run build:binaries",
"build:binaries": "bun run script/build-binaries.ts", "build:binaries": "bun run script/build-binaries.ts",
"build:schema": "bun run script/build-schema.ts", "build:schema": "bun run script/build-schema.ts",
@@ -69,32 +70,35 @@
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
"picomatch": "^4.0.2", "picomatch": "^4.0.2",
"posthog-node": "^5.29.2", "posthog-node": "^5.29.2",
"vscode-jsonrpc": "^8.2.0", "vscode-jsonrpc": "^8.2.0"
"zod": "^4.3.0"
}, },
"devDependencies": { "devDependencies": {
"@types/js-yaml": "^4.0.9", "@types/js-yaml": "^4.0.9",
"@types/picomatch": "^3.0.2", "@types/picomatch": "^3.0.2",
"bun-types": "1.3.11", "bun-types": "1.3.11",
"typescript": "^5.7.3" "typescript": "^5.7.3",
"zod": "^4.3.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"oh-my-opencode-darwin-arm64": "3.17.2", "oh-my-opencode-darwin-arm64": "3.17.4",
"oh-my-opencode-darwin-x64": "3.17.2", "oh-my-opencode-darwin-x64": "3.17.4",
"oh-my-opencode-darwin-x64-baseline": "3.17.2", "oh-my-opencode-darwin-x64-baseline": "3.17.4",
"oh-my-opencode-linux-arm64": "3.17.2", "oh-my-opencode-linux-arm64": "3.17.4",
"oh-my-opencode-linux-arm64-musl": "3.17.2", "oh-my-opencode-linux-arm64-musl": "3.17.4",
"oh-my-opencode-linux-x64": "3.17.2", "oh-my-opencode-linux-x64": "3.17.4",
"oh-my-opencode-linux-x64-baseline": "3.17.2", "oh-my-opencode-linux-x64-baseline": "3.17.4",
"oh-my-opencode-linux-x64-musl": "3.17.2", "oh-my-opencode-linux-x64-musl": "3.17.4",
"oh-my-opencode-linux-x64-musl-baseline": "3.17.2", "oh-my-opencode-linux-x64-musl-baseline": "3.17.4",
"oh-my-opencode-windows-x64": "3.17.2", "oh-my-opencode-windows-x64": "3.17.4",
"oh-my-opencode-windows-x64-baseline": "3.17.2" "oh-my-opencode-windows-x64-baseline": "3.17.4"
}, },
"overrides": {}, "overrides": {},
"trustedDependencies": [ "trustedDependencies": [
"@ast-grep/cli", "@ast-grep/cli",
"@ast-grep/napi", "@ast-grep/napi",
"@code-yeongyu/comment-checker" "@code-yeongyu/comment-checker"
] ],
"peerDependencies": {
"zod": "^4.0.0"
}
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-darwin-arm64", "name": "oh-my-opencode-darwin-arm64",
"version": "3.17.2", "version": "3.17.4",
"description": "Platform-specific binary for oh-my-opencode (darwin-arm64)", "description": "Platform-specific binary for oh-my-opencode (darwin-arm64)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-darwin-x64-baseline", "name": "oh-my-opencode-darwin-x64-baseline",
"version": "3.17.2", "version": "3.17.4",
"description": "Platform-specific binary for oh-my-opencode (darwin-x64-baseline, no AVX2)", "description": "Platform-specific binary for oh-my-opencode (darwin-x64-baseline, no AVX2)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-darwin-x64", "name": "oh-my-opencode-darwin-x64",
"version": "3.17.2", "version": "3.17.4",
"description": "Platform-specific binary for oh-my-opencode (darwin-x64)", "description": "Platform-specific binary for oh-my-opencode (darwin-x64)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-linux-arm64-musl", "name": "oh-my-opencode-linux-arm64-musl",
"version": "3.17.2", "version": "3.17.4",
"description": "Platform-specific binary for oh-my-opencode (linux-arm64-musl)", "description": "Platform-specific binary for oh-my-opencode (linux-arm64-musl)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-linux-arm64", "name": "oh-my-opencode-linux-arm64",
"version": "3.17.2", "version": "3.17.4",
"description": "Platform-specific binary for oh-my-opencode (linux-arm64)", "description": "Platform-specific binary for oh-my-opencode (linux-arm64)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-linux-x64-baseline", "name": "oh-my-opencode-linux-x64-baseline",
"version": "3.17.2", "version": "3.17.4",
"description": "Platform-specific binary for oh-my-opencode (linux-x64-baseline, no AVX2)", "description": "Platform-specific binary for oh-my-opencode (linux-x64-baseline, no AVX2)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-linux-x64-musl-baseline", "name": "oh-my-opencode-linux-x64-musl-baseline",
"version": "3.17.2", "version": "3.17.4",
"description": "Platform-specific binary for oh-my-opencode (linux-x64-musl-baseline, no AVX2)", "description": "Platform-specific binary for oh-my-opencode (linux-x64-musl-baseline, no AVX2)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-linux-x64-musl", "name": "oh-my-opencode-linux-x64-musl",
"version": "3.17.2", "version": "3.17.4",
"description": "Platform-specific binary for oh-my-opencode (linux-x64-musl)", "description": "Platform-specific binary for oh-my-opencode (linux-x64-musl)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-linux-x64", "name": "oh-my-opencode-linux-x64",
"version": "3.17.2", "version": "3.17.4",
"description": "Platform-specific binary for oh-my-opencode (linux-x64)", "description": "Platform-specific binary for oh-my-opencode (linux-x64)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-windows-x64-baseline", "name": "oh-my-opencode-windows-x64-baseline",
"version": "3.17.2", "version": "3.17.4",
"description": "Platform-specific binary for oh-my-opencode (windows-x64-baseline, no AVX2)", "description": "Platform-specific binary for oh-my-opencode (windows-x64-baseline, no AVX2)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-windows-x64", "name": "oh-my-opencode-windows-x64",
"version": "3.17.2", "version": "3.17.4",
"description": "Platform-specific binary for oh-my-opencode (windows-x64)", "description": "Platform-specific binary for oh-my-opencode (windows-x64)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
+64
View File
@@ -2831,6 +2831,70 @@
"created_at": "2026-04-15T05:03:42Z", "created_at": "2026-04-15T05:03:42Z",
"repoId": 1108837393, "repoId": 1108837393,
"pullRequestNo": 3440 "pullRequestNo": 3440
},
{
"name": "CHLK",
"id": 30882682,
"comment_id": 4252344048,
"created_at": "2026-04-15T13:10:30Z",
"repoId": 1108837393,
"pullRequestNo": 3455
},
{
"name": "omer-koren",
"id": 54630488,
"comment_id": 4257838546,
"created_at": "2026-04-16T06:34:57Z",
"repoId": 1108837393,
"pullRequestNo": 3470
},
{
"name": "EnochLi15",
"id": 38340798,
"comment_id": 4259785224,
"created_at": "2026-04-16T11:45:01Z",
"repoId": 1108837393,
"pullRequestNo": 3473
},
{
"name": "Disaster-Terminator",
"id": 47147571,
"comment_id": 4272328109,
"created_at": "2026-04-18T01:42:07Z",
"repoId": 1108837393,
"pullRequestNo": 3497
},
{
"name": "Netzhangheng",
"id": 25896014,
"comment_id": 4272702675,
"created_at": "2026-04-18T04:24:37Z",
"repoId": 1108837393,
"pullRequestNo": 3499
},
{
"name": "andomeder",
"id": 33397443,
"comment_id": 4273945668,
"created_at": "2026-04-18T14:55:50Z",
"repoId": 1108837393,
"pullRequestNo": 3514
},
{
"name": "CoderLuii",
"id": 203967356,
"comment_id": 4275088581,
"created_at": "2026-04-19T03:28:19Z",
"repoId": 1108837393,
"pullRequestNo": 3518
},
{
"name": "aschina",
"id": 31149103,
"comment_id": 4287617163,
"created_at": "2026-04-21T10:00:13Z",
"repoId": 1108837393,
"pullRequestNo": 3560
} }
] ]
} }
+2 -2
View File
@@ -1,6 +1,6 @@
# src/ — Plugin Source # src/ — Plugin Source
**Generated:** 2026-04-11 **Generated:** 2026-04-18
## OVERVIEW ## OVERVIEW
@@ -10,7 +10,7 @@ Entry point `index.ts` orchestrates 5-step initialization: loadConfig → create
| File | Purpose | | File | Purpose |
|------|---------| |------|---------|
| `index.ts` | Plugin entry, exports `OhMyOpenCodePlugin` | | `index.ts` | Plugin entry, default-exports `pluginModule: PluginModule` with `{ id, server }` |
| `plugin-config.ts` | JSONC parse, multi-level merge, Zod v4 validation | | `plugin-config.ts` | JSONC parse, multi-level merge, Zod v4 validation |
| `create-managers.ts` | TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler | | `create-managers.ts` | TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler |
| `create-tools.ts` | SkillContext + AvailableCategories + ToolRegistry (26 tools) | | `create-tools.ts` | SkillContext + AvailableCategories + ToolRegistry (26 tools) |
@@ -0,0 +1 @@
# fixture root
@@ -0,0 +1 @@
# fixture package
@@ -0,0 +1 @@
export const file16 = 16
@@ -0,0 +1 @@
export const file17 = 17
@@ -0,0 +1 @@
export const file18 = 18
@@ -0,0 +1 @@
export const file19 = 19
@@ -0,0 +1 @@
export const file20 = 20
@@ -0,0 +1 @@
# fixture src
@@ -0,0 +1 @@
export const file01 = 1
@@ -0,0 +1 @@
export const file02 = 2
@@ -0,0 +1 @@
export const file03 = 3
@@ -0,0 +1 @@
export const file04 = 4
@@ -0,0 +1 @@
export const file05 = 5
@@ -0,0 +1 @@
export const file06 = 6
@@ -0,0 +1 @@
export const file07 = 7
@@ -0,0 +1 @@
export const file08 = 8
@@ -0,0 +1 @@
export const file09 = 9
@@ -0,0 +1 @@
export const file10 = 10
@@ -0,0 +1 @@
export const file11 = 11
@@ -0,0 +1 @@
export const file12 = 12
@@ -0,0 +1 @@
export const file13 = 13
@@ -0,0 +1 @@
export const file14 = 14
@@ -0,0 +1 @@
export const file15 = 15
+121
View File
@@ -0,0 +1,121 @@
import { cpSync, mkdirSync, mkdtempSync, rmSync } from "node:fs"
import { tmpdir } from "node:os"
import { join } from "node:path"
import type { PluginInput } from "@opencode-ai/plugin"
import { createOpencodeClient } from "@opencode-ai/sdk"
import { describe, expect, it } from "bun:test"
type InitMetrics = {
coldMs: number
warmMs: [number, number]
medianMs: number
}
function getMedian(values: number[]): number {
const sorted = [...values].sort((left, right) => left - right)
return sorted[Math.floor(sorted.length / 2)] ?? 0
}
function createPluginInput(directory: string): PluginInput {
const client = createOpencodeClient({ directory })
return {
client,
project: {
id: `perf-${Date.now()}`,
worktree: directory,
time: { created: Date.now() },
},
directory,
worktree: directory,
serverUrl: new URL("http://localhost"),
$: Bun.$,
}
}
async function importFreshPluginModule(): Promise<(typeof import("../../index"))["default"]> {
const token = `${Date.now()}-${Math.random()}`
return (await import(`../../index?perf=${token}`)).default
}
async function measureInitMetrics(directory: string): Promise<InitMetrics> {
const pluginModule = await importFreshPluginModule()
const measurements: number[] = []
for (let index = 0; index < 3; index += 1) {
const input = createPluginInput(directory)
const start = performance.now()
await pluginModule.server(input, {})
measurements.push(performance.now() - start)
}
return {
coldMs: measurements[0] ?? 0,
warmMs: [measurements[1] ?? 0, measurements[2] ?? 0],
medianMs: getMedian(measurements),
}
}
async function measureScenario(
label: string,
populateDirectory: (directory: string) => void,
): Promise<InitMetrics> {
const rootDirectory = mkdtempSync(join(tmpdir(), "perf-d09-"))
const projectDirectory = join(rootDirectory, label)
const configDirectory = join(rootDirectory, "opencode-config")
const previousConfigDirectory = process.env.OPENCODE_CONFIG_DIR
mkdirSync(configDirectory, { recursive: true })
process.env.OPENCODE_CONFIG_DIR = configDirectory
try {
populateDirectory(projectDirectory)
return await measureInitMetrics(projectDirectory)
} finally {
if (previousConfigDirectory === undefined) {
delete process.env.OPENCODE_CONFIG_DIR
} else {
process.env.OPENCODE_CONFIG_DIR = previousConfigDirectory
}
rmSync(rootDirectory, { recursive: true, force: true })
}
}
function logMetrics(label: string, metrics: InitMetrics): void {
console.info(
`${label}: cold=${metrics.coldMs.toFixed(1)}ms warm=[${metrics.warmMs.map((value) => value.toFixed(1)).join(", ")}] median=${metrics.medianMs.toFixed(1)}ms`,
)
}
describe("plugin init performance", () => {
it("stays within the empty project init budget", async () => {
// given
const metrics = await measureScenario("empty-project", (directory) => {
mkdirSync(directory, { recursive: true })
})
// when
logMetrics("empty-project", metrics)
// then
// regression budget
expect(metrics.medianMs).toBeLessThan(500)
})
it("stays within the in-tree fixture init budget", async () => {
// given
const fixtureDirectory = new URL("./fixtures/in-tree/", import.meta.url)
const metrics = await measureScenario("in-tree-fixture", (directory) => {
cpSync(fixtureDirectory, directory, { recursive: true })
})
// when
logMetrics("in-tree-fixture", metrics)
// then
// regression budget
expect(metrics.medianMs).toBeLessThan(700)
})
})
+8 -8
View File
@@ -1,6 +1,6 @@
# src/agents/ — 11 Agent Definitions # src/agents/ — 11 Agent Definitions
**Generated:** 2026-04-11 **Generated:** 2026-04-18
## OVERVIEW ## OVERVIEW
@@ -10,16 +10,16 @@ Agent factories following `createXXXAgent(model) → AgentConfig` pattern. Each
| Agent | Model | Temp | Mode | Fallback Chain | Purpose | | Agent | Model | Temp | Mode | Fallback Chain | Purpose |
|-------|-------|------|------|----------------|---------| |-------|-------|------|------|----------------|---------|
| **Sisyphus** | claude-opus-4-6 max | 0.1 | all | k2p5 -> kimi-k2.5 -> gpt-5.4 medium -> glm-5 -> big-pickle | Main orchestrator, plans + delegates | | **Sisyphus** | claude-opus-4-7 max | 0.1 | all | k2p5 -> kimi-k2.5 -> gpt-5.4 medium -> glm-5 -> big-pickle | Main orchestrator, plans + delegates |
| **Hephaestus** | gpt-5.4 medium | 0.1 | all | — | Autonomous deep worker | | **Hephaestus** | gpt-5.4 medium | 0.1 | all | — | Autonomous deep worker |
| **Oracle** | gpt-5.4 high | 0.1 | subagent | gemini-3.1-pro high -> claude-opus-4-6 max | Read-only consultation | | **Oracle** | gpt-5.4 high | 0.1 | subagent | gemini-3.1-pro high -> claude-opus-4-7 max | Read-only consultation |
| **Librarian** | minimax-m2.7 | 0.1 | subagent | minimax-m2.7-highspeed -> claude-haiku-4-5 -> gpt-5-nano | External docs/code search | | **Librarian** | gpt-5.4-mini-fast | 0.1 | subagent | minimax-m2.7-highspeed -> minimax-m2.7 -> claude-haiku-4-5 -> gpt-5.4-nano | External docs/code search |
| **Explore** | grok-code-fast-1 | 0.1 | subagent | minimax-m2.7-highspeed -> minimax-m2.7 -> claude-haiku-4-5 -> gpt-5-nano | Contextual grep | | **Explore** | gpt-5.4-mini-fast | 0.1 | subagent | minimax-m2.7-highspeed -> minimax-m2.7 -> claude-haiku-4-5 -> gpt-5.4-nano | Contextual grep |
| **Multimodal-Looker** | gpt-5.3-codex medium | 0.1 | subagent | k2p5 -> gemini-3-flash -> glm-4.6v -> gpt-5-nano | PDF/image analysis | | **Multimodal-Looker** | gpt-5.3-codex medium | 0.1 | subagent | k2p5 -> gemini-3-flash -> glm-4.6v -> gpt-5-nano | PDF/image analysis |
| **Metis** | claude-opus-4-6 max | **0.3** | subagent | gpt-5.4 high -> gemini-3.1-pro high | Pre-planning consultant | | **Metis** | claude-opus-4-7 max | **0.3** | subagent | gpt-5.4 high -> gemini-3.1-pro high | Pre-planning consultant |
| **Momus** | gpt-5.4 xhigh | 0.1 | subagent | claude-opus-4-6 max -> gemini-3.1-pro high | Plan reviewer | | **Momus** | gpt-5.4 xhigh | 0.1 | subagent | claude-opus-4-7 max -> gemini-3.1-pro high | Plan reviewer |
| **Atlas** | claude-sonnet-4-6 | 0.1 | primary | gpt-5.4 medium | Todo-list orchestrator | | **Atlas** | claude-sonnet-4-6 | 0.1 | primary | gpt-5.4 medium | Todo-list orchestrator |
| **Prometheus** | claude-opus-4-6 max | 0.1 | — | internal planner | Strategic planner (internal) | | **Prometheus** | claude-opus-4-7 max | 0.1 | — | internal planner | Strategic planner (internal) |
| **Sisyphus-Junior** | claude-sonnet-4-6 | 0.1 | all | user-configurable | Category-spawned executor | | **Sisyphus-Junior** | claude-sonnet-4-6 | 0.1 | all | user-configurable | Category-spawned executor |
## TOOL RESTRICTIONS ## TOOL RESTRICTIONS
+4 -4
View File
@@ -57,7 +57,7 @@ describe("Sisyphus prompt identity", () => {
describe("#given a Sisyphus agent created with default model", () => { describe("#given a Sisyphus agent created with default model", () => {
describe("#when checking the prompt", () => { describe("#when checking the prompt", () => {
it("#then contains the agent identity section with override directive", () => { it("#then contains the agent identity section with override directive", () => {
const config = createSisyphusAgent("anthropic/claude-opus-4-6") const config = createSisyphusAgent("anthropic/claude-opus-4-7")
expect(config.prompt).toContain("<agent-identity>") expect(config.prompt).toContain("<agent-identity>")
expect(config.prompt).toContain("Sisyphus") expect(config.prompt).toContain("Sisyphus")
@@ -65,7 +65,7 @@ describe("Sisyphus prompt identity", () => {
}) })
it("#then identity section appears before the Role section", () => { it("#then identity section appears before the Role section", () => {
const config = createSisyphusAgent("anthropic/claude-opus-4-6") const config = createSisyphusAgent("anthropic/claude-opus-4-7")
const prompt = config.prompt ?? "" const prompt = config.prompt ?? ""
const identityIndex = prompt.indexOf("<agent-identity>") const identityIndex = prompt.indexOf("<agent-identity>")
const roleIndex = prompt.indexOf("<Role>") const roleIndex = prompt.indexOf("<Role>")
@@ -115,7 +115,7 @@ describe("Agent identity preservation through overrides", () => {
describe("#given a Sisyphus agent with prompt_append override", () => { describe("#given a Sisyphus agent with prompt_append override", () => {
describe("#when merging the override", () => { describe("#when merging the override", () => {
it("#then identity section is preserved in the merged prompt", () => { it("#then identity section is preserved in the merged prompt", () => {
const baseConfig = createSisyphusAgent("anthropic/claude-opus-4-6") const baseConfig = createSisyphusAgent("anthropic/claude-opus-4-7")
const merged = mergeAgentConfig(baseConfig, { prompt_append: "Extra instructions here" }) const merged = mergeAgentConfig(baseConfig, { prompt_append: "Extra instructions here" })
expect(merged.prompt).toContain("<agent-identity>") expect(merged.prompt).toContain("<agent-identity>")
@@ -129,7 +129,7 @@ describe("Agent identity preservation through overrides", () => {
describe("#given a Sisyphus agent with model override only", () => { describe("#given a Sisyphus agent with model override only", () => {
describe("#when merging the override", () => { describe("#when merging the override", () => {
it("#then identity section is preserved unchanged", () => { it("#then identity section is preserved unchanged", () => {
const baseConfig = createSisyphusAgent("anthropic/claude-opus-4-6") const baseConfig = createSisyphusAgent("anthropic/claude-opus-4-7")
const merged = mergeAgentConfig(baseConfig, { model: "openai/gpt-5.4" }) const merged = mergeAgentConfig(baseConfig, { model: "openai/gpt-5.4" })
expect(merged.prompt).toContain("<agent-identity>") expect(merged.prompt).toContain("<agent-identity>")
+6 -6
View File
@@ -150,16 +150,16 @@ task(
### 3.5 Handle Failures (USE RESUME) ### 3.5 Handle Failures (USE RESUME)
**CRITICAL: When re-delegating, ALWAYS use \`session_id\` parameter.** **CRITICAL: When re-delegating, ALWAYS use \`task_id\` parameter.**
Every \`task()\` output includes a session_id. STORE IT. Every \`task()\` output includes a task_id. STORE IT.
If task fails: If task fails:
1. Identify what went wrong 1. Identify what went wrong
2. **Resume the SAME session** - subagent has full context already: 2. **Resume the SAME session** - subagent has full context already:
\`\`\`typescript \`\`\`typescript
task( task(
session_id="ses_xyz789", // Session from failed task task_id="ses_xyz789", // Task ID from failed task
load_skills=[...], load_skills=[...],
prompt="FAILED: {error}. Fix by: {specific instruction}" prompt="FAILED: {error}. Fix by: {specific instruction}"
) )
@@ -167,7 +167,7 @@ If task fails:
3. Maximum 3 retry attempts with the SAME session 3. Maximum 3 retry attempts with the SAME session
4. If blocked after 3 attempts: Document and continue to independent tasks 4. If blocked after 3 attempts: Document and continue to independent tasks
**Why session_id is MANDATORY for failures:** **Why task_id is MANDATORY for failures:**
- Subagent already read all files, knows the context - Subagent already read all files, knows the context
- No repeated exploration = 70%+ token savings - No repeated exploration = 70%+ token savings
- Subagent knows what approaches already failed - Subagent knows what approaches already failed
@@ -292,6 +292,6 @@ export const DEFAULT_ATLAS_CRITICAL_RULES = `<critical_overrides>
- Pass inherited wisdom to every subagent - Pass inherited wisdom to every subagent
- Parallelize independent tasks - Parallelize independent tasks
- Verify with your own tools - Verify with your own tools
- **Store session_id from every delegation output** - **Store task_id from every delegation output**
- **Use \`session_id="{session_id}"\` for retries, fixes, and follow-ups** - **Use \`task_id="{task_id}"\` for retries, fixes, and follow-ups**
</critical_overrides>` </critical_overrides>`
+2 -2
View File
@@ -164,10 +164,10 @@ Count remaining **top-level task** checkboxes. Ignore nested verification/eviden
### 3.5 Handle Failures ### 3.5 Handle Failures
**CRITICAL: Use \`session_id\` for retries.** **CRITICAL: Use \`task_id\` for retries.**
\`\`\`typescript \`\`\`typescript
task(session_id="ses_xyz789", load_skills=[...], prompt="FAILED: {error}. Fix by: {instruction}") task(task_id="ses_xyz789", load_skills=[...], prompt="FAILED: {error}. Fix by: {instruction}")
\`\`\` \`\`\`
- Maximum 3 retries per task - Maximum 3 retries per task
+2 -2
View File
@@ -169,10 +169,10 @@ Count remaining **top-level task** checkboxes. Ignore nested verification/eviden
### 3.5 Handle Failures ### 3.5 Handle Failures
**CRITICAL: Use \`session_id\` for retries.** **CRITICAL: Use \`task_id\` for retries.**
\`\`\`typescript \`\`\`typescript
task(session_id="ses_xyz789", load_skills=[...], prompt="FAILED: {error}. Fix by: {instruction}") task(task_id="ses_xyz789", load_skills=[...], prompt="FAILED: {error}. Fix by: {instruction}")
\`\`\` \`\`\`
- Maximum 3 retries per task - Maximum 3 retries per task
@@ -43,7 +43,7 @@ describe("maybeCreateSisyphusConfig", () => {
// given // given
const agentOverrides: AgentOverrides = { const agentOverrides: AgentOverrides = {
sisyphus: { sisyphus: {
model: "anthropic/claude-opus-4-6", model: "anthropic/claude-opus-4-7",
permission: { permission: {
apply_patch: "allow", apply_patch: "allow",
}, },
@@ -55,8 +55,8 @@ describe("maybeCreateSisyphusConfig", () => {
const config = maybeCreateSisyphusConfig({ const config = maybeCreateSisyphusConfig({
disabledAgents: [], disabledAgents: [],
agentOverrides, agentOverrides,
availableModels: new Set(["anthropic/claude-opus-4-6"]), availableModels: new Set(["anthropic/claude-opus-4-7"]),
systemDefaultModel: "anthropic/claude-opus-4-6", systemDefaultModel: "anthropic/claude-opus-4-7",
isFirstRunNoCache: false, isFirstRunNoCache: false,
availableAgents: [], availableAgents: [],
availableSkills: [], availableSkills: [],
@@ -67,7 +67,7 @@ describe("maybeCreateSisyphusConfig", () => {
// then // then
expect(config).toBeDefined(); expect(config).toBeDefined();
expect(config?.model).toBe("anthropic/claude-opus-4-6"); expect(config?.model).toBe("anthropic/claude-opus-4-7");
// Claude models should allow the user override // Claude models should allow the user override
expect(config?.permission).toHaveProperty("apply_patch", "allow"); expect(config?.permission).toHaveProperty("apply_patch", "allow");
}); });
@@ -2,13 +2,13 @@ import { describe, expect, spyOn, test } from "bun:test"
import { createBuiltinAgents } from "./builtin-agents" import { createBuiltinAgents } from "./builtin-agents"
import * as shared from "../shared" import * as shared from "../shared"
const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-6" const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-7"
describe("createBuiltinAgents custom agent visibility", () => { describe("createBuiltinAgents custom agent visibility", () => {
test("#given runtime custom agents #when orchestrator prompts are built #then custom agents are not advertised for automatic delegation", async () => { test("#given runtime custom agents #when orchestrator prompts are built #then custom agents are not advertised for automatic delegation", async () => {
//#given //#given
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"])
) )
try { try {
+1 -1
View File
@@ -182,7 +182,7 @@ Multi-step task? **ALWAYS consult Plan Agent first.** Do NOT start implementatio
- Single-file fix or trivial change → proceed directly - Single-file fix or trivial change → proceed directly
- Anything else (2+ steps, unclear scope, architecture) → \`task(subagent_type="plan", ...)\` FIRST - Anything else (2+ steps, unclear scope, architecture) → \`task(subagent_type="plan", ...)\` FIRST
- Use \`session_id\` to resume the same Plan Agent - ask follow-up questions aggressively - Use \`task_id\` to resume the same Plan Agent - ask follow-up questions aggressively
- If ANY part of the task is ambiguous, ask Plan Agent before guessing - If ANY part of the task is ambiguous, ask Plan Agent before guessing
Plan Agent returns a structured work breakdown with parallel execution opportunities. Follow it.` Plan Agent returns a structured work breakdown with parallel execution opportunities. Follow it.`
@@ -211,7 +211,7 @@ describe("buildParallelDelegationSection", () => {
it("#given Claude model #when building #then returns empty", () => { it("#given Claude model #when building #then returns empty", () => {
//#given //#given
const model = "anthropic/claude-opus-4-6" const model = "anthropic/claude-opus-4-7"
const categories = [deepCategory] const categories = [deepCategory]
//#when //#when
@@ -244,7 +244,7 @@ describe("buildNonClaudePlannerSection", () => {
//#then //#then
expect(result).toContain("Plan Agent") expect(result).toContain("Plan Agent")
expect(result).toContain("session_id") expect(result).toContain("task_id")
expect(result).toContain("Multi-step") expect(result).toContain("Multi-step")
}) })
+4 -7
View File
@@ -25,13 +25,10 @@ export const EXPLORE_PROMPT_METADATA: AgentPromptMetadata = {
} }
export function createExploreAgent(model: string): AgentConfig { export function createExploreAgent(model: string): AgentConfig {
const restrictions = createAgentToolRestrictions([ const restrictions = createAgentToolRestrictions(
"write", ["write", "edit", "apply_patch", "task", "call_omo_agent"],
"edit", ["lsp_symbols", "lsp_goto_definition", "lsp_find_references", "lsp_diagnostics", "ast_grep_search"],
"apply_patch", )
"task",
"call_omo_agent",
])
return { return {
description: description:
+8 -8
View File
@@ -56,7 +56,7 @@ describe("getHephaestusPromptSource", () => {
test("returns 'gpt' for non-GPT models and undefined", () => { test("returns 'gpt' for non-GPT models and undefined", () => {
// given // given
const model1 = "anthropic/claude-opus-4-6"; const model1 = "anthropic/claude-opus-4-7";
const model2 = undefined; const model2 = undefined;
// when // when
@@ -124,7 +124,7 @@ describe("getHephaestusPrompt", () => {
test("Claude model returns generic GPT prompt (Hephaestus default)", () => { test("Claude model returns generic GPT prompt (Hephaestus default)", () => {
// given // given
const model = "anthropic/claude-opus-4-6"; const model = "anthropic/claude-opus-4-7";
// when // when
const prompt = getHephaestusPrompt(model); const prompt = getHephaestusPrompt(model);
@@ -149,7 +149,7 @@ describe("getHephaestusPrompt", () => {
test("useTaskSystem=false includes Todo Discipline for Claude models", () => { test("useTaskSystem=false includes Todo Discipline for Claude models", () => {
// given // given
const model = "anthropic/claude-opus-4-6"; const model = "anthropic/claude-opus-4-7";
// when // when
const prompt = getHephaestusPrompt(model, false); const prompt = getHephaestusPrompt(model, false);
@@ -239,7 +239,7 @@ describe("createHephaestusAgent", () => {
// given // given
const gpt54Model = "openai/gpt-5.4"; const gpt54Model = "openai/gpt-5.4";
const gptGenericModel = "openai/gpt-4o"; const gptGenericModel = "openai/gpt-4o";
const claudeModel = "anthropic/claude-opus-4-6"; const claudeModel = "anthropic/claude-opus-4-7";
// when // when
const gpt54Config = createHephaestusAgent(gpt54Model); const gpt54Config = createHephaestusAgent(gpt54Model);
@@ -322,7 +322,7 @@ describe("maybeCreateHephaestusConfig GPT apply_patch guard", () => {
// given // given
const agentOverrides: AgentOverrides = { const agentOverrides: AgentOverrides = {
hephaestus: { hephaestus: {
model: "anthropic/claude-opus-4-6", model: "anthropic/claude-opus-4-7",
permission: { permission: {
apply_patch: "allow", apply_patch: "allow",
}, },
@@ -334,8 +334,8 @@ describe("maybeCreateHephaestusConfig GPT apply_patch guard", () => {
const config = maybeCreateHephaestusConfig({ const config = maybeCreateHephaestusConfig({
disabledAgents: [], disabledAgents: [],
agentOverrides, agentOverrides,
availableModels: new Set(["anthropic/claude-opus-4-6"]), availableModels: new Set(["anthropic/claude-opus-4-7"]),
systemDefaultModel: "anthropic/claude-opus-4-6", systemDefaultModel: "anthropic/claude-opus-4-7",
isFirstRunNoCache: false, isFirstRunNoCache: false,
availableAgents: [], availableAgents: [],
availableSkills: [], availableSkills: [],
@@ -346,7 +346,7 @@ describe("maybeCreateHephaestusConfig GPT apply_patch guard", () => {
// then // then
expect(config).toBeDefined(); expect(config).toBeDefined();
expect(config?.model).toBe("anthropic/claude-opus-4-6"); expect(config?.model).toBe("anthropic/claude-opus-4-7");
expect(config?.permission).toHaveProperty("apply_patch", "allow"); expect(config?.permission).toHaveProperty("apply_patch", "allow");
}); });
}); });
+3 -3
View File
@@ -409,9 +409,9 @@ After delegation, ALWAYS verify: works as expected? follows codebase pattern? MU
Every \`task()\` output includes a session_id. **USE IT for follow-ups.** Every \`task()\` output includes a session_id. **USE IT for follow-ups.**
- **Task failed/incomplete** - \`session_id="{id}", prompt="Fix: {error}"\` - **Task failed/incomplete** - \`task_id="{id}", prompt="Fix: {error}"\`
- **Follow-up on result** - \`session_id="{id}", prompt="Also: {question}"\` - **Follow-up on result** - \`task_id="{id}", prompt="Also: {question}"\`
- **Verification failed** - \`session_id="{id}", prompt="Failed: {error}. Fix."\` - **Verification failed** - \`task_id="{id}", prompt="Failed: {error}. Fix."\`
${ ${
oracleSection oracleSection
+4 -4
View File
@@ -312,10 +312,10 @@ Every delegation prompt needs these 6 sections:
After delegation, verify by reading every file the subagent touched. Check: works as expected? follows codebase pattern? Do not trust self-reports. After delegation, verify by reading every file the subagent touched. Check: works as expected? follows codebase pattern? Do not trust self-reports.
<session_continuity> <session_continuity>
Every \`task()\` returns a session_id. Use it for all follow-ups: Every \`task()\` returns a task_id. Use it for all follow-ups:
- Task failed/incomplete: \`session_id="{id}", prompt="Fix: {error}"\` - Task failed/incomplete: \`task_id="{id}", prompt="Fix: {error}"\`
- Follow-up on result: \`session_id="{id}", prompt="Also: {question}"\` - Follow-up on result: \`task_id="{id}", prompt="Also: {question}"\`
- Verification failed: \`session_id="{id}", prompt="Failed: {error}. Fix."\` - Verification failed: \`task_id="{id}", prompt="Failed: {error}. Fix."\`
This preserves full context, avoids repeated exploration, saves 70%+ tokens. This preserves full context, avoids repeated exploration, saves 70%+ tokens.
</session_continuity> </session_continuity>
+4 -4
View File
@@ -277,11 +277,11 @@ After delegation, ALWAYS verify: works as expected? follows codebase pattern? MU
### Session Continuity ### Session Continuity
Every \`task()\` output includes a session_id. **USE IT for follow-ups.** Every \`task()\` output includes a task_id. **USE IT for follow-ups.**
- **Task failed/incomplete** - \`session_id="{id}", prompt="Fix: {error}"\` - **Task failed/incomplete** - \`task_id="{id}", prompt="Fix: {error}"\`
- **Follow-up on result** - \`session_id="{id}", prompt="Also: {question}"\` - **Follow-up on result** - \`task_id="{id}", prompt="Also: {question}"\`
- **Verification failed** - \`session_id="{id}", prompt="Failed: {error}. Fix."\` - **Verification failed** - \`task_id="{id}", prompt="Failed: {error}. Fix."\`
${ ${
oracleSection oracleSection
+8 -8
View File
@@ -317,15 +317,15 @@ AFTER THE WORK YOU DELEGATED SEEMS DONE, ALWAYS VERIFY THE RESULTS AS FOLLOWING:
### Session Continuity (MANDATORY) ### Session Continuity (MANDATORY)
Every \`task()\` output includes a session_id. **USE IT.** Every \`task()\` output includes a task_id. **USE IT.**
**ALWAYS continue when:** **ALWAYS continue when:**
- Task failed/incomplete → \`session_id=\"{session_id}\", prompt=\"Fix: {specific error}\"\` - Task failed/incomplete → \`task_id=\"{task_id}\", prompt=\"Fix: {specific error}\"\`
- Follow-up question on result → \`session_id=\"{session_id}\", prompt=\"Also: {question}\"\` - Follow-up question on result → \`task_id=\"{task_id}\", prompt=\"Also: {question}\"\`
- Multi-turn with same agent → \`session_id=\"{session_id}\"\` - NEVER start fresh - Multi-turn with same agent → \`task_id=\"{task_id}\"\` - NEVER start fresh
- Verification failed → \`session_id=\"{session_id}\", prompt=\"Failed verification: {error}. Fix.\"\` - Verification failed → \`task_id=\"{task_id}\", prompt=\"Failed verification: {error}. Fix.\"\`
**Why session_id is CRITICAL:** **Why task_id is CRITICAL:**
- Subagent has FULL conversation context preserved - Subagent has FULL conversation context preserved
- No repeated file reads, exploration, or setup - No repeated file reads, exploration, or setup
- Saves 70%+ tokens on follow-ups - Saves 70%+ tokens on follow-ups
@@ -336,10 +336,10 @@ Every \`task()\` output includes a session_id. **USE IT.**
task(category="quick", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix the type error in auth.ts...") task(category="quick", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix the type error in auth.ts...")
// CORRECT: Resume preserves everything // CORRECT: Resume preserves everything
task(session_id="ses_abc123", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix: Type error on line 42") task(task_id="ses_abc123", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix: Type error on line 42")
\`\`\` \`\`\`
**After EVERY delegation, STORE the session_id for potential continuation.** **After EVERY delegation, STORE the task_id for potential continuation.**
### Code Changes: ### Code Changes:
- Match existing patterns (if codebase is disciplined) - Match existing patterns (if codebase is disciplined)
+8 -8
View File
@@ -389,15 +389,15 @@ AFTER THE WORK YOU DELEGATED SEEMS DONE, ALWAYS VERIFY THE RESULTS AS FOLLOWING:
### Session Continuity (MANDATORY) ### Session Continuity (MANDATORY)
Every \`task()\` output includes a session_id. **USE IT.** Every \`task()\` output includes a task_id. **USE IT.**
**ALWAYS continue when:** **ALWAYS continue when:**
- Task failed/incomplete → \`session_id="{session_id}", prompt="Fix: {specific error}"\` - Task failed/incomplete → \`task_id="{task_id}", prompt="Fix: {specific error}"\`
- Follow-up question on result → \`session_id="{session_id}", prompt="Also: {question}"\` - Follow-up question on result → \`task_id="{task_id}", prompt="Also: {question}"\`
- Multi-turn with same agent → \`session_id="{session_id}"\` - NEVER start fresh - Multi-turn with same agent → \`task_id="{task_id}"\` - NEVER start fresh
- Verification failed → \`session_id="{session_id}", prompt="Failed verification: {error}. Fix."\` - Verification failed → \`task_id="{task_id}", prompt="Failed verification: {error}. Fix."\`
**Why session_id is CRITICAL:** **Why task_id is CRITICAL:**
- Subagent has FULL conversation context preserved - Subagent has FULL conversation context preserved
- No repeated file reads, exploration, or setup - No repeated file reads, exploration, or setup
- Saves 70%+ tokens on follow-ups - Saves 70%+ tokens on follow-ups
@@ -408,10 +408,10 @@ Every \`task()\` output includes a session_id. **USE IT.**
task(category="quick", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix the type error in auth.ts...") task(category="quick", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix the type error in auth.ts...")
// CORRECT: Resume preserves everything // CORRECT: Resume preserves everything
task(session_id="ses_abc123", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix: Type error on line 42") task(task_id="ses_abc123", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix: Type error on line 42")
\`\`\` \`\`\`
**After EVERY delegation, STORE the session_id for potential continuation.** **After EVERY delegation, STORE the task_id for potential continuation.**
### Code Changes: ### Code Changes:
- Match existing patterns (if codebase is disciplined) - Match existing patterns (if codebase is disciplined)
+4 -4
View File
@@ -387,10 +387,10 @@ Post-delegation: delegation never substitutes for verification. Always run \`<ve
### Session continuity ### Session continuity
Every \`task()\` returns a session_id. Use it for all follow-ups: Every \`task()\` returns a task_id. Use it for all follow-ups:
- Failed/incomplete → \`session_id="{id}", prompt="Fix: {specific error}"\` - Failed/incomplete → \`task_id="{id}", prompt="Fix: {specific error}"\`
- Follow-up → \`session_id="{id}", prompt="Also: {question}"\` - Follow-up → \`task_id="{id}", prompt="Also: {question}"\`
- Multi-turn → always \`session_id\`, never start fresh - Multi-turn → always \`task_id\`, never start fresh
This preserves full context, avoids repeated exploration, saves 70%+ tokens. This preserves full context, avoids repeated exploration, saves 70%+ tokens.
+7 -7
View File
@@ -18,7 +18,7 @@ describe("isGpt5_4Model", () => {
}); });
test("does not match non-GPT models", () => { test("does not match non-GPT models", () => {
expect(isGpt5_4Model("anthropic/claude-opus-4-6")).toBe(false); expect(isGpt5_4Model("anthropic/claude-opus-4-7")).toBe(false);
expect(isGpt5_4Model("google/gemini-3.1-pro")).toBe(false); expect(isGpt5_4Model("google/gemini-3.1-pro")).toBe(false);
expect(isGpt5_4Model("openai/o1")).toBe(false); expect(isGpt5_4Model("openai/o1")).toBe(false);
}); });
@@ -64,7 +64,7 @@ describe("isGptModel", () => {
}); });
test("claude models are not gpt", () => { test("claude models are not gpt", () => {
expect(isGptModel("anthropic/claude-opus-4-6")).toBe(false); expect(isGptModel("anthropic/claude-opus-4-7")).toBe(false);
expect(isGptModel("anthropic/claude-sonnet-4-6")).toBe(false); expect(isGptModel("anthropic/claude-sonnet-4-6")).toBe(false);
expect(isGptModel("litellm/anthropic.claude-opus-4-5")).toBe(false); expect(isGptModel("litellm/anthropic.claude-opus-4-5")).toBe(false);
}); });
@@ -75,7 +75,7 @@ describe("isGptModel", () => {
}); });
test("opencode provider is not gpt", () => { test("opencode provider is not gpt", () => {
expect(isGptModel("opencode/claude-opus-4-6")).toBe(false); expect(isGptModel("opencode/claude-opus-4-7")).toBe(false);
}); });
}); });
@@ -95,7 +95,7 @@ describe("isMiniMaxModel", () => {
test("does not match non-minimax models", () => { test("does not match non-minimax models", () => {
expect(isMiniMaxModel("openai/gpt-5.4")).toBe(false); expect(isMiniMaxModel("openai/gpt-5.4")).toBe(false);
expect(isMiniMaxModel("anthropic/claude-opus-4-6")).toBe(false); expect(isMiniMaxModel("anthropic/claude-opus-4-7")).toBe(false);
expect(isMiniMaxModel("google/gemini-3.1-pro")).toBe(false); expect(isMiniMaxModel("google/gemini-3.1-pro")).toBe(false);
expect(isMiniMaxModel("opencode-go/kimi-k2.5")).toBe(false); expect(isMiniMaxModel("opencode-go/kimi-k2.5")).toBe(false);
}); });
@@ -116,7 +116,7 @@ describe("isGlmModel", () => {
test("#given non-GLM models #then returns false", () => { test("#given non-GLM models #then returns false", () => {
expect(isGlmModel("openai/gpt-5.4")).toBe(false); expect(isGlmModel("openai/gpt-5.4")).toBe(false);
expect(isGlmModel("anthropic/claude-opus-4-6")).toBe(false); expect(isGlmModel("anthropic/claude-opus-4-7")).toBe(false);
expect(isGlmModel("google/gemini-3.1-pro")).toBe(false); expect(isGlmModel("google/gemini-3.1-pro")).toBe(false);
}); });
}); });
@@ -156,11 +156,11 @@ describe("isGeminiModel", () => {
}); });
test("#given claude models #then returns false", () => { test("#given claude models #then returns false", () => {
expect(isGeminiModel("anthropic/claude-opus-4-6")).toBe(false); expect(isGeminiModel("anthropic/claude-opus-4-7")).toBe(false);
expect(isGeminiModel("anthropic/claude-sonnet-4-6")).toBe(false); expect(isGeminiModel("anthropic/claude-sonnet-4-6")).toBe(false);
}); });
test("#given opencode provider #then returns false", () => { test("#given opencode provider #then returns false", () => {
expect(isGeminiModel("opencode/claude-opus-4-6")).toBe(false); expect(isGeminiModel("opencode/claude-opus-4-7")).toBe(false);
}); });
}); });
+23 -23
View File
@@ -7,7 +7,7 @@ import * as connectedProvidersCache from "../shared/connected-providers-cache"
import * as modelAvailability from "../shared/model-availability" import * as modelAvailability from "../shared/model-availability"
import * as shared from "../shared" import * as shared from "../shared"
const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-6" const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-7"
let createBuiltinAgents: (typeof import("./builtin-agents"))["createBuiltinAgents"] let createBuiltinAgents: (typeof import("./builtin-agents"))["createBuiltinAgents"]
async function importFreshBuiltinAgentsModule(): Promise<typeof import("./builtin-agents")> { async function importFreshBuiltinAgentsModule(): Promise<typeof import("./builtin-agents")> {
@@ -32,7 +32,7 @@ describe("createBuiltinAgents with model overrides", () => {
// #given // #given
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set([ new Set([
"anthropic/claude-opus-4-6", "anthropic/claude-opus-4-7",
"kimi-for-coding/k2p5", "kimi-for-coding/k2p5",
"opencode/kimi-k2.5-free", "opencode/kimi-k2.5-free",
"zai-coding-plan/glm-5", "zai-coding-plan/glm-5",
@@ -45,7 +45,7 @@ describe("createBuiltinAgents with model overrides", () => {
const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL, undefined, undefined, [], {}) const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL, undefined, undefined, [], {})
// #then // #then
expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-6") expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-7")
expect(agents.sisyphus.thinking).toEqual({ type: "enabled", budgetTokens: 32000 }) expect(agents.sisyphus.thinking).toEqual({ type: "enabled", budgetTokens: 32000 })
expect(agents.sisyphus.reasoningEffort).toBeUndefined() expect(agents.sisyphus.reasoningEffort).toBeUndefined()
} finally { } finally {
@@ -170,7 +170,7 @@ describe("createBuiltinAgents with model overrides", () => {
test("Sisyphus is created on first run when no availableModels or cache exist", async () => { test("Sisyphus is created on first run when no availableModels or cache exist", async () => {
// #given // #given
const systemDefaultModel = "anthropic/claude-opus-4-6" const systemDefaultModel = "anthropic/claude-opus-4-7"
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null) const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null)
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(new Set()) const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(new Set())
@@ -180,7 +180,7 @@ describe("createBuiltinAgents with model overrides", () => {
// #then // #then
expect(agents.sisyphus).toBeDefined() expect(agents.sisyphus).toBeDefined()
expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.6") expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.7")
} finally { } finally {
cacheSpy.mockRestore() cacheSpy.mockRestore()
fetchSpy.mockRestore() fetchSpy.mockRestore()
@@ -299,7 +299,7 @@ describe("createBuiltinAgents with model overrides", () => {
// #given // #given
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set([ new Set([
"anthropic/claude-opus-4-6", "anthropic/claude-opus-4-7",
"kimi-for-coding/k2p5", "kimi-for-coding/k2p5",
"opencode/kimi-k2.5-free", "opencode/kimi-k2.5-free",
"zai-coding-plan/glm-5", "zai-coding-plan/glm-5",
@@ -341,7 +341,7 @@ describe("createBuiltinAgents with model overrides", () => {
test("excludes hidden custom agents from orchestrator prompts", async () => { test("excludes hidden custom agents from orchestrator prompts", async () => {
// #given // #given
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"])
) )
const customAgentSummaries = [ const customAgentSummaries = [
@@ -377,7 +377,7 @@ describe("createBuiltinAgents with model overrides", () => {
test("excludes disabled custom agents from orchestrator prompts", async () => { test("excludes disabled custom agents from orchestrator prompts", async () => {
// #given // #given
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"])
) )
const customAgentSummaries = [ const customAgentSummaries = [
@@ -413,7 +413,7 @@ describe("createBuiltinAgents with model overrides", () => {
test("excludes custom agents when disabledAgents contains their name (case-insensitive)", async () => { test("excludes custom agents when disabledAgents contains their name (case-insensitive)", async () => {
// #given // #given
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"])
) )
const disabledAgents = ["ReSeArChEr"] const disabledAgents = ["ReSeArChEr"]
@@ -449,7 +449,7 @@ describe("createBuiltinAgents with model overrides", () => {
test("does not advertise duplicate custom agents case-insensitively", async () => { test("does not advertise duplicate custom agents case-insensitively", async () => {
// #given // #given
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"])
) )
const customAgentSummaries = [ const customAgentSummaries = [
@@ -481,7 +481,7 @@ describe("createBuiltinAgents with model overrides", () => {
test("does not surface custom agent strings in orchestrator prompts", async () => { test("does not surface custom agent strings in orchestrator prompts", async () => {
// #given // #given
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"])
) )
const customAgentSummaries = [ const customAgentSummaries = [
@@ -555,7 +555,7 @@ describe("createBuiltinAgents without systemDefaultModel", () => {
]) ])
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set([ new Set([
"anthropic/claude-opus-4-6", "anthropic/claude-opus-4-7",
"kimi-for-coding/k2p5", "kimi-for-coding/k2p5",
"opencode/kimi-k2.5-free", "opencode/kimi-k2.5-free",
"zai-coding-plan/glm-5", "zai-coding-plan/glm-5",
@@ -569,7 +569,7 @@ describe("createBuiltinAgents without systemDefaultModel", () => {
// #then // #then
expect(agents.sisyphus).toBeDefined() expect(agents.sisyphus).toBeDefined()
expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-6") expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-7")
} finally { } finally {
cacheSpy.mockRestore() cacheSpy.mockRestore()
fetchSpy.mockRestore() fetchSpy.mockRestore()
@@ -590,7 +590,7 @@ describe("createBuiltinAgents with requiresProvider gating (hephaestus)", () =>
const providers = options?.connectedProviders ?? [] const providers = options?.connectedProviders ?? []
return providers.includes("openai") return providers.includes("openai")
? new Set(["openai/gpt-5.3-codex"]) ? new Set(["openai/gpt-5.3-codex"])
: new Set(["anthropic/claude-opus-4-6"]) : new Set(["anthropic/claude-opus-4-7"])
}) })
try { try {
@@ -609,7 +609,7 @@ describe("createBuiltinAgents with requiresProvider gating (hephaestus)", () =>
test("hephaestus is not created when no required provider is connected", async () => { test("hephaestus is not created when no required provider is connected", async () => {
// #given - only anthropic models available, not in hephaestus requiresProvider // #given - only anthropic models available, not in hephaestus requiresProvider
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set(["anthropic/claude-opus-4-6"]) new Set(["anthropic/claude-opus-4-7"])
) )
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["anthropic"]) const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["anthropic"])
@@ -699,10 +699,10 @@ describe("createBuiltinAgents with requiresProvider gating (hephaestus)", () =>
test("hephaestus is created when explicit config provided even if provider unavailable", async () => { test("hephaestus is created when explicit config provided even if provider unavailable", async () => {
// #given // #given
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set(["anthropic/claude-opus-4-6"]) new Set(["anthropic/claude-opus-4-7"])
) )
const overrides = { const overrides = {
hephaestus: { model: "anthropic/claude-opus-4-6" }, hephaestus: { model: "anthropic/claude-opus-4-7" },
} }
try { try {
@@ -781,7 +781,7 @@ describe("Sisyphus and Librarian environment context toggle", () => {
beforeEach(() => { beforeEach(() => {
fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set(["anthropic/claude-opus-4-6", "google/gemini-3-flash"]) new Set(["anthropic/claude-opus-4-7", "google/gemini-3-flash"])
) )
}) })
@@ -840,7 +840,7 @@ describe("Atlas is unaffected by environment context toggle", () => {
beforeEach(() => { beforeEach(() => {
fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"])
) )
}) })
@@ -893,7 +893,7 @@ describe("createBuiltinAgents with requiresAnyModel gating (sisyphus)", () => {
test("sisyphus is created when at least one fallback model is available", async () => { test("sisyphus is created when at least one fallback model is available", async () => {
// #given // #given
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set(["anthropic/claude-opus-4-6"]) new Set(["anthropic/claude-opus-4-7"])
) )
try { try {
@@ -918,7 +918,7 @@ describe("createBuiltinAgents with requiresAnyModel gating (sisyphus)", () => {
// #then // #then
expect(agents.sisyphus).toBeDefined() expect(agents.sisyphus).toBeDefined()
expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.6") expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.7")
} finally { } finally {
cacheSpy.mockRestore() cacheSpy.mockRestore()
fetchSpy.mockRestore() fetchSpy.mockRestore()
@@ -929,7 +929,7 @@ describe("createBuiltinAgents with requiresAnyModel gating (sisyphus)", () => {
// #given // #given
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(new Set()) const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(new Set())
const overrides = { const overrides = {
sisyphus: { model: "anthropic/claude-opus-4-6" }, sisyphus: { model: "anthropic/claude-opus-4-7" },
} }
try { try {
@@ -1039,7 +1039,7 @@ describe("createBuiltinAgents with requiresAnyModel gating (sisyphus)", () => {
describe("buildAgent with category and skills", () => { describe("buildAgent with category and skills", () => {
const { buildAgent } = require("./agent-builder") const { buildAgent } = require("./agent-builder")
const TEST_MODEL = "anthropic/claude-opus-4-6" const TEST_MODEL = "anthropic/claude-opus-4-7"
beforeEach(() => { beforeEach(() => {
clearSkillCache() clearSkillCache()
+1 -1
View File
@@ -1,6 +1,6 @@
# src/cli/ — CLI: install, run, doctor, mcp-oauth # src/cli/ — CLI: install, run, doctor, mcp-oauth
**Generated:** 2026-04-11 **Generated:** 2026-04-18
## OVERVIEW ## OVERVIEW
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -46,7 +46,7 @@ Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi > Verce
OpenAI Native openai/ models (GPT-5.4 for Oracle) OpenAI Native openai/ models (GPT-5.4 for Oracle)
Gemini Native google/ models (Gemini 3.1 Pro, Flash) Gemini Native google/ models (Gemini 3.1 Pro, Flash)
Copilot github-copilot/ models (fallback) Copilot github-copilot/ models (fallback)
OpenCode Zen opencode/ models (opencode/claude-opus-4-6, etc.) OpenCode Zen opencode/ models (opencode/claude-opus-4-7, etc.)
Z.ai zai-coding-plan/glm-5 (visual-engineering fallback) Z.ai zai-coding-plan/glm-5 (visual-engineering fallback)
Kimi kimi-for-coding/k2p5 (Sisyphus/Prometheus fallback) Kimi kimi-for-coding/k2p5 (Sisyphus/Prometheus fallback)
Vercel vercel/ models (universal proxy, always last fallback) Vercel vercel/ models (universal proxy, always last fallback)
@@ -26,8 +26,8 @@ describe("generateOmoConfig - model fallback system", () => {
//#then //#then
expect([ expect([
"github-copilot/claude-opus-4.6", "github-copilot/claude-opus-4.7",
"github-copilot/claude-opus-4-6", "github-copilot/claude-opus-4-7",
]).toContain((result.agents as Record<string, { model: string }>).sisyphus.model) ]).toContain((result.agents as Record<string, { model: string }>).sisyphus.model)
}) })
@@ -74,7 +74,7 @@ describe("generateOmoConfig - model fallback system", () => {
//#then //#then
expect((result.agents as Record<string, { model: string }>).librarian.model).toBe("zai-coding-plan/glm-4.7") expect((result.agents as Record<string, { model: string }>).librarian.model).toBe("zai-coding-plan/glm-4.7")
expect((result.agents as Record<string, { model: string }>).sisyphus.model).toBe("anthropic/claude-opus-4.6") expect((result.agents as Record<string, { model: string }>).sisyphus.model).toBe("anthropic/claude-opus-4-7")
}) })
test("uses native OpenAI models when only ChatGPT available", () => { test("uses native OpenAI models when only ChatGPT available", () => {
@@ -131,7 +131,7 @@ describe("generateOmoConfig - model fallback system", () => {
}> }>
//#then //#then
expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.6") expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-7")
expect(agents.sisyphus.fallback_models).toEqual([ expect(agents.sisyphus.fallback_models).toEqual([
{ {
model: "openai/gpt-5.4", model: "openai/gpt-5.4",
@@ -141,7 +141,7 @@ describe("generateOmoConfig - model fallback system", () => {
expect(categories.deep.model).toBe("openai/gpt-5.4") expect(categories.deep.model).toBe("openai/gpt-5.4")
expect(categories.deep.fallback_models).toEqual([ expect(categories.deep.fallback_models).toEqual([
{ {
model: "anthropic/claude-opus-4.6", model: "anthropic/claude-opus-4-7",
variant: "max", variant: "max",
}, },
]) ])
+82
View File
@@ -0,0 +1,82 @@
# src/cli/doctor/ — Health Diagnostics (25 Check Files)
**Generated:** 2026-04-18
## OVERVIEW
`bunx oh-my-opencode doctor` — parallel diagnostic checks across 4 categories (System, Config, Tools, Models). Catches broken installs, config typos, missing dependencies, provider misconfigurations before they become runtime errors.
## COMMAND FLAGS
```bash
bunx oh-my-opencode doctor # Full diagnostics (all 4 categories)
bunx oh-my-opencode doctor --status # Compact dashboard (status only)
bunx oh-my-opencode doctor --verbose # Deep details (model resolution traces)
bunx oh-my-opencode doctor --json # Machine-readable output
```
## CHECK CATEGORIES
| Category | File | Validates |
|----------|------|-----------|
| **SYSTEM** | `checks/system.ts` | OpenCode binary found + version ≥1.0.150, plugin registered in opencode.json, loaded plugin version matches installed |
| **CONFIG** | `checks/config.ts` | JSONC validity, Zod schema passes, no unknown keys, model override syntax correct |
| **TOOLS** | `checks/tools.ts` | AST-Grep CLI + NAPI, comment-checker binary, LSP servers reachable, GitHub CLI auth, built-in MCP reachability |
| **MODELS** | `checks/model-resolution.ts` | models.json cache exists, per-agent fallback resolution, category overrides valid, provider availability |
## SUPPORTING CHECK FILES (25 total)
```
checks/
├── index.ts # Registration
├── system.ts # Main System aggregator
├── system-binary.ts # OpenCode binary discovery (PATH + desktop app)
├── system-plugin.ts # opencode.json plugin entry detection
├── system-loaded-version.ts # Cache vs npm latest
├── config.ts # Main Config aggregator
├── tools.ts # Main Tools aggregator
├── dependencies.ts # AST-Grep CLI/NAPI + comment-checker presence
├── tools-gh.ts # gh cli install + auth status
├── tools-lsp.ts # LSP server enumeration
├── tools-mcp.ts # Built-in + user MCP reachability
├── model-resolution.ts # Main Models aggregator
├── model-resolution-cache.ts # models.json presence + freshness
├── model-resolution-config.ts # oh-my-opencode.jsonc parse
├── model-resolution-effective-model.ts # Per-agent fallback chain trace
├── model-resolution-variant.ts # Model variant (max, high, medium) handling
├── model-resolution-details.ts # Verbose output formatter
└── model-resolution-types.ts # Shared types
```
## EXECUTION FLOW
```
doctor command
→ runner.ts: parallel check execution with 30s per-check timeout
→ checks/index.ts registers all 4 category checks
→ each check returns: { status: "ok" | "warn" | "error", detail: string }
→ formatter.ts: render to stdout (text/status/json)
→ exit code: 0 (all ok) | 1 (errors) | 2 (warnings only)
```
## KEY FILES
| File | Purpose |
|------|---------|
| `index.ts` | CLI command entry, flag parsing |
| `runner.ts` | Parallel `Promise.allSettled()` orchestration, 30s timeout per check |
| `formatter.ts` | Pretty printing: colored status, hierarchical output |
| `types.ts` | `DoctorCheck`, `CheckResult`, `DoctorReport` types |
## HOW TO ADD A CHECK
1. Create `src/cli/doctor/checks/{name}.ts` exporting check function matching `DoctorCheck`
2. Register in `checks/index.ts`
3. Category-level aggregator (system/config/tools/model-resolution) invokes it
4. Return `{ status, detail }` — no throws, all errors caught by runner
## EXIT CODES
- `0`: All checks passed (or only info messages)
- `1`: One or more errors — plugin will likely not work
- `2`: Warnings only — plugin works with degraded features
@@ -34,7 +34,7 @@ describe("loadAvailableModelsFromCache", () => {
join(tempDir, "cache", "opencode", "models.json"), join(tempDir, "cache", "opencode", "models.json"),
JSON.stringify({ JSON.stringify({
openai: { models: { "gpt-5.4": {} } }, openai: { models: { "gpt-5.4": {} } },
anthropic: { models: { "claude-opus-4-6": {}, "claude-sonnet-4-6": {} } }, anthropic: { models: { "claude-opus-4-7": {}, "claude-sonnet-4-6": {} } },
}) })
) )
@@ -14,7 +14,7 @@ describe("model-resolution check", () => {
// then: Should have agent entries // then: Should have agent entries
const sisyphus = info.agents.find((a) => a.name === "sisyphus") const sisyphus = info.agents.find((a) => a.name === "sisyphus")
expect(sisyphus).toBeDefined() expect(sisyphus).toBeDefined()
expect(sisyphus!.requirement.fallbackChain[0]?.model).toBe("claude-opus-4-6") expect(sisyphus!.requirement.fallbackChain[0]?.model).toBe("claude-opus-4-7")
expect(sisyphus!.requirement.fallbackChain[0]?.providers).toContain("anthropic") expect(sisyphus!.requirement.fallbackChain[0]?.providers).toContain("anthropic")
}) })
@@ -42,7 +42,7 @@ describe("model-resolution check", () => {
// given: User has override for oracle agent // given: User has override for oracle agent
const mockConfig = { const mockConfig = {
agents: { agents: {
oracle: { model: "anthropic/claude-opus-4-6" }, oracle: { model: "anthropic/claude-opus-4-7" },
}, },
} }
@@ -51,8 +51,8 @@ describe("model-resolution check", () => {
// then: Oracle should show the override // then: Oracle should show the override
const oracle = info.agents.find((a) => a.name === "oracle") const oracle = info.agents.find((a) => a.name === "oracle")
expect(oracle).toBeDefined() expect(oracle).toBeDefined()
expect(oracle!.userOverride).toBe("anthropic/claude-opus-4-6") expect(oracle!.userOverride).toBe("anthropic/claude-opus-4-7")
expect(oracle!.effectiveResolution).toBe("User override: anthropic/claude-opus-4-6") expect(oracle!.effectiveResolution).toBe("User override: anthropic/claude-opus-4-7")
}) })
it("shows user override for category when configured", async () => { it("shows user override for category when configured", async () => {
@@ -169,13 +169,13 @@ describe("model-resolution check", () => {
const info = getModelResolutionInfoWithOverrides({ const info = getModelResolutionInfoWithOverrides({
agents: { agents: {
oracle: { model: "anthropic/claude-opus-4-6-thinking" }, oracle: { model: "anthropic/claude-opus-4-7-thinking" },
}, },
}) })
const oracle = info.agents.find((agent) => agent.name === "oracle") const oracle = info.agents.find((agent) => agent.name === "oracle")
expect(oracle).toBeDefined() expect(oracle).toBeDefined()
expect(oracle!.effectiveModel).toBe("anthropic/claude-opus-4-6-thinking") expect(oracle!.effectiveModel).toBe("anthropic/claude-opus-4-7-thinking")
expect(oracle!.capabilityDiagnostics).toMatchObject({ expect(oracle!.capabilityDiagnostics).toMatchObject({
resolutionMode: "alias-backed", resolutionMode: "alias-backed",
canonicalization: { canonicalization: {
+20 -24
View File
@@ -355,9 +355,9 @@ describe("generateModelConfig", () => {
// #when generateModelConfig is called // #when generateModelConfig is called
const result = generateModelConfig(config) const result = generateModelConfig(config)
// #then explore should use native OpenAI model // #then explore should use native OpenAI mini-fast (primary model)
expect(result.agents?.explore?.model).toBe("openai/gpt-5.4") expect(result.agents?.explore?.model).toBe("openai/gpt-5.4-mini-fast")
expect(result.agents?.explore?.variant).toBe("medium") expect(result.agents?.explore?.variant).toBeUndefined()
}) })
test("explore uses gpt-5-mini when only Copilot available", () => { test("explore uses gpt-5-mini when only Copilot available", () => {
@@ -381,7 +381,7 @@ describe("generateModelConfig", () => {
const result = generateModelConfig(config) const result = generateModelConfig(config)
// #then // #then
expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4.6") expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-7")
}) })
test("Sisyphus is created when multiple fallback providers are available", () => { test("Sisyphus is created when multiple fallback providers are available", () => {
@@ -398,7 +398,7 @@ describe("generateModelConfig", () => {
const result = generateModelConfig(config) const result = generateModelConfig(config)
// #then // #then
expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4.6") expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-7")
}) })
test("Sisyphus resolves to gpt-5.4 medium when only OpenAI is available", () => { test("Sisyphus resolves to gpt-5.4 medium when only OpenAI is available", () => {
@@ -553,15 +553,15 @@ describe("generateModelConfig", () => {
}) })
describe("special-case agents include fallback_models", () => { describe("special-case agents include fallback_models", () => {
test("explore includes fallback_models when Copilot and Claude are both available", () => { test("explore includes fallback_models when OpenAI and Claude are both available", () => {
// #given both Copilot and Claude are available // #given both OpenAI and Claude are available
const config = createConfig({ hasCopilot: true, hasClaude: true }) const config = createConfig({ hasOpenAI: true, hasClaude: true })
// #when generateModelConfig is called // #when generateModelConfig is called
const result = generateModelConfig(config) const result = generateModelConfig(config)
// #then explore should have fallback_models from the remaining chain entries // #then explore should have fallback_models from the remaining chain entries
expect(result.agents?.explore?.model).toBe("anthropic/claude-haiku-4-5") expect(result.agents?.explore?.model).toBe("openai/gpt-5.4-mini-fast")
expect(result.agents?.explore?.fallback_models).toBeDefined() expect(result.agents?.explore?.fallback_models).toBeDefined()
expect(result.agents?.explore?.fallback_models?.length).toBeGreaterThan(0) expect(result.agents?.explore?.fallback_models?.length).toBeGreaterThan(0)
}) })
@@ -573,37 +573,33 @@ describe("generateModelConfig", () => {
// #when generateModelConfig is called // #when generateModelConfig is called
const result = generateModelConfig(config) const result = generateModelConfig(config)
// #then explore should not have fallback_models (only one chain entry matches) // #then explore should not have fallback_models (only one distinct chain entry matches)
expect(result.agents?.explore?.model).toBe("anthropic/claude-haiku-4-5") expect(result.agents?.explore?.model).toBe("anthropic/claude-haiku-4-5")
expect(result.agents?.explore?.fallback_models).toEqual([ expect(result.agents?.explore?.fallback_models).toBeUndefined()
{
model: "anthropic/claude-haiku-4.5",
},
])
}) })
test("librarian includes fallback_models when opencode-go and Claude are both available", () => { test("librarian includes fallback_models when OpenAI and opencode-go are both available", () => {
// #given opencode-go and Claude are available // #given OpenAI and opencode-go are available
const config = createConfig({ hasOpencodeGo: true, hasClaude: true }) const config = createConfig({ hasOpenAI: true, hasOpencodeGo: true })
// #when generateModelConfig is called // #when generateModelConfig is called
const result = generateModelConfig(config) const result = generateModelConfig(config)
// #then librarian should have fallback_models // #then librarian should have fallback_models
expect(result.agents?.librarian?.model).toBe("opencode-go/minimax-m2.7") expect(result.agents?.librarian?.model).toBe("openai/gpt-5.4-mini-fast")
expect(result.agents?.librarian?.fallback_models).toBeDefined() expect(result.agents?.librarian?.fallback_models).toBeDefined()
expect(result.agents?.librarian?.fallback_models?.length).toBeGreaterThan(0) expect(result.agents?.librarian?.fallback_models?.length).toBeGreaterThan(0)
}) })
test("librarian omits fallback_models when only one provider matches", () => { test("librarian omits fallback_models when only ZAI is available", () => {
// #given only opencode-go is available // #given only ZAI is available
const config = createConfig({ hasOpencodeGo: true }) const config = createConfig({ hasZaiCodingPlan: true })
// #when generateModelConfig is called // #when generateModelConfig is called
const result = generateModelConfig(config) const result = generateModelConfig(config)
// #then librarian should not have fallback_models // #then librarian should not have fallback_models
expect(result.agents?.librarian?.model).toBe("opencode-go/minimax-m2.7") expect(result.agents?.librarian?.model).toBe("zai-coding-plan/glm-4.7")
expect(result.agents?.librarian?.fallback_models).toBeUndefined() expect(result.agents?.librarian?.fallback_models).toBeUndefined()
}) })
}) })
@@ -672,7 +668,7 @@ describe("generateModelConfig", () => {
const result = generateModelConfig(config) const result = generateModelConfig(config)
// #then should prefer native anthropic over gateway // #then should prefer native anthropic over gateway
expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4.6") expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-7")
}) })
}) })
+6 -2
View File
@@ -127,7 +127,9 @@ export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig {
for (const [role, req] of Object.entries(CLI_AGENT_MODEL_REQUIREMENTS)) { for (const [role, req] of Object.entries(CLI_AGENT_MODEL_REQUIREMENTS)) {
if (role === "librarian") { if (role === "librarian") {
let agentConfig: AgentConfig | undefined let agentConfig: AgentConfig | undefined
if (avail.opencodeGo) { if (avail.native.openai) {
agentConfig = { model: "openai/gpt-5.4-mini-fast" }
} else if (avail.opencodeGo) {
agentConfig = { model: "opencode-go/minimax-m2.7" } agentConfig = { model: "opencode-go/minimax-m2.7" }
} else if (avail.zai) { } else if (avail.zai) {
agentConfig = { model: ZAI_MODEL } agentConfig = { model: ZAI_MODEL }
@@ -142,7 +144,9 @@ export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig {
if (role === "explore") { if (role === "explore") {
let agentConfig: AgentConfig let agentConfig: AgentConfig
if (avail.native.claude) { if (avail.native.openai) {
agentConfig = { model: "openai/gpt-5.4-mini-fast" }
} else if (avail.native.claude) {
agentConfig = { model: "anthropic/claude-haiku-4-5" } agentConfig = { model: "anthropic/claude-haiku-4-5" }
} else if (avail.opencodeZen) { } else if (avail.opencodeZen) {
agentConfig = { model: "opencode/claude-haiku-4-5" } agentConfig = { model: "opencode/claude-haiku-4-5" }
+6 -4
View File
@@ -28,8 +28,8 @@ describe("generateModelConfig OpenAI-only model catalog", () => {
const result = generateModelConfig(config) const result = generateModelConfig(config)
// #then // #then
expect(result.agents?.explore).toEqual({ model: "openai/gpt-5.4", variant: "medium" }) expect(result.agents?.explore).toEqual({ model: "openai/gpt-5.4-mini-fast" })
expect(result.agents?.librarian).toEqual({ model: "openai/gpt-5.4", variant: "medium" }) expect(result.agents?.librarian).toEqual({ model: "openai/gpt-5.4-mini-fast" })
}) })
test("fills remaining OpenAI-only category gaps with OpenAI models", () => { test("fills remaining OpenAI-only category gaps with OpenAI models", () => {
@@ -54,8 +54,10 @@ describe("generateModelConfig OpenAI-only model catalog", () => {
const result = generateModelConfig(config) const result = generateModelConfig(config)
// #then // #then
expect(result.agents?.explore).toMatchObject({ model: "opencode-go/minimax-m2.7" }) expect(result.agents?.explore).toMatchObject({ model: "openai/gpt-5.4-mini-fast" })
expect(result.agents?.librarian).toMatchObject({ model: "opencode-go/minimax-m2.7" }) expect(result.agents?.librarian).toMatchObject({ model: "openai/gpt-5.4-mini-fast" })
expect(result.agents?.explore).not.toMatchObject({ variant: "medium" })
expect(result.agents?.librarian).not.toMatchObject({ variant: "medium" })
expect(result.categories?.quick).toMatchObject({ model: "openai/gpt-5.4-mini" }) expect(result.categories?.quick).toMatchObject({ model: "openai/gpt-5.4-mini" })
}) })
}) })
+2 -2
View File
@@ -1,8 +1,8 @@
import type { AgentConfig, CategoryConfig, GeneratedOmoConfig, ProviderAvailability } from "./model-fallback-types" import type { AgentConfig, CategoryConfig, GeneratedOmoConfig, ProviderAvailability } from "./model-fallback-types"
const OPENAI_ONLY_AGENT_OVERRIDES: Record<string, AgentConfig> = { const OPENAI_ONLY_AGENT_OVERRIDES: Record<string, AgentConfig> = {
explore: { model: "openai/gpt-5.4", variant: "medium" }, explore: { model: "openai/gpt-5.4-mini-fast" },
librarian: { model: "openai/gpt-5.4", variant: "medium" }, librarian: { model: "openai/gpt-5.4-mini-fast" },
} }
const OPENAI_ONLY_CATEGORY_OVERRIDES: Record<string, CategoryConfig> = { const OPENAI_ONLY_CATEGORY_OVERRIDES: Record<string, CategoryConfig> = {
+35 -33
View File
@@ -5,16 +5,16 @@ import { transformModelForProvider as transformSharedModelForProvider } from "..
describe("transformModelForProvider", () => { describe("transformModelForProvider", () => {
describe("github-copilot provider", () => { describe("github-copilot provider", () => {
test("transforms claude-opus-4-6 to claude-opus-4.6", () => { test("transforms claude-opus-4-7 to claude-opus-4.7", () => {
// #given github-copilot provider and claude-opus-4-6 model // #given github-copilot provider and claude-opus-4-7 model
const provider = "github-copilot" const provider = "github-copilot"
const model = "claude-opus-4-6" const model = "claude-opus-4-7"
// #when transformModelForProvider is called // #when transformModelForProvider is called
const result = transformModelForProvider(provider, model) const result = transformModelForProvider(provider, model)
// #then should transform to claude-opus-4.6 // #then should transform to claude-opus-4.7
expect(result).toBe("claude-opus-4.6") expect(result).toBe("claude-opus-4.7")
}) })
test("transforms claude-sonnet-4-5 to claude-sonnet-4.5", () => { test("transforms claude-sonnet-4-5 to claude-sonnet-4.5", () => {
@@ -152,32 +152,32 @@ describe("transformModelForProvider", () => {
}) })
test("does not transform claude models for google provider", () => { test("does not transform claude models for google provider", () => {
// #given google provider and claude-opus-4-6 model // #given google provider and claude-opus-4-7 model
const provider = "google" const provider = "google"
const model = "claude-opus-4-6" const model = "claude-opus-4-7"
// #when transformModelForProvider is called // #when transformModelForProvider is called
const result = transformModelForProvider(provider, model) const result = transformModelForProvider(provider, model)
// #then should pass through unchanged (google doesn't use claude) // #then should pass through unchanged (google doesn't use claude)
expect(result).toBe("claude-opus-4-6") expect(result).toBe("claude-opus-4-7")
}) })
}) })
describe("anthropic provider", () => { describe("anthropic provider", () => {
test("transforms claude-opus-4-6 to claude-opus-4.6", () => { test("preserves hyphenated claude-opus-4-7 for config output (regression: installer must not write dotted IDs)", () => {
// #given anthropic provider and claude-opus-4-6 model // #given anthropic provider and claude-opus-4-7 model
const provider = "anthropic" const provider = "anthropic"
const model = "claude-opus-4-6" const model = "claude-opus-4-7"
// #when transformModelForProvider is called // #when transformModelForProvider is called
const result = transformModelForProvider(provider, model) const result = transformModelForProvider(provider, model)
// #then should transform to claude-opus-4.6 // #then should keep hyphenated form so Anthropic provider resolution succeeds on fresh installs
expect(result).toBe("claude-opus-4.6") expect(result).toBe("claude-opus-4-7")
}) })
test("transforms claude-sonnet-4-6 to claude-sonnet-4.6", () => { test("preserves hyphenated claude-sonnet-4-6 for config output", () => {
// #given anthropic provider and claude-sonnet-4-6 model // #given anthropic provider and claude-sonnet-4-6 model
const provider = "anthropic" const provider = "anthropic"
const model = "claude-sonnet-4-6" const model = "claude-sonnet-4-6"
@@ -185,11 +185,11 @@ describe("transformModelForProvider", () => {
// #when transformModelForProvider is called // #when transformModelForProvider is called
const result = transformModelForProvider(provider, model) const result = transformModelForProvider(provider, model)
// #then should transform to claude-sonnet-4.6 // #then should keep hyphenated form
expect(result).toBe("claude-sonnet-4.6") expect(result).toBe("claude-sonnet-4-6")
}) })
test("transforms claude-haiku-4-5 to claude-haiku-4.5", () => { test("preserves hyphenated claude-haiku-4-5 for config output", () => {
// #given anthropic provider and claude-haiku-4-5 model // #given anthropic provider and claude-haiku-4-5 model
const provider = "anthropic" const provider = "anthropic"
const model = "claude-haiku-4-5" const model = "claude-haiku-4-5"
@@ -197,19 +197,19 @@ describe("transformModelForProvider", () => {
// #when transformModelForProvider is called // #when transformModelForProvider is called
const result = transformModelForProvider(provider, model) const result = transformModelForProvider(provider, model)
// #then should transform to claude-haiku-4.5 // #then should keep hyphenated form
expect(result).toBe("claude-haiku-4.5") expect(result).toBe("claude-haiku-4-5")
}) })
}) })
describe("vercel provider", () => { describe("vercel provider", () => {
test("prepends anthropic/ and applies anthropic transform for claude models", () => { test("prepends anthropic/ and applies anthropic transform for claude models", () => {
// #given vercel provider and claude-opus-4-6 model // #given vercel provider and claude-opus-4-7 model
// #when transformModelForProvider is called // #when transformModelForProvider is called
const result = transformModelForProvider("vercel", "claude-opus-4-6") const result = transformModelForProvider("vercel", "claude-opus-4-7")
// #then should produce anthropic/claude-opus-4.6 // #then should produce anthropic/claude-opus-4.7
expect(result).toBe("anthropic/claude-opus-4.6") expect(result).toBe("anthropic/claude-opus-4.7")
}) })
test("prepends anthropic/ and applies anthropic transform for claude-sonnet", () => { test("prepends anthropic/ and applies anthropic transform for claude-sonnet", () => {
@@ -267,12 +267,12 @@ describe("transformModelForProvider", () => {
}) })
test("delegates to sub-provider when model already has sub-provider prefix", () => { test("delegates to sub-provider when model already has sub-provider prefix", () => {
// #given vercel provider and anthropic/claude-opus-4-6 (already prefixed) // #given vercel provider and anthropic/claude-opus-4-7 (already prefixed)
// #when transformModelForProvider is called // #when transformModelForProvider is called
const result = transformModelForProvider("vercel", "anthropic/claude-opus-4-6") const result = transformModelForProvider("vercel", "anthropic/claude-opus-4-7")
// #then should apply anthropic transform within the prefix // #then should apply anthropic transform within the prefix
expect(result).toBe("anthropic/claude-opus-4.6") expect(result).toBe("anthropic/claude-opus-4.7")
}) })
test("prepends minimax/ for minimax models", () => { test("prepends minimax/ for minimax models", () => {
@@ -338,14 +338,16 @@ describe("transformModelForProvider", () => {
}) })
}) })
test("uses a CLI-local transform implementation", () => { test("uses a CLI-local transform implementation distinct from the shared runtime transform", () => {
// #given // #given the CLI transform (used by the installer) and the shared runtime transform
const cliResult = transformModelForProvider("anthropic", "claude-opus-4-6") const cliResult = transformModelForProvider("anthropic", "claude-opus-4-7")
const sharedResult = transformSharedModelForProvider("anthropic", "claude-opus-4-6") const sharedResult = transformSharedModelForProvider("anthropic", "claude-opus-4-7")
// #when // #when both are called with the same anthropic claude input
// #then the CLI preserves hyphenated form for config output,
// the shared runtime transform converts dash→dot for API calls
expect(transformModelForProvider).not.toBe(transformSharedModelForProvider) expect(transformModelForProvider).not.toBe(transformSharedModelForProvider)
expect(cliResult).toBe("claude-opus-4.6") expect(cliResult).toBe("claude-opus-4-7")
expect(sharedResult).toBe("claude-opus-4.6") expect(sharedResult).toBe("claude-opus-4.7")
}) })
}) })
+6 -1
View File
@@ -54,7 +54,12 @@ export function transformModelForProvider(provider: string, model: string): stri
} }
if (provider === "anthropic") { if (provider === "anthropic") {
return claudeVersionDot(model) // Installer writes hyphenated IDs (claude-opus-4-7) to the config. The
// runtime provider-model-id-transform converts dash→dot when calling the
// Anthropic API. Keeping the dotted form in the config breaks fresh
// installs with ProviderModelNotFoundError because Anthropic's provider
// registers models under hyphenated IDs.
return model
} }
return model return model
+1 -1
View File
@@ -49,7 +49,7 @@ describe("refreshModelCapabilities", () => {
sourceUrl: "https://override.example/api.json", sourceUrl: "https://override.example/api.json",
models: { models: {
"gpt-5.4": { id: "gpt-5.4" }, "gpt-5.4": { id: "gpt-5.4" },
"claude-opus-4-6": { id: "claude-opus-4-6" }, "claude-opus-4-7": { id: "claude-opus-4-7" },
}, },
})) }))
let stdout = "" let stdout = ""
+11 -11
View File
@@ -98,7 +98,7 @@ describe("message.part.delta handling", () => {
sessionID: "ses_main", sessionID: "ses_main",
role: "assistant", role: "assistant",
agent: "Sisyphus - Ultraworker", agent: "Sisyphus - Ultraworker",
modelID: "claude-opus-4-6", modelID: "claude-opus-4-7",
variant: "max", variant: "max",
}, },
}, },
@@ -113,7 +113,7 @@ describe("message.part.delta handling", () => {
//#then //#then
const rendered = stdoutSpy.mock.calls.map((call) => String(call[0] ?? "")).join("") const rendered = stdoutSpy.mock.calls.map((call) => String(call[0] ?? "")).join("")
expect(rendered).toContain("\u001b[38;2;0;206;209m") expect(rendered).toContain("\u001b[38;2;0;206;209m")
expect(rendered).toContain("claude-opus-4-6 (max)") expect(rendered).toContain("claude-opus-4-7 (max)")
expect(rendered).toContain("└─") expect(rendered).toContain("└─")
expect(rendered).toContain("Sisyphus - Ultraworker") expect(rendered).toContain("Sisyphus - Ultraworker")
stdoutSpy.mockRestore() stdoutSpy.mockRestore()
@@ -128,7 +128,7 @@ describe("message.part.delta handling", () => {
{ {
type: "message.updated", type: "message.updated",
properties: { properties: {
info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" },
}, },
}, },
{ {
@@ -187,7 +187,7 @@ describe("message.part.delta handling", () => {
{ {
type: "message.updated", type: "message.updated",
properties: { properties: {
info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" },
}, },
}, },
{ {
@@ -242,7 +242,7 @@ describe("message.part.delta handling", () => {
{ {
type: "message.updated", type: "message.updated",
properties: { properties: {
info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" },
}, },
}, },
{ {
@@ -309,7 +309,7 @@ describe("message.part.delta handling", () => {
{ {
type: "message.updated", type: "message.updated",
properties: { properties: {
info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" },
}, },
}, },
{ {
@@ -353,7 +353,7 @@ describe("message.part.delta handling", () => {
{ {
type: "message.updated", type: "message.updated",
properties: { properties: {
info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6", variant: "max" }, info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7", variant: "max" },
}, },
}, },
{ {
@@ -388,7 +388,7 @@ describe("message.part.delta handling", () => {
{ {
type: "message.updated", type: "message.updated",
properties: { properties: {
info: { id: "msg_user", sessionID: "ses_main", role: "user", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, info: { id: "msg_user", sessionID: "ses_main", role: "user", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" },
}, },
}, },
{ {
@@ -410,7 +410,7 @@ describe("message.part.delta handling", () => {
{ {
type: "message.updated", type: "message.updated",
properties: { properties: {
info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" },
}, },
}, },
{ {
@@ -619,7 +619,7 @@ describe("message.part.delta handling", () => {
{ {
type: "message.updated", type: "message.updated",
properties: { properties: {
info: { id: "msg_1", sessionID: "ses_main", role: "assistant", agent: "Sisyphus", modelID: "claude-opus-4-6" }, info: { id: "msg_1", sessionID: "ses_main", role: "assistant", agent: "Sisyphus", modelID: "claude-opus-4-7" },
}, },
}, },
{ {
@@ -634,7 +634,7 @@ describe("message.part.delta handling", () => {
{ {
type: "message.updated", type: "message.updated",
properties: { properties: {
info: { id: "msg_1", sessionID: "ses_main", role: "assistant", agent: "Sisyphus", modelID: "claude-opus-4-6" }, info: { id: "msg_1", sessionID: "ses_main", role: "assistant", agent: "Sisyphus", modelID: "claude-opus-4-7" },
}, },
}, },
{ {
+55 -3
View File
@@ -3,6 +3,7 @@ import { describe, it, expect, mock, beforeEach, afterEach, afterAll } from "bun
import * as originalSdk from "@opencode-ai/sdk" import * as originalSdk from "@opencode-ai/sdk"
import * as originalPortUtils from "../../shared/port-utils" import * as originalPortUtils from "../../shared/port-utils"
import * as originalBinaryResolver from "./opencode-binary-resolver" import * as originalBinaryResolver from "./opencode-binary-resolver"
import * as originalServerAuth from "../../shared/opencode-server-auth"
const originalConsole = globalThis.console const originalConsole = globalThis.console
@@ -13,11 +14,15 @@ const mockCreateOpencode = mock(() =>
server: { url: "http://127.0.0.1:4096", close: mockServerClose }, server: { url: "http://127.0.0.1:4096", close: mockServerClose },
}) })
) )
const mockCreateOpencodeClient = mock(() => ({ session: {} })) const mockCreateOpencodeClient = mock((options?: { baseUrl?: string }) => ({
session: {},
baseUrl: options?.baseUrl,
}))
const mockIsPortAvailable = mock(() => Promise.resolve(true)) const mockIsPortAvailable = mock(() => Promise.resolve(true))
const mockGetAvailableServerPort = mock(() => Promise.resolve({ port: 4096, wasAutoSelected: false })) const mockGetAvailableServerPort = mock(() => Promise.resolve({ port: 4096, wasAutoSelected: false }))
const mockConsoleLog = mock(() => {}) const mockConsoleLog = mock(() => {})
const mockWithWorkingOpencodePath = mock((startServer: () => Promise<unknown>) => startServer()) const mockWithWorkingOpencodePath = mock((startServer: () => Promise<unknown>) => startServer())
const mockInjectServerAuthIntoClient = mock(() => {})
mock.module("@opencode-ai/sdk", () => ({ mock.module("@opencode-ai/sdk", () => ({
createOpencode: mockCreateOpencode, createOpencode: mockCreateOpencode,
@@ -34,10 +39,15 @@ mock.module("./opencode-binary-resolver", () => ({
withWorkingOpencodePath: mockWithWorkingOpencodePath, withWorkingOpencodePath: mockWithWorkingOpencodePath,
})) }))
mock.module("../../shared/opencode-server-auth", () => ({
injectServerAuthIntoClient: mockInjectServerAuthIntoClient,
}))
afterAll(() => { afterAll(() => {
mock.module("@opencode-ai/sdk", () => originalSdk) mock.module("@opencode-ai/sdk", () => originalSdk)
mock.module("../../shared/port-utils", () => originalPortUtils) mock.module("../../shared/port-utils", () => originalPortUtils)
mock.module("./opencode-binary-resolver", () => originalBinaryResolver) mock.module("./opencode-binary-resolver", () => originalBinaryResolver)
mock.module("../../shared/opencode-server-auth", () => originalServerAuth)
mock.restore() mock.restore()
}) })
@@ -52,6 +62,7 @@ describe("createServerConnection", () => {
mockServerClose.mockClear() mockServerClose.mockClear()
mockConsoleLog.mockClear() mockConsoleLog.mockClear()
mockWithWorkingOpencodePath.mockClear() mockWithWorkingOpencodePath.mockClear()
mockInjectServerAuthIntoClient.mockClear()
globalThis.console = { ...console, log: mockConsoleLog } as typeof console globalThis.console = { ...console, log: mockConsoleLog } as typeof console
}) })
@@ -59,6 +70,49 @@ describe("createServerConnection", () => {
globalThis.console = originalConsole globalThis.console = originalConsole
}) })
it("attach mode injects auth only for loopback URLs", async () => {
// given
const signal = new AbortController().signal
// when
const localhostResult = await createServerConnection({ attach: "http://localhost:8080", signal })
const loopbackResult = await createServerConnection({ attach: "http://127.0.0.1:8080", signal })
const anyBindResult = await createServerConnection({ attach: "http://0.0.0.0:8080", signal })
const remoteResult = await createServerConnection({ attach: "https://example.com", signal })
// then
expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: "http://localhost:8080" })
expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: "http://127.0.0.1:8080" })
expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: "http://0.0.0.0:8080" })
expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: "https://example.com" })
expect(mockInjectServerAuthIntoClient).toHaveBeenCalledTimes(3)
expect(mockInjectServerAuthIntoClient).toHaveBeenNthCalledWith(1, localhostResult.client)
expect(mockInjectServerAuthIntoClient).toHaveBeenNthCalledWith(2, loopbackResult.client)
expect(mockInjectServerAuthIntoClient).toHaveBeenNthCalledWith(3, anyBindResult.client)
expect(mockInjectServerAuthIntoClient).not.toHaveBeenCalledWith(remoteResult.client)
expect(mockWithWorkingOpencodePath).not.toHaveBeenCalled()
localhostResult.cleanup()
loopbackResult.cleanup()
anyBindResult.cleanup()
remoteResult.cleanup()
expect(mockServerClose).not.toHaveBeenCalled()
})
it("attach mode skips auth injection for invalid attach URLs", async () => {
// given
const signal = new AbortController().signal
const attachUrl = "not-a-url"
// when
const result = await createServerConnection({ attach: attachUrl, signal })
// then
expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: attachUrl })
expect(mockInjectServerAuthIntoClient).not.toHaveBeenCalled()
result.cleanup()
expect(mockServerClose).not.toHaveBeenCalled()
})
it("attach mode returns client with no-op cleanup", async () => { it("attach mode returns client with no-op cleanup", async () => {
// given // given
const signal = new AbortController().signal const signal = new AbortController().signal
@@ -68,8 +122,6 @@ describe("createServerConnection", () => {
const result = await createServerConnection({ attach: attachUrl, signal }) const result = await createServerConnection({ attach: attachUrl, signal })
// then // then
expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: attachUrl })
expect(mockWithWorkingOpencodePath).not.toHaveBeenCalled()
expect(result.client).toBeDefined() expect(result.client).toBeDefined()
expect(result.cleanup).toBeDefined() expect(result.cleanup).toBeDefined()
result.cleanup() result.cleanup()
+18
View File
@@ -1,9 +1,21 @@
import { createOpencode, createOpencodeClient } from "@opencode-ai/sdk" import { createOpencode, createOpencodeClient } from "@opencode-ai/sdk"
import pc from "picocolors" import pc from "picocolors"
import type { ServerConnection } from "./types" import type { ServerConnection } from "./types"
import { injectServerAuthIntoClient } from "../../shared/opencode-server-auth"
import { getAvailableServerPort, isPortAvailable, DEFAULT_SERVER_PORT } from "../../shared/port-utils" import { getAvailableServerPort, isPortAvailable, DEFAULT_SERVER_PORT } from "../../shared/port-utils"
import { withWorkingOpencodePath } from "./opencode-binary-resolver" import { withWorkingOpencodePath } from "./opencode-binary-resolver"
const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1", "[::1]", "0.0.0.0"])
function isLoopbackAttachUrl(url: string): boolean {
try {
const parsed = new URL(url)
return LOOPBACK_HOSTS.has(parsed.hostname)
} catch {
return false
}
}
function isPortStartFailure(error: unknown, port: number): boolean { function isPortStartFailure(error: unknown, port: number): boolean {
if (!(error instanceof Error)) { if (!(error instanceof Error)) {
return false return false
@@ -40,6 +52,9 @@ export async function createServerConnection(options: {
if (attach !== undefined) { if (attach !== undefined) {
console.log(pc.dim("Attaching to existing server at"), pc.cyan(attach)) console.log(pc.dim("Attaching to existing server at"), pc.cyan(attach))
const client = createOpencodeClient({ baseUrl: attach }) const client = createOpencodeClient({ baseUrl: attach })
if (isLoopbackAttachUrl(attach)) {
injectServerAuthIntoClient(client)
}
return { client, cleanup: () => {} } return { client, cleanup: () => {} }
} }
@@ -66,12 +81,14 @@ export async function createServerConnection(options: {
console.log(pc.dim("Port"), pc.cyan(port.toString()), pc.dim("became occupied, attaching to existing server")) console.log(pc.dim("Port"), pc.cyan(port.toString()), pc.dim("became occupied, attaching to existing server"))
const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` }) const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` })
injectServerAuthIntoClient(client)
return { client, cleanup: () => {} } return { client, cleanup: () => {} }
} }
} }
console.log(pc.dim("Port"), pc.cyan(port.toString()), pc.dim("is occupied, attaching to existing server")) console.log(pc.dim("Port"), pc.cyan(port.toString()), pc.dim("is occupied, attaching to existing server"))
const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` }) const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` })
injectServerAuthIntoClient(client)
return { client, cleanup: () => {} } return { client, cleanup: () => {} }
} }
@@ -93,6 +110,7 @@ export async function createServerConnection(options: {
console.log(pc.dim("Port range exhausted, attaching to existing server on"), pc.cyan(DEFAULT_SERVER_PORT.toString())) console.log(pc.dim("Port range exhausted, attaching to existing server on"), pc.cyan(DEFAULT_SERVER_PORT.toString()))
const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${DEFAULT_SERVER_PORT}` }) const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${DEFAULT_SERVER_PORT}` })
injectServerAuthIntoClient(client)
return { client, cleanup: () => {} } return { client, cleanup: () => {} }
} }
+1 -1
View File
@@ -74,7 +74,7 @@ export async function promptInstallConfig(detected: DetectedConfig): Promise<Ins
message: "Do you have access to OpenCode Zen (opencode/ models)?", message: "Do you have access to OpenCode Zen (opencode/ models)?",
options: [ options: [
{ value: "no", label: "No", hint: "Will use other configured providers" }, { value: "no", label: "No", hint: "Will use other configured providers" },
{ value: "yes", label: "Yes", hint: "opencode/claude-opus-4-6, opencode/gpt-5.4, etc." }, { value: "yes", label: "Yes", hint: "opencode/claude-opus-4-7, opencode/gpt-5.4, etc." },
], ],
initialValue: initial.opencodeZen, initialValue: initial.opencodeZen,
}) })
+1 -1
View File
@@ -1,6 +1,6 @@
# src/config/ — Zod v4 Schema System # src/config/ — Zod v4 Schema System
**Generated:** 2026-04-11 **Generated:** 2026-04-18
## OVERVIEW ## OVERVIEW
-24
View File
@@ -27,30 +27,6 @@ describe("BackgroundTaskConfigSchema", () => {
}) })
}) })
describe("maxDescendants", () => {
describe("#given valid maxDescendants (50)", () => {
test("#when parsed #then returns correct value", () => {
const result = BackgroundTaskConfigSchema.parse({ maxDescendants: 50 })
expect(result.maxDescendants).toBe(50)
})
})
describe("#given maxDescendants below minimum (0)", () => {
test("#when parsed #then throws ZodError", () => {
let thrownError: unknown
try {
BackgroundTaskConfigSchema.parse({ maxDescendants: 0 })
} catch (error) {
thrownError = error
}
expect(thrownError).toBeInstanceOf(ZodError)
})
})
})
describe("syncPollTimeoutMs", () => { describe("syncPollTimeoutMs", () => {
describe("#given valid syncPollTimeoutMs (120000)", () => { describe("#given valid syncPollTimeoutMs (120000)", () => {
test("#when parsed #then returns correct value", () => { test("#when parsed #then returns correct value", () => {

Some files were not shown because too many files have changed in this diff Show More