Skip to content

Upgrading to v0.4

Joey King edited this page Oct 5, 2026 · 1 revision

Upgrading to v0.4

v0.4.0 of the core module, published 2026-10-05, adds the gate, agentrt.CanonicalJSON, and a fix for a crash that a model-chosen number could cause. An upgrade from v0.3.x needs nothing beyond re-pinning. A consumer that runs on the Driver calls nothing that changes, and no migration or operator step is needed: unlike v0.3.0, this release adds no migration, so older processes need not be stopped first. The minor bump marks the change of identity recorded in decision 7, not an incompatible change.

There is one behaviour a consumer could notice, and one reason to upgrade soon. Both are below, after the versions.

The versions

Four nested modules carry new tags, and every module that pins the core now pins v0.4.0 on main.

Module Tag Notes
core, github.com/joeylking/agent-runtime v0.4.0 the gate, CanonicalJSON, the number bound
mcp mcp/v0.2.1 adds ReadOwned, OwnedPrivately, ReadManifest, ReadRules, and FileRule; requires core v0.4.0
export/otel export/otel/v0.1.1 carries Decision.Origin as a span attribute; requires core v0.4.0
proxy proxy/v0.1.0 new, its first tag; requires core v0.4.0 and mcp/v0.2.1
providers/ollama, providers/anthropic, providers/openai unchanged, v0.2.0 re-pinned to core v0.4.0 on main without a new tag, because their code did not change
bench unchanged, bench/v0.1.1 has no requirements at all

Tags are created only where code changed. The tagged provider modules still pin core v0.3.0, which v0.4.0 only adds to, so a consumer that imports one of them and raises the core to v0.4.0 gets the new core with the old adapter, and nothing in the adapter depends on what changed.

go get github.com/joeylking/agent-runtime@v0.4.0
go get github.com/joeylking/agent-runtime/mcp@v0.2.1
go get github.com/joeylking/agent-runtime/export/otel@v0.1.1
go mod tidy

Only the lines for modules you import are needed. mcp and export/otel require core v0.4.0, so raising either raises the core with it. The proxy is a program and not a library you import. To build it, from a clone of the repository:

(cd proxy && go build -o ~/bin/agentrt-proxy ./cmd/agentrt-proxy)

See MCP Proxy for what it is and what it does not govern. Build the operator command from the same release if you rebuild it, as before:

go install github.com/joeylking/agent-runtime/cmd/agentrt@v0.4.0

The behaviour you could notice: the number bound

JSON a consumer hands the runtime is now refused where it enters when a number's literal is longer than 10,000 characters, or its exponent is beyond plus or minus 10,000. What happens depends on where the number is:

  • in a decision's arguments, it becomes an invalid_decision observation;
  • in a tool's content, it becomes a tool_error;
  • in a capability, or in a reconciliation's result, it fails the run;
  • in a tool's input schema, it fails registration.

Nothing stored or hashed changes, and arguments that passed before still pass unless they carry such a number (TestCheckJSON_RefusesNumbersPastTheBound, TestDriver_HugeNumbersAreRefusedWhereTheyEnter, TestGate_HugeNumberIsAnInvalidDecision, TestCheckArgs_RefusesNumbersPastTheBound). A consumer whose tools never see numbers that large sees no difference. If one does, for a legitimate reason, the number is now an invalid decision and the agent is told so, as for any malformed argument.

The security fix, present in every release through v0.3.2

A model-chosen number could end the process. The JSON Schema library the runtime uses reads a number as a big.Rat, which cannot hold an exponent, written or implied by the digits after the point, beyond a million. Validating such a number against minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, or uniqueItems dereferenced the nil it left and panicked, and nothing recovered it. Arguments such as {"n":1e-10000000} or 0.1e-9223372036854775808 crashed a Driver consumer from inside Start or Resume, and CheckArgs and ToolSchema.Check the same way, whenever a tool's schema bounds a number. A schema's own bound past that reach was silently dropped, or made every validation against it panic.

v0.4.0 refuses such numbers where they enter, as above, and validation now recovers a panic inside the library as a refusal of the arguments, never an acceptance (TestValidate_APanicInTheLibraryIsARefusal). The bug is in every release through v0.3.2.

What a consumer should do. Upgrade. A consumer whose tools bound a number, with minimum, maximum, multipleOf, or uniqueItems, is exposed to a model that writes such a number. Until the upgrade, recover around Start, Resume, and CheckArgs and treat a recovered panic as a refusal of the arguments. A consumer whose schemas never bound a number is not reached by this path, but the upgrade costs nothing.

What does not change

  • Stored data. No migration, no new column, and no stored byte changes for a decision without an origin, so approval hashes and the replay key are the same. agentrt.CanonicalJSON is the existing encoder, exported, and every hash is unchanged (TestContentHash_Golden).
  • What the Driver writes. Start and Resume now run on the gate's code, and the rows, events, payloads, transaction boundaries, and clock readings are the same (TestGate_ExternalLoopMatchesTheDriver).
  • Recordings and pending approvals. Both survive.
  • The operator's side. agentrt behaves as before. Only a database that a proxy has used carries extra tables, its own proxy_calls and proxy_schema_migrations, and the runtime's schema is unchanged.

What you can adopt

None of this is required. If you already have a loop of your own in Go, The Gate lets it use the runtime's controls without replacing it. If you have an MCP host in any language, MCP Proxy puts the controls in front of its tools, with the limits on what it can govern stated first. Security Model says what each one trusts.

Next

Status and Roadmap lists what v0.4.0 contains with the tests that verify it. Upgrading to v0.3 is the one to read if you are coming from v0.2.

Clone this wiki locally