# @mono-agent/runtime-adapter

Use this package when a typed host needs mono-agent's stable runtime facade
without importing provider-kernel internals.

## Category

<!-- package-metadata:start -->
<!-- Generated by scripts/generate-package-docs.mjs. Do not edit by hand. -->

Category: `runtime`
Tier: `core`
Catalog responsibility: Wraps @mono-agent/agent-runtime behind runtime contracts and owns sandbox policy/process wrapping.

<!-- package-metadata:end -->

## Responsibility

Typed runtime facade over `@mono-agent/agent-runtime`. It parses runtime model references, selects or validates execution mode, exposes the available backend matrix, owns sandbox policy/process wrapping, bridges the kernel's structural process-job controller to a typed neutral host interface, creates a runtime wrapper, and exposes a small structural runtime contract to the harness.

## Install / Usage

```bash
pnpm add @mono-agent/runtime-adapter
```

<!-- doc-test:typescript -->

```ts
import {
  createMonoRuntime,
  parseMonoRuntimeModelReference,
} from "@mono-agent/runtime-adapter";

const model = parseMonoRuntimeModelReference("pi:openai:gpt-5.5");
const runtime = createMonoRuntime({ workspace: process.cwd() });
const result = await runtime.run("You are a concise assistant.", {
  model,
  executionMode: "sdk",
  messages: [{ role: "user", content: "Summarize README.md." }],
  abortSignal: new AbortController().signal,
  cwd: process.cwd(),
  allowedTools: ["Read"],
});

if (result.error) throw new Error(result.error);
console.log(result.text);
```

Use this package when a TypeScript host needs the mono-agent runtime contract.
Use `@mono-agent/agent-runtime` directly only when the host deliberately owns
the lower-level sandbox injection and provider-kernel integration.
Set `RuntimeRunOptions.piToolExecutionMode` to `"sequential"` when every Pi
tool must serialize, or leave the default `"safe-parallel"` mode to overlap
only independent read-only built-ins. Stateful, mutating, and MCP tools remain
sequential in the default mode.

Provider-owned project discovery is opt-in at this facade. For Claude SDK runs,
`RuntimeRunOptions.settingSources` accepts `"user"`, `"project"`, and `"local"`;
omitted/empty disables those filesystem sources while Anthropic managed
settings remain in force. Each opted-in source may configure executable hooks
and plugins. Enable only sources whose settings you trust, and avoid opting in
while running in an untrusted checkout. For Codex app-server runs,
`RuntimeRunOptions.codexLoadProjectDocs: true` restores Codex's native project
document defaults; omitted/false disables automatic discovery with
`project_doc_max_bytes=0`. Explicit `codexAppServerArgs` remain authoritative.
`RuntimeRunOptions.codexSandboxNetworkAccess` is also code-only: strict `true`
enables Codex's native network access for plan/read-only and
default/acceptEdits/workspace-write turns, including retained threads. Omitted
or any other runtime value keeps network access disabled. The dedicated
no-tools probe always remains read-only with network disabled, while
bypassPermissions remains danger-full-access regardless of this field.
This provider-native control is unrelated to `RuntimeRunOptions.sandboxPolicy`,
which governs mono-agent's own sandbox and is not consumed by Codex's tool loop.
Workspace-write plus network access grants repository read and network egress
in the same turn; prefer plan for read-only browsing.
Codex owns its native collaboration agents and their profiles: the facade
normalizes their activity but does not inject `nativeSubagents` definitions.
`RuntimeRunOptions.nativeSubagents` is the typed Claude-native `Task` profile
contract; a non-empty list on a direct Codex attempt returns a capability
mismatch so a fallback router can continue. Use `codexLoadProjectDocs` to let
Codex and its own agents load repository instructions.

For heterogeneous fallback chains, `resolveAttempt().policyOptions` may project
only `allowedTools`, `disallowedTools`, and `permissionMode` for the runtime
actually being attempted. Other logical request fields, including
`codexSandboxNetworkAccess`, remain protected and cannot be replaced through
`resolveAttempt().options`.

