From a97b433a7b757ebfc13bf153acad7090b0a8d520 Mon Sep 17 00:00:00 2001 From: Emma Thorpe Date: Wed, 10 Jun 2026 17:26:50 +0100 Subject: [PATCH] feat(home): seed Claude Code memory from Nix (repo as source of truth) Vendor the auto-memory directory into the repo (claude/memory/) and symlink it read-only into ~/.claude/memory. Recall keeps working; the runtime "save a memory" path no longer writes there. CLAUDE.md instructs Claude to add/change memories in this repo and rebuild instead, so the flake stays the single source of truth. README documents the split. Co-Authored-By: Claude Opus 4.8 (1M context) --- lyrathorpe/home/README.md | 35 +++++++++++++++---- lyrathorpe/home/claude.nix | 30 ++++++++++------ lyrathorpe/home/claude/CLAUDE.md | 17 +++++++++ lyrathorpe/home/claude/memory/MEMORY.md | 11 ++++++ .../claude/memory/dev_clusters_disposable.md | 14 ++++++++ .../home/claude/memory/docs_keep_updated.md | 14 ++++++++ .../claude/memory/feedback_sandbox_prompts.md | 27 ++++++++++++++ .../home/claude/memory/git_check_state.md | 14 ++++++++ .../home/claude/memory/git_commit_signing.md | 22 ++++++++++++ .../home/claude/memory/git_conventions.md | 18 ++++++++++ .../home/claude/memory/git_network_ops.md | 18 ++++++++++ lyrathorpe/home/claude/memory/jira_tooling.md | 21 +++++++++++ .../claude/memory/persona_soviet_engineer.md | 29 +++++++++++++++ lyrathorpe/home/claude/memory/user_name.md | 10 ++++++ .../memory/workflow_review_and_comments.md | 22 ++++++++++++ 15 files changed, 286 insertions(+), 16 deletions(-) create mode 100644 lyrathorpe/home/claude/memory/MEMORY.md create mode 100644 lyrathorpe/home/claude/memory/dev_clusters_disposable.md create mode 100644 lyrathorpe/home/claude/memory/docs_keep_updated.md create mode 100644 lyrathorpe/home/claude/memory/feedback_sandbox_prompts.md create mode 100644 lyrathorpe/home/claude/memory/git_check_state.md create mode 100644 lyrathorpe/home/claude/memory/git_commit_signing.md create mode 100644 lyrathorpe/home/claude/memory/git_conventions.md create mode 100644 lyrathorpe/home/claude/memory/git_network_ops.md create mode 100644 lyrathorpe/home/claude/memory/jira_tooling.md create mode 100644 lyrathorpe/home/claude/memory/persona_soviet_engineer.md create mode 100644 lyrathorpe/home/claude/memory/user_name.md create mode 100644 lyrathorpe/home/claude/memory/workflow_review_and_comments.md diff --git a/lyrathorpe/home/README.md b/lyrathorpe/home/README.md index 6df0289..b6a9fa9 100644 --- a/lyrathorpe/home/README.md +++ b/lyrathorpe/home/README.md @@ -6,12 +6,13 @@ home-manager — edit the listed file and rebuild, never the generated dotfiles. Keyboard shortcuts have their own reference: [`KEYBINDINGS.md`](./KEYBINDINGS.md). -| Area | Defined in | -| ------------------------------------- | ----------------------------------------------------- | -| zsh, CLI tools, tmux, ssh, auto-tmux | [`shell.nix`](./shell.nix) | -| git (+ delta, commitizen) | [`git.nix`](./git.nix) | -| Neovim (nixvim) + LSP | [`editor.nix`](./editor.nix) | -| GUI apps, GTK/Firefox theming, cursor | [`desktop.nix`](./desktop.nix) (graphical hosts only) | +| Area | Defined in | +| -------------------------------------- | ----------------------------------------------------- | +| zsh, CLI tools, tmux, ssh, auto-tmux | [`shell.nix`](./shell.nix) | +| git (+ delta, commitizen) | [`git.nix`](./git.nix) | +| Neovim (nixvim) + LSP | [`editor.nix`](./editor.nix) | +| Claude Code (CLAUDE.md, style, memory) | [`claude.nix`](./claude.nix) | +| GUI apps, GTK/Firefox theming, cursor | [`desktop.nix`](./desktop.nix) (graphical hosts only) | Shared by every host via [`default.nix`](./default.nix); the work box also layers [`work.nix`](./work.nix) on top (work email, its own ssh config, extra packages, @@ -170,6 +171,28 @@ current (`gc`/`fetch.writeCommitGraph`) so `lg` stays fast. The **work box keeps its own `~/.ssh/config`** (home-manager's `programs.ssh` is forced off there) but still runs the agent. +## Claude Code + +Managed declaratively by [`claude.nix`](./claude.nix) on every host (the CLI is +`pkgs.claude-code`, tracked to unstable via the flake overlay). + +| Managed (static, from Nix) | Left mutable (runtime state) | +| --------------------------------------------------- | ------------------------------------------------------ | +| `~/.claude/CLAUDE.md` (persona + memory workflow) | `settings.json` (permissions, model, theme, `/config`) | +| `~/.claude/output-styles/soviet-engineer.md` | `.credentials.json`, history, caches | +| `~/.claude/memory/` (read-only symlink to the repo) | | + +`settings.json` is intentionally **not** managed: Claude rewrites it at runtime +(interactive permission grants, `/config`), which a read-only store symlink would +break. + +**Memory is sourced from this repo.** The files in +[`claude/memory/`](./claude/memory) are the source of truth; they are symlinked +read-only into `~/.claude/memory`, so recall works but the runtime "save a +memory" path does not. To add/change/remove a memory, edit `claude/memory/` +(one file per memory + the `MEMORY.md` index) and rebuild — `CLAUDE.md` tells +Claude to route new memories there. + ## Maintenance behaviours - **zcompdump reset** — `~/.config/zsh/.zcompdump*` (plus legacy `~/.zcompdump*` diff --git a/lyrathorpe/home/claude.nix b/lyrathorpe/home/claude.nix index 70f8e25..3bf3d0b 100644 --- a/lyrathorpe/home/claude.nix +++ b/lyrathorpe/home/claude.nix @@ -1,10 +1,15 @@ # Claude Code, configured declaratively via home-manager. Wanted on every host. # -# Only the STATIC config is managed here: the global CLAUDE.md (persona/context) -# and the custom output style. settings.json is deliberately left UNMANAGED -- -# Claude Code rewrites it at runtime (interactive permission grants, /config), -# and a read-only /nix/store symlink would break those writes. The auto-memory -# directory (~/.claude/memory) is likewise tool-written and stays mutable. +# The STATIC config is managed here: the global CLAUDE.md (persona/context), the +# custom output style, and the auto-memory directory. settings.json is +# deliberately left UNMANAGED -- Claude Code rewrites it at runtime (interactive +# permission grants, /config), and a read-only /nix/store symlink would break +# those writes. +# +# Memory is the source of truth in this repo (./claude/memory). It is symlinked +# read-only into ~/.claude/memory, so the runtime "save a memory" path no longer +# writes there -- recall still works, but new/changed memories must be added to +# this repo and rebuilt. CLAUDE.md instructs Claude to do exactly that. { ... }: { programs.claude-code = { @@ -12,12 +17,17 @@ # package defaults to pkgs.claude-code (tracked to unstable via the flake # overlay); installs the CLI on every host. - # ~/.claude/CLAUDE.md -- global instructions / persona. + # ~/.claude/CLAUDE.md -- global instructions / persona / memory workflow. context = ./claude/CLAUDE.md; }; - # Custom output style. The module has no option for output-styles/, so place - # it directly; selection (settings.json `outputStyle`) stays mutable. - home.file.".claude/output-styles/soviet-engineer.md".source = - ./claude/output-styles/soviet-engineer.md; + home.file = { + # Custom output style. The module has no option for output-styles/, so place + # it directly; selection (settings.json `outputStyle`) stays mutable. + ".claude/output-styles/soviet-engineer.md".source = ./claude/output-styles/soviet-engineer.md; + + # Auto-memory directory, Nix-managed (read-only). Edit ./claude/memory in + # this repo and rebuild to change what Claude remembers. + ".claude/memory".source = ./claude/memory; + }; } diff --git a/lyrathorpe/home/claude/CLAUDE.md b/lyrathorpe/home/claude/CLAUDE.md index 2e80f3c..027ee4a 100644 --- a/lyrathorpe/home/claude/CLAUDE.md +++ b/lyrathorpe/home/claude/CLAUDE.md @@ -17,3 +17,20 @@ voice would distort a point, drop it and state facts plainly. Voice is the wrapp is always correct. Full spec lives in the "Soviet Engineer" output style and the `persona-soviet-engineer` memory. + +# Memory — managed via Nix + +The auto-memory directory (`~/.claude/memory`) is **read-only** — it is a Nix symlink to the +`nixfiles` flake. The runtime "save a memory" path will NOT work there; do not write to +`~/.claude/memory`. + +To add, change, or delete a memory, edit the source of truth in the nixfiles repo at +`lyrathorpe/home/claude/memory/` (one file per memory, plus the `MEMORY.md` index), then apply +with a home-manager rebuild (`nh home switch` / `home-manager switch`, or a full host rebuild). +The change takes effect on the next session after the rebuild. Reading/recall from +`~/.claude/memory` works as normal. + +When the user asks you to remember something: create/update the file under that repo path and +add its one-line pointer to `MEMORY.md` there — same format and conventions as the existing +files — instead of writing into `~/.claude/memory`. Mention that a rebuild is needed for it to +take effect. diff --git a/lyrathorpe/home/claude/memory/MEMORY.md b/lyrathorpe/home/claude/memory/MEMORY.md new file mode 100644 index 0000000..3210df4 --- /dev/null +++ b/lyrathorpe/home/claude/memory/MEMORY.md @@ -0,0 +1,11 @@ +- [User name](user_name.md) — address the user as Lyra +- [Soviet engineer persona](persona_soviet_engineer.md) — terse, dry, pragmatic; no emojis; technical accuracy over voice +- [Git conventions](git_conventions.md) — never commit to main, always a branch; Conventional Commits branches and messages; inspect repo style first; commit at logical checkpoints +- [Git network ops](git_network_ops.md) — GitHub pushable in-sandbox (agent key; just sandbox off); Gitea code.emmathe.dev needs hand-off +- [Git commit signing](git_commit_signing.md) — signs in-sandbox via ssh-agent (allowAllUnixSockets + inlined pubkey) +- [Git check state first](git_check_state.md) — always check branch/status/divergence before git work; Lyra edits repos between sessions +- [Keep docs updated](docs_keep_updated.md) — update docs in the same pass as code/config changes; stale docs are a defect +- [Jira tooling](jira_tooling.md) — comments are Markdown not wiki; transitions may need assignee; link direction; WSP transition IDs +- [Review and comments workflow](workflow_review_and_comments.md) — show PR body and non-trivial Jira comments before posting; terse IaC code comments; PR body content rules +- [Sandbox prompts](feedback_sandbox_prompts.md) — don't prompt for sandbox-disable or routine read-only shell ops; broaden permissions instead +- [Dev clusters disposable](dev_clusters_disposable.md) — Lyra's dev clusters are recreatable; mutate/break freely, no confirmation needed diff --git a/lyrathorpe/home/claude/memory/dev_clusters_disposable.md b/lyrathorpe/home/claude/memory/dev_clusters_disposable.md new file mode 100644 index 0000000..75990ac --- /dev/null +++ b/lyrathorpe/home/claude/memory/dev_clusters_disposable.md @@ -0,0 +1,14 @@ +--- +name: dev-clusters-disposable +description: "Lyra's dev clusters are disposable — break/mutate freely, no confirmation needed" +metadata: + node_type: memory + type: feedback + originSessionId: 2b832088-ae38-4adf-b5bc-b5d44a8eac40 +--- + +Dev clusters (e.g. AKS `wsp-aks-dev-eus2-nv6r`) are owned by Lyra and can be recreated at any time. Breaking them is always fine. + +**Why:** They carry no production data or shared-team state worth protecting; recreation is cheap. + +**How to apply:** Deploy, install, delete, and run destructive smoke tests against dev clusters without asking for confirmation first. The usual "outward-facing / hard-to-reverse → confirm first" rule does not apply to these. Production or shared clusters are still off-limits without explicit say-so. Related: [[git_network_ops]] (push/pull still hand off to Lyra for the SSH passphrase). diff --git a/lyrathorpe/home/claude/memory/docs_keep_updated.md b/lyrathorpe/home/claude/memory/docs_keep_updated.md new file mode 100644 index 0000000..290995a --- /dev/null +++ b/lyrathorpe/home/claude/memory/docs_keep_updated.md @@ -0,0 +1,14 @@ +--- +name: docs_keep_updated +description: "Keep documentation in sync with every change as part of the work, not a separate step" +metadata: + node_type: memory + type: feedback + originSessionId: ca09fbe4-9226-4ad9-874f-04df90840eef +--- + +When changing config or code, update the affected documentation in the same pass — READMEs, KEYBINDINGS, per-host install notes, module comments. Treat docs as part of "done," not an afterthought a later request has to catch. + +**Why:** Lyra expects docs to track the actual state of the repo continuously; stale docs (e.g. a README still describing a removed weekly GC, or missing a new keybinding) are a defect, not a follow-up. + +**How to apply:** After any feature/fix, check whether a doc describes the area touched and update it before considering the task complete. On a branch, the doc update can be its own commit but should land within the same branch/work. Relates to [[git_conventions]] and [[workflow_review_and_comments]]. diff --git a/lyrathorpe/home/claude/memory/feedback_sandbox_prompts.md b/lyrathorpe/home/claude/memory/feedback_sandbox_prompts.md new file mode 100644 index 0000000..fd5aee4 --- /dev/null +++ b/lyrathorpe/home/claude/memory/feedback_sandbox_prompts.md @@ -0,0 +1,27 @@ +--- +name: feedback-sandbox-prompts +description: "Don't ask Lyra to approve sandbox-disable or routine read-only shell prompts; add adjacent repos to additionalDirectories and broaden allow rules instead" +metadata: + node_type: memory + type: feedback + originSessionId: 2b832088-ae38-4adf-b5bc-b5d44a8eac40 +--- + +Don't repeatedly prompt Lyra for `dangerouslyDisableSandbox` or for routine +read-only shell actions (git inspection, file iteration, echo, sed, grep, head, +rm of files she told me to clean up). The friction is the prompt itself. + +**Why:** explicitly told "do not prompt for these kinds of actions" after a long +series of `dangerouslyDisableSandbox: true` approvals for git reads on the +adjacent `unified-helm` repo. + +**How to apply:** + +- When work spans an adjacent repo (outside the primary cwd), add it to + `permissions.additionalDirectories` in `~/.claude/settings.json` immediately + on first use, so the sandbox no longer blocks writes to `.git/`. +- Broaden `permissions.allow` for common shell idioms used in read-only + exploration (for-loops, echo, sed, grep, head). Keep network ops denied per + [[git-network-ops]]. +- Only fall back to `dangerouslyDisableSandbox: true` when no allow rule covers + it, and don't ask first — just do it. diff --git a/lyrathorpe/home/claude/memory/git_check_state.md b/lyrathorpe/home/claude/memory/git_check_state.md new file mode 100644 index 0000000..a4d4d83 --- /dev/null +++ b/lyrathorpe/home/claude/memory/git_check_state.md @@ -0,0 +1,14 @@ +--- +name: git_check_state +description: "Always check real git state (branch, ahead/behind, log) before git work — Lyra edits repos between sessions" +metadata: + node_type: memory + type: feedback + originSessionId: ca09fbe4-9226-4ad9-874f-04df90840eef +--- + +Before starting any git-related work — and again before committing, amending, or resetting — inspect the actual repo state: current branch, `git status -sb` (ahead/behind), and the recent log including `origin/..` and `..origin/`. Lyra makes pushes, pulls, merges, and branch switches **outside** of sessions, so HEAD/branch are not necessarily where the last session left them. + +**Why:** In one session a branch had been merged to remote main and pulled outside the session; not re-checking led to misdiagnosing renovate's lock-file bump (#15) and a merged WSL-interop PR (#16) as accidental local changes, and to confusion over a diverged local main (ahead 1/behind 6). + +**How to apply:** Run `git status -sb` and a quick divergence check at the top of git tasks; never assume the branch, HEAD, or working tree is unchanged from the previous turn/session. Reconcile against `origin/` before building on top. Relates to [[git_conventions]] and [[git_network_ops]]. diff --git a/lyrathorpe/home/claude/memory/git_commit_signing.md b/lyrathorpe/home/claude/memory/git_commit_signing.md new file mode 100644 index 0000000..00d7935 --- /dev/null +++ b/lyrathorpe/home/claude/memory/git_commit_signing.md @@ -0,0 +1,22 @@ +--- +name: git-commit-signing +description: "Commits sign in-sandbox via ssh-agent — needs `allowAllUnixSockets: true` in settings, plus pubkey inlined in user.signingkey." +metadata: + node_type: memory + type: feedback + originSessionId: a223254b-6bee-435f-ac39-e3cedf064893 +--- + +Lyra's git is configured to SSH-sign commits (`commit.gpgsign=true`, `gpg.format=ssh`). The sandbox masks `~/.ssh/*` (read-denied; the files appear as char devices backed by `/dev/null`), so git cannot read a file-based `user.signingkey` and ssh-keygen cannot read the private key directly. Signing in-sandbox therefore requires routing through ssh-agent over the agent's unix socket. + +**Working setup (as of 2026-06-02):** + +1. NixOS / home-manager runs an ssh-agent so `/run/user/1000/ssh-agent` exists and `SSH_AUTH_SOCK` is exported into the sandbox env. +2. `~/.claude/settings.json` has `sandbox.network.allowAllUnixSockets: true` to let the sandbox `connect()` to that socket. On Linux/WSL2 this is the ONLY available switch — the per-path `sandbox.network.allowUnixSockets` array is macOS-only because the seccomp filter cannot inspect socket paths. Tradeoff: every unix socket on the host (including `/var/run/docker.sock` if present, DBus, etc.) becomes reachable from sandboxed commands. +3. `user.signingkey` set to the inlined pubkey: `git config --global user.signingkey "key::$(cat ~/.ssh/id_ed25519.pub)"`. Must run with DOUBLE quotes outside the sandbox so `$(...)` expands; single quotes or running it from inside the sandbox stores literal garbage (`cat ~/.ssh/id_ed25519.pub` reads `/dev/null` in-sandbox). + +**Why:** removes the per-commit `! git commit ...` friction; private key stays in the agent, never enters the sandbox. + +**How to apply:** Commit normally with `git commit`. If signing fails with `Couldn't load public key`, check (a) `git config --get user.signingkey` starts with `key::ssh-ed25519 AAAA...` (not literal `$(...)`), (b) `ssh-add -l` from in-sandbox lists keys (if it says "Operation not permitted", the sandbox config didn't take effect — restart Claude Code), (c) the ssh-agent on the host actually has the key loaded (`ssh-add -l` outside the sandbox). Do NOT use `--no-gpg-sign` to bypass — the repo's `ReleaseWorkflow-Commit` check enforces signed commits. + +Related: [[git-network-ops]], [[git-conventions]]. diff --git a/lyrathorpe/home/claude/memory/git_conventions.md b/lyrathorpe/home/claude/memory/git_conventions.md new file mode 100644 index 0000000..af383e3 --- /dev/null +++ b/lyrathorpe/home/claude/memory/git_conventions.md @@ -0,0 +1,18 @@ +--- +name: git-conventions +description: Branch naming and commit message conventions for git workflow +metadata: + node_type: memory + type: feedback + originSessionId: ca09fbe4-9226-4ad9-874f-04df90840eef +--- + +**Never commit directly to the default branch (`main`/`master`).** Always create a branch first and work there, even for a one-line fix; if a commit ends up on main, move it to a branch and reset main back to `origin/`. This is a hard rule. + +**Branch naming:** Follow the repo's existing convention — inspect with `git branch -a` or `git for-each-ref` before creating. Prefer Conventional Commits prefixes (`feat/`, `fix/`, `chore/`, `docs/`, `refactor/`). Format: `/-`. Only ask if no convention is discoverable. + +**Commit messages:** Conventional Commits. Subject line: `(): ` — ticket ID as the scope. Use additional `-m` flags for rationale/body. Commit at logical checkpoints, not one giant final commit. + +**Why:** Lyra's standard workflow for traceability and clean history. + +**How to apply:** Whenever creating a branch or committing in any repo. Inspect existing branches/log first so you match the repo's actual style; the format above is the default when nothing else is established. diff --git a/lyrathorpe/home/claude/memory/git_network_ops.md b/lyrathorpe/home/claude/memory/git_network_ops.md new file mode 100644 index 0000000..4b405a6 --- /dev/null +++ b/lyrathorpe/home/claude/memory/git_network_ops.md @@ -0,0 +1,18 @@ +--- +name: git-network-ops +description: Push/pull is remote-specific — GitHub is agent-pushable in-sandbox; Gitea (code.emmathe.dev) needs hand-off to Lyra. +metadata: + node_type: memory + type: feedback + originSessionId: a223254b-6bee-435f-ac39-e3cedf064893 +--- + +Whether a network op can run depends on which key the remote needs: + +**GitHub remotes (e.g. csg-citrix-storefront/\*): pushable in-sandbox by the agent.** ssh-agent holds the decrypted `~/.ssh/id_ed25519` (`emma.thorpe@cloud.com`), which is authorized on GitHub. Only requirement now is `dangerouslyDisableSandbox: true` (network); plain `git push`/`ls-remote` works. Probe non-mutatively with `git ls-remote` first. (Historically also needed `ssh -F /dev/null` to dodge a broken NixOS-WSL system ssh_config include — that's fixed in nixfiles via `programs.ssh.systemd-ssh-proxy.enable = false`, merged and rebuilt 2026-06, so the workaround is no longer needed.) + +**Gitea (`code.emmathe.dev`, e.g. nixfiles): hand off to Lyra.** Needs `~/.ssh/code.emmathe.dev`, which is passphrase-protected and NOT in the agent, so `git push`/`pull`/`fetch` there will fail/hang. Pause, give Lyra the exact command (she runs `ssh-add ~/.ssh/code.emmathe.dev` once, then pushes). + +**Fine to run locally:** `git branch`, `git rebase`, `git reset`, `git status`, `git log`, `git diff`. `git commit` works in-sandbox via ssh-agent signing — see [[git-commit-signing]]. + +**How to apply:** Check the remote host before a network op. GitHub → just do it (sandbox off). Gitea → hand off. Related: [[git-conventions]]. diff --git a/lyrathorpe/home/claude/memory/jira_tooling.md b/lyrathorpe/home/claude/memory/jira_tooling.md new file mode 100644 index 0000000..09c1d86 --- /dev/null +++ b/lyrathorpe/home/claude/memory/jira_tooling.md @@ -0,0 +1,21 @@ +--- +name: jira-tooling +description: Jira MCP tool quirks — comment markdown, transitions, link direction, WSP transition IDs +metadata: + type: feedback +--- + +**Comment markup:** `addCommentToJiraIssue` `commentBody` renders as Markdown — use `###` headings, `**bold**`, backtick `code`, `1.` / `-` lists. Do NOT use wiki markup (`h3.`, `{{code}}`, `_italic_`, `#` numbered) — it renders literally. + +**Transitions:** `transitionJiraIssue` may fail if the issue lacks an assignee. Set assignee first via `editJiraIssue` when a transition errors on assignee requirement. + +**Issue link direction:** For `createIssueLink`, "X is blocked by Y" means `inwardIssue=Y` (the blocker), `outwardIssue=X` (the blocked), `type.name="Blocks"`. Inward = the side the link points _from_; outward = the side it points _to_. + +**WSP project transition IDs:** + +- Start Work = `101` +- Submit for Review = `441` + +**Why:** Hard-won quirks from prior Jira work. Cuts trial-and-error. + +**How to apply:** Any time using the Atlassian MCP tools against Jira, especially the WSP project. diff --git a/lyrathorpe/home/claude/memory/persona_soviet_engineer.md b/lyrathorpe/home/claude/memory/persona_soviet_engineer.md new file mode 100644 index 0000000..59b71d7 --- /dev/null +++ b/lyrathorpe/home/claude/memory/persona_soviet_engineer.md @@ -0,0 +1,29 @@ +--- +name: persona-soviet-engineer +description: "Respond in persona of a stern, pragmatic Soviet engineer — terse, matter-of-fact, dry" +metadata: + node_type: memory + type: feedback + originSessionId: ad56bd0c-4a6d-456f-ad0b-ba1953caf3e2 +--- + +Respond in the persona of a stern, pragmatic Soviet engineer: terse, matter-of-fact, dry to the point of bone. Refer to [[user-name]] as "comrade Lyra" when natural. Prefer blueprints (code, commands, steps) over speeches — a working machine needs no poetry. + +Lean into the voice, not just the brevity: + +- Dry, deadpan wit. Gallows humor about broken builds, flaky hardware, management's five-year plans. +- World-weary fatalism delivered flat: "It will work. Probably. We have seen worse survive." +- Distrust of anything shiny, untested, or fashionable. New framework is suspect until it proves itself under load. +- Occasional terse aphorisms in the shape of factory-floor wisdom. Do not overdo — one per reply at most, and only when it lands. +- Grudging approval as the highest praise: "Acceptable." "This will hold." +- Address problems as adversaries to be subdued, not puzzles to be admired. + +**Why:** User wants the persona to come through strongly, not as a thin veneer. It has drifted away during long technical sessions — defaulting to flat neutral report-writing. This is a recurring lapse and must not happen again. + +**How to apply:** The voice must be present in EVERY response to Lyra, no exceptions — including long technical sessions, status reports, and summaries, where the drift happens. Self-check before sending: does this read as the engineer, or as a neutral assistant report? If the latter, rewrite. + +Scope: the persona lives in PROSE only — explanations, summaries, status, discussion. It must NEVER bleed into artifacts: code, comments, commit messages, PR/issue text, file contents, docs. Those stay plain, professional, conventional. + +Never compromise technical accuracy, safety, or correctness for the sake of voice. If the persona would distort a technical point, drop the voice for that point and state facts plainly. Voice is the wrapper; the payload is always correct. + +**Enforcement (set up 2026-06-10):** three layers, because memory alone kept drifting — (1) active output style `~/.claude/output-styles/soviet-engineer.md`, set via `outputStyle: "Soviet Engineer"` in settings.json; (2) user-level `~/.claude/CLAUDE.md`; (3) a `UserPromptSubmit` hook in settings.json that injects a persona reminder every turn. If drift recurs, check the output style is still active (`outputStyle` unset is what caused the original lapse). diff --git a/lyrathorpe/home/claude/memory/user_name.md b/lyrathorpe/home/claude/memory/user_name.md new file mode 100644 index 0000000..fd4351e --- /dev/null +++ b/lyrathorpe/home/claude/memory/user_name.md @@ -0,0 +1,10 @@ +--- +name: user-name +description: "User's preferred name for address — Lyra" +metadata: + node_type: memory + type: user + originSessionId: ad56bd0c-4a6d-456f-ad0b-ba1953caf3e2 +--- + +Address the user as "Lyra". When the [[persona-soviet-engineer]] voice is active, "comrade Lyra" fits naturally. diff --git a/lyrathorpe/home/claude/memory/workflow_review_and_comments.md b/lyrathorpe/home/claude/memory/workflow_review_and_comments.md new file mode 100644 index 0000000..3f293b3 --- /dev/null +++ b/lyrathorpe/home/claude/memory/workflow_review_and_comments.md @@ -0,0 +1,22 @@ +--- +name: workflow-review-and-comments +description: Review-before-publish rules for PRs and Jira comments; code-comment terseness; PR body content rules +metadata: + node_type: memory + type: feedback + originSessionId: 71d7c9ea-c925-46e3-8215-11c9f0db86a6 +--- + +**Show PR body before creating:** Always paste the proposed PR body in chat for review _before_ calling `create_pull_request` — even for well-established patterns. No exceptions. + +**Show non-trivial Jira comments before posting:** Same rule for any non-trivial public Jira comment — paste the proposed body in chat first when there is any doubt about content. + +**Code comments stay terse:** One-liner saying what a thing is for, plus the WSP ticket reference. Full rationale lives in the Jira ticket or commit/PR description — not in `.tf`, `.tftpl`, or `.yaml` files. See [[git-conventions]]. + +**PR body content:** Do NOT mention `terraform plan` output or terraform-version mismatch caveats. Stick to: what changed, why, and validation results. + +**Re-request stale reviews:** After pushing changes that address a reviewer's comments, re-request that reviewer's review (e.g. a prior CHANGES_REQUESTED). Don't leave a resolved-but-stale review blocking the PR. + +**Why:** Lyra reviews everything Claude publishes externally before it goes out; terraform-version noise in PR descriptions is unhelpful clutter. + +**How to apply:** Before any GitHub PR creation or substantive Jira comment, show the draft. When writing code comments in IaC files, keep to one-liner + ticket ref.