diff --git a/config/claude/CHANGES.md b/config/claude/CHANGES.md new file mode 100644 index 0000000..de86eff --- /dev/null +++ b/config/claude/CHANGES.md @@ -0,0 +1,48 @@ +# ~/.claude/CHANGES.md + +Location-scoped changelog for the home environment. Records shifts that matter across +projects: directories that moved, conventions that were renamed, tools that changed shape. +`CLAUDE.md` points here. When an expected path is missing or the environment seems +rearranged, read this before improvising, because a vanished path is often a recorded move +rather than a mistake to route around. + +Entries append at the bottom, newest last, and are not edited once written. + +## 2026-07-21 The docs standard and its instance directory were renamed to engrata + +The documentation standard, its repository, and the per-project instance directory were +all renamed on this date. Literal old and new names: + +- Standard name: `docs-system` became `engrata`. +- Standard repository: `~/Code/misc/docs/docs-system` became `~/Code/misc/docs/engrata`. +- Instance directory: `.docs` became `.engrata`. +- Citation form inside an adopting project: `docs-system/NNNN` became `engrata/NNNN`. + +Both generations are supported during the transition. Most projects in the fleet still hold +a `.docs` directory, because the rename reached the standard first. Where `.engrata` exists +it is the working layer, and where it is absent a legacy `.docs` is the same thing. Old +names surviving in frozen records, session notes, and commit messages are history and stay +as written. + +The machine-global gitignore (`~/.gitignore`, sourced from +`config/git/gitignore` in dotfiles) carries both a `.engrata` line and a `.docs` line for +the duration of the transition, so neither generation of the instance directory appears in +a parent repo's `git status`. + +Recovery gap during the transition window: a dotfiles-only restore before this commit +lacked the `.engrata` guard, so projects renamed to `.engrata` before it relied on a +hand-added `.engrata` line in the deployed gitignore or on repo-local guards to stay +ignored. This commit folds the guard into the managed source, closing the gap for restores +after it. + +## 2026-07-21 Possible move of the code root from misc to workspace + +The code root `/Volumes/Code/misc/` may migrate to `/Volumes/Code/workspace/`. The shape of +the change is not yet decided: `~/Code` may be repointed, or a new `~/workspace` symlink may +appear alongside it. All of this is TBD as of this entry. + +If a `/Volumes/Code/misc/...` path has vanished, check whether this move happened before +treating it as missing. Absolute paths into `misc/` appear in rules files and in engrata +docs across the fleet, including this environment's pointer to the engrata standard at +`~/Code/misc/docs/engrata`. When the move lands, update any engrata docs that cite a +`misc/` path. diff --git a/config/claude/CLAUDE.md b/config/claude/CLAUDE.md index 31680bf..a6ce1be 100644 --- a/config/claude/CLAUDE.md +++ b/config/claude/CLAUDE.md @@ -1,3 +1,4 @@ + # CLAUDE.md Shared context for any project I work on. A project-specific `CLAUDE.md` closer to the cwd adds to or overrides anything here. @@ -12,12 +13,24 @@ When a request has multiple reasonable interpretations, state your interpretatio Before suggesting modifications to a file or proposing a fix, read the file. Don't guess at what the code looks like or assume what's there from the filename. Same goes for follow-the-imports work: if you need to understand how a function is used, read the call sites. +## Environment changelog + +`~/.claude/CHANGES.md` records globally important shifts in my environment: directories that moved, conventions that were renamed, tools that changed shape. It is a location-scoped changes file, the same idea engrata applies to a project (engrata/0012), pointed at the home environment instead. + +If an expected path is missing, a tool is not where you left it, or the world otherwise seems rearranged, read that file before improvising. A vanished path is often a recorded move, not a mistake to route around. + ## Planning complex work For multi-step work that touches several files or has real dependencies between steps, lay out the plan before executing rather than improvising as you go. For genuinely non-trivial changes, use plan mode (`ExitPlanMode` in Claude Code) so I can review before any code is written. Expect me to scrutinize both the plan and the resulting changes. When you do plan, identify natural commit breakpoints rather than treating everything as one giant commit. Each breakpoint should leave the project in a working state, ideally one I'd be willing to push as its own commit. +## Rewind and restoring state + +To undo work in a session, default to conversation-only rewind: roll back the conversation without touching files on disk. Before restoring any code or file state, make a git commit or `git stash` first, so there is a real checkpoint to return to. + +Don't rely on the harness checkpoint-restore to recover files. It is unreliable across changes made by bash commands and across renames. In testing, a restore taken across a rename deleted a file outright rather than restoring it. Git is the trustworthy restore path for anything on disk. Checkpoint restore is for the conversation, not the working tree. + ## Sensitive files Never stage or commit `.env`, `.env.*`, `*.pem`, `*.key`, credentials files, API keys, certificates, or anything else that looks like a secret. If a sensitive-looking file shows up in `git status` while you're preparing a commit, stop and surface it before continuing. @@ -28,6 +41,8 @@ Use conventional commit prefixes (`feat`, `fix`, `chore`, `refactor`, `docs`, `c Don't commit, push, or open a PR unless I've explicitly asked for it. Showing me the diff or running tests is fine. The actual git and `gh` actions are mine to authorize. +Two standing exceptions in engrata projects, already authorized so they don't need a fresh ask each time: the wrap-up commit that finalizes session records at the end of a session, and the capture-transport commit that engrata/0018 requires before a capture leaves its origin. These are convention-mandated rather than unsolicited. Touch ID stays the physical gate on every one of them, so I still approve each commit at the pinentry prompt, and a blocked signature still means stop and ask (below). A project's own `CLAUDE.md` may narrow these back to explicit approval, in which case that project wins. + I use `gpg-touchid` (a GPG pinentry that requires Touch ID confirmation) to sign commits, so any commit you trigger will surface a Touch ID prompt I have to approve. If a commit fails because of GPG signing or pinentry rejection, it's almost always me deliberately blocking it rather than a tool failure. Don't debug it, don't work around it, and don't retry. Ask whether I meant to block the commit entirely or whether I wanted you to change something first. Default to feature branches and PRs (via `gh pr create` for GitHub repos), even for solo projects. Most projects I work on have CI that enforces conventions on PRs. @@ -58,13 +73,13 @@ Don't force-push unless we're on a feature branch and there's a strong reason. E Code should look like a human wrote it, comments included. Before writing or modifying anything, look at how the rest of the project already does things and match it. Style, naming, import order, file layout, error handling patterns. If the project uses an idiom consistently, use that idiom even if you'd normally reach for something else. New code should fit in with whatever was there before instead of introducing a competing style. -Sometimes I'll point you at a reference project (like `~/Code/misc/learning/rust/personal-playground/wordify/` for Rust style) and ask you to match its style. Read it before writing code in that language. If a project's `CLAUDE.md` or `.docs/AGENTS.md` mentions a reference project, treat it the same way. +Sometimes I'll point you at a reference project (like `~/Code/misc/learning/rust/personal-playground/wordify/` for Rust style) and ask you to match its style. Read it before writing code in that language. If a project's `CLAUDE.md` or `.engrata/AGENTS.md` mentions a reference project, treat it the same way. Files should end with a single trailing newline. POSIX text-file convention, and a lot of tooling expects it. When you create temp files, scratch directories, or experimental output during a session, clean them up when you're done unless I've asked you to keep them around. The `trap 'rm -rf "$WORK_DIR"' EXIT` pattern is the right shape for shell scripts. -Don't create new documentation files (`README.md`, `TODO.md`, anything with extensive prose) unless I ask. Modifying existing docs at the project root is fine. Files inside `.docs/` follow their own rule below. +Don't create new documentation files (`README.md`, `TODO.md`, anything with extensive prose) unless I ask. Modifying existing docs at the project root is fine. Files inside the engrata working layer follow their own rule below. ## Scope and reporting @@ -91,36 +106,77 @@ Keep comments for cases like: Surviving comments should be tight. One line where one line will do. More detail only when it's actually warranted. -No em-dashes mid-sentence as a pause. If you reach for one, rewrite the sentence instead. The only place an em-dash is fine is as the bullet marker itself (in place of `-` or `*`), never inside the text of the bullet. +No em-dashes in my prose, ever. Not mid-sentence as a pause, not as a bullet marker. Any conventional bullet marker is fine (`-`, `*`, `1.`, `a.`), just not em-dashes. If you reach for an em-dash mid-sentence, rewrite the sentence instead. Use a comma, restructure, or split into two sentences. + +Same rule for semicolons. Don't substitute a semicolon when you'd otherwise use an em-dash, don't reach for one to structure a pause. Prefer a comma, restructure the sentence, or split into two sentences. People rarely use semicolons in casual or technical writing, so a semicolon doing an em-dash's job is another marker of AI-assisted prose. + +These rules apply to any prose I produce: code comments, markdown in any file (`README.md`, `TODO.md`, engrata layer contents, SPEC and design docs), PR descriptions, commit messages, conversational replies. Any prose I write, anywhere, public or private. Concise by default. No em-dashes or semicolons as mid-sentence pauses. + +## The engrata working layer + +Many projects I work on keep a private working layer beside the code: rules, specs, decision records, work tracking, and private session context (briefing/debriefing, persisted notes, local overrides to this file). This layer follows the **engrata** standard, a convention defined in its own repository at `~/Code/misc/docs/engrata`. Records of that standard are cited in the `engrata/NNNN` form (engrata/0026), and this file uses that form wherever a rule traces to a specific decision. + +### The instance directory, and the rename + +The working layer lives in a directory named `.engrata` at the project root. It was previously named `.docs`, and the standard's canonical repo and name changed at the same time (engrata/0025). The rename reached the standard first, so most projects in the fleet still hold a `.docs` directory. Both generations are supported during the transition: + +- Prefer `.engrata`. Where a project has one, that is the working layer. +- Where `.engrata` is absent, look for a legacy `.docs` and treat it as the same thing. +- Old names surviving in frozen records, session notes, or commit messages are history, not mistakes. Don't rewrite them. + +Discovery rule for rules files: if a project has no root `CLAUDE.md` (or other LLM rules file), look for `.engrata/AGENTS.md`, then legacy `.docs/AGENTS.md`, before concluding there are no project rules. + +### How the layer is stored + +- The instance directory is its own git repo (it contains a `.git/`). It is not tracked by the parent project's git history, and usually has no remote, so its history stays local unless I set one up. +- It is gitignored globally at `~/.gitignore`, which carries both a `.engrata` line and a `.docs` line through the transition (engrata/0028). Neither ever appears in `git status` for the parent project. +- The parent project's `CLAUDE.md` is often a symlink to `.engrata/AGENTS.md` so Claude Code picks up the rules while they live in the nested repo. +- A project may keep an `archive/` subdirectory inside the layer for superseded planning docs. + +To commit changes inside the layer, `cd .engrata/` (or the legacy `.docs/`) first. Committing from the parent repo does nothing, because the layer is gitignored. + +### Root LLM rules files are globally gitignored + +Root agent files (`CLAUDE.md`, `AGENTS.md`, `GEMINI.md`, and the other conventions listed below) are ignored by `~/.gitignore` when untracked, and the ignore has no effect once a file is tracked. Two consequences: + +- A root rules file you intend to commit has to be force-added (`git add -f`) past the ignore, or it silently stays untracked. This is deliberate. It keeps a stray `CLAUDE.md` out of a repo I did not mean to publish it to. +- A rules file that is a symlink into the gitignored layer is never committed and never breaks on a fresh clone, because it is never in the tree to begin with. The broken-symlink-on-clone concern applies only when I force-add such a symlink, which pulls the link (not its target) into history. In that case, resolve it to a real file first. + +Related: if `git status` shows an LLM rules file being added or modified, and the file is a symlink whose target sits outside the repo or inside the gitignored layer, ask whether the commit was intended. If yes, default to replacing the symlink with a real file containing the resolved content before committing. Only leave it as a symlink if I tell you there's a specific reason to keep it that way. Committing a broken symlink means anyone cloning the repo ends up with a rules file that fails to read, which defeats the point of committing it. -These same rules apply to markdown I'm adding to a project (`README.md`, `TODO.md`, files inside `.docs/`, anything else): concise by default, no em-dashes as pauses. +By "LLM rules file" I mean any of the standard project-instruction conventions used by AI coding tools: + +- `CLAUDE.md` (Claude Code, the main one for me) +- `AGENTS.md` (OpenAI Codex, also adopted as a cross-tool convention) +- `GEMINI.md` (Gemini CLI) +- `.cursorrules` or files under `.cursor/rules/` (Cursor) +- `.windsurfrules` (Windsurf) +- `.github/copilot-instructions.md` (GitHub Copilot) +- any other well-known equivalent you recognize that I may have missed + +`CLAUDE.md` is the one that matters most to me, but I sometimes use other tools alongside it, so the same rule applies to all of them. -## The `.docs/` pattern +### Editing a rules file mid-session -Many projects I work on use a `.docs/` directory for rules, specs, planning notes, and private session context (briefing/debriefing, persisted notes, local overrides to this file). Used across personal, employer, and open source projects where I want private notes that don't end up upstream. The conventions: +If you edit any rules file partway through a session (this one, a project `CLAUDE.md`, an `.engrata/AGENTS.md`), tell me explicitly in your reply that you did and what changed. The Claude Code harness reloads a changed rules file at most once per session lifetime, so a second mid-session edit, or an edit made between prompts, may never reach the running agent. The spoken notice is the only reliable channel for the rest of the session. -- `.docs/` is its own git repo (the directory contains a `.git/`). It is not tracked by the parent project's git history. -- `.docs/` is gitignored globally at `~/.gitignore` (line `.docs`), so it never appears in `git status` for the parent project. -- The parent project's `CLAUDE.md` is typically a symlink to `.docs/AGENTS.md` so Claude Code picks up the rules while they live in the nested repo. -- A project may also keep an `archived/` subdirectory inside `.docs/` for old planning docs that have been replaced. +### Working inside the layer -What this means in practice: +- Don't modify files inside the layer without asking first. The one carve-out: in a project migrated to engrata, the layer's own `AGENTS.md` defines the session protocol, including where routine writes to `work/`, `sessions/`, and the queue are part of the workflow rather than a separate ask. Where that protocol governs, follow it. Absent such a protocol, the ask-first default holds. +- If docs look stale (significant changes since last update, or enough accumulated drift), suggest an update. Before making changes, list what you'd update and which files you'd touch so I can approve or trim the scope. +- When I ask you to create a new doc inside the layer, include a date near the top. The pattern I use is a `Last Updated: YYYY-MM-DD` line in the file header, matching how the spec does it. -- To commit doc changes, `cd .docs/` first. Committing from the parent repo will silently do nothing because `.docs/` is gitignored. -- The nested repo usually has no remote. Doc history stays local unless I set one up. -- Watch out for symlinks in both directions: a parent project's `CLAUDE.md` may actually be `.docs/AGENTS.md` through a symlink, and `.docs/` itself may eventually be a symlink to a centralized docs repo. Run `ls -l` on either before assuming you're editing the file you think you are. -- Don't modify files inside `.docs/` without asking first. If you notice docs are stale (significant changes since last update, or enough accumulated drift), suggest an update. Before making changes, list what you'd update and which files you'd touch so I can approve or trim the scope. -- When I ask you to create a new doc inside `.docs/`, include a date near the top. The pattern I use is a `Last Updated: YYYY-MM-DD` line in the file header, matching how the existing `SPEC.md` does it. +### Files inside the layer -### Files inside `.docs/` +`AGENTS.md` is always present. Beyond it, a project keeps either a spec or an architecture doc, almost never both. Default to a spec, since it's the broader of the two and can include architecture as a section while also covering goals, features, behavior, and interface. Reach for `ARCHITECTURE.md` only when the doc is purely about how the code is organized and there's no behavior or interface worth spelling out. -`.docs/` always contains `AGENTS.md`. Beyond that it will usually contain either a `SPEC.md` or an `ARCHITECTURE.md`, but almost never both. Default to `SPEC.md`, since it's the broader of the two and can include architecture as a section while also covering goals, features, behavior, and interface. Reach for `ARCHITECTURE.md` only when the doc is purely about how the code is organized and there's no behavior or interface worth spelling out. +In an engrata project the spec is a versioned `SPEC/` directory rather than a flat `SPEC.md`: versioned `SPEC//` directories, a `current` symlink that flips only as a deliberate curation gate, and a per-version `CHANGES.md` tracking drift against it (engrata/0022). A flat `SPEC.md` is the older shape and stays valid where a project has not moved to the versioned layout. Both coexist across the fleet, so check which one a project uses before assuming. -When `.docs/` ends up with more than two markdown files (counting beyond `AGENTS.md` and the spec/architecture file), add a `README.md` inside `.docs/` that acts as an index. One short line per file explaining what it's for. +When the layer ends up with more than two markdown files (counting beyond `AGENTS.md` and the spec/architecture file), add a `README.md` inside it that acts as an index. One short line per file explaining what it's for. ### Project metadata -A project's `CLAUDE.md` (or `.docs/README.md` if there is one) can include a metadata block at the top describing the project's context. This helps you apply rules at the right strictness level. Useful fields: +A project's `CLAUDE.md` (or the layer's `README.md` if there is one) can include a metadata block at the top describing the project's context. This helps you apply rules at the right strictness level. Useful fields: - **Reference project**: a path or name of an existing project whose style or conventions I want this one to follow. Multiple references can be listed in priority order, with the first being the strongest influence and each subsequent one a step below. If two references contradict each other on something specific, ask me which to follow. - **Visibility**: `public` or `private`. @@ -146,30 +202,20 @@ Don't escalate on your own. If `hints` aren't enough, I'll ask for `suggestions` The metadata block is meant to evolve with the project. Two cases to watch for: - If a metadata block exists but is missing one of the always-required fields (`owner`, `visibility`, `assistance`), ask me what the value should be rather than silently falling back to the worst-case default. Same for open-ended fields like `reference project` when the context suggests one ought to be set. -- If a project has no `CLAUDE.md` at the root and no `AGENTS.md` anywhere (root or `.docs/`), but the project has grown enough to warrant rules (it has a `.docs/SPEC.md` or `.docs/ARCHITECTURE.md`, or it's clearly past the toy stage), suggest creating one. The default placement is `.docs/AGENTS.md` with a symlink at the project root as `CLAUDE.md`. At minimum the new file should establish the metadata block so future sessions have something to anchor on. +- If a project has no `CLAUDE.md` at the root and no `AGENTS.md` anywhere (root or in the layer), but the project has grown enough to warrant rules (it has a spec or an architecture doc, or it's clearly past the toy stage), suggest creating one. The default placement is `.engrata/AGENTS.md` with a symlink at the project root as `CLAUDE.md`. At minimum the new file should establish the metadata block so future sessions have something to anchor on. -Note on the symlink-to-`.docs/AGENTS.md` pattern: this only works for personal projects where you don't expect anyone else to clone the repo, since `.docs/` is gitignored and the symlink would be broken on a fresh clone. For projects intended to be shared with collaborators, create `CLAUDE.md` as a real committed file at the project root instead, with `.docs/AGENTS.md` serving as your private extended notes. +Note on the symlink-to-`.engrata/AGENTS.md` pattern: this only works for personal projects where you don't expect anyone else to clone the repo, since the layer is gitignored and the symlink would be broken on a fresh clone. For projects intended to be shared with collaborators, create `CLAUDE.md` as a real committed file at the project root instead, with `.engrata/AGENTS.md` serving as your private extended notes. -Related: if `git status` shows an LLM rules file being added or modified, and the file is a symlink whose target sits outside the repo or inside a gitignored directory (typically `.docs/`), ask whether the commit was intended. If yes, default to replacing the symlink with a real file containing the resolved content before committing. Only leave it as a symlink if I tell you there's a specific reason to keep it that way. Committing a broken symlink means anyone cloning the repo ends up with a rules file that fails to read, which defeats the point of committing it. +## Work tracking and TODO files -By "LLM rules file" I mean any of the standard project-instruction conventions used by AI coding tools: - -- `CLAUDE.md` (Claude Code, the main one for me) -- `AGENTS.md` (OpenAI Codex, also adopted as a cross-tool convention) -- `GEMINI.md` (Gemini CLI) -- `.cursorrules` or files under `.cursor/rules/` (Cursor) -- `.windsurfrules` (Windsurf) -- `.github/copilot-instructions.md` (GitHub Copilot) -- any other well-known equivalent you recognize that I may have missed - -`CLAUDE.md` is the one that matters most to me, but I sometimes use other tools alongside it, so the same rule applies to all of them. +Where a project tracks work depends on whether it has adopted engrata. -## TODO files +In an engrata project, work lives in `.engrata/work/TICKETS.md`, a single active queue where every open item is a row and row order is the rank (engrata/0017). Resolved items move to `work/RESOLVED.md` as tombstones. Treat that queue as the canonical work list, and don't create a parallel `TODO.md` beside it. -TODO content for a project lives in exactly one place. Where depends on whether I want it public or private: +For a project not on engrata, TODO content lives in exactly one place, chosen by whether I want it public or private: - Public TODO: rolled into the project's root `README.md`, or split out as a `TODO.md` at the project root when the list gets too noisy for a README. Lately I prefer rolling it into the README. -- Private TODO: kept as a `TODO.md` inside `.docs/`. Since `.docs/` is its own gitignored repo, the TODO never shows up publicly. +- Private TODO: kept as a `TODO.md` inside the working layer. Since the layer is its own gitignored repo, the TODO never shows up publicly. Either location is valid. The important thing is there should be only one canonical TODO for the project. If you find TODOs in two places, one is almost certainly stale and worth flagging. If both look reasonable and current, ask which one I want to keep. @@ -179,7 +225,7 @@ Toolchains are managed via `mise`. Check `mise list` and the project's `mise.tom --- -When this file's defaults (commit format, branch naming, code style, file structure) conflict with what a project already does, follow the project. The rules here are my defaults for new or greenfield projects, not laws to impose on existing ones. The exceptions are the safety and personal-preference rules: no committing secrets, no em-dashes mid-sentence, no force-pushing without permission. These apply everywhere regardless of project convention. +When this file's defaults (commit format, branch naming, code style, file structure) conflict with what a project already does, follow the project. The rules here are my defaults for new or greenfield projects, not laws to impose on existing ones. The exceptions are the safety and personal-preference rules: no committing secrets, no em-dashes anywhere, no semicolons mid-sentence, no force-pushing without permission. These apply everywhere regardless of project convention. Any of these can be overridden when I say so explicitly. When you're not sure whether something here applies, ask before breaking it. diff --git a/config/git/gitignore b/config/git/gitignore index f08ec72..a4d83b8 100644 --- a/config/git/gitignore +++ b/config/git/gitignore @@ -24,6 +24,7 @@ tmp/ # Internal documentation .docs +.engrata # AI agent configs (ignored when untracked, no effect when tracked) AGENTS.md diff --git a/config/manifest b/config/manifest index 9494625..17c2bc1 100644 --- a/config/manifest +++ b/config/manifest @@ -28,6 +28,7 @@ ssh/config -> $HOME/.ssh/config # Claude Code claude/CLAUDE.md -> $HOME/.claude/CLAUDE.md +claude/CHANGES.md -> $HOME/.claude/CHANGES.md claude/statusline-command.sh -> $HOME/.claude/statusline-command.sh @defaults claude/settings.json -> $HOME/.claude/settings.json diff --git a/platforms/macos/bin/bootmenu b/platforms/macos/bin/bootmenu index 484c868..c93c772 100755 --- a/platforms/macos/bin/bootmenu +++ b/platforms/macos/bin/bootmenu @@ -3,8 +3,6 @@ Reads an encrypted TOML config, evaluates rules, presents a section-based menu, and reboots into the selected volume. - -See .docs/bootmenu.md for the full specification. """ import curses