id: SMH-PLAN-SLXZ2R9V type: plan title: "Plugin Tool Authority and Run Settlement" spec: SMH-SPEC-PLUG0001 status: draft depends_on: []
Plugin Tool Authority and Run Settlement
Outcome
Ordinary component tools remain callable only under request/caller authority, including nested composition. Lifecycle handlers can ensure one next request; cancellation/failure wins; one settled notification follows all run work without reentrant starts.
Scope
Implement the amended Plugin System: Tool visibility and authority; candidate/publication and request-pin rules; Budgets and failure; Event boundary → Continuation and settlement. Context-edit persistence, exact request reconstruction, physical routing, and usage aggregation belong to Recorded Context and Dispatch Provenance.
Exclude a new scripting engine, MCP client/discovery backend, new provider operations, vendor/OAuth migration, full bundled-tool migration, and Brush/Nushell SDK design. Implement only host/WIT additions consumed by the slices below; no speculative hook inventory or capability hierarchy. Do not rewrite existing approved plans.
Entry contracts
The existing harness plan supplies ordinary trusted component loading, complete-generation publication, generic tool dispatch, grants, recorded effects, and shared invocation budgets.
It is owned by SMH-SPEC-SPEC0001, so it is an external interface prerequisite, not a same-spec depends_on entry.
Provider-codec/transport proof consumes the ordinary component contract from the provider-plugin plan, not its full vendor/OAuth rollout.
Inspected code has direct component declaration/invocation in smith-harness/src/wasm.rs and plugins/echo/, but no agent-connected plugin manager, grants, action dispatcher, or nested-call host surface.
wit/smith-plugin.wit is tool-only and lacks schema, effect, and lifecycle contracts.
smith-core/src/tools.rs still dispatches fixed native built-ins; agent.rs has queued delivery and TurnSettled, not the amended authority/settlement protocol.
Prerequisite gaps must be resolved in their owning work before dependent proof; they are not permission to retain a native shadow dispatch path or invent an implemented interface.
Plan/interface dependencies do not imply implementation completion.
flowchart TB
H["PLUG0001: ordinary sandbox and host contracts"] -.-> P["SLXZ2R9V: authority and lifecycle policy"]
V["AIAGD002: component provider contract"] -.-> P
E["99TPLN9I B1: atomic context edit"] -.-> P
P -.-> L["99TPLN9I B3: pinned request loadout"]
P -.-> U["99TPLN9I B5: causal child usage"]
Behaviors
Each slice crosses ordinary component loading, host policy, core execution, and its public/binary observation where required.
Use complete explicitly loaded guest packages, including separate composition and lifecycle consumers; never automatically discover documentation examples.
Use raw wit-bindgen; each added world interface needs two real consumers and a naming/glossary audit.
Missing basic host contracts block the slice rather than making a unit-only or native substitute count as acceptance.
B1 · Invoke only the tool advertised by the originating request
A built eval/RPC turn advertises a validated ordinary component tool, invokes its matching handler, records the result, and follows up under the same round generation.
Touch wit/smith-plugin.wit, smith-harness/src/wasm.rs, the harness registration/runtime owner, smith-core/src/tools.rs, agent.rs, and real guest fixtures.
- Connect validated contribution schemas/identities to generic dispatch; registration is not a hardcoded tool-name match.
- Keep registration, activation, per-request advertisement, and caller authorization distinct in host-owned state.
- Reject model-emitted disabled, absent, unadvertised, or schema-invalid calls before invocation or effects.
- Return actionable typed diagnostics naming the tool, authority failure, and correction; do not drop the error or select an ambiguous short name.
- Source definitions and executable handlers from one originating request pin through the complete tool batch. B1 consumes the entry harness's baseline request pin; B2 extends discovery/publication policy and proves reload/retry/failover retention.
Proof: real component and scripted component provider through built eval/RPC; an advertised call succeeds, active-but-unadvertised model call fails, disabled call fails, and malformed arguments never enter the guest.
Contributed names cannot fall through to native built-ins, including names matching old defaults.
Direct PluginInstance::invoke tests support codec bounds but are not binary/plugin parity proof.
B2 · Publish discoveries without changing an active round
Validate a discovered contribution set while a request is stalled; the current response/tool batch uses its original definitions and handlers, while a later round sees the replacement.
Touch harness generation/registry/runtime owners, wasm.rs, smith-core/src/agent.rs, and the shared request vocabulary.
- Candidate registration/validation performs no operational effects, active mutation, or active subscriptions.
- Publish one complete generation atomically; failed publication leaves the previous generation and handlers usable.
- Discovery grants no invocation or effect authority; only validated publication makes a contribution eligible for future loadouts.
- Pin catalog/provider contributions, advertised definitions, active-policy snapshot, handler bindings, and generation across establishment retries/failover and the resulting tool batch.
- Preserve session/branch/queue/secrets/cancellation outside generation lifetime; release retired instances only after pinned work finishes.
- Hand an immutable round loadout to companion B3; core must not independently resample live registries.
Proof: explicit readiness/release signals around retry, response, and tool execution; publish a changed schema/handler and assert old work stays old, later work becomes new. A candidate attempting an effect or runtime mutation fails before publication; invalid reload retains old subscriptions and produces no candidate effect. Unknown/ambiguous discovered names fail deterministically with sorted candidates; no discovery protocol or remote-tool backend is required.
B3 · Compose a hidden active tool under narrowing authority
An ordinary component explicitly invokes an active unadvertised tool through the host; success requires caller invocation permission and the intersection of target grants and caller-delegated scopes.
Touch WIT capability/resource surfaces, harness dispatch/effect/budget owners, smith-core/src/tools.rs, durable effect records, and complete composition fixtures.
- The host creates and validates caller/request identities and delegated authority; guests cannot forge a caller by supplying another identity string.
- Resolve nested targets inside the parent's generation pin; validate every target schema before execution.
- Disabled targets remain unreachable; a target grant alone never authorizes its caller.
- Scope intersection may only narrow at each hop; secrets follow the same explicit authorized-local-effect boundary.
- Carry stable invocation/effect IDs, causal parents, generation, and usage references through the ordinary intent/completion ledger.
- Share deadline, fuel, memory/table, host allocation, conversion, log, and output budgets across parent and structured children; fan-out cannot multiply ceilings.
- Serialize per instance; orchestration cannot deadlock by reentering a busy instance or detaching child work.
- Children finish or cancel before parent return; ordinary guest errors may be caught, but cancellation, exhausted budgets, sandbox violations, and recording failures escape as terminal failures.
- Retain already-completed effect evidence on later parent failure; do not automatically retry uncertain child effects.
Proof: two ordinary plugin consumers compose through a third target with a bounded real filesystem effect; delegated path A succeeds, target-only permission and path B fail before effects. Nested hop escalation, disabled targets, forged identities, budget-spinning children, conversion/output overflow, parent cancellation, and recording failure fail closed. Child usage/effect attribution feeds companion B5; separate evidence from parent success or durable plugin-state commit. Run the built binary with real files/components and assert denied paths are untouched and all completed child effects remain inspectable after parent failure.
B4 · Ensure one continuation at an actionable boundary
Turn-complete and pre-settlement handlers can request continuation or runtime changes; one validated boundary produces at most the required next request, not duplicate work.
Touch WIT event/action records, the harness ordered handler/action owner, smith-core/src/agent.rs, companion context-edit APIs, and eval/RPC runtime wiring.
- Deliver typed events in deterministic registration order under one shared bounded invocation budget.
- Apply cancellation immediately; validate other mutations as one conflict-free batch and publish atomically only between requests after the stream and complete tool-result batch.
- Route context-edit actions through companion B1 validation/publication; runtime prompt/tool/model/provider/config changes never persist user configuration implicitly.
- Coalesce duplicate continuation requests; an already-eligible tool follow-up or queued-input request satisfies ensure-one-next-request.
- Preserve queued input order and its original delivery mode; ending a run does not discard queued input without an accepted queue action.
- Explicit stop, cancellation, terminal stream/run failure, or required-decision failure defeats continuation.
- Disable a failed/over-budget handler only for its generation and emit one typed diagnostic.
- Required-decision failure terminates without partial actions, duplicate terminal events, or erasing recorded effect evidence.
Proof: two real handlers request continuation at the same boundary; scripted endpoint observes one request. Repeat with an eligible tool follow-up and each queue delivery mode; input appears once without splitting tool calls/results. Conflicting model/tool/context changes leave the prior runtime/projection intact; failed required decisions and hard exits retain queued input and prevent continuation. Built eval/RPC outputs and durable request sequence agree; no handler-owned alternate agent loop.
B5 · Notify settlement only after all run work resolves
A run settles once after continuation decisions and structured children finish/cancel; settled handlers cannot reopen it or observe a new run reentrantly.
Touch smith-core/src/agent.rs, harness lifecycle/child-work owners, smith-rpc/src/lib.rs, and built-binary lifecycle tests.
- Separate actionable pre-settlement from notification-only settled dispatch.
- Reject and diagnose continuation for the completed run; do not let it schedule a provider request.
- Preserve accepted queued input for a later run; new-run requests received during notification remain deferred until every settled handler returns.
- Resolve cancellation/child cleanup and required decision outcomes before one terminal/settled notification; release generation pins only when their work permits.
- Make RPC
wait/statusand eval completion reflect the same settled boundary after child cleanup and all settled handlers return, not merely arrival of a provider terminal event. - Worker/frontend input can enqueue during notification without starting a second run or blocking render/IO threads on guest work.
Proof: a real settled handler uses a deadline-bounded synchronization fixture while another RPC client request queues a new run; no new provider request/event appears until all handlers finish.
Rejected settled continuation yields one diagnostic, one terminal notification, and no reopened run.
Cancellation with active child work cancels/joins it before wait reports settled; queued input remains available to the next run.
Use explicit channels/readiness and injected time, never sleeps, polling waits, or retries.
Behavior dependencies
Local slices build observable policy; companion edges transfer contracts at the earliest consumer without whole-plan mutual dependencies.
flowchart LR
B1["B1: advertised model-call authority"] --> B2["B2: publication and round pins"]
B2 --> B3["B3: authorized composition"]
B3 --> B4["B4: one continuation"]
B4 --> B5["B5: singular settlement"]
E["99TPLN9I B1: atomic edit"] -.-> B4
B2 -.-> L["99TPLN9I B3: request loadout"]
B3 -.-> U["99TPLN9I B5: usage attribution"]
Interface structure
Core owns semantic run/queue/terminal state; harness owns plugin identity, grants, generation bindings, bounded kernels, child orchestration, and ordered handler dispatch. Typed boundary actions and round pins live in shared vocabulary; no Wasmtime types, futures, or harness dependencies leak into core/RPC. Candidate registration, authority checks, action validation, and effect intent publication precede guest operational effects. Names of new harness modules are chosen by their first real consumer, not a speculative manager hierarchy.
flowchart TB
W["Ordinary wasm components"] --> I["smith:plugin typed calls and actions"]
I --> H["smith-harness: authority, pins, budgets, handlers"]
H --> C["smith-core: run boundaries, queue, durable effects"]
C --> R["smith-rpc: wait and status"]
H --> CLI["smith-cli: shared eval runtime"]
Arrows show runtime handoffs, not imports. Harness drives core through its permitted dependency; core receives immutable shared records and returns semantic outcomes without importing harness types.
Verification and stop conditions
- Every new test file names
SMH-SPEC-PLUG0001; persistence/accounting tests reference their owningSMH-SPEC-SPEC0001sentences. - Run fresh scoped host/guest
cargo x check,cargo x e2e, docs and architecture gates after integrated slices; full relevant gates before completion. - Snapshot typed diagnostics, normalized lifecycle traces, and LF-only RPC lines; redact IDs, never authority-relevant fields.
- Property tests prove scope intersection never widens, conflict validation is deterministic, and rejected action batches preserve state.
- Exact size/allocation bounds cover shared handles, loadouts, action batches, child work, and error paths; scoped mutants target authorization, pin retention, coalescing, and settlement guards.
- Two real consumers and the naming/glossary audit gate every world-shape change; prototype permits breaking changes, not relaxed sandbox laws.
- Keep instruction budgets unchanged unless separately authorized; profile regressions rather than silently changing pins.
- Stop if a guest can forge caller authority, operational work begins during candidate registration, or nested scopes/budgets can widen.
- Stop if disabled/unadvertised model calls reach native fallback, handler failure publishes partial actions, or recording failure is catchable.
- Stop if guest/child work outlives its parent/run, settlement starts reentrant work, or frontend status reports settled before cleanup and handlers finish.
- Stop for missing prerequisite host contracts; do not expand this plan into general harness, provider/OAuth, scripting, or SDK-facility delivery.
Draft creation proves no implementation state.