From 1b98a9ed2acff1605895700302ff276ba88baa5b Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Mon, 13 Jul 2026 23:05:00 -0500 Subject: feat(launcher): wire the local runtime — codex --oss over ollama MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ai --runtime local now launches codex against the machine's ollama (explicit --local-provider=ollama, model from AI_LOCAL_MODEL, default gpt-oss:120b). Verified end to end with a codex exec completion through the local model. The dependency check probes AGENT_BIN now that AGENT_CMD carries flags. This makes codex-over-ollama the de-facto answer to the runtime spec's first-supported-local-CLI blocker. --- claude-templates/bin/ai | 32 +++++++++++++++++--------------- scripts/tests/ai-launcher-runtime.bats | 13 ++++++++++--- todo.org | 3 +++ 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/claude-templates/bin/ai b/claude-templates/bin/ai index c09faab..c805e8b 100755 --- a/claude-templates/bin/ai +++ b/claude-templates/bin/ai @@ -11,9 +11,10 @@ # in the 'ai' session (new window or switch to existing). # Use '.' for current directory. Git prep per dir. # -# ai --runtime Launch with a different agent CLI: claude (default) or -# codex. 'local' is reserved for a local-LLM CLI, pending -# the model evaluation. Also settable via AI_RUNTIME. +# ai --runtime Launch with a different agent CLI: claude (default), +# codex, or local (codex --oss against this machine's +# ollama; model per AI_LOCAL_MODEL, default gpt-oss:120b). +# Also settable via AI_RUNTIME. # # ai --attach Attach to the existing 'ai' session without changes. # @@ -30,20 +31,21 @@ SESSION="ai" RUNTIME="${AI_RUNTIME:-claude}" - -# Map the runtime name to the agent CLI a pane launches. Both current CLIs -# take the opening instructions as a positional prompt, so only the command -# name varies; a runtime whose CLI needs different plumbing gets its own case. +LOCAL_MODEL="${AI_LOCAL_MODEL:-gpt-oss:120b}" + +# Map the runtime name to the agent CLI a pane launches. All three take the +# opening instructions as a positional prompt. AGENT_BIN is the binary the +# dependency check probes; AGENT_CMD is the full launch command (the local +# runtime rides codex's open-source provider against the machine's ollama — +# model per AI_LOCAL_MODEL, default gpt-oss:120b, verified on ratio's +# Strix Halo 2026-07-13). resolve_agent_cmd() { case "$RUNTIME" in - claude) AGENT_CMD="claude" ;; - codex) AGENT_CMD="codex" ;; - local) - echo "ai: the 'local' runtime is reserved but not wired yet (pending the local-model evaluation) — valid runtimes: claude, codex" >&2 - exit 2 - ;; + claude) AGENT_BIN="claude"; AGENT_CMD="claude" ;; + codex) AGENT_BIN="codex"; AGENT_CMD="codex" ;; + local) AGENT_BIN="codex"; AGENT_CMD="codex --oss --local-provider=ollama -m $LOCAL_MODEL" ;; *) - echo "ai: unknown runtime '$RUNTIME' — valid runtimes: claude, codex" >&2 + echo "ai: unknown runtime '$RUNTIME' — valid runtimes: claude, codex, local" >&2 exit 2 ;; esac @@ -73,7 +75,7 @@ usage() { } check_deps() { - for cmd in fzf tmux "$AGENT_CMD"; do + for cmd in fzf tmux "$AGENT_BIN"; do if ! command -v "$cmd" &>/dev/null; then echo "ai: $cmd is not installed" >&2 exit 1 diff --git a/scripts/tests/ai-launcher-runtime.bats b/scripts/tests/ai-launcher-runtime.bats index 4ec24bf..b93f778 100644 --- a/scripts/tests/ai-launcher-runtime.bats +++ b/scripts/tests/ai-launcher-runtime.bats @@ -38,10 +38,17 @@ teardown() { [[ "$output" == codex\ * ]] } -@test "--runtime local is reserved and says why it is not wired" { +@test "--runtime local launches codex --oss over ollama with the default local model" { run bash "$AI" --runtime local --print-launch "$PROJ" - [ "$status" -eq 2 ] - [[ "$output" == *"not wired"* ]] + [ "$status" -eq 0 ] + [[ "$output" == "codex --oss --local-provider=ollama -m gpt-oss:120b "* ]] + [[ "$output" == *"protocols.org"* ]] +} + +@test "AI_LOCAL_MODEL overrides the local runtime's model" { + AI_LOCAL_MODEL=qwen3-coder:30b run bash "$AI" --runtime local --print-launch "$PROJ" + [ "$status" -eq 0 ] + [[ "$output" == "codex --oss --local-provider=ollama -m qwen3-coder:30b "* ]] } @test "an unknown runtime errors and names the valid ones" { diff --git a/todo.org b/todo.org index 8f85e44..42dd8f0 100644 --- a/todo.org +++ b/todo.org @@ -293,6 +293,9 @@ Analysis in [[file:docs/design/2026-07-13-runtime-portability-inventories.org]] *** 2026-07-13 Mon @ 13:34:17 -0500 Hook parity inventoried — only two hooks carry real porting work Full mapping in [[file:docs/design/2026-07-13-runtime-portability-inventories.org]]. AskUserQuestion deny is moot off Claude (no popup tool to deny); PostToolUse validators survive via the bundles' git pre-commit hooks; clear-resume folds into the session-plumbing child; session-title is cosmetic. Real gaps: PreCompact priority-save (prose downgrade) and Stop wrap-teardown (Codex notify / manual elsewhere) — decisions in the VERIFY below. +*** 2026-07-13 Mon @ 23:04:21 -0500 Local runtime wired — ai --runtime local runs codex --oss over ollama +The reserved lane went live the same day: =local= maps to =codex --oss --local-provider=ollama -m $AI_LOCAL_MODEL= (default gpt-oss:120b; qwen3-coder:30b via the env var). Verified end to end: =codex exec --oss --local-provider=ollama -m gpt-oss:120b= returned a correct completion through the local model (~7K tokens). The explicit provider flag avoids config.toml dependence (a root-level =oss_provider= key would also work; appending to the file lands in the last TOML table and silently does nothing — learned live). Dependency check keys on AGENT_BIN (codex) now that AGENT_CMD carries flags. This partially answers the spec's "first supported local editing CLI" blocker: codex-over-ollama is the de-facto v1. The model-floor child's live trial (a takuzu session under =ai --runtime local=) is the next step. + *** 2026-07-13 Mon @ 16:39:41 -0500 Launcher runtime flag built — ai --runtime claude|codex Shipped TDD (new =scripts/tests/ai-launcher-runtime.bats=, 6 tests red→green): =--runtime= flag + =AI_RUNTIME= env on =bin/ai=, runtime→CLI mapping (claude default, codex 1:1 — both take the opening line as a positional prompt), runtime-aware dependency check, =local= reserved with a clear not-wired-yet error (pending the model-floor evaluation), and a =--print-launch= mode as the test seam (prints the pane launch command, no tmux/fzf). Kept small per the 2026-06-24 helper-task caveat — dispatch pre-parse only, no launcher restructure. The Emacs-side equivalent (ai-term multi-LLM) remains .emacs.d's June handoff. Live smoke: correct commands for both runtimes against real projects. -- cgit v1.2.3