`RuntimeRunOptions.toolLifecycleSink` is the typed incremental persistence seam
for managed tools. It receives an invocation with stable call id/name,
and redaction-eligible arguments, then exactly one result
with `success`, `rejected`, `error`, `exit_nonzero`, `timeout`, `signal`,
`cancelled`, or `interrupted`, an existing observability failure kind, optional
detail/duration, bounded-content input, and host artifact paths. The awaited
return exposes only stable record/sequence, persistence and truncation/byte
metadata, and opaque artifact references. Hosts should make this sink
idempotent: a retry of an identical phase returns the same record and a
conflicting retry fails rather than overwriting history.

## Architecture

`runtime-adapter` is the typed boundary between harness code and the JavaScript
provider kernel:

### Data flow

1. Model helpers parse and validate a canonical reference and execution mode.
2. `createMonoRuntime()` injects the mono-agent sandbox implementation exactly
   once, then constructs either one runtime or an ordered fallback router.
3. `MonoRuntimeLike` exposes `run()`, acknowledged live-input messages, an
   awaited incremental tool-lifecycle sink, tool reconfiguration, and bounded
   provider session lifecycle methods to `agent-harness`.
4. Local-provider and MCP helpers translate host config into provider-neutral
   runtime options without importing channel or application code.
5. `bridgeProcessJobsController()` validates host limits and adapts the typed
   process-job controller to the kernel's JSDoc-only structural shape.

### Package structure

| Source file | Responsibility |
| --- | --- |
| `src/runtime-adapter.ts` | Model parsing, backend descriptors, facade construction, and fallback routing |
| `src/types.ts` | Structural runtime, result, event, live-input, approval, and session contracts |
| `src/sandbox*.ts` | Sandbox policy, managed SRT integrity, and command wrapping |
| `src/local-providers.ts` | Ollama, LM Studio, and OpenAI-compatible provider validation/discovery |
| `src/mcp-servers.ts` / `src/runtime-policies.ts` | MCP normalization and legacy-policy migration |
| `src/process-jobs.ts` | Typed host controller, kernel-shape bridge, launch/result contracts, and conformance boundary |

## Public API

### Start here

| API | Use it for |
| --- | --- |
| `createMonoRuntime()` | Construct the typed runtime facade and inject mono-agent's sandbox implementation |
| `probeAcpProfile()` / ACP management helpers | Operate a host-resolved ACP profile while injecting the same sandbox implementation |
| `parseMonoRuntimeModelReference()` | Parse and validate a canonical model string |
| `listMonoRuntimeBackends()` / `describeMonoRuntimeSupport()` / `monoRuntimeSupportsLiveInput()` | Present backend capabilities and compatibility without starting a provider |
| `createSandboxPolicy()` / `failClosedSandboxPolicy()` | Build explicit filesystem and network policy data |
| `discoverLocalProviderModels()` / `runtimeOptionsForLocalProvider()` | Validate and project a configured local Pi provider |
| `parseMcpServers()` | Normalize HTTP, SSE, and stdio MCP server definitions |
| `RuntimeToolLifecycleSink` and event/persistence types | Bind one host-owned durable lifecycle writer without importing provider internals |
| `bridgeProcessJobsController()` / `ProcessJobsController` | Inject a typed host-owned process-job controller without making the kernel import workspace contracts |

The generated inventory below is exhaustive; the table above is the recommended
consumer entry path.

<!-- public-api-inventory:start -->
<!-- Generated by scripts/generate-public-api-docs.mjs. Do not edit by hand. -->

Every symbol exported by each public code entrypoint is listed below.

**`@mono-agent/runtime-adapter`**

