Skip to content

chamnan 1.35.0 — protection and context that hold in real-world text

Choose a tag to compare

@ArcticFox2029 ArcticFox2029 released this 06 Oct 08:41
· 93 commits to main since this release

This release makes chamnan's protection hold in the shapes real text actually takes — commands in shell history, infrastructure state, keys cut off mid-file, names typed in another Unicode form — and makes its heavier steps cheap enough to stop noticing, rather than adding new features.

What was measured Before After
Refreshing a 584,000-character map after a one-file edit (scrub step) 5.9 s 0.02 s
Editing a requirements.txt with 200 past revisions (removed-package check) 18.9 s 0.15 s
Scrubbing one line of 8,000 repeated key- 27 s 0.94 s
chamnan-recall median query 90-100 ms 52-55 ms
curl -u user:PASS, mysql -pPASS, sshpass -p, docker login -p, ConvertTo-SecureString '…' -AsPlainText printed redacted
A private key cut off before its END line (a capped read, head, a truncated paste) body printed redacted
Terraform plan variables and state outputs ("db_password": {"value": …}) printed redacted
chamnan-impact café.py typed in the other Unicode form than the file was created in "nothing recorded" found
An instruction file that quotes one path outside the repository drift check silently off for the file checked

Together they say one thing: the protection and the context hold in the shapes text really arrives in, and the steps that ran on every edit no longer cost seconds.

What you will notice

  • Secrets in commands are caught. A password passed as a flag or positional to curl, mysql, sshpass, docker/helm login, redis-cli, smbclient, htpasswd or PowerShell's ConvertTo-SecureString is redacted — the shapes shell history and pasted commands carry. ssh -p 2222, mkdir -p and $VAR references are left alone.
  • Private keys are redacted in every form tried, including a PEM block cut before its end, a PuTTY .ppk, and a JSON Web Key's private members. Public keys and certificates are untouched.
  • Terraform plans and state are safer to map. A value Terraform stores under a secret-named object — every input variable in a plan, every output in a state, sensitive or not — is redacted.
  • Accented and non-Latin file names are found however they were typed. A file created with a decomposed name (as macOS keeps some) is found by chamnan-impact, the file pointer and the history join whether you type it composed or decomposed.
  • The map refreshes quickly after a small edit, and editing a dependency manifest with a long history no longer stalls.
  • chamnan-recall finds a note whatever the case or accents, and the automatic pointer stops offering notes that match only common words.
  • Repeated advice is capped at two notices a session per kind, and AGENTS.md is no longer rewritten by the pre-commit hook when nothing it describes changed.

Most of the rest is deliberately invisible on the happy path; its purpose is to make unusual text and unusual setups fail less often.

Under the hood

Security

  • Command-anchored rules for passwords given as flags or positionals; a bare -p (a port, or "parents" to most tools) is never touched.
  • A PEM block with no END line is redacted through its body, stopping at the first line that is not key material; PuTTY Private-Lines: and JWK d/p/q/dp/dq/qi/k inside an object with kty.
  • The "value" member inside a secret-named object; header-style names (X-Api-Key:) open the list rules; a secret split by a shell line continuation is redacted on both lines; stripping invisible characters can no longer reassemble a credential; an uncaught traceback is scrubbed before it reaches stderr.
  • The commit guard also guards commits made through the PowerShell tool, scans every staged file git calls binary (including BOM-less UTF-16 and the string literals of .pyc files), says so when it runs out of time, and names the commits only the reflog still holds.
  • Injected lines lose Unicode tag characters and invisible operators; a commit subject quoted to the agent is fenced as repository text.

Performance

  • The map re-scrubs only the sections an edit changed (5.9 s → 0.02 s on a 584,000-character map).
  • A manifest's history is read with one batched git process (18.9 s → 0.15 s on a 200-revision fixture).
  • Every secret-word name run is bounded, so a long value after a secret word scrubs in linear time (8,000 characters of key-: 27 s → 0.94 s).
  • Recall stems each query term once (90-100 ms → 52-55 ms, identical results); subprocess is no longer imported by the two hooks that run on every Bash call; the session start reads HEAD off .git instead of spawning git.

