Skip to content

Runtime and memory (code map)

The repo guide splits runtime orientation into two major tracks:

Area Primary Files
Steelmoth runtime behavior steelmoth-runtime/src/steelmoth_runtime/runtime.py, steelmoth-runtime/src/steelmoth_runtime/memlink.py
Memlink service behavior memlink-hybrid/README.md, memlink-hybrid/openapi.yaml, memlink-hybrid/src/memlink_hybrid/

steelmoth-runtime is the active conversation runtime package. The root README identifies it as responsible for Telegram ingress, reply generation, runtime context, and retrieval integration.

Account-runtime channel unification (Phases 1-8, committed) consolidated the normal-chat reply path through process_account_turn so Web UI and Telegram share one planner, tool registry, memory boundary, and reply pipeline. Phase 9 / 9-bis / 10 are in flight per PRD 0043 + RFC 0080 to close the remaining operational gaps: Phase 9 (ADR 0121) turns the Telegram relay route from a parallel event consumer into an event forwarder that publishes through the same SSE persistence + broadcast pipeline the dashboard uses, so Telegram- originated turns mirror live into Web UI. Phase 9-bis fixes the memlink 400 on out:telegram:* assistant ingest. Phase 10 (ADR 0120 + ADR 0122) retires the telegram_photo:<path> text marker and introduces a structured channel- neutral Attachment type with an owner-scoped store and scope-authed retrieval route.

Runtime-owned memory boundaries now include canonical owner identity handling for web-chat living-document routes, client-editable owner-scoped user_model_summary surfaced through the client-facing learning-profile alias, and the operator-only agent_system_prompt living-document override consumed by chat prompt assembly. Use runtime.md, data-and-scope.md, and web-chat-api.md for the detailed auth, owner-scope, and fallback behavior before editing routes_memory.py, dashboard memory components, runtime owner-id resolution, or prompt assembly.

Runtime-owned self-code source inspection uses source_search.py for read-only term extraction and ranking, self_code.py for direct self-code read/list/search commands, and self_code_safety.py for shared protected-path exclusion plus snippet redaction. The read path and search path share one post-filter classifier so nested protected directories and key/cert variants are blocked consistently. Use runtime.md for the detailed source-answer synthesis and fallback behavior.

memlink-hybrid is the memory service. The root README identifies it as a standalone service backed by PostgreSQL schemas for core, world, and moth memory. The OpenAPI contract is memlink-hybrid/openapi.yaml.

It serves HTTP concurrently: infrastructure/server.py runs a stdlib ThreadingWSGIServer (one request per daemon thread) and adapters/outbound/db.py (PostgresDatabase) is backed by a bounded psycopg_pool.ConnectionPool — each request thread and the single in-process derivation worker check out their own connection (ADR 0146 Phase 1, which replaced the prior single-threaded wsgiref server + one RLock-guarded connection that serialized all callers — the garcia chat-history outage). World-memory RLS (migration 0079) stays correct under pooling because the app.owner_id scope is a transaction-local GUC set per checkout; the recycled-connection isolation guarantee is enforced by tests/test_pool_rls_isolation.py.

Inbound auth (adapters/inbound/auth.py) carries an Ed25519 local public-key verify path alongside the legacy HMAC scheme (ADR 0146). The prontera prerequisite that feeds it — per-tenant Ed25519 keypairs, an Ed25519 /sign returning {signature, kid}, and a GET /.well-known/memlink-jwks.json carrying the owner↔kid binding — is specified in docs/plans/2026-06-17-memlink-phase2-prontera-ed25519-sign-jwks-spec.md (Phase 2, operator-gated; deployed dormant on the prontera broker). Phase 3 / Design B wires the verifier’s two resolvers (public_key_resolver / owner_kid_allowlist) as a composition of two pieces (bootstrap): infrastructure/jwks_key_store.py (JwksKeyStore) is a pure per-vault kid → public key cache (lazy, fail-closed, refresh-on-unknown-kid debounced/rate-limited/circuit-broken, bounded stale-on-error), and adapters/outbound/owner_vault_directory.py (OwnerVaultDirectory) resolves owner → currently-assigned vault from the client-provisioning control-plane tables (steelmoth.clients ⋈ pool_slots, memlink’s own Postgres; short TTL + negative-cache + rate-limit so an auth-failure flood can’t exhaust the pool; the operator is a static entry). So a request claiming owner A is verified against A’s assigned vault’s key — and because clients.owner_id is the single source feeding both the gateway’s signing identity and this lookup, the binding can’t drift (ADR 0146 #F; the JWKS carries no owner_id). It stays inert — the resolvers are built only when MEMLINK_HYBRID_SCOPE_AUTH_ASYMMETRIC is on AND a JWKS store + Postgres store exist (else None), so a default-off build does zero network I/O and the verify path is byte-identical until activation (Phase 4/5, gated). The runtime-signer↔verifier canonical bytes are pinned equal by a shared golden corpus (steelmoth-runtime + memlink-hybrid tests).

The enforce precondition is rotation-on-release (ADR 0146, operator-decided Option A — retire-don’t-reuse): a pool slot reused across owners would let a prior owner’s retained (un-rotatable) token sign for the slot’s next owner once verify is enforced. The provisioner’s release path retires the slot (status='retired', never reused) instead of freeing it when ProvisionerConfig.retire_slot_on_release (env STEELMOTH_PROVISIONER_RETIRE_SLOT_ON_RELEASE) is set — default-off/inert; flip near enforce. Design + decision: docs/plans/2026-06-17-memlink-rotation-on-release-design.md.

  • Update this page when runtime wiring, memlink API contracts, or the repo guide’s runtime reading order changes.
  • For endpoint or schema changes, use the OpenAPI contract and relevant handler code as sources before editing this page.
  • For live runtime fixes, follow the engineering pre-flight rule: prove the edited file and function are the live path before changing code.
  • This page is a high-level orientation only. It does not enumerate all runtime routes, adapters, migrations, or sidecar integrations.
  • It does not assert the current production container image or environment.