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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ are not orphaned onto init while still holding their memory.
- **Dials, not config files** — provider lane, model tier, thinking depth,
advisor level, plus the spark/fable toggles; every combination maps to a
pre-computed routing.
- **Hosted or local** — an optional runtime broker can advertise only the local
targets this machine supports; selecting one delegates first-use setup and
launch without mixing cloud credentials into the session.
- **Live preview** — see which model leads every role, and its fallback
chain, before anything runs.
- **One-shot overlays** — each launch is an ephemeral `--config`; your omp
Expand Down
10 changes: 9 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ environment variable with a sane fallback.
| `←` `→` | change the selected dial |
| `d` | reset all dials to defaults |
| `ctrl+o` | describe the task, let a local model set the dials |
| `enter` | launch oh-my-pi with the generated setup |
| `enter` | launch oh-my-pi with the selected hosted profile or local runtime |
| `m` | launch plain managed omp (no overlay) |
| `u` | launch through a sandboxed omp, if you have one |
| `v` | manage broker account selections and presets |
Expand All @@ -32,6 +32,7 @@ environment variable with a sane fallback.
| `CODE_SESSION_STATE` | directory recording live sessions for `code ls` / `code session reap`; `off` disables recording | `$XDG_STATE_HOME/code/sessions` — note this one defaults to a path rather than to disabled, so the registry works without wrapper changes |
| `CODE_OMP` | omp binary for trusted launches (`m` and `enter`) | `omp-managed`, then `omp` on PATH |
| `CODE_OMP_UNTRUSTED` | sandboxed omp for the `u` key | `ompu` on PATH, else the key is hidden and inert |
| `CODE_RUNTIME_BROKER` | executable implementing `runtime list --json` and `runtime run TARGET -- ...`; applicable targets become a runtime dial | no runtime dial; hosted behavior is unchanged |
| `OMP_AUTH_BROKER_URL` | central auth broker behind the usage panel and the account picker (`v`); inherited from your omp environment | no fetch — the usage panel has nothing to show |
| `OMP_AUTH_BROKER_TOKEN` | bearer token for that broker | same: `code` only fetches when both the URL and the token are set |
| `OMP_AUTH_BROKER_SNAPSHOT_CACHE` | broker snapshot cache path; `code` never reads it, it only forwards it to the omp it launches | forwarded empty |
Expand All @@ -50,6 +51,13 @@ broker (`OMP_AUTH_BROKER_URL` / `OMP_AUTH_BROKER_TOKEN`).
Provider authentication is owned by OMP, not `code`. Authenticate with
`omp auth-broker login` before launching `code`.

The runtime-broker boundary is deliberately narrow. `code` reads only
schema-version-1 targets marked `applicable`, then delegates the selected
target's complete lifecycle to the broker. It does not download weights,
create credentials, or assume a container engine. Local launches receive the
thinking dial and forwarded OMP arguments, but not cloud auth-broker variables;
the runtime broker owns its OMP profile, routing config, and fallback policy.

## The `code generate` subcommand

