Repository navigation
feat: pin a template's model and reasoning for every box - #51
Merged
Merged
Conversation
…easoning # Conflicts: # ARCHITECTURE.md # CHANGELOG.md # test/config.test.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
One knob per template, applied to every box booted from it (
open,fleet,run):Why: every harness has a default model and a TUI to change it, and a box has nobody at the TUI. Left alone an agent runs whatever its provider ranks first; an opencode member on an OpenRouter key came up on Nano Banana Pro, an image model with no tool use (live, 2026-09-08). Pinning it in the launch command has to be repeated in
[fleet.agents]and[run.agents], and a plaine2b-box openfollowed by typingopencodegets neither. So the pin goes where each harness reads its defaults, and the launch commands stay untouched.src/model-pin.jsowns the per-harness knowledge, verified against each vendor's docs or a file the CLI wrote itself:ANTHROPIC_MODELCLAUDE_CODE_EFFORT_LEVELOPENCODE_CONFIG_CONTENT(inline JSON{"model": …})~/.codex/config.tomlmodelmodel_reasoning_effort~/.grok/config.toml[models] defaultdefault_reasoning_effort~/.factory/settings.jsonmodelreasoningEffort~/.prime/agent/settings.jsondefaultProvider+defaultModel(split at the first/)defaultThinkingLevel~/.config/muse/settings.jsonreasoning_effort--modeis its knobmodelEnv: the env-route variables plusHERDR_E2B_MODEL/HERDR_E2B_REASONINGon every pinned box, merged intoresolveEnvbelow the user's own[templates.<name>.env](a hand-writtenANTHROPIC_MODELstill wins). The two shared variables are also the hook for a user's own launch command:mine --model "$HERDR_E2B_MODEL".pinCommand: one-line commands with the seeds' rules (one line, variable names never values, never overwrite a key that is already set), run byprovision.jsright after the first-run seed. Codex keys are prepended so they sit above any[table]; grok only creates a[models]section when none exists.resolveEnvConfigreadsmodel/reasoningper template intotemplateModels.config.example.toml(per-harness table), README,docs/headless-run.md, ARCHITECTURE, CHANGELOG.Test plan
node --test test/model-pin.test.js: 16 tests. The five file-route commands are executed with bash against fake homes: codex prepends and is idempotent, keys land above an existing table and a set key is untouched; grok creates[models]and leaves an existing one alone; droid merges without clobbering; prime splitsprime-inference/z-ai/glm-5.2at the first slash and keeps a bare id whole; muse pins reasoning and reports the model; no variables → nothing writtennode --test test/config.test.js:templateModelsparsing, the env rung, the user's env table winningbash test/cli.test.sh: 322 passed[templates.opencode] model = "openrouter/qwen/qwen3.8-max-0902"and no-min any launch command →e2b-box run -t opencodebannerbuild · qwen/qwen3.8-max-0902, file home, 15 s[templates.codex] model = "gpt-5.4",reasoning = "low"→e2b-box up -t codex, box~/.codex/config.tomlreadsmodel = "gpt-5.4"/model_reasoning_effort = "low"above the seeded trust table,HERDR_E2B_MODEL/REASONINGpresent in the box env, re-running the pin says "already set - leaving it alone"Notes
CHANGELOG.md/config.example.toml/docs/headless-run.mdhunks with feat: e2b-box run drives every shipped agent template headless #50; whichever merges second rebases.