Consolidate Claude Code tooling: global-settings v1.6.0, developer docs, shellcheck CI#22
Conversation
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>
- 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>
Split monolithic commands.md into domain-specific references (openspec, tender) and add new skill guides for checklists, evals, and patterns. Update testing, workflow, and writing-skills docs. Bump global settings scripts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rse-spec
The retrofit playbook walks through bringing legacy apps under hydra
ADR-008's spec ↔ code annotation convention. Apps built spec-first via
/opsx-apply get the annotations for free; apps that predate the
convention need a one-time retrofit pass.
The three skills, in order:
/opsx-coverage-scan {app} — audit only, produces coverage-report.md
/opsx-annotate {app} — applies file + method tags from Bucket 1
/opsx-reverse-spec {app} — drafts retrofit spec for a 2a/2b cluster
(--cluster=new capability,
--extend=add REQs to existing)
Playbook covers prereqs, the three-skill sequence, bucket-by-bucket
guide (1, 2a, 2b, 3a, 3b, 4), common gotchas sourced from the
opencatalogi pilot (helper methods, listener vs business logic,
Bucket 1 vs 2a tiebreaker, Nextcloud appinfo/ specifics,
.git-blame-ignore-revs config), and roll-out order across the 11 PHP
apps + ExApp Python wrappers.
Referenced from:
- hydra/openspec/architecture/adr-008-testing.md (rule definition)
- hydra/.claude/skills/opsx-{coverage-scan,annotate,reverse-spec}/SKILL.md
- hydra/CLAUDE.md (Skills Overview "Retrofit" line)
…llcheck CI - Simplify install/update docs for global Claude settings - Enhance usage tracker with calibration support and improved logging - Add shellcheck GitHub Actions workflow - Update .gitignore for usage tracker runtime files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ADME, dedupe docs - Extract Workstation Setup and prerequisites from docs/claude/README.md into new docs/claude/workstation-setup.md (258 lines); cuts main README from 901 to 601 lines (-33%) - Slim ADR section to brief intro + link to writing-adrs.md - Slim Personas section to brief intro + link to testing.md - Fix sudo npm install -g in local-llm.md (avoid running package scripts as root); add note on user-level npm prefix / npx - Fix "full day of normal usage" → "full session (~5h rolling window)" in parallel-agents.md (session is rolling, not daily) - Add "Security model — defense in depth" section to global-settings/README.md documenting the three protection layers (deny-list, hook, chmod) - Merge usage-tracker/QUICKSTART.md into README.md: add Understanding the Status Bar table + "No ~/.claude/projects/ directory" troubleshooting row; delete QUICKSTART.md (all content preserved) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-guides feat: Add settings-repo-ref tracking, harden write blocks, and expand developer guides
…st harness - Pin canonical gh-api source check to the literal `repos/ConductionNL/.github/contents/global-settings/` prefix so the canonical string cannot be smuggled via headers, query params, or pipeline segments. - Require `-c` for the eval/bash/sh write rule so `.sh` filenames no longer false-positive via the `\bsh\b` word boundary (e.g. `diff a/foo.sh b/foo.sh`). - Use command-segment boundary for the cp/mv rule so chained invocations like `foo && cp … ~/.claude/settings.json` are caught. - Add a wget/curl/dd direct-write guard (rule #7) for tools that write via flag rather than redirect. - Drop `settings-repo-path` from the unlock command — it was never rewritten during an update and was left writable after every unlock. - Update the CONTRACT text in check-settings-version.sh to match the tightened gh-api prefix check. - Add tests/test-block-write-commands.sh with combinatorial coverage of attack vectors × path variants × chain prefixes. - Normalize hook script mode to 755 for consistency. - Bump VERSION 1.5.3 → 1.6.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ttings-improvements # Conflicts: # .gitattributes
…s/global-claude-settings-improvements
- Move retrofit commands into commands-openspec.md and keep /sync-docs in commands.md (general section) - Update retrofit playbook for ADR-003 §Spec traceability (from ADR-008), ghost-change model, and sync_spec_content.py - Restructure top-level README.md with a directory-purpose table and clearer entry points - Add anti-pattern preservation guidance to writing-docs.md (load-bearing "why" notes shouldn't be stripped) - Add writing-adrs / writing-skills rows to the Source-of-Truth table; drop stale hydra ADR index row - Cross-link the retrofit playbook from workflow.md and app-lifecycle.md for legacy apps Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Document how SKILL.md file paths resolve against Claude's CWD at invocation, with a canonical-path table per target location and an authoring checklist to catch workspace-sensitive drift. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolve 11 ShellCheck findings (mix of info/warning) so the PR passes the shellcheck.yml CI gate introduced on this branch: - block-write-commands.sh: SC2016 disable for sed backreference regex (must be single-quoted; \& is sed syntax, not a shell variable). - check-settings-version.sh: convert 4 'echo "\\n"' lines to printf for portable-shell compliance (SC2028). - tests/test-block-write-commands.sh: file-level disable for SC2016/SC2088 — the harness intentionally feeds literal \$VAR/~ tokens to the hook as test fixtures. Drop unused HOMES_BARE array (SC2034). Verified: all 7073 hook tests still pass (94 allow, 6979 deny).
Documents the /review-pr skill (usage, strictness modes, inline comment flow) in commands.md and testing.md. Tightens the L5 auto-detection description in writing-skills.md to call out that both grading.json and timing.json must be present under evals/, and that timing.json is evidence of actual skill execution via the eval runner. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Updates writing-specs.md to use REQ-NNN identifiers (dropping the
{AREA} segment from the heading format) and adds a new
'Cross-Referencing Requirements' section with a table showing how to
reference requirements from tasks.md, other specs, PRs, and PHPDoc tags.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d fix jq iterator - Remove wordpress-docker-specific references in README and playwright-setup; use generic workspace descriptions instead - Update skill-evals: document new 3-way merge update mechanism (replaces local-mods.patch), workspace rotation/archiving rules, and notable-detection/dedup logic - Add scripts/ subfolder convention to writing-skills directory layout - Fix jq content[]? iterator in block-write-commands.sh to handle non-array content Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ttings-improvements
CRLF blobs arrived via origin/main merge; .gitattributes already enforces eol=lf for *.svg so normalize the index entries. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ush-auth script - README.md: update artifact diagram (specs/*.md) and add workstation-setup.md to tree - getting-started.md: link to workstation-setup.md for new machine setup - workflow.md: correct "Three optional" → "Four optional" artifacts - writing-specs.md: add CRITICAL callout that scenario headings must use #### (4 hashes) - commands.md: include global-claude-settings.md in sync-docs dev docs file list - docker.md / testing.md: add cross-links to playwright-setup.md - block-write-commands.sh: fix git_push_authorized() to read full last user message (previously only checked the last line of the last text block, so multi-line messages with the auth phrase on a non-final line were incorrectly rejected) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1434a1f to
e581646
Compare
|
The static settings.json deny pattern is a prefix match; verified locally against the hook, none of the following trigger any block:
Same evasion shape that Suggestion: move install-gating into the hook itself, mirroring the existing
This also ports cleanly to other package managers without growing the static deny list further. |
|
Docs review — accuracy + xref passPass over 1.
|
| Source | Authorized phrases |
|---|---|
Hook (global-settings/block-write-commands.sh:38) |
push for me · commit and push · please git push · push my changes |
Docs (docs/claude/global-claude-settings.md:211) |
push for me · commit and push · please push · push my changes |
A developer who reads the docs and types "please push" gets blocked. A developer who reads the hook's deny message gets the right phrase. Pick one — the hook's deny message (which references "please git push" verbatim) is the source of truth, so the docs should be updated.
2. Broken anchor in the onboarding flow
docs/claude/getting-started.md:56:
[main README](../../README.md#4-install-vs-code-extensions)The root README.md has 5 H2 headings, none of them 4-install-vs-code-extensions. The heading actually exists in docs/claude/workstation-setup.md:38 (### 4. Install VS Code Extensions). Fix: link to ./workstation-setup.md#4-install-vs-code-extensions.
3. ⚠️ Overstated security claim — gives a false sense of robustness
docs/claude/global-claude-settings.md:209:
All guards use
(^|[;&|]\s*)cmd\bpatterns to catch commands both at the start of a line and when chained via&&,;, or||.
This is not actually true for the canonical-source check at block-write-commands.sh:153, which is the guard most relevant to security. That check uses substring-anywhere matching (grep -qE with no segment anchor) — exactly the gap demonstrated in the bypass writeup elsewhere on this PR.
Either:
- soften the claim ("most guards use…"), or
- (preferred) tighten the canonical check so the universal claim becomes true.
The current text leads readers to under-estimate the attack surface they should test against.
Cosmetic / render issues
4. skill-patterns.md — links to paths that don't exist in this repo
| Line | Link target | Resolves to |
|---|---|---|
| 43, 155 | [templates/architecture-template.md](templates/architecture-template.md) |
docs/claude/templates/… (does not exist) |
| 60, 156 | [references/dutch-gov-backend-standards.md](references/dutch-gov-backend-standards.md) |
docs/claude/references/… (does not exist) |
| 76, 157 | [examples/output-templates.md](examples/output-templates.md) |
docs/claude/examples/… (does not exist) |
| 177 | [learnings.md](learnings.md) |
docs/claude/learnings.md (does not exist) |
The author seems to mean "inside your skill's folder" (relative to .claude/skills/<skill>/), not relative to the doc's directory. As written, every renderer (GitHub, IDE preview, Docusaurus) treats them as real links and 404s. Fix: switch to inline code — `templates/architecture-template.md` — instead of links.
5. Placeholder syntax rendered as live links
docs/claude/writing-specs.md:265shows an example of cross-spec reference syntax that renders as a live link to nowhere:[archival-destruction-workflow#REQ-006](../archival-destruction-workflow/spec.md#req-006-legal-hold-management).docs/claude/writing-docs.md:520:See [X](path/to/file.md).— literal template syntax presented as a live link.
Both should be in fenced code blocks, not inline markdown.
Inconsistencies / observations
6. Node.js version conflict
docs/claude/getting-started.md:11: prerequisite is Node.js 20+ (required by OpenSpec CLI)..github/workflows/release.yml:23:workflow_calldefault isnode-version: "18".
The release input is overrideable per-caller, but a fresh contributor reading the prerequisites and then hitting an 18-default release will be confused. Either bump the workflow default, or note the pinned 18 in getting-started.
7. Ghost file: exapp-sidecar-status.md
It appears in gh pr diff --name-only and the PR description ("exapp-sidecar status"), but it is not present in docs/claude/ at PR head — added then removed within the PR. If intentional, the PR body should drop the mention.
8. Broad settings.local.json bootstrap recommendation
docs/claude/README.md:357-360 recommends bootstrapping with allow-list entries like:
"Bash(bash:*)", "Bash(rm:*)", "Bash(curl:*)", ...Not a security hole on its own — the global deny on rm -rf and the hook still cover the worst cases — but Bash(rm:*) auto-approves single-file rm without any prompt, and Bash(bash:*) opens up bash -c-style indirection. For a copy-paste-bootstrap audience, this is a higher-trust default than the rest of the doc set implies. Worth either narrowing the suggestion (e.g. drop bash:* and rm:*) or adding a "review before keeping" note.
|
Comment 1 — npm install guard gaps: - Remove inadequate static `Bash(npm install:*)` deny from settings.json - Add word-boundary hook guard covering npm install/i/add, pnpm, yarn, bun (catches chained variants like `cd subdir && npm install`); npm ci excluded Comment 2 — canonical-source bypass (two compounding bugs): - Fix 1: decoy protection on gh api canonical check — reject if any non-canonical gh api call appears alongside the canonical one - Fix 2: remove global /dev/null suppression from redirect guard; /dev/null already excluded by [^[:space:]&>/] so the second condition was redundant and silenced the guard for other redirects in the same cmd Test harness: - Add TESTS_ASK category with run_hook_ask() (verifies exit 0 + ask JSON) - 13 new ASK fixtures: all npm/pnpm/yarn/bun install forms + /dev/null decoy - 14 new DENY fixtures: canonical decoy attack (2 variants × 7 protected files) - 2 new ALLOW fixtures: npm ci, npm ci --ignore-scripts - Total: 7073 → 7102 (all pass) Comment 3 — docs accuracy and cross-reference fixes: - global-claude-settings.md: fix push phrase (please push → please git push); update "All guards use" claim to accurately describe the canonical check - getting-started.md: fix broken anchor (README.md#4 → workstation-setup.md) - skill-patterns.md: convert 7 broken markdown links to inline code - release.yml: bump default node-version 18 → 20 (matches documented prereq) - README.md: add "review before keeping" note on broad bootstrap allow-list Comment 4 — usage-tracker bugs: - _should_notify: reset last_notification on weekly window rollover so 25/50/75% thresholds fire again in each new week - usage-api-cache.json: chmod 0o600 after write (org-scoped OAuth data) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Review comments addressedAll four review comments have been resolved in this branch. Comment 1 — Package manager install guardAdded a hook guard that intercepts Removed Comment 2 — Canonical-source bypass attack (two bugs)Bug 1 — substring-anywhere Bug 2 — Comment 3 — Usage tracker bugs (both repos)Weekly reset watermark not clearing: When a new billing week starts, Cache file permissions: After writing OAuth-sourced cost data to the cache file, Comment 4 — Documentation and cosmetic fixes
All fixes applied to both |
Took origin/main's expanded retrofit playbook (from PR #36): updated title, ghost changes section, relative skill links, procest as testbed example, Bucket 2 un-spec'd methods table, and revised roll-out order. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…olution Restores six items from the branch version that were dropped when the merge conflict was resolved in favour of origin/main wholesale: - Prerequisites: skills auto-create a retrofit/… feature branch - Scan output: annotated + plumbing meta-buckets described - Annotate idempotency: skill prompts to reuse or recreate a ghost change - Reverse-spec: /opsx-ff invocation to fill design.md, full script path - Specter sync: error-handling note (don't leave spec in-tree but missing from Specter) - Specter sync: column semantics for retrofit vs retrofit_extensions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Verification — fixes look correct, two harness issues to addressPulled ✅ Per-claim verification:
Two issues that relativize the "7102/7102 pass" claim1. Test harness hardcodes
|
Replace hardcoded /home/wilco with TEST_HOME (defaults to \$HOME) and TEST_REPO_DIR (defaults to \$TEST_HOME/.github) so the 7102 fixtures align with the hook's protected-path regex on any machine. Add .github/workflows/hook-tests.yml to run the harness in CI on every PR/push that touches global-settings/**. The workflow seeds \$HOME/.claude/settings-repo-path with \$GITHUB_WORKSPACE so the git-show ALLOW fixtures also pass in the runner environment. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Harness portability + CI gate — addressed in 6156359Both follow-up issues from the verification pass are fixed. 1. Test harness portability
2. CI gateAdded
The minor doc-clarity nit on Ready for merge from my side. |
…ntain permissions' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Summary
This PR brings forward the full body of work from
feature/claude-code-tooling(which originally landed as PR #13 but received 8 additional commits that never reached main) plus the newdocs/global-claude-settings-improvementswork. The net effect onmain:v1.4.0→v1.6.0— tightensblock-write-commands.shhook guards, drops unused unlock path, addssettings-repo-ref/settings-repo-urlconfig, and introduces a 7073-case test harness (tests/test-block-write-commands.sh) that exercises the protected-path regex against combinatorial attack fixtures.docs/claude/— getting-started, workflow, skill-patterns, skill-checklist, writing-skills/-specs/-adrs/-docs, retrofit playbook, parallel-agents, Playwright setup, exapp-sidecar status, and separate command references for OpenSpec / Tender flows. Includes workstation-setup refs, scenario heading warning, generalized workspace examples, expanded skill-evals archiving, and push-auth script fix.writing-skills.md..github/workflows/shellcheck.ymlrunsludeeus/action-shellcheck@2.0.0on every PR that touches.shfiles.claude-usage-tracker.py./review-prcommand documented; L5 eval requirements clarified in skill guides..gitattributesfor LF normalization,.gitignore).Once this PR merges,
feature/claude-code-toolingbecomes fully contained inmainand can be deleted (planned as a follow-up).Checks
global-settings/VERSIONcorrectly bumped 1.4.0 → 1.6.0Test plan
docs/claude/layout for duplication / broken cross-refsglobal-settingsversion viacheck-settings-version.shbanner on next Claude Code session