A manifest declares repo path -> target, and the script walks it. Symlinks, not copies, so an installed file edits the repo and one commit reaches every other machine. Idempotent — a correct link is a no-op, safe after every pull. A real file where a link should go is moved to .bak-<timestamp> and reported, because on a new machine that may be the only copy of something written by hand. Conditional targets are what make it portable: officer.dev/CLAUDE.md and the officer-chat-events hook both name ~/officer-dev/platform, so a laptop with no Officer install gets neither instead of getting a document that lies. mask-secret is a command now rather than a path only true on this machine, and user/CLAUDE.md says so. It is a generated wrapper, not a symlink, and that is forced: mask-secret.py resolves its own path to find mask-hooks.d, so a symlink would reach back into the repo and run every machine's hooks. The wrapper sets MASK_HOOKS_DIR to the ones this machine installed and still runs the script from the repo, so no code is copied. Verified against a scratch HOME: re-run is all ok, the hand-written file survives as .bak, and a machine without Officer skips both conditional lines.
57 lines
2.2 KiB
Markdown
57 lines
2.2 KiB
Markdown
# claude-mds
|
|
|
|
CLAUDE.md files and Claude Code configuration, kept under version control.
|
|
|
|
## Install, on any machine
|
|
|
|
```sh
|
|
git clone git@gitea.officer.dev:pastilhas/claude-mds.git ~/projects/claude-mds
|
|
~/projects/claude-mds/install.sh
|
|
```
|
|
|
|
`--dry-run` first if you want to see it before it happens.
|
|
|
|
Everything is **symlinked, not copied** — so editing an installed file edits the repo, and the change
|
|
is one `git commit` away from every other machine. Re-run it after each `git pull`; a correct link is
|
|
a no-op.
|
|
|
|
It will not overwrite anything in silence. A real file where a link should go is moved to
|
|
`<name>.bak-<timestamp>` and reported, because on a new machine that file may be the only copy of
|
|
something written by hand.
|
|
|
|
## What lands where
|
|
|
|
`manifest` is the whole answer, and it is the only place paths are declared. Today:
|
|
|
|
| repo | target | only if |
|
|
| ---- | ------ | ------- |
|
|
| `user/CLAUDE.md` | `~/.claude/CLAUDE.md` | always |
|
|
| `officer.dev/CLAUDE.md` | `~/officer-dev/CLAUDE.md` | `~/officer-dev/platform` exists |
|
|
| `tools/mask-hooks.d/officer-chat-events` | `~/.local/claude-scripts/mask-hooks.d/` | `~/officer-dev/platform` exists |
|
|
|
|
Plus `mask-secret` on `~/.local/bin`, as a command rather than a path.
|
|
|
|
Adding a file later is one manifest line, not an edit to the shell.
|
|
|
|
## The two kinds of file
|
|
|
|
- **`user/`** — who you are working with and how. Loads in every session on every machine.
|
|
- **`officer.dev/`** — one workspace on one machine. Conditional, so it never lands where it would be
|
|
a lie.
|
|
|
|
## mask-secret
|
|
|
|
Masks a pasted secret everywhere the chat history keeps it:
|
|
|
|
```sh
|
|
printf '%s' "$SECRET" | mask-secret
|
|
```
|
|
|
|
It owns Claude Code's own transcripts. Anywhere else that keeps a second copy of the chat — a
|
|
database, a mirror, a log shipper — is a **hook**: an executable in `tools/mask-hooks.d/`, listed in
|
|
the manifest with the condition that says which machines it belongs on.
|
|
|
|
The installed `mask-secret` is a small generated wrapper, and that is deliberate. The script finds its
|
|
hooks beside itself and resolves symlinks to do it, so a bare symlink would reach back into the repo
|
|
and run *every* machine's hooks. The wrapper points it at the ones this machine installed.
|