Skip to main content
Architecture Decision Records (ADRs) document the key architectural decisions made during ISCL’s design, including the context, alternatives considered, and trade-offs accepted. Each decision has been formalized and accepted by the architecture team.
Status: Accepted | Date: 2025-02-01 | Deciders: Architecture team

Context

AI agents — OpenClaw, ElizaOS, MCP-connected LLMs, Telegram bots — need to perform crypto operations on behalf of users: token transfers, swaps, approvals, and balance queries. These agents run potentially untrusted code, including community-authored skills, LLM-generated actions, and third-party plugins.The core problem: how do you let AI agents sign transactions without giving them access to private keys?Existing approaches each have fundamental shortcomings:
  1. Agent holds keys directly — Simple to implement but catastrophic if the agent is compromised. A single malicious skill or prompt injection can drain the wallet. There is no policy layer, no audit trail, and no approval step.
  2. Hardware wallet with manual approval — Secure key isolation, but every transaction requires physical human interaction. This is incompatible with autonomous agent workflows where an agent may execute dozens of operations per hour.
  3. Custodial API (third-party signing service) — Introduces counterparty risk, requires trusting an external entity with key material, and creates a single point of failure. Not viable for users who require self-custody.
  4. Embedded TEE / secure enclave — Hardware-dependent, complex to deploy, and does not solve the policy or approval problem. The agent still needs to be told “yes” or “no” based on risk assessment.
None of these approaches balance security with agent autonomy. The system needs to isolate keys from untrusted code while still allowing agents to request crypto operations programmatically, with configurable policy enforcement and human-in-the-loop approval when appropriate.Additional forces at play:
  • Multiple agent frameworks exist (OpenClaw, ElizaOS, MCP, custom bots) and the solution must be framework-agnostic.
  • Skills are authored by third parties and cannot be fully trusted, even after code review.
  • The attack surface includes prompt injection, supply chain compromise, malicious skill packages, and compromised RPC endpoints.
  • Operations range from low-risk (balance queries) to high-risk (large transfers, unlimited approvals), requiring graduated security responses.
  • Audit and compliance require a tamper-evident record of every signing operation.

Decision

Divide the system into three trust domains with strict, enforced boundaries. Every line of code belongs to exactly one domain. No component straddles a boundary.Domain A — Untrusted (Agent Framework + Skills)Packages: @clavion/adapter-openclaw, @clavion/adapter-mcp, @clavion/plugin-eliza, @clavion/adapter-telegramDomain A contains all agent-facing code: skill wrappers, intent builders, and adapter clients. Code in this domain is considered potentially compromisable at all times.Capabilities:
  • Construct declarative TxIntents (JSON objects describing desired operations)
  • Communicate with Domain B exclusively via localhost HTTP API
  • Read balance and transaction status data through Domain B
Restrictions:
  • No access to private keys or any key material
  • No direct signing capability
  • No direct blockchain RPC access
  • No control over approval summaries shown to users
  • No access to policy configuration or audit data
The key insight is that Domain A code expresses intent, never execution. A skill says “I want to transfer 100 USDC to 0xABC” — it never constructs raw calldata, never sets gas parameters, and never touches a signing function.Domain B — Trusted (ISCL Core)Packages: @clavion/core, @clavion/signer, @clavion/audit, @clavion/policy, @clavion/preflight, @clavion/registryDomain B is the only domain that holds key material and can sign transactions. Every operation follows a mandatory pipeline:
TxIntent --> PolicyEngine.evaluate() --> TxBuilder.build() --> PreflightService.simulate()
--> ApprovalService.requestApproval() --> WalletService.sign() --> Broadcast --> AuditTrace
No step in this pipeline can be bypassed. There is no signRaw API, no backdoor for “trusted” skills, and no way to skip policy evaluation. The single signing entry point (WalletService.sign) requires both a valid PolicyDecision and a single-use ApprovalToken.Security guarantees:
  • Keys are encrypted at rest (scrypt + AES-256-GCM) and decrypted only in memory for signing
  • Policy engine evaluates every intent against configurable rules (value limits, contract allowlists, token allowlists)
  • Preflight simulation detects anomalies before signing (balance changes, gas estimation, risk scoring)
  • Approval tokens are single-use with TTL — no replay attacks
  • Every critical step is written to an append-only audit trail with intentId correlation
  • RPC access uses an allowlist — only approved endpoints are contacted
