Skip to content

Build1 publisher2 min readPublished

One matching prefix aborts all four writes in a Claude Code audit-memo sync

The gate between Claude Code's self-written audit memos and one developer's Obsidian wiki scans only the four files it intends to copy, tests them against two credential prefixes, and exits 2 on the first match.

The Engineer · Build desk

Illustration accompanying One matching prefix aborts all four writes in a Claude Code audit-memo sync

What happened

  • A shell script called wiki-sync-improvements.sh copies the audit and plan documents Claude Code writes into ~/.claude/improvements/ over to an Obsidian wiki, and 4 of the directory's 12 Markdown files pass its filter.
  • Every candidate is grepped for a two-prefix secret pattern before anything is written, and one match makes the script print the offending paths to stderr and exit 2 with no files copied.
  • The script defaults to dry mode through MODE="${1:-dry}", so invoking it with no argument prints the plan and writes nothing at all.
  • The sample audit memo names the author's projects, flags seo-affiliate-site with 63 uncommitted files, and records that closet-os holds a gitignored 1.9 KB .env.production.local.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint The gate can only refuse the batch, so one memo with a pasted token means a human edits that file before any of the day's audits reach the wiki.
  • decision Anyone reusing the pattern has to rewrite it against the credentials their own stack issues, because sk- and ghp_ are the only two shapes this scan recognises.
  • cost Coexistence instead of overwrite means the wiki gains a file for every changed memo on every apply run, and thinning those copies is left to the operator.

The scan is two prefixes wide. SECRET_RE is `(sk-[A-Za-z0-9_-]{16,}|ghp_[A-Za-z0-9]{20,})` [6]. Both branches of that alternation open on a literal, so a secret that does not begin `sk-` or `ghp_` is not a hit [17]. A Postgres URL with the password inline goes through. The accident the dev.to author describes is narrower than the general case: a fragment of an API key pasted during debugging and then quoted back into a memo the agent wrote [14].

grep runs over the candidate list, not over the directory [7]. The `case` statement admits `audit-*.md`, `*-plan-*.md` and `*-curation-*.md` [3], which on this machine selects 4 files out of 12 and leaves 8 that the scanner never opens and the sync never copies [16]. One loop builds both sets, so what gets inspected and what gets written cannot come apart. log.md is excluded by name, at 2,316 lines and roughly 228 KB of chronological log that does not fit the wiki's one-note-per-file granularity [12].

When any candidate matches, the script prints the offending paths to stderr and exits 2 before touching the destination [7]. "A single hit halts every candidate," the author wrote [8]. Partial syncs were rejected because the script would otherwise have to decide which file to skip, and "a mistake in that call is the scariest failure mode here", the author wrote [9]. I would take that trade at four candidates, where a false positive costs one read of the abort list and one re-run. It gets more expensive as the directory grows, because one stale `sk-` string in a months-old audit stops every other memo alongside it [7].

The write path never overwrites. A candidate is staged to a temp file, compared with `cmp -s` against any same-name file at the destination, then either deleted or moved into place under a timestamped name [11]. The recorded dry run reported `planned=4 total_candidates=4` [15].

The credential pattern is not what holds the rest of the memo back. The project inventory in the audit excerpt matches nothing in SECRET_RE [13], and `audit-*.md` is on the admit list [3]. The filename filter is the whole content policy, and the destination is the author's own human-facing wiki [2].

What to watch

  • Whether SECRET_RE grows past sk- and ghp_ after a memo quotes a credential of a different shape, such as a connection string.
  • Whether the timestamped coexistence rule acquires a prune or retention step as meta/improvements/ fills up.
  • How commands-consolidation-plan.md is handled: the published text breaks off while introducing it.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories