30 Commits
Author SHA1 Message Date
Sunil 5beffaeb17 Merge remote-tracking branch 'upstream/main' into fix/simplify-ignore-git-revert
# Conflicts:
#	hooks/simplify-ignore-test.sh
#	hooks/simplify-ignore.sh
2026-10-10 17:11:41 +05:30
Sunil e9e172d909 fix(hooks): simplify-ignore keeps a change reverted with git and re-hides the file 2026-10-06 00:14:30 +05:30
Sunil 807bba68af fix(hooks): simplify-ignore never loses a block whose placeholder was removed 2026-10-05 23:55:43 +05:30
ayobamiseun 7b31a90852 fix(hooks): insert protected block content literally under bash 5.2
The round-trip test added in this PR failed on ubuntu-latest while passing
on macOS: after Read → Stop, a protected block containing a backslash came
back altered (byte 109, line 3 of the fixture).

expand_file rebuilds each line with `${line//$placeholder/$block_content}`.
Bash 5.2 enables patsub_replacement by default, which makes the replacement
side of that expansion special: an unquoted `&` expands to the matched text
and backslashes are consumed. Block content is raw code and routinely
contains `&&` and backslashes, so on any bash 5.2 host every protected block
with either character was corrupted when it was expanded back. Bash 3.2 on
macOS has no such option, which is why local runs never showed it.

