Context Harness started with a focused promise: put useful project context behind a small, local, inspectable retrieval layer. The latest work takes the next step. Context Harness can now run agents locally, persist their execution, and give them purpose-built tools without turning a TOML file into an unchecked plugin system.
The result is a practical agent runtime for real projects:
- standalone agent definitions that live with the workspace;
- provider-neutral model boundaries with an OpenAI Responses adapter;
- bounded model/tool loops with explicit permissions and approvals;
- durable history, checkpoints, cancellation, and safe recovery;
- delegation with inherited authority and shared budgets;
- declarative public tools backed by trusted built-in, compiled Rust, privileged Lua, or MCP implementations;
- static inspection that does not read secrets or start executable backends.
It is enough machinery to build useful project agents, while keeping the local security boundary visible.
Profiles and agents now have separate jobs
Context Harness previously called its reusable MCP prompt personas “agents.” That name implied an execution lifecycle the feature never had. The distinction is now explicit across the CLI, configuration, REST API, Lua interface, and Rust API:
| Choose | When | Context Harness owns |
|---|---|---|
| Profile | Cursor, Claude, or another client already owns the conversation | A reusable role, suggested tools, arguments, and optional startup context |
| Agent | You want Context Harness to perform and govern the task | Model calls, tool execution, permissions, approvals, durable history, and recovery |
New profiles use [profiles.inline.*] or [profiles.script.*], ctx profile,
the /profiles/* REST API, a Lua profile table, and the Rust Profile trait.
Existing [agents.*] configuration, /agents/* integrations, Lua agent
scripts, Rust aliases, and ctx agent test/init continue to work as deprecated
compatibility paths.
Executable agents keep the name because they actually run:
ctx profile test code-reviewer # resolve a role; no model call
ctx agent run code-reviewer "Review this change" # execute a durable run
A standalone .ctx/agents/code-reviewer.toml can still be projected as an MCP
profile, letting one role support either execution model without pretending the
two lifecycles are the same.
An agent is now a project resource
A standalone agent is a small TOML file in .ctx/agents:
[agent]
name = "project-researcher"
description = "Answers project questions from indexed evidence"
model = "default"
tools = ["project.search", "project.get"]
[agent.execution]
max_turns = 8
timeout_seconds = 180
[agent.permissions]
mode = "read-only"
[prompt]
system = """
Search project context before answering factual questions. Retrieve full
documents when excerpts are not enough, cite the files you use, and identify
missing evidence instead of guessing.
"""
The immediate request stays outside the resource:
ctx agent run project-researcher \
"Explain the architecture and cite the files you used."
That separation matters. The resource defines a reusable role, limits, and authority. The run input defines today’s job. The same pattern works for code review, release planning, incident analysis, documentation work, and many other project workflows. It is not tied to a particular wiki or source system.
Tool names no longer have to equal implementations
Agents should receive tools named for the job they need to do. Hosts, meanwhile, need to know exactly which implementation will run and which authority it can exercise. Declarative bindings connect those two views.
schema_version = 1
[tool]
name = "project.search"
implementation = "builtin.retrieval.search"
description = "Search indexed project files"
[config]
source = "filesystem:project"
[fixed]
limit = 8
[restrictions]
sources = ["filesystem:project"]
max_output_bytes = 65536
The model sees a small project.search schema. It cannot change the fixed result
limit or search another source. At runtime, Context Harness validates the public
arguments, adds the fixed values, checks the effective arguments, applies the
source accessor, bounds the result, and records the resolved binding identity.
This is composition, not dynamic code loading. A resource can select and narrow a trusted implementation. It cannot download a plugin, grant itself a capability, or escape the host’s authority.
Static inspection is a real boundary
Agent systems are much easier to operate when “show me the configuration” does not secretly mean “start everything.” The new inspection commands are deliberately side-effect-free:
ctx agent validate
ctx agent show project-researcher --json
ctx tool bindings validate
ctx tool bindings show project.search --json
They do not open the context database, resolve credential values, evaluate Lua, spawn MCP processes, access the network, or call a model. Secret-bearing fields retain environment-variable references and are redacted from inspection and durable metadata.
MCP aliases make the distinction especially clear. Static validation can prove that a local declaration is well-formed, but it reports the remote metadata as unresolved. Only separately authorized startup may discover the remote schema. If that schema no longer matches the binding, preparation fails before the alias is advertised to the model.
One lifecycle for every selected tool
The runtime does not grow a new execution branch for every public tool name. Selected adapters share one lifecycle:
- resolve the resource and implementation identity;
- intersect host authority, implementation needs, binding restrictions, agent permissions, and runtime policy;
- validate public and effective arguments;
- persist approval before any side effect;
- execute with cancellation and output bounds;
- persist the result and binding snapshot before model continuation.
That common path now covers source-scoped retrieval, path-scoped file reads, registered compiled tools, privileged Lua adapters, MCP aliases, developer tools, and agent delegation.
The backend-specific rules remain explicit. Compiled Rust implementations must be registered by the embedding host. Privileged Lua requires authorization before module evaluation, and CPU-bound execution is cooperatively cancelled at VM instruction boundaries. MCP keeps its process and external-side-effect approval requirements, and MCP-backed runs are non-resumable.
Runs survive more than a terminal session
Local execution writes run state, ordered events, tool invocations, approvals, usage, artifacts, checkpoints, and binding snapshots to SQLite. Operators can inspect that state without contacting the original provider:
ctx agent history --limit 20
ctx agent inspect <run-id>
ctx agent resume <run-id>
Recovery is intentionally strict. A changed prompt, model binding, tool schema, fixed argument, restriction, implementation version, or workspace identity can invalidate resume. A tool invocation with uncertain side effects is never replayed just because a process restarted. This favors an explainable stop over a convenient duplicate action.
Delegation follows the same philosophy. A parent can invoke only named child agents, children cannot gain capabilities denied to the parent, and the tree shares depth, deadline, and model-turn budgets.
A generic starting point
The repository now includes two ways to get started:
examples/local-agentscontains a project researcher, a code reviewer, source-scoped retrieval, and a path-scoped documentation reader.skills/context-harness-agentsis a reusable Codex skill that can inspect an existing project, configure model and connector resources, create narrowly scoped tools, validate the result, and guide agent implementation. Its bundled initializer refuses to overwrite existing files.
The complete walkthrough is in Build Local Agents, with every new command in the CLI reference. For assisted setup, the Agent Setup Skill guide documents installation, invocation, customization, and validation end to end.
Where this leaves Context Harness
Context Harness is still local-first context infrastructure. SQLite remains the canonical record, retrieval remains useful on its own, and accelerated indexes remain rebuildable sidecars. The agent runtime builds on that foundation instead of replacing it.
What changed is the distance between context and action. You can now define a project agent, give it a deliberately small tool surface, see exactly what those tools resolve to, run it with bounded authority, and recover its history after the terminal is gone.
That is a much stronger base for agents people can actually understand and operate—not just demos that happen to call tools.