The dials are backed by a pre-rendered catalog. Building it is two steps, both
Expand Down
82 changes: 71 additions & 11 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,9 @@ func logScore(idx, lnLo, lnHi float64) int {

// costScore rates the current config from 1 (cheap) to 5 (dear).
func (m model) costScore() int {
if _, ok := m.selectedRuntime(); ok {
return 1
}
fast := m.sel["fast"] == "on" && m.sel["lane"] != "claude-only"
var num, den float64
m.weightedModels(m.currentRows(), func(w float64, id, lvl string) {
Expand All @@ -1155,6 +1158,9 @@ func (m model) costScore() int {

// speedScore rates the current config from 1 (slow) to 5 (fast).
func (m model) speedScore() int {
if _, ok := m.selectedRuntime(); ok {
return 3
}
fast := m.sel["fast"] == "on" && m.sel["lane"] != "claude-only"
var num, den float64
m.weightedModels(m.currentRows(), func(w float64, id, lvl string) {
Expand Down Expand Up @@ -1252,6 +1258,15 @@ func (m model) applyAdvisor(rows []string, level string) []string {
// shows while fable is on (and the lane can host it at all). A dial this catalog
// generated no combo for is dropped the same way — it is not a choice.
func (m model) visibleFacets() []facet {
if _, local := m.selectedRuntime(); local {
var out []facet
for _, f := range m.facets {
if f.key == "runtime" || f.key == "thinking" {
out = append(out, f)
}
}
return out
}
lane := m.sel["lane"]
var out []facet
for _, f := range m.facets {
Expand Down Expand Up @@ -1758,11 +1773,12 @@ func (f *wheelInputFilter) Filter(app tea.Model, msg tea.Msg) tea.Msg {
}

type model struct {
generated map[string][]string
advisors map[string][]string // "level/ctx" → advisor model chain
facts map[string]modelFact // model id → cost ($/1M) + curated speed (tok/s)
avail availability
glyphs map[string]string
generated map[string][]string
advisors map[string][]string // "level/ctx" → advisor model chain
facts map[string]modelFact // model id → cost ($/1M) + curated speed (tok/s)
avail availability
glyphs map[string]string
runtimeTargets []runtimeTarget

// Catalog capability, phrased as absence so the zero value keeps every dial:
// a model with no catalog yet (the onboarding shell, tests) must behave as it
Expand Down Expand Up @@ -1805,6 +1821,7 @@ type model struct {

launchManaged bool // m: run CODE_OMP with no overlay (the managed defaults)
launchUntrusted bool // u: run the CODE_OMP_UNTRUSTED sandbox
launchRuntime string // delegated local runtime target selected via CODE_RUNTIME_BROKER
hasSandbox bool // a sandbox binary exists; gates the u key
genConfig string // generated config YAML to launch omp with (generator Enter)
firstPrompt string // prompt from the suggest box, forwarded as omp's first message
Expand Down Expand Up @@ -2696,6 +2713,20 @@ func (m *model) syncPreviewAt(yoff int) {
// generator list on the left, so the preview shows only what that selection
// produces — the role → model routing itself.
var b strings.Builder
if target, local := m.selectedRuntime(); local {
b.WriteString(lipgloss.NewStyle().Bold(true).Render(target.Label) + "\n")
b.WriteString(stDim.Render(target.statusLine()) + "\n\n")
b.WriteString("model " + target.Model + "\n")
if target.ContextWindow > 0 {
b.WriteString(fmt.Sprintf("context %dk tokens\n", target.ContextWindow/1000))
}
b.WriteString("routing every role stays local\n")
b.WriteString("fallbacks disabled\n")
content := lipgloss.NewStyle().MaxWidth(m.vp.Width).Render(b.String())
m.vp.SetContent(content)
m.vp.SetYOffset(yoff)
return
}
id := comboID(m.sel)
if base, ok := m.generated[id]; ok {
_, roles := splitMeta(base)
Expand Down Expand Up @@ -2976,6 +3007,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.relayout() // the taller/shorter footer changes the body height
case "d":
m.sel = defaultSel()
if len(m.runtimeTargets) > 0 {
m.sel["runtime"] = "hosted"
}
m.clampSel() // the defaults assume a full catalog; this one may not be
m.persistSelection()
m.syncPreview()
Expand Down Expand Up @@ -3018,6 +3052,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.launchManaged = true
return m, tea.Quit
case "enter":
if target, local := m.selectedRuntime(); local {
m.launchRuntime = target.Name
return m, tea.Quit
}
// Enter always launches the generated profile for the current facets —
// the untouched default combo is a generated profile like any other.
// Never for a combo the catalog doesn't carry, though: genConfigYAML
Expand Down Expand Up @@ -3185,6 +3223,9 @@ func (m model) previewPane(w, h int) string {
// accent is the context colour — the selected lane in the generator.
// Blue / purple / orange.
func (m model) accent() string {
if _, local := m.selectedRuntime(); local {
return cGreen
}
return laneColor(m.sel["lane"])
}

Expand Down Expand Up @@ -3333,6 +3374,10 @@ func (m model) genLines() ([]string, int) {
}
row := fmt.Sprintf("%s%s%s%s", ptr, childPad, gly, stDim.Render(pad(label, 9-childW)))
for _, v := range f.values {
display := v
if f.key == "runtime" {
display = m.runtimeValueLabel(v)
}
switch {
case v == m.sel[f.key]:
col := acc
Expand All @@ -3345,9 +3390,9 @@ func (m model) genLines() ([]string, int) {
if onRow { // the cursor sits on the selected value of the focused row
st = st.Background(lipgloss.Color(cSelBg))
}
row += " " + st.Render(" "+v+" ")
row += " " + st.Render(" "+display+" ")
default:
row += " " + stDim.Render(v)
row += " " + stDim.Render(display)
}
}
switch {
Expand Down Expand Up @@ -3377,11 +3422,11 @@ func (m model) genLines() ([]string, int) {
// was once wiped by an edit exactly because of that. CODE_FACET_GLYPHS may
// override any entry (see main).
//
// lane ⇄ (f127) model ⚙ (f085) thinking 💡 (f0eb) advisor 🧭 (f14e)
// runtime 🖥 (f108) lane ⇄ (f127) model ⚙ (f085) thinking 💡 (f0eb) advisor 🧭 (f14e)
// spark 🚀 (f135) fable 📖 (f02d) default 🎯 (f140) fast ⚡ (f0e7)
func defaultGlyphs() map[string]string {
return map[string]string{
"lane": "\uf127", "model": "\uf085", "thinking": "\uf0eb", "advisor": "\uf14e",
"runtime": "\uf108", "lane": "\uf127", "model": "\uf085", "thinking": "\uf0eb", "advisor": "\uf14e",
"spark": "\uf135", "fable": "\uf02d", "main": "\uf140", "fast": "\uf0e7",
}
}
Expand Down Expand Up @@ -3417,8 +3462,18 @@ func main() {
broker := resolveBroker(os.Getenv("CODE_AUTH_VAULTS"), os.Getenv("CODE_AUTH_VAULTS_FILE"))
accountState := os.Getenv("CODE_AUTH_ACCOUNT_STATE")
accountSelections := loadAccountSelectionState(accountState)
runtimeTargets := loadRuntimeTargets()
facets := facetDefs(glyphs)
if len(runtimeTargets) > 0 {
facets = append([]facet{runtimeFacet(glyphs["runtime"], runtimeTargets)}, facets...)
}
selectionState := os.Getenv("CODE_SELECTION_STATE")
selection := loadSelectionState(selectionState, facets)
if len(runtimeTargets) > 0 {
if _, ok := selection["runtime"]; !ok {
selection["runtime"] = "hosted"
}
}
// The u key only exists when a sandbox binary does — an explicit
// CODE_OMP_UNTRUSTED or an ompu on PATH; otherwise hide it from the help
// and ignore the keypress rather than dying on exec.
Expand Down Expand Up @@ -3446,8 +3501,9 @@ func main() {
spin: sp,
help: clikit.NewHelp(),
glyphs: glyphs,
runtimeTargets: runtimeTargets,
facets: facets,
sel: loadSelectionState(selectionState, facets),
sel: selection,
selectionState: selectionState,
hasSandbox: hasSandbox,
}
Expand All @@ -3459,7 +3515,7 @@ func main() {
// CODE_GENERATED is an operator config error and is left visible as the
// usual empty routing panel instead).
app := tea.Model(m)
if len(generated) == 0 && os.Getenv("CODE_GENERATED") == "" {
if len(generated) == 0 && os.Getenv("CODE_GENERATED") == "" && len(runtimeTargets) == 0 {
app = newOnboarding(m)
}
// Cell-motion mouse reporting carries wheel events. Filter rejected
Expand All @@ -3478,6 +3534,10 @@ func main() {
status = withSession("sandbox", "CODE_OMP_UNTRUSTED", []string{"ompu"}, func() int {
return runSandbox("CODE_OMP_UNTRUSTED", []string{"ompu"}, fm.firstPrompt)
})
case fm.launchRuntime != "":
status = withSession("runtime:"+fm.launchRuntime, "CODE_RUNTIME_BROKER", nil, func() int {
return runRuntimeTarget(fm.launchRuntime, fm.sel["thinking"], fm.firstPrompt)
})
case fm.launchManaged:
status = withSession("managed", "CODE_OMP", []string{"omp-managed", "omp"}, func() int {
return runTrusted("CODE_OMP", []string{"omp-managed", "omp"}, managedLaunchArgv,
Expand Down
4 changes: 2 additions & 2 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,14 +466,14 @@ func TestGenConfigYAMLAgentOverrides(t *testing.T) {
// them all to empty strings without anything failing; this locks each value.
func TestDefaultGlyphs(t *testing.T) {
want := map[string]rune{
"lane": 0xf127, "model": 0xf085, "thinking": 0xf0eb, "advisor": 0xf14e,
"runtime": 0xf108, "lane": 0xf127, "model": 0xf085, "thinking": 0xf0eb, "advisor": 0xf14e,
"spark": 0xf135, "fable": 0xf02d, "main": 0xf140, "fast": 0xf0e7,
}
g := defaultGlyphs()
if len(g) != len(want) {
t.Errorf("defaultGlyphs has %d entries, want %d", len(g), len(want))
}
for _, f := range facetDefs(g) {
for _, f := range append([]facet{runtimeFacet(g["runtime"], nil)}, facetDefs(g)...) {
r := []rune(g[f.key])
if len(r) != 1 {
t.Errorf("glyph for %q is %d runes, want exactly 1", f.key, len(r))
Expand Down
Loading
Loading