```text
AcpCallbackContext
AcpInteractionRequest
AcpProfileDescriptor
AgentRuntimeCustomModel
AgentRuntimeCustomProvider
CodedError
CreateMonoRuntimeOptions
DEFAULT_DENY_WRITE
DiscoverLocalProviderModelsOptions
DiscoveredLocalModel
LocalProviderCapabilities
LocalProviderDefinition
LocalProviderModelDefinition
LocalProviderPricing
LocalProviderRuntimeOptions
LocalProviderType
MANAGED_SRT_TREE_SHA256
ModelEffortLevels
MonoAcpControlOptions
MonoAcpInteractionHandler
MonoAcpInteractionRequest
MonoAcpListSessionsRequest
MonoAcpProfileResolver
MonoAcpSessionControlOptions
MonoRuntimeApprovalDecision
MonoRuntimeApprovalRequest
MonoRuntimeAttemptContext
MonoRuntimeAttemptResolution
MonoRuntimeAttemptResolver
MonoRuntimeBackendCapabilities
MonoRuntimeBackendDescriptor
MonoRuntimeBackendId
MonoRuntimeBackendTransport
MonoRuntimeCompactionRecord
MonoRuntimeFallbackChainEntry
MonoRuntimeHostOptions
MonoRuntimeLike
MonoRuntimeParsedPricingModel
MonoRuntimePricing
MonoRuntimeRetryPolicy
MonoRuntimeRouteSafetyMode
MonoRuntimeSandboxEngine
MonoRuntimeSelectionEntry
MonoRuntimeSupportDescription
NormalizedMcpServer
NormalizedMcpTransport
PI_TRANSPORTS
PiTransport
PrepareSandboxedCommandInput
PreparedSandboxCommand
ProcessJobLaunchOptions
ProcessJobProcessHandle
ProcessJobProcessResult
ProcessJobStartRequest
ProcessJobStartResult
ProcessJobsController
RuntimeAdapterError
RuntimeAdapterErrorCode
RuntimeAdapterErrorDetails
RuntimeCompactionPolicy
RuntimeEventLike
RuntimeExecutionMode
RuntimeLiveInputMessage
RuntimeMcpAppConnection
RuntimeMcpAppHost
RuntimeMcpAppRegistration
RuntimeMessage
RuntimeModelReference
RuntimeNativeSubagentDefinition
RuntimeNativeSubagentsOptions
RuntimePolicies
RuntimePromptOverrides
RuntimeResult
RuntimeRunOptions
RuntimeSubagentActivityEvent
RuntimeSubagentActivityPhase
RuntimeSubagentIdentity
RuntimeToolLifecycleEvent
RuntimeToolLifecyclePersistence
RuntimeToolLifecycleSink
RuntimeToolLifecycleTerminalState
RuntimeToolLimits
RuntimeToolOptions
SANDBOX_FALLBACKS
SANDBOX_MODES
SANDBOX_NETWORK_MODES
SandboxCommandSpec
SandboxEffectiveMode
SandboxEffectiveState
SandboxEngine
SandboxEngineId
SandboxErrorCode
SandboxFallback
SandboxMode
SandboxNetworkMode
SandboxNetworkPolicy
SandboxNetworkPolicyInput
SandboxPolicy
SandboxPolicyError
SandboxPolicyInput
SandboxPolicyRuntimeOptions
SandboxUnavailableError
SrtFilesystemSettings
SrtNetworkSettings
SrtSandboxEngineOptions
SrtSettings
assertExecutionModeCompatible
assertParsedRuntimeModelReference
authenticateAcpProfile
bridgeProcessJobsController
createMonoRuntime
createPiOAuthApiKeyResolver
createSandboxPolicy
createSrtSandboxEngine
defaultExecutionModeForModel
deleteAcpSession
describeMonoRuntimeSupport
describeSandboxEffectiveState
discoverClaudeSdkModels
discoverLocalProviderModels
failClosedSandboxPolicy
inspectCodexSubscriptionSearch
isCodedError
isPlainObject
isPrivateBaseUrl
isRuntimeExecutionMode
isRuntimeSubagentActivityEvent
isValidMcpServerName
listAcpSessions
listMonoRuntimeBackends
logoutAcpProfile
managedSrtInstallRoot
mergeSandboxPolicies
modelReferenceKey
monoRuntimeSupportsLiveInput
monoRuntimeSupportsMcpApps
monoRuntimeSupportsSessionResume
networkPolicyAllowsUrl
parseMcpServers
parseMonoRuntimeModelReference
prepareSandboxedCommand
probeAcpProfile
protectSandboxRoots
resolveModelEffortLevels
resolveRuntimePolicies
resolveSandboxEffectiveState
runtimeBackendForModel
runtimeOptionsForLocalProvider
sandboxEffectiveStateWarning
sandboxPolicyToRuntimeOptions
sandboxRequired
selectMonoRuntimeBackendId
srtSettingsForPolicy
validateLocalProviderDefinition
```

<!-- public-api-inventory:end -->

Supported backend seams are exposed as data:

