Folio Docs

Implementation Guide

This document explains how the ideas in The Document is the Computer are currently realized in the Folio prototype. It is implementation-facing: what exists, which classes carry the design, how data moves, and where the prototype is still intentionally incomplete.

Prototype Scope

Folio is not trying to implement the entire book at once. The prototype is strongest in the owned-state path: ::task, ::py, ::table, ::note, lifecycle metadata, and multi-document storage. It also includes a mirrored-state path for ::cal, ::email, ::chat, and ::web, but those are explicitly projections over mock backends rather than text-owned databases.

The key architectural split is: owned state is canonical in document text; mirrored state remains canonical in a backend while the document stores projection parameters, local annotations, and a durable action journal.

High-Level Architecture

Folio is built as a document runtime around a small core loop:

  1. Raw document text is stored in DocumentStore.
  2. DirectiveParser parses the text into directive descriptors.
  3. RenderCanvas turns those descriptors into a text-first reading surface with lazy widget activation.
  4. Each widget emits explicit mutations through SyncBus.
  5. DocumentStore applies those mutations to the target document and persists the result.
  6. NamespaceBridge rebuilds document-scoped Python state from the latest text.

Nothing in the system is supposed to mutate hidden widget state and then treat the document as a secondary export. The document remains the substrate, and the runtime is a projection over that substrate.

Runtime Flow

index.html
  -> DocumentStore(seedDoc, storageKey, seedDocumentId)
  -> SyncBus(store)
  -> DirectiveParser()
  -> DocumentSecurityPolicy()
  -> CapabilityRegistry(policy)
  -> NamespaceBridge(registry, parser, store, policy)
  -> RenderCanvas(renderCanvasEl, registry, bus, parser, scrollRoot, { appApi })

SyncBus event
  -> DocumentStore.applyMutation(event)
  -> parser.parse(text)
  -> bridge.syncDocument(text, index)
  -> canvas.update(text, index, bridge)

This orchestration currently lives in folio/index.html. The prototype does not yet have a separate application controller class; index.html is still the bootstrap and wiring layer.

How The Manuscript Maps To Code

Manuscript idea Current realization in Folio Primary classes
The document is the substrate Document text is the only persisted artifact. Widgets emit text mutations through the bus. DocumentStore, SyncBus, renderers
Owned state vs mirrored state Renderer manifests declare trust: 'owned' or trust: 'mirrored'. Mirrored renderers are gated by document trust and capability grants. CapabilityRegistry, DocumentSecurityPolicy
Python as document-scoped computation All ::py blocks execute top-to-bottom in one shared worker namespace rebuilt from current document text. NamespaceBridge, PyodideWorker, PyRenderer
Transclusion as the note primitive ::note resolves a source block, including cross-document references via source-doc=..., and writes back to the source on edit. TransclusionResolver, NoteRenderer
Derived tables from computation ::table source=py-block reads exported result/table_result, tracks divergence, and can re-sync to latest computed output. TableRenderer, NamespaceBridge
Lifecycle and carry-forward ::meta[status] affects activation policy; ::spawn creates next and roll-up documents and carries open tasks forward by reference. MetaRenderer, SpawnRenderer, DocumentStore
Graceful degradation Every directive can fall back to raw text; the shell starts from text and upgrades nearby directives into widgets. RenderCanvas

Core Data Structures

Document Text

The source artifact is always plain text. The parser recognizes single-line directives such as ::task[id]{...} and block directives such as ::py, ::table, ::email, ::note, and ::web.

Directive Descriptors

DirectiveParser turns text into an index of descriptors with type, id, params, lineStart, lineEnd, raw, and optional body. The rest of the system works from these descriptors rather than reparsing arbitrary DOM.

Sync Events

Widget actions, text editing, spawn operations, compaction, and transclusion writebacks all travel through SyncBus as explicit events. Folio currently supports append, replace, and delete mutations. DocumentStore normalizes these events against a concrete document id and records the resulting history entry.

Owned State In Folio

::task

Tasks are true owned state. The directive line is the task. Toggling a checkbox rewrites that directive line with updated status and optional completed metadata. Blocking relationships are resolved from the in-memory task cache built during rendering.

::note and transclusion

Notes now implement the transclusion architecture rather than acting as isolated inline note blocks. A note can point at another block in the current document or in another document via source-doc. When a transcluded note is edited, the writeback patch targets the source block, not the transcluding block.

::note[finance-contact]{source=contact:finance.team field=notes}
::end

