@route_33/opencode 0.4.6 → 0.4.7-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -95
- package/dist/cli/production-smoke/production-smoke.js +1649 -0
- package/dist/index.js +3577 -1266
- package/dist/tui-entry/index.js +6989 -0
- package/dist/v2-entry/index.js +4203 -0
- package/package.json +38 -42
- package/LICENSE +0 -21
- package/dist/index.d.ts +0 -23
- package/dist/tui/index.d.ts +0 -5
- package/dist/tui/index.js +0 -542
- package/docs/gateway-limits-variants-broadcast.md +0 -146
- package/docs/gateway-pricing-proposal.md +0 -96
- package/docs/getting-started.html +0 -570
|
@@ -1,570 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>The route33 opencode Setup — Complete Guide</title>
|
|
7
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
|
-
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
|
10
|
-
<style>
|
|
11
|
-
:root {
|
|
12
|
-
--paper: #f5f1e8;
|
|
13
|
-
--paper-raised: #fdfbf6;
|
|
14
|
-
--ink: #1a1a18;
|
|
15
|
-
--ink-soft: #4a4a44;
|
|
16
|
-
--ink-faint: #8a8a80;
|
|
17
|
-
--accent: #f0b90b;
|
|
18
|
-
--accent-soft: #f7d654;
|
|
19
|
-
--line: #d8d2c2;
|
|
20
|
-
--code-bg: #26241f;
|
|
21
|
-
--code-ink: #e8e4d8;
|
|
22
|
-
--ok: #2e7d4f;
|
|
23
|
-
--warn: #b45309;
|
|
24
|
-
}
|
|
25
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
26
|
-
html { scroll-behavior: smooth; }
|
|
27
|
-
body {
|
|
28
|
-
background: var(--paper);
|
|
29
|
-
color: var(--ink);
|
|
30
|
-
font-family: 'Inter', system-ui, sans-serif;
|
|
31
|
-
font-size: 16px;
|
|
32
|
-
line-height: 1.65;
|
|
33
|
-
-webkit-font-smoothing: antialiased;
|
|
34
|
-
}
|
|
35
|
-
.wrap { max-width: 820px; margin: 0 auto; padding: 0 24px 96px; }
|
|
36
|
-
|
|
37
|
-
header {
|
|
38
|
-
border-bottom: 3px solid var(--ink);
|
|
39
|
-
padding: 48px 0 32px;
|
|
40
|
-
margin-bottom: 40px;
|
|
41
|
-
}
|
|
42
|
-
.brand {
|
|
43
|
-
display: flex; align-items: center; gap: 12px;
|
|
44
|
-
font-family: 'JetBrains Mono', monospace;
|
|
45
|
-
font-size: 13px; font-weight: 600;
|
|
46
|
-
letter-spacing: 0.08em; text-transform: uppercase;
|
|
47
|
-
color: var(--ink-soft); margin-bottom: 20px;
|
|
48
|
-
}
|
|
49
|
-
.brand-mark {
|
|
50
|
-
width: 28px; height: 28px; border: 2.5px solid var(--ink);
|
|
51
|
-
border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
|
|
52
|
-
font-weight: 600; font-size: 14px; color: var(--ink);
|
|
53
|
-
border-bottom-color: var(--accent);
|
|
54
|
-
}
|
|
55
|
-
h1 {
|
|
56
|
-
font-size: clamp(30px, 5vw, 42px);
|
|
57
|
-
font-weight: 700; letter-spacing: -0.02em; line-height: 1.15;
|
|
58
|
-
}
|
|
59
|
-
h1 .hl { box-shadow: inset 0 -0.38em 0 var(--accent); }
|
|
60
|
-
.lede { margin-top: 14px; font-size: 18px; color: var(--ink-soft); max-width: 62ch; }
|
|
61
|
-
|
|
62
|
-
.toc {
|
|
63
|
-
background: var(--paper-raised);
|
|
64
|
-
border: 1px solid var(--line);
|
|
65
|
-
border-radius: 8px;
|
|
66
|
-
padding: 20px 24px;
|
|
67
|
-
margin: 32px 0 8px;
|
|
68
|
-
}
|
|
69
|
-
.toc-title {
|
|
70
|
-
font-family: 'JetBrains Mono', monospace;
|
|
71
|
-
font-size: 11.5px; font-weight: 600; letter-spacing: 0.08em;
|
|
72
|
-
text-transform: uppercase; color: var(--ink-faint); margin-bottom: 10px;
|
|
73
|
-
}
|
|
74
|
-
.toc ol { margin: 0 0 0 20px; }
|
|
75
|
-
.toc li { margin: 4px 0; font-size: 14.5px; }
|
|
76
|
-
|
|
77
|
-
section { margin-top: 56px; }
|
|
78
|
-
.step-head { display: flex; align-items: baseline; gap: 14px; margin-bottom: 6px; }
|
|
79
|
-
.step-num {
|
|
80
|
-
font-family: 'JetBrains Mono', monospace;
|
|
81
|
-
font-size: 13px; font-weight: 600;
|
|
82
|
-
background: var(--ink); color: var(--paper);
|
|
83
|
-
padding: 3px 10px; border-radius: 3px;
|
|
84
|
-
flex-shrink: 0; transform: translateY(-2px);
|
|
85
|
-
}
|
|
86
|
-
h2 { font-size: 24px; font-weight: 700; letter-spacing: -0.01em; }
|
|
87
|
-
h3 { font-size: 17px; font-weight: 600; margin-top: 28px; margin-bottom: 8px; }
|
|
88
|
-
p { margin: 12px 0; color: var(--ink-soft); }
|
|
89
|
-
p strong, li strong { color: var(--ink); }
|
|
90
|
-
ul, ol { margin: 12px 0 12px 22px; color: var(--ink-soft); }
|
|
91
|
-
li { margin: 6px 0; }
|
|
92
|
-
a { color: var(--ink); text-decoration-color: var(--accent); text-decoration-thickness: 2px; text-underline-offset: 2px; }
|
|
93
|
-
a:hover { background: var(--accent-soft); }
|
|
94
|
-
|
|
95
|
-
code {
|
|
96
|
-
font-family: 'JetBrains Mono', monospace;
|
|
97
|
-
font-size: 0.86em;
|
|
98
|
-
background: rgba(26,26,24,0.07);
|
|
99
|
-
padding: 2px 6px; border-radius: 4px;
|
|
100
|
-
}
|
|
101
|
-
pre {
|
|
102
|
-
background: var(--code-bg); color: var(--code-ink);
|
|
103
|
-
border-radius: 8px; padding: 18px 20px;
|
|
104
|
-
margin: 16px 0; overflow-x: auto;
|
|
105
|
-
font-family: 'JetBrains Mono', monospace;
|
|
106
|
-
font-size: 13.5px; line-height: 1.6;
|
|
107
|
-
border-left: 4px solid var(--accent);
|
|
108
|
-
}
|
|
109
|
-
pre code { background: none; padding: 0; font-size: inherit; }
|
|
110
|
-
pre .c { color: #8a8577; }
|
|
111
|
-
pre .p { color: var(--accent); }
|
|
112
|
-
|
|
113
|
-
.note, .warning, .tip {
|
|
114
|
-
border-radius: 8px; padding: 14px 18px; margin: 18px 0;
|
|
115
|
-
font-size: 14.5px; line-height: 1.55;
|
|
116
|
-
}
|
|
117
|
-
.note { background: var(--paper-raised); border: 1px solid var(--line); border-left: 4px solid var(--ink); }
|
|
118
|
-
.warning { background: #fdf3e0; border: 1px solid #ecd9ae; border-left: 4px solid var(--warn); }
|
|
119
|
-
.tip { background: #eef5ef; border: 1px solid #cfe3d3; border-left: 4px solid var(--ok); }
|
|
120
|
-
.note .tag, .warning .tag, .tip .tag {
|
|
121
|
-
display: block; font-family: 'JetBrains Mono', monospace;
|
|
122
|
-
font-size: 11px; font-weight: 600; letter-spacing: 0.08em;
|
|
123
|
-
text-transform: uppercase; margin-bottom: 4px; color: var(--ink);
|
|
124
|
-
}
|
|
125
|
-
.note p, .warning p, .tip p { margin: 4px 0; }
|
|
126
|
-
|
|
127
|
-
table { width: 100%; border-collapse: collapse; margin: 18px 0; font-size: 14px; }
|
|
128
|
-
th {
|
|
129
|
-
text-align: left; font-family: 'JetBrains Mono', monospace;
|
|
130
|
-
font-size: 11.5px; letter-spacing: 0.06em; text-transform: uppercase;
|
|
131
|
-
color: var(--ink-soft); border-bottom: 2px solid var(--ink);
|
|
132
|
-
padding: 8px 12px 8px 0;
|
|
133
|
-
}
|
|
134
|
-
td { padding: 9px 12px 9px 0; border-bottom: 1px solid var(--line); vertical-align: top; color: var(--ink-soft); }
|
|
135
|
-
td code { font-size: 12.5px; }
|
|
136
|
-
|
|
137
|
-
.checklist { list-style: none; margin-left: 0; }
|
|
138
|
-
.checklist li { padding-left: 30px; position: relative; margin: 10px 0; }
|
|
139
|
-
.checklist li::before {
|
|
140
|
-
content: ""; position: absolute; left: 0; top: 3px;
|
|
141
|
-
width: 16px; height: 16px;
|
|
142
|
-
border: 2px solid var(--ink); border-radius: 4px;
|
|
143
|
-
background: var(--paper-raised);
|
|
144
|
-
}
|
|
145
|
-
.checklist li::after {
|
|
146
|
-
content: ""; position: absolute; left: 4.5px; top: 6px;
|
|
147
|
-
width: 5px; height: 9px;
|
|
148
|
-
border: solid var(--ok); border-width: 0 2.5px 2.5px 0;
|
|
149
|
-
transform: rotate(42deg);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
.tree {
|
|
153
|
-
background: var(--code-bg); color: var(--code-ink);
|
|
154
|
-
border-radius: 8px; padding: 18px 20px;
|
|
155
|
-
margin: 16px 0; overflow-x: auto;
|
|
156
|
-
font-family: 'JetBrains Mono', monospace;
|
|
157
|
-
font-size: 13px; line-height: 1.7;
|
|
158
|
-
border-left: 4px solid var(--accent);
|
|
159
|
-
white-space: pre;
|
|
160
|
-
}
|
|
161
|
-
.tree .dir { color: var(--accent); font-weight: 600; }
|
|
162
|
-
.tree .cm { color: #8a8577; }
|
|
163
|
-
|
|
164
|
-
footer {
|
|
165
|
-
margin-top: 80px; padding-top: 24px;
|
|
166
|
-
border-top: 1px solid var(--line);
|
|
167
|
-
font-family: 'JetBrains Mono', monospace;
|
|
168
|
-
font-size: 12px; color: var(--ink-faint);
|
|
169
|
-
display: flex; justify-content: space-between; flex-wrap: wrap; gap: 8px;
|
|
170
|
-
}
|
|
171
|
-
</style>
|
|
172
|
-
</head>
|
|
173
|
-
<body>
|
|
174
|
-
<div class="wrap">
|
|
175
|
-
<header>
|
|
176
|
-
<div class="brand"><span class="brand-mark">R</span> route33.ai × opencode</div>
|
|
177
|
-
<h1>The route33 opencode setup, <span class="hl">end to end</span></h1>
|
|
178
|
-
<p class="lede">Everything you need for a fully-equipped opencode harness on the route33.ai gateway: the terminal, the provider plugin, the oh-my-openagent orchestration layer, codebase intelligence, and how to shape your own agents. Roughly fifteen minutes, soup to nuts.</p>
|
|
179
|
-
</header>
|
|
180
|
-
|
|
181
|
-
<nav class="toc">
|
|
182
|
-
<div class="toc-title">In this guide</div>
|
|
183
|
-
<ol>
|
|
184
|
-
<li><a href="#stack">The moving parts</a></li>
|
|
185
|
-
<li><a href="#wezterm">WezTerm — the terminal</a></li>
|
|
186
|
-
<li><a href="#opencode-install">opencode itself</a></li>
|
|
187
|
-
<li><a href="#plugin">@route_33/opencode — the provider plugin</a></li>
|
|
188
|
-
<li><a href="#auth">Connecting your API key</a></li>
|
|
189
|
-
<li><a href="#omoa">oh-my-openagent — the orchestration layer</a></li>
|
|
190
|
-
<li><a href="#codebase-mcp">codebase-memory-mcp — codebase intelligence</a></li>
|
|
191
|
-
<li><a href="#dot-opencode">The .opencode/ directory, explained</a></li>
|
|
192
|
-
<li><a href="#agents">Configuring your own agents</a></li>
|
|
193
|
-
<li><a href="#verify">Verifying the whole stack</a></li>
|
|
194
|
-
<li><a href="#reference">Reference: env vars & troubleshooting</a></li>
|
|
195
|
-
</ol>
|
|
196
|
-
</nav>
|
|
197
|
-
|
|
198
|
-
<!-- ============ 1. THE STACK ============ -->
|
|
199
|
-
<section id="stack">
|
|
200
|
-
<div class="step-head"><span class="step-num">1</span><h2>The moving parts</h2></div>
|
|
201
|
-
<p>Five pieces of software cooperate in this setup. Knowing which layer owns what saves you from debugging the wrong one later:</p>
|
|
202
|
-
<table>
|
|
203
|
-
<tr><th>Layer</th><th>Component</th><th>What it owns</th></tr>
|
|
204
|
-
<tr><td><strong>Terminal</strong></td><td>WezTerm</td><td>Renders the TUI. GPU-accelerated, multiplexed panes, configured in Lua.</td></tr>
|
|
205
|
-
<tr><td><strong>Agent runtime</strong></td><td>opencode</td><td>The TUI + server. Loads plugins, MCP servers, agents, commands.</td></tr>
|
|
206
|
-
<tr><td><strong>Provider</strong></td><td>@route_33/opencode</td><td>Registers the <code>route_33</code> provider: key-scoped model discovery, cost/limit metadata, auth, key-setup wizard.</td></tr>
|
|
207
|
-
<tr><td><strong>Orchestration</strong></td><td>oh-my-openagent</td><td>The agent roster (Sisyphus, Oracle, explore, …), delegation categories, background tasks, fallback strategy, CodeGraph.</td></tr>
|
|
208
|
-
<tr><td><strong>Code intelligence</strong></td><td>codebase-memory-mcp</td><td>A knowledge graph of your repo (callers, traces, architecture) over MCP. Optional — see the note in its section.</td></tr>
|
|
209
|
-
</table>
|
|
210
|
-
</section>
|
|
211
|
-
|
|
212
|
-
<!-- ============ 2. WEZTERM ============ -->
|
|
213
|
-
<section id="wezterm">
|
|
214
|
-
<div class="step-head"><span class="step-num">2</span><h2>WezTerm — the terminal</h2></div>
|
|
215
|
-
<p>opencode is a full-screen TUI. Any modern terminal works, but WezTerm is the recommended one: GPU-accelerated rendering, native panes and tabs (handy when oh-my-openagent fans out background agents), and a Lua config file that lives happily in version control.</p>
|
|
216
|
-
|
|
217
|
-
<h3>Install (macOS)</h3>
|
|
218
|
-
<pre><code><span class="p">$</span> brew install --cask wezterm</code></pre>
|
|
219
|
-
<p>Linux and Windows packages are on <a href="https://wezterm.org/installation.html">wezterm.org</a>.</p>
|
|
220
|
-
|
|
221
|
-
<h3>Minimal config</h3>
|
|
222
|
-
<p>WezTerm reads <code>~/.wezterm.lua</code> (or <code>~/.config/wezterm/wezterm.lua</code>). A sensible starting point for opencode work:</p>
|
|
223
|
-
<pre><code><span class="c">-- ~/.wezterm.lua</span>
|
|
224
|
-
local wezterm = require 'wezterm'
|
|
225
|
-
local config = wezterm.config_builder()
|
|
226
|
-
|
|
227
|
-
config.font = wezterm.font 'JetBrains Mono'
|
|
228
|
-
config.font_size = 13.0
|
|
229
|
-
config.color_scheme = 'Builtin Solarized Dark'
|
|
230
|
-
config.window_padding = { left = 12, right = 12, top = 12, bottom = 12 }
|
|
231
|
-
|
|
232
|
-
<span class="c">-- Panes for watching background agents alongside your main session</span>
|
|
233
|
-
config.keys = {
|
|
234
|
-
{ key = 'd', mods = 'CMD', action = wezterm.action.SplitHorizontal },
|
|
235
|
-
{ key = 'd', mods = 'CMD|SHIFT', action = wezterm.action.SplitVertical },
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return config</code></pre>
|
|
239
|
-
|
|
240
|
-
<div class="tip">
|
|
241
|
-
<span class="tag">Why panes matter here</span>
|
|
242
|
-
<p>oh-my-openagent can render background agents into visible terminal panes (<code>tmux: enabled</code> in its config). With WezTerm splits you get the same visibility natively — main session on the left, a log tail or second session on the right.</p>
|
|
243
|
-
</div>
|
|
244
|
-
</section>
|
|
245
|
-
|
|
246
|
-
<!-- ============ 3. OPENCODE ============ -->
|
|
247
|
-
<section id="opencode-install">
|
|
248
|
-
<div class="step-head"><span class="step-num">3</span><h2>opencode itself</h2></div>
|
|
249
|
-
<p>You need opencode <strong>1.17.0 or newer</strong> (the plugin peer-depends on it). Installers:</p>
|
|
250
|
-
<pre><code><span class="c"># macOS / Linux — install script</span>
|
|
251
|
-
<span class="p">$</span> curl -fsSL https://opencode.ai/install | bash
|
|
252
|
-
|
|
253
|
-
<span class="c"># or Homebrew</span>
|
|
254
|
-
<span class="p">$</span> brew install sst/tap/opencode
|
|
255
|
-
|
|
256
|
-
<span class="c"># or npm</span>
|
|
257
|
-
<span class="p">$</span> npm install -g opencode-ai</code></pre>
|
|
258
|
-
<p>Check what you got:</p>
|
|
259
|
-
<pre><code><span class="p">$</span> opencode --version
|
|
260
|
-
1.17.20</code></pre>
|
|
261
|
-
</section>
|
|
262
|
-
<section id="plugin">
|
|
263
|
-
<div class="step-head"><span class="step-num">4</span><h2>@route_33/opencode — the provider plugin</h2></div>
|
|
264
|
-
<p>This is the piece that makes route33 models appear in opencode. It discovers the catalog live from the gateway, decorates models with cost/limit/capability metadata, and owns authentication.</p>
|
|
265
|
-
|
|
266
|
-
<h3>Install with the built-in installer</h3>
|
|
267
|
-
<pre><code><span class="p">$</span> opencode plugin @route_33/opencode</code></pre>
|
|
268
|
-
<p>Run it from your project directory to register the plugin in that project's <code>.opencode/</code>, or pass <code>--global</code> (or run it from your home directory) to register it in <code>~/.config/opencode/</code> for every project. Either way it patches two config files at the chosen level:</p>
|
|
269
|
-
<table>
|
|
270
|
-
<tr><th>File</th><th>What it registers</th></tr>
|
|
271
|
-
<tr><td><code>opencode.json(c)</code></td><td>The <strong>server plugin</strong> — model discovery, cost/limit enrichment, auth.</td></tr>
|
|
272
|
-
<tr><td><code>tui.json</code></td><td>The <strong>TUI plugin</strong> — the first-run key-setup wizard.</td></tr>
|
|
273
|
-
</table>
|
|
274
|
-
<p>Re-running with a new version needs <code>--force</code> to replace the existing pin.</p>
|
|
275
|
-
|
|
276
|
-
<div class="warning">
|
|
277
|
-
<span class="tag">"Package not found" outside the route33 repo?</span>
|
|
278
|
-
<p>The installer resolves the module name against npm — it works from any directory <em>as long as the package is published</em>. If your registry doesn't serve <code>@route_33/opencode</code> yet (or you're on a pre-release checkout), install from a local path instead. Two forms are known to work:</p>
|
|
279
|
-
<pre><code><span class="c">// opencode.json(c) — bare relative path, resolved against the config file's location</span>
|
|
280
|
-
{
|
|
281
|
-
"plugin": ["../packages/integrations/opencode-route33"]
|
|
282
|
-
}</code></pre>
|
|
283
|
-
<pre><code><span class="c">// or an absolute file:// URL (works everywhere, but is machine-bound)</span>
|
|
284
|
-
{
|
|
285
|
-
"plugin": ["file:///Users/you/route_33/packages/integrations/opencode-route33"]
|
|
286
|
-
}</code></pre>
|
|
287
|
-
<p>Avoid the <code>file:../relative</code> form — empirically (opencode 1.18.4) it fails to resolve. A local-path install covers the server plugin only; add the same entry to <code>tui.json</code> yourself if you want the key-setup wizard, and run <code>bun install && bun run build</code> in the package directory first so <code>dist/</code> exists.</p>
|
|
288
|
-
</div>
|
|
289
|
-
|
|
290
|
-
<h3>Prefer to do it by hand?</h3>
|
|
291
|
-
<pre><code><span class="c">// ~/.config/opencode/opencode.json</span>
|
|
292
|
-
{
|
|
293
|
-
"plugin": ["@route_33/opencode"]
|
|
294
|
-
}</code></pre>
|
|
295
|
-
<pre><code><span class="c">// ~/.config/opencode/tui.json</span>
|
|
296
|
-
{
|
|
297
|
-
"plugin": ["@route_33/opencode"]
|
|
298
|
-
}</code></pre>
|
|
299
|
-
|
|
300
|
-
<div class="note">
|
|
301
|
-
<span class="tag">Good to know</span>
|
|
302
|
-
<p>The plugin never writes to your config on its own. opencode has no TUI-plugin auto-discovery, so if you skip the <code>tui.json</code> entry the setup wizard simply never appears — the server plugin (the part that actually serves models) works regardless.</p>
|
|
303
|
-
</div>
|
|
304
|
-
|
|
305
|
-
<div class="tip">
|
|
306
|
-
<span class="tag">Working inside the route33 repo?</span>
|
|
307
|
-
<p>You're already done with this step. The repo's <code>.opencode/opencode.jsonc</code> declares <code>@route_33/opencode@latest</code> for you — skip ahead to <a href="#auth">the auth step</a>.</p>
|
|
308
|
-
</div>
|
|
309
|
-
</section>
|
|
310
|
-
|
|
311
|
-
<section id="auth">
|
|
312
|
-
<div class="step-head"><span class="step-num">5</span><h2>Connecting your API key</h2></div>
|
|
313
|
-
<p>Mint a key in the route33 dashboard under your organization's <em>API keys</em> section — one per project, since per-project keys are the metering boundary. Then pick whichever resolution path fits your workflow; the first one that resolves wins.</p>
|
|
314
|
-
|
|
315
|
-
<h3>Option A — environment variable (highest precedence)</h3>
|
|
316
|
-
<pre><code><span class="p">$</span> export ROUTE33_API_KEY=r33_your_key_here</code></pre>
|
|
317
|
-
<p>Good for CI, containers, and one-off shells.</p>
|
|
318
|
-
|
|
319
|
-
<h3>Option B — opencode's auth store</h3>
|
|
320
|
-
<pre><code><span class="p">$</span> opencode auth login</code></pre>
|
|
321
|
-
<p>Choose <code>route_33</code> from the provider list and paste your key.</p>
|
|
322
|
-
|
|
323
|
-
<h3>Option C — let the wizard handle it</h3>
|
|
324
|
-
<p>If neither of the above is set, the TUI wizard pops up on first launch and offers to save a key for you:</p>
|
|
325
|
-
<ul>
|
|
326
|
-
<li><strong>Inside a git workspace</strong> → saved per-project to <code><project>/.opencode/route33.key</code>. The file is written with mode <code>0600</code> and the plugin auto-adds it (plus <code>tui.json</code>) to <code>.opencode/.gitignore</code> so it never gets committed.</li>
|
|
327
|
-
<li><strong>Outside a git workspace</strong> → saved globally. A global key only applies <em>outside</em> git workspaces — inside one, the per-project key always wins.</li>
|
|
328
|
-
</ul>
|
|
329
|
-
|
|
330
|
-
<div class="note">
|
|
331
|
-
<span class="tag">Snoozing the wizard</span>
|
|
332
|
-
<p>Hitting "Skip" silences the prompt for 7 days — for that workspace only, or everywhere if you pick "Skip for all workspaces". To re-arm it sooner, remove the <code>project-key-prompt.dismissed-at*</code> entries from <code>~/.local/state/opencode/kv.json</code>. To disable the wizard permanently, set <code>ROUTE33_TUI_PROMPT=0</code>.</p>
|
|
333
|
-
</div>
|
|
334
|
-
|
|
335
|
-
<h3>Pointing at a non-production gateway (optional)</h3>
|
|
336
|
-
<p>Out of the box the plugin talks to <code>https://api.route33.ai/v1</code>. To develop against a local kind cluster:</p>
|
|
337
|
-
<pre><code><span class="c"># Example: your local kind cluster's API host</span>
|
|
338
|
-
<span class="p">$</span> export ROUTE33_BASE_URL=https://api-<hash>-<user>-<workspace>.route33.ai/v1</code></pre>
|
|
339
|
-
<p>In the route33 repo, that hostname is computed for you by <code>deploy/lib/workspace-env.sh</code> (the <code>R33_HOST_API</code> variable).</p>
|
|
340
|
-
</section>
|
|
341
|
-
<section id="omoa">
|
|
342
|
-
<div class="step-head"><span class="step-num">6</span><h2>oh-my-openagent — the orchestration layer</h2></div>
|
|
343
|
-
<p><strong>oh-my-openagent</strong> (OMOA) is the plugin that turns a single opencode session into an orchestrated agent harness. It ships the named agent roster you interact with — Sisyphus (the orchestrator), Oracle (deep reasoning), explore and librarian (parallel search), Metis and Momus (planning) — plus delegation categories, background tasks, runtime model fallback, and a built-in CodeGraph for code intelligence.</p>
|
|
344
|
-
|
|
345
|
-
<h3>Install</h3>
|
|
346
|
-
<p>Add it to the <code>plugin</code> array in both config files, alongside the route33 plugin:</p>
|
|
347
|
-
<pre><code><span class="c">// ~/.config/opencode/opencode.json</span>
|
|
348
|
-
{
|
|
349
|
-
"plugin": [
|
|
350
|
-
"oh-my-openagent@latest",
|
|
351
|
-
"@route_33/opencode@latest"
|
|
352
|
-
]
|
|
353
|
-
}</code></pre>
|
|
354
|
-
<pre><code><span class="c">// ~/.config/opencode/tui.json</span>
|
|
355
|
-
{
|
|
356
|
-
"plugin": ["oh-my-openagent@latest"]
|
|
357
|
-
}</code></pre>
|
|
358
|
-
|
|
359
|
-
<h3>Configure: oh-my-openagent.jsonc</h3>
|
|
360
|
-
<p>OMOA reads its own config file, <code>oh-my-openagent.jsonc</code>, from the same directory as your opencode config — global at <code>~/.config/opencode/</code>, per-project at <code><repo>/.opencode/</code>. This is where you bind models to agents and categories. The route33 repo ships a working example — the highlights:</p>
|
|
361
|
-
<pre><code><span class="c">// .opencode/oh-my-openagent.jsonc (abridged)</span>
|
|
362
|
-
{
|
|
363
|
-
<span class="c">// 429/5xx depletion failover, back to primary once quota resets</span>
|
|
364
|
-
"runtime_fallback": { "enabled": true, "notify_on_fallback": true },
|
|
365
|
-
|
|
366
|
-
<span class="c">// OMOA's built-in CodeGraph = the single code-intelligence source</span>
|
|
367
|
-
"codegraph": { "enabled": true, "telemetry": false },
|
|
368
|
-
|
|
369
|
-
<span class="c">// Fan-out limits for parallel background agents</span>
|
|
370
|
-
"background_task": {
|
|
371
|
-
"defaultConcurrency": 8,
|
|
372
|
-
"providerConcurrency": { "route_33": 10, "route_33/anthropic": 4 }
|
|
373
|
-
},
|
|
374
|
-
|
|
375
|
-
"agents": {
|
|
376
|
-
"sisyphus": { "model": "route_33/moonshotai/kimi-k3", "variant": "max" },
|
|
377
|
-
"oracle": { "model": "route_33/openai/gpt-5.6-sol", "variant": "high" },
|
|
378
|
-
"explore": { "model": "route_33/openai/gpt-5.6-luna" },
|
|
379
|
-
"librarian": { "model": "route_33/openai/gpt-5.6-luna" }
|
|
380
|
-
},
|
|
381
|
-
|
|
382
|
-
"categories": {
|
|
383
|
-
"visual-engineering": { "model": "route_33/openai/gpt-5.6-sol", "variant": "high" },
|
|
384
|
-
"deep": { "model": "route_33/openai/gpt-5.6-terra", "variant": "xhigh" },
|
|
385
|
-
"quick": { "model": "route_33/openai/gpt-5.6-luna" },
|
|
386
|
-
"writing": { "model": "route_33/moonshotai/kimi-k2.7-code" }
|
|
387
|
-
}
|
|
388
|
-
}</code></pre>
|
|
389
|
-
<p>The mental model: <strong><code>agents</code></strong> binds a model to a named persona, <strong><code>categories</code></strong> binds a model to a <em>kind of work</em> (visual, deep research, quick fixes, writing). When Sisyphus delegates, the category resolver picks the model from the category first, falling back to the agent default.</p>
|
|
390
|
-
|
|
391
|
-
<div class="note">
|
|
392
|
-
<span class="tag">Variants</span>
|
|
393
|
-
<p><code>"variant"</code> selects a reasoning tier the model advertises (e.g. kimi-k3's <code>max</code>, gpt-5.6's <code>high</code>/<code>xhigh</code>). Variants come from the gateway's broadcast — the route33 plugin passes them through verbatim, so OMOA variant names and gateway variant names are the same vocabulary.</p>
|
|
394
|
-
</div>
|
|
395
|
-
|
|
396
|
-
<div class="tip">
|
|
397
|
-
<span class="tag">Flavours</span>
|
|
398
|
-
<p>Keep alternate OMOA configs as <em>flavours</em> in <code>.opencode/omo-flavours/<name>.jsonc</code> (the route33 repo keeps <code>r33-kimi-k3.jsonc</code> there). Copy one over <code>oh-my-openagent.jsonc</code> to switch the whole model matrix in one move.</p>
|
|
399
|
-
</div>
|
|
400
|
-
</section>
|
|
401
|
-
|
|
402
|
-
<section id="codebase-mcp">
|
|
403
|
-
<div class="step-head"><span class="step-num">7</span><h2>codebase-memory-mcp — codebase intelligence</h2></div>
|
|
404
|
-
<p><strong>codebase-memory-mcp</strong> builds a persistent knowledge graph of your repository — functions, classes, call chains, architecture — and exposes it to opencode over MCP. Agents can then answer "who calls this?" or "trace this call chain" structurally instead of grepping.</p>
|
|
405
|
-
|
|
406
|
-
<h3>Install and register</h3>
|
|
407
|
-
<pre><code><span class="c"># Install the CLI + server (auto-detects opencode and offers to register itself)</span>
|
|
408
|
-
<span class="p">$</span> npm install -g codebase-memory-mcp
|
|
409
|
-
<span class="p">$</span> codebase-memory-mcp install</code></pre>
|
|
410
|
-
<p>Or register it manually in your opencode config:</p>
|
|
411
|
-
<pre><code><span class="c">// ~/.config/opencode/opencode.json</span>
|
|
412
|
-
{
|
|
413
|
-
"mcp": {
|
|
414
|
-
"codebase-memory-mcp": {
|
|
415
|
-
"type": "local",
|
|
416
|
-
"enabled": true,
|
|
417
|
-
"command": ["codebase-memory-mcp"]
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}</code></pre>
|
|
421
|
-
<p>Then index your repo once — agents do the rest via tools like <code>search_graph</code>, <code>trace_path</code>, <code>get_code_snippet</code>, and <code>get_architecture</code>:</p>
|
|
422
|
-
<pre><code><span class="p">$</span> codebase-memory-mcp cli index_repository '{"path": "."}'</code></pre>
|
|
423
|
-
<p>An optional graph-visualization UI runs on port 9749 (<code>codebase-memory-mcp --ui=true</code>).</p>
|
|
424
|
-
|
|
425
|
-
<div class="warning">
|
|
426
|
-
<span class="tag">Pick ONE code-intelligence source</span>
|
|
427
|
-
<p>OMOA ships its own built-in CodeGraph with a fresher watcher-based index. Running both means two indexes and agents torn between two tool vocabularies. The route33 repo's decision (2026-07-14): <strong>CodeGraph on, codebase-memory-mcp off</strong> — that's why <code>.opencode/opencode.jsonc</code> carries it under <code>"enabled": false</code> and the four <code>codebase-memory-*</code> skills sit in OMOA's <code>disabled_skills</code>. Flip the flag to <code>true</code> only if you've disabled CodeGraph.</p>
|
|
428
|
-
</div>
|
|
429
|
-
</section>
|
|
430
|
-
<section id="dot-opencode">
|
|
431
|
-
<div class="step-head"><span class="step-num">8</span><h2>The .opencode/ directory, explained</h2></div>
|
|
432
|
-
<p>opencode merges configuration from two roots. Everything in this guide lands in one of them:</p>
|
|
433
|
-
<table>
|
|
434
|
-
<tr><th>Root</th><th>Scope</th><th>Commit?</th></tr>
|
|
435
|
-
<tr><td><code>~/.config/opencode/</code></td><td>Global — every project on your machine</td><td>n/a (your dotfiles)</td></tr>
|
|
436
|
-
<tr><td><code><repo>/.opencode/</code></td><td>Project — wins over global inside that repo</td><td>Yes, mostly — see below</td></tr>
|
|
437
|
-
</table>
|
|
438
|
-
|
|
439
|
-
<p>A fully-equipped project directory (this is the route33 repo's real layout):</p>
|
|
440
|
-
<div class="tree"><span class="dir">.opencode/</span>
|
|
441
|
-
|-- <span class="dir">opencode.jsonc</span> <span class="cm"># plugins + MCP servers for THIS project</span>
|
|
442
|
-
|-- <span class="dir">oh-my-openagent.jsonc</span> <span class="cm"># OMOA model matrix: agents + categories</span>
|
|
443
|
-
|-- <span class="dir">agents/</span> <span class="cm"># custom agent definitions (*.md with frontmatter)</span>
|
|
444
|
-
| `-- 2po-commit.md
|
|
445
|
-
|-- <span class="dir">commands/</span> <span class="cm"># custom slash commands (*.md)</span>
|
|
446
|
-
| `-- 2po-commit.md
|
|
447
|
-
|-- <span class="dir">omo-flavours/</span> <span class="cm"># alternate OMOA configs to swap in</span>
|
|
448
|
-
| `-- r33-kimi-k3.jsonc
|
|
449
|
-
|-- <span class="dir">route33.key</span> <span class="cm"># per-project API key (GIT-IGNORED, mode 0600)</span>
|
|
450
|
-
|-- <span class="dir">tui.json</span> <span class="cm"># TUI plugin registration (GIT-IGNORED)</span>
|
|
451
|
-
`-- <span class="dir">.gitignore</span> <span class="cm"># guards the two files above + node_modules</span></div>
|
|
452
|
-
|
|
453
|
-
<h3>What each file is for</h3>
|
|
454
|
-
<table>
|
|
455
|
-
<tr><th>File</th><th>Purpose</th></tr>
|
|
456
|
-
<tr><td><code>opencode.jsonc</code></td><td>Project-level opencode config: the <code>plugin</code> array, <code>mcp</code> servers, provider overrides. JSONC — comments allowed.</td></tr>
|
|
457
|
-
<tr><td><code>tui.json</code></td><td>TUI plugin registration. Written by <code>opencode plugin</code> or the wizard; git-ignored because it can hold machine-local state.</td></tr>
|
|
458
|
-
<tr><td><code>oh-my-openagent.jsonc</code></td><td>OMOA's own config — the agent/category model matrix from <a href="#omoa">section 6</a>.</td></tr>
|
|
459
|
-
<tr><td><code>agents/*.md</code></td><td>Custom agents (next section). Markdown body = system prompt, YAML frontmatter = config.</td></tr>
|
|
460
|
-
<tr><td><code>commands/*.md</code></td><td>Custom slash commands — a prompt template invoked as <code>/name</code> in the TUI.</td></tr>
|
|
461
|
-
<tr><td><code>route33.key</code></td><td>The per-project API key written by the wizard. Never committed — the plugin maintains <code>.opencode/.gitignore</code> for you.</td></tr>
|
|
462
|
-
<tr><td><code>AGENTS.md</code> (repo root)</td><td>Not inside <code>.opencode/</code>, but part of the same story: the project knowledge base every agent reads. The route33 repo's root <code>AGENTS.md</code> is the canonical example.</td></tr>
|
|
463
|
-
</table>
|
|
464
|
-
|
|
465
|
-
<div class="note">
|
|
466
|
-
<span class="tag">Global vs project, in practice</span>
|
|
467
|
-
<p>Keep your <em>personal</em> setup global — plugins, the auth-store key, your default OMOA matrix in <code>~/.config/opencode/</code>. Keep <em>team-shared</em> setup in the repo — the project's plugin pins, the OMOA matrix tuned to this codebase, custom agents and commands everyone should have. Project config wins on conflict, so a repo can tighten a model choice without touching your other projects.</p>
|
|
468
|
-
</div>
|
|
469
|
-
</section>
|
|
470
|
-
<section id="agents">
|
|
471
|
-
<div class="step-head"><span class="step-num">9</span><h2>Configuring your own agents</h2></div>
|
|
472
|
-
<p>Custom agents are Markdown files with YAML frontmatter, dropped in <code>.opencode/agents/</code> (project) or <code>~/.config/opencode/agents/</code> (global). The filename becomes the agent name; the frontmatter configures it; the Markdown body is the system prompt.</p>
|
|
473
|
-
|
|
474
|
-
<h3>Anatomy of an agent file</h3>
|
|
475
|
-
<p>This is a trimmed version of the route33 repo's real <code>.opencode/agents/2po-commit.md</code> — a locked-down commit agent that can run git but can't edit files:</p>
|
|
476
|
-
<pre><code>---
|
|
477
|
-
description: Create git commits for current changes
|
|
478
|
-
mode: primary
|
|
479
|
-
model: route_33/openai/gpt-5.6-luna
|
|
480
|
-
hidden: true
|
|
481
|
-
permission:
|
|
482
|
-
edit: deny
|
|
483
|
-
bash:
|
|
484
|
-
"*": deny
|
|
485
|
-
"git status*": allow
|
|
486
|
-
"git diff*": allow
|
|
487
|
-
"git add*": allow
|
|
488
|
-
"git commit*": allow
|
|
489
|
-
webfetch: deny
|
|
490
|
-
---
|
|
491
|
-
|
|
492
|
-
You are a git commit assistant. Your only job is to stage and
|
|
493
|
-
commit ALL changes with a well-crafted commit message.
|
|
494
|
-
...</code></pre>
|
|
495
|
-
|
|
496
|
-
<h3>The frontmatter keys that matter</h3>
|
|
497
|
-
<table>
|
|
498
|
-
<tr><th>Key</th><th>Values</th><th>Effect</th></tr>
|
|
499
|
-
<tr><td><code>description</code></td><td>free text</td><td>Shown in the agent picker; also how the orchestrator decides when to delegate to this agent.</td></tr>
|
|
500
|
-
<tr><td><code>mode</code></td><td><code>primary</code> | <code>subagent</code> | <code>all</code></td><td><code>primary</code> = you can switch to it directly (Tab in the TUI). <code>subagent</code> = only invocable via delegation.</td></tr>
|
|
501
|
-
<tr><td><code>model</code></td><td><code>provider/model</code></td><td>Pin this agent to a model — e.g. a cheap <code>gpt-5.6-luna</code> for a high-volume commit bot. Beats the global default.</td></tr>
|
|
502
|
-
<tr><td><code>hidden</code></td><td><code>true</code> | <code>false</code></td><td>Hide from the picker while keeping it delegable.</td></tr>
|
|
503
|
-
<tr><td><code>permission</code></td><td>per-tool allow/deny</td><td>Default-deny with glob exceptions, as above: this agent can only run four git commands and nothing else.</td></tr>
|
|
504
|
-
</table>
|
|
505
|
-
|
|
506
|
-
<h3>Custom slash commands</h3>
|
|
507
|
-
<p>The sibling <code>.opencode/commands/</code> folder holds prompt templates invoked as <code>/name</code>. Same Markdown format — a <code>description</code> in frontmatter, the prompt in the body, optional <code>agent</code> and <code>model</code> pins. The repo's <code>2po-commit.md</code> command is the companion to the agent above: typing <code>/2po-commit</code> runs that prompt through that agent.</p>
|
|
508
|
-
|
|
509
|
-
<div class="tip">
|
|
510
|
-
<span class="tag">The design rule of thumb</span>
|
|
511
|
-
<p><strong>Agents</strong> are for <em>who does the work</em> (a persona with a model and a permission envelope). <strong>Commands</strong> are for <em>what work to do</em> (a reusable prompt). <strong>OMOA categories</strong> are for <em>which model fits this kind of work</em> when the orchestrator delegates. Most setups need a handful of commands, one or two custom agents, and zero new categories.</p>
|
|
512
|
-
</div>
|
|
513
|
-
</section>
|
|
514
|
-
<section id="verify">
|
|
515
|
-
<div class="step-head"><span class="step-num">10</span><h2>Verifying the whole stack</h2></div>
|
|
516
|
-
<p>Launch <code>opencode</code> in your project and run through this checklist:</p>
|
|
517
|
-
<ul class="checklist">
|
|
518
|
-
<li>route33 models appear in the model picker as <code>vendor/slug</code> IDs (<code>anthropic/claude-haiku-4-5</code>, <code>openai/gpt-5.5</code>, …)</li>
|
|
519
|
-
<li>Costs and context limits show up on model entries</li>
|
|
520
|
-
<li>A chat request to a route33 model completes</li>
|
|
521
|
-
<li>The agent picker (Tab) lists the OMOA roster — Sisyphus, Oracle, explore, librarian, plus your custom agents</li>
|
|
522
|
-
<li>Your custom slash command appears when you type <code>/</code></li>
|
|
523
|
-
<li>Asking "who calls X?" uses graph tools (CodeGraph or codebase-memory-mcp, whichever you enabled)</li>
|
|
524
|
-
</ul>
|
|
525
|
-
|
|
526
|
-
<div class="warning">
|
|
527
|
-
<span class="tag">Seeing "0 models injected"?</span>
|
|
528
|
-
<p>The warning <code>route33: no model catalog available — 0 models injected</code> means no key resolved. Re-run <code>opencode auth login</code>, check your <code>ROUTE33_API_KEY</code>, or confirm <code>.opencode/route33.key</code> exists in your project. The key dictates which models are available — without one, discovery has nothing to work with.</p>
|
|
529
|
-
</div>
|
|
530
|
-
</section>
|
|
531
|
-
|
|
532
|
-
<section id="reference">
|
|
533
|
-
<div class="step-head"><span class="step-num">⚙</span><h2>Reference: env vars & troubleshooting</h2></div>
|
|
534
|
-
<table>
|
|
535
|
-
<tr><th>Variable</th><th>Effect</th></tr>
|
|
536
|
-
<tr><td><code>ROUTE33_API_KEY</code></td><td>Gateway API key. Highest precedence.</td></tr>
|
|
537
|
-
<tr><td><code>ROUTE33_BASE_URL</code></td><td>Override the default gateway URL (<code>https://api.route33.ai/v1</code>).</td></tr>
|
|
538
|
-
<tr><td><code>ROUTE33_TUI_PROMPT</code></td><td>Set to <code>0</code> to disable the key-setup wizard.</td></tr>
|
|
539
|
-
<tr><td><code>ROUTE33_DISCOVERY</code></td><td>Set to <code>0</code> to disable dynamic catalog discovery (injects zero models, no warning).</td></tr>
|
|
540
|
-
<tr><td><code>ROUTE33_STRICT</code></td><td>Set to <code>0</code> to downgrade unknown-model reference errors to a warning plus a stub entry.</td></tr>
|
|
541
|
-
<tr><td><code>ROUTE33_CACHE_DIR</code></td><td>Override the on-disk catalog cache directory.</td></tr>
|
|
542
|
-
</table>
|
|
543
|
-
|
|
544
|
-
<h3>Common bumps</h3>
|
|
545
|
-
<table>
|
|
546
|
-
<tr><th>Symptom</th><th>Likely cause and fix</th></tr>
|
|
547
|
-
<tr><td>No route33 models in picker</td><td>No key resolved → <a href="#auth">section 5</a>. Or discovery opted out → unset <code>ROUTE33_DISCOVERY</code>.</td></tr>
|
|
548
|
-
<tr><td>Key wizard never appears</td><td>Missing <code>tui.json</code> plugin entry → <a href="#plugin">section 4</a>. Or snoozed → clear <code>project-key-prompt.dismissed-at*</code> in <code>~/.local/state/opencode/kv.json</code>.</td></tr>
|
|
549
|
-
<tr><td>Global key ignored inside a repo</td><td>By design — per-project keys win inside git workspaces. Save a project key via the wizard.</td></tr>
|
|
550
|
-
<tr><td>Agents use the wrong models</td><td>Project <code>oh-my-openagent.jsonc</code> overrides global → check <code><repo>/.opencode/</code> first.</td></tr>
|
|
551
|
-
<tr><td>Duplicate graph tools / confused search</td><td>Both CodeGraph and codebase-memory-mcp enabled → pick one, <a href="#codebase-mcp">section 7</a>.</td></tr>
|
|
552
|
-
<tr><td><code>file:</code>-prefixed local plugin path fails</td><td>Known opencode quirk — use the bare relative form (<code>../packages/integrations/opencode-route33</code>) or an absolute <code>file://</code> URL → <a href="#plugin">section 4</a>.</td></tr>
|
|
553
|
-
<tr><td><code>opencode plugin</code> says "package not found"</td><td>Your npm registry doesn't serve <code>@route_33/opencode</code> → install from a local path instead, <a href="#plugin">section 4</a>.</td></tr>
|
|
554
|
-
</table>
|
|
555
|
-
|
|
556
|
-
<h3>Small conveniences worth knowing</h3>
|
|
557
|
-
<ul>
|
|
558
|
-
<li><strong>Dot/dash tolerance</strong> — a config reference like <code>anthropic/claude-opus-4.8</code> automatically resolves to the served <code>anthropic/claude-opus-4-8</code>. Arbitrary renames don't resolve.</li>
|
|
559
|
-
<li><strong>Stale-cache fallback</strong> — if the gateway is unreachable, the plugin serves the last good cached catalog rather than failing. Only a cold start with no cache and no gateway yields zero models.</li>
|
|
560
|
-
<li><strong>Live key reload</strong> — a key saved through the wizard takes effect immediately, no restart needed.</li>
|
|
561
|
-
</ul>
|
|
562
|
-
</section>
|
|
563
|
-
|
|
564
|
-
<footer>
|
|
565
|
-
<span>@route_33/opencode · v0.4.0</span>
|
|
566
|
-
<span>source: packages/integrations/opencode-route33</span>
|
|
567
|
-
</footer>
|
|
568
|
-
</div>
|
|
569
|
-
</body>
|
|
570
|
-
</html>
|