From 304bb2eb4016d02da1c5a56aa2526735e15fb02a Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 04:52:54 +0000 Subject: [PATCH 1/3] CLAUDE.md is a view: rendered from record/views.d/CLAUDE.md.j2 The hand-written map moves into the template verbatim, so the rendered file matches today's CLAUDE.md byte for byte apart from the generated stamp and one new section: the principles in force, from docs("DP", in_force=true), so the bootloader cannot name a retired principle or miss a new one. The regenerated CLAUDE.md is not committed here; the generate job on main writes it, as for every view (CONTRIBUTING). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Dex8HCzKcCoo8P71LRqAve --- luria.yaml | 6 +++ record/changelog.d/claude-md-view.md | 7 ++++ record/views.d/CLAUDE.md.j2 | 62 ++++++++++++++++++++++++++++ tests/test_bootloader_view.py | 38 +++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 record/changelog.d/claude-md-view.md create mode 100644 record/views.d/CLAUDE.md.j2 create mode 100644 tests/test_bootloader_view.py diff --git a/luria.yaml b/luria.yaml index 5b415105..ffd2ef5a 100644 --- a/luria.yaml +++ b/luria.yaml @@ -165,6 +165,12 @@ schemes: many: true required: false influence: influenced_by +# Files rendered from a template over the record (ADR-130). The +# bootloader keeps its prose in the template and derives what would drift. +views: + bootloader: + template: record/views.d/CLAUDE.md.j2 + output: CLAUDE.md remotes: SG: name: strata-g diff --git a/record/changelog.d/claude-md-view.md b/record/changelog.d/claude-md-view.md new file mode 100644 index 00000000..8d09176b --- /dev/null +++ b/record/changelog.d/claude-md-view.md @@ -0,0 +1,7 @@ +### Documentation + +- This repository's `CLAUDE.md` is now a view ([ADR-130](record/decisions.d/ADR-130.md)), rendered by + `luria index` from `record/views.d/CLAUDE.md.j2`. The hand-written map + stays prose in the template. A new "Principles in force" section lists + the active design principles, derived from the record. Edit the + template, never `CLAUDE.md`. diff --git a/record/views.d/CLAUDE.md.j2 b/record/views.d/CLAUDE.md.j2 new file mode 100644 index 00000000..a9606c76 --- /dev/null +++ b/record/views.d/CLAUDE.md.j2 @@ -0,0 +1,62 @@ +# CLAUDE.md + +Luria is a CLI that keeps a project's memory — and this repository is its +own first user: the record here is scaffolded, generated, and linted by +the code in `luria/`. This file is a map, not a manual; when it disagrees +with `luria --help` or the docs, it is this file that is wrong. + +Orient first: + +- **Run `luria --help`** — the live command surface; every command takes + `--help`. +- [Project memory](docs/project-memory.md) — the model: sources vs. generated views, + schemes, journals, fragments, remotes, and how references are checked. +- [The record](docs/record.md) — this project's own configuration, + generated: what kinds of entry exist and what to type to file one. +- [Decisions](docs/decisions/README.md) and + [design principles](docs/design-principles.md) — why things are the way + they are. Check here before re-deriving or re-litigating a choice. +- [Comment directives](docs/directives.md) — how to acknowledge a lint + finding deliberately instead of working around it. + +## Working agreements + +- **Work goes to a branch and a pull request, never straight to `main`.** + The record is the deliverable; it needs a chance to be read before it + becomes what the project believes. +- **File the record entry in the same contribution as the work** + (`luria new`): a changelog fragment for the change, a devlog entry for + anything the next person would otherwise rediscover, a decision document + when a real alternative was rejected. Filed with context loaded it costs + a paragraph; re-derived cold it costs a session. +- **Never edit a generated file.** Anything stamped `GENERATED` — the + decision index, tag pages, `docs/design-principles.md`, journal books, + reports, `docs/record.md`, `docs/configuration.md`, the README badge + region — is rebuilt by `luria index`. Edit the sources, rerun it. +- **Never hand-write a link target for a code.** Write the bare code and + run `luria link --fix`; record prose renders into views in other + directories, so only the fixer knows the frame a target must resolve + from. Codes in backticks are mentions, not citations, and are left + alone. +- **A guard that keeps catching you is a bug report about the workflow.** + One catch is the net working; the same catch twice means the hazard is + upstream, and the fix is to remove what generates the mistake, not to + keep thanking the net. + +## Developing the package + +`python -m pytest tests -q` plus `luria lint` is what CI runs. A new check +joins the lint only if the violation is always wrong and mechanically +fixable; anything needing judgement is a report with an acknowledgement +directive. Fire any new guard once on a real case before trusting it, and +say so in the devlog. + +## Principles in force + +The standing values decisions cite by number, derived from the record so +this list cannot name a retired one or miss a new one. The argument behind +each is in the [design principles](docs/design-principles.md). + +{% for p in docs("DP", in_force=true) %} +- {{ p.code }}: {{ p.title }} +{% endfor %} diff --git a/tests/test_bootloader_view.py b/tests/test_bootloader_view.py new file mode 100644 index 00000000..244fa3c5 --- /dev/null +++ b/tests/test_bootloader_view.py @@ -0,0 +1,38 @@ +# tests/test_bootloader_view.py +"""This repository's own `CLAUDE.md` is a view (ADR-130): the hand-written +map stays prose in its template, and the principles it lists are derived, +so the bootloader cannot name a principle that was retired or miss one +that was adopted. +""" + +from __future__ import annotations + +from luria import adr_index, config, views + + +def bootloader(): + return config.current().views["bootloader"] + + +def test_claude_md_is_rendered_from_a_template(): + view = bootloader() + root = config.current().root + assert view.output == root / "CLAUDE.md" + assert view.template == root / "record/views.d/CLAUDE.md.j2" + + +def test_it_lists_exactly_the_principles_in_force(): + text = views.render(bootloader()) + section = text.split("## Principles in force", 1)[1] + for scheme in [config.current().schemes["DP"]]: + for doc in adr_index.load_scheme(scheme): + listed = f"[{doc.code}]" in section + assert listed == (doc.status_value == scheme.active), doc.code + + +def test_it_keeps_the_hand_written_map(): + text = views.render(bootloader()) + assert "This file is a map, not a manual" in text + assert "## Working agreements" in text + assert text.startswith("