::note[carry-call-finance]{source=task:call-finance source-doc=daily:2026-03-23 field=raw}
::end

::py

Python is document-scoped, not widget-scoped. NamespaceBridge rebuilds globals from document text, then asks PyodideWorker to execute all Python blocks in document order. Auto blocks evaluate during document sync; manual blocks are held until the user runs them. Exported Python variables are captured per block and exposed to dependent renderers such as ::table.

::table

Tables are stored in text as pipe-delimited rows. If linked to a ::py block, Folio treats the table body as a derived owned snapshot: it can be re-synced from computation, manually edited, detached from the source, and queried from Python as structured row objects.

Mirrored State In Folio

Mirrored directives render data from mock backends. The backend remains canonical. The document stores projection parameters and a local journal of actions. This is the prototype realization of the manuscript’s “durable orchestration layer above apps” claim.

The mock backends now also expose exportState(), importState(...), reset(...), and seeding/upsert helpers. This is the first implementation slice for a future LLM-backed simulation layer.

Simulation Slice

Folio now includes a first-pass simulation stack under folio/src/simulation/. SimulationProfileStore persists authored profile data, SimulationScenarioStore persists generated scenario state, richer ledger entries, and the last generated backend snapshot per profile, SimulationSettingsStore persists remote endpoint/model configuration, SimulationSecretsStore persists the remote API key separately, and SimulationCoordinator turns those inputs into backend state.

The concrete actions are Generate today and Generate document from the menu. Both now run through a single remote provider path: Remote OpenAI-compatible API. If no API key has been saved, generation stops with a configuration message instead of falling back to a local simulator.

profile + scenario
  -> SimulationPromptBuilder
  -> OpenAICompatibleSimulationLLMClient
  -> SimulationNormalizer
  -> SimulationCoordinator.applyNormalizedGeneration(...)
  -> mirrored backends
profile + scenario + example document
  -> SimulationDocumentPromptBuilder
  -> OpenAICompatibleSimulationLLMClient
  -> SimulationDocumentNormalizer
  -> SimulationCoordinator.generateDocument()
  -> compiled Folio text document

The prototype also surfaces provider status in the product: the settings UI shows whether a remote API key is present, which endpoint and model will be used, and the live remote provider status while generation runs.

SimulationPromptBuilder now covers the main mirrored-state surface types described in the design: buildDayPrompt(...), buildInboxPrompt(...), buildChatPrompt(...), buildCalendarPrompt(...), buildDayPlanPrompt(...), and buildAdvanceTimelinePrompt(...). SimulationDocumentPromptBuilder adds a second prompt family for owned-state document generation, using the seed document as a structural example while asking the model for a profile-specific document spec rather than raw Folio text.

SimulationDocumentNormalizer validates that spec, fills missing structure, and compiles it into a complete Folio document with contacts, transcluded notes, a templated Python block, a linked table, tasks, mirrored directives, and lifecycle metadata. This means the prototype now exercises both mirrored-state generation and full document generation against the same remote provider path.

The coordinator provides the backend orchestration boundary for future LLM generation by:

This keeps future LLM generation on the backend side of the architecture rather than inside renderer code.

Capability And Trust Model

Each renderer declares a manifest with a trust domain. Owned renderers are available by default. Mirrored renderers require two conditions:

  1. The current document must be marked trusted.
  2. The required read grant for that renderer or mirrored namespace must be present.

CapabilityRegistry enforces this policy both when a renderer tries to render and when NamespaceBridge tries to expose mirrored namespaces to Python. This is how Folio avoids ambient access to mail, calendar, chat, or web state.

// Example manifest shape
{
  type: 'email',
  trust: 'mirrored',
  grants: { render: 'email.read', query: 'email.read' }
}

Shell Architecture

The visible UI is the reading surface in RenderCanvas. The hidden editor exists, but the prototype currently presents the document through a text-first canvas instead of a split editor by default.

RenderCanvas builds a segment model from prose and directives, mounts fallback text first, and lazily activates nearby widgets. It also supports:

Lifecycle Layer

::meta[status] and ::spawn are Folio’s first pass at the document lifecycle described in the manuscript.

::spawn creates the next document and a roll-up document in DocumentStore, then rewrites the current document’s status. Open tasks are carried forward by cross-document ::note references rather than copied into disconnected duplicates.

Persistence And Inspection

DocumentStore now supports multiple documents, stable document ids, event history, and snapshots. That makes lifecycle, carry-forward, and transclusion operate on real document objects instead of only one text buffer called “current”. In the browser console you can inspect:

Known Limits