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
+29 -11
View File
@@ -3,26 +3,44 @@
The **northern star**. What HAL is, the environment it runs in, and what changes when it
works. Every research effort and design decision is checked against this folder.
| File | Purpose |
| File / folder | Purpose |
|------|---------|
| [`mission.md`](mission.md) | Vision, mission, and the values that decide arguments |
| [`context.md`](context.md) | The environment — conditions, not aspirations |
| [`effect.md`](effect.md) | What is different when the work is done |
| [`how-we-build.md`](how-we-build.md) | Rules that hold across the mesh, each one earned |
| [`how-we-build.md`](how-we-build.md) | The rules that hold across the mesh, each one earned. **The source of the mesh constitution** — the governed page the mesh injects into design sessions is derived from it. |
| [`repos.md`](repos.md) | Where implementation lives, and what each repository owns |
| [`process/`](process/) | The playbooks — how work moves through this repository, for engineers and agents alike |
## Rules
- Markdown only.
- **Stable by nature.** Changes here reflect a genuine shift in intent, not iteration.
- **Stable by nature.** Changes here reflect a genuine shift in intent, not iteration. The one
exception is `how-we-build.md`, which changes whenever a rule is earned — and only through
its amendment process.
- Research and design must be traceable back to what is written here.
- **Instance-agnostic.** These documents describe the mesh as a concept. No machine names, no
counts, no topology.
## Note on `VISION.md`
## On the architecture overview in the code repository
The repository root carries `VISION.md`, an architecture overview predating this folder.
It is a useful description of *how* the mesh works and should be folded into
[`02-DESIGN`](../02-DESIGN/), not here — GENESIS answers *why*.
The code repository carries an architecture overview predating this folder. It is a useful
description of *how* the mesh works, and its content now lives — anonymised and checked against
the implementation — in [`02-DESIGN/00-as-is/`](../02-DESIGN/00-as-is/). GENESIS answers *why*;
that document answered *how*, which is the design layer's job.
It has also drifted: it lists "Symlinks, not copies" as a key design principle, while the
operating rules forbid creating symlinks at all after one caused production data loss.
A founding document contradicting a hard rule is precisely the failure this folder exists
to prevent.
It had also drifted from the implementation in ways worth recording, since both were found by
comparing it against the code rather than by anyone noticing:
- It described the pipeline as having a separate builder process and a build stage that
packages. Neither was true after 2026-08-04; the documents stayed stale until 2026-08-06
([ADR 0014](../adr/0014-build-publish-and-deploy-are-three-silos.md)).
- It listed the mesh as spanning a fixed number of named machines, which is exactly the
content this repository cannot carry.
One earlier note in this file has been withdrawn as **wrong**, and is recorded here rather than
deleted. It claimed the overview's "symlinks, not copies" principle contradicted the mesh's
hard rule against symlinks. It does not. The rule forbids *creating* a symlink by hand; the
installer creates and reconciles every link the mesh needs, deliberately
([ADR 0011](../adr/0011-the-installer-owns-linking.md)). The rule is about who may link, not
about whether the mesh links — a misreading common enough that the ADR now says so explicitly.
+5
View File
@@ -1,3 +1,8 @@
---
status: canonical
updated: 2026-08-22
---
# Engineering Context
The conditions the mesh is built for. Properties, not an inventory — no node here is
+5
View File
@@ -1,3 +1,8 @@
---
status: canonical
updated: 2026-08-22
---
# Effect
Imagine the mesh works as intended. What is different?
+170 -26
View File
@@ -1,42 +1,186 @@
---
status: canonical
updated: 2026-08-23
derives: knowledge-base constitution page
decisions:
- adr/0009-the-mesh-is-governed-by-a-constitution.md
---
# How we build
Working notes on the rules that hold across the mesh. Short, and each one earned.
The rules that hold across the mesh. Short, and each one earned.
## Name a context after its aggregate, not after a metaphor
**This document is the source of the mesh constitution.** The governed page the mesh injects
into design sessions is *derived* from it, section for section, and carries the rules without
the reasoning. Never edit that page directly — an edit there survives until the next sync and
then vanishes, taking its reasoning with it. The sync is playbook
[`process/05-constitution-sync.md`](process/05-constitution-sync.md), and it is how the claim
"HQ is the source" is checked.
`hal/agents` owns **Agent**. A *brain* — memory, thoughts, cognition — is something an
agent **has**, a concept inside the aggregate. It is not a module.
Section numbers are stable. The orchestrator and the review fragments cite them.
The cost of getting this wrong is visible today: `hal/brain` names the node runtime, so
the most evocative word in the system points at infrastructure, and `hal/cortex`
describes itself as "mesh messaging" in its manifest while the anatomy documentation
calls it the interactive runtime — and it runs on no node at all.
---
## 1. Purpose
These are the principles and guardrails every piece of work in the mesh is checked against —
design sessions, analysis gates, reviews, and agents acting on their own. A rule stated here is
non-negotiable unless amended per §6.
They exist because each was violated first. Where a rule reads as arbitrary, that is a sign the
incident behind it is not written down, and the fix is to write it down, not to relax the rule.
---
## 2. Non-negotiables
| Rule | What it means |
|---|---|
| **Never write to a production database directly** | No insert, update, delete or schema statement executed against production by hand. Schema changes go through numbered migrations; data changes go through application code or the module's own capabilities. Raw statements skip every side effect the proper path has — events, audit, cache invalidation, fan-out. |
| **Every schema change is a migration** | Numbered, in the module's own language, compiled with it. Both a baseline for a fresh installation *and* an incremental migration for installations that already exist. If code references a column, the migration creating it must exist. [ADR 0006](../adr/0006-schema-changes-are-numbered-migrations.md) |
| **Never bypass the pipeline** | No manual database edit, no manual restart as a workaround. Fix the cause and deploy. A workaround that works is a workaround that is never removed, and the next person cannot tell the node from its declaration. |
| **Never create a symlink** | The installer owns all linking and reconciles it. A hand-made link caused production data loss through container volume resolution — and the judgement needed to make a safe exception is exactly the judgement unavailable at the moment it matters. [ADR 0011](../adr/0011-the-installer-owns-linking.md) |
| **Never push directly to the main branch** | Branch, push, review, merge. Every merge is a human checkpoint, without exception. |
| **One change per pull request, and never merge your own** | Unrelated improvements bundled together cannot be reviewed or reverted separately. Self-merging removes the checkpoint that is the entire point. |
| **Never open a pull request unprompted** | A permissions list saying it is allowed is not a request. |
| **A failed step fails the job** | A sequence that continues past a failure does the next thing in the wrong place. Gate each step on the last. [ADR 0008](../adr/0008-a-failed-step-fails-the-job.md), and §5. |
### A failed step must stop the steps after it — how it was earned
A worktree creation failed because the branch name collided with an existing namespace. The
change into that worktree failed too. The copy, the staging and the commit that followed all
ran in the shared checkout and committed to a local main. The error was printed and scrolled
past.
This is the same shape as the faults the mesh's whole refactor exists to remove: a step
reported failure, nothing stopped, and the damage happened somewhere nobody was looking.
---
## 3. Module and infrastructure rules
### Manifests
- **Never bump a version by hand.** The builder owns versioning. A version change in a diff is
a defect; revert it.
- **Features are detected, not declared.** The installer discovers what a module carries from
what its directory contains. A declared list and the directory it describes drift, and the
directory is the one that is true.
- **Every runtime variable is declared.** A variable the module reads and the manifest does not
declare is invisible to the mesh: it will not be generated, injected, or audited.
- **Provisioned credentials arrive through declared requirements**, never hardcoded in code,
compose files or scripts. [ADR 0005](../adr/0005-capabilities-are-provisioned-on-declaration.md)
### Placement
- **Core modules belong to the monorepo** — the runtime, delivery, provisioning, configuration,
knowledge, and the shared infrastructure the mesh provisions against.
- **Every standalone application gets its own repository**, with a manifest at its root,
registered as a build source. Creating an application directory in the monorepo is a
convention violation and reviewers reject it.
[ADR 0010](../adr/0010-applications-live-in-their-own-repository.md)
### Migrations
- Numbered, idempotent, and safe to re-run. Guard every statement.
- The initial migration is **frozen** once it has run anywhere. Change is a new number.
- Numbers are unique. A duplicate prefix is a defect, not a style question.
### Managed files
**A file edited on a node is a bug with a delay on it.** Everything under the mesh's managed
surface is regenerated from the mesh database; a local edit survives one synchronisation and is
then silently overwritten, bringing back whatever it fixed. Use the mesh operation that owns
the value. If unsure whether a file is managed, ask the tooling — the answer is not visible
from the file. [ADR 0004](../adr/0004-managed-files-are-generated-never-edited.md)
---
## 4. Naming and boundaries
### Name a context after its aggregate, not after a metaphor
A context named `agents` owns **Agent**. A *brain* — memory, thoughts, cognition — is something
an agent **has**: a concept inside the aggregate, not a module.
The cost of getting this wrong is visible today. An anatomy name points at the node runtime, so
the most evocative word in the system names infrastructure; another describes itself as "mesh
messaging" in its manifest while the anatomy documentation calls it the interactive runtime —
and it runs on no node at all.
Anatomy makes attractive names and poor boundaries. Name the thing the domain calls it.
## Ubiquitous language is checked, not assumed
### Group by domain, not by single function
If a document states a rule about the mesh, say how the rule is verified. This repository
has a documented requirement that every module exposing tools declares `brain` as a
dependency. Zero modules do. An unenforced rule is indistinguishable from a wrong one,
and costs more, because people believe it.
A module is a purpose, not a piece of software. Four modules that together constitute "how a
node is reachable" and cannot be assigned, versioned or replaced as one thing are four
accidents, not four boundaries.
[ADR 0017](../adr/0017-modules-outside-the-core-are-grouped-by-domain.md)
## Contexts integrate through the record, never through a shared schema
### Contexts integrate through the record, never through a shared schema
Publish to the stream; do not join across a boundary. Today five domains share one
45-table schema, which is why work that belongs to one context keeps having to be
Publish to the stream; do not join across a boundary. Today several domains share one
forty-five-table schema, which is why work belonging to one context keeps having to be
implemented in another.
## A failed step must stop the steps after it
---
Scripted work runs as a sequence, and a sequence that continues past a failure does the
next thing in the wrong place. Gate each step on the last: `cd X || exit`, not `cd X`
followed by a newline.
## 5. Evidence and verification
Earned the obvious way. A `git worktree add` failed because the branch name collided with
an existing namespace; the `cd` into that worktree failed too; and the `cp`, `git add` and
`git commit` that followed ran in the shared checkout and committed to local `main`. The
error was printed and scrolled past.
### Ubiquitous language is checked, not assumed
This is the same shape as the faults this refactor exists to remove — a step reported
failure, nothing stopped, and the damage happened somewhere nobody was looking.
**If a document states a rule about the mesh, it says how the rule is verified.** This
repository has a documented requirement that every capability-exposing module declare the core
runtime as a dependency. Zero modules do.
An unenforced rule is indistinguishable from a wrong one, and costs more, because people
believe it.
### Behavioural criteria require runtime evidence
A criterion of the form *"the script runs"*, *"the endpoint answers"*, or *"the migration
applied"* is satisfied only when the change has actually been exercised: a real run, a real
request, a pipeline log, a live query showing the expected result.
**Marking a runtime criterion verified from a diff is itself a violation.** A reviewer who
finds one names the evidence required and returns the work.
The reason is the mesh's most consistent failure shape: a green result proves transport, not
effect. Absence reads as success unless something looked.
### Search the record before forming a hypothesis
The first action on any error message, failing service or unexpected behaviour is to search the
operational memory for the literal error text — before a hypothesis, not after one fails. The
knowledge base is indexed on symptoms.
This fires hardest on *familiar* ground, where a confident trail feels like progress. Two
entries were each rediscovered from scratch over several hours in a single session because the
search was skipped. Both were already written down.
---
## 6. Amendment
This document is governed. It does not change by commit message or unilateral decision.
1. **Propose** — a change stating what rule is changing, why the current wording is
inadequate, and what reviewed it.
2. **Review** — sign-off by reviewers who are not the proposer.
3. **Record** — the change is a decision and gets a record in [`adr/`](../adr/), because a
rule the mesh enforces is architecturally significant.
4. **Sync** — playbook [`process/05-constitution-sync.md`](process/05-constitution-sync.md)
publishes the derived page. An unsynced rule is a rule the mesh does not enforce, whatever
this document says.
No drive-by edits. Every change traces to a recorded decision.
---
## 7. Overrides
A team or product may define additional constraints that **narrow or tighten** these rules.
They may never relax them.
An override says which rule it tightens, or which gap it fills, and follows the same amendment
process. Absence of an override means these rules apply unmodified.
+5
View File
@@ -1,3 +1,8 @@
---
status: canonical
updated: 2026-08-22
---
# Mission
## Vision
+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.
+51
View File
@@ -0,0 +1,51 @@
---
status: canonical
updated: 2026-08-23
---
# The HAL repositories
The map of where implementation lives. Humans use it for orientation; agents use it for issue
triage (playbook [`process/03-issues.md`](process/03-issues.md)). The `code:` frontmatter
field in design documents points at entries here.
Repository *names* are recorded; hosts, URLs and owners are not — this repository is public,
and a forge address is an operational detail (see [`README`](../README.md)).
| Repository | Owns |
|---|---|
| `hal` | The monorepo — the node runtime, the module catalogue, the delivery machinery, and the bootstrap scripts. Every core module lives here. |
| `hal-hq` | This repository — mission, research, design, decisions, issue diagnosis. The source of truth for *why*. Carries no implementation. |
| *(one per application)* | Every standalone application, site or side-project gets its own repository, with `module.yml` at the root. Registered with the mesh as a build source; built and deployed by the same pipeline as anything in the monorepo. |
## What lives where inside the monorepo
Named by role, because the layout is itself part of the as-is design — see
[`02-DESIGN/00-as-is/`](../02-DESIGN/00-as-is/).
| Area | Holds |
|---|---|
| Module catalogue | One directory per module, each with a manifest. Core modules sit under the mesh's own namespace; everything else at the top level. |
| Node runtime | The daemon and interactive runtime that every node runs. |
| Bootstrap scripts | First-node initialisation, joining an existing mesh, and node rescue. |
| Shared library | The SDK every module builds against. |
| Pipeline test harness | End-to-end coverage of the delivery pipeline. Currently unbuildable — see [`04-ISSUES/005`](../04-ISSUES/005-pipeline-test-harness-unbuildable/00-report.md). |
## Why applications do not live in the monorepo
A standalone application in the monorepo is a convention violation, and reviewers reject it.
The reasoning is recorded in [`adr/0010`](../adr/0010-applications-live-in-their-own-repository.md):
the mesh installs, provisions for, and ships an application through exactly the same machinery
whether or not its source sits beside the mesh's own — so co-location buys nothing and costs
the monorepo's review cadence.
## There is no npm workspace
Each module is a standalone package that consumes its dependencies from the private registry,
not from a sibling directory. The workspace was removed after it caused build-versus-development
divergence — a workspace member importing another resolved to local unbuilt source in the
pipeline and to a published version in development. Recorded in
[`adr/0007`](../adr/0007-no-npm-workspace.md).
Consequence, and it is a real one: a cross-package change is two steps — publish, then consume
— and a repository-wide `npm install` does not exist.