claudemd-cli 0.9.5 → 0.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/README.md +103 -95
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,35 @@ All notable changes to the `claudemd` plugin. This changelog tracks plugin artif
|
|
|
8
8
|
- **Canonical spec version source**: `spec/CLAUDE.md` top-line title (`# AI-CODING-SPEC vX.Y.Z — Core`) + `spec/CLAUDE-changelog.md` top `##` entry.
|
|
9
9
|
- **Plugin semver vs spec semver** are independent: plugin patch (0.2.0 → 0.2.1) may ship when spec is unchanged (this release); plugin minor (0.1.9 → 0.2.0) ships when spec minor updates (v0.2.0 shipped spec v6.10.0).
|
|
10
10
|
|
|
11
|
+
## [0.9.6] - 2026-05-10
|
|
12
|
+
|
|
13
|
+
**Patch — defensive hardening + test coverage gap closure.** Spec unchanged (still v6.11.7); plugin-only patch. Triggered by an audit pass that found `scripts/hard-rules-audit.js` had zero test coverage and no error context on `JSON.parse` failure, plus `hooks/session-start-check.sh` embedded the upstream tag in a banner without a strict semver gate. Three small changes; no behavior change for users on the green path.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- `[fix]` **`hard-rules-audit.js` opaque error on broken / missing `spec/hard-rules.json`** — pre-fix: `JSON.parse(fs.readFileSync(manifestPath, 'utf8'))` at L21 surfaced bare `ENOENT` / `SyntaxError` with no path context, leaving the operator to guess which file broke. Post-fix: try/catch wraps the parse, throws `hard-rules-audit: failed to load <path>: <reason>`; an additional shape-check (`Array.isArray(manifest.rules)`) throws `hard-rules-audit: <path> missing required 'rules' array` when the JSON is valid but the manifest body is wrong.
|
|
18
|
+
- `[fix]` **`session-start-check.sh` lacked semver gate before embedding `remote_tag` in `additionalContext`** — pre-fix: `jq --arg new "$remote_tag"` already safe-quotes the value, so JSON injection wasn't reachable, but a malformed remote tag (newline-injected, exotic glyphs from a compromised mirror) would still produce a confusing upgrade banner. Post-fix: a `[[ "$remote_tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || return 0` gate after `head -1 | awk | sed`. Defense-in-depth, not a fix to a live exploit.
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- `[test]` **`tests/scripts/hard-rules-audit.test.js` — 6 cases, 0 → 6 coverage**: (1) byte-exact production fixture (reads real `spec/hard-rules.json` per project memory `feedback_test_fixture_format_drift` — locks against test/impl drift), (2) missing manifest path → error names the file, (3) malformed JSON → error names the file, (4) JSON valid but `rules` array missing → error explains what's missing, (5) cross-ref of `rule_hits_section` to live log rows (verifies `§10-V` deny rows reach `§10-specificity.hits.deny`), (6) `demoteCandidates` correctly excludes self-enforced rules (avoids false-positive `§iron-law-2` demotion suggestion). All 6 pass; total Node test count 211 → 217.
|
|
23
|
+
|
|
24
|
+
### Versioning
|
|
25
|
+
|
|
26
|
+
- `package.json` 0.9.5 → **0.9.6** (npm).
|
|
27
|
+
- `.claude-plugin/plugin.json` 0.9.5 → **0.9.6**.
|
|
28
|
+
- `.claude-plugin/marketplace.json` two version fields 0.9.5 → **0.9.6**.
|
|
29
|
+
- Spec headers unchanged (v6.11.7 still current); no `spec/CLAUDE-changelog.md` entry — plugin-only patch.
|
|
30
|
+
|
|
31
|
+
### Validation
|
|
32
|
+
|
|
33
|
+
- `node --test tests/scripts/*.test.js` → 217 passed (211 prior + 6 new), 0 failed.
|
|
34
|
+
- `bash hooks/session-start-check.sh < /dev/null` → exit 0; banner emitted as expected; semver gate not exercised on green path (operator-side smoke).
|
|
35
|
+
- Verification log of why three of four originally suspected HIGH hook bugs turned out to be false positives recorded in this session's audit transcript:
|
|
36
|
+
- `sandbox-disposal-check.sh` printf `\x1e` — `printf '/tmp|claudemd_only\x1e%s|both' "$HOME"` produces 1 RS byte; `read -d $'\x1e'` correctly splits into 2 specs.
|
|
37
|
+
- `pre-bash-safety-check.sh` heredoc terminator — bash itself treats `EOF # comment` as heredoc body (not terminator), so the regex matching this behavior is correct, not a bypass.
|
|
38
|
+
- `banned-vocab-check.sh` baseline regex — `code→123ms` and `code → 123ms` both correctly fail the `[0-9].*(→|->|=>).*[0-9]` test (left side requires a number); previously-claimed asymmetry doesn't exist.
|
|
39
|
+
|
|
11
40
|
## [0.9.5] - 2026-05-10
|
|
12
41
|
|
|
13
42
|
**Patch — `mem-audit.sh` hotfix (3 bugs introduced in v0.9.4).** Spec unchanged (still v6.11.7); plugin-only patch. The new Stop hook shipped in v0.9.4 silently failed validation on every Stop event ("Hook JSON output validation failed — Invalid input") and produced false-positive missing-marker warnings on legitimate memories. v0.9.5 fixes all three issues and adds `tests/hooks/mem-audit.test.sh` (9/9 cases) to lock them down.
|
package/README.md
CHANGED
|
@@ -1,23 +1,42 @@
|
|
|
1
1
|
# claudemd
|
|
2
2
|
|
|
3
|
-
Claude Code plugin that enforces **AI-CODING-SPEC v6.11 HARD rules** through shell hooks and ships the spec as part of the plugin.
|
|
3
|
+
> Claude Code plugin that enforces **AI-CODING-SPEC v6.11 HARD rules** through shell hooks — and ships the spec itself as part of the plugin.
|
|
4
4
|
|
|
5
|
+
[](https://github.com/sdsrss/claudemd/actions/workflows/ci.yml)
|
|
6
|
+
[](https://www.npmjs.com/package/claudemd-cli)
|
|
5
7
|
[](LICENSE)
|
|
6
8
|
|
|
9
|
+
claudemd plugs into the Claude Code hook system to **block commits, pushes, and bash commands** that violate AI-CODING-SPEC v6.11 — banned vocabulary in commit messages, `rm -rf $VAR` without variable validation, ship-on-red-CI, unread `MEMORY.md` entries during release flows, and more. The spec itself (`CLAUDE.md` + `CLAUDE-extended.md` + `CLAUDE-changelog.md`) ships with the plugin and installs into `~/.claude/`, so the rules Claude Code reads at session start match the rules the hooks enforce.
|
|
10
|
+
|
|
11
|
+
A standalone CLI (`npx claudemd-cli`) reuses the same `banned-vocab.patterns` source for git pre-commit hooks, GitHub Actions, and other agents that don't run inside Claude Code.
|
|
12
|
+
|
|
7
13
|
---
|
|
8
14
|
|
|
9
|
-
##
|
|
15
|
+
## Quick start
|
|
10
16
|
|
|
11
|
-
|
|
12
|
-
|---|---|
|
|
13
|
-
| 11 shell hooks | `banned-vocab-check` · `pre-bash-safety-check` · `ship-baseline-check` · `residue-audit` · `memory-read-check` · `sandbox-disposal-check` · `session-start-check` · `session-summary` · `transcript-vocab-scan` · `version-sync` · `mem-audit` (v0.9.4) |
|
|
14
|
-
| 9 slash commands | `/claudemd-status` · `/claudemd-update` · `/claudemd-audit` · `/claudemd-toggle` · `/claudemd-doctor` · `/claudemd-uninstall` · `/claudemd-rules` · `/claudemd-clean-residue` · `/claudemd-sparkline` |
|
|
15
|
-
| 1 standalone CLI | `claudemd-cli lint` · `claudemd-cli audit` (v0.9.0+ — for git pre-commit / CI / cross-agent use; npm package: [`claudemd-cli`](https://www.npmjs.com/package/claudemd-cli); same `banned-vocab.patterns` source as the in-CC hook) |
|
|
16
|
-
| Spec v6.11.7 | `~/.claude/CLAUDE.md` · `CLAUDE-extended.md` · `CLAUDE-changelog.md` (backup-before-overwrite) |
|
|
17
|
+
Run **both** slash commands inside Claude Code:
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
```
|
|
20
|
+
/plugin marketplace add sdsrss/claudemd
|
|
21
|
+
/plugin install claudemd@claudemd
|
|
22
|
+
```
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
Then verify on your next session:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
/claudemd-status
|
|
28
|
+
/claudemd-doctor
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`status` reports plugin version, shipped vs installed spec version, kill-switch state, and rule-hits row count. `doctor` runs 9+ health checks with `[✓] / [△] / [✗]` markers.
|
|
32
|
+
|
|
33
|
+
The spec-file copy into `~/.claude/` runs from the `SessionStart` hook on the next session. To install in the **current** session, run the script directly (find `<version>` with `ls ~/.claude/plugins/cache/claudemd/claudemd/ | sort -V | tail -1`):
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
node ~/.claude/plugins/cache/claudemd/claudemd/<version>/scripts/install.js
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
> ⚠️ **`~/.claude/CLAUDE.md` is shared real estate.** Claude Code reads this file as your user-global instructions across every project. If you've hand-written personal instructions there (`Always reply in 中文`, `My name is X`, etc.), install moves your existing files to `~/.claude/backup-<ISO>/` (last 5 kept automatically) before writing the spec. Since v0.5.3, install prints a `[claudemd] WARN: …` line to stderr when the existing file does not look like a claudemd spec. To bring your personal instructions back on uninstall, run `CLAUDEMD_SPEC_ACTION=restore /claudemd-uninstall`.
|
|
21
40
|
|
|
22
41
|
---
|
|
23
42
|
|
|
@@ -35,57 +54,45 @@ Verify in one command (Linux): `node --version && jq --version && gh --version &
|
|
|
35
54
|
|
|
36
55
|
---
|
|
37
56
|
|
|
38
|
-
##
|
|
39
|
-
|
|
40
|
-
Run **both** slash commands inside Claude Code. First registers the GitHub marketplace, second installs the plugin:
|
|
41
|
-
|
|
42
|
-
```
|
|
43
|
-
/plugin marketplace add sdsrss/claudemd
|
|
44
|
-
/plugin install claudemd@claudemd
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
That's it for normal use. The plugin's own `hooks/hooks.json` is registered by Claude Code immediately, and the `SessionStart` hook bootstraps `install.js` in the background on your **next** Claude Code session — copying `spec/CLAUDE*.md` into `~/.claude/` (backup-before-overwrite) and writing the install manifest. Verify with `/claudemd-status` after the next session.
|
|
57
|
+
## What it installs
|
|
48
58
|
|
|
49
|
-
|
|
59
|
+
| Layer | Contents |
|
|
60
|
+
|---|---|
|
|
61
|
+
| 11 shell hooks | `banned-vocab-check` · `pre-bash-safety-check` · `ship-baseline-check` · `residue-audit` · `memory-read-check` · `sandbox-disposal-check` · `session-start-check` · `session-summary` · `transcript-vocab-scan` · `version-sync` · `mem-audit` |
|
|
62
|
+
| 9 slash commands | `/claudemd-status` · `/claudemd-update` · `/claudemd-audit` · `/claudemd-toggle` · `/claudemd-doctor` · `/claudemd-uninstall` · `/claudemd-rules` · `/claudemd-clean-residue` · `/claudemd-sparkline` |
|
|
63
|
+
| 1 standalone CLI | `claudemd-cli lint` · `claudemd-cli audit` ([npm: `claudemd-cli`](https://www.npmjs.com/package/claudemd-cli)) |
|
|
64
|
+
| Spec v6.11.7 | `~/.claude/CLAUDE.md` · `CLAUDE-extended.md` · `CLAUDE-changelog.md` (backup-before-overwrite) |
|
|
50
65
|
|
|
51
|
-
|
|
52
|
-
node ~/.claude/plugins/cache/claudemd/claudemd/<version>/scripts/install.js
|
|
53
|
-
```
|
|
66
|
+
Install moves any existing `~/.claude/CLAUDE*.md` to `~/.claude/backup-<ISO>/` (last 5 kept automatically). Uninstall offers `keep / restore / delete`; `delete` requires an extra confirmation.
|
|
54
67
|
|
|
55
68
|
> Since v0.1.5, hook registration lives in the plugin's own `hooks/hooks.json` — the Claude Code harness expands `${CLAUDE_PLUGIN_ROOT}` there automatically on every invocation, so hooks track the active plugin version without manual re-registration. `install.js`'s remaining jobs are (1) copy `spec/CLAUDE*.md` into `~/.claude/` (with backup-before-overwrite), (2) evict any legacy claudemd hook entries from prior installs (≤0.1.1 absolute-path form, 0.1.2-0.1.4 `${CLAUDE_PLUGIN_ROOT}`-in-settings.json form), and (3) write the installed manifest. It never touches other-plugin hooks. Claude Code's plugin-lifecycle `postInstall` field is not honored, so the script runs from `SessionStart` instead.
|
|
56
69
|
|
|
57
|
-
### Verify
|
|
58
|
-
|
|
59
|
-
```
|
|
60
|
-
/claudemd-status
|
|
61
|
-
/claudemd-doctor
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
`status` reports plugin version, shipped vs installed spec version, kill-switch state, and rule-hits row count. `doctor` runs 9+ health checks with `[✓] / [△] / [✗]` markers.
|
|
65
|
-
|
|
66
70
|
---
|
|
67
71
|
|
|
68
|
-
##
|
|
72
|
+
## Hooks (what fires when)
|
|
69
73
|
|
|
70
|
-
Once installed,
|
|
74
|
+
Once installed, hooks run silently in the background. Verbose log: `~/.claude/logs/claudemd.jsonl` (one row per hook decision). Aggregate via `/claudemd-audit`.
|
|
71
75
|
|
|
72
76
|
| Trigger | Hook | What happens |
|
|
73
77
|
|---|---|---|
|
|
74
|
-
| `git commit` with banned vocab (e.g. `significantly`, `70% faster`, `should work`) | `banned-vocab-check` | Blocks the commit with a message pointing to §10-V spec rule. |
|
|
78
|
+
| `git commit` with banned vocab (e.g. `significantly`, `70% faster`, `should work`) | `banned-vocab-check` | Blocks the commit with a message pointing to the §10-V spec rule. |
|
|
75
79
|
| Bash command with `rm -rf $VAR` (unvalidated expansion) or unpinned `npx <pkg>` | `pre-bash-safety-check` (v0.5.0+) | Blocks at PreToolUse:Bash per §8 SAFETY. Bypass via `[allow-rm-rf-var]` / `[allow-npx-unpinned]` token in the command, or pin/validate the variable. |
|
|
76
80
|
| `git push` while base-branch CI is red | `ship-baseline-check` | Blocks the push (2-second `gh run list` timeout; fail-open if `gh` absent or times out). |
|
|
77
|
-
| Session end with `~/.claude/tmp/` growth > 20 entries | `residue-audit` | Advisory stderr warning; never blocks. |
|
|
78
81
|
| Bash command matching ship/push/deploy/release with an unread matched `MEMORY.md` entry | `memory-read-check` | Blocks the command with a list of memory files to Read first. |
|
|
82
|
+
| Session end with `~/.claude/tmp/` growth > 20 entries | `residue-audit` | Advisory stderr warning; never blocks. |
|
|
79
83
|
| Session end with fresh `tmp.XXXXXX`-style directories | `sandbox-disposal-check` | Advisory stderr warning. |
|
|
80
|
-
|
|
|
81
|
-
|
|
|
84
|
+
| Stop event with `Why:`-less hard-rule citations in the assistant turn | `mem-audit` (v0.9.4+) | Detects spec-citation patterns missing the `Why:` rationale token; advisory log. |
|
|
85
|
+
| Session end | `session-summary` (v0.8.0+) | Writes `~/.claude/.claudemd-state/last-session-summary.json`; banner emit at next `SessionStart`. |
|
|
86
|
+
| New session start with GitHub remote tag newer than local cache max version | `session-start-check` (v0.4.0+) | Injects an "upgrade available" banner via `additionalContext`. Rate-limited to once per 24h via `~/.claude/.claudemd-state/upstream-check.lastrun` sentinel. 3-second `git ls-remote` timeout, fail-open. |
|
|
87
|
+
| First `UserPromptSubmit` after a mid-session `/plugin install` upgrade | `version-sync` (v0.3.1+) | Backgrounds `install.js` once per session when the manifest version diverges from the active plugin's `package.json`. Sentinel-gated; fail-open. |
|
|
88
|
+
| `PostToolUse` after assistant text containing banned vocab | `transcript-vocab-scan` | Advisory; logs to rule-hits without blocking. |
|
|
82
89
|
|
|
83
|
-
|
|
90
|
+
## Commands
|
|
84
91
|
|
|
85
92
|
| Command | Purpose |
|
|
86
93
|
|---|---|
|
|
87
94
|
| `/claudemd-status` | Plugin version + spec version + kill-switch state + logs line count. |
|
|
88
|
-
| `/claudemd-update` | Interactive diff against plugin-shipped spec, then apply-all or cancel (spec trio is lockstep — per-file select would
|
|
95
|
+
| `/claudemd-update` | Interactive diff against plugin-shipped spec, then apply-all or cancel (spec trio is lockstep — per-file select would dangle §EXT cross-references). |
|
|
89
96
|
| `/claudemd-audit [--days N]` | Aggregate rule-hits over last N days (default 30). Top banned-vocab patterns, per-hook deny counts. |
|
|
90
97
|
| `/claudemd-toggle <hook-name>` | Enable/disable a specific hook by toggling `DISABLE_*_HOOK` in `settings.json` env. |
|
|
91
98
|
| `/claudemd-doctor [--prune-backups=N]` | Health checks; optionally prune `~/.claude/backup-*` dirs older than N. v0.7.1+ also flags rule sections whose bypass:deny ratio > 50% (R-N6 §0.1 demotion candidates). |
|
|
@@ -96,20 +103,20 @@ Once installed, the hooks run silently in the background:
|
|
|
96
103
|
|
|
97
104
|
---
|
|
98
105
|
|
|
99
|
-
## Standalone CLI
|
|
106
|
+
## Standalone CLI
|
|
100
107
|
|
|
101
|
-
The same `banned-vocab.patterns` source the in-CC hook uses is also exposed as a
|
|
108
|
+
The same `banned-vocab.patterns` source the in-CC hook uses is also exposed as a Node CLI for **git pre-commit hooks, GitHub Actions, and other agents** (Codex, Cursor, OpenClaw) — anywhere outside the Claude Code process.
|
|
102
109
|
|
|
103
110
|
```bash
|
|
104
|
-
# Dev mode (this repo, before npm publish):
|
|
105
|
-
node bin/claudemd-lint.js lint "your commit message here"
|
|
106
|
-
node bin/claudemd-lint.js audit ~/.claude/projects/<encoded>/<session>.jsonl
|
|
107
|
-
|
|
108
111
|
# After npm publish (operator-driven, not part of plugin install):
|
|
109
112
|
npx claudemd-cli lint "your commit message here"
|
|
110
113
|
npx claudemd-cli lint --stdin < message.txt
|
|
111
|
-
npx claudemd-cli audit
|
|
114
|
+
npx claudemd-cli audit ~/.claude/projects/<encoded>/<session>.jsonl
|
|
112
115
|
npx claudemd-cli audit transcript.jsonl --json
|
|
116
|
+
|
|
117
|
+
# Dev mode (this repo, before npm publish):
|
|
118
|
+
node bin/claudemd-lint.js lint "your commit message here"
|
|
119
|
+
node bin/claudemd-lint.js audit ~/.claude/projects/<encoded>/<session>.jsonl
|
|
113
120
|
```
|
|
114
121
|
|
|
115
122
|
| Subcommand | Purpose |
|
|
@@ -120,6 +127,7 @@ npx claudemd-cli audit transcript.jsonl --json
|
|
|
120
127
|
| `--version` / `--help` | Standard. |
|
|
121
128
|
|
|
122
129
|
**Pre-commit example (`.git/hooks/commit-msg`)**:
|
|
130
|
+
|
|
123
131
|
```bash
|
|
124
132
|
#!/usr/bin/env bash
|
|
125
133
|
npx claudemd-cli lint --stdin < "$1" || exit 1
|
|
@@ -129,17 +137,17 @@ The CLI does NOT depend on `~/.claude/` state — pure stateless input → stdou
|
|
|
129
137
|
|
|
130
138
|
---
|
|
131
139
|
|
|
132
|
-
## Kill-switches
|
|
140
|
+
## Kill-switches
|
|
133
141
|
|
|
134
|
-
All visible in `/claudemd-status`.
|
|
142
|
+
All visible in `/claudemd-status`. Three tiers:
|
|
135
143
|
|
|
136
|
-
**1. Plugin-wide.**
|
|
144
|
+
**1. Plugin-wide.** Short-circuits every hook before any logic runs:
|
|
137
145
|
|
|
138
146
|
```bash
|
|
139
147
|
export DISABLE_CLAUDEMD_HOOKS=1
|
|
140
148
|
```
|
|
141
149
|
|
|
142
|
-
**2. Per-hook.** Disable one
|
|
150
|
+
**2. Per-hook.** Disable one, leave others active:
|
|
143
151
|
|
|
144
152
|
```bash
|
|
145
153
|
export DISABLE_BANNED_VOCAB_HOOK=1 # or
|
|
@@ -149,8 +157,8 @@ export DISABLE_RESIDUE_AUDIT_HOOK=1 # or
|
|
|
149
157
|
export DISABLE_MEMORY_READ_HOOK=1 # or
|
|
150
158
|
export DISABLE_SANDBOX_DISPOSAL_HOOK=1 # or
|
|
151
159
|
export DISABLE_SESSION_START_HOOK=1 # or
|
|
152
|
-
export DISABLE_SESSION_SUMMARY_HOOK=1 #
|
|
153
|
-
export DISABLE_USER_PROMPT_SUBMIT_HOOK=1
|
|
160
|
+
export DISABLE_SESSION_SUMMARY_HOOK=1 # v0.8.0+ — Stop hook writing summary
|
|
161
|
+
export DISABLE_USER_PROMPT_SUBMIT_HOOK=1 # transcript-vocab-scan
|
|
154
162
|
```
|
|
155
163
|
|
|
156
164
|
**2a. Per-sub-feature** (v0.4.0+). Sub-flags inside an enabled hook, named without the `_HOOK` suffix:
|
|
@@ -167,7 +175,7 @@ export DISABLE_SESSION_SUMMARY_BANNER=1 # v0.8.0+ — only the SessionStart b
|
|
|
167
175
|
# but no additionalContext line is injected.
|
|
168
176
|
```
|
|
169
177
|
|
|
170
|
-
**3. Per-invocation escape hatches
|
|
178
|
+
**3. Per-invocation escape hatches.** Embed in the command itself, no env var needed:
|
|
171
179
|
|
|
172
180
|
| Escape | Where | Bypasses |
|
|
173
181
|
|---|---|---|
|
|
@@ -179,9 +187,32 @@ export DISABLE_SESSION_SUMMARY_BANNER=1 # v0.8.0+ — only the SessionStart b
|
|
|
179
187
|
|
|
180
188
|
---
|
|
181
189
|
|
|
190
|
+
## Update
|
|
191
|
+
|
|
192
|
+
Claude Code has **no** `/plugin update` slash command — it's silently ignored as unrecognized. The canonical upgrade sequence is:
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
/plugin marketplace update claudemd # refresh local marketplace clone (git fetch)
|
|
196
|
+
/plugin uninstall claudemd@claudemd # remove old plugin version
|
|
197
|
+
/plugin install claudemd@claudemd # install latest from refreshed clone
|
|
198
|
+
/reload-plugins # apply changes to current session
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Or open the interactive UI via `/plugin` → **Installed** tab → select `claudemd` → follow upgrade prompts.
|
|
202
|
+
|
|
203
|
+
After the plugin upgrade, sync the shipped spec into `~/.claude/`:
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
/claudemd-update
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The command prints per-file diff summary, then prompts `apply-all` or `cancel`. Per-file select is intentionally not supported — the spec trio (`CLAUDE.md` + `CLAUDE-extended.md` + `CLAUDE-changelog.md`) evolves lockstep, and mixing versions would dangle `§EXT §X-EXT` cross-references in Core. Backup is automatic (retained to 5). `/claudemd-update` never fetches from GitHub — it only diffs the plugin-cache spec against your `~/.claude/CLAUDE*.md`. The network fetch is Claude Code's job (via `/plugin marketplace update`).
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
182
213
|
## Uninstall
|
|
183
214
|
|
|
184
|
-
|
|
215
|
+
Claude Code's marketplace lifecycle does not fire `preUninstall`, so `/plugin uninstall claudemd@claudemd` alone leaves orphan state behind (`~/.claude/.claudemd-manifest.json`, `~/.claude/.claudemd-state/`, `~/.claude/logs/claudemd.jsonl`). Use the **two-step flow**:
|
|
185
216
|
|
|
186
217
|
```
|
|
187
218
|
/claudemd-uninstall # clear manifest + state + log (plugin still installed)
|
|
@@ -197,7 +228,7 @@ Reversing the order is the orphan-state vector — `${CLAUDE_PLUGIN_ROOT}` and `
|
|
|
197
228
|
| Option | Env vars | Behavior |
|
|
198
229
|
|---|---|---|
|
|
199
230
|
| `keep` (default) | (none) | `~/.claude/CLAUDE*.md` left in place; settings.json hook entries cleared. |
|
|
200
|
-
| `restore` | `CLAUDEMD_SPEC_ACTION=restore` | Copies the most recent `~/.claude/backup-<ISO>/*.md` back to `~/.claude/`. Use this if your install-time stderr showed `[claudemd] WARN: existing ~/.claude/CLAUDE.md does not look like a claudemd spec` —
|
|
231
|
+
| `restore` | `CLAUDEMD_SPEC_ACTION=restore` | Copies the most recent `~/.claude/backup-<ISO>/*.md` back to `~/.claude/`. Use this if your install-time stderr showed `[claudemd] WARN: existing ~/.claude/CLAUDE.md does not look like a claudemd spec` — your hand-written user-global instructions are sitting in the backup waiting to be brought back. |
|
|
201
232
|
| `delete` | `CLAUDEMD_SPEC_ACTION=delete CLAUDEMD_CONFIRM=1` | Hard-AUTH: removes the three spec files. |
|
|
202
233
|
|
|
203
234
|
`CLAUDEMD_PURGE=1` (env var) on `/claudemd-uninstall` also drops `~/.claude/.claudemd-state/` and your rule-hits log.
|
|
@@ -216,34 +247,11 @@ The slash command and the script are equivalent — the slash command just suppl
|
|
|
216
247
|
|
|
217
248
|
---
|
|
218
249
|
|
|
219
|
-
## Update
|
|
220
|
-
|
|
221
|
-
Claude Code has **no** `/plugin update` slash command — it's silently ignored as unrecognized. The canonical upgrade sequence is:
|
|
222
|
-
|
|
223
|
-
```
|
|
224
|
-
/plugin marketplace update claudemd # refresh local marketplace clone (git fetch)
|
|
225
|
-
/plugin uninstall claudemd@claudemd # remove old plugin version
|
|
226
|
-
/plugin install claudemd@claudemd # install latest from refreshed clone
|
|
227
|
-
/reload-plugins # apply changes to current session
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
Or open the interactive UI via `/plugin` → **Installed** tab → select `claudemd` → follow upgrade prompts.
|
|
231
|
-
|
|
232
|
-
After the plugin upgrade, sync the shipped spec into `~/.claude/`:
|
|
233
|
-
|
|
234
|
-
```
|
|
235
|
-
/claudemd-update
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
The command prints per-file diff summary, then prompts `apply-all` or `cancel`. Per-file select is intentionally not supported — the spec trio (`CLAUDE.md` + `CLAUDE-extended.md` + `CLAUDE-changelog.md`) evolves lockstep, and mixing versions would dangle `§EXT §X-EXT` cross-references in Core. Backup is automatic (retained to 5). `/claudemd-update` never fetches from GitHub — it only diffs the plugin-cache spec against your `~/.claude/CLAUDE*.md`. The network fetch is Claude Code's job (via `/plugin marketplace update`).
|
|
239
|
-
|
|
240
|
-
---
|
|
241
|
-
|
|
242
250
|
## Troubleshooting
|
|
243
251
|
|
|
244
252
|
**`Plugin "claudemd" not found in any marketplace`** — you forgot the `/plugin marketplace add sdsrss/claudemd` step. Re-run it, then retry install.
|
|
245
253
|
|
|
246
|
-
**Hooks don't fire / `~/.claude/CLAUDE*.md` not present after install** — Claude Code's `postInstall` lifecycle is not honored, so `install.js` runs from the `SessionStart` hook on your next session, not at install time. Either start a fresh Claude Code session, or run the script manually right now (replace `<version>` with the installed version dir
|
|
254
|
+
**Hooks don't fire / `~/.claude/CLAUDE*.md` not present after install** — Claude Code's `postInstall` lifecycle is not honored, so `install.js` runs from the `SessionStart` hook on your next session, not at install time. Either start a fresh Claude Code session, or run the script manually right now (replace `<version>` with the installed version dir):
|
|
247
255
|
|
|
248
256
|
```bash
|
|
249
257
|
node ~/.claude/plugins/cache/claudemd/claudemd/<version>/scripts/install.js
|
|
@@ -251,9 +259,9 @@ node ~/.claude/plugins/cache/claudemd/claudemd/<version>/scripts/install.js
|
|
|
251
259
|
|
|
252
260
|
Verify with `/claudemd-status` — the "log.lines" count should increment after the next hook fires.
|
|
253
261
|
|
|
254
|
-
**`/plugin update claudemd` does nothing / empty stdout** — `/plugin update` is not a valid Claude Code slash command; CC silently ignores unrecognized commands. Use the canonical sequence
|
|
262
|
+
**`/plugin update claudemd` does nothing / empty stdout** — `/plugin update` is not a valid Claude Code slash command; CC silently ignores unrecognized commands. Use the canonical sequence in the [Update](#update) section: `/plugin marketplace update claudemd` → `/plugin uninstall claudemd@claudemd` → `/plugin install claudemd@claudemd` → `/reload-plugins`. If that also fails (marketplace clone refuses to refresh), manually `git -C ~/.claude/plugins/marketplaces/claudemd fetch origin main --tags && git merge --ff-only origin/main`, then `git archive v<version> | tar -x -C ~/.claude/plugins/cache/claudemd/claudemd/<version>/`, then run that version's `scripts/install.js`.
|
|
255
263
|
|
|
256
|
-
**`Hook command references ${CLAUDE_PLUGIN_ROOT} but the hook is not associated with a plugin`** (5 errors on every `Bash` tool call + every session end) — you're on claudemd 0.1.2 / 0.1.3 / 0.1.4. Those releases wrote hook commands into `~/.claude/settings.json` under the literal `${CLAUDE_PLUGIN_ROOT}` token, but the CC harness only expands that variable for hooks defined in a plugin's own `hooks/hooks.json` — never in `settings.json`. The fix is v0.1.5+, which moves hook registration into the plugin's `hooks/hooks.json` (where the token expands correctly) and evicts the stale settings.json entries on install. Upgrade via the canonical sequence in the
|
|
264
|
+
**`Hook command references ${CLAUDE_PLUGIN_ROOT} but the hook is not associated with a plugin`** (5 errors on every `Bash` tool call + every session end) — you're on claudemd 0.1.2 / 0.1.3 / 0.1.4. Those releases wrote hook commands into `~/.claude/settings.json` under the literal `${CLAUDE_PLUGIN_ROOT}` token, but the CC harness only expands that variable for hooks defined in a plugin's own `hooks/hooks.json` — never in `settings.json`. The fix is v0.1.5+, which moves hook registration into the plugin's `hooks/hooks.json` (where the token expands correctly) and evicts the stale settings.json entries on install. Upgrade via the canonical sequence in the [Update](#update) section, then restart the Claude Code session to clear the cached hook registry.
|
|
257
265
|
|
|
258
266
|
**`ship-baseline-check` silently passes on red CI** — `gh` CLI is not installed, or authentication failed. Install with `brew install gh` / `apt-get install gh` and run `gh auth login`. Check with `/claudemd-doctor` — it reports `gh: missing` if absent.
|
|
259
267
|
|
|
@@ -265,14 +273,6 @@ Verify with `/claudemd-status` — the "log.lines" count should increment after
|
|
|
265
273
|
|
|
266
274
|
---
|
|
267
275
|
|
|
268
|
-
## Extending
|
|
269
|
-
|
|
270
|
-
- **Add a 6th hook**: see `docs/ADDING-NEW-HOOK.md` for the 5-step guide (hook script + test + plugin registration + doc + version bump).
|
|
271
|
-
- **Rule-hits log schema**: see `docs/RULE-HITS-SCHEMA.md` for the JSONL row format used by `/claudemd-audit`.
|
|
272
|
-
- **Design rationale + decisions log**: `docs/superpowers/specs/2026-04-21-claudemd-plugin-design.md`.
|
|
273
|
-
|
|
274
|
-
---
|
|
275
|
-
|
|
276
276
|
## Project layout
|
|
277
277
|
|
|
278
278
|
```
|
|
@@ -280,19 +280,27 @@ claudemd/
|
|
|
280
280
|
├── .claude-plugin/
|
|
281
281
|
│ ├── plugin.json # minimal manifest (name, version, author, license, keywords)
|
|
282
282
|
│ └── marketplace.json # marketplace catalog entry
|
|
283
|
-
├── hooks/ #
|
|
283
|
+
├── hooks/ # 11 shell hooks + hooks/lib/ (hook-common, rule-hits, platform)
|
|
284
284
|
│ └── hooks.json # authoritative hook registration (v0.1.5+); CC expands ${CLAUDE_PLUGIN_ROOT} here
|
|
285
285
|
├── commands/ # 9 slash-command markdown files
|
|
286
286
|
├── bin/ # standalone CLI entrypoint (claudemd-lint.js → `npx claudemd-cli` on npmjs.org)
|
|
287
287
|
├── scripts/ # 10 Node.js management scripts + scripts/lib/ (single-source registry, lint, etc.)
|
|
288
|
-
├── spec/ # shipped v6.11.7 CLAUDE*.md trio
|
|
288
|
+
├── spec/ # shipped v6.11.7 CLAUDE*.md trio + hard-rules.json manifest
|
|
289
289
|
├── tests/ # hook shell tests + Node.js tests + integration + fixtures
|
|
290
290
|
├── docs/ # ADDING-NEW-HOOK.md + RULE-HITS-SCHEMA.md + superpowers/
|
|
291
|
-
└── .github/workflows/ci.yml
|
|
291
|
+
└── .github/workflows/ # ci.yml (ubuntu+macOS × node 20) + npm-publish.yml (tag-triggered)
|
|
292
292
|
```
|
|
293
293
|
|
|
294
294
|
---
|
|
295
295
|
|
|
296
|
+
## Extending
|
|
297
|
+
|
|
298
|
+
- **Add a new hook** — see [`docs/ADDING-NEW-HOOK.md`](docs/ADDING-NEW-HOOK.md) for the 5-step guide (hook script + test + plugin registration + doc + version bump).
|
|
299
|
+
- **Rule-hits log schema** — [`docs/RULE-HITS-SCHEMA.md`](docs/RULE-HITS-SCHEMA.md) for the JSONL row format used by `/claudemd-audit`.
|
|
300
|
+
- **Design rationale + decisions log** — [`docs/superpowers/specs/2026-04-21-claudemd-plugin-design.md`](docs/superpowers/specs/2026-04-21-claudemd-plugin-design.md).
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
296
304
|
## License
|
|
297
305
|
|
|
298
|
-
MIT
|
|
306
|
+
MIT — see [LICENSE](LICENSE).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claudemd-cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6",
|
|
4
4
|
"description": "Standalone CLI for §10-V banned-vocab + transcript scanning. Companion to the claudemd Claude Code plugin (github.com/sdsrss/claudemd) for use in git pre-commit hooks, GitHub Actions, and other agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|