| Backend | Model refs | Execution mode | Boundary |
| --- | --- | --- | --- |
| ACP v1 stdio | `acp:<profile-id>` | `acp` | Strict bounded ACP client through `@mono-agent/agent-runtime` |
| Claude SDK | `claude:<model>` | `sdk` | Claude SDK through `@mono-agent/agent-runtime` |
| Claude Code CLI | `claude:<model>` | `cli` | Claude Code CLI bridge through `@mono-agent/agent-runtime` |
| Codex app CLI | `codex:<model>` | `cli` | Codex app-server bridge through `@mono-agent/agent-runtime` |
| OpenCode app CLI | `opencode:<provider>:<model>` | `cli` | OpenCode app-server bridge through `@mono-agent/agent-runtime` |
| Pi SDK provider | `pi:<provider>:<model>` | `sdk` | Pi SDK gateway, including provider ids such as `openai-codex` or Copilot-style provider ids |

Claude Code CLI settings discovery is provider-owned and does not consume
`settingSources`. Claude-native teammate definitions add `Task` to an explicit
allowlist automatically; callers using only filesystem `.claude/agents`
profiles must include `Task` themselves. The kernel's in-process delegation
surface similarly requires `Agent`. Direct Codex accepts only an effective
allow-all policy, so restrictive named allowlists fail before provider startup.

Native and in-process delegation paths emit the exact
`RuntimeSubagentActivityEvent` shape: `subagent.id` is the canonical parent
attachment key (normally the initiating parent tool-use id, with a stable
synthetic fallback for orphan lifecycle records), while optional `nativeId` and
`agentPath` retain provider correlation metadata. Its
`RuntimeSubagentActivityPhase` phases are `agent_started`, `started`,
`completed`, `message`, and `agent_completed`; child `message` activity is never
parent answer text or a tool completion. `RuntimeEventLike` remains permissive
for other provider telemetry; use `isRuntimeSubagentActivityEvent()` to narrow
an open event before consuming the required normalized fields.

### ACP v1 profiles

ACP is a dedicated transport mode, not a CLI alias: persist and pass the tuple
`sdk: "acp"`, model `acp:<profile-id>`, and `executionMode: "acp"`. Supply a
typed `resolveAcpProfile` callback to `createMonoRuntime()` or the individual
run. `onAcpInteractionRequest` handles host permission and elicitation requests
when a profile-specific callback is absent. Bind one host-owned exact 32-byte
binary `acpSessionTokenKey` at `createMonoRuntime()` (or on each ACP run) and
keep it stable across restarts. The key is required for every ACP task run and
for every operation that emits or consumes a session handle.

The exported `probeAcpProfile`, `authenticateAcpProfile`, `logoutAcpProfile`,
`listAcpSessions`, and `deleteAcpSession` wrappers accept the same resolver and
policy context. `listAcpSessions` and `deleteAcpSession` require
`MonoAcpSessionControlOptions`, including `acpSessionTokenKey`; probe,
authentication, and logout do not consume handles and leave the key optional.
The confidential authenticated v2 handles must be preserved byte-for-byte and
must not be compared for equality. Legacy v1 handles are rejected. The wrappers
deliberately do not accept a caller-provided sandbox implementation:
runtime-adapter injects its owned implementation before calling the
product-neutral kernel. The underlying agent service is never managed or
stopped; only the operation-owned stdio bridge process is reaped.

### Local Pi providers

`runtimeOptionsForLocalProvider()` converts host config into the custom-provider context expected by `@mono-agent/agent-runtime`'s Pi adapter. It only returns options when the parsed model is `pi:<provider>:<model>` and `<provider>` matches a configured local provider. Built-in Pi providers such as `pi:openai-codex:gpt-5.5` return `{}`.

Built-in Pi OAuth providers still need credentials. Use
`createPiOAuthApiKeyResolver({ path })` and pass it to `createMonoRuntime()` as
`resolvePiApiKey` when the host owns an auth JSON file such as
`~/.pi/agent/auth.json`.

Ollama example:

```ts
import {
  parseMonoRuntimeModelReference,
  runtimeOptionsForLocalProvider,
} from "@mono-agent/runtime-adapter";

const model = parseMonoRuntimeModelReference("pi:ollama:qwen3:8b");
const runtimeOptions = runtimeOptionsForLocalProvider(model, [
  {
    id: "ollama",
    type: "ollama",
    baseUrl: "http://localhost:11434",
    enabled: true,
    models: [
      { name: "qwen3:8b", capabilities: { context_window: 32768 } },
    ],
  },
]);
```

