writeonce/docs/stories/jarvis/00-story.md
shoney.arickathil ad1ad8361c docs(audit): fix stale docs against the code (TLS, net.connect, RNG, lang-41); jarvis deps
Code is the source of truth; these claims no longer matched runtime/src:

- "net.connect does not exist" — landed 2026-09-07 (id 110); net.connect_tls /
  read_tls / write_tls (115-117) + net.accept_tls (118), WO_B_MAX 118. Fixed
  in jarvis 00-story (problem statement + architecture + out-of-scope), porch
  00-story (proxy middleware row), rv2 7 (push-collector fork), 00-code-review
- "TLS: none / proxy-mandated forever" — retired by rv2 9 (in-process TLS both
  directions). Fixed in porch + web-app + site example READMEs (proxy is now a
  deployment choice; HSTS row), 00-code-review
- "no RNG anywhere in the runtime" — imprecise: the runtime has a getrandom(2)
  source since rv2 9 (TLS ephemerals), but nothing exposes it to .wo yet.
  Fixed in CODE-LOGIC (digests), lang 34, porch 2, status lang-39 row
- "porch 9 blocked on language 41" — lang 41 fixed 63065ff. Fixed in porch 1,
  jarvis 00-story, status NEXT PLAN, dependency graph (L41 done, P9 ready)
- dependency graph §7 rewritten: the runtime side is done; jarvis 1 waits only
  on porch (developer's porch-first order). Adds jarvis 1's dependency table +
  the build order that satisfies it
- 00-code-review: a dated 2026-09-09 re-verification appended (record kept)
- site README lives in the writeonce-site submodule: committed there, pointer
  bumped here

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit f1049dd9b7c7770da28bcabfc1cb1324621e7ee6)
2026-09-15 01:16:13 +02:00

119 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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`](../wmux/00-story.md), 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. When this track was written
(2026-09-07) the runtime could not reach anything outbound — it had learned to
*listen* (sockets in 8/11/35, unix sockets and peer address in 35 and runtime-v2)
but never to *dial*: no `net.connect`, no outbound TLS. **Both gaps are now
closed** (confirmed against `runtime/src/wob.h`): `net.connect` (id 110, TCP) and
the full TLS 1.3 client `net.connect_tls`/`net.read_tls`/`net.write_tls` (ids
115–117, runtime-v2 9, live-gated) — plus inbound `net.accept_tls` (118) for porch.
An LLM API is HTTPS on a remote host, and the runtime can now dial it directly.
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
runtime work, now **partly built**:
- **`net.connect`** — outbound TCP — ✅ **landed 2026-09-07** (`wob.h` id 110,
`getaddrinfo` DNS + blocking connect; the outbound half language 38 named).
- **An outbound TLS client** — HTTPS over that socket — owned by
runtime-v2 [9](../runtime-v2/09-in-process-tls.md) (in-process TLS), which
**retires the standing "TLS is the proxy's job" doctrine**. In progress and
mostly landed: **A AEAD** (ChaCha20-Poly1305 + AES-GCM), **B HKDF**,
**C X25519**, **D signatures** (RSA PKCS1/PSS + ECDSA-P256), **E X.509** +
**SAN/hostname**, **F1** record layer, **F2** key schedule, **F3a** message
layer, **F3b** offline handshake verification, and the **F3c-core sans-io
handshake driver** — all vector-gated against RFC 8448 and real cert chains.
What jarvis still waits on is **F3c-net**: the `net.connect_tls` builtin (the
socket glue driving that driver over a real fd) plus a system CA trust-anchor
walk — and **G** (inbound server) for porch, not jarvis.
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) ⇄ net.connect_tls ✅ (rv2 9, done) ⇄ 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](01-chat-loop.md) — ✅ `ready` (forks auto-approved, `review_pending`) | a prompt sent to one LLM, tokens streamed back to the browser, the conversation persisted durably | the outbound seam (TLS phase F); porch 2/3/6/7; wo-html |
| 2 | [tool use / the agent loop](02-tool-use.md) — `refine` | function-calling and multi-step orchestration through actors — where "assistant" becomes "agent" | 1 |
| 3 | [retrieval (RAG)](03-retrieval.md) — `refine` | 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.
**Sequencing (set 2026-09-09):** the outbound TLS seam is done (runtime-v2 9),
so jarvis is no longer blocked on the runtime. The developer set the build order:
**jarvis is implemented once [porch](../porch/00-story.md) is complete and ready
for all future jarvis iterations** — jarvis's chat loop is a porch app, so porch
lands first, then jarvis 1–3.
## Dependencies
Consumed, and already `ready` or shipped:
| Needs | From |
| --- | --- |
| signed cookies, session id | porch [2](../porch/02-randomness-and-cookies.md) |
| durable conversation history, revocable sessions | porch [3](../porch/03-sessions.md) + `@table` |
| incremental response writes | porch [6](../porch/06-streaming-core.md) |
| token streaming to the browser | porch [7](../porch/07-sse-and-compression.md) (SSE) |
| the chat UI | `wo-html` / `writeonce-view` |
Blockers, which must land before iteration 1 starts:
| Blocker | Owner | State |
| --- | --- | --- |
| outbound TCP (`net.connect`) | language [38](../language-runtime-database/38-content-platform-capabilities.md) | ✅ **landed 2026-09-07** (`wob.h` id 110) |
| outbound TLS client | runtime-v2 [9](../runtime-v2/09-in-process-tls.md) — in-process TLS; **retires the proxy-termination doctrine** | ✅ **LANDED 2026-09-09** — the full client: A–E crypto, F1–F3c handshake, SAN/hostname + basicConstraints/EKU chain validation, and **`net.connect_tls` / `net.read_tls` / `net.write_tls`** (ids 115–117), live-gated (`just tls`, 5/0) from `.wo` incl. untrusted-chain + hostname-mismatch negatives. **jarvis's outbound seam is open** (G inbound server is porch's, not jarvis's) |
## 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 porch is complete | the runtime blockers (`net.connect`, TLS, language 41) have all landed; what jarvis now waits on is the **framework** — the developer set jarvis to follow porch completion (see Sequencing) — 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.