Runtime, Networking, And Shell Backlog
Detailed decompositions for runtime, networking, shell, agent, and web shell
work. WORKPLAN.md links here but should not inline these subtasks.
Scheduler/Park Measurement
Pre-thread dispatch instrumentation and compact-vs-generic ParkBench comparison are historical context. In-process threading later closed the first blocked/resume measurement path with QEMU samples for private ParkSpace wait/wake. Future measurement work should be tied to a concrete runtime or SMP change, especially per-thread/per-CPU ring behavior.
In-Process Threading Implementation
Current implementation subgates recorded in the old workplan were all marked
complete, but the parent task still appeared unchecked. Before starting
follow-up work, reconcile this status against code, docs/roadmap.md, and
docs/changelog.md.
Completed subgates retained for context:
- Add
Threadstate with per-thread kernel stack, registers, and FS base. - Change scheduling from process-level to thread-level while preserving process-owned address spaces and cap tables.
- Add
ThreadSpawner/ThreadHandleand basic join/exit smoke. - Implement the first park authority capability and contended-path measurements.
Runtime Ring Reactor Bridge
The current kernel ABI still exposes one process-owned capability ring. A multithreaded runtime therefore needs a compatibility bridge until per-thread kernel rings land.
Ordered gates:
- Add one runtime-owned process-ring CQ drainer.
- Map
user_datacompletions back to ParkSpace-backed per-thread wait records. - Prove sibling threads can issue ordinary calls and receive out-of-order completions without both draining the process CQ.
- Retire the bridge when per-thread capability rings and completion routing
by generation-checked
ThreadRefbecome the kernel ABI.
Telnet Shell Demo
Visible outcome: make run-telnet boots capOS in QEMU with
hostfwd=tcp:127.0.0.1:2323-:23, a telnet-gateway boot service listens on
guest port 23 through the kernel TCP capability surface, and a scripted host
smoke runs telnet 127.0.0.1 2323, logs in through the existing credential
flow, issues one shell command, and sees a clean disconnect. The proof should
include a console UART line and a host-side transcript.
Ordered gates:
- Add the Phase B TCP interfaces to the canonical shared schema:
NetworkManager,TcpListener, andTcpSocket. Keep this milestone TCP-only;UdpSocket,DeviceMmio,DMAPool, andInterruptare decomposed-NIC / userspace-driver scope. - Replace the synthetic 10 ms smoltcp clock with scheduler-driven polling
on real
TICK_COUNT; the HTTP proof now persists as a retained smoltcp runtime polled from scheduler ticks. Depends onTimer. - Close the delegated endpoint relabeling gap before exposing shell launch
over Telnet. A remote shell user must not be able to type an arbitrary
endpoint identity such as
badge 200and spawn a child that acts as a different chat/adventure participant. Omitted shell syntax now preserves the delegated source identity, and the low-level spawn hardening proof keeps the legacy badge-zero encoding covered. The containment gates indocs/backlog/stage-6-capability-semantics.mdare complete; do not expose Telnet shell launch to any future badge-selection regression. Normal shell help and smoke-help expectations no longer advertise badge syntax. - Implement
NetworkManager,TcpListener, andTcpSocketas kernelCapObjects wrapping the existing smoltcp smoke path. Reuse ring dispatch; do not add syscalls.acceptandrecvmay be blocking calls for this milestone, with bounded result buffers and explicit close behavior. Initial implementation landed in commit7446e04at2026-04-25 14:48 UTC; follow-up review fixes removed timer-path allocation from deferred completion, hardened result-cap cleanup, and addedmake qemu-network-client-harnesscoverage for userspaceNetworkManagerClient,TcpListenerClient.accept, andTcpSocketClientsend/recv/close. - Complete the next endpoint-identity containment transition before unrelated Telnet gateway work: Gate 1 representation plus the minimum trusted mint path landed as the historical service-object routing proof. The selected follow-on is now Session-Bound Invocation Context: keep production remote shell launch blocked until one-session-per-process, privacy-preserving endpoint caller-session metadata, and shared-service migration settle.
- Add the socket-backed terminal handoff needed by the demo.
capos-shellmust still receive a cap namedterminalwithTerminalSessioninterface id, backed by the accepted TCP socket. Do not pass rawTcpSocket,ByteStream, orStdIOas a replacement for the login terminal boundary. Satisfy this either by adding typed service-export / grant support so a userspacetelnet-gatewayendpoint can be presented as aTerminalSession, or by implementing a real kernel socket-backedTerminalSessionCapObject. Implemented asTcpSocket.intoTerminalSession, which consumes a connected socket cap and returns a move-onlyTerminalSessionresult cap.make qemu-network-client-harnessproves output, prompt, visible echo, and submitted line handling over an accepted TCP connection. - Add a
telnet-gatewaydemo binary andsystem-telnet.cuemanifest. The trusted demo gateway gets bootstrapNetworkManagerandProcessSpawnerauthority, plus pass-throughcreds,sessions,audit, andbrokercaps needed to spawncapos-shellwith the same login/session semantics as the UART shell. The spawned shell must not receive raw network or broad process-spawn authority. - Add
make run-telnetand a scriptedqemu-telnet-harnesshost smoke that drives the full login/command/exit sequence and requires a proof line. - Document in
docs/proposals/networking-proposal.mdanddocs/proposals/shell-proposal.mdthat telnet is demo-only plaintext, binds only to host loopback in the QEMU harness, preserves theTerminalSessionboundary, and will be replaced by the SSH gateway once host-key, user-key, account, audit, and persistence prerequisites land. Implemented by branch commit5d11b12at2026-04-25 20:06 UTC.make qemu-telnet-harnessproves127.0.0.1:2323 -> guest :23, password login,caps, thesessioncommand, and clean exit with no password, rawNetworkManager, rawProcessSpawner, raw TCP, or unknown-cap leakage in the host transcript. Replacing the gateway’s factory network/spawn authority with scoped listener and shell-launch caps is tracked inREVIEW_FINDINGS.md; it is not required for the host-local visible demo.
SSH Shell Gateway
Visible outcome: make run-ssh-shell boots capOS in QEMU with a host-local
forward to guest SSH, an ssh-gateway service authenticates a normal OpenSSH
client with a configured public key, launches capos-shell with an
SSH-backed TerminalSession, runs one shell command, and disconnects cleanly.
The shell must see the same terminal/session/broker boundary as the Telnet
demo, not raw TCP or SSH protocol authority.
Blocked by: Telnet Shell Demo for socket-backed TerminalSession,
cryptography/key-management for sign-only host keys, local account/key records
for authorized SSH keys, audit records for remote authentication decisions,
and persistent storage before production host or authorized keys are treated
as durable.
Closeout prerequisite: before this milestone closes, reconcile its target
name and host-harness placement with the run-target/init-mandate policy in
docs/backlog/run-targets-and-init-policy.md (Gate A naming split, Gate B
init mandate, Gate C test split, Gate D default-make run integration).
The current make run-ssh-shell working name and any scripted host harness
may need to become test-ssh-shell and be relocated, and default-run
exposure has to be addressed there, not as another run-ssh-* recipe.
Ordered gates:
- Document the first SSH gateway contract in
docs/proposals/ssh-shell-proposal.md: gateway authority, host-key custody, authorized-key mapping, accepted channel set, denied SSH features, terminal handoff, audit, resource limits, and teardown. - Close or explicitly preserve the scoped gateway authority gap for SSH
before implementation: the gateway must receive a manifest-declared
scoped listener or listener factory for only the configured SSH port, and
the spawned shell must receive no raw
NetworkManager,TcpListener,TcpSocket, or transport protocol authority. A temporary host-local demo compromise must stay documented inREVIEW_FINDINGS.mdand the harness must prove the child boundary withcaps. - [x] Scoped listener authority sub-slice:tcp_listen_authoritymanifest grants use the cap badge as a validated TCP port and mint a one-shotTcpListenAuthoritythat can create only that listener;make run-tcp-listen-authorityproves generic init can forward the scoped cap to a child without rawNetworkManager. - Terminal-host wiring sub-slice:
ssh-gateway-terminal-hostnow uses manifest-scopedTcpListenAuthorityon the SSH development port andRestrictedShellLauncherto hand a socket-backedTerminalSessiontocapos-shellwhile proving the child lacks raw network, TCP, spawn, key-store, host-key, SSH gateway, terminal-factory, and launcher authority. This closes the scoped gateway authority gap for the bounded host-local proof; the final OpenSSH transport and channel harness remain separate gates. - Add manifest-declared shell launch authority for the gateway. Prefer a
shell-only launcher or supervisor grant that can start only
capos-shellwith reviewed pass-through caps; do not grant broadProcessSpawnerauthority to the SSH gateway unless it is explicitly recorded as a host-local development compromise. - [x] Restricted shell launcher sub-slice:restricted_shell_launchermanifest grants forward an init-heldRestrictedShellLaunchercap to a child service.make run-restricted-shell-launcherproves the child service has no rawProcessSpawner,launchShellhas no binary selector and launches onlycapos-shell, session/profile mismatch and dangerous grant attempts fail closed, and the spawned shell uses the supplied session while lacking raw network, TCP, host-key, authorized-key-store, SSH gateway, and restricted-shell-launcher authority. - Add schema/design stubs for the minimum SSH support objects:
SshGatewayor equivalent service contract, sign-onlySshHostKeywrapper around aKeyVault/PrivateKey,AuthorizedKeyStore, and SSH-backedTerminalSessionconstruction. Do not expose private-key bytes, raw authorized-key storage, or vault administration to the spawned shell. Implemented as schema/type-surface stubs forSshGateway,SshHostKey,AuthorizedKeyStore,SshTerminalFactory,TcpListenAuthority, andRestrictedShellLauncher; no bootable kernel or userspace implementation is implied by this gate. - Add a development host-key path. Manifest-seeded keys may be used only
for QEMU proof and must be labeled non-production; production host keys
require the key-management and storage path. Implemented as
kernelParams.sshDevelopmentHostKeyplus the narrowssh_development_host_keykernel source. The focused proof ismake run-ssh-host-key; the development cap signs boundedssh-ed25519exchange hashes from the manifest seed, verifies against the configured public key in QEMU, denies wrong algorithms, and remains explicitly non-production. Persistent production host-key storage, rotation, and key management remain future work. - Add public-key user authentication. Accepted SSH keys map to principals
and allowed shell profiles;
SessionManagermints the session only after signature verification, andAuthorityBrokerstill decides the actual shell bundle. - [x] Public-key session bridge sub-slice:SessionManager.sshPublicKeychecks a configuredAuthorizedKeyStorerecord plus bounded fixture auth bytes/signature, mints aUserSessionwith the accepted principal/profile andpublicKeyauth strength, andmake run-ssh-public-key-authproves unknown, disabled, unsupported, and bad-signature paths fail closed before broker bundle minting. This is not full SSH transport authentication or shell launch wiring. - [x] AccountStore-bound session sub-slice:SessionManager.sshPublicKeyconsults the bootstrapRamAccountStoreafter signature verification (lookup_by_principal), so non-Activeaccount statuses (Disabled, Locked, RecoveryOnly) and missing principals fail closed before a session is minted. Each denial cause maps to a stable, principal-blankedauth=audit code (ssh-key-unknown,ssh-key-disabled,ssh-key-profile-not-allowed,ssh-bad-signature,ssh-account-missing,ssh-account-disabled,ssh-account-locked,ssh-account-recovery-only,ssh-account-lookup-failed,ssh-profile-kind-invalid,ssh-profile-not-interactive,ssh-auth-bytes-invalid).make run-ssh-public-key-authcovers the non-account-status codes; thessh-account-*codes need anAccountStoreManagerCapkernel cap source for runtime-mutated QEMU proofs (tracked indocs/backlog/local-users-management.mdGate 2). - Reject unsupported SSH features with protocol failures and audit reason
codes: password auth when disabled,
exec, SFTP/subsystems, port forwarding, agent forwarding, X11 forwarding, arbitrary environment import, and multiple active shell channels. - [x] Policy-surface sub-slice:capos-config::ssh_policyreturns allowed/denied decisions, SSH protocol failure classes, and stable audit reason codes for the narrow allowed path and the denied feature set, including second session-channel opens before any shell request. Password auth remains fail-closed until a real verifier/backoff path is part of the gateway policy.make run-ssh-feature-policyproves the table in QEMU. The full gateway item remains open until this policy is invoked byssh-gateway. - Implement the gateway as a terminal host. It owns SSH packet/channel
state and gives
capos-shellonly a cap namedterminalplus the normal scoped launch grants. The child must not receive raw network, host-key, authorized-key-store, key-vault, or broad spawn authority. - [x] Bounded terminal-host wiring sub-slice:make run-ssh-gateway-terminal-hostproves a generic-init child service can combine scopedTcpListenAuthority,AuthorizedKeyStore,SessionManager,AuthorityBroker, andRestrictedShellLaunchergrants to deny an unknown key, mint apublicKeysession from a configured key, reject a mismatched broker profile, accept the matching broker profile, convert one host-local TCP socket into aTerminalSession, and launchcapos-shellwithout giving the shell raw network, process-spawner, TCP listener/socket, host-key, authorized-key-store, SSH gateway, SSH terminal-factory, or restricted-shell-launcher authority. This remains a bounded plain-TCP proof and does not complete full SSH packet/channel ownership or the OpenSSH harness gate. - Add
system-ssh-shell.cue,make run-ssh-shell, and a host harness usingsshagainst the forwarded port. The harness must prove one successful public-key login, one shell command, clean exit, unknown-key denial, disabled-password denial, denied forwarding/subsystem requests, and cleanup after client disconnect. - [ ] OpenSSH version-exchange slice: add a realssh-gatewayservice andsystem-ssh-shell.cueskeleton that accepts one host-local OpenSSH TCP connection, exchanges RFC 4253 identification strings, records the client software/version in bounded audit/proof output, and disconnects before key exchange without launching a shell. The normal compatibility harness should use/usr/bin/ssh; a separate low-level hostile TCP/banner fixture should prove malformed banners plus overlong identification strings fail closed. - [ ] KEXINIT and algorithm-selection slice: parse the unencrypted KEXINIT binary-packet exchange far enough to negotiate a pinned development algorithm set, reject unsupported algorithms with SSH disconnects, and keep the negotiated algorithm names out of any authority decision. The initial reviewed set should be exactly one modern KEX,ssh-ed25519host keys, one AEAD cipher/MAC pair, andnonecompression until rekey and broader algorithm policy exist. - [ ] Development key-exchange slice: complete the negotiated KEX, derive traffic keys from the shared secret, exchange hash, and session id per RFC 4253, callSshHostKey.signExchangeHashfor the SSH exchange hash, and complete the OpenSSH handshake without exposing private host-key bytes or raw entropy to the gateway’s child shell. Entropy is input for ephemeral KEX material, padding, and challenges; this remains non-production until host keys are durable and the entropy source has a reviewed production-quality policy. - [ ] OpenSSH public-key userauth slice: bind the OpenSSH userauth transcript toSessionManager.sshPublicKeyso the accepted key maps to the configured principal/profile, unknown keys are denied generically, and disabled password auth returns the expected SSH failure without invokingCredentialStore. - [ ] Channel policy slice: invokecapos-config::ssh_policyfor session-channel open, PTY, window-change, shell, exec, subsystem, forwarding, agent, X11, environment, and second-channel requests. The harness must prove the allowed shell path plus the denied feature requests with protocol-visible failures and sanitized audit reason codes. - [ ] SSH terminal launch slice: replace the plain-TCP terminal-host driver with the SSH channel-backed terminal path, launchcapos-shellthroughRestrictedShellLauncher, runsession,caps, andexitover OpenSSH, and prove disconnect cleanup for both client-close-before-shell and shell-exit-before-client-close. - Update
docs/proposals/shell-proposal.md,docs/proposals/boot-to-shell-proposal.md,docs/security/trust-boundaries.md, anddocs/proposals/index.mdwhen implementation begins so remote SSH login policy, terminal authority, and audit records stay aligned with the code.
Decomposed NIC Milestone
Move the NIC driver and TCP/IP stack out of the kernel into dedicated
userspace processes after the Telnet Shell Demo has made the socket interfaces
capability-shaped. make run-telnet must still pass end-to-end with zero
change to the shell or gateway.
Blocked by: Telnet Shell Demo and the userspace-driver transition gate.
- Define first
DeviceMmio,DMAPool, andInterruptschemas. - Move virtio-net ownership into a userspace driver process holding only
DeviceMmio,Interrupt, andDMAPoolcaps. - Split smoltcp into a separate userspace network-stack process that holds
the
Niccap from the driver and re-exports the Phase B socket interfaces. - Confirm
make run-telnetstill passes with the decomposed topology and the kernel no longer depends onsmoltcpor virtio-net.
Agent Shell / Agent Runner
The native shell’s agent mode must land before exposing the shell through a browser. The shell remains the trusted runner and session-cap holder. The model service receives prompts and returns structured tool calls, but never receives session caps, terminal caps, launcher authority, raw tokens, or secrets. Use a deterministic test model for the first proof.
Visible outcome: make run-agent-shell boots capOS in QEMU, grants
capos-shell a broker-issued LanguageModel cap plus per-tool permission map,
enters agent mode, exposes the current session bundle as typed tool
descriptors, executes one read-only tool call automatically, requires consent
or step-up for a mutating/admin-shaped call, handles user cancellation, and
records redacted audit output.
Ordered gates:
- Add the first agent-runner schema/interfaces:
LanguageModel,ModelInfo,ToolDescriptor,ToolCall,ToolResult, permission mode metadata, and bounded streaming/cancel semantics. Keep tool calls structured; do not parse model text as shell commands. - Extend
AuthorityBrokersession profiles so an operator shell can receive aLanguageModelcap and a per-tool permission map without receiving model-admin, model-catalog, or provider-token authority. - Add a deterministic in-tree
LanguageModeltest service that emits scripted tool calls for QEMU proofs. Do not block this milestone on large local model weights, remote providers, GPU, or storage. - Implement native shell agent mode: build the tool table from granted
session caps and schema metadata, stream model turns, gate each tool call
through
auto/consent/stepUp/forbidden, invoke only the capabilities held by the shell runner, and feed outcomes back into the loop. - Wire consent, step-up, cancellation, timeout, quota, and audit behavior. User interrupts beat model momentum; denied or cancelled tool calls become ordinary tool outcomes instead of hidden control flow.
- Add
make run-agent-shelland a scripted QEMU harness that proves read-only auto execution, denied forbidden/admin tool exposure, one consent or step-up prompt, cancellation, and redacted audit records. - Update
docs/proposals/llm-and-agent-proposal.md,docs/proposals/shell-proposal.md, andWORKPLAN.mdto record that WebShellGateway hosts this agent-capable shell/runner instead of defining a separate browser-side agent authority model.
WebShellGateway
Add the browser-hosted terminal and authentication gateway after both remote
TerminalSession proof and agent shell are in place. The gateway owns
HTTP/WebSocket or equivalent transport, TLS/origin/RP-ID validation, WebAuthn
challenge/response, terminal rendering, and session teardown. It launches the
same agent-capable native shell with the same broker-issued session profile.
Blocked by: Telnet Shell Demo for socket-backed TerminalSession, Agent
Shell / Agent Runner, passkey challenge/credential support in auth/session
services, and TLS/origin/RP-ID policy. OIDC is a follow-up path on the same
gateway, not a prerequisite for the first WebAuthn shell.
Visible outcome: make run-webshell boots capOS in QEMU with host-local
forwarding to the web gateway, a headless browser harness opens the terminal
UI with a virtual WebAuthn authenticator, authenticates, runs one shell or
agent command, logs out or closes the tab, and verifies clean
shell/process/session teardown plus a recorded transcript/proof line.
Ordered gates:
- Define the web terminal stream protocol over WebSocket or an equivalent browser transport: input, output, resize, paste, close, cancellation, flow control, session IDs, and bounded buffering.
- Add WebAuthn/passkey credential and challenge support: public-credential records, single-use bounded challenges, entropy fail-closed behavior, origin/RP-ID binding, user-presence/user-verification policy, sign-count handling, rate limiting, and redacted audit events.
- Add TLS and browser origin policy for QEMU and deployment modes. The first harness may use a local development trust path, but the gateway must have explicit Host/Origin/RP-ID checks and no production plaintext mode.
- Implement
WebShellGatewayas a terminal host service: accept browser sessions, authenticate, request the narrow shell/agent bundle fromAuthorityBroker, create or wrap a web-backedTerminalSession, spawncapos-shell, proxy terminal events, and release all session resources on logout, tab close, timeout, or shell exit. - Add
system-webshell.cueand manifest/grant wiring. The gateway gets only listen/TLS/auth/session/broker/restricted-launch grants needed for the job; the spawned shell does not receive raw network, raw auth material, model-provider tokens, or broad process-spawn authority. - Add
make run-webshellandqemu-webshell-harnesswith a headless browser virtual authenticator, transcript capture, login/command proof, logout/close proof, and assertions that failed auth and stale browser sessions do not leave a live shell. - Add optional OIDC authorization-code + PKCE login on the same gateway
after the OAuth/OIDC service exists. ID-token verification and
acr/amrmapping feedSessionManager/AuthorityBroker; raw tokens do not enter the shell or browser terminal transcript. - Update
docs/proposals/boot-to-shell-proposal.md,docs/proposals/shell-proposal.md,docs/proposals/llm-and-agent-proposal.md, and security trust-boundary docs with WebShellGateway authority, auth, terminal, audit, and teardown rules.