Base layer: the mesh as it is, under the mesh as it should be

HQ held only the to-be. Every reader had to already know the system the
decisions were about, and an as-is claim had nowhere to live except inside
an intention.

Adds 02-DESIGN/00-as-is — eleven documents written from the implementation
and the operational record, not from intent, including the parts nobody
would choose again. The two existing designs move under 01-to-be. Layers
are declared in frontmatter and never mix: a design that ships does not
move, its as-is counterpart is written, and both stand.

Back-fills adr/0001-0014 for decisions taken in implementation and never
recorded — the broker, the module abstraction, the mesh database, managed
files, provisioning, migrations, the workspace removal, failing loudly,
the constitution, application placement, linking, the employee model, the
artifact, the three silos. Each marked reconstructed, dated from the
history, and citing the evidence it was recovered from. The two existing
records renumber to 0015 and 0016 so the ledger runs oldest first;
0017 extends 0015 to modules outside the core, principle only — the
domain list is deliberately not invented here.

how-we-build.md becomes the source of the mesh constitution, with a sync
playbook, so the enforced copy stops being the only one that is true.

Process becomes explicit: five playbooks, eight thin skills that defer to
them, a repository map, and AGENTS.md with CLAUDE.md as its include.

The five Observations become 04-ISSUES 001-005 where they can be owned and
closed. 006 is new and uncomfortable: HQ is not indexed into the knowledge
base. That claim is what decision 27 rests on, it was never checked, and
the README now says so instead of repeating it.

