Files
alknet/docs/architecture/README.md
glm-5.2 5fc074713c docs(http): add ADR-041 MCP tool-gateway pattern for to_mcp
The to_mcp spec was describing one MCP tool per alknet operation — the
tool-bloat problem. An LLM connecting to a node with 200 operations gets
200 MCP tools dumped into its context, degrading reasoning and wasting
context budget.

ADR-041 replaces this with the tool-gateway pattern (same pattern as
opencode's memory and worktree tools): to_mcp exposes 4 fixed meta-tools
(search, schema, call, batch) that gate access to the full operation
registry. The LLM has a few tools in context, discovers operations on
demand through search + schema, then calls. Same principle as Linux's
man command — don't preload all documentation; query on demand.

Gateway tool set:
- search -> services/list (names + descriptions, AccessControl-filtered)
- schema -> services/schema (full OperationSpec for a specific op)
- call -> call.requested (Query/Mutation only, request/response)
- batch -> multiple call.requested (correlated IDs, OQ-14)

Subscription operations are excluded — MCP tool calls are
request/response by protocol design (the client blocks until
CallToolResult returns); streaming subscriptions don't fit. Subscriptions
are filtered out of search results and cannot be invoked via call.

http-mcp.md to_mcp section rewritten: the gateway tool set, Subscription
exclusion, and the service behavior (tools/list returns 4 fixed tools,
tools/call dispatches through the gateway). The 'Why' section adds the
tool-bloat rationale and the memory/worktree tool pattern that informed
the design.

README/overview ADR tables and the top-level README current-state note
updated for ADR-041.
2026-06-29 08:34:44 +00:00

18 KiB
Raw Blame History

status, last_updated
status last_updated
draft 2026-06-28

Alknet Architecture

Current State

Pre-implementation of the storage/repo pattern. The project has completed a pivot from a three-layer model to an ALPN-as-service model. The greenfield workspace contains alknet-vault (stable — implementation complete and verified, local-only by construction per ADR-025, HD-derivation key model per ADR-026) and research/reference material. Foundational ADRs (001035) are in place, with the call crate implemented and reviewed.

The storage and auth strategy research (docs/research/alknet-storage-strategy/findings.md) surfaced the repo/adapter pattern as the answer to cross-node state (peer identity, credentials). This has now landed as four ADRs:

  • ADR-030 (PeerEntry and Identity.id decoupling): authorized_fingerprints: HashSet<String>peers: Vec<PeerEntry>; Identity.id becomes the stable peer_id (not the fingerprint); key rotation changes the fingerprint, not the identity. Supersedes ADR-029's v1 UUID source (the one-way door — PeerId is logical, not crypto — is preserved; the source changes from UUID to Identity.id from PeerEntry). Resolves OQ-33 and the storage-boundary half of OQ-34.
  • ADR-031 (CredentialStore repo trait): the second repo trait in core (alongside IdentityProvider), with InMemoryCredentialStore default adapter. Establishes the credential-persistence abstraction.
  • ADR-032 (Forwarded-for identity): forwarded_for field on call.requested and OperationContext; metadata only — AccessControl::check never reads it; the from_call handler populates it. Wire-format one-way door, included with the ADR-029 migration window.
  • ADR-033 (Storage boundary and repo/adapter pattern): core defines repo traits + in-memory defaults; persistence adapters are separate crates; the assembly layer wires the adapter. Resolves OQ-34's storage-boundary question. Concrete adapter shapes now committed by ADR-035 (was OQ-36).

The alknet-call crate is implemented and reviewed — both the server-side core and the client/adapter surface (207 lib + 2 integration tests passing). The alknet-core and alknet-call crate specs are in draft; the alknet-vault crate specs are stable.

alknet-http specs drafted. The alknet-http crate (HTTP interface — h2/http/1.1/h3 server + from_openapi/to_openapi/from_mcp/to_mcp adapters) now has architecture specs: crates/http/ (overview, http-server, http-adapters, http-mcp, webtransport) and six new ADRs — ADR-036 (HTTP-to-call mapping), ADR-037 (MCP stdio exclusion), ADR-038 (HTTP/3 + WebTransport as first-class, correcting the Phase 0 deferral framing), ADR-039 (HTTP server + client host colocated in one crate), ADR-040 (WebTransport ALPN-stream-proxy — browser → WebTransport stream → any ALPN handler via WASM parser; the "VPN-like without being a VPN" use case), ADR-041 (to_mcp tool-gateway pattern — 4 fixed gateway tools instead of one tool per operation, addressing LLM context tool-bloat). ADR-003 Amendment 1 clarifies that alknet-call is a protocol-foundation crate (the alknet-httpalknet-call dependency edge). The specs are in draft; implementation has not started. Three open questions carried: OQ-38 (WebTransport standalone relay service scope — distinct from the in-process ALPN-stream-proxy resolved by ADR-040), OQ-39 (to_openapi published-spec versioning), OQ-40 (reqwest client config).

Next step: The storage/repo-pattern ADRs (030033) are accepted and amend the core and call specs. The next implementation phase is the ADR-029 migration (peer-keyed overlays, PeerRef routing, retire remote_safe/trusted_peer) with the ADR-030 PeerEntry change and the ADR-032 forwarded_for field folded in — the OperationContext, from_call handler, and AuthPolicy are all under edit, making this the cheapest window. After that: alknet-http implementation (specs drafted, ADRs 036038 proposed), which consumes the CredentialStore trait and the OperationAdapter contract. The alknet-ssh crate (the other post-core crate, specced in parallel) proceeds independently — it depends on alknet-core, not alknet-call.

Architecture Documents

Document Status Description
overview.md draft Workspace-level overview, crate graph, shared types, design principles
open-questions.md draft Centralized OQ tracker with door-type classifications
crates/core/README.md draft alknet-core crate index
crates/core/core-types.md draft ProtocolHandler, HandlerError, Connection, BiStream, StreamError
crates/core/endpoint.md draft ALPN router, HandlerRegistry, accept loop, shutdown
crates/core/auth.md draft AuthContext, Identity, IdentityProvider, AuthToken, resolution flow
crates/core/config.md draft StaticConfig, DynamicConfig, ArcSwap, ConfigReloadHandle
crates/call/README.md draft alknet-call crate index
crates/call/call-protocol.md draft CallAdapter, EventEnvelope framing, stream model, PendingRequestMap, bidirectional calls, streaming subscribe example
crates/call/operation-registry.md draft OperationSpec, Handler, OperationRegistry, AccessControl, capability injection, service discovery, irpc integration
crates/call/client-and-adapters.md draft CallClient (outbound connection opener), from_call / from_jsonschema, OperationAdapter trait, adapter location map, no-env-vars invariant, exchange-of-operations pattern
crates/http/README.md draft alknet-http crate index
crates/http/overview.md draft Crate purpose, two roles (server + client host), dependencies, adapter location map
crates/http/http-server.md draft HttpAdapter for h2/http1.1, axum over QUIC, Bearer auth, stealth, /healthz
crates/http/http-adapters.md draft from_openapi (reqwest) and to_openapi (projection); no-env-vars injection point
crates/http/http-mcp.md draft from_mcp / to_mcp (feature-gated), streamable-HTTP-only, stdio exclusion
crates/http/webtransport.md draft h3/WebTransport handler — the browser streaming path
crates/vault/README.md stable alknet-vault crate index
crates/vault/mnemonic-derivation.md stable BIP39, SLIP-0010, BIP-0032, derivation paths, key types
crates/vault/encryption.md stable AES-256-GCM, EncryptedData, key versioning, salt (Phase B reserved)
crates/vault/service.md stable VaultServiceHandle lifecycle, direct dispatch, cache, error model
crates/vault/protocol.md stable DerivedKey redaction, KeyType, serialization behavior

ADR Table

ADR Title Status
001 ALPN-Based Protocol Dispatch Accepted
002 ProtocolHandler Trait Accepted
003 Crate Decomposition Accepted
004 Auth as Shared Core (IdentityProvider) Accepted
005 irpc as Call Protocol Foundation Accepted
006 ALPN String Convention and Connection Model Accepted
007 BiStream Type Definition Accepted
008 Vault Integration Point Accepted
009 One-Way Door Decision Framework Accepted
010 ALPN Router and Endpoint Accepted
011 AuthContext Structure and Resolution Flow Accepted
012 Call Protocol Stream Model Accepted
013 Rust as Canonical Implementation Language Accepted
014 Secret Material Flow and Capability Injection Accepted
015 Privilege Model and Authority Context Accepted
016 Abort Cascade for Nested Calls Accepted
017 Call Protocol Client and Adapter Contract Accepted
018 Vault as Standalone Crate Accepted
019 Vault Assembly-Layer-Only Access Accepted
020 HD Derivation for Encryption Keys Accepted
021 Key Rotation via Version-Indexed Paths Accepted
022 Handler Registration, Provenance, and Composition Authority Accepted
023 Operation Error Schemas Accepted
024 Operation Registry Layering Accepted
025 Vault Local-Only Dispatch Accepted
026 Vault Key Model — HD Derivation Accepted
027 TLS Identity Redesign — ACME + RawKey Decoupling Accepted
028 Peer-Scoped Registry Filtering for CallClient Inbound Dispatch AcceptedSuperseded by ADR-029
029 Peer-Graph Routing Model for alknet-call Composition Accepted (Assumption 1's PeerId source superseded by ADR-030)
030 PeerEntry and Identity.id Decoupling Accepted (supersedes ADR-029 Assumption 1's UUID source)
031 CredentialStore Repo Trait Accepted
032 Forwarded-For Identity (Metadata, Not Authority) Accepted
033 Storage Boundary and Repo/Adapter Pattern Accepted
034 Outgoing-Only X.509 and the Three Peer Roles Accepted
035 Concrete Persistence Adapter Shapes — Read/Write Split, honker+SQLite Accepted
036 HTTP-to-Call Operation Mapping Proposed
037 MCP Stdio Transport Exclusion Proposed
038 HTTP/3 and WebTransport as First-Class HTTP Transports Proposed
039 HTTP Server and Client Host Colocated in alknet-http Proposed
040 WebTransport ALPN-Stream-Proxy Proposed
041 MCP Tool-Gateway Pattern for to_mcp Proposed

Open Questions

See open-questions.md for the full tracker.

Resolved one-way doors:

  • OQ-01: BiStream type — trait with Connection parameter (ADR-007)
  • OQ-02: AuthContext timing — hybrid model (ADR-004)
  • OQ-03: ALPN naming — alknet/ prefix, no version (ADR-006)
  • OQ-05: Multi-connectivity endpoint — quinn + iroh, both feature-gated (ADR-010)
  • OQ-06: ALPN per connection, not per stream (ADR-006)
  • OQ-08: Vault integration — CLI-embedded, assembly-layer only (ADR-008, ADR-014)
  • OQ-16: Safe vault operations for call protocol exposure — none for now (ADR-014)
  • OQ-18: Privilege model — internal = authority switch, External/Internal visibility, handler identity + scoped env (ADR-015)
  • OQ-17: Abort cascade — call.aborted cascades to descendants; default abort-dependents, continue-running opt-in (ADR-016)
  • OQ-15: Call protocol client and adapter contract — CallClient opens connections; from_call imports remote ops; connection direction independent of call direction (ADR-017)

Resolved two-way doors:

  • OQ-04: Dynamic handler registration — static at startup (ADR-010); scoped to the HandlerRegistry (ALPN-level) by ADR-024, which governs OperationRegistry mutability separately
  • OQ-07: Call protocol scope — bidirectional streams, EventEnvelope, ID-based correlation (ADR-012)
  • OQ-11: Handler-level auth resolution observability — handlers store resolved identity on Connection (Option B); two identity scopes: connection-level (observability) and per-request (ACL)
  • OQ-12: TLS identity provisioning — two use cases: RFC 7250 raw keys (default, P2P) and X.509 certs (domain-hosted, browsers). ACME designed in ADR-027; RawKey decoupled from iroh feature.
  • OQ-13: Operation path format — /{service}/{op} is the correct design for alknet-call, not a simplification
  • OQ-14: Batch operation semantics — multiple correlated call.requested events is the correct protocol design, not a simplification
  • OQ-19: Session-scoped registries — agent-written operations via OperationEnv trait layering; protocol doesn't need changes; OperationEnv must remain a trait. Generalized by ADR-024 to cover connection-scoped overlays as well.
  • OQ-20: Encryption key derivation — HD derivation from BIP39 seed, not PBKDF2; salt field unused in v2 (wire-format compat) (ADR-020)
  • OQ-21: Remote vault access — resolved (ADR-025): vault is local-only by construction; remote access requires a separate vault-server crate with its own ADR
  • OQ-22: Key rotation — version-indexed derivation paths; rotate method re-encrypts (ADR-021)
  • OQ-23: Handler identity registration path — registration bundle with provenance, composition authority, scoped env, capabilities (ADR-022)
  • OQ-24: Operation error schemas — declared domain errors with typed details payload; adapter fidelity for from_openapi/to_openapi (ADR-023)

Resolved by the storage/repo-pattern ADRs (ADR-030033):

  • OQ-33: PeerId stabilityresolved by ADR-030 (logical id; source is Identity.id = PeerEntry.peer_id, stable across key rotation; UUID workaround removed)
  • OQ-34: Persistent peer registryresolved by ADR-030 + ADR-031 + ADR-033 (storage boundary: core defines repo traits + in-memory defaults; persistence adapters are separate crates)
  • OQ-35: API key asymmetrydissolved (the framing was wrong; PeerEntry supports multiple credential paths)

Resolved by the call-completion / ADR-029 work:

  • OQ-27: from_call re-import triggerresolved (auto-re-import on connection establishment; refresh() is a feature addition)
  • OQ-28: from_call namespace collisionresolved (same-peer collision = error; cross-peer dissolved by ADR-029)
  • OQ-29: CallClient TLS client-authresolved (wire quinn client-auth; key-type-aware server cert verification; fingerprint normalization to ed25519: across quinn/iroh)
  • OQ-30: PeerRef::Any routing policyresolved (insertion-order first-match; richer routing is a feature extension)
  • OQ-31: services/list-peers re-export semanticsresolved (opt-in services/list-peers; services/list is "own ops only")

Open (feature extensions, not blocking):

  • OQ-32: Multi-hop federation — the one-hop model is the architectural commitment; multi-hop is a feature extension that doesn't break downstream
  • OQ-36: Concrete persistence adapter shapesresolved by ADR-035 (read-sync / write-async / honker-NOTIFY cache invalidation; alknet-store-sqlite crate; IdentityStore write trait; CredentialStore::put/delete async)
  • OQ-37: X.509 outgoing-only caseresolved by ADR-034 (three remote roles named: public X.509 endpoint, transport relay, hub; PeerEntry asymmetry is correct; client-side verifier selection by PeerEntry presence)
  • OQ-38: WebTransport standalone relay service scope — the standalone relay (future alknet-relay, fork of iroh-relay with WebTransport proxy fallback) is distinct from the in-process ALPN-stream-proxy (ADR-040); scope question, not deferral
  • OQ-39: to_openapi published-spec versioning — versioning strategy for generated OpenAPI specs (one-way after first publication)
  • OQ-40: reqwest client config and connection pooling — two-way-door config shape for the outbound HTTP client

Deferred (not active):

  • OQ-09: WASM target boundaries — design constraint, not deliverable
  • OQ-10: Git adapter scope — start with smart protocol, add ERC721 later

Document Lifecycle

Status Meaning Transitions
draft Under active development. May change significantly. reviewed when open questions are resolved
reviewed Architecture is final. Implementation may begin. Changes require review. stable when implementation is complete and verified
stable Locked. Changes require review and may warrant an ADR. deprecated when superseded
deprecated Superseded. Kept for reference. Removed when no longer referenced

References

  • Pivot proposal: docs/research/pivot/alpn-service-architecture.md
  • Cleanup plan: docs/research/pivot/cleanup-plan.md
  • SDD process: docs/sdd_process.md
  • Reference implementation: /workspace/@alkdev/alknet-main/