Skip to content

Documents installed and symlinked everywhere: a home for VOICE.md and its class #340

Description

@twistedmelonman

Filed here because dotfiles is the closest existing home, not because this
belongs here long term. The payload is documents, not scripts, and the whole
point is that it must not inherit this repo's script-testing load. Move it
once a destination exists.

The problem

personify's VOICE.md is gitignored on purpose, like a .env. It is a
detailed per-user writing profile, roughly 24KB, and it is loaded by the skill
as authoritative. Because it is gitignored, it reaches other machines through
no channel at all: neither git pull nor /plugin update moves it, and
nothing reconciles two machines that disagree.

It is not alone. VOICE.corpus.md is gitignored beside it, and the same shape
shows up across the personal and side-gig environments: a document that has to
land at a known path on several machines, is not secret enough for a secret
store, and is not a script.

The failure mode that makes it worth fixing

Silent, not loud. SKILL.md Step 0 takes the first path that exists, in this
order:

  1. $PERSONIFY_VOICE
  2. $XDG_CONFIG_HOME/personify/VOICE.md, else ~/.config/personify/VOICE.md
  3. VOICE.md in the skill's own directory

A real file at 2 shadows the checkout at 3. You then edit the checkout copy,
the skill keeps loading the config copy, and the output is wrong in a way
nothing reports. SKILL.md line 20 already tells the model to warn when it
sees a guide at both paths, so the sharp edge is known, but that only fires
when both exist and the model is already in Step 0.

Drift is not hypothetical. This machine carries
~/.config/personify/VOICE.md.bak-20260814 at 10,767 bytes against a current
23,920. Less than half the current guide.

This machine is currently fine, and that is luck of local setup rather than
anything the repo guarantees: ~/.config/personify/VOICE.md is a symlink to
~/Developer/personify/VOICE.md, so both paths hash identically
(9ec05054). Nothing in either repo creates that symlink.

Two separable pieces

1. Drift visibility. Cheap, useful under every transport, and worth doing
first.

VOICE.md already carries a hand-maintained **Status:** v0.3 marker on line
3, which will drift from reality the first time it is edited without a bump. A
content hash cannot drift.

Two designs, answering different questions:

  • Report-only fingerprint. Step 0 prints the loaded file's short hash next to
    the version it already reads. No stored expected value, nothing to bless,
    nothing to go stale. Comparing two machines is then reading two lines. This
    answers "are these the same guide", which is the question actually being
    asked.
  • Stored expected hash. Also catches corruption and forgotten edits on a
    single machine, but needs re-blessing on every voice edit. A stale expected
    hash is worse than none, because it cries wolf. If this is wanted, the
    expected value belongs beside the file in the private repo, so re-blessing is
    a commit to the repo just edited rather than a cross-repo chore.

Preference is report-only, and that the hash replaces reliance on the
hand-maintained Status: line rather than sitting beside it. A SHA-256 of a
document discloses nothing about its contents, so the value itself is safe to
print or publish either way.

2. Distribution. A content-distribution repo, private, on the
twistedmelonman account. Deliberately an exception to the public-by-default
rule for that account, because the payload is personal behavioral profiles.

Minimum shape:

  • A manifest of source path to destination path.
  • An installer that symlinks each entry.
  • CI that runs link-check and markdown-lint, and nothing else. Seconds, not
    minutes.

The constraint that keeps it small

Write it into that repo's own CLAUDE.md as a rule with its reason: no
executable payload, the only script is the installer, CI runs link-check and
markdown-lint only. Without that written down, the first thing that almost fits
gets added, and the testing load arrives with it. That is how this repo got to
where it is, and is the reason the new thing should not live here.

The part that needs actual care

The installer can create a symlink on a clean machine. It cannot safely fix a
machine that already has a real file at the destination, which is exactly the
silently-shadowing case. It should refuse loudly and name both paths rather
than clobber or back up and continue. The machine in that state is the one
currently producing wrong output, so a quiet fix there is the worst outcome.

Open questions

  • How many documents are in this class across all the environments? If it is
    genuinely one file, a private gist symlinked into place is competitive and
    needs no infrastructure. The answer decides repo versus gist, and cannot be
    answered from this machine.
  • How many machines have personify installed? Fewer than three weakens the
    ergonomics argument for a repo considerably.
  • Does VOICE.corpus.md need the same treatment, or is provenance-only
    material fine living in one place? It is not loaded when writing.

Not doing now

No changes made. Recorded so the design is not re-derived later.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions