writeonce/docs/stories/jarvis/00-story.md
shoney.arickathil cc1c82b2ef docs: jarvis track, runtime-v2 7/8/9, lang-41 fix design, fiber scope-gap
- jarvis (00-story): 6th track, 2nd software built with writeonce — an AI
  assistant; direct-HTTPS design; blockers named (net.connect + TLS)
- runtime-v2 7 observability + 8 symmetric cipher: moved from the language
  track (were 30/43); 9 in-process TLS: created from the gap jarvis surfaces,
  RETIRES the "TLS is the proxy's job" doctrine (both directions)
- language 41 (arena hang): fix design to ready — marshal cross-shard
  messages (root), align the shard_id % nshards route/compare + assert bound;
  poison-on-free + minimal fixture as follow-ups
- fiber scope-gap analysis (plan/exploration/fiber/01): porch vs fiber, what
  porch lacks, would developers prefer porch
- board + dependency-graph synced (porch 2-8 ready; rv2 table; §5/§5a graphs)

(cherry picked from commit 203470ceb2a151fe3584931cd4237af3f96a9f29)
2026-09-15 01:15:31 +02:00

5.7 KiB

Story — jarvis, the writeonce AI assistant

The sixth track, and the second whose product is an end-user program rather than a language capability — after wmux, the terminal multiplexer. Where wmux proves writeonce can build the tool a developer lives in, jarvis proves it can build the tool of the moment: an AI assistant, written end to end in .wo, durable and single-binary by construction. It serves the same north star — adoption by Linux developers — by meeting them where the attention is.

Numbering restarts at 1 and is local to this track; frontmatter carries track: jarvis. Status rules are the repo's, unchanged: status: in frontmatter is the only place state lives, no directory encodes it.

The problem, stated once

An assistant's whole job is to reach a model, and the runtime cannot reach anything outbound. It learned to listen — sockets in 8/11/35, unix sockets and peer address in 35 and runtime-v2 — but it has never learned to dial: there is no net.connect (outbound TCP), confirmed against runtime/src/wob.h (the net builtins stop at listen/accept/read/write plus the unix-socket client), and no outbound TLS client anywhere. An LLM API is HTTPS on a remote host. jarvis therefore does not begin until two things exist.

The design chosen is direct outbound HTTPS — jarvis dials the LLM API itself, keeping the pure single-binary story. That gates the whole track on language work:

  • net.connect — outbound TCP — language 38, written but not yet built.
  • An outbound TLS client — HTTPS over that socket — now owned by runtime-v2 9 (in-process TLS), created 2026-09-07 from this gap. It retires the standing "TLS is the proxy's job" doctrine, giving the runtime TLS both directions — the load-bearing choice jarvis's direct-HTTPS design forced into the open.

A local-gateway alternative was considered and set aside: jarvis could speak to a small companion process over a unix socket (net.connect_unix, id 107) or spawn one (proc.spawn, id 97) — both exist today — and let that companion do the HTTPS, exactly as inbound TLS terminates at a proxy. It is buildable now. It was rejected in favour of the single-binary story, in which the assistant owns its own connection rather than shipping a second executable.

Architecture

browser  ⇄  jarvis (a porch app)  ⇄  [blocked seam: net.connect + TLS]  ⇄  LLM API

Requests arrive at a porch web app; the answer streams the other way, token by token, LLM → jarvis → browser, over porch's SSE. Conversation state is durable in a @table, so history survives a restart with no external store — the writeonce differentiator wmux already showed for session state, applied to chat.

The iterations

Ordered by dependency; the first rung is the whole end-to-end seam, and nothing past it is worth building until that seam is proven.

# Iteration Delivers Needs
1 the chat loop a prompt sent to one LLM, tokens streamed back to the browser, the conversation persisted durably the outbound seam (language 38 + TLS); porch 2/3/6/7; wo-html
2 tool use / the agent loop function-calling and multi-step orchestration through actors — where "assistant" becomes "agent" 1
3 retrieval (RAG) embeddings + vector search over a document set; carries its own sub-gap — an embeddings call over the same outbound path, plus a vector store (pure-.wo or a new primitive, decided in that story) 1, and the embeddings/vector decision

Sketched, not committed — named so the shape is visible, not to schedule them: model routing / multi-model (choose a backend per request) and an MCP client (jarvis as an MCP host, calling tools over the protocol) — both on-brand, both later.

Only iteration 1's scope is settled by this overview; every iteration file is written and refined to ready before its code lands, per the repo's story discipline.

Dependencies

Consumed, and already ready or shipped:

Needs From
signed cookies, session id porch 2
durable conversation history, revocable sessions porch 3 + @table
incremental response writes porch 6
token streaming to the browser porch 7 (SSE)
the chat UI wo-html / writeonce-view

Blockers, which must land before iteration 1 starts:

Blocker Owner
outbound TCP (net.connect) language 38
outbound TLS client runtime-v2 9 — in-process TLS, created 2026-09-07 from this gap; retires the proxy-termination doctrine

What this track does NOT own

Not jarvis's Why
local, in-process model inference needs an ML runtime and heavy FFI — against the no-external-dependency doctrine
the local-gateway companion process considered and rejected (above) in favour of the single-binary story
voice / audio in or out a separate surface with its own capture and codec story; no rung asks for it
starting before the blockers land like porch 9 waiting on language 41, jarvis waits on the outbound seam — documented, not worked around

Review protocol

Same as every track: the developer reads one iteration, approves or amends, and the next starts only after approval. Each iteration is an unsplittable value slice with phases, Given/When/Then acceptance criteria, and an out-of-scope list, proven by a gate before it is called done.