skip to content
Replays

Global Config Harness

Standing Harness Preferences

A global config file now resolves harness, model, and assistant choices before Gantry starts work.

Gantry milestones

2 milestones 9 tasks 21 agents

5 plan 9 execute 12 review

141k peak context

103k median execute

A global config file now resolves harness, model, and assistant choices before Gantry starts work.

2h 19m total 8m 43s per task

3m 37s plan 51m 10s execute 26m 25s review

83 edits 591 commands

codex harness

This run made the global Gantry config file into the standing preference layer for agent selection. It had to keep the old default harness behavior intact while adding role harnesses, role model pins, per-harness settings, and assistant preferences that real runs would actually honor.

The decomposition split the work at the right architectural boundary. The first milestone built the parsing and resolution foundation, and the second milestone carried that foundation through invocations, the config command, and documentation. The current tree still shows that split: global config owns the file and settings catalog, harness code owns role and model resolution, run and assistant code consume the resolved values, and the docs describe the precedence model.

How this walkthrough is structured

Feature

What did the run build and ship?

Gantry now reads one global config file for standing role, harness, model, and assistant preferences while preserving harness-native model deferral.

Build

How did Gantry structure the work?

The run first built a typed global-preference foundation, then sent the user-facing execution and command surfaces back over that foundation until absent model pins stayed absent.

Milestone 1

Global Config Foundation

4 tasks 11 agents 46m 9s wall time 133k peak context

The foundation is still visible in `src/engine/global_config.rs` and `src/engine/harness/mod.rs`. The config module owns the path, schema values, warning collection, role harness preferences, per-harness settings, role model pins, assistant preferences, and settings rows. The harness module still resolves roles through the global tier and keeps main-model absence distinct from an explicit override. Some original run-site scaffolding has since moved into the current run module layout, but the resolved data contract remains standing.

This milestone carried the internal contract: read the hand-edited file, preserve compatibility, and make later code consume resolved preferences instead of reinterpreting text. Its child sprints all passed cleanly, which is consistent with a foundation cut that separated parsing, per-harness configuration, harness selection, and model selection. The outer review still found a remaining forgiveness gap around malformed lines in the newer sections, so the milestone did not pretend the parser surface was finished. That gap became the first item of the next milestone rather than being hidden inside unrelated execution work.

Preference Defaults

2 agents 7m 38s wall time 84k peak context

The live global config module still exposes the preference object that carries default harness, role harness preferences, per-harness settings, role model pins, assistant preferences, and warnings. The parser distinguishes role keys under the harness table from per-harness settings tables, and tests in the module cover stale values, unknown harness ids, invalid values, and compatibility for preserving comments while writing the default harness. That is the durable read surface this sprint introduced.

This sprint was asked to define the typed global preference read surface while leaving the old default-harness behavior alone. That was a good first cut because every later sprint could depend on one contract for warnings, paths, role preferences, per-harness tables, model pins, and assistant preferences. It passed without recorded repair, so the next agents could treat parsing and compatibility as a stable boundary. The sprint did not have to decide how real launches would consume the values.

Harness Configuration

1 agents 8m 43s wall time 89k peak context

Per-harness global settings still flow through the harness configuration path. `configs_with_global` applies global binary, main model, small model, and argument settings only to registered harnesses, while environment values keep their higher precedence. The current config schema and settings catalog also expose the same per-harness settings, so the feature is no longer just launch plumbing.

This sprint took the typed preferences and narrowed its responsibility to per-harness runtime configuration. The brief kept the work local: merge file settings with built-in defaults and environment-backed compatibility settings, validate harness ids through the registry, and keep absent main models absent. It completed cleanly, leaving model resolution free to consume already-merged harness config rather than reopening the file.

Harness Resolution

2 agents 9m 49s wall time 103k peak context

Role-based harness resolution in the live harness module still includes the global preference tier and still documents that harness selection has no environment tier. Startup fallback has returned to the narrower case where nothing else states a harness. The main binary resolves global preferences before checking installed harnesses and preflight state, so startup looks at the same role map the run will actually dispatch.

This sprint inserted the global file as a role-selection tier instead of letting startup fallback carry that meaning implicitly. The brief gave the agent a finite precedence chain to prove: role flag, run-wide flag, plan pin, global role choice, global default, then fallback. The sprint stayed green, and its boundary mattered because later model selection needed a final role harness answer before choosing what model, if any, to pass.

Role Model Selection

2 agents 10m 48s wall time 133k peak context

The live harness module still has resolved role agent configs with a harness, optional model override, model source, and warnings. Heavy roles keep `None` for the model when nothing pins a main model, while util resolves through the small-model path. Tests in the harness module still cover environment precedence, global role pins, global per-harness models, util semantics, and the absent-main-model case.