Turn the option off at the top of the hook; older bashes reject the shopt,
so the error is ignored there. Extend the byte-fidelity fixture with `&&`
and `&` so the ampersand case is guarded alongside the backslash one.
2026-09-18 09:49:16 +01:00
ayobamiseun 73d1181ce1 test(hooks): add regression coverage for sdd-cache and simplify-ignore round-trip (#295) 2026-09-18 09:45:07 +01:00
Addy Osmani 4876585989 Merge #578: expand current file on simplify-ignore Stop to prevent data loss 2026-09-17 20:29:09 -07:00
Addy Osmani 2a96fb8c8a Merge #510: fix and CI-wire the SessionStart envelope test 2026-09-17 20:29:05 -07:00
mavericksea-aiandClaude Opus 5 510259aca0 fix(hooks): keep the rewrite in the cache when simplify-ignore falls back
When a Stop leaves no BLOCK_ placeholder to expand, the hook has to restore
the backup to recover the protected block — which overwrote whatever had
replaced the file. Copy that content into the cache as <id>.recovered first
and name both paths in the warning, so the rewrite is merged back by hand
rather than lost.

Adds a test that the fallback keeps the rewritten content in the cache, and
a minimal lifecycle test (Read, a direct write with no event, Stop) asserting
the write survives.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 01:59:59 +00:00
mavericksea-aiandClaude Opus 5 b1ac22c7d2 fix(hooks): expand simplify-ignore files at Stop instead of restoring backups
The Stop branch restores every cached file from its backup, but that
backup is written on PreToolUse Read and refreshed only by the
PostToolUse Edit|Write branch. A change made to a filtered file through
any other route between Read and Stop — a Bash command, a formatter, an
external editor — is overwritten at session end. Reproduced in #295:
Bash wrote const editable = 2 and read it back, Stop left const
editable = 1 on disk, with no crash and no failed tool call.

The hook protects the content of an annotated block, not the file: the
header documents the backup as holding the model's changes, and Edit and
Write already preserve them. So Stop now runs the same placeholder
expansion the Edit|Write branch runs, against the file as it is on disk.
Whatever wrote the file wrote its filtered form with the placeholders
intact, so expanding it restores the protected blocks and keeps the
change, whichever route it came from.

The expansion body moves into an expand_file function that both branches
call, so the fuzzy-match and deleted-block warnings apply at Stop too.
When no cached BLOCK_<hash> is left, the file was rewritten wholesale and
the hook cannot place the block; it falls back to the backup as before,
now with a warning instead of in silence. That residual is documented in
SIMPLIFY-IGNORE.md. With no outside write, expansion reproduces the
backup exactly, so Read→Stop and Read→Edit→Stop are byte-identical.

Test 11 drives the real hook through Read, an Edit event, a write with no
event after it, and Stop; it fails at be4e44a on the two assertions for
the lost write. Suite: 28 passed, 0 failed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 01:35:47 +00:00
Santhi Prakash a598aab8d6 fix(hooks): stop auto-injecting the meta-skill on SessionStart (#569)
The plugin's SessionStart hook injected using-agent-skills/SKILL.md as
additionalContext on every session. Claude Code already discovers and
routes skills from their descriptions, so the hook stacks a second
router on the native one — the pattern docs/getting-started.md warns
against ("That creates two routers for the same task"), measured at
~3.5k wasted cache-creation tokens per session in #569.

Delete hooks/hooks.json (the registration; the plugin now ships no
hooks) and keep hooks/session-start.sh as a standalone script for hosts
without native skill routing, matching the fix shape suggested in the
issue. Update the hook header, CONTRIBUTING.md, codex-setup.md, and
gemini-cli-setup.md to match.
2026-09-15 19:21:06 +00:00
Santhi PrakashandPaperclip 5b6389b215 test(hooks): assert SessionStart hookSpecificOutput envelope
#474 changed session-start.sh to the host-required
hookSpecificOutput.hookEventName/additionalContext shape. The
regression test still expected the old {priority, message} payload, so
`bash hooks/session-start-test.sh` fails on current main.

Sabotage: the pre-change test errors with "expected IMPORTANT priority,
got undefined". After this change both the jq and jq-missing paths pass.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 06:06:07 +00:00
ayobamiseun abfb0b3200 fix(hooks): emit the standard SessionStart envelope (#465)
The session-start hook emitted {"priority", "message"} JSON on all three
of its output paths. Codex CLI validates SessionStart hook output and
fails the hook on that shape ('hook returned invalid session start JSON
output', #465); the documented contract for both Codex and Claude Code is

  {"hookSpecificOutput": {"hookEventName": "SessionStart",
                          "additionalContext": "..."}}

Switch all three paths (meta-skill injection, jq-missing fallback,
meta-skill-missing fallback) to that envelope. Verified each path emits
valid JSON of the new shape: happy path via jq shape assertion, jq-missing
via PATH='' run, meta-skill-missing via a copy outside the repo.
2026-08-08 18:41:01 +01:00
Jagadish 9497ed8969 Merge branch 'addyosmani:main' into fix/quote-opt-in-hook-paths 2026-07-20 09:11:15 +05:30
JagadishandCursor bb68af5624 fix(hooks): quote opt-in hook paths in setup docs
Unquoted ${CLAUDE_PROJECT_DIR} in SDD-CACHE and SIMPLIFY-IGNORE setup
examples breaks when the project path contains spaces, the same class
of failure fixed for SessionStart in #214.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-20 09:03:58 +05:30
youjinchoi dbb32a565c fix(hooks): simplify-ignore-test asserts the no-jq guard instead of failing
Test 10 pipes malformed JSON through the real hook, but the hook's jq
guard exits with 'error: missing jq' before parsing on machines without
jq (default Git for Windows, minimal Linux). The suite then reports a
failure unrelated to the contributor's change; tests 1-9 only exercise
the extracted filter_file and keep passing.

Mirror session-start-test.sh, which CONTRIBUTING documents as validating
both the jq and no-jq branches: with jq on PATH keep the existing
bad-JSON warning assertion, without it assert the documented missing-jq
guard message.

Verified on Windows (Git Bash): 21 passed, 0 failed both with jq 1.8.1
on PATH and without jq.
2026-07-18 02:39:16 +09:00
Addy Osmani 5c5dbe653e Merge pull request #269 from worldfunction4/main
fix: add path fallback for manual installation in hooks.json
2026-06-14 01:38:34 -07:00
zhoujingtian 22ce244ba9 fix(hooks): make simplify-ignore-test.sh executable
hooks/simplify-ignore-test.sh was committed with mode 100644 while its
sibling test script hooks/session-start-test.sh is 100755. Both share
the same #!/bin/bash shebang and live in the same directory; set the
exec bit for consistency.
2026-06-14 15:23:28 +08:00
Layyes b7833777b1 Fix command execution in hooks.json 2026-06-13 12:30:34 +08:00
Layyes 212e7a1d9c fix: add path fallback for manual installation in hooks.json
When users manually copy hooks to .claude/ instead of installing via plugin, ${CLAUDE_PLUGIN_ROOT} is not set and the SessionStart hook silently fails.
   This adds a fallback to ${CLAUDE_PROJECT_DIR}/.claude/hooks/ so the hook works in both plugin and manual install modes. If neither path exists, it silently succeeds.
2026-06-13 12:27:18 +08:00
Bortlesboat d409c9ae5c test: add session-start JSON regression coverage 2026-05-06 21:21:34 -04:00
Addy OsmaniandClaude Opus 4.7 501d2266dd hooks: gracefully fall back when jq is missing
The fix in 43a0dde introduces jq as a hard runtime dependency for the
session-start hook. jq is not preinstalled on every macOS or Linux setup,
so users without it would hit a cryptic failure on every new session.

Add a `command -v jq` guard that emits a valid INFO-priority JSON message
explaining the dependency and pointing at install commands. Skills remain
available individually — only the meta-skill injection is skipped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:09:22 -07:00
james 43a0dde996 fix: JSON-escape hook content in session-start hook
Fixes issue #89: session-start hook now properly escapes SKILL.md content
when constructing JSON output, preventing parse errors when markdown
contains quotes or control characters.

Uses jq -cn with --arg flag to properly escape all special characters
in the message field.
2026-04-24 23:06:28 -07:00
Federico Bartoli 4743df93b7 refactor(hooks): address review feedback on sdd-cache
Drop the 24h TTL: HTTP validators are the whole freshness contract.
Key cache on URL alone; prompt-aware keying with normalization gave
false safety (semantic differences slipped through). Prompt is kept
as metadata and surfaced in the hit message so the next agent can
judge whether the earlier reading applies. Reframe docs around
"HTTP resource cache, not prompt cache".

While here, fix two latent bugs:
- Replace the unquoted heredoc in the pre-hook with printf. The
  heredoc expanded $vars and backticks inside cached content, so a
  compromised doc page could trigger command substitution on cache
  hit.
- Strip CR before awk paragraph-mode parsing of curl -I -L output
  so blank separators between response blocks on a redirect chain
  are recognised (was silently picking intermediate headers).

Remove dead -v IGNORECASE=1 (gawk-only; tolower() already handles it).
2026-04-18 08:49:29 +02:00
Federico Bartoli 9a429d0574 feat(hooks): opt-in citation cache for source-driven-development
Adds a pair of optional Claude Code hooks that cache WebFetch output
on disk but revalidate every reuse against the origin. Content is
served only when the server returns 304 Not Modified, so
source-driven-development's "verify against current docs" guarantee
still holds across sessions.

- hooks/sdd-cache-pre.sh: PreToolUse hook. For a cached entry, issues
  a HEAD with If-None-Match / If-Modified-Since. On 304, blocks the
  WebFetch (exit 2) and returns cached content via stderr; otherwise
  allows the fetch through.
- hooks/sdd-cache-post.sh: PostToolUse hook. Captures response plus
  current ETag / Last-Modified. Entries without a validator are
  never stored — without one, the pre hook cannot verify freshness
  and caching would amount to trusting memory.
- Cache key: sha256(url + normalized_prompt). Prompt is lowercased
  and whitespace-collapsed so stylistic variants hit the same entry;
  semantically different prompts still miss.
- Hard 24h TTL as a safety net against misbehaving origins.
- hooks/SDD-CACHE.md: opt-in setup, end-to-end testing, debugging.
- .gitignore: ignore the .claude/sdd-cache/ directory.

Hooks are opt-in: users register them in .claude/settings.json. The
source-driven-development skill itself is unchanged.
2026-04-16 19:34:38 +02:00
Addy Osmani 111eade87e For #7 some additional minor tweaks 2026-03-27 18:38:08 -07:00
Federico Bartoli 1730a69454 Add simplify-ignore hook for block-level code protection
Single bash script that prevents the model from seeing (and accidentally
simplifying) code blocks marked with simplify-ignore annotations during
/code-simplify sessions.

Hook flow:
- PreToolUse Read: backs up file, replaces blocks with BLOCK_<hash> placeholders
- PostToolUse Edit|Write: expands placeholders, applies model changes, re-filters
- Stop: restores files from backup when session ends

Features:
- Hash-based tokens (content-addressed, unambiguous round-trip)
- Multi-block support per file
- Optional reason string: /* simplify-ignore-start: perf-critical */
- Language-aware placeholders (preserves comment syntax per language)
- Glob-safe parameter expansion (Bash 3.2 compatible)
- Atomic locking with stale lock recovery
- Trailing newline preservation
- Self-healing recovery from interrupted sessions
- Cross-platform: Bash 3.2+, jq, shasum/sha1sum (macOS, Linux, Git Bash)

Implements #2
2026-03-18 05:20:14 +01:00
Federico Bartoli 0490a93323 Add Claude Code plugin manifest and marketplace catalog
Enable this repo to work as a Claude Code plugin so users can
install it via `/plugin marketplace add addyosmani/agent-skills`.

Add:
- .claude-plugin/plugin.json — plugin manifest exposing
  .claude/commands/ as namespaced slash commands under
  the agent-skills: prefix
- .claude-plugin/marketplace.json — marketplace catalog
  listing this repo as the agent-skills plugin

Fix:
- hooks/hooks.json — rewrite from deprecated flat-array format
  to the plugin-system format keyed by event type; use
  ${CLAUDE_PLUGIN_ROOT} so the hook resolves correctly when the
  plugin is installed from the marketplace into the local cache
- README — replace non-existent `claude plugin add` with the
  correct `/plugin marketplace add` workflow; document namespaced
  slash commands and --plugin-dir usage; add .claude-plugin/ to
  the project tree
2026-02-23 12:29:43 +01:00
Federico Bartoli a63f54b8ab Rename stale swe-skills references to agent-skills
The repository was renamed from swe-skills to agent-skills but
internal references were never updated. This caused:
- session-start.sh to silently fail (path using-swe-skills/ did
  not exist; the directory is using-agent-skills/)
- slash commands to invoke non-existent swe-skills: namespace
- docs and setup guides to point at the old clone URL

Rename all occurrences across 14 files: commands, CLAUDE.md,
README tree, docs/, and hooks/.
2026-02-23 12:02:07 +01:00
Addy Osmani a3372ca0fc add hooks session starter 2026-02-15 14:28:13 -08:00
Addy Osmani d2e333a2c6 add CLAUDE.md and hooks 2026-02-15 14:28:07 -08:00