Reliability

  • One quoted path outside the repository no longer switches off the instruction-file drift check for the whole file.
  • Locks record their host, so another machine's live lock is not broken; a sync client's conflict copies are not read as notes; git's "dubious ownership" refusal and the file git will not keep are named with their fixes.
  • A Python file chamnan cannot parse keeps its docstring and top-level names; a source file that declares a legacy encoding keeps its summary; a capped preview never ends in half a character.
  • Shallow clones, sparse checkouts and linked worktrees of shallow clones are recognised as what they are.

Cross-platform

  • Path lookups compare both sides in NFC and answer with the spelling on disk; an NFD-named module keeps its used-by edge; non-ASCII commit text arrives intact whatever i18n.logOutputEncoding says; a stamped date ages by the calendar beyond UTC+12.

Context and knowledge

  • Recall folds case and Latin, Greek and Cyrillic accents (Thai untouched), drops words most notes share from scoring (MRR 0.727 → 0.780 on title words), and rebuilds an index scrubbed by an older redactor.
  • The map honours AI-ignore files and lists the test and build commands a repository declares; chamnan-impact shows why a file last changed; chamnan-where sees __all__, entry points and Thai or differently normalised identifiers.

What we noticed on the way

  • A redaction that announced itself and missed. When a key file was read only in part, the redactor replaced the BEGIN line and printed the body under it — a <REDACTED> saying the key had been handled, over the key. Every capped reader in the package could produce that input.
  • A drift check one path could turn off. The instruction-file check asks git about every quoted path in one call, and git refuses the whole call if any path lies outside the repository. Instruction files routinely quote /var/log/… or ../shared/…, so the check reported nothing for exactly the files people maintain most.
  • The same file under two names. APFS keeps a name in the form it was created; git and the keyboard hand over the other. Each was internally consistent, and the lookup between them compared bytes.

Research

Every research finding screened for this release ends in a verdict — tested, already there, or not worth it — and the tests led to most of the fixes above. The citations from code back to rounds are in the attached INDEX_CITED_IN_CODE.md; python3 .chamnan/tools/research_citations.py --write regenerates it.

Measured and not adopted: starting hooks with python3 -S — 1.5 ms of a 120 ms hook, within noise; shipping chamnan as a single zipapp — the outside measurement found a warm zipapp 2.76× slower than a directory layout; a near-duplicate detector for notes — on a real store of a few dozen notes no pair came within reach of any published threshold; indexing notebook outputs — a 400 KB notebook's base64 never reaches the map, which lists notebooks as unindexed source.

Verification

Checks Gotcha
6746/6746 152/2,395 — 152 recorded since v1.34.0, 2,395 in total

6746/6746 on the release gate (macOS), and CI green on all five legs — macOS · Linux · Windows on Python 3.8 and 3.13 — on the same commit. The corpus gate (608 files, 98 extensions, 7 writing systems) planted credentials and found 0 in the index; redaction checks 52/52. The count went from 5,401 to 5,618 check( calls in the source: 68 sections added and three shortened by six calls, where functions that only their own tests called were removed.

Known limitations

  • The command-flag rules cover the named tools; a password passed positionally to a tool not on the list is not recognised by shape.
  • The redactor still misses a bare AWS secret access key with no name beside it (98 of 99 corpus shapes caught), and a kubeconfig token: with a random value.
  • Notebooks are listed as unindexed source; their code cells are not read.
  • Windows behaviour is verified on CI, not on a Windows machine here.

Upgrade

/plugin update chamnan. Nothing to do afterwards; a recall index built before this is rebuilt on the next chamnan-recall --reindex.

This release is about protection and context holding in the shapes text really arrives in.