Architecture decision records¶
One record per decision that shapes the code (ADR 0001), in a trimmed MADR 4 format: 0000-template.md.
| ADR | Title | Status | Date |
|---|---|---|---|
| 0001 | Record architecture decisions | accepted | 2026-10-23 |
| 0002 | A modulith of a kernel, modules and lets | accepted | 2026-10-23 |
| 0003 | Heads are views on head-agnostic operations | accepted | 2026-10-23 |
| 0004 | Discovery through packages, entry points and pluggy | accepted | 2026-10-23 |
| 0005 | Dependency injection by type through ServiceLets | accepted | 2026-10-23 |
| 0006 | Plugins are installed through the uv tool receipt | accepted | 2026-10-23 |
| 0007 | Plugins are scaffolded with copier from this repository | accepted | 2026-10-23 |
| 0008 | Releases are derived from conventional commits | accepted | 2026-10-23 |
| 0009 | Unit, integration and e2e tests, as in the Aignostics Python SDK | accepted | 2026-10-23 |
| 0010 | Towards a reactive workflow engine | proposed | 2026-10-23 |
| 0011 | Agentic coding standards are enforced by the repository | accepted | 2026-10-23 |
| 0012 | Layered configuration with per-module settings | accepted | 2026-10-23 |
| 0013 | Pull-request-based development and releases | accepted | 2026-10-23 |
| 0014 | Agent skills ship with Heinzelmännchen and as a Claude Code plugin | accepted | 2026-10-23 |
| 0015 | Health checks are lets, aggregated by hz system doctor |
accepted | 2026-10-23 |
| 0016 | The project is called Heinzelmännchen; the command is hz |
accepted | 2026-10-23 |
| 0017 | First-party plugins live in the core repository as workspace packages | accepted | 2026-10-23 |
| 0018 | One administrative namespace: hz system; skills live in agent-skills/ |
accepted | 2026-10-23 |
| 0019 | MCP and REST heads derive everything from operations | accepted | 2026-10-23 |
| 0020 | Add a daemon head for background and reactive operation | proposed | 2026-10-23 |
| 0021 | Workflows are Markdown contracts with YAML frontmatter | proposed | 2026-10-23 |
| 0022 | Workflows embedded in documents are discovered by connectors and run only once registered | proposed | 2026-10-23 |
| 0023 | The inventory is compiled from declared, discovered and plugin-contributed entries and published as graphs | proposed | 2026-10-23 |
| 0024 | People and teams come from a directory of record, are referenced by role, and are minimised | proposed | 2026-10-23 |
| 0025 | Plugin distributions are named heinzel-<name> |
accepted | 2026-10-23 |
| 0026 | The plugin API is versioned with SemVer, and discovery checks each plugin's compatible core range | proposed | 2026-10-23 |
| 0027 | Nothing is sent home: no telemetry, crash reports or usage pings | accepted | 2026-10-23 |
| 0028 | Integrations are capability adapters; workflows name capabilities, never vendors | proposed | 2026-10-23 |
| 0029 | Agent runners are capability adapters; core ships Claude Code and a generic command adapter | proposed | 2026-10-23 |
| 0030 | Credentials live in the OS keychain behind a credentials service | accepted | 2026-10-24 |
| 0031 | The CLI checks for a newer release hourly, anonymously and in the background, and says so on stderr | accepted | 2026-10-24 |
| 0032 | Modules declare interactive setup steps; hz setup runs them all |
proposed | 2026-10-24 |
| 0033 | Read GitHub through its REST API with urllib; merged pull requests from the pulls list | superseded | 2026-10-24 |
| 0034 | Read Jira and Confluence Cloud through their REST APIs with urllib, Basic auth and epoch-millisecond JQL | superseded | 2026-10-24 |
| 0035 | Integrations go through the vendor's CLI as an ordinary employee | accepted | 2026-10-24 |
| 0036 | make install installs every tool the build needs, pinned and checksummed, on macOS and Linux |
proposed | 2026-10-24 |
| 0037 | Plugins bring playbooks: asset types with discovery hints, template contracts and recommended settings | proposed | 2026-10-24 |
| 0038 | Drafts are approved in place | proposed | 2026-10-24 |
| 0039 | A web head: a React app served by the API head | proposed | 2026-10-24 |
| 0040 | Layers and playbooks are plugins: a plugin may be a layer with a parent and a site, and layers stack general to specific | proposed | 2026-10-24 |
| 0041 | Expert mode: newcomers see the everyday commands, hz system expert on shows all |
proposed | 2026-10-24 |
| 0042 | Read Google Workspace through the Google Workspace CLI (gws) |
accepted | 2026-10-24 |
| 0043 | Desktop notifications: one policy in the core, shown once, by hz's own macOS app | proposed | 2026-10-24 |
| 0044 | Themes are data a plugin ships: module.theme(...) offers them, hz system theme use picks one |
proposed | 2026-10-24 |
| 0045 | A chat that knows where you are and acts through hz, with every change confirmed in code | proposed | 2026-10-24 |
| 0048 | A terminal in the web head | proposed | 2026-10-24 |
| 0046 | An installable web app on a fixed port, with paired devices and notifications from its service worker | proposed | 2026-10-24 |
| 0047 | Plugins are managed from the web app, and adding one shows what it installs before it is confirmed | proposed | 2026-10-24 |
| 0049 | Heinzelmännchen are durable agents: one session each, owned by hz | proposed | 2026-10-24 |
| 0050 | Pydantic AI runs a turn; a coding agent is a handoff | proposed | 2026-10-24 |
| 0051 | The workflow module becomes the heinzel module | accepted | 2026-10-24 |
| 0052 | The graph emerges from recorded reads and writes | proposed | 2026-10-24 |
| 0053 | The team graph is drawn with React Flow and laid out by elk; Mermaid is only an export | proposed | 2026-10-24 |
| 0054 | Observability is whether each team promise is kept: telemetry in, a graph out | proposed | 2026-10-24 |
| 0055 | Connectors show their sign-in, test live on demand, and bind themselves when they are alone | accepted | 2026-10-24 |
| 0056 | Modules contribute status items, header actions and Today widgets as data, viewed from their own operations | proposed | 2026-10-24 |
| 0057 | AI access is a module: one choice like the theme, options are adapters of ai-access |
proposed | 2026-10-24 |
| 0058 | Soundscapes are data a plugin ships, chosen like a theme: module.soundscape(...), hz system sound use |
proposed | 2026-10-24 |
| 0059 | The calendar and the mail write through hz, after a confirmation | proposed | 2026-10-24 |
| 0060 | Themes follow the time of day and the weather: variants on a closed vocabulary of signals | proposed | 2026-10-24 |
| 0062 | Heinzelmännchen find the MCP servers and skills you already gave Claude, read-only first | proposed | 2026-10-25 |
| 0061 | Plugins ship skills every AI path can use: module.skill(...), read-only tools, an explicit export |
proposed | 2026-10-24 |
| 0065 | Plugins may ship versioned React views alongside their Python declarations | proposed | 2026-10-25 |
| 0067 | hz owns sessions across Pydantic and native CLI turns | proposed | 2026-10-25 |
| 0068 | Human approval is a scoped proof carriable by every authorized head | proposed | 2026-10-25 |
| 0072 | Plugins declare navigation and Settings metadata as checked data | proposed | 2026-10-25 |
| 0082 | Plugin documentation is generated from the kernel and recorded by the tooling every plugin shares | proposed | 2026-10-24 |
Amendments: 0025 amends
0016 (plugin naming); 0013 amends
0008; 0020 and
0021 amend 0010;
0032 amends 0018 (hz setup);
0028 amends 0024 (the directory is a
capability); 0038 amends 0010 and
0020 (approval in place instead of an approval queue; hz inbox is a view);
0039 amends 0018
(hz ui) and 0019 (a token-protected web head may expose what the unauthenticated REST
head doesn't); 0041 amends
0018 (hz system expert; help lists the everyday commands) and
0039 (the navigation lists the same ones);
0043 amends 0020 (every tick ends by
popping up due notices) and 0039 (the notify operations are
web endpoints, not REST ones); 0045 amends
0018 (hz chat), 0029
(hz operations as agent tools through the MCP head) and 0039
(chat sessions instead of the stateless resend); 0048 amends
0039 (a terminal over a WebSocket; inline styles allowed);
0046 amends
0039 (a fixed port and paired devices) and
0043 (notifications in the web app);
0047 amends
0006 (add shows first and installs on --confirm, from PyPI
or https git only) and 0039 (plugin changes are web endpoints,
not REST ones; POST /api/restart);
0049 amends
0010 (a turn of a continuous session instead of a session per render),
0020 (the tick wakes Heinzelmännchen by key; team state on hz/state with leases),
0021 (one contract per Heinzelmännchen, in versions; records become turn bodies),
0029 (the runner no longer owns the session),
0038 (lessons; hz drafts and hz approve) and
0045 (the sidebar chat with a Heinzelmännchen is its
session), and in its durable-turns amendment 0028 (fingerprints per facet) and
0052 (downstream wakes only when the approved output
moved); 0050 amends
0029 (Pydantic AI in the core as the turn engine; runners are the
handoff) and 0045 (the chat on the same engine);
0051 amends 0021 (operation
names), 0038 (hz inbox becomes hz drafts and hz approve),
0041 (the everyday set) and
0045 (heinzel.* settings in the never-run policy);
0052 amends 0021 (observed
edges beside declared ones), 0023 (no entity schema or single-writer rule for now),
0038 (repeated nudges and the fallback, proposed) and
0049 (receipt-grade events are action
entries; the report tool); 0054 amends
0037 (the core's graph module ships the graph keeper's playbook) and
0052 (telemetry logs in the team repository before the
spine; hz report); 0055
amends 0028 (a sole installed adapter serves its capability
automatically);
0057 amends
0029 (an AI access option names the agent runner that serves it) and
0050 ([heinzel] model gives way to [ai] routing);
0058 amends
0027, 0039 and
0046 (fixed allowlisted player origins while a stream is in
effect; the player loads only after Play; amended by 0092);
0060 amends 0044
(variants that follow signals; a base theme is checked for contrast too);
0059 amends
0028 (a write mode and three reads for calendar and mail),
0038 (no place_draft for them: a mail draft is placed in the mailbox, a
calendar write is confirmed) and 0042 (writes and their scopes).
0061 amends
0014 (plugin skills reach Claude Code through hz system skill
export) and 0050 (skills are SkillLets; a turn gets
an index and loads bodies on demand).
ADRs 0021–0024 are
proposed together and disagree on a few points (data file format, the shared inventory module, canonicalization,
selector grammar); each lists them under More Information.
Supersessions: 0035 supersedes 0033 and 0034 (vendor CLIs instead of REST over urllib with tokens).
Rules¶
- Statuses:
proposed→acceptedorrejected; laterdeprecatedorsuperseded(withsuperseded-by). - Accepted records are immutable. Only their front matter changes (
status,superseded-by,amended-by); a changed decision is a new ADR that supersedes or amends the old one, with the links set on both. - Numbers are sequential and never reused; files are
NNNN-title-in-kebab-case.md. - This index lists every record with the title, status and date from its file;
tests/unit/documentation_test.pychecks the template, this table and the links between records. - New ADR: copy 0000-template.md or use the
write-adrskill.
2026-10-23 retrofit¶
ADRs 0001–0020 were converted to this template on 2026-10-23. The conversion only restructured them: decisions,
statuses and dates are unchanged. "Alternatives considered" became Considered Options, "Forces" became Decision
Drivers, status annotations became amends/amended-by front matter, and each record gained a Confirmation that
names the checks that exist in the repository. Where no alternatives were written down, the record says so instead
of inventing them. Two factual corrections came with it: ADR 0004 names the pluggy hook heinzel_lets (renamed from
joy_lets), and ADR 0017, already implemented with the clock plugin (plugins/heinzel-clock), was accepted.
| 0063 | World Clock is a local interactive globe in the right panel | proposed | 2026-10-25 | | 0064 | Themes can dress the core Heinzelmännchen with a palette and snow | proposed | 2026-10-25 | | 0071 | Text branding uses the name and original artwork | proposed | 2026-10-25 | | 0073 | Themes supply safe SVG layers for personal avatars | proposed | 2026-10-25 | | 0081 | State repositories: one writer per branch, append-only segments, the daemon pushes | proposed | 2026-10-25 | | 0080 | One invite line and a reviewed first win | proposed | 2026-10-25 | | 0084 | Private web sharing admits exact HTTPS origins and keeps device authentication | proposed | 2026-10-25 | | 0074 | Machine resource meters use bounded local sampling | proposed | 2026-10-25 | | 0083 | Restart and apply verifies the replacement server | proposed | 2026-10-25 | | 0079 | Core PyPI trusted publishing is isolated from builds | proposed | 2026-10-25 | | 0085 | Web updates verify the reloaded frontend | proposed | 2026-10-26 | | 0078 | Native desktop uses the shared lifecycle service and existing daemon | proposed | 2026-10-25 | | 0087 | Managed backend ownership is independent of the native window | proposed | 2026-10-27 | | 0088 | The collapsed sidebar keeps sound controls | proposed | 2026-10-27 | | 0089 | One selected workspace panel on every screen size | proposed | 2026-10-27 | | 0090 | Installed apps share their authenticated URL | proposed | 2026-10-28 | | 0091 | Confirmed plugin adds use server-owned operation receipts | proposed | 2026-10-28 | | 0092 | YouTube sign-in is an explicit player choice | proposed | 2026-10-28 | | 0093 | Touch users inspect updates before installing | proposed | 2026-10-28 | | 0094 | Plugins own their features and independent delivery | accepted | 2026-10-29 | | 0095 | The standard Heinzelmännchen theme owns the bundled soundscapes | accepted | 2026-10-29 | | 0096 | Release the plugin boundary at the first unused version | accepted | 2026-10-29 | | 0097 | Plugin authors use one small artifact-based toolchain | proposed | 2026-10-29 | | 0098 | Pages showcases the product and discovers public plugin metadata | proposed | 2026-10-30 | | 0099 | Review connected reads and local agent notifications separately | proposed | 2026-10-30 | | 0104 | Bind notification deduplication to observed source items | proposed | 2026-10-30 |