nodwyn.

Architecture decision records

One decision per file. Amend by editing and noting the change; never delete.

ADRs 2, 8, 28 and 34 cite sections of the original build plan (§3.3, the bootstrap safety envelope; §3.4, the control plane's reference; §4, B3, the bootstrap's dev tools), which plan.md no longer has: read it with git show 2f4394f^:plan.md.

  • 0042 — Releases distribute binaries and books (amended: from Gitea to GitHub)
  • 0044 — Wails owns the native window while console RPC keeps its origin and authentication

  • 0001 — Value representation

  • 0002 — Log format and event kinds
  • 0003 — Model tool calls are Scheme applications
  • 0004 — Primitive metadata
  • 0005 — Keychain crypto (amended: a keychain may have no passphrase; credentials managed in the console)
  • 0006 — Unbound egress defaults to deny
  • 0007 — Scheme scope: written from scratch, documented first
  • 0008 — LLM client is a Provider interface, Ollama first
  • 0009 — Context and cache discipline
  • 0010 — Core/front-end boundary
  • 0011 — Terminal stack
  • 0012 — Two binaries, always
  • 0013 — Promotion
  • 0014 — .nodwyn/init.scm convention
  • 0015 — Friction log
  • 0016 — Fallback is allowed and honest
  • 0017 — Standing command approvals
  • 0018 — Turn budgets and long-running turns (implemented, unattended runs and judged approval included; amended by 0035)
  • 0019 — Jev sees content, never secrets (amends SPEC; amended: what the judge is told about a call; what needs a plan, a chat's earlier messages, and looking)
  • 0020 — Jev as egress primitives; register-check (amends plan P5; implemented, amended for the judge tools and judged approval)
  • 0021 — A real UI after v0: daemon, protocol, clients (implemented)
  • 0022 — Cowork: workspaces, attachments, MCP servers (implemented; amended: a chat-completions model takes images unless it says not)
  • 0023 — Untrusted MCP servers: isolation, pinning, fail-closed (implemented: remote servers, and contained ones in podman or docker)
  • 0024 — OAuth2 credentials: acquisition, refresh, scopes (implemented, from the console too; W5 builds on it)
  • 0025 — Log-derived ingress redaction and buffered model output
  • 0026 — The agent loop is a Scheme procedure
  • 0027 — Configured models and narrowed contexts (amended: the helpers ticked last are the next task's)
  • 0028 — A scratch directory beside the repository (amended: in the data directory, excepted from the denylist; then in the system's temporary directory, outside the protected ones)
  • 0029 — Optional tool parameters
  • 0030 — One app, three ways to reach it: desktop, browser, phone (amended: a computer nobody sits at, where devices pair by invitation and the person signs in with a passkey; another nodwyn links as a device, ADR 54; this computer's sign-in makes no passkey and is no cookie)
  • 0031 — The project is renamed nodwyn
  • 0032 — The default loop works the way pil did (amended 2026-10-17: a lean profile for sessions nobody approves, and a full one; 2026-10-18: the lean prompt carries AGENTS.md, this repository's completeness rules are in its own init.scm, and sandbox mode's lean prompt and no-change reminder)
  • 0033 — Go 1.26 is the base
  • 0034 — Sessions in git worktrees (partly implemented: a session in a worktree from the console)
  • 0035 — A chat is the way to work, and it asks less (amends 17, 18, 30)
  • 0036 — A repository's AGENTS.md joins the system prompt (amended: the lean prompt carries it too)
  • 0037 — Work on nodwyn is validated before it is called done
  • 0038 — fs-edit takes several edits to one file in one call
  • 0039 — Tasks are named, archived and deleted, and listed by folder, named by the model in its first reply (amends 2; amended 2026-10-23)
  • 0040 — A conversation's model is a choice
  • 0041 — Providers, models and efforts are chosen in the console (amends 8, 40; amended: a model's settings are its own; its list is asked with its key and its reply cap comes out of its context; what providers publish fills what an entry leaves unset; the judge's model settings sit with the models'; Anthropic and Baseten are providers to choose; a relay's report that its provider failed is retried; a new task starts on the choices made last, kept by the daemon)
  • 0043 — fs-edit works on the text the model reads, so a line with a credential on it can be edited (amends 25, 38)

  • 0045 — User-owned project trust, executable identity, credential transport settings, keychain bounds and persistence, and canonical project paths

  • 0046 — The judge is a provider's: Jev or OpenAI's Decisions API, chosen in Settings, with [jev] become [judge] and one set of judge primitives, judge-yes-no, judge-score and judge-choice (amends 19, 20, 41)
  • 0047 — A task's judge is a choice beside its model, a ChatGPT plan's sign-in is no judge, its model is not typed, and Settings is tabs with one for the judge (amends 30, 41, 46; amended: Settings is five tabs, saves one way, and has one place for each thing)
  • 0048 — A terminal for the model, experimental and unguarded: term-open and five more primitives, on a pseudo-terminal and an emulator, behind [experimental] terminal; temporary, to measure what it is worth before making it safe
  • 0049 — Scheduled tasks, one task each, whose runs start from a handover, with a log index read from the end; a task's limits are its own, none unless set (amended 2026-10-27) (amends 18, 34, 9; implemented: turn limits, worktree bases, log index, console history, scheduler and console management, and since 2026-10-17 rules for its timing said in the daemon's words, with recent runs; login startup built as ADR 53's slice 0; amended: Home kept Limits as it was left, until a task's limits became its own)
  • 0050 — Retrieval (accepted; the conversation, the repository and earlier tasks implemented): index-search over a project index of the repository kept in nodwyn's data directory and shared by worktrees, the conversation and, when the person allows it per project, earlier tasks; index-update and recall; embeddings when a model is chosen for them (amends SPEC's Memory, 2, 22, 32)
  • 0051 — Task memory: a card per turn and the notes compaction writes, kept with the words of the log's events beside each log as <id>.mem; index-search shows what it finds under its turns, and recall of a turn's message shows its card; vectors from a small shipped model, model-written summaries and the console later (amends 9 and 50; partly implemented: cards, notes and their words); console keyword search and focused turn history implemented
  • 0052 — The console installs on a phone as a web app: a manifest, icons and a service worker that caches nothing, and notices shown through it (amends 30; Web Push not built; several hosts in one app is ADR 54)
  • 0053 — Workflows: a trigger (a timetable, an event polled through the guard, Run now), filters, an instruction with the event attached as data, runs going to one task or one per subject, and an outbox for outward actions (amends 49, 30; implemented: the timetable, as ADR 49's amendment of 2026-10-17, slice 0: a login item, the daemon's desktop notices, locked keys said on Home, slice 2: the Workflows page and a daily spend limit, slice 3: workflows that watch pull requests or a command, slice 4: the outbox, slice 5: email through Gmail, and slice 6: the TUI and the command line; the rest not built)
  • 0054 — Several hosts in one window: this computer links to another nodwyn as a device of its console, with an invitation made there, keeps the token in its keychain bound to that host, and relays a console's socket to it through its daemon; the sidebar by host, Needs you across hosts, Runs on, Hosts and Add a host (amends 30, 52; implemented; amended: a link that is the person's changes the host's limits, models and default model, not what its tasks may do unasked or its providers, unless the host is started with --no-link-settings, and never holds a touch; and, from 2026-10-27, the sidebar starts every host folded, this browser remembering the hosts opened; a phone's home host, the TUI and line mode not built)
  • 0055 — Sandbox mode: nodwyn run --sandbox container declares the machine a disposable sandbox, as a benchmark's task container is; its tools reach any path but nodwyn's own directories and credential files, what its commands start in the background keeps running, it needs no git repository, and it is unattended and auto-approved; a turn that ends on the model's word is asked once to check its result, and the same call four times in a row warns rather than stops (amends 17, 18, 28, 32)
  • 0056 — An explicit managed static-app service, with a host capability ceiling, weaker child devices, durable edits and daily local-inference accounting; ordinary Nodwyn remains unchanged
  • 0057 — A batch of read-only calls (fs-read, fs-list, fs-find, index-grep, outline, the git tools) runs concurrently, its budget reserved and its results recorded in the order of the calls; any other batch runs in order (amends 18 and 38)
  • 0058 — Apache 2.0, and a public repository on GitHub
  • 0059 — A website on GitHub Pages, built from the docs: a guide for the console, standalone and server use, and the repository's docs as the reference