flowchart LR
user["Browser user"] --> ui["HTML + CSS + JavaScript"]
ui -->|"REST: create, list, load"| api["FastAPI routes"]
ui <-->|"WebSocket: submit + events"| socket["WebSocket endpoint"]
api --> app["AutocodeApplication"]
socket --> app
app --> runner["AgentRunner port"]
runner --> demo["deterministic demo"]
runner --> harness["agent-harness"]
app --> repo["SessionRepository"]
repo --> journal["append-only journal"]
repo --> sqlite["SQLite projection"]
app --> broker["session event broker"]
broker --> socket
app --> artifacts["artifact store"]
app --> search["search index"]
app --> jobs["background jobs"]
Autocode: Full-Stack Architecture and Reliability Contract
This chapter maps the application built in the numbered chapters. Autocode starts with the headless agent from the preceding course and adds a browser interface, web service, durable data layer, realtime event path, background work, and operating surface. Later chapters implement each boundary; this page fixes the vocabulary, stack, request flow, and definition of done they share.
The running application
Autocode is a local-first web application. A user opens a browser, creates or selects a session, submits a coding task, watches model and tool events arrive incrementally, and can refresh or reconnect into the same durable history. The CLI calls the same application service, so it does not acquire a second definition of session behavior.
The central entity is a session. It is more than a chat transcript:
\text{Session} = (\text{id}, \text{messages}, \text{events}, \text{artifacts}, \text{config\_hash}, \text{version}).
The identifier connects browser routes, WebSocket streams, database rows, and artifact references. Events preserve what happened, artifacts hold bytes that do not belong in event rows, and the version or cursor makes replay and synchronization observable. Runtime objects such as database connections, sockets, DOM nodes, and model clients remain outside the serialized record.
The complete stack
The browser never opens SQLite or calls the model directly. FastAPI owns transport concerns such as validation, status codes, static assets, and WebSocket lifecycle. AutocodeApplication owns the use case: append the user message, invoke an agent runner, persist every meaningful event, and publish it to observers. The repository owns durable ordering. These separations let a test replace the browser, network, or model without replacing the business behavior under test.
Request, event, and failure contracts
The stack carries two related flows. REST handles resource-shaped operations such as creating and loading sessions. WebSockets handle a long-lived run in which the client submits one message and receives many ordered events. Both flows meet in the application service and write through the same repository.
| Failure class | What the user observes | Primary guard |
|---|---|---|
| Contract drift | Frontend sends or assumes a shape the API no longer supports | Typed transport models and browser-to-service integration tests |
| Durability | A message acknowledged in the UI disappears after restart | Journal before projection or publication, then replay drill |
| Disconnect | Streaming stops or repeats after the socket returns | Monotonic cursors, idempotent projection, and replay from the last cursor |
| Convergence | Two devices disagree indefinitely about one session | Commutative merge and property-style two-writer tests |
| Leakage | Secrets or private code enter logs, bundles, or telemetry | Central scrubber and regression tests around every export boundary |
| Staleness | Search or job state describes files that have changed | Content fingerprints, checkpoints, and visible freshness state |
| Upgrade breakage | New code cannot open old data or serve old clients | Versioned data/API contracts and rehearsed rollback |
The experience targets are observable: first local UI feedback within 100 ms, stream lag no greater than one buffered chunk, local session reads targeting p99 at or below 50 ms, and no duplicate durable event after reconnect. Chapters measure these against named workloads rather than treating the targets as achieved by declaration.
The artifact contract in code
The project keeps durable facts serializable and injected dependencies out of persisted state. A small record demonstrates the boundary that later adapters preserve.
from autocode.domain import SessionRecord
session = SessionRecord("demo-session", title="Release rehearsal", config_hash="cfg-a")
session.append("user_message", {"content": "check the upgrade path"})
session.append("assistant_message", {"content": "I will inspect the release artifacts"})
print(session.to_dict())
assert session.version == 2
assert [event.kind for event in session.events] == ["user_message", "assistant_message"]{'session_id': 'demo-session', 'title': 'Release rehearsal', 'config_hash': 'cfg-a', 'version': 2, 'updated_at': '2026-08-27T00:00:12.554389+00:00', 'events': [{'session_id': 'demo-session', 'cursor': 1, 'kind': 'user_message', 'payload': {'content': 'check the upgrade path'}, 'event_id': 'demo-session:1:user_message:3718c3ae13a62ffe:2026-08-27T00:00:12.554312+00:00', 'created_at': '2026-08-27T00:00:12.554312+00:00', 'idempotency_key': ''}, {'session_id': 'demo-session', 'cursor': 2, 'kind': 'assistant_message', 'payload': {'content': 'I will inspect the release artifacts'}, 'event_id': 'demo-session:2:assistant_message:b467f81b59524387:2026-08-27T00:00:12.554389+00:00', 'created_at': '2026-08-27T00:00:12.554389+00:00', 'idempotency_key': ''}]}
The record contains event payloads and their cursors, but no open database connection or model client. That distinction matters at restart: a durable session can be reconstructed from facts, while runtime dependencies can be recreated from the current environment and configuration. Chapter 04 gives this record a journal and queryable projection.
Execution paths and ownership
The standard course path is the complete local web application, not an in-memory substitute. It serves browser assets and FastAPI routes from one process, stores sessions in SQLite plus the journal, and uses a deterministic agent runner so every learner can execute the same tests without credentials. The live-agent path swaps only the AgentRunner implementation.
| Path | Included | Purpose |
|---|---|---|
| Deterministic full stack | Browser UI, REST, WebSocket, application service, journal, SQLite, tests | Canonical build and evidence path |
| Live local agent | Deterministic stack with the agent-harness runner selected | Real model and tool behavior through the same boundaries |
| Production adapter | Reverse proxy, PostgreSQL, object store, managed identity, worker process | Deployment extension after local contracts pass |
| Dogfood release | Built wheel/image, representative workspace, backups, issue log | Product and operational evidence |
The backing project owns reusable implementation. The notebooks introduce each boundary, execute controlled examples through project APIs, and interpret the result. Frontend behavior lives in committed web assets; Python notebook cells do not maintain a second mock implementation of the application.
Acceptance conditions and non-goals
The capstone is complete when another learner can install autocode, start the service, open the browser, create a session, send a task, observe streamed events, refresh into the same SQLite-backed history, reconnect from a cursor, and prove the vertical slice with an automated WebSocket integration test. The same release must still demonstrate artifact recovery, search freshness, two-writer merge, checkpointed jobs, backup restore, and redacted support output.
The local application is production-shaped but not presented as a commercial service. The course does not claim production-grade process isolation, multi-tenant billing, universal semantic search quality, mobile clients, a hosted control plane, or a finished PostgreSQL/S3 deployment. Its full-stack claim is narrower and testable: frontend, transport, application logic, agent integration, persistence, realtime delivery, packaging, and operations form one runnable system.
Exercises
Trace one browser submission through every boundary. The goal is to distinguish a user interaction, a transport message, an application command, a durable event, and a rendered projection instead of calling all five “the message.”
[P00.1] Trace one browser submission
Describe the path of one user message from the composer to the WebSocket endpoint, application service, journal and SQLite projection, agent runner, session broker, and rendered timeline. At each boundary, name the data shape and the failure guard.