This roadmap starts from the implementation status ledger, not the historical feature waves. Its job is to order work so that new surface area is built on explicit identity, authority, bounds, and lifecycle contracts. It contains no calendar promise: priorities describe dependency and risk, while milestones describe verifiable exit conditions.
The old R0–R5 roadmap was useful for bootstrapping breadth. It is retired as a status authority because a wave-sized “done” label hid host-specific gaps: streams exist without wire pulling, tasks exist without kernel suspend/resume, and policies exist while some child evaluators omit the parent policy entirely.
Prioritization model🔗
Every work package is ranked on five questions:
- Authority: can the gap disclose or mutate state across a principal or capability boundary?
- Integrity: can it silently violate a serialized, persisted, or language-level contract?
- Blast radius: how many later features would otherwise copy the defect?
- Dependency: does another useful package need this boundary to be stable first?
- Evidence: can completion be expressed as focused and real-boundary tests?
| Priority | Meaning | Scheduling rule |
|---|---|---|
| P0 | authority or unbounded-input correctness | stop expanding the affected surface until closed |
| P1 | composition/protocol/persistence foundation | land before dependent agent or host features |
| P2 | semantic honesty and reliability | next coherent hardening wave |
| P3 | deliberate feature completion | begin only after its P0/P1 dependencies |
| P4 | portability, scale, and continuous quality | parallelize where it cannot obscure higher-risk work |
Small effort does not automatically raise priority. A one-line wire-format change needs migration and compatibility thought; a large identity fix can be P0 because everything above it assumes ownership.
Dependency spine🔗
flowchart TB
accTitle: Dependency spine
accDescr: Shows the components and relationships described in Dependency spine.
A0["P0.0 authenticated approval + journal reads"] --> I1["P0.2 principal-owned sessions"]
A0 --> J1["P1.4 explicit journal execution identity"]
TK["P0.5 live token lifecycle + capability semantics"] --> I1
C1["P0.1 capability-complete child context"] --> H1["P1.1 shared host builder"]
I1 --> H1
B1["P0.3 bounded frames and raw fetch"] --> S1["P1.2 subscription lifecycle + bounded queues"]
I1 --> S1
H1 --> P1["P1.3 ParseCtx and host parity"]
H1 --> R1["P2.1 Reef strictness and cache identity"]
H1 --> C2["P2.2 configuration contract honesty"]
J1 --> G1["P2.3 blob pin leases and health reporting"]
B1 --> W1["P1.5 wire-contract convergence"]
W1 --> ST["P3.1 stream cursor protocol"]
C1 --> ST
S1 --> ST
C1 --> T1["P3.2 unified task runtime"]
I1 --> T1
C1 --> WM["P3.5 WASM host ABI"]
L1["P2.4 language metadata and type soundness"] --> E1["P3.3 semantic editor index"]
H1 --> E1
ST --> WIN["P4 Windows transport/process design"]
T1 --> WINThis graph is intentionally conservative. For example, a stream cursor protocol is not merely a new RPC: it needs bounded queues, cancellation ownership, session/ref authorization, and wire budgets. Building it before those contracts would multiply later migration work.
Roadmap at a glance🔗
| Package | Priority | Primary owner | Depends on | Exit signal |
|---|---|---|---|---|
| authenticate approval and journal query; strengthen plan identity | P0 | kernel, proto, Leash | none | no unauthenticated authority mutation/read; refs cannot overwrite across owners |
| capability-complete child evaluator construction | P0 | shoal-eval | none | all child paths inherit exact authority/profile |
| principal-owned kernel sessions | P0 | shoal-kernel, shoal-auth | none | same name cannot cross owner without ACL |
| bounded frame and raw value retrieval | P0 | kernel, proto, MCP | none | no allocation or response exceeds negotiated budget |
| explicit policy-loader safety modes | P0 | Leash and hosts | none | agent hosts fail closed; local fallback is deliberate and visible |
| live token lifecycle and capability meaning | P0 | auth/kernel | none | bounded revocation latency; metadata cannot masquerade as grants |
| shared evaluator host builder | P1 | eval plus shoal/kernel | child context, identity | profile differences are declarative and tested |
| subscription lifecycle and bounded delivery | P1 | kernel/MCP | identity, wire bounds | unsubscribe stops worker; overflow is explicit |
| parser-context parity | P1 | syntax/eval/hosts | host builder | same bindings classify same statement across hosts |
| journal execution identity/schema | P1 | journal/kernel/eval | none | coarse/fine rows are explicitly related |
| wire-contract convergence | P1 | proto/kernel/MCP | wire bounds | DateTime/span/raw behavior matches schema and tests |
| Reef strictness and cache identity | P2 | Reef/eval | host builder | changes/errors cannot remain silently stale in strict mode |
| configuration honesty | P2 | config/hosts/prompt | host builder | every accepted field is consumed or rejected/deprecated |
| pin leases and durability health | P2 | journal/hosts | journal identity | pins have owners; write failure becomes observable |
| method metadata and function type soundness | P2 | value/eval/syntax | none | bidirectional method parity and uniform annotations |
| complete effectful ports | P2 | value/eval | child context | evaluator effect paths stop reaching ambient host directly |
| stream stdin and wire cursor | P3 | value/eval/proto/kernel/MCP | P0/P1 bounds/lifecycle | bounded pull/cancel/end/error contract is live |
| unified task runtime | P3 | eval/exec/kernel | child context/identity | local and kernel control the same owned task abstraction |
| semantic editor index | P3 | syntax/eval/LSP | host builder/language metadata | symbols understand modules/scopes and UTF-16 positions |
| prompt producer completion | P3 | shoal, prompt | config honesty | context fields are real or removed; slow data is deferred |
| WASM host integration | P3 | WASM/eval/Leash | capability context | effect-scoped ABI with wall deadline and value conversion |
| Windows architecture | P4 | cross-crate | task/stream/transport contracts | native transport, ConPTY, path, sandbox honesty, CI |
| continuous quality gates | P4/continuous | workspace | package-specific | evidence generated, not restated manually |
P0 — close authority and input-boundary defects🔗
P0.0 Authenticate approval and journal reads; fix plan identity🔗
Problem. cap.request is one of the router’s unattached methods. Its handler receives no Attachment, looks up a global stored plan by ref, evaluates the plan under the plan owner’s policy, and sets stored.approved = true. It never authenticates or authorizes the caller as an approver. journal.query is also routed without attachment and returns rows from the shared journal without caller scoping. The socket is Unix-user protected, but bearer-token principals within that user are presented as authority boundaries elsewhere.
Plan identity compounds the issue. Plan::new hashes (effects, reversibility, estimates) and uses only 16 hex characters. It excludes source, session, and principal. The kernel stores one StoredPlan per ref in a process-global HashMap, so two equal-effect plans overwrite each other even when their source or owner differs. Later apply/approved-exec checks prevent a simple source swap, but refs are not stable owner-scoped plan identities and an old plan can be invalidated by a new one.
Design. Require an attached authenticated caller for journal reads and capability requests. Define an explicit approver capability/profile; ordinary plan ownership is not automatically approval authority. Scope journal rows by caller policy, with a separate audited grant for cross-principal inspection. Make stored plan IDs unique and opaque (for example a random nonce) or hash a canonical record that includes source/AST digest, owner/session identity, and a collision-safe full digest. Keep content identity separate from object identity when both are useful.
Acceptance tests. Through raw kernel connections and MCP:
- unattached
cap.requestandjournal.queryreturnNOT_ATTACHED; - an attached non-approver cannot approve another principal’s plan or query its rows;
- an authorized supervisor can approve only the exact allowed owner/session/effect/source record;
- two principals and two sources with identical effect sets receive independent stored plan IDs;
- creating the second never changes
plan.get/plan.applyfor the first; - concurrent creation cannot overwrite, approve, or apply the wrong record;
- approval, denial, and journal access produce an audit event or durable record;
- deterministic content fingerprints, if exposed, are never treated as bearer authority.
Exit. The router’s public/unattached allowlist is generated or pinned as session.attach, parse, and complete only, unless a future method has an explicit proof for public access. Handler signatures make caller context mandatory for every state read/mutation. Protocol comments and tests agree with the router.
P0.1 One capability-complete child evaluator constructor🔗
Problem. spawn, parallel, on, and .shl execution create evaluators through separate paths. They do not consistently inherit Leash, Reef state, configuration, ports, cancellation, and session-scoped facilities. The policy omission can turn a restricted parent into an unrestricted child.
Design. Introduce a typed EvaluatorContext or ChildProfile owned by shoal-eval. It should carry explicit capabilities rather than clone arbitrary mutable evaluator state.
// Shape, not a pinned API.
struct EvaluatorContext {
fs: Arc<dyn Fs>,
exec: Arc<dyn Exec>,
clock: Arc<dyn Clock>,
opener: Arc<dyn Opener>,
secrets: Arc<dyn SecretPort>,
config: Arc<dyn ConfigPort>,
leash: Arc<LeashContext>,
reef: ReefContext,
cancel: CancelToken,
host_profile: HostProfile,
}Separate inherited mutable language state—bindings, cwd, environment, module cache, transcript—from authority. Each child kind can choose copy/share/isolate semantics for language state but must not accidentally widen capabilities.
Acceptance tests. For every constructor site:
- a parent with
proc_spawn = denycannot spawn through the child; - a denied filesystem effect remains denied;
- Reef resolution sees the documented inherited scope and lock;
- fake
Fs,Exec,Clock, opener, secret, and config ports observe child operations; - cancellation reaches a process tree and a waiting stream;
- child-local cwd/env mutation does not mutate the parent unless the construct promises it;
- adding a new capability field causes a compile error or a single exhaustive builder update.
Exit. No direct Evaluator::new remains at semantic child sites; a repository check enumerates and permits only composition-root construction. The security tests run through real spawn, parallel, on, and .shl syntax, not only the builder.
P0.2 Principal-owned kernel sessions🔗
Problem. A named session remembers the principal that first created it, but lookup is by name. A different authenticated principal can later attach to that same evaluator and transcript.
Decision required. Choose one model explicitly:
- sessions are keyed by
(principal_id, session_name)and names are private by default; or - sessions have a stable owner plus persisted or memory-resident ACL, with explicit share/revoke.
The first is the safer near-term contract. The second is a product feature and needs audit events, permission inheritance, race handling, and protocol methods.
Acceptance tests. Use two real tokens and two connections:
- the second principal cannot read variables, transcript, task, PTY, plan, or event state from the first principal’s same-named session;
- attach races cannot create two inconsistent owners;
- refs from one owner fail under the other with one stable authorization error;
- journal principal/session filters reflect the owner model;
- disconnect and restart behavior is documented and tested;
- MCP resource URIs cannot bypass the same check.
Migration. Current live sessions are memory-only, so there is no session-state data migration. Journal rows remain historical facts; do not rewrite principals. If the protocol’s returned session ID changes, support old clients through a versioned attach response or a deliberate breaking version.
P0.3 Bounded frame ingestion and explicit raw retrieval🔗
Problem. Kernel and MCP readers call read_line before checking the 16 MiB cap. A peer can force larger allocation with a newline-free frame. value.get {format:"raw"} returns full base64 without the ordinary 64 KiB elision clamp, and MCP forwards it.
Design. Replace line accumulation with a bounded delimiter reader that:
- consumes chunks up to a hard maximum;
- detects overflow before growing beyond the maximum;
- closes or drains the offending frame according to one documented rule;
- preserves multiple valid frames already buffered;
- rejects invalid UTF-8/JSON without poisoning the next connection state.
Raw data should use either (offset, length) slices with a hard per-response maximum or an immutable blob resource with chunked reads. Base64 expansion must count against the response budget.
Acceptance tests. Cover one-byte chunking, exact-boundary frames, cap-plus-one without newline, two frames in one read, malformed JSON followed by valid input according to the chosen recovery rule, large raw values through kernel and MCP, offset overflow, and disconnect during a chunk.
Exit. Memory use is bounded independently of newline arrival, every response has a documented maximum, and an agent can retrieve a large immutable value through bounded repeated requests.
P0.4 Explicit policy-loader safety modes🔗
Problem. The convenient local policy loader can turn a malformed user policy into permissive operation. That may suit an interactive rescue mode, but it is unsafe as an implicit agent-host default.
Design. Add an explicit mode such as FailClosed, FailOpenWithDiagnostic, or NoPolicy. Composition roots choose deliberately. Kernel/MCP production startup should fail closed when a configured policy cannot be read or parsed. The local REPL may offer a visible recovery choice.
Acceptance tests. Missing, unreadable, wrong-version, and malformed policies must be exercised through CLI and kernel startup. Attach/capability results must distinguish “policy allowed” from “OS dimension enforced.” No test may infer network containment when the backend is absent.
P0.5 Live token lifecycle and capability meaning🔗
Problem. The persistent kernel opens tokens.json once and keeps the resulting token vector in memory. The separate shoal-token command rewrites that file, but the kernel has no reload path. A new token fails until restart; an externally revoked token remains accepted until restart unless its already-loaded expiry passes. PROFILE and --cap values are returned in attach metadata but are not consumed by Leash or handler authorization.
Design. Prefer kernel-owned create/list/revoke operations behind a local administrative authority, so mutation and validation share one serialized store. If file-based administration remains, add an interprocess lock, persisted generation, safe reload before validation or via a watcher, and a stated maximum revocation latency. A failed reload should fail closed for tokens changed since the last known-good generation without breaking already-established policy deliberately.
Choose one semantic contract for profile/caps:
- make them enforced restrictions intersected with principal Leash and handler rights; or
- rename/version them as descriptive labels and remove capability wording from responses/CLI.
They must never widen principal policy. Established connections also need a revocation decision: revocation may block only future attach, or it may terminate/recheck sessions; state that explicitly.
Acceptance tests. Against a live kernel, create a token and attach without restart; revoke it and prove attach fails within the promised bound; exercise expiry; race two administrators without lost updates; corrupt/partially replace the file; and prove cap/profile strings do not grant an operation absent principal policy. If live connections are revoked, verify task/PTY/subscription cleanup.
Exit. CLI output identifies serving versus disk generation, operational docs no longer require an unstated restart, and the status/attach schema says whether token attributes are enforced or merely descriptive.
P1 — stabilize shared composition, protocol, and persistence🔗
P1.1 Shared evaluator host builder🔗
Problem. Local and kernel composition roots install different config, aliases, environment, init, adapters, Reef, journal/frecency, event, and prompt-related services.
Design. Create a host-neutral builder whose inputs are explicit:
| Input | Examples |
|---|---|
| identity | principal, session ID, interactive actor |
| filesystem/session | cwd, environment, state root |
| policy | Leash context and enforcement requirements |
| language extensions | adapters, Reef chain, aliases, init modules |
| persistence | journal handle, frecency, transcript policy |
| interaction | terminal/PTY, opener, picker, prompt snapshot producer |
| agent bridge | EventBus publisher, ref store, output limits |
Define named profiles such as InteractiveLocal, NonInteractiveLocal, and KernelSession. A profile must state deliberate omissions; it must not rely on which setter a caller happened to remember.
Acceptance tests. Feed the same temp config, adapter, Reef manifest, init file, cwd, env, and fake ports into local and kernel profiles. Assert equal language-visible bindings where parity is promised and exact, documented differences where it is not.
Exit. Composition roots primarily parse CLI/protocol inputs and select a profile. Feature wiring does not require unrelated edits to two hand-built evaluator sequences.
P1.2 Subscription ownership and bounded EventBus delivery🔗
Current split. The kernel bus already has the right core backpressure shape: a 1,024-event replay ring, a 256-event queue per subscriber, one isolated writer thread, coalesced {dropped, latest_seq} summaries, and explicit queue closure on kernel unsubscribe/disconnect. Two adjacent paths still diverge:
- the evaluator’s in-language EventBus uses unbounded
mpscsubscribers and clones/sends while its channel-map mutex is held; - MCP
resources/subscribecreates a dedicated connection/thread, butresources/unsubscribehas no facade-side registry or handle with which to stop it.
Design. Reuse the kernel semantics as the cross-bus vocabulary: owner, subscription ID, capacity, overflow/gap marker, cancellation token, and close/join path. Give MCP a URI-keyed registry whose unsubscribe closes the dedicated connection and joins or supervises its worker. Give language channels finite per-subscriber capacity without blocking a publisher; release the global map lock before fan-out where practical.
Acceptance tests. Preserve the existing kernel stalled-consumer, coalesced-gap, unsubscribe, and disconnect tests. Add equivalent language-bus pressure tests. Through real MCP stdio, prove that unsubscribe stops notifications and the forwarding worker, disconnect cleans all owned subscriptions, and repeated cycles return thread/task counts to baseline. A durable-channel gap must remain repairable through cursor read.
P1.3 Parser-context and host parity🔗
Problem. Local parsing can use evaluator bindings through ParseCtx; kernel exec parses each request context-free. A name bound as a command/function can therefore classify differently.
Options. Either expose an immutable parse snapshot from evaluator state, or make initial parsing binding-neutral and perform shared post-parse statement-head resolution. Do not place evaluator dependencies in the syntax leaf.
Acceptance tests. Build a table of aliases, functions, module exports, Reef tools, adapters, builtins, unknown names, and shadowing cases. Parse/evaluate each through local source, script, kernel, and MCP. Pin the same AST or the same documented semantic result.
P1.4 Explicit journal execution identity🔗
Problem. Kernel runs add a coarse whole-submission entry while the embedded evaluator adds per-statement rows to the same entry table. Code reconstructs journal-channel membership by inspecting AST shape because there is no row kind or parent relationship.
Design. Add stable columns or a related execution table:
kind = submission | statement
parent_id = NULL for submission; submission id for statements
ordinal = statement order inside the submission
host = local | kernel | other stable vocabularyChoose whether local multi-statement source also receives a submission row. Queries should require or clearly default a granularity. Event payloads return IDs directly instead of discovering “latest.”
Migration. Bump PRAGMA user_version; migrate in one transaction; preserve v1 rows. AST-shape classification may backfill known kernel coarse rows, but ambiguous historical rows must remain explicitly unknown rather than guessed as authoritative.
Acceptance tests. Create a v1 fixture, migrate, execute multi-statement success/failure/crash cases, reopen, query each granularity, replay journal/transcript channels, and verify no duplicate or misattributed counts.
P1.5 Wire-contract convergence🔗
Resolve the known producer/schema disagreements together:
- emit DateTime in the documented RFC3339 form or version the schema to Unix nanoseconds;
- preserve the implemented optional outcome-span path in normal and elided encodings, with producer coverage for honest absence;
- make raw byte retrieval bounded as in P0.3;
- pin recursive value budget accounting and truncation summaries;
- distinguish durable blob refs from process-local task/PTY/stream/plan refs;
- generate or test the numeric error-code inventory from one owner.
Run serialization fixtures through proto, kernel producer, MCP mapper, and resource read. Avoid changing only a comment: consumers need a transition story for any previously emitted DateTime.
P2 — make semantic and operational contracts honest🔗
P2.1 Reef strict discovery, cache identity, and probe authority🔗
Add a strict mode for scripts/agents that reports unreadable or malformed ancestor manifests, lock-write failure, unavailable providers, and ambiguous latest resolution. Decide whether a runner/hermetic-only manifest establishes scope even with no tools.
Replace cwd-only evaluator caching with a chain identity that includes discovered manifest paths and change tokens. Separate fast metadata caching from security-sensitive executable content identity. Version probes execute code; route them through the same Leash/spawn capability path before probing.
Exit tests. Modify/create/delete a manifest while cwd stays fixed; replace an executable without changing its name; make the lock unwritable; present an empty-tools runner manifest; deny probe spawn; restart and prove deterministic lock/view behavior.
P2.2 Configuration contract honesty🔗
For render.width, kernel.*, journal.*, and leash.policy, choose one of three honest outcomes:
- wire the field through the shared host builder;
- mark it experimental and reject it outside the owning host;
- deprecate and remove it with a validation diagnostic.
Unify core and rich-prompt project discovery while migrating legacy prompt.template to prompt.format.left. Add a generated consumer ledger so a typed field without a read site is a review failure.
P2.3 Journal pin leases and durability health🔗
Replace anonymous permanent pins with owner leases: manual, history retention, live session spill, or another stable class. Session shutdown/restart needs a recovery rule. GC should never delete a leased object and should report why a candidate is retained.
Journaling intentionally avoids breaking command execution, but swallowed write errors need an observable health channel, diagnostic counter, or degraded status. Align evaluator, kernel, history, and doctor on one state-root resolver.
P2.4 Method metadata parity and function type soundness🔗
Generate or validate metadata against dispatch in both directions. The initial fixture must catch the current table/range .get over-advertisement and bool .str/.display under-advertisement.
Define one runtime annotation checker for expression calls, command-style calls, defaults, variadic arguments, closures, module functions, and return values. Decide whether annotations coerce or check exactly; encode the decision in corpus cases and diagnostics with spans.
P2.5 Complete effectful capability ports🔗
Inventory direct std::fs, path metadata/canonicalization/existence, OpenOptions, and watcher calls inside evaluator/value effect paths. Extend Fs or introduce narrower traits for metadata, atomic write/append, and watch. Keep pure parsing/rendering code free of host traits.
Exit. A denied or fake filesystem capability observes .save, .append, watch, canonicalization, and all builtins. A repository lint/check prevents new ambient filesystem calls in restricted modules.
P2.6 Resolution and registry consolidation🔗
Create a typed command-resolution result for builtin, function, alias, adapter, Reef executable, ambient executable, and interpreter runner. Preserve current precedence through table-driven tests before refactoring. Keep the builtin identity registry in the leaf syntax crate; resolution itself belongs in evaluation and must not create a dependency cycle.
P3 — complete deliberately scoped features🔗
P3.1 Stream-to-stdin and wire cursor protocol🔗
This is one lifecycle design, not two convenience patches. Define:
- cursor ownership and session/principal authorization;
- item, error, end, timeout, and cancellation frames;
- maximum items/bytes per pull and queue capacity;
- slow-consumer overflow behavior;
- conversion from structured items to stdin bytes;
- child exit versus producer error precedence;
- disconnect, drop, and kernel-restart semantics.
Prefer pull with bounded batches over an unbounded push-only socket. For stdin, write through a cancellation-aware producer task and close the pipe deterministically. Never eagerly collect an unbounded stream to simulate support.
P3.2 Unified owned task runtime🔗
Evaluator jobs and kernel async tasks currently expose overlapping but different control. Define one task abstraction around owned process groups/async computation, state transitions, output refs, cancellation, suspend/resume capability, and terminal association.
If suspend/resume cannot be provided for a task class, capability discovery should say so before the operation. Preserve the current honest TASK_CONTROL_UNAVAILABLE until a real backend exists.
P3.3 Semantic editor index🔗
Build an analysis layer over parsed ASTs with document/module identity, lexical scopes, exports, function signatures, and source maps. It must not execute arbitrary config, Reef probes, or commands. Convert byte spans to UTF-16 LSP positions at one tested boundary.
Then move declaration, references, rename, signature help, and semantic completion from token splitting to this index. Dynamic aliases/adapter/Reef commands can remain explicitly partial with a snapshot interface from the host.
P3.4 Complete the prompt producer🔗
Decide which PromptContext fields are product promises. Produce editing mode, multiline state, output mode, stash count, battery, and custom modules, or remove misleading unused schema. Slow segments such as git status should use a cached/deferred producer with invalidation and a redraw signal; the pure renderer remains IO-free.
Set a host-side collection budget separately from pure render time. Snapshot tests should cover missing, stale, and updated deferred segments without depending on a live git repository.
P3.5 WASM host ABI🔗
Do not expose the current Wasmtime leaf as “plugin support.” First define:
- component/module format and versioning;
- value and error conversion;
- declared effects and Leash checks for every host import;
- filesystem/network/process/secret capabilities;
- fuel plus wall-clock deadline/interruption;
- memory/table/instance limits and output budgets;
- cache identity, signature/provenance, and update policy;
- cancellation and trap diagnostics.
The first end-to-end test should invoke a tiny module through evaluator syntax, deny an undeclared effect, interrupt an infinite loop by wall time, and preserve a structured value round trip.
P3.6 Runner and PTY ergonomics🔗
Generalize bare path-head execution beyond .shl only after command resolution is typed and runner selection is unambiguous. Preserve explicit run as the diagnostic escape hatch.
For kernel PTYs, add a screen/change event or cursor protocol only after subscription lifecycle and bounds land. Screen diffs need sequence, resize, reset, and slow-consumer semantics; polling remains the honest current interface until then.
P4 — portability, scale, and continuous evidence🔗
P4.1 Windows as an architecture project🔗
Create a Windows design record before scattering cfg(windows) branches. It must decide:
- authenticated local transport replacing Unix sockets;
- ConPTY ownership, resize, screen, and cancellation;
- job objects replacing Unix process groups/signals;
- path/wide-string representation and non-UTF-8 contract translation;
- executable resolution and extension rules;
- filesystem sandbox honesty when no matching backend exists;
- symlink/reparse-point-safe undo;
- file watch semantics;
- state/config directory conventions;
- Windows CI and real integration tests.
Leaf language crates can be made portable in parallel. Do not claim host support until the transport, execution, persistence, and security matrix is coherent.
P4.2 Kernel scale and failure containment🔗
After correctness work, replace thread-per-connection/subscription where measurements justify it. Before selecting an async runtime, measure connection counts, publisher contention, memory per idle session, and PTY/task load. Remove panic-capable work from shared lock sections and define poison recovery or process-fail policy.
P4.3 Continuous quality gates🔗
- generate corpus/adapters/crate counts for the site instead of copying them;
- merge duplicate conformance harness logic into shared test support;
- make fuzz target compilation blocking before expanding fuzz claims;
- isolate ANSI tests from ambient
NO_COLORand test both modes deliberately; - opt member crates into workspace lints one at a time, fixing existing violations first;
- record benchmark baselines with hardware/toolchain metadata and compare distributions;
- add architecture checks for child constructors, ambient filesystem calls, protocol error codes, method metadata parity, config consumers, and internal link targets.
Milestone gates🔗
Milestones are capability gates, not dates.
Gate A — authority-safe embedding🔗
Complete P0.0, P0.1, P0.2, P0.4, and P0.5.
Exit statement: “Every evaluator derives from an explicit capability profile, authenticated session names cannot cross principal boundaries, and only an authorized attached caller can read shared journal state or mutate plan approval.”
Required evidence: adversarial child syntax tests, two-token live kernel tests, fail-closed policy startup tests, and updated threat model.
Gate B — bounded agent transport🔗
Complete P0.3, P1.2, and P1.5.
Exit statement: “Every inbound frame, outbound value, and live subscription has an enforced budget, owner, overflow/cancellation rule, and tested facade mapping.”
Required evidence: cap-plus-one allocation tests, raw chunk retrieval through MCP, stalled-consumer stress, unsubscribe lifecycle, and producer/schema serialization fixtures.
Gate C — one deliberate host model🔗
Complete P1.1, P1.3, P2.1, and P2.2.
Exit statement: “Local and kernel environments are constructed from named profiles, with tested parity and explicit differences for config, parsing, adapters, Reef, and init state.”
Gate D — durable execution identity🔗
Complete P1.4 and P2.3.
Exit statement: “Every persisted row has a declared execution granularity/parent, every retained blob has an owner, and degraded durability is observable.”
Gate E — stream/task expansion🔗
Complete Gate A and Gate B before P3.1/P3.2.
Exit statement: “Streams and tasks cross process boundaries with bounded pull/output, exact ownership, cancellation, and honest control capabilities.”
Pull-request slicing guidance🔗
Avoid combining a schema migration, semantic behavior change, and broad module move in one review. Preferred slices are:
- characterization tests for current behavior and known defect;
- new leaf type/trait or versioned protocol shape;
- one composition-root integration;
- remaining host/facade integrations;
- migration/compatibility removal after consumers move;
- docs/status/diagram update in the same semantic landing.
For security fixes, the characterization test must not normalize the vulnerable behavior as desired; mark it ignored or assert the safe target in the fixing branch. For wire/schema changes, keep old fixtures so backward handling is explicit.
Work that can safely parallelize🔗
| Track | Can run beside | Must coordinate with |
|---|---|---|
| method metadata fixtures | journal schema design, policy loader | function type work and completion generation |
| journal v2 fixture tooling | prompt producer, LSP index exploration | kernel event replay and history CLI |
| prompt deferred snapshot design | journal, wire reader | shared host/config builder |
| Windows leaf-crate compile fixes | most Unix hardening | public path/value/proto representation decisions |
| benchmark harness metadata | all semantic work | release baseline claims |
| doc generation/link checks | all tracks | renamed routes and generated protocol/config data |
P0.1 and the shared host builder should be serialized around evaluator construction. P0.2 and task/ event ref work must agree on identity. P0.3 and stream cursor design must share one budget vocabulary.
Deliberate non-goals for the next hardening gates🔗
- adding more kernel methods before identity and bounds are stable;
- presenting WASM as a plugin ecosystem before a capability ABI exists;
- emulating stream support by unbounded collection;
- claiming universal hermetic networking without an enforcing backend;
- recovering live PTY/task objects after restart without a supervised-process design;
- broad Windows host claims based only on compiling leaf crates;
- rewriting the language to achieve resolver cleanup;
- preserving historical wiki/root prose as a second status database.
Retiring the historical R0–R5 roadmap🔗
The useful rationale maps forward as follows:
| Historical wave | Preserved result | Remaining work now owned by |
|---|---|---|
| R0 interactive ergonomics | local render/exit correctness | continuous host regression tests |
| R1 streams/channels | structured sources/combinators/bridge | P1.2 and P3.1 |
| R2 namespaces/builtins | structured data/OS command surface | P2.5 and effect-backend honesty |
| R3 modules/tasks/plan/undo | composition primitives and journal integration | P0.1, P1.4, P3.2 |
| R4 ports/modularization | dependency direction and smaller modules | P1.1, P2.5, P2.6 |
| R5 corpus/docs/polish | corpus beyond original target | continuous quality and this Zola atlas |
Historical counts—1,218 corpus cases, 74 suites, and 42 adapters—must not be used as current status. The corpus audit represented in this site found 1,310 cases across 77 suites. Adapter inventory is better generated because definitions and command tables do not map one-to-one to a meaningful feature count.
Roadmap maintenance rule🔗
A package moves to complete only when its stated exit tests exist and the implementation status ledger loses the corresponding qualification. If implementation reveals a new dependency, update the dependency spine before starting dependent work. If a product decision removes a feature, replace the package with an explicit unsupported contract and test; deletion can be a valid completion.