Coding Harnesses
Once can be the automation substrate for a coding harness. The harness does not need Once-specific prompt templates or built-in target kinds for every toolchain. It connects to the Model Context Protocol server, discovers the available target kinds and examples, creates or edits workspace files, validates the loaded graph, runs a capability, and checks the resulting evidence.
Connect Once#
Start the server in the project directory with editing and execution enabled:
{
"mcpServers": {
"once": {
"command": "mise",
"args": [
"-C",
"/absolute/path/to/project",
"exec",
"--",
"once",
"mcp",
"--workspace",
"/absolute/path/to/project",
"--allow-run"
]
}
}
}
The configuration above can be stored as a Claude Code project server. The same connection can be registered directly from either harness:
# Codex
codex mcp add once -- mise -C /absolute/path/to/project exec -- \
once mcp --workspace /absolute/path/to/project --allow-run
# Claude Code, private to the current project
claude mcp add --scope local once -- mise -C /absolute/path/to/project exec -- \
once mcp --workspace /absolute/path/to/project --allow-run
These commands configure the server, not the harness approval policy. For a
headless run, also give the harness permission to edit the project and execute
the registered tools inside an appropriate sandbox. Otherwise the client can
reject once_apply_edit or once_run_tests even though the server advertises
them.
Omit --allow-run when the harness should only inspect the graph and project
memory. In that mode Once does not advertise tools that edit, build, test, run,
or start processes.
During initialization the server returns cross-tool workflow instructions. Every advertised tool also carries a strict input schema, behavioral hints, an output schema, and structured content. A harness can therefore plan from the live protocol contract instead of scraping this guide.
Call once_query_workspace before using filesystem tools. It returns the exact
root configured for the server, whether the root manifest exists, the current
target count, any graph loading error, and the next relevant calls. This avoids
writing files under the harness working directory when the server was
configured for a different directory.
Run Headlessly with Codex and Claude#
Headless clients cannot stop to approve a tool call. Once marks
once_apply_edit as destructive because one edit operation can delete a target.
Use each client's non-interactive permission mode only inside a workspace whose
contents and server configuration you trust.
Run Codex with a turn-local Once server configuration:
codex exec \
--dangerously-bypass-approvals-and-sandbox \
-C /absolute/path/to/project \
-c 'mcp_servers.once.command="mise"' \
-c 'mcp_servers.once.args=["exec","--","once","mcp","--workspace","/absolute/path/to/project","--allow-run"]' \
'Use the Once Model Context Protocol server to create, validate, and run this project.'
Keep the bypass scoped to the project with -C. Omit it for an interactive
session where Codex can ask before applying an edit.
Claude Code accepts its server configuration from a file such as
once-server.json:
{
"mcpServers": {
"once": {
"command": "mise",
"args": [
"exec",
"--",
"once",
"mcp",
"--workspace",
"/absolute/path/to/project",
"--allow-run"
]
}
}
}
Then run Claude from that project:
claude -p \
--dangerously-skip-permissions \
--mcp-config ./once-server.json \
--strict-mcp-config \
'Use the Once Model Context Protocol server to create, validate, and run this project.'
Place --strict-mcp-config after the configuration path. The Claude option
accepts more than one path, so the following option also makes the boundary
between configuration paths and the prompt explicit.
For both clients, launch Once through mise exec so graph actions inherit the
project's pinned compilers and runtime environment. Query canonical target
identifiers with once_query_targets; execution tools also resolve ./Target
from the configured workspace even when the server process was started
elsewhere.
Create and Run a Typed Graph#
Use this loop for requests such as “build an Android app with Once” or “add a Rust command-line tool with Once”:
- Call
once_query_workspaceand use itsrootfor every filesystem operation. - Call
once_list_target_kindsand choose a kind whose description anduse_whentext match the request. When the request names an ecosystem or target-kind family, include it inqueryso it takes priority over generic intent words and unrelated target kinds do not consume harness context. - Call
once_query_schemafor its complete attribute, dependency, provider, capability, and example contract. When several starters match, prefer the narrowestuse_whendescription that satisfies the request. Minimal starters avoid unrelated targets and dependencies. - For an unchanged starter, call
once_materialize_example. It copies the complete bundle without returning file contents through the model, refuses all writes when any destination conflicts, and returns canonical targets, workspace validation, and suggested next calls. Useonce_query_exampleonly when the harness needs to inspect or adapt the starter files itself. - Call
once_query_targetsto obtain canonical target identifiers from the loaded workspace. - Call
once_validate_workspace. Repair every structured diagnostic and repeat untilvalidistrue. - Call
once_query_capabilitiesfor the chosen target and invokeonce_build_target,once_run_target, or the testing tools as appropriate. - Check
success,exit_code, and the structured output record. Run calls include boundedcaptured_stdoutandcaptured_stderrrecords when the target declares those logs. - Call
once_query_evidencewith the returned target or capability subject to retain and inspect the durable result.
Use once_validate_target before creating a proposed target table from
scratch. After once_apply_edit, always use once_validate_workspace because
table validation cannot detect missing dependencies, incompatible providers,
unmatched source patterns, or dependency cycles.
Adopt Existing Test Runners#
Use this loop when a repository already runs tests through pytest, Ruby Specification, Minitest, Vitest, Jest, or another native runner:
- Inspect the existing package manifests, test configuration, and documented test commands. Keep each native runner as the source of truth.
- Call
once_list_target_kindsonce with the exact runner names inquery, such aspytest vitest minitest. The result combines all matching runner families without loading unrelated target kinds. - Call
once_query_schemafor every matching test kind. Build one target table per coherent test suite, callonce_validate_targetfor each table, then create them with oneonce_apply_editcall. - Use workspace-relative runtime paths when the repository owns an
environment. A pytest target automatically detects
.venv/bin/pythonwhenpythonis omitted. Python, Ruby, and Node.js target kinds also accept explicit workspace-relative paths, names on the executable search path, and absolute paths. - Call
once_validate_workspace, then run every new target completely once withonce_run_tests. The initial plan intentionally contains one batch per target so the native runners can establish complete manifests. Readnext_planin the completed response for the file or case batches that the next run will use. Theplanfield describes the run that just finished. - Call
once_query_test_manifestwhen stable unit identifiers are needed for exact execution. Increasejobsfor later runs after confirming the expected batches innext_plan. - Repeat an unchanged run and inspect its cache decisions. Query an affected plan with representative changed paths, and use one manifest unit to prove exact execution when the target kind supports it.
The Testing and Scheduling guide provides runner-first declarations and explains the safety boundary between affected selection and automatic batching.
For an Android application, the live catalog leads the harness to
android_binary and its runnable starter. The harness creates the returned
manifest and sources with once_materialize_example, validates the complete
graph, discovers the starter's canonical target identifier, builds it, and
checks the Android application package output. Android-specific behavior
remains in the target kind, so the harness follows the same loop for other
ecosystems.
Adopt an Unfamiliar External Rule#
The built-in catalog is a shortcut, not the boundary of what a harness can model. When a requested node comes from an unsupported rule, plugin, or build system, use this loop:
- Identify the authoritative external symbol from the source build manifest, registry, plugin declaration, or checked-in rule.
- Call
once_fetch_external_sourcewith a public HTTPS address for its source code, registry record, or reference. The response is bounded and includes a content digest, so the harness can record exactly what it interpreted. - Call
once_query_module_contract. It returns the exact Starlark declaration helpers, schema invariants, implementation context, generic analysis and action primitives, the reserved test provider and normalized result contract, maintenance invariants, registration snippet, and build and test starter modules. Schema defaults are descriptive strings; implementations provide optional runtime fallbacks withctx["attr"].get(...). - Write a project-local target kind that represents only the requested node and the dependency closure needed to run it. Keep unrelated nodes in the existing build system.
- Add
source_reference(...)metadata for every external concept the local target kind interprets. Record the system, symbol, public address, reason this mapping applies, and the returned content digest when the fetch was not truncated. During maintenance, re-fetch the same source and compare its digest before changing the local graph. - Call
once_validate_modulebefore registering or using the module. Repair its structured diagnostic until the returned target kind contracts match the intended graph boundary. - Register the module, create its target tables, then continue with target, workspace, execution, output, and evidence validation.
This lets the harness maintain the project-specific graph instead of waiting for Once or an external rules package to encode every possible integration. The Once executor stays ecosystem-neutral. The local module translates the upstream behavior into explicit inputs, outputs, tools, providers, and portable actions.
The same path works with a rule from the Bazel Central Registry, a Buck2 prelude rule, a Gradle plugin, or another public ecosystem. Once does not claim that an arbitrary fetched rule is compatible. The harness must interpret the source, validate the generated module, and prove the requested capability by executing it and checking its outputs.
Run an Annotated Script#
Use scripts when the requested automation is one executable action rather than a typed multi-target graph:
- Create or update the script with
oncedeclarations for inputs, outputs, environment names, working directory, dependency scripts, and fingerprints. - Call
once_validate_scriptwith the workspace-relative path. Repair any diagnostic before execution. - Call
once_exec_script. Checksuccess,exit_code, captured streams, action digest, cache state, and the returned evidence subject. - Inspect declared output files through the harness workspace.
- When cache behavior matters, call
once_exec_scriptagain without changing declared inputs and require a cache hit.
This route executes the same annotated script contract as once exec --script.
It also materializes declared outputs when a prior action result is reused.
Use Project Memory Safely#
Once evidence is durable provenance for completed actions. It records the subject, status, action and input digests, cache decision, exit code, captured stream digests, and creation time.
Evidence is historical. A prior passing record does not prove that current inputs are unchanged. Use it to understand what ran and to correlate results, then invoke the relevant build, run, test, or script capability when the user needs a current result. The action cache decides whether that invocation can be reused safely.
Completion Contract#
A harness should report success only after all of these are true:
- the requested workspace files exist;
- the harness wrote them under the root returned by
once_query_workspace; - every project-local module validates against the live authoring contract;
- complete-workspace validation succeeds;
- the requested capability returns
success: trueand exit code0; - important declared outputs exist and have the expected content or type; and
- matching evidence can be queried for the completed action.
The Model Context Protocol reference documents transport and error behavior. The generated tool catalog is the exact tool contract served at runtime. The module reference defines the target kind authoring surface, while the memory reference defines the evidence records that close the validation loop.