ELNOR REPO READER TEXT MIRROR Original path: Current Specs/DOC11/DOC11_PROPOSAL_EXTERNAL_AGENT_ENGINE_ADAPTER.md Source repo: /Users/OpenClaw1/Elnor/Elnor Specs Git branch: main Git commit: dbaa25962edc11ab30e8d4ca1715f9ae5bf77331 Generated: 2026-06-09T01:23:58.539Z --- # DOC11 — External Agent Engine Adapter (PROPOSAL) **Status:** proposal — for architect review + red team; **not operative.** No existing file is modified by this document; it binds to other specs by reference only. **Target owner doc:** DOC11 (OpenClaw Gateway-First runtime truth, model controls, usage telemetry, EC/Q integration). **Compatibility:** operative **DOC11 R14** (`DOC11_OPENCLAW_GATEWAY_MODEL_CONTROLS_AND_EC_INTEGRATION_R14.md`, v1.11.30 R14) **and** pending **R15** (`DOC11_R15_OPENCLAW_RELEASE_ALIGNMENT_AMENDMENT_PROPOSAL_R3.md`). See §10. **Primary source of truth (the brief):** `OP-A and Operations and Trackers/CAPABILITY_NOTE_EXTERNAL_AGENT_CLI_ADAPTERS.md` (architect-approved 2026-06-04; full headless loop verified 2026-06-04 on subscription auth). **Date:** 2026-06-04 · **Architect:** Will Brody. --- ## 0. Scope, ownership boundary, and how to read this ### 0.1 What this capability is ELNOR drives external coding/review engines **headlessly** — on the architect's **subscriptions**, not per-token API billing where avoidable — with engine routing, model/think controls, billing-path discipline, run provenance/telemetry, and EC policy gating. The capability is operationally proven (capability note §1: Codex `LOOP_CONFIRMED` 2026-06-04, no API key; Claude Code in daily headless use). This is squarely DOC11's existing job: the adapter mostly **reports runtime truth about, and exposes controls over, engine/runtime machinery OpenClaw already provides** (provider/model/runtime selection, auth-source, billing path), plus an **EC-driven external-invocation bridge** for the arms-length (file-bus) case. It introduces no new truth store and no second prompt-control language. ### 0.2 Ownership boundary — what this proposal OWNS vs REFERENCES | Concern | Owner | This proposal | |---|---|---| | Engine/agent registry, adapter/invocation contracts, runtime truth of engines | **DOC11 (this doc)** | defines | | `ResolvedEnginePlan`, manual override, `routing_mode`, why-routed telemetry | **DOC11 (this doc)** | defines | | Billing-path assertion + per-engine tier/billing rules + plan meters | **DOC11 (this doc)** | defines | | Run provenance + usage telemetry integration | **DOC11 (this doc)** | defines, extends R14 telemetry | | **Routing *policy* engine** (rules/signals/weights deciding *which* engine) | **separate future spec** (provisional `DOC-ROUTING`) | **referenced**, not defined (§3.5) | | **Reverse MCP server** (ELNOR exposed to external LLMs = `mcp_pull`) | DOC16 §16.7.4 (config/scope) + DOC24 §17 (scope enforcement) + DOC11 runtime | **referenced**, not built here (§6.4) | | Memory **selection/assembly** of injected context | DOC24 / DOC84 (delivery), DOC72/DOC73 | **referenced**; adapter consumes a rendered packet (§6.4) | | **Egress** classification + delegation MFC | E0 §22 (`E0OutboundDestinationClass`) + §3.3 (`DelegationMFC`) | **referenced, never redefined** (§6.2) | | **Send-time gate / disclosure policy** | DOC81 R2 (send-time gate; §4.0 internal-use-permissive; R-5 multi-principal) | **referenced, never redefined** (§6.2, §9) | | **Credential providers, secret leases, account setup, action/egress gate** | **DOC5** (security/auth/credential plane, in planning) | **referenced**; adapter states hygiene inline now and **re-homes to DOC5** when it lands (§6.3) | | Cost/billing-tier rows, quota/usage views | DOC13 | **obligation** (§8) | | Engines settings panel render, auth-source indicator, credit meter UI | DOC20 | **obligation** (§8) | | External agents as multi-agent room participants / ACP | DOC12 + OpenClaw ACP / Codex Supervisor | **obligation** (§8) | | EC policy-evaluator socket + durable run/receipt writes | EC Core | **obligation** (§8) | ### 0.3 No-phantom statement Every contract, field, lint, and fixture below traces to the capability note, DOC11 R14/R15, E0/DOC81, the live OpenClaw runtime docs, or Anthropic's published billing policy — or it is flagged `OPEN_FOR_ARCHITECT_REVIEW` in §11 (5 items, the cap). DOC11 R14 conventions are matched: branded `*_ref` types, `schema_owner`, capability-evidence labels (`native_probed | native_documented_not_probed | wrapper_composed | unsupported | advisory_only`, R14 §0.4), desired/effective/executed truth, settings-only honesty, and DOC10 XDI companion-ledger rows for every cross-doc obligation (R14 §0.7). --- ## 1. The model: three orthogonal axes, aligned to OpenClaw's real runtime model The earlier "native backend vs external delegate" binary is replaced by the way OpenClaw actually works (live docs, `concepts/agent-runtimes`): a **provider × runtime** matrix, several rows of which are subscription-authed with no per-token fee, all OpenClaw-orchestrated. The adapter models **three orthogonal axes**: 1. **`engine`** — vendor/product family: `claude | openai_codex | gemini`. 2. **`invocation_topology`** — *who runs the loop and where*, mapped to OpenClaw runtime ids where applicable. 3. **`memory_access_mode`** — how the run reaches ELNOR memory: `native_push | mcp_pull | none`. (Context level, including "no context", is therefore a setting on any topology — decoupled from the topology choice.) ```ts type EngineFamily = "claude" | "openai_codex" | "gemini"; type InvocationTopology = | "openclaw_runtime_pi" // OpenClaw PI runner; e.g. Codex OAuth provider route (openai + ChatGPT/Codex OAuth). OpenClaw owns the full loop. | "openclaw_runtime_codex" // OpenClaw bundled Codex app-server runtime (agentRuntime.id="codex"); Codex owns more of the loop, OpenClaw mirrors/projects. | "openclaw_runtime_claude_cli"// OpenClaw claude-cli backend (agentRuntime.id="claude-cli"; claude -p). OpenClaw drives the local claude binary. | "openclaw_acp" // OpenClaw ACP/acpx control plane for external harnesses (Claude Code, Gemini CLI, OpenCode, Cursor). | "ec_external_cli" // EC drives an external CLI (codex exec / claude -p / gemini) directly, outside OpenClaw, via the file bus. | "ec_external_sdk_embedded" // EC embeds an SDK in-process (Claude Agent SDK / Codex SDK) outside OpenClaw. | "raw_api" // direct provider API (per-token). | "local"; // local model. type MemoryAccessMode = "native_push" | "mcp_pull" | "none"; type BillingTier = "T1_subscription" | "T2_api" | "T3_local"; // capability note §5 ``` Reference map (engine × topology × billing), traceable to OpenClaw docs + capability note §5 + Anthropic policy (§4): | Engine | Topology | Auth source | Billing | Loop owner | Evidence label (until probed) | |---|---|---|---|---|---| | openai_codex | `openclaw_runtime_pi` | ChatGPT/Codex OAuth | **T1 flat** | OpenClaw (PI) | `native_documented_not_probed` | | openai_codex | `openclaw_runtime_codex` | ChatGPT/Codex OAuth | **T1 flat** | Codex app-server (mirrored) | `native_documented_not_probed` | | openai_codex | `ec_external_cli` (`codex exec`) | ChatGPT/Codex OAuth | **T1 flat** | Codex | **`native_probed`** (LOOP_CONFIRMED 2026-06-04) | | claude | `openclaw_runtime_claude_cli` (`claude -p`) | Claude subscription (CLI) | **T1 → Agent SDK credit pool** (see §4) | OpenClaw drives `claude` | `native_documented_not_probed` | | claude | `ec_external_sdk_embedded` (Agent SDK) | Claude subscription / setup-token | **T1 → Agent SDK credit pool** | Claude Agent SDK | `wrapper_composed` (in daily use) | | claude / openai_codex | `raw_api` | API key | **T2 per-token** | provider | `native_documented_not_probed` | | any | `local` | — | **T3** | local | per existing local-first arch | > Note (R14 §0.4 honesty): `openclaw_runtime_*` rows are labelled `native_documented_not_probed` because OpenClaw's docs document them as supported/common, but they have not been re-probed on the architect's current build since the April 2026 runtime migration. They flip to `native_probed` after the §11 OPEN-1 verification. They do not block this proposal; `ec_external_cli` (Codex) is proven. --- ## 2. Engine registry + adapter contracts ### 2.1 EngineDescriptor ```ts type Brand = T & { readonly __brand: B }; type EngineDescriptorRef = Brand; type EngineRunRef = Brand; type SessionRef = Brand; type ReasonCodeId = Brand; interface EngineDescriptor { engine_descriptor_ref: EngineDescriptorRef; schema_owner: "DOC11"; engine: EngineFamily; invocation_topology: InvocationTopology; // version pinning + drift check (capability note §3 rule 5) pinned_version: string; // e.g. codex-cli 0.137.0, claude-code 2.1.162, codex-sdk 0.137.0, agent-sdk 0.3.162 observed_version?: string; // probed at run time version_drift_state: "match" | "drift_detected" | "unknown"; // auth + billing auth_source: "subscription_oauth" | "subscription_cli" | "setup_token" | "api_key" | "local_none"; billing_tier: BillingTier; expected_billing_path: "flat_subscription" | "agent_sdk_credit" | "per_token_api" | "local"; // asserted before every run (§4) // runtime truth (R14 desired/effective/executed) login_status: "logged_in" | "expired" | "reauth_required" | "missing" | "unknown"; health: "healthy" | "degraded" | "unavailable" | "unknown"; evidence_label: "native_probed" | "native_documented_not_probed" | "wrapper_composed" | "unsupported" | "advisory_only"; last_verified_at?: string; user_visible_message?: string; } ``` ### 2.2 Invocation contracts (one-shot, resumed-session, embedded-SDK) Maps to the capability note §1 interfaces and OpenClaw runtime selection. ```ts type SandboxMode = "read_only" | "workspace_write_scoped" | "workspace_write_full"; // least-privilege default = read_only interface EngineInvocation { engine_run_ref: EngineRunRef; schema_owner: "DOC11"; engine_descriptor_ref: EngineDescriptorRef; mode: "one_shot" | "resumed_session" | "embedded_sdk_session"; // working directory + sandbox discipline (capability note §3 rule 6; least-privilege by role) working_dir: string; // scoped to the task; report folder for write roles sandbox_mode: SandboxMode; permission_mode: string; // engine-native permission mode / allowlist gate (EC-consulted, §6.1) tool_allowlist: string[]; // session continuity (capability note §1: codex exec resume; claude -p --resume; SDK session id) session_ref?: SessionRef; // ELNOR<->engine session mapping; stamped on provenance // memory memory_access_mode: MemoryAccessMode; // native_push | mcp_pull | none (§6.4) injected_packet_ref?: string; // when native_push: a DOC24/DOC84-rendered packet (reference; adapter does not assemble) // the resolved plan a run consumes (§3) resolved_plan_ref: string; } ``` **Defaults (capability note §3 rule 6):** review/audit roles default `sandbox_mode = read_only`; report-writer roles get `workspace_write_scoped` to the report folder; `workspace_write_full` requires explicit per-run architect grant. All auth material is supplied to the engine process out-of-band, never via prompt/args that could be logged (§6.3). ### 2.3 Routes / read-models / events (R14 idiom) ``` POST /api/engines/run -> start an EngineInvocation, returns engine_run_ref GET /api/engines/registry -> EngineDescriptor[] (runtime truth read-model) GET /api/engines/run/{ref} -> AgentRunRecord (provenance + status, §5) POST /api/engines/run/{ref}/abort -> STOP propagation (R14 abort/STOP seam) ``` Events (non-durable progress per R14 streaming rules; durable facts to EC §5): `engine.run.started`, `engine.run.progress`, `engine.run.completed`, `engine.run.failed`, `engine.run.blocked`, `engine.billing_path_asserted`, `engine.credit_warning`. --- ## 3. Per-role routing **seam** (the policy engine is a separate spec) ### 3.1 Routing targets and named agents A **named agent** is a saved bundle (engine / topology / model / think-level / memory-mode / permission / tool-allowlist) and is a first-class routing target. The adapter stores the bundle; *which* target a request routes to is a policy decision owned elsewhere (§3.5). ```ts type ThinkLevel = "off" | "low" | "medium" | "high" | "max"; // thinking-token budget (capability note §6) interface RoutingTargetBundle { target_ref: string; // engine bundle or named agent schema_owner: "DOC11"; display_label: string; engine: EngineFamily; invocation_topology: InvocationTopology; model: string; think_level: ThinkLevel; permission_mode: string; tool_allowlist: string[]; memory_access_mode: MemoryAccessMode; billing_tier: BillingTier; } ``` ### 3.2 ResolvedEnginePlan — what a run consumes (DOC11 owns this) ```ts interface ResolvedEnginePlan { resolved_plan_ref: string; schema_owner: "DOC11"; engine: EngineFamily; invocation_topology: InvocationTopology; model: string; think_level: ThinkLevel; permission_mode: string; tool_allowlist: string[]; memory_access_mode: MemoryAccessMode; billing_tier: BillingTier; routing_mode: "manual" | "suggest" | "auto"; decided_by: "manual_override" | "named_agent" | "policy_rule" | "default"; why_routed_trace_ref?: string; // never a black box; rendered in Inspector ec_policy_consulted: boolean; // routing is policy-respecting (§6.1) } ``` ### 3.3 Routing mode + override `routing_mode` is scoped (global default / per-named-agent / per-conversation / per-run) and defaults to **`manual`** (or `suggest`). **Manual override always wins.** This honors the architect decision that automatic routing is deferred; the adapter ships the *seam* (inputs + recorded output), not an auto-router. ### 3.4 Lints ``` engine.run_without_resolved_plan engine.named_agent_target_unknown engine.routing_decision_without_trace // why-routed must exist when decided_by != manual_override ``` ### 3.5 The routing **policy** engine is referenced, not defined here The rules/signals/weights that *decide* a target (cost from DOC13, plan-window pressure, sensitivity from DOC81, subject tags, learned engine performance) belong to a separate spec (provisional `DOC-ROUTING`). DOC11 supplies the **inputs** (the registry + runtime truth) and records the **output** (`ResolvedEnginePlan` + why-routed). Cross-doc obligation in §8. --- ## 4. Billing-path discipline (the cost guarantee) ### 4.1 Per-engine billing model (traceable to OpenClaw docs + Anthropic published policy) - **Codex / ChatGPT subscription** → **T1 flat.** OpenAI explicitly supports Codex OAuth in external tools like OpenClaw; no separate programmatic credit cap is surfaced. Default for heavy/long/bulk agentic runs. - **Claude subscription** → **T1, but metered to the Agent SDK credit pool.** Per Anthropic's help center, starting **2026-06-15** the Agent SDK and `claude -p` no longer count toward interactive plan limits; they draw from a separate **monthly Agent SDK credit** (Pro $20 / Max 5x $100 / Max 20x $200), at standard API rates, no rollover; past the credit, usage flows to API rates only if usage credits are enabled, else requests stop. `claude -p` (headless) is classified as programmatic regardless of being "the CLI"; the interactive subscription bucket has no automation entry point. Therefore **all adapter-driven Claude use is the credit pool, then API.** - **API key (either vendor)** → **T2 per-token** (explicit overflow). - **Local** → **T3.** ### 4.2 Billing-path assertion before every run ```ts interface BillingPathAssertion { engine_run_ref: EngineRunRef; schema_owner: "DOC11"; expected_billing_path: "flat_subscription" | "agent_sdk_credit" | "per_token_api" | "local"; asserted_env_clean_of_api_key: boolean; // the ANTHROPIC_API_KEY-silently-wins trap (capability note §5 rule 1) assertion_result: "pass" | "mismatch_blocked"; reason_codes: ReasonCodeId[]; } ``` The `ANTHROPIC_API_KEY` (and equivalent) silently overrides subscription OAuth, so API keys stay **out of the default agent environment**; the adapter asserts the expected billing path **before every run** and blocks on mismatch. This assertion + no-silent-spill is the mechanism that actually guarantees "use the subscription, save API fees." ### 4.3 Queueing + spill Subscription plans rate-limit (capability note §5 rule 2): the adapter **queues (concurrency 1–2)** and surfaces stalls rather than spinning. **Spill to T2 (raw API) only via an explicit policy toggle with a recorded reason** — never silently. ### 4.4 Claude Agent SDK credit meter ```ts interface ClaudeCreditMeter { schema_owner: "DOC11"; plan_tier: "pro" | "max_5x" | "max_20x" | "unknown"; // OPEN-4: confirm tier for defaults monthly_credit_usd: number; // 20 / 100 / 200 consumed_usd_estimate: number; remaining_usd_estimate: number; reset_at: string; // refreshes with billing cycle, no rollover on_exhaustion: "block" | "spill_to_api_if_enabled"; // OPEN-4 behavior choice; default block warn_threshold_pct: number; // surfaced in DOC20 Engines panel + warning event } ``` ### 4.5 Lints ``` engine.billing_path_mismatch // expected != actual (capability note build lint) engine.api_key_in_default_agent_env // API key present where subscription OAuth expected engine.silent_api_spill // T1 -> T2 without explicit toggle + reason engine.claude_run_without_credit_meter // Claude T1 run not metered against the Agent SDK credit ``` --- ## 5. Run provenance + telemetry ```ts interface AgentRunRecord { engine_run_ref: EngineRunRef; schema_owner: "DOC11"; engine: EngineFamily; invocation_topology: InvocationTopology; model: string; think_level: ThinkLevel; billing_tier: BillingTier; billing_path_actual: "flat_subscription" | "agent_sdk_credit" | "per_token_api" | "local"; auth_source: EngineDescriptor["auth_source"]; sandbox_mode: SandboxMode; session_ref?: SessionRef; memory_access_mode: MemoryAccessMode; credit_consumed_usd_estimate?: number; // for Claude agent_sdk_credit runs evidence_label: EngineDescriptor["evidence_label"]; started_at: string; ended_at?: string; outcome: "success" | "blocked" | "failed" | "degraded" | "requires_user_action"; report_artifact_ref?: string; // file-bus report (§6.5) reason_codes: ReasonCodeId[]; } ``` Provenance integrates with DOC11 R14 usage-telemetry + runtime-truth read-models and is **Inspector-renderable** (capability note §6). It feeds DOC13 cost views (§8) and is the durable signal a future router learns engine performance from (§3.5). The transcript ELNOR renders for `ec_external_*`/`openclaw_*` runs is labelled `wrapper_composed` vs `native_*` per R14 §0.4 — never presented as native Gateway truth when it is reconstructed from a subprocess/CLI stream. Lints: `engine.run_without_provenance`, `engine.wrapper_transcript_labeled_native`. --- ## 6. EC integration, egress, secrets, and memory access (bind by reference) ### 6.1 EC policy-evaluator socket The SDK/engine **permission hooks are the EC policy-evaluator socket** (capability note §6): every agent action the engine wants to take is offered to EC for an allow/deny/confirm decision against the DOC81 R2 gates. Routing is policy-respecting (`ec_policy_consulted`), architect-overridable per run. Obligation: EC §8. ### 6.2 Delegation egress (E0 §22 + DOC81 R2) — referenced, never redefined Delegating to an external agent **is egress**. An invocation that carries memory content is an egress event classified under **E0 §22 `E0OutboundDestinationClass`** (`cloud_api`, `agent_messaging`) and governed by **E0 §3.3 `DelegationMFC`** + the **DOC81 R2 send-time gate** (typed destination → destination-specific decision → send-time gate; `local_file_export` rules apply to artifacts the engines write). This adapter **binds to those contracts by reference and does not redefine them.** ```ts interface DelegationEgressBinding { engine_run_ref: EngineRunRef; schema_owner: "DOC11"; carries_memory_content: boolean; e0_outbound_destination_class_ref: string; // E0 §22 — cloud_api | agent_messaging (referenced) delegation_mfc_ref?: string; // E0 §3.3 (referenced) doc81_send_time_gate_decision_ref?: string; // DOC81 R2 (referenced) } ``` > Note: a cloud model call is `cloud_api` egress whether the topology is OpenClaw-native or external — the gate is topology-agnostic. External topologies *add* the `agent_messaging` surface (handing over a commission/files) and, if `mcp_pull` is on, the agent pulling memory back (§6.4). ### 6.3 Secrets hygiene (inline now; **re-homes to DOC5**) Per capability note §3 rule 8 / §5 rule 4: auth material **never** enters the repo, logs, reports, memory files, prompts, or tool args, and is **never echoed**. Per-engine auth artifacts live in **non-repo folders** (`/Users/OpenClaw1/Elnor/.codex-auth/` pattern; `.claude-auth/` when needed). When the **DOC5** security/credential plane lands, the credential-provider taxonomy, `SecretRef`/`SecretLease` materialization, and the action/egress gate become **DOC5-owned** and this adapter **consumes** them; the bindings in §6.2/§6.4 redirect to DOC5's egress gate (which consumes DOC81). Obligation: DOC5 §8. Lints: `engine.secret_in_repo_log_report_or_memory`, `engine.secret_in_prompt_or_args`. ### 6.4 Memory access modes (and the Reverse MCP server is referenced, not built) - **`native_push`** — EC assembles the same context packet via DOC24 / DOC84 and renders it onto the engine's input surface (prompt or working-dir files). Same selection machinery as native delivery; only the render target differs (a DOC84/KDA delivery-target obligation, §8). Subject to the §6.2 send-time gate. - **`mcp_pull`** — the engine pulls ELNOR memory on demand via the **existing Reverse MCP Server** (DOC16 §16.7.4: *"expose Elnor as an MCP server for external LLMs"*; runtime nominally DOC11, scope enforcement DOC24 §17). This adapter **references** that server; it does **not** define or build it. **Every memory-returning reverse-MCP call is itself an egress** and MUST pass the same §6.2 gate (DOC24 scope enforcement + DOC81/E0). Whether the reverse-MCP runtime stays in DOC11 or moves to DOC5 is OPEN-2. - **`none`** — only prompt + working-dir; the "no context" setting; used deliberately for independent red-team. Lint: `engine.mcp_pull_without_send_time_gate`. ### 6.5 File-bus contract (the durable exchange pattern) For `ec_external_*` topologies, the durable exchange is the proven file bus (capability note §1, §4): commission written into the repo → engine runs against the working dir → report written to a designated folder (e.g. `Reviews/`). The report artifact is captured into `AgentRunRecord.report_artifact_ref` and routed into the normal task-output → extraction pipeline (DOC23/DOC82/DOC25 seams) so memory-saving, extraction, and learning still occur; capture fidelity tracks topology (native > embedded-SDK > CLI) but the pipeline is unchanged. Obligation: §8. --- ## 7. Failure / unhappy paths (per contract) ```ts type EngineFailureMode = | "auth_expired_or_revoked" // -> structured blocked state + re-login flow; NEVER silent API fallback (capability note §3 rule 1) | "version_drift" // pinned != observed -> drift_detected; block or warn per policy | "rate_limit_or_plan_stall" // -> queued/stalled, surfaced (capability note §5 rule 2) | "claude_credit_exhausted" // -> block, or explicit API spill if toggle on (§4.4) | "sandbox_violation" // engine attempted out-of-scope FS/network -> blocked | "network_loss_mid_run" // -> attempt resume via session_ref, else blocked | "orphaned_session" // -> reap or resume via session_ref | "report_not_written" // file-bus report missing -> failed outcome | "billing_path_mismatch"; // §4.2 -> blocked before run interface EngineFailure { engine_run_ref: EngineRunRef; schema_owner: "DOC11"; failure_mode: EngineFailureMode; user_visible_message: string; // structured degraded/blocked state, not silent failure (R14 honesty) recovery_action?: "relogin" | "update_pin" | "wait_or_queue" | "enable_spill" | "resume_session" | "rewrite_report" | "manual"; reason_codes: ReasonCodeId[]; } ``` Hard rule (capability note §3 rule 1; §5 rule 1): on auth failure the adapter surfaces a re-login flow and **never silently falls back to API billing.** Lints: `engine.silent_api_fallback_on_auth_failure`, `engine.failure_without_structured_state`. --- ## 8. Cross-doc obligations (proposed OP-A rows; DOC10 XDI mirror per R14 §0.7) | Target | Obligation | Provisional OP-A id | |---|---|---| | DOC13 | Engine tier cost rows; Claude Agent SDK credit meter; T2 API-spill cost attribution | `OBL-D13-ENGINE-TIER-COST-01` | | DOC13 | Plan-window/quota pressure surfaced for subscription engines | `OBL-D13-ENGINE-QUOTA-PRESSURE-01` | | DOC12 | External agents as room participants where applicable; OpenClaw ACP / Codex Supervisor seam | `OBL-D12-EXTAGENT-ACP-01` | | DOC20 | Engines settings panel: per-role engine/topology/model/think/permission/tool-allowlist; **auth-source indicator**; **Claude credit meter**; why-routed view; plan-usage meter | `OBL-D20-ENGINES-PANEL-01` | | EC Core | Engine permission-hook contract (policy-evaluator socket); durable `AgentRunRecord` + receipts writes | `OBL-EC-ENGINE-PERMISSION-HOOK-01` | | DOC16/DOC24/DOC11-runtime | Reverse MCP server is the `mcp_pull` surface; every memory-returning call gated | `OBL-D16-REVERSE-MCP-PULL-GATE-01` | | DOC24 / DOC84 (KDA) | "render context packet for external-agent surface" delivery target (for `native_push`) | `OBL-D84-EXTAGENT-PACKET-RENDER-01` | | DOC23/DOC82/DOC25 | Route engine file-bus reports into the task-output → extraction pipeline | `OBL-D23-EXTAGENT-OUTPUT-INTAKE-01` | | DOC5 (future) | Re-home credential providers / `SecretLease` / action+egress gate; adapter consumes | `OBL-D5-ENGINE-CRED-REHOME-01` | | Routing policy spec (future) | Owns rules/signals/weights; consumes DOC11 registry + `ResolvedEnginePlan` | `OBL-ROUTING-ENGINE-SELECTION-01` | | E0 / DOC81 | Egress binding for delegation (reference only) | `OBL-D81-DELEGATION-EGRESS-REF-01` | --- ## 9. Phase-2 multi-principal note Per capability note §5 rule 3 + DOC81 R-5: **other users authenticate themselves or ride T2 — never the architect's subscription** (license-bound). Reinforced by Anthropic policy: the Claude Agent SDK credit is **per-user and cannot be pooled**, so any shared/team automation must use an API key (T2), not a subscription seat. Phase-1 single-principal hooks (`auth_source`, per-principal billing path) are present and dormant; the adapter does not implement networking. --- ## 10. Compatibility with R14 and pending R15 **R14 (operative):** conforms to R14 §0 conventions — canonical naming table (§0.6A: new names introduced here are listed for fold-in), Settings-Only honesty (§0.6B), capability-evidence labels (§0.4), desired/effective/executed truth, anti-ghost, DOC10 XDI companion-ledger rows (§0.7). No R14 contract is redefined. New canonical names to add to §0.6A on adoption: `EngineDescriptor`, `EngineInvocation`, `ResolvedEnginePlan`, `RoutingTargetBundle`, `AgentRunRecord`, `BillingPathAssertion`, `ClaudeCreditMeter`, `DelegationEgressBinding`, `EngineFailure`. **R15 (pending):** - **§10 (Codex app-server/code-mode migration; RLD-11-13):** the adapter's Codex topologies (`openclaw_runtime_pi` / `openclaw_runtime_codex`) bind to R15's app-server/code-mode model and **do not re-assert a deprecated `codex-cli/*` provider surface**. *This is the one collision surface; it is resolved here by alignment, not contradiction.* - **§15 (model catalog source-plan/auth/fallback/quota):** the adapter's `auth_source` indicator, `expected_billing_path`, and `ClaudeCreditMeter` are **additive extensions** of §15's auth/source-plan/quota surface — not a second control language. - **§16 (subagent readback/parent review):** complementary; external-agent runs surface as provenance + (where applicable) ACP participants. - **§22 (route/event closure) + §23 (acceptance tests):** the redline will need to add this proposal's routes/events to the §22 appendix and its golden scenarios to §23. --- ## 11. OPEN_FOR_ARCHITECT_REVIEW (5 — the cap) 1. **OPEN-1 (verification):** confirm the architect's current OpenClaw build exposes the no-fee Codex OAuth provider (`openclaw_runtime_pi`/`_codex`) and the `claude-cli` backend (enable `codex` plugin + `codex login`; `claude auth login` + `agentRuntime.id: claude-cli`; run `openclaw doctor --fix` to clear legacy pins; `openclaw models status`). On success, flip those rows from `native_documented_not_probed` to `native_probed`. 2. **OPEN-2 (ownership):** does the **Reverse MCP server runtime** stay in DOC11 (DOC16 §16.7.4) or migrate to DOC5 as an inbound-auth/egress surface? 3. **OPEN-3 (scope):** confirm the routing **policy** engine is a separate spec (DOC11 holds only registry + `ResolvedEnginePlan` + override + telemetry). 4. **OPEN-4 (Claude credit defaults):** confirm Max tier for `ClaudeCreditMeter` defaults (5x $100 / 20x $200) and the `on_exhaustion` behavior (default `block` vs `spill_to_api_if_enabled`). 5. **OPEN-5 (naming):** confirm the `engine` × `invocation_topology` canonical vocabulary aligns with R15 §10's OpenClaw runtime-id naming before fold-in to §0.6A. --- ## 12. Lints + golden fixtures (summary) **Lints** (consolidated): `engine.billing_path_mismatch`, `engine.api_key_in_default_agent_env`, `engine.silent_api_spill`, `engine.claude_run_without_credit_meter`, `engine.run_without_resolved_plan`, `engine.named_agent_target_unknown`, `engine.routing_decision_without_trace`, `engine.run_without_provenance`, `engine.wrapper_transcript_labeled_native`, `engine.secret_in_repo_log_report_or_memory`, `engine.secret_in_prompt_or_args`, `engine.mcp_pull_without_send_time_gate`, `engine.silent_api_fallback_on_auth_failure`, `engine.failure_without_structured_state`. **Golden fixtures** (executable assertions): - `fx_codex_oneshot_readonly_audit` — `openai_codex` / `ec_external_cli` / `read_only` / `none`; expects T1 flat, billing-path assert pass, provenance stamped, report intake. - `fx_claude_p_drafting_with_credit_meter` — `claude` / `openclaw_runtime_claude_cli`; expects `agent_sdk_credit` path, credit meter decremented, warn event near threshold. - `fx_mcp_pull_governed` — `ec_external_sdk_embedded` / `mcp_pull`; expects each memory-returning reverse-MCP call passes the §6.2 gate. - `fx_native_push_packet` — `native_push`; expects a DOC24/DOC84-rendered packet, send-time gate decision present. - `fx_auth_expired_relogin` — expects structured blocked state + re-login, **no** silent API fallback. - `fx_billing_path_mismatch_blocked` — API key in env where subscription expected → blocked before run. - `fx_claude_credit_exhausted` — expects block (or explicit toggle spill), surfaced, never silent. - `fx_multi_principal_phase2` — second principal → per-user auth or T2; never architect subscription. *End of proposal — `DOC11_PROPOSAL_EXTERNAL_AGENT_ENGINE_ADAPTER.md`. Status: proposal, not operative.*