Domain C — Limited Trust (Secure Executor)Packages: @clavion/sandboxDomain C runs untrusted skill code in isolated Docker containers with aggressive restrictions:
  • --network none by default (no network access)
  • --read-only root filesystem
  • --cap-drop ALL (all Linux capabilities dropped)
  • --security-opt no-new-privileges
  • seccomp profile blocks clone, fork, exec (no process spawning)
  • Resource limits: memory (128MB), CPU (0.5 cores), execution timeout
Domain C communicates with Domain B exclusively via the ISCL Core API. Key material is never present on the container’s filesystem or in its environment variables.Boundary EnforcementThe three-domain boundary is enforced at multiple levels simultaneously:
  • Package level: Domain B packages are never imported by Domain A code. TypeScript project references enforce this at build time.
  • Network level: Keys are never transmitted over HTTP, even on localhost. Only approval tokens and signed transaction hashes cross the API boundary.
  • Process level: Sandbox containers have no access to the host filesystem where keys are stored.
  • Runtime level: The API server validates all inputs against strict JSON schemas (additionalProperties: false) — no undocumented fields pass through.
  • Test level: A dedicated security test suite (tests/security/) verifies domain boundaries, including tests for key exfiltration attempts, import graph integrity, and cross-domain access.
Cross-Domain CommunicationAll communication between domains flows through the ISCL Core HTTP API at localhost:3100. There are no shared memory spaces, no direct function calls, and no file-based communication channels between domains.
Domain A  --HTTP-->  Domain B (ISCL Core API)
Domain C  --HTTP-->  Domain B (ISCL Core API)
Domain A and Domain C never communicate directly with each other.

Consequences

  • Key isolation is physical, not just logical. Private keys exist only in Domain B’s process memory and encrypted keystore. A compromised agent skill literally cannot access them — they are in a different process, behind an API with no key-export endpoint.
  • Compromised skills have limited blast radius. The worst a malicious skill can do is submit a TxIntent, which still must pass policy evaluation, preflight simulation, and user approval before any funds move.
  • Every operation has an audit trail. The append-only SQLite audit trace in Domain B records the full lifecycle of every intent, from submission through policy decision, approval, signing, and broadcast. This is essential for incident response and compliance.
  • Approval is flexible. The architecture supports CLI prompts, web-based approval dashboards, and Telegram inline keyboards. Approval mode is configurable per deployment (cli, web, auto) and per policy rule (requireApprovalAbove).
  • Framework-agnostic design. The localhost HTTP API is a universal integration point. Adding support for a new agent framework (e.g., a new LLM orchestrator) requires only writing a thin adapter in Domain A — no changes to the security-critical Domain B code.
  • Defense in depth. Multiple independent enforcement layers (package boundaries, process isolation, network restrictions, schema validation, policy engine, preflight simulation) mean that a single failure does not compromise the system.
Status: Accepted | Date: 2025-02-01 | Deciders: Architecture team

Context

ISCL requires an append-only audit trail that records every security-relevant step in the transaction lifecycle: intent receipt, policy evaluation, preflight simulation, approval decisions, signing events, broadcast results, and errors. This trail serves three purposes:
  1. Incident forensics. When something goes wrong — a transaction is unexpectedly approved, a policy bypass is suspected, or funds move to an unrecognized address — operators need a complete, tamper-evident record of every step that led to the outcome, correlated by a single intent ID.
  2. Compliance and accountability. Each audit event captures who requested what, which policy rules were applied, what risk score was calculated, whether the user approved, and when the signature was produced. This provides a provable chain of custody for every signing operation.
  3. Rate limiting. The policy engine enforces per-wallet transaction rate limits (e.g., 10 transactions per hour). This requires durable, queryable state that survives process restarts — counting recent transactions by wallet address within a sliding time window.
The audit store needs to satisfy these requirements:
  • Append-only writes. Events are inserted but never updated or deleted. This prevents retroactive tampering with the audit record.
  • Correlation queries. Retrieve all events for a given intent ID to reconstruct the full lifecycle of a single operation.
  • Time-ordered retrieval. List recent events across all intents for dashboard display and monitoring.
  • Rate limit queries. Count events per wallet within a time window, with efficient indexed lookups.
  • Zero external dependencies. ISCL is a local runtime — it should not require a database server, connection pool, or network-accessible data store.
  • Durability. Events must survive process crashes without data loss.
  • Low latency. Audit logging is in the critical path of every transaction. Inserts must not block the pipeline.
