Repository navigation
microagent v0.11.0
Added
- Workflow checks require full commit pins for external actions and reusable workflows, while correctly ignoring references printed inside shell bodies.
- Two more fuzz harnesses over untrusted input: the output of
git blame, which
a repository, its attributes file and the user's pager choose, and a
repository's instructions file, which goes into the system role of every run
made in that tree. Both assert on what survives the pass rather than on that
it does not crash, so a name left in a blame line or a fence left able to
close the block the builder wrote is a failed check on everyzig build test. --replnames its own commands on stderr before the first prompt:/helprepeats them, and
/exitends the session beside/quitand EOF.
Changed
- A session log record's
cwdcarries the part of the working directory under the
home and a~in front of it, so the record no longer holds the account name the
absolute path spelled out. A directory outside the home is recorded whole, and so
is one under a run whoseHOMEis unset. A monitor still tells two runs apart by
directory, and the store holds no more about the operator than it did.
Fixed
-
Instruction-count parsing uses a POSIX regular expression on both GNU and BSD sed.
-
Portable benchmark tests resolve
truethrough PATH on macOS, and the source-reference fixture uses an explicit condition that passes ShellCheck on hosted runners. -
Workflow shell checks decode YAML quotes, folded scalars and block indicators,
keeprun:text inside shell heredocs in the original step, and handle braces
in quoted expressions. SBOM checks count direct pins from the manifests rather
than depend on inline lock annotations. -
Dependency lock checks compare literal version pins and reject malformed
SHA-256 digests, including bad digests beside otherwise valid ones. -
Benchmark rows escape run IDs and agent specifications as JSON. Missing Git
statistics are reported as unavailable instead of zero changes. Simultaneous runs
use separate work directories and retain their own logs. An instruction gate with
a missing baseline or an unmeasured row fails instead of silently skipping it. -
Benchmark interruptions give commands time to flush before process-group cleanup.
Missing deadline support, failed overhead prompts, failed instruction samples, Harbor
runs and summaries are reported as failures. Custom Harbor endpoints supply their
actual egress host and a JSON-escaped provider configuration. SBOM hash failures or
malformed digests stop generation and preserve the previous inventory. -
HTTP MCP refusal bodies use the same JSON nesting guard as successful responses,
and every failed call releases a stdio server marked dead. Combining-mark truncation
walks the preceding character's own UTF-8 bytes, preserving multibyte text. -
MCP discovery follows tool catalog pages with opaque cursor values, one
deadline and a shared byte allowance. Failed catalogs cannot advertise partial
tables, and duplicate detection no longer scans every earlier tool per entry. -
Benchmark deadlines kill surviving process-group descendants before
returning, including children that ignore termination after their parent exits. -
MCP initialization checks the server's selected protocol revision and uses
it in later HTTP headers, rejecting unsupported or malformed selections. -
Completion requests append to the base URL's path while preserving its
query and percent encoding, rather than appending inside a query or fragment. -
URL credentials stay redacted in configuration errors, malformed endpoint
values and allocation failures as well as request diagnostics. -
Harbor validates endpoint hosts, ports and control characters, and refuses
control characters in API keys before setup without quoting the key. -
Very large accepted time budgets wait within the OS timestamp range instead
of expiring immediately, while retaining the original deadline and clock. -
Harbor checks numeric ceilings against the binary's integer ranges before
setup and forwards accepted number spellings as decimal digits. -
Failed POSIX subprocess launches close their pipes and reap their children,
including MCP startup failures, invalid executables and oversized arguments
or environments. The build patches its cached Zig library for this cleanup. -
Arguments of rejected tool calls still spend the response byte allowance, so
excessive indices cannot bypass the ceiling. Rejection diagnostics count
streamed fragments without treating interleaved fragments as separate calls. -
MCP replies are checked for excessive JSON nesting before parsing their trees,
so deeply nested schemas, structured results and errors cannot crash serialization. -
Non-object MCP error replies retain only a capped diagnostic instead of the
complete serialized reply in the run allocator. -
Every source citation in the threat model names the line its function is defined on
again, somake lint, and the push workflow's lint job that runs it, is green on a
tree the gates otherwise pass. Forty of the drifted citations were moved to the line
the source has them on, and five that cited a line inside a function's body now name
the function beside them, which is what lets the check verify the pair rather than a
bare line that goes stale on the next insertion above it. -
Built-in tool subprocesses reject NUL bytes before the OS can execute truncated arguments.
-
Responses past the byte ceiling stop reading, discard pending tool calls and exit incomplete,
even when the provider keeps the stream open. An answer exactly at the ceiling remains valid. -
The memory benchmark rejects failed commands and unreadable measurements, checks ptrace
errors and resumes and reaps traced children when measurement fails. A command's own
SIGTRAP is delivered, while later exec stops are handled as tracer events. -
Session home-path redaction checks the full prefix before slicing, avoiding crashes
in shorter working directories and incorrect redaction of unrelated paths. -
MCP stdio deadlines include blocked request writes. Oversized complete lines and
notification floods are refused under the response allowance. -
Lazy MCP initialization and the tool request share one deadline; dead servers are not
initialized again. Structured results retain error flags and allocate only their capped prefix. -
Conversation compaction reuses the existing message buffer instead of reserving space
for both the old conversation and its replacement. -
JSON buffers keep one owner throughout writes, so a failed allocation releases the
current buffer instead of leaking it or freeing an earlier allocation twice. -
Provider stream errors are parsed as JSON, including whitespace and escaped field names;
a null error field does not turn a successful response into a failure. -
An MCP server that answers a request with
202 Acceptedis no longer reported as a
failure. Only the4xxand5xxclasses are refusals; a202to a request is the
streamable-HTTP transport accepting it and answering out of band, and the frame in the
body is the answer, so the call now succeeds the way a200does. -
An MCP refusal that carries a JSON-RPC error object now reports the server's own reason
instead of a bare status. A400with{"error":{"code":-32602,"message":"bad args"}}
saidHTTP 400and threw the reason away; it now readsbad args (code -32602) (HTTP 400),
the same sentence a200carrying an error frame already produced. A refusal with an HTML
page or no body still falls back to the status alone. -
microagent updatetells a reader to setGITHUB_TOKENon a403only when the body
is actually the API's rate limit. A403is also a token without the scope, or a
repository nobody may read, and sending someone after a token that changes nothing was
the wrong answer to those. A429still needs no body to be told apart. -
make check-refsreads a citation pair that the Markdown wrapped across a line break.
The pattern asked for the name and the path adjacent, so a pair broken between them was
never read, never checked and never repaired: a citation the gate cannot see is one it
agrees with whatever it happens to say. Ten of the threat model's citations were in that
shape and every one had drifted onto unrelated code, by as much as a thousand lines.
Ten are now on the line their symbol is defined on, one naming a function that no longer
exists, which is the control's own key resolution and now reads as it. -
make check-refsno longer prints a fixed citation as the summary of what it found. It
namedtoolCallLineat a line that was not wrong whatever the run had found, so a reader
of a red gate was walked to a citation that was fine and the gate read as disagreeing
with itself. The list above is the report. -
make check-refs FIX=1repairs a wrapped pair. The rewrite matched the name beside its
path andsedmatches inside one line, so a citation broken across a break was reported
as moved and never was: the gate stayed red with the fix flag on and nothing explained
why. The path span is unique in a document and is now what the rewrite matches, which
repairs the wrapped shape as well as one written on a single line. -
A turn whose request body was completely on the wire is not sent a second time when the
flush of it stalls past the stall timeout. The timeout was reported as a failure to send,
which the retry schedule answered by re-POSTing a request the provider may already have
generated and billed; a stall after the last byte is now classified as a lost head, which
ends the run with the same note rather than buying a second billable completion for one turn. -
MCP tool names are checked against the provider's 64-character limit including their
server prefix and its allowed letters, digits, dashes and underscores; unusable names
are reported and omitted from remote and preset schemas. -
A clock set before 1970 no longer reads as a negative number of seconds where a
Retry-Afterdate is subtracted from it. A container with no RTC, a host restored
from a snapshot and a machine with a flat RTC battery all boot into one, and the
negative reading made every wait longer than it is: a deadline that had already
passed was read as still in the future, so the run sat out the 120-second cap
waiting on a rate limit it was not under. Both ends of the range saturate rather
than trapping a checked build, which is what a clock set far enough ahead did to
the first request of a run. -
An HTTP date outside the years a four-digit IMF-fixdate field can spell is refused
witherror.OutOfRangerather than walked to or narrowed. Past 9999 the year was
reached one year at a time from 1970, so a value at the top of ani64was a walk
of billions of iterations; before 1970 the standard library's calendar counts days
from the epoch and has no day before it to name, so a release build wrapped into a
date at the far end of the calendar and a checked build trapped. A session record's
own stamp saturates at the same two ends, so a clock set far ahead writes the
largest stamp a monitor can still order rather than none at all. -
A child process group that two tool calls claim at the same moment is no longer
lost. The writers are everybashcommand and every MCP server, on whichever
worker the io hands them, and the table's claim was a load followed by a store: two
of them could read the same free slot and the second store overwrote the first, so
one group sat outside the table and was exactly the child Ctrl+C left running.
Claiming a slot is a compare-and-swap now, and retiring one swaps against the pid
it is given, so a caller can never clear a slot another child has since taken. -
The Harbor adapter forwards
MICROAGENT_MAX_SPEND_TOKENSto the container. The
binary read the billed-token ceiling from the environment all along, the adapter
checked the variable and never passed it, so a benchmark operator setting it was
working from the source and the one ceiling here counted in what the provider bills
was the one that did not reach the run. A mistyped value is now refused at the
command line, beside the other ceilings, rather than after a container start. -
microagent update --helpnames the spelling that reaches it,microagent help update, the way the main--helpalready did. The two are the same text asked
two ways and only one of them said so.