Continual Harness
The harness is a durable set of operating lessons that every future session sees. UGENT can read a finished session and propose additions to it, but nothing is applied until you approve it by hand.
Two commands: /refine proposes, /harness reviews.
Why it is propose-only
An agent that edits its own instructions unsupervised optimises whatever proxy it can reach. A note that quietly changes future behaviour is the wrong thing to let it write unattended, so UGENT splits the two halves: the model may propose, only a person may apply.
This is a deliberate difference from the upstream design this feature is adapted from, which applies harness edits directly.
Turning it on
Off by default. In ugent.toml:
[harness]
enabled = trueThat makes the commands available. It does not make anything happen on its own: there is no timer, no turn counter, and no hook that triggers a refinement. /refine is the only trigger. With an empty harness, an enabled harness costs one indexed database read per turn and injects nothing.
Proposing: /refine
Run it after a session that taught you something:
/refineOr point it at what you care about:
/refine focus on how we handled the flaky integration testsTwo calls happen, both on the background transport so neither streams into your chat:
- A cheap review gate decides whether the session holds anything worth proposing. Most sessions do not, and you will see "the review gate found nothing in this session worth keeping." That is the normal answer, not a failure. Set
review_gate = falseto skip it and always run the full pass. - If the gate says yes, a full pass reads the last 40,000 characters of the trajectory and queues proposals.
Nothing is applied. The result is always a queue you have to act on.
Reviewing: /harness
| Command | Does |
|---|---|
/harness or /harness list | Show pending proposals and the current entry set |
/harness show <id> | Full detail for one proposal, including the exact text that would be injected |
/harness approve <id> | Apply it to the entry set |
/harness reject <id> | Discard it without applying |
/harness rollback <refinement-id> | Undo every approved edit from one refinement pass |
Ids may be abbreviated. An ambiguous prefix resolves to nothing rather than guessing.
Only after approve does the entry appear, as a [HARNESS_CONTEXT] block, in the next turn's context.
Read show before you approve
/harness lists a preview; /harness show prints the entry verbatim, and that is the exact string that gets injected. Approval is the entire safety model, so it is worth the extra command.
The three kinds of entry
| Kind | Holds |
|---|---|
prompt | A narrow behavioural addendum. Use sparingly: every prompt note is paid for on every future turn. |
memory | A durable fact, decision, or recorded failure. |
subagent | A reusable delegation brief, including purpose, scope boundary, and acceptance criteria. |
The upstream skill kind is deliberately absent. UGENT ships no built-in skills, and third-party skills and MCP servers are externally owned, so a skill entry would have nothing first-party to reference.
What gets refused automatically
Some proposals are refused outright and never reach the queue: those that would reduce oversight or widen what may run unsupervised. Standing approval for destructive commands, skipping confirmations, disabling the firewall, hiding actions from you, or approving harness proposals automatically.
This exists because a harness entry is injected into every future session, so an entry of that shape is a persistent change to how supervised the agent is, not a single bad turn. There is no legitimate version of such an edit: an operator who genuinely wants to relax a confirmation edits their own config, where the change is visible and version-controlled.
A refusal is reported separately from a malformed edit, and a pass in which every edit was refused says so rather than reporting "nothing to propose". If you hit a false positive, the log names the phrase that matched, and you can write the entry by hand.
Keeping the queue reviewable
max_pending (default 25) bounds the review queue in both directions: a refinement pass will not start when the queue is already full, and a single pass cannot push it past the cap. Withheld edits are counted and reported.
A queue nobody reviews is worse than no queue, because it buries new proposals among stale ones.
Rollback
/harness rollback <refinement-id> reverses every approved edit from one pass, newest first. Reversed proposals are recorded as rolled_back, which is not the same as rejected — the latter means a human declined it before it was ever applied.
Rollback refuses outright when a recorded previous state cannot be read, rather than treating that as "there was nothing here" and deleting the entry.
Channels: off by default
/harness and /refine are refused over channel plugins unless you opt in:
[harness]
allow_channel_review = trueThe default is closed, and deliberately coarse. The entry set is global, so approving a prompt entry changes the system prompt of every future session for every user. A channel API key authenticates the channel, not the person typing. On a shared or port-exposed channel, leaving this open would let anyone who can reach it rewrite what the agent believes.
Turn it on when the channel is your own operator console and you accept that everyone who can reach it may approve.
Where it is enabled, approve and rollback take a two-step confirmation: the first call returns the rendered proposal and a confirmation token, and the client re-sends the command carrying it.
Configuration reference
[harness]
# Make the commands available and inject approved entries. Off by default.
enabled = false
# Cheap review call before each pass. On by default: most sessions yield
# nothing, and the gate costs far less than the pass it avoids.
review_gate = true
# Pending proposals allowed. Bounds both entry to a pass and how many one pass
# may add.
max_pending = 25
# Whether /harness and /refine are reachable over channel plugins.
allow_channel_review = false
# Optional dedicated model for refinement. Unset means the session model.
[harness.refine]
provider = "openai"
model = "gpt-5-mini"What this is not
- Not memory. Memory is a recall engine over a large corpus, searched per turn. The harness is a small enumerable set injected wholesale. Only the injection seam is shared.
- Not per-workspace. Entries live in the session database, so a lesson approved in one workspace is visible in all of them. Worth knowing before you approve something project-specific.
- Not automatic. Nothing refines on a schedule or at a compaction boundary.