Alternatives considered:
  1. PostgreSQL / MySQL — Full-featured relational databases. Satisfy all query requirements but introduce an external server dependency, connection management, schema migrations, and operational overhead (backups, user management, network configuration). Dramatically overweight for a local single-user runtime.
  2. Flat-file JSON / JSONL — Simple append-only writing. No dependencies. But queries require scanning the entire file. Rate limit counts and correlation queries become O(n) as the log grows. No indexing, no transactions, no crash safety guarantees.
  3. LevelDB / RocksDB — Embedded key-value stores. Low overhead, no external dependencies. But key-value semantics are awkward for the access patterns needed: range queries over timestamps, filtering by intent ID, counting by wallet address within a window. Would require building a secondary index layer on top.
  4. In-memory only — Fastest option. But all audit data is lost on process restart. Unacceptable for forensics, compliance, and rate limiting that must survive restarts.

Decision

Use SQLite via better-sqlite3 as the audit trail storage engine, with WAL (Write-Ahead Logging) mode enabled.Schema design — two tables:audit_events — The primary audit trail. Each row is an immutable event.
CREATE TABLE IF NOT EXISTS audit_events (
  id TEXT PRIMARY KEY,           -- UUID, generated per event
  timestamp INTEGER NOT NULL,    -- Unix milliseconds (Date.now())
  intent_id TEXT NOT NULL,       -- Correlation key linking all events for one intent
  event TEXT NOT NULL,           -- Event type (e.g. "policy_evaluated", "signed")
  data TEXT NOT NULL,            -- JSON payload with event-specific details
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_intent_id ON audit_events(intent_id);
CREATE INDEX idx_event ON audit_events(event);
CREATE INDEX idx_timestamp ON audit_events(timestamp);
rate_limit_events — Lightweight table for per-wallet rate counting.
CREATE TABLE IF NOT EXISTS rate_limit_events (
  wallet_address TEXT NOT NULL,  -- Checksummed 0x address
  timestamp INTEGER NOT NULL     -- Unix milliseconds
);

CREATE INDEX idx_rate_wallet_ts ON rate_limit_events(wallet_address, timestamp);
Rate limit events are periodically cleaned up (rows older than the rate limit window are deleted) to prevent unbounded growth.Access patterns:The AuditTraceService class provides five operations:
MethodQueryPurpose
log(event, data)INSERT INTO audit_eventsAppend an audit event
getTrail(intentId)WHERE intent_id = ? ORDER BY timestamp ASCReconstruct an intent’s lifecycle
getRecentEvents(limit)ORDER BY timestamp DESC LIMIT ?Dashboard and monitoring display
recordRateLimitTick(wallet)INSERT INTO rate_limit_eventsRecord a transaction for rate counting
countRecentTxByWallet(wallet, windowMs)WHERE wallet_address = ? AND timestamp > ?Count recent transactions for rate limiting
All queries use prepared statements, created once at initialization and reused for every call. This eliminates SQL parsing overhead on the hot path.WAL mode:WAL (Write-Ahead Logging) is enabled at initialization via PRAGMA journal_mode = WAL. This provides:
  • Concurrent reads during writes. The audit trail can be queried (e.g., for the web dashboard) while new events are being written without blocking.
  • Better write performance. WAL batches writes to a separate log file before merging, reducing filesystem synchronization overhead.
  • Crash safety. WAL ensures that committed transactions survive process crashes. An incomplete write during a crash is automatically rolled back on next open.
Synchronous writes:better-sqlite3 is chosen specifically because it provides synchronous, blocking operations. In the ISCL audit context, this is a feature:
  • Audit writes complete before the pipeline proceeds to the next step. There is no risk of “audit gap” where a signing event occurs but the corresponding audit record is lost due to an async write queue.
  • The synchronous API simplifies error handling — a failed write throws immediately in the calling context.
  • Latency of SQLite inserts (with WAL, on SSD) is typically 10-50 microseconds. This is negligible compared to RPC calls (~50-500ms) and blockchain confirmation (~2-12 seconds) in the same pipeline.

Consequences

  • Zero deployment dependencies. SQLite is embedded in the process. No database server to install, configure, monitor, or secure. The audit trail is a single file on disk.
  • Natural correlation model. SQL queries make it trivial to reconstruct an intent’s lifecycle (WHERE intent_id = ?), count events in a window (WHERE timestamp > ?), or analyze patterns (GROUP BY event).
  • Crash-safe durability. WAL mode guarantees that committed events survive unexpected process termination. This is essential for an audit trail that must be tamper-evident.
  • Fast enough for the hot path. Prepared statement inserts with WAL mode add microseconds of latency per audit event. Given that each transaction pipeline includes multiple RPC calls (50-500ms each), audit logging is never the bottleneck.
  • Portable. The audit database is a single .sqlite file. It can be backed up with a file copy, moved between machines, or inspected with any SQLite client (sqlite3 CLI, DB Browser for SQLite, DBeaver).
  • Rate limiting survives restarts. Because rate limit state is persisted to SQLite, restarting ISCL Core does not reset the transaction counter. An attacker cannot bypass rate limits by triggering a process restart.
Status: Accepted | Date: 2025-02-01 | Deciders: Architecture team

Context

AI agents need to perform crypto operations: token transfers, DEX swaps, spending approvals, and native ETH transfers. The question is: what format should agents use to express these requests to the signing layer?The core tension is between expressiveness and safety. A more expressive format lets agents do more things, but a more constrained format is easier to validate, simulate, and explain to users.Approach 1: Raw Transaction SigningThe agent constructs a complete EVM transaction (to, data, value, gas parameters) and sends it to the signing layer for signature.Problems:
  • No policy enforcement. Raw calldata is opaque — the policy engine cannot determine whether a transaction is a benign transfer or a malicious contract call without decoding every possible contract ABI.
  • No simulation safety. The signing layer cannot meaningfully simulate or explain what a raw transaction does without understanding the target contract.
  • Attack surface. A compromised agent can craft arbitrary calldata: call selfdestruct, interact with attacker-controlled contracts, set unlimited approvals, or perform reentrancy attacks. The signing layer has no semantic understanding to prevent this.
  • No user-readable approval. The approval prompt would show raw hex calldata. Users cannot meaningfully approve or deny what they cannot understand.
Approach 2: High-Level SDK CallsThe agent imports a crypto SDK and calls typed functions like sdk.transfer(token, to, amount). The SDK handles transaction construction and signing internally.Problems:
  • Library sharing violates trust boundaries. If the agent imports the signing SDK, it has access to the signing functions in its process memory. A compromised agent could call signing functions directly, bypassing policy and approval.
  • No audit trail. Operations happen as function calls within the agent process. There is no natural interception point for logging, policy enforcement, or user confirmation.
  • Framework coupling. Each agent framework (OpenClaw, ElizaOS, MCP, Telegram) has different language and runtime requirements. A single SDK would need to support all of them.
Approach 3: Declarative Intent FormatThe agent constructs a JSON document describing what it wants to do (action type, parameters, constraints) and submits it to a separate process for execution. The executing process handles transaction construction, policy evaluation, simulation, approval, and signing.This is the approach we evaluated and selected.

Decision

Define a TxIntent v1 JSON schema as the universal request format for all crypto operations. Agents construct TxIntents; ISCL Core interprets and executes them.Design principles:
  1. Agents express “what”, never “how”. A TxIntent says “transfer 100 USDC to 0xAlice” — it does not specify the ERC-20 transfer(address,uint256) function selector, ABI encoding, gas price, nonce, or chain-specific parameters. ISCL Core handles all of that.
  2. Closed set of action types. TxIntent v1 defines exactly five action types: transfer, transfer_native, approve, swap_exact_in, and swap_exact_out. There is no generic “call” or “execute” action. This means every possible operation is known at compile time, can be validated against a strict schema, and can be explained in human-readable terms.
  3. Strict schema validation. The schema uses additionalProperties: false at every level. No undocumented fields pass validation. This prevents agents from injecting unexpected data that might be interpreted by downstream components.
  4. Canonical form for integrity. TxIntents are canonicalized using JCS (JSON Canonicalization Scheme) and hashed with keccak256. This produces a deterministic fingerprint used for approval token binding — the token is tied to a specific intent, preventing substitution attacks.
Schema structure:
TxIntent v1
+-- version: "1"                    -- Schema version for forward compatibility
+-- id: UUID                        -- Idempotency key and audit correlation
+-- timestamp: number               -- Unix milliseconds, creation time
+-- chain
|   +-- type: "evm"                 -- Chain family (only EVM in v1)
|   +-- chainId: number             -- Target chain (1, 10, 42161, 8453)
|   +-- rpcHint?: string            -- Optional RPC URL hint (informational only)
+-- wallet
|   +-- address: "0x..."            -- Signing wallet
|   +-- profile?: string            -- Optional wallet profile name
+-- action: (one of)
|   +-- transfer                    -- ERC-20 transfer
|   +-- transfer_native             -- Native ETH transfer
|   +-- approve                     -- ERC-20 spending approval
|   +-- swap_exact_in               -- DEX swap with exact input
|   +-- swap_exact_out              -- DEX swap with exact output
+-- constraints
|   +-- maxGasWei: string           -- Hard cap on gas cost
|   +-- deadline: number            -- Unix timestamp expiry
|   +-- maxSlippageBps: number      -- Slippage tolerance (basis points)
+-- preferences?
|   +-- gasSpeed?: string           -- slow | normal | fast
|   +-- privateRelay?: boolean      -- Use private mempool
+-- metadata?
    +-- source?: string             -- Adapter name (for audit)
    +-- note?: string               -- Human-readable context
Action type definitions:Each action type has a fixed set of fields. No action accepts arbitrary contract addresses or calldata as direct parameters.
ActionFieldsWhat ISCL Builds
transferasset, to, amountERC-20 transfer(address,uint256) call
transfer_nativeto, amountPlain ETH value transfer (no calldata)
approveasset, spender, amountERC-20 approve(address,uint256) call
swap_exact_inrouter, assetIn, assetOut, amountIn, minAmountOut, provider?Uniswap V3 exactInputSingle or 1inch API calldata
swap_exact_outrouter, assetIn, assetOut, amountOut, maxAmountIn, provider?Uniswap V3 exactOutputSingle
The router field on swap actions is validated against a known set of router addresses per chain. An agent cannot specify an arbitrary contract — only known, audited DEX routers are accepted.
What TxIntent prevents at the schema level:By restricting operations to a closed set of action types, the format makes entire categories of attacks impossible at the schema level:
  • Arbitrary contract calls. There is no call(address, calldata) action type. An agent cannot interact with contracts that are not ERC-20 tokens or known DEX routers.
  • Self-destruct or delegate calls. No action type maps to these operations.
  • Unlimited approvals by default. The approve action requires an explicit amount. The policy engine can enforce a cap via maxApprovalAmount.
  • Calldata injection. ISCL Core constructs calldata from typed parameters. The agent never provides raw hex calldata.
  • Gas manipulation. Gas parameters are set by ISCL Core based on RPC estimation, not by the agent. The maxGasWei constraint provides a ceiling but not a floor.
Extensibility:Adding a new action type requires a Domain B code change (new builder, schema entry, policy rule). This is intentional — every new operation must be explicitly implemented, reviewed, and tested before agents can use it. The schema version field ("1") allows future incompatible changes via a new version number.

Consequences

  • Every operation is human-readable. The approval prompt can always show a clear description: “Transfer 100 USDC to 0xAlice on Base” rather than raw hex. Users can make informed approval decisions.
  • Policy engine has full semantic understanding. The policy engine knows exactly what each intent does: which tokens are involved, what value is being transferred, which contracts are targeted. This enables precise rules (token allowlists, value caps, recipient restrictions).
  • Preflight simulation is meaningful. Because ISCL Core builds the transaction from typed parameters, it knows exactly what to simulate and what balance changes to expect. Anomalous simulation results (unexpected balance changes, revert) are detectable.
  • Framework-agnostic. Any adapter that can produce JSON can construct a TxIntent. The format is the same whether the request comes from OpenClaw, MCP, ElizaOS, Telegram, or a future adapter.
  • Canonical hashing enables integrity binding. Approval tokens are bound to specific intent hashes. Modifying any field after approval invalidates the token. This prevents substitution attacks (approve a small transfer, then swap the intent for a large one).
Status: Accepted | Date: 2025-02-01 | Deciders: Architecture team

Context

ISCL Core exposes an HTTP API that accepts transaction intents, returns approval tokens, and triggers signing operations. The fundamental question is: who should be able to reach this API?The API surface is security-critical. It can:
  • Trigger transaction signing (with valid approval tokens)
  • Read wallet balances and transaction history
  • Approve or deny pending transactions
  • Register and manage skills
  • Access audit trail data
If this API were exposed to the network, it would become a target for:
  1. Remote exploitation. An attacker on the same network (or internet, if port-forwarded) could submit TxIntents directly, bypassing the agent entirely. While policy and approval would still apply, the attack surface expands dramatically.
  2. Man-in-the-middle on approval tokens. Approval tokens are bearer tokens — anyone who holds one can use it to trigger signing. If tokens traverse a network, they can be intercepted.
  3. Information disclosure. Balance queries, audit trail data, and pending approval details contain sensitive financial information.
  4. Denial of service. An exposed API can be flooded with requests, overwhelming the single-process ISCL Core.
Deployment model implications:ISCL is designed as a local runtime — it runs on the same machine as the AI agent, providing a secure signing service to co-located software. This is fundamentally different from a cloud API or shared service model.The target users are:
  • Individual operators running an AI agent on their workstation or VPS
  • Development teams running agents in containerized environments (Docker Compose)
  • Small-team deployments where agent and signer co-locate by design
These users benefit from zero-configuration security. They should not need to set up TLS certificates, API authentication, firewall rules, or network policies to get a secure deployment.Alternatives considered:
  1. Network-accessible API with authentication — Expose on 0.0.0.0 with API key or JWT auth. This would allow remote agents to connect to a shared ISCL Core. However, it introduces authentication management, token rotation, TLS certificate management, and a larger attack surface. For v0.1, this complexity is not justified.
  2. Unix domain socket — Bind to a filesystem socket instead of TCP. Provides strong access control via filesystem permissions. However, Docker networking does not natively support Unix sockets for inter-container communication, and the Fastify ecosystem has better-tested TCP support. Could be considered for v0.2.
  3. mTLS with client certificates — Mutual TLS ensures both parties are authenticated. Strong security but very high operational overhead: certificate generation, distribution, rotation, and CA management. Completely disproportionate for a localhost service.

Decision

Bind the ISCL Core HTTP API exclusively to 127.0.0.1 (IPv4 loopback). Do not bind to 0.0.0.0 or any network-facing interface.Implementation details:Fastify listen configuration:
await server.listen({ host: "127.0.0.1", port: 3100 });
By binding to 127.0.0.1, the operating system’s TCP/IP stack ensures that only processes on the same machine can connect. No firewall configuration, TLS, or authentication is needed — the OS enforces access control.Docker Compose networking:In the Docker Compose stack, services communicate through Docker’s internal network. The ISCL Core service binds to 0.0.0.0 inside the container (to be reachable from other containers on the Docker network), but the port is only published to localhost on the host:
ports:
  - "127.0.0.1:3100:3100"
This means the host machine can reach the API at localhost:3100, but the port is not exposed on any external network interface.No authentication required:Because only local processes can reach the API, the system does not implement request authentication (API keys, JWTs, cookies). This is a deliberate simplification. The approval flow provides human authorization for fund-affecting operations; the network binding provides access control.The one exception is the approval token mechanism: sign-and-send requires a valid, single-use approval token. This is not authentication (it does not identify the caller) but authorization (it proves the operation was approved by a human).When localhost-only is insufficient:The localhost binding is appropriate for v0.1. Future versions may need network-accessible deployments for:
  • Remote agents connecting to a central signer (e.g., multiple agents on different machines sharing one keystore)
  • Mobile approval workflows (user approves from a phone, signer is on a server)
  • Multi-machine Docker Swarm or Kubernetes deployments
These scenarios would require adding authentication, TLS, and rate limiting at the API level. The architecture supports this extension — the Fastify server can be configured with additional middleware without changing the core signing pipeline.
Future versions may support network-accessible deployments (remote agents, mobile approval, Kubernetes) by adding Fastify middleware for authentication and TLS — no changes to routes or the signing pipeline required.

Consequences

  • Zero-configuration security. New deployments are secure by default. There is no “forgot to set up auth” failure mode. The OS enforces that only local processes can connect.
  • No credential management. No API keys to rotate, no certificates to renew, no secrets to distribute. This eliminates an entire category of operational overhead and security risk.
  • Defense in depth with approval tokens. Even if a local process submits malicious intents, it still needs a valid approval token (which requires human confirmation) to trigger signing. Localhost binding + approval tokens provide two independent access control layers.
  • Simple containerization. Docker Compose uses standard port mapping (127.0.0.1:3100:3100) to maintain the localhost guarantee. No service mesh or overlay network configuration required.
  • Reduced attack surface. Network-accessible APIs must defend against the full spectrum of network attacks: port scanning, brute force, DDoS, TLS downgrade, session hijacking. A localhost-only API faces none of these.

Next steps