This sprint carried the hardest foundation rule: role model pins are not the same as harness defaults, and an unpinned main model must not become a forced flag. The brief kept it focused on producing a resolved role-agent artifact, not wiring every call site. It passed cleanly, which let the next milestone treat role harness and role model selection as one consumable object.

Milestone 2

Execution CLI Completion

5 tasks 17 agents 57m 30s wall time 141k peak context

The current tree still carries the user-facing completion work. Run construction resolves role agent configs before launching agents, assistant turns preserve optional model overrides, `gantry config` prints and writes the global settings surface, and the agent docs describe the global file as the standing preference home. Some original tests from this run were later deleted during test-suite maintenance, but their covered behavior is represented in the reorganized run, harness, config, and assistant tests.

This milestone moved from resolution to observable behavior. It began by closing the parser gap left by the foundation review, then wired real role launches, assistant selection, command output, and docs. The assistant sprint was the stress point: review found that an absent assistant model was being collapsed into an explicit value, and the run replanned that unit before continuing. A later command sprint also reran its gate after review, and the final landing record shows integration needed reconciliation after the green child work.

Parser Warning Fix

2 agents 2m 5s wall time 52k peak context

The global config parser now emits warnings for malformed non-assignment lines, including lines inside known sections, instead of silently skipping them. The surrounding valid values still survive, so one bad hand-edited line does not poison the whole file. The tests around malformed headers, unrelated lines, invalid section values, and scoped row warnings remain in `src/engine/global_config.rs`.

This sprint was residual foundation work with a deliberately small blast radius. The milestone review had already located the bug: malformed lines in the newer config sections were being ignored instead of entering the warning-and-unset path. The unit passed cleanly because it only had to bring that gap under the existing forgiveness contract before the command and docs made the file more visible.

Real Role Runs

2 agents 13m 15s wall time 141k peak context

Current run construction resolves role agent configs once and stores them in the run context. Agent launch code reads the role config for the stage, passes an explicit model only when the resolved role has one, and tags agent work with the resolved harness and model. Util work uses the resolved util model through the small-model path, while mechanical stages can still carry no model.

This sprint was the execution bridge between resolution and real agent subprocesses. Its brief was broad but still bounded by one contract: every plan, build, review, and util launch should receive the already-resolved harness and optional model value. It passed without recorded repair, which shows the foundation was strong enough for launch code to consume without reopening precedence decisions.

Assistant Preferences

5 agents 21m 31s wall time 116k peak context 1 replan

Assistant selection now reads explicit choices, repo-local pins, global assistant preferences, inherited run harnesses where appropriate, and built-in fallbacks in order. The assistant model remains optional through resolution, console setup, and `AgentAssistantDriver::build_spec`; with no pin, the agent spec carries no explicit model. The assistant docs and diagnostic command also report this as harness default behavior rather than a passed model value.

This was the sprint where the abstraction was tested hardest. The first attempt made assistant selection global-config aware but violated the model-deferral rule by always turning absence into a concrete model. Review recorded that as a repair note and forced a replan, after which the sprint ran again and passed. The boundary was correct: assistant resolution could be fixed locally without changing the role-run contract from the previous sprint.

Config Commands

2 agents 7m 28s wall time 82k peak context

`gantry config` now works as an inspection surface for the global settings file. It builds an effective settings catalog with source markers, warnings, overridden file values, environment bindings, and dynamic per-harness rows. The command still supports the default harness workflow while adding role harness and role model setters that write through the schema-aware global config writer.

This sprint turned the resolved picture into a command surface after real launches already honored it. The brief kept the command from becoming a full editor: print the path and effective role and assistant values, keep the old default-harness setter, and add narrow setters for common role preferences. Review triggered another gate at this boundary, fitting a user-facing command whose risk was mostly compatibility and source attribution.

Config Docs

2 agents 3m 30s wall time 75k peak context

The surviving docs describe the global config file as the home for standing harness choices, role model pins, per-harness settings, and assistant preferences. `docs/agents/config.md` covers the file location, command surface, and model environment precedence, while `docs/agents/harnesses.md` explains role harness order and the absence of a harness environment tier. `docs/agents/assistant-and-mcp.md` documents assistant harness and model precedence plus the no-model-flag handoff.

The final sprint was documentation after the implementation and command surface existed. Its brief asked the agent to explain one precedence model rather than describe partial internals: global file shape, harness selection order, model environment asymmetry, model deferral, util small-model behavior, and assistant preferences. It passed cleanly, which left the milestone with implementation, CLI output, and docs aligned.