Private HTTP(S) URLs such as `localhost`, RFC1918 addresses, and Tailscale CGNAT addresses are allowed. Public hosts require `https://` plus `trustPublicUrl: true`; invalid local-provider config throws `RuntimeAdapterError` instead of falling back to a hosted provider.

### Route safety and managed SRT

`uniform` fallback safety reuses one monotonic runtime contract and fails closed
when a route cannot represent a required capability. Explicit
`per-route-native` creates isolated provider runtimes: Pi retains mono-agent
tool policy and uses SRT only when an effective native sandbox policy is active
(otherwise telemetry says `disabled` and subprocess tools are unsandboxed),
Claude drops only the unrepresentable mono-agent SRT layer, and direct
Codex/OpenCode use provider-native safety with an effective allow-all policy
(allowlist omitted or containing `"*"`, empty denylist). That projection is
available only when the effective internal `sandboxPolicy.protectedRoots` is
empty: a provider-native non-Pi route carrying protected roots is rejected as
`safety_unavailable` before its resolver or provider runs. This also covers a
named `Agent` child that inherits a protected parent policy. Capability-bearing
inputs are never silently discarded; an unsupported route is skipped with
bounded, credential-free safety telemetry.

On macOS, the default SRT resolver prefers the integrity-verified managed copy in
the private mono-agent cache. It revalidates the managed tree against an
independently pinned digest before each launch. A present but corrupt managed
install fails closed and never downgrades to an external `srt`; the external
command is considered only when the managed path is absent. External and
explicit commands are canonicalized to absolute trusted files, pinned by content
and filesystem identity after their functional proof, and revalidated before
use. Generated filesystem policy denies global reads first, then reopens only
configured roots, reviewed immutable OS paths, and narrowly derived runtime
dependencies; relative deny-write globs stay anchored to the policy root.

Application hosts can pass `trustedReadRoots` to `createSrtSandboxEngine` for
host-owned execution state such as the active managed agent-app closure. Those
roots are canonicalized once, remain readable after request-policy
intersection, are never widened to their parent directory, and are always
added to `denyWrite`. This is not a config surface for model- or user-supplied
paths.

The Node executable that starts a managed or explicit SRT CLI must also be
single-link, executable without setuid/setgid privilege bits, current-user- or
root-owned, and not group/world-writable. This is a path-sandbox invariant, not
only a cross-principal ownership check: an unseen hardlink alias inside a writable
root could expose a user-owned launcher inode to the same-UID sandboxed workload,
while no portable API can enumerate all aliases.
NVM, Homebrew Cellar, system Node, and hosted toolcache paths are accepted without
path allowlisting when their selected executable satisfies that contract. A
multiple-link rejection names the observed link count and directs the operator
to a single-link Node installation. Managed cache files and standalone SRT
executables retain the same single-link rule independently. Explicit Node+CLI
resolution fails closed on Windows or another platform without POSIX uid
ownership checks instead of treating POSIX-looking mode bits as NTFS authority.

## Dependency Boundary

This is the only facade package that depends on `@mono-agent/agent-runtime`. Other packages consume its small `MonoRuntimeLike` interface, backend descriptors, and sandbox policy helpers instead of importing provider/runtime internals.

## What This Package Does Not Own

It does not build prompts, manage memory, expose UI, poll communication channels, or persist observability artifacts.

## Related Documentation

- [Runtime and providers](https://mono-agent-docs.vercel.app/runtime/) explains the normal
  config-first path.
- [Backends and model references](https://mono-agent-docs.vercel.app/runtime/backends/)
  documents the five bridge selections surfaced by this facade.
- [Local providers](https://mono-agent-docs.vercel.app/runtime/local-providers/) covers
  Ollama, LM Studio, and compatible gateways.
- [Sandboxing](https://mono-agent-docs.vercel.app/tools/sandbox/) describes the policy that
  this package validates and enforces through managed SRT.
- [`@mono-agent/agent-runtime`](https://github.com/robertsreberski/mono-agent/tree/main/packages/agent-runtime)
  owns the underlying provider kernel.

## Verification

```bash
pnpm --filter @mono-agent/runtime-adapter run build
pnpm --filter @mono-agent/runtime-adapter run typecheck
pnpm --filter @mono-agent/runtime-adapter run test
```
