Why: external tool ecosystems speak MCP; the kernel had no way to
mount them, so every external capability needed a bespoke builtin.
Evidence: go vet ./... clean; go test ./... 11 packages ok. Tests run
against a REAL stdio server (test binary re-exec via
mcp.RunFakeServer) and httptest HTTP servers: initialize handshake,
tools/list with pagination cap, tools/call success / tool-level
isError / unknown-tool rpc error, JSON and SSE response modes,
Mcp-Session-Id capture, manager registration as mcp__<server>__<tool>,
namespace wildcard allowlist (mcp__fake__* keeps only that namespace,
unknown wildcard fails closed), unreachable server failing the step,
hung server bounded by per-request timeout, config validation
(duplicate names, dual/missing transport, bad name chars), and an
adapter end-to-end execution calling an MCP tool.
Impact: new runtime/mcp package; native.Options gains MCP *mcp.Manager
and Close() for process cleanup; tools.Registry.Restrict gains
prefix/* namespace entries; server-provided metadata is capped (64
tools/server, 1 KiB descriptions, 64 KiB text results) and treated as
untrusted input.
Refs: plan B5; agent-execution standard (tool providers get
authorized capability only).
Why: tavily_search/web_search existed as tools but were never
registered on the default execution path (parity-matrix #5 leftover),
and the kernel had no URL fetch capability at all.
Evidence: go vet ./... clean; go test ./... all ok. Fetch cases cover
private/loopback/link-local rejection (127/8, 10/8, 192.168/16,
169.254 metadata endpoint, ::1), file:// scheme rejection, DNS
resolution landing on private space, per-hop redirect validation
rejecting a redirect to loopback, allowed-host policy, HTML stripping
(script/style removed, entities decoded), content-type gating, stub
end-to-end fetch, and absence without FetchConfig (IP normalization
fix included: IPv4-mapped ::ffff:0:0/96 must not swallow all IPv4).
Adapter tests assert Options.Search registers both search tools and
passes queries to the provider, and that neither registers when
unconfigured.
Impact: native.Options gains Search and Fetch; both tool families are
opt-in by the composition root (fail-closed), closing parity-matrix
#5 wiring.
Refs: docs/parity-matrix.md #5; product settings tools.tavily.*
injection point.
Why: the kernel had no system-tool capability, so deliverable generation
via CLI/Python (the settled product direction) could not run inside
agent-native executions; squad's BashPermission gate had nothing to
guard.
Evidence: go vet ./... clean; go test ./... all ok. Cases cover echo
and non-zero exit reporting, env whitelist isolation (host secrets do
not leak into children), timeout and context-cancel killing the whole
process group promptly, blocklist rejection (sudo/destructive
patterns), 64 KiB head+tail output truncation, python script
persistence under .agent/scripts/, and fail-closed registration (no
interpreter configured = no tool). Adapter tests verify Options.Exec
wiring, per-request Env merge, allowlist stripping, and absence
without Options.Exec.
Impact: native.Options gains Exec *tools.ExecConfig; exec.Request.Env
now flows into child processes; workspace profile gains up to 2 tools
(only when configured). NOT an OS sandbox - isolation stays a host
responsibility, documented in tool descriptions.
Refs: parity-matrix #3/#4; settled product decision (deliverables via
CLI/Python + skills, see archived card feature-exec-interpreters).
Why: the five builtin tools could not express file discovery (no glob),
code search (literal-only grep), paged reads (200 KiB silent
truncation), or batch edits, capping the kernel below general coding-
agent parity.
Evidence: go vet ./... clean; go test ./... all ok. New cases cover
numbered line ranges and beyond-EOF rejection, regex/include/
ignore_case grep with invalid-regex errors, double-star glob
(**/*.go, docs/**, no-match), workspace confinement of glob, and
multi_edit atomicity (failed batch leaves the file untouched).
Impact: WorkspaceTools now registers 7 tools (adds glob, multi_edit);
read_file gains optional offset/limit and announces truncation; grep
gains regex/include/ignore_case while keeping literal default
behavior; existing callers see only additive changes.
Refs: docs/parity-matrix.md #3 (tool semantics negatives, Batch2).
Why: the frozen exec port could not express per-request model, tool
allowlist, skills, budget, or identifiers, so squad roles and product
profiles had no way to steer one execution; contract v0.1.0 semantics
(budget/cancel) stayed unconsumed (parity-matrix #4/#10/#16).
Evidence: go vet ./... clean; go test ./... all ok, including new
loop budget caps (tool calls, prompt tokens, deadline), cancel
propagation into a blocking tool, registry Restrict fail-closed
policy tests, native adapter v2 tests (model override, allowlist,
deadline-bound context, execution-id log header, skills prompt line),
and settle classification marking budget_exceeded permanent.
Impact: exec.Request gains optional Model/ToolAllowlist/Skills/Budget/
SessionScope/ExecutionID/Env (zero value = legacy behavior); runtime
loop enforces a shared budget and emits budget_exceeded events;
adapters/native consumes all new fields. Consumers on the old port
keep compiling and behaving identically.
Refs: docs/parity-matrix.md rows #4/#10/#16 (Batch2 scope); deps/
development-guidelines standards/agent-execution.md (shared budget
across retry layers).
Contract codes now use the agent.* values, and runtime can emit structured logs without changing results when no logger is configured.
Co-authored-by: Cursor <cursoragent@cursor.com>