Also corrects the ADR index into something generated, the "02-DESIGN is
empty" claim, the VISION.md pointer that did not survive the repo split,
and a note asserting the symlink rule was contradicted — it was a
misreading; the rule forbids hand-made links, the installer links by design.
This commit is contained in:
2026-08-23 03:08:26 +02:00
parent cf9357e8e9
commit 702efca6bb
74 changed files with 3676 additions and 138 deletions
+59
View File
@@ -0,0 +1,59 @@
# Process — overview
How work moves through hal-hq, and who may do what. Every other document in this folder is a
playbook: trigger, who runs it, steps, outputs. Engineers and agents follow the same
playbooks; agents must not act outside them.
## The audiences
| Audience | Contract |
|---|---|
| **Engineers** | Read and write everything. hal-hq is the single source of truth for mission, research, design, decisions and issue diagnosis. |
| **Agents** | The same rights as engineers, exercised through these playbooks. |
| **Anyone else** | This repository is public and written for them, but it is not a support channel. Nothing here identifies the mesh it describes. |
## The knowledge flow
```
idea ──► 01-RESEARCH ──► decision (adr/) ──► 02-DESIGN/01-to-be ──► built (code repo)
│ │ │
│ │ └─► 02-DESIGN/00-as-is once shipped
│ └────► abandoned (recorded, kept)
└─(small/obvious, decision recorded in DECISIONS.md)────► 02-DESIGN directly
symptom ──► 04-ISSUES ──► diagnosis ──► code-repo fix and/or design amendment
how-we-build.md ──► constitution sync ──► knowledge base ──► injected into design meetings
```
## The two design layers
`02-DESIGN` holds two layers that are never mixed:
| Layer | What it is | Changes when |
|---|---|---|
| `00-as-is/` | The mesh that exists today. Describes shipped behaviour, including behaviour nobody would choose again. | Something ships, or an as-is claim is found to be wrong. |
| `01-to-be/` | The mesh being built toward. Every statement traceable to a record in `adr/`. | A decision is taken or amended. |
A to-be document that ships does not move. Its as-is counterpart is written or updated, the
to-be document's frontmatter goes to `implemented`, and both stand — one describing what runs,
the other recording what was intended. Deleting the intention loses the reasoning, which is
the expensive half.
## The playbooks
| # | Playbook | Trigger |
|---|---|---|
| [01](01-research.md) | Research | An idea worth investigating before committing to design |
| [02](02-graduation.md) | Graduation & design change | Research concludes, or a design must change |
| [03](03-issues.md) | Issues | Something is wrong — often with the owner unknown |
| [04](04-build-handoff.md) | Build handoff | A design is ready to be built |
| [05](05-constitution-sync.md) | Constitution sync | `how-we-build.md` changed a rule the mesh enforces |
## Status lives in frontmatter
Research overviews, design docs, issue reports and decision records each carry their status as
YAML frontmatter (schemas in the section READMEs and playbooks). There are **no central status
files**. `DECISIONS.md` is a ledger of decisions as they were taken — an index and a home for
decisions too small to warrant a record — and is explicitly *not* a status board. Cross-cutting
views are generated on demand by the `hal-status` skill and never written to disk.
+48
View File
@@ -0,0 +1,48 @@
# Playbook 01 — Research
**Trigger.** An idea, technology or approach worth investigating before it is committed to
design. Also: an as-is document that raises a question nobody can answer.
**Who runs it.** Anyone.
## Steps
1. Take the next free number: highest `01-RESEARCH/NNN-*` plus one, zero-padded to three
digits. Never skip or reuse a number.
2. Create `01-RESEARCH/NNN-descriptive-name/` and a `status.md` in it carrying:
```yaml
---
status: active
initiated: YYYY-MM-DD
touches: [] # areas, subsystems or as-is design docs the effort bears on
---
```
Then a short prose summary: **what** is being investigated, **why**, and **what it
touches**.
3. Do the research in further documents in the same folder — notes, option analyses, evidence,
draft designs. Anything goes. Keep the summary in `status.md` current as the effort changes
shape.
## What makes research worth reading
State evidence, not assertion. *"Zero of 124 modules declare `brain` as a dependency"*
outranks *"the dependency rule is not followed"*. An effort that measured nothing has not
finished.
Research describes real observations but never identifies the mesh it observed. The shape of a
finding survives anonymisation intact — *a node publicly named but behind a household NAT*
carries the whole lesson without naming anything.
## Do not
- Do not put status in prose. It lives in `status.md`'s frontmatter, and the prose must not restate it.
- Do not set `became:` while the effort is open — playbook 02 sets it at closure.
- Do not write into `02-DESIGN` from an open effort.
## Closing
An effort never just stops. It closes through playbook [02](02-graduation.md) as `graduated`
or `abandoned`, always with `became:` pointing at what it turned into. Nothing is deleted —
what was rejected, and why, is the more expensive half to rediscover.
+60
View File
@@ -0,0 +1,60 @@
# Playbook 02 — Graduation and design change
**Trigger.** A research effort concludes, or an existing design must change.
**Who runs it.** Anyone, with the decision recorded before the design moves.
## Graduating research
1. **Check it against GENESIS.** An effort graduates only if its conclusion is traceable to
[`mission.md`](../mission.md), [`context.md`](../context.md) and
[`effect.md`](../effect.md). If it conflicts, either the effort is wrong or GENESIS is —
say which, in writing, before proceeding.
2. **Record the decision.** Write a record in [`adr/`](../../adr/) taking the next free
number. Format and rules are in [`adr/README.md`](../../adr/README.md). State evidence,
not assertion, and record the options that were rejected — that is the half worth keeping.
3. **Write the design.** Create the document under `02-DESIGN/01-to-be/` with frontmatter:
```yaml
---
layer: to-be
status: designed
code: [] # owning code repo(s); set at build handoff, empty before
updated: YYYY-MM-DD
decisions: [adr/NNNN-....md]
---
```
4. **Close the effort.** Set the effort's `status.md` frontmatter to `status: graduated` and
`became:` pointing at the design document and the decision record.
5. **Add a ledger line.** Append the decision to [`DECISIONS.md`](../../DECISIONS.md) under
today's heading, pointing at the record.
## Amending an existing design
A design changes only through a decision.
1. Write the decision record. If it reverses an earlier one, the earlier record's `status:`
becomes `superseded-by: adr/NNNN-....md` — **its text is never edited**.
2. Edit the to-be design document and set `updated:` to today.
3. If the amendment came from an issue, set that issue's `amended-design:` to the document
path.
4. Add the ledger line.
## When something ships
Implementation state is a third axis, independent of both design and decision.
1. Write or update the matching document under `02-DESIGN/00-as-is/` so it describes what now
runs — including anything that shipped differently from the intent. A design that shipped
bent is an as-is fact, not a design amendment.
2. Set the to-be document's `status: implemented` and its `code:` to the owning repositories
from [`repos.md`](../repos.md).
3. `status: implemented` must be defensible from the owning repository's main branch, not from
intent. If it cannot be checked, it is `in-progress`.
## Do not
- Do not move a to-be document into `00-as-is/`. Write the as-is document; both stand.
- Do not edit an as-is document to describe an intention. That is what the to-be layer is for.
- Do not change a decision record's meaning. Supersede it.
+47
View File
@@ -0,0 +1,47 @@
# Playbook 03 — Issues
**Trigger.** Something is wrong at the level of the mesh's design or governance — a rule that
turns out to be unenforced, a stated behaviour that does not happen, a silent failure the
design permits.
**Who runs it.** Anyone may open an issue. No localisation is required to report one.
## What belongs here, and what does not
| Belongs in `04-ISSUES` | Belongs in the knowledge base |
|---|---|
| The design permits a failure to be silent | How to fix one occurrence of it |
| A documented rule is enforced by nothing | A command that works around it |
| A stated invariant is false in practice | A node-specific quirk |
| The owning component is unknown and finding it needs the whole mesh in view | Symptom → fix, once the answer is known |
The knowledge base already holds the operational record and is indexed on symptoms. This
folder is not a second copy of it. An issue here is a question HQ must **answer**, not an
incident someone must **clear**.
## Steps
1. Take the next free number. Create `04-ISSUES/NNN-short-name/00-report.md`:
```yaml
---
status: open
opened: YYYY-MM-DD
located-in: [] # owning repo(s)/module(s), filled by diagnosis
fixed-by: # PR or commit reference, filled at resolution
amended-design: # design doc path, when the root cause was a design gap
---
```
Then the symptom **as observed**, in plain terms, with the evidence that it happened.
2. Investigate in `01-diagnosis.md` in the same folder — the trail, dated, including what was
ruled out. Move `status:` to `diagnosing`, then `located` once the owner is known.
3. Resolve. Set `status: resolved`, fill `fixed-by:`, and if the root cause was a design gap,
run playbook [02](02-graduation.md) and fill `amended-design:`.
## Rules
- Closed issues are never deleted — they are the mesh's symptom-to-component memory.
- An issue whose answer is a general lesson should also be written to the knowledge base, so
the next person searching a symptom finds it. Both, not either.
- `status: wontfix` is legitimate and requires a sentence saying why.
+30
View File
@@ -0,0 +1,30 @@
# Playbook 04 — Build handoff
**Trigger.** A to-be design is settled and work is about to start in a code repository.
**Who runs it.** Whoever starts the build.
## Steps
1. **Confirm the design is settled.** Its frontmatter reads `status: designed`, and every
claim in it traces to a record in [`adr/`](../../adr/). An open question in the text is a
reason to run playbook [01](01-research.md), not to start building around it.
2. **Name the owner.** Set `code:` in the design's frontmatter to the repositories from
[`repos.md`](../repos.md). If the repository does not exist yet, add it to `repos.md` in
the same change.
3. **Check the as-is.** Read the matching `02-DESIGN/00-as-is/` document. What is being
replaced is stated there; if it is not, write it before changing it. Building against an
undocumented as-is is how a shipped behaviour gets lost.
4. **Flip the status.** `status: in-progress`, `updated:` today.
5. **Build in the code repository.** hal-hq is not a code repository and never carries
implementation.
6. **On completion**, run the "when something ships" section of playbook
[02](02-graduation.md).
## Rules
- Every merge is a human checkpoint, without exception.
- Never open a pull request unprompted. A permissions list saying it is allowed is not a
request.
- Work in an isolated worktree, never a shared checkout. A failed `cd` in a shared checkout
commits to the wrong branch, and the error scrolls past.
@@ -0,0 +1,37 @@
# Playbook 05 — Constitution sync
**Trigger.** [`how-we-build.md`](../how-we-build.md) changed a rule that the mesh enforces at
runtime.
**Who runs it.** Whoever made the change.
## Why this playbook exists
The mesh injects a constitution into every eligible design meeting; agents check their output
against it and a constitution-check phase can block a meeting. That text is **derived**.
`how-we-build.md` is the source.
Two texts stating the same rules will drift, and the enforced copy winning by default means
the reasoned copy quietly stops being true. This playbook is the mechanism that stops that —
and, per the repository's own rule, it is how the rule "HQ is the source" is checked.
## Steps
1. Edit [`how-we-build.md`](../how-we-build.md). Each rule keeps the reasoning that earned it;
the derived page carries the rule alone.
2. Record the change as a decision — a rule the mesh enforces is architecturally significant.
Playbook [02](02-graduation.md).
3. Publish the derived page to the knowledge base under the constitution slug, replacing its
body. Keep the section numbering stable: the meeting orchestrator and the review fragments
cite sections by number.
4. Verify the derived page reads back with the change present. A publish that reported success
and did nothing is exactly the failure class this repository exists to name.
5. Note the sync in the ledger line for the decision.
## Rules
- **Never edit the derived page directly.** An edit there survives until the next sync and
then vanishes, taking its reasoning with it.
- The derived page may only be **tightened** by per-team override pages, never relaxed.
- If the sync cannot be performed, say so in the ledger line. An unsynced rule is a rule the
mesh does not enforce, whatever `how-we-build.md` says.