Skip to content

Commit f5ea6c3

Browse files
committed
refactor(ai/repl): extract opencode profiles to separate module
- Move profile definitions to dedicated profiles.nix module - Add activation hook for profile symlink management - Support 9 profiles: claude, codex, codexglm, gemini, agy, agyclaude, ghcp, glm, openrouter, zen - Generate oh-my-opencode.jsonc configs per profile - Add ocx CLI tool for profile switching
1 parent 80f00f2 commit f5ea6c3

File tree

2 files changed

+214
-3
lines changed

2 files changed

+214
-3
lines changed

home/ai/repl/opencode/default.nix

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ in {
1010

1111
home.packages = mkIf config.programs.opencode.enable (lib.attrsets.attrValues {
1212
inherit (pkgs.ai) ccusage-opencode;
13-
ocx = pkgs.writeShellScriptBin "ocx" ''
14-
exec ${pkgs.pnpm}/bin/pnpm dlx ocx "$@"
15-
'';
1613
});
1714

1815
programs.opencode = let

home/ai/repl/opencode/profiles.nix

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
{
2+
lib,
3+
config,
4+
pkgs,
5+
...
6+
}: let
7+
inherit (lib) mkIf;
8+
cfg = config.programs.opencode;
9+
10+
## Base agents used across all profiles
11+
agentNames = [
12+
"Sisyphus"
13+
"Sisyphus-Junior"
14+
"Planner-Sisyphus"
15+
"oracle"
16+
"frontend-ui-ux-engineer"
17+
"document-writer"
18+
"multimodal-looker"
19+
"explore"
20+
"librarian"
21+
];
22+
23+
## Agent role -> model mapping per profile
24+
profiles = {
25+
## Pure Claude via Anthropic API
26+
claude = {
27+
Sisyphus = "anthropic/claude-opus-4-5";
28+
Sisyphus-Junior = "anthropic/claude-sonnet-4-5";
29+
Planner-Sisyphus = "anthropic/claude-sonnet-4-5";
30+
oracle = "anthropic/claude-opus-4-5";
31+
frontend-ui-ux-engineer = "anthropic/claude-sonnet-4-5";
32+
document-writer = "anthropic/claude-haiku-4-5";
33+
multimodal-looker = "anthropic/claude-sonnet-4-5";
34+
explore = "anthropic/claude-sonnet-4-5";
35+
librarian = "anthropic/claude-haiku-4-5";
36+
};
37+
38+
## OpenAI Codex models
39+
codex = {
40+
Sisyphus = "openai/gpt-5.1-codex-max";
41+
Sisyphus-Junior = "openai/gpt-5.1-codex-max";
42+
Planner-Sisyphus = "openai/gpt-5.1-codex-max";
43+
oracle = "openai/gpt-5.1-codex-max-high";
44+
frontend-ui-ux-engineer = "openai/gpt-5.1-codex-max";
45+
document-writer = "openai/gpt-5.1-codex-mini-high";
46+
multimodal-looker = "openai/gpt-5.1-codex-max";
47+
explore = "openai/gpt-5.1-codex-max";
48+
librarian = "openai/gpt-5.1-codex-mini-high";
49+
};
50+
51+
## Codex + GLM hybrid
52+
codexglm = {
53+
Sisyphus = "openai/gpt-5.1-codex-max";
54+
Sisyphus-Junior = "zai-coding-plan/glm-4.7";
55+
Planner-Sisyphus = "zai-coding-plan/glm-4.7";
56+
oracle = "openai/gpt-5.1-codex-max-high";
57+
frontend-ui-ux-engineer = "zai-coding-plan/glm-4.7";
58+
document-writer = "zai-coding-plan/glm-4.7";
59+
multimodal-looker = "openai/gpt-5.1-codex-max";
60+
explore = "zai-coding-plan/glm-4.7";
61+
librarian = "openai/gpt-5.1-codex-mini-high";
62+
};
63+
64+
## Google Gemini models
65+
gemini = {
66+
Sisyphus = "google/gemini-3-pro-preview";
67+
Sisyphus-Junior = "google/gemini-3-flash-preview";
68+
Planner-Sisyphus = "google/gemini-3-flash-preview";
69+
oracle = "google/gemini-3-pro-preview";
70+
frontend-ui-ux-engineer = "google/gemini-3-flash-preview";
71+
document-writer = "google/gemini-3-flash-preview";
72+
multimodal-looker = "google/gemini-3-flash-preview";
73+
explore = "google/gemini-3-flash-preview";
74+
librarian = "google/gemini-3-flash-preview";
75+
};
76+
77+
## Antigravity models (Google routed Claude/Gemini)
78+
agy = {
79+
Sisyphus = "google/antigravity-claude-opus-4-5-thinking";
80+
Sisyphus-Junior = "google/antigravity-claude-sonnet-4-5-thinking";
81+
Planner-Sisyphus = "google/antigravity-claude-sonnet-4-5-thinking";
82+
oracle = "google/antigravity-claude-opus-4-5-thinking";
83+
frontend-ui-ux-engineer = "google/antigravity-gemini-3-pro";
84+
document-writer = "google/antigravity-gemini-3-flash";
85+
multimodal-looker = "google/antigravity-gemini-3-pro";
86+
explore = "google/antigravity-claude-sonnet-4-5-thinking";
87+
librarian = "google/antigravity-gemini-3-flash";
88+
};
89+
90+
## Antigravity + native Claude hybrid
91+
agyclaude = {
92+
Sisyphus = "google/antigravity-claude-opus-4-5-thinking";
93+
Sisyphus-Junior = "anthropic/claude-sonnet-4-5";
94+
Planner-Sisyphus = "anthropic/claude-sonnet-4-5";
95+
oracle = "google/antigravity-claude-opus-4-5-thinking";
96+
frontend-ui-ux-engineer = "anthropic/claude-sonnet-4-5";
97+
document-writer = "anthropic/claude-haiku-4-5";
98+
multimodal-looker = "google/antigravity-gemini-3-pro";
99+
explore = "anthropic/claude-sonnet-4-5";
100+
librarian = "anthropic/claude-haiku-4-5";
101+
};
102+
103+
## GitHub Copilot models
104+
ghcp = {
105+
Sisyphus = "github-copilot/claude-opus-4.5";
106+
Sisyphus-Junior = "github-copilot/claude-sonnet-4.5";
107+
Planner-Sisyphus = "github-copilot/claude-sonnet-4.5";
108+
oracle = "github-copilot/claude-opus-4.5";
109+
frontend-ui-ux-engineer = "github-copilot/claude-sonnet-4.5";
110+
document-writer = "github-copilot/claude-haiku-4.5";
111+
multimodal-looker = "github-copilot/claude-sonnet-4.5";
112+
explore = "github-copilot/claude-sonnet-4.5";
113+
librarian = "github-copilot/claude-haiku-4.5";
114+
};
115+
116+
## Pure GLM models
117+
glm = {
118+
Sisyphus = "zai-coding-plan/glm-4.7";
119+
Sisyphus-Junior = "zai-coding-plan/glm-4.7";
120+
Planner-Sisyphus = "zai-coding-plan/glm-4.7";
121+
oracle = "zai-coding-plan/glm-4.7";
122+
frontend-ui-ux-engineer = "zai-coding-plan/glm-4.7";
123+
document-writer = "zai-coding-plan/glm-4.7";
124+
multimodal-looker = "zai-coding-plan/glm-4.7";
125+
explore = "zai-coding-plan/glm-4.7";
126+
librarian = "zai-coding-plan/glm-4.7";
127+
};
128+
129+
## OpenRouter free models
130+
openrouter = {
131+
Sisyphus = "openrouter/moonshotai/kimi-k2:free";
132+
Sisyphus-Junior = "openrouter/moonshotai/kimi-k2:free";
133+
Planner-Sisyphus = "openrouter/moonshotai/kimi-k2:free";
134+
oracle = "openrouter/moonshotai/kimi-k2:free";
135+
frontend-ui-ux-engineer = "openrouter/moonshotai/kimi-k2:free";
136+
document-writer = "openrouter/moonshotai/kimi-k2:free";
137+
multimodal-looker = "openrouter/moonshotai/kimi-k2:free";
138+
explore = "openrouter/moonshotai/kimi-k2:free";
139+
librarian = "openrouter/moonshotai/kimi-k2:free";
140+
};
141+
142+
## Zen profile (OpenCode free models)
143+
zen = {
144+
Sisyphus = "opencode/big-pickle";
145+
Sisyphus-Junior = "opencode/glm-4.7-free";
146+
Planner-Sisyphus = "opencode/big-pickle";
147+
oracle = "opencode/big-pickle";
148+
frontend-ui-ux-engineer = "opencode/minimax-m2.1-free";
149+
document-writer = "opencode/glm-4.7-free";
150+
multimodal-looker = "opencode/minimax-m2.1-free";
151+
explore = "opencode/glm-4.7-free";
152+
librarian = "opencode/glm-4.7-free";
153+
};
154+
};
155+
156+
## oh-my-opencode base config (shared across profiles)
157+
ohMyOpencodeBase = {
158+
"$schema" = "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json";
159+
google_auth = false; ## Using Antigravity auth instead
160+
disabled_hooks = ["session-notification"];
161+
ralph_loop = {
162+
enabled = false;
163+
};
164+
};
165+
166+
## ghost.jsonc base config
167+
ghostConfig = {
168+
registries = {};
169+
componentPath = ".opencode";
170+
};
171+
172+
## Generate oh-my-opencode.jsonc for a profile
173+
mkOhMyOpencodeConfig = _profileName: agentModels:
174+
ohMyOpencodeBase
175+
// {
176+
agents = lib.genAttrs agentNames (agent: {
177+
model = agentModels.${agent};
178+
});
179+
};
180+
181+
## Generate profile directory contents
182+
mkProfileFiles = profileName: agentModels: let
183+
ohMyConfig = mkOhMyOpencodeConfig profileName agentModels;
184+
in {
185+
"opencode/profiles/${profileName}/oh-my-opencode.jsonc" = {
186+
inherit (cfg) enable;
187+
text = builtins.toJSON ohMyConfig;
188+
};
189+
"opencode/profiles/${profileName}/ghost.jsonc" = {
190+
inherit (cfg) enable;
191+
text = builtins.toJSON ghostConfig;
192+
};
193+
};
194+
195+
## Generate all profile files
196+
allProfileFiles =
197+
lib.foldl' (acc: profileName:
198+
acc // (mkProfileFiles profileName profiles.${profileName})) {} (lib.attrNames profiles);
199+
in {
200+
## Symlink oh-my-opencode.jsonc to current profile (managed by ocx)
201+
home.activation.opencodeProfileSymlink = mkIf config.programs.opencode.enable (
202+
lib.hm.dag.entryAfter ["writeBoundary"] ''
203+
$DRY_RUN_CMD ln -sfn "profiles/current/oh-my-opencode.jsonc" \
204+
"''${XDG_CONFIG_HOME:-$HOME/.config}/opencode/oh-my-opencode.jsonc"
205+
''
206+
);
207+
## Profile switching is handled by ocx (pnpm dlx ocx)
208+
xdg.configFile = mkIf cfg.enable allProfileFiles;
209+
home.packages = lib.mkIf cfg.enable (lib.attrsets.attrValues {
210+
ocx = pkgs.writeShellScriptBin "ocx" ''
211+
exec ${pkgs.pnpm}/bin/pnpm dlx ocx "$@"
212+
'';
213+
});
214+
}

0 commit comments

Comments
 (0)