Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .claude/hooks/context-forced-eval.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/bin/bash
# context-forced-eval.sh
# Hook: UserPromptSubmit
# Purpose: Inject skill evaluation context when user prompt matches context-related keywords
# Installed by: /contextdocs:context-guard install
#
# Keyword-gated — only fires on context-related prompts to avoid overhead on
# unrelated coding tasks. Advisory only — never blocks.
#
# Claude Code only — OpenCode, Codex CLI, Cursor, and other tools
# do not support Claude Code hooks.

set -euo pipefail

# Read hook input from stdin
INPUT=$(cat)

# Skip in Untether sessions (Telegram stays lean)
[ -n "${UNTETHER_SESSION:-}" ] && echo '{}' && exit 0

# Extract prompt
PROMPT=$(echo "$INPUT" | jq -r '.prompt // empty' 2>/dev/null || true)

# Skip empty prompts
[ -z "$PROMPT" ] && echo '{}' && exit 0

# Convert to lowercase for matching
LOWER=$(echo "$PROMPT" | tr '[:upper:]' '[:lower:]')

# Check for context-related keywords
MATCH=false

# Slash commands (exact prefix match)
case "$LOWER" in
/ai-context*|/context-guard*|/context-verify*) MATCH=true ;;
esac

# Keyword matching
if [ "$MATCH" = "false" ]; then
if echo "$LOWER" | grep -qE '(claude\.md|agents\.md|context|stale|hook[s ]|guard|verify|score|health|cursorrules|copilot|memory.*promot|drift|bridge|ai-context|context-guard|context-verify|llms\.txt|windsurfrules|clinerules|gemini\.md)'; then
MATCH=true
fi
fi

# No match — pass through silently
if [ "$MATCH" = "false" ]; then
echo '{}'
exit 0
fi

# Inject skill evaluation context
cat << 'EOF'
{
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "SKILL EVALUATION: This project uses ContextDocs (3 skills). Evaluate whether this prompt matches a skill and activate it via the Skill() tool before responding:\n\n1. ai-context — Generate, update, fix, or audit AI IDE context files (CLAUDE.md, AGENTS.md, bridges). Use for stale context, bootstrapping, MEMORY.md promotion, or drift.\n2. context-guard — Install, uninstall, or check Context Guard hooks. Use for hook setup, commit guards, or freshness enforcement.\n3. context-verify — Validate context file quality with 0-100 scoring. Use for health checks, line budgets, CI verification.\n\nIf a skill matches, call Skill(skill-name) NOW. If none match, proceed normally."
}
}
EOF
2 changes: 1 addition & 1 deletion .claude/skills/ai-context/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: ai-context
description: Generates, updates, and maintains AGENTS-first AI IDE context files with AGENTS.md as canonical shared context and thin tool-specific bridges. Use this skill when the user wants to create a CLAUDE.md, generate AGENTS.md, set up context files for a project, update stale AI context, bootstrap context for a new repo, promote MEMORY.md patterns into CLAUDE.md, audit context for drift, or generate cursorrules, copilot instructions, clinerules, windsurfrules, or GEMINI.md. Use proactively whenever context files may need attention, even if not explicitly requested.
description: Generates, updates, and maintains AGENTS-first AI IDE context files with AGENTS.md as canonical shared context and thin tool-specific bridges. Use this skill when the user wants to create a CLAUDE.md, generate AGENTS.md, set up context files for a project, update or fix out-of-date context files, refresh stale CLAUDE.md or AGENTS.md, bootstrap context for a new repo, move or promote MEMORY.md patterns into CLAUDE.md, audit context for drift, or generate cursorrules, copilot instructions, clinerules, windsurfrules, or GEMINI.md. This is the right skill for updating, regenerating, or fixing context files — not just checking them. Use proactively whenever context files may need attention, even if not explicitly requested.
---

# AI Context File Generator
Expand Down
7 changes: 7 additions & 0 deletions .claude/skills/context-guard/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ Fires before `git commit`. Checks staging area for structural files without cont

Fires at session start. Quick context health check: counts context files, detects stale files (source commits ahead), warns if aggregate line count exceeds budget. Advisory only — cannot block session start.

### context-forced-eval.sh (UserPromptSubmit)

Fires on every user prompt. Checks for context-related keywords and injects a skill evaluation sequence that instructs Claude to evaluate and activate ContextDocs skills before responding. Keyword-gated to avoid overhead on unrelated prompts. Advisory only — never blocks.

### context-updater agent

Autonomous agent (`.claude/agents/context-updater.md`) launched by Claude in response to hook output. Applies surgical, incremental context file updates. Uses `.git/.context-updater-running` flag for loop prevention.
Expand All @@ -80,6 +84,9 @@ Autonomous agent (`.claude/agents/context-updater.md`) launched by Claude in res
"SessionStart": [
{ "hooks": [{ "type": "command", "command": ".claude/hooks/context-session-start.sh" }] }
],
"UserPromptSubmit": [
{ "hooks": [{ "type": "command", "command": ".claude/hooks/context-forced-eval.sh" }] }
],
"Stop": [
{ "hooks": [{ "type": "command", "command": ".claude/hooks/context-guard-stop.sh" }] }
]
Expand Down
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @littlebearapps/core
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
docs/promotion/
docs/plans/

# Dev workspace and scratch files
ai-context-workspace/
incoming/
tests/activation-results/

# === Direnv ===
.envrc.local
.direnv/
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ Invoke as `/contextdocs:command-name` in Claude Code, or as prompts in Codex CLI

## Hooks (Claude Code Only)

6 opt-in hooks, installed via `/contextdocs:context-guard install`. Hooks reference the context-updater agent for autonomous action:
7 opt-in hooks, installed via `/contextdocs:context-guard install`. Hooks reference the context-updater agent for autonomous action:

- `context-session-start.sh` — session-start context health check (advisory)
- `context-forced-eval.sh` — keyword-gated skill evaluation on context-related prompts (advisory)
- `context-drift-check.sh` — post-commit drift detection
- `context-structural-change.sh` — structural change reminders to update `AGENTS.md` first, then bridges
- `content-filter-guard.sh` — Write guard for high-risk OSS files
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to ContextDocs will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Fixed

* Context Guard hooks no longer flag infrastructure rule files as false positives ([#13](https://github.com/littlebearapps/contextdocs/issues/13))
* ai-context skill triggers more reliably when you describe stale context or MEMORY.md promotion scenarios
* SKILL.md and CLAUDE.md descriptions now match the canonical product definition across all tools

## [1.4.0](https://github.com/littlebearapps/contextdocs/compare/v1.3.0...v1.4.0) (2026-03-13)


Expand Down
1 change: 1 addition & 0 deletions _typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ initialised = "initialised"
center = "center"

# Technical terms
promot = "promot" # regex partial match for promote/promotion in hooks
contextdocs = "contextdocs"
pitchdocs = "pitchdocs"
llms = "llms"
Expand Down
18 changes: 10 additions & 8 deletions commands/context-guard.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ Context Guard has two enforcement tiers:

- **`install`**: Install Context Guard (Tier 1) into the current project:
1. Create `.claude/hooks/` directory if it does not exist
2. Copy `context-drift-check.sh`, `context-structural-change.sh`, `content-filter-guard.sh`, `context-guard-stop.sh`, and `context-session-start.sh` from the plugin's `hooks/` directory to `.claude/hooks/`
2. Copy `context-drift-check.sh`, `context-structural-change.sh`, `content-filter-guard.sh`, `context-guard-stop.sh`, `context-session-start.sh`, and `context-forced-eval.sh` from the plugin's `hooks/` directory to `.claude/hooks/`
3. Make the scripts executable (`chmod +x`)
4. Create `.claude/agents/` directory if it does not exist
5. Copy `context-updater.md` from the plugin's `.claude/agents/` directory to `.claude/agents/context-updater.md`
6. Merge PreToolUse, PostToolUse, SessionStart, and Stop hook entries into `.claude/settings.json` (create the file if needed; if entries already exist, append without overwriting)
6. Merge PreToolUse, PostToolUse, SessionStart, UserPromptSubmit, and Stop hook entries into `.claude/settings.json` (create the file if needed; if entries already exist, append without overwriting)
7. Copy `context-quality.md` to `.claude/rules/context-quality.md` (create directory if needed)
8. Report what was installed

Expand All @@ -43,8 +43,8 @@ Context Guard has two enforcement tiers:
4. Report what was installed, noting Tier 2 is active

- **`uninstall`**: Remove all Context Guard hooks from the current project:
1. Remove `.claude/hooks/context-drift-check.sh`, `.claude/hooks/context-structural-change.sh`, `.claude/hooks/content-filter-guard.sh`, `.claude/hooks/context-guard-stop.sh`, `.claude/hooks/context-session-start.sh`, and `.claude/hooks/context-commit-guard.sh`
2. Remove all Context Guard hook entries (PreToolUse, PostToolUse, SessionStart, and Stop) from `.claude/settings.json` (preserve other hooks)
1. Remove `.claude/hooks/context-drift-check.sh`, `.claude/hooks/context-structural-change.sh`, `.claude/hooks/content-filter-guard.sh`, `.claude/hooks/context-guard-stop.sh`, `.claude/hooks/context-session-start.sh`, `.claude/hooks/context-forced-eval.sh`, and `.claude/hooks/context-commit-guard.sh`
2. Remove all Context Guard hook entries (PreToolUse, PostToolUse, SessionStart, UserPromptSubmit, and Stop) from `.claude/settings.json` (preserve other hooks)
3. Remove `.claude/rules/context-quality.md`
4. Remove `.claude/agents/context-updater.md`
5. Report what was removed
Expand All @@ -68,9 +68,10 @@ Context Guard installed (Tier 1 — Nudge):
✓ .claude/hooks/content-filter-guard.sh — blocks Write on high-risk OSS files, advises on medium-risk
✓ .claude/hooks/context-guard-stop.sh — nudges to update context docs before session ends
✓ .claude/hooks/context-session-start.sh — quick context health check at session start
✓ .claude/hooks/context-forced-eval.sh — injects skill evaluation on context-related prompts
✓ .claude/agents/context-updater.md — autonomous agent for surgical context file updates
✓ .claude/rules/context-quality.md — auto-loaded quality standards for context files
✓ .claude/settings.json — PreToolUse, PostToolUse, SessionStart, and Stop hooks registered
✓ .claude/settings.json — PreToolUse, PostToolUse, SessionStart, UserPromptSubmit, and Stop hooks registered

Tier 2 (Guard) not installed. Run /contextdocs:context-guard install strict to also
block commits when structural files change without context doc updates.
Expand All @@ -88,19 +89,20 @@ Context Guard installed (Tier 1 + Tier 2 — Nudge + Guard):
✓ .claude/hooks/content-filter-guard.sh — blocks Write on high-risk OSS files, advises on medium-risk
✓ .claude/hooks/context-guard-stop.sh — nudges to update context docs before session ends
✓ .claude/hooks/context-session-start.sh — quick context health check at session start
✓ .claude/hooks/context-forced-eval.sh — injects skill evaluation on context-related prompts
✓ .claude/hooks/context-commit-guard.sh — blocks commits with stale context docs
✓ .claude/agents/context-updater.md — autonomous agent for surgical context file updates
✓ .claude/rules/context-quality.md — auto-loaded quality standards for context files
✓ .claude/settings.json — PreToolUse, PostToolUse, SessionStart, and Stop hooks registered
✓ .claude/settings.json — PreToolUse, PostToolUse, SessionStart, UserPromptSubmit, and Stop hooks registered
```

### Status
```
Context Guard Status:
✓ Tier 1 — Nudge (Stop hook active — reminds about context docs before session end)
✓ Tier 2 — Guard (commit blocker active — blocks commits with stale context)
✓ Base hooks installed (3/3 scripts in .claude/hooks/)
✓ Settings configured (PreToolUse, PostToolUse, and Stop entries in .claude/settings.json)
✓ Base hooks installed (scripts in .claude/hooks/)
✓ Settings configured (PreToolUse, PostToolUse, UserPromptSubmit, and Stop entries in .claude/settings.json)
✓ Context-updater agent installed (.claude/agents/context-updater.md)
✓ Quality rule active (.claude/rules/context-quality.md)

Expand Down
59 changes: 59 additions & 0 deletions hooks/context-forced-eval.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/bin/bash
# context-forced-eval.sh
# Hook: UserPromptSubmit
# Purpose: Inject skill evaluation context when user prompt matches context-related keywords
# Installed by: /contextdocs:context-guard install
#
# Keyword-gated — only fires on context-related prompts to avoid overhead on
# unrelated coding tasks. Advisory only — never blocks.
#
# Claude Code only — OpenCode, Codex CLI, Cursor, and other tools
# do not support Claude Code hooks.

set -euo pipefail

# Read hook input from stdin
INPUT=$(cat)

# Skip in Untether sessions (Telegram stays lean)
[ -n "${UNTETHER_SESSION:-}" ] && echo '{}' && exit 0

# Extract prompt
PROMPT=$(echo "$INPUT" | jq -r '.prompt // empty' 2>/dev/null || true)

# Skip empty prompts
[ -z "$PROMPT" ] && echo '{}' && exit 0

# Convert to lowercase for matching
LOWER=$(echo "$PROMPT" | tr '[:upper:]' '[:lower:]')

# Check for context-related keywords
MATCH=false

# Slash commands (exact prefix match)
case "$LOWER" in
/ai-context*|/context-guard*|/context-verify*) MATCH=true ;;
esac

# Keyword matching
if [ "$MATCH" = "false" ]; then
if echo "$LOWER" | grep -qE '(claude\.md|agents\.md|context|stale|hook[s ]|guard|verify|score|health|cursorrules|copilot|memory.*promot|drift|bridge|ai-context|context-guard|context-verify|llms\.txt|windsurfrules|clinerules|gemini\.md)'; then
MATCH=true
fi
fi

# No match — pass through silently
if [ "$MATCH" = "false" ]; then
echo '{}'
exit 0
fi

# Inject skill evaluation context
cat << 'EOF'
{
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "SKILL EVALUATION: This project uses ContextDocs (3 skills). Evaluate whether this prompt matches a skill and activate it via the Skill() tool before responding:\n\n1. ai-context — Generate, update, fix, or audit AI IDE context files (CLAUDE.md, AGENTS.md, bridges). Use for stale context, bootstrapping, MEMORY.md promotion, or drift.\n2. context-guard — Install, uninstall, or check Context Guard hooks. Use for hook setup, commit guards, or freshness enforcement.\n3. context-verify — Validate context file quality with 0-100 scoring. Use for health checks, line budgets, CI verification.\n\nIf a skill matches, call Skill(skill-name) NOW. If none match, proceed normally."
}
}
EOF
1 change: 1 addition & 0 deletions llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
- [Doc Standards Rule](./.claude/rules/doc-standards.md): Auto-loaded documentation quality standards — 4-Question Test, Lobby Principle, progressive disclosure, banned phrases (PitchDocs, Claude Code only)
- [Docs Awareness Rule](./.claude/rules/docs-awareness.md): Auto-loaded documentation trigger map — suggests PitchDocs commands when docs-relevant work is detected (PitchDocs, Claude Code only)
- [Context Session Start Hook](./hooks/context-session-start.sh): SessionStart hook that runs a quick context health check — detects stale files, warns on high aggregate line count (Claude Code only)
- [Context Forced Eval Hook](./hooks/context-forced-eval.sh): UserPromptSubmit hook that injects skill evaluation on context-related prompts — keyword-gated, advisory only (Claude Code only)
- [Context Drift Check Hook](./hooks/context-drift-check.sh): PostToolUse hook that detects stale AI context files after git commits (Claude Code only)
- [Context Structural Change Hook](./hooks/context-structural-change.sh): PostToolUse hook that reminds about AGENTS-first context updates after structural changes (Claude Code only)
- [Content Filter Guard Hook](./hooks/content-filter-guard.sh): PreToolUse hook that blocks Write on high-risk OSS files — CODE_OF_CONDUCT.md, LICENSE, SECURITY.md (Claude Code only)
Expand Down
32 changes: 32 additions & 0 deletions scripts/update-installed-hooks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ TIER1_HOOKS=(
"context-structural-change.sh"
"context-guard-stop.sh"
"context-session-start.sh"
"context-forced-eval.sh"
)

# Tier 2 hook (only updated if already present)
Expand Down Expand Up @@ -50,6 +51,16 @@ SESSION_START_ENTRY='{
]
}'

# UserPromptSubmit entry to inject via jq
USER_PROMPT_SUBMIT_ENTRY='{
"hooks": [
{
"type": "command",
"command": ".claude/hooks/context-forced-eval.sh"
}
]
}'

UPDATED=0
SKIPPED=0
WARNINGS=()
Expand Down Expand Up @@ -135,6 +146,22 @@ for PROJECT in "${PROJECTS[@]}"; do
echo " settings.json: added SessionStart entry"
fi

# --- Patch settings.json: add UserPromptSubmit if missing ---
HAS_USER_PROMPT_SUBMIT=$(jq '
.hooks.UserPromptSubmit // [] |
any(.[]; .hooks[]?.command | test("context-forced-eval\\.sh"))
' "$SETTINGS" 2>/dev/null || echo "false")

if [ "$HAS_USER_PROMPT_SUBMIT" = "true" ]; then
echo " settings.json: UserPromptSubmit already present"
else
TEMP=$(mktemp)
jq --argjson entry "$USER_PROMPT_SUBMIT_ENTRY" '
.hooks.UserPromptSubmit = (.hooks.UserPromptSubmit // []) + [$entry]
' "$SETTINGS" > "$TEMP" && mv "$TEMP" "$SETTINGS"
echo " settings.json: added UserPromptSubmit entry"
fi

# --- Warn if Stop hook entry is missing from settings.json ---
HAS_STOP=$(jq '
.hooks.Stop // [] |
Expand All @@ -144,6 +171,11 @@ for PROJECT in "${PROJECTS[@]}"; do
if [ "$HAS_STOP" != "true" ]; then
WARNINGS+=("$NAME: Stop hook entry missing from settings.json (context-guard-stop.sh won't run)")
fi

# --- Warn if UserPromptSubmit hook entry is missing from settings.json ---
if [ "$HAS_USER_PROMPT_SUBMIT" != "true" ]; then
WARNINGS+=("$NAME: UserPromptSubmit hook entry missing from settings.json (context-forced-eval.sh won't run)")
fi
else
echo " settings.json: NOT FOUND — skipping patch"
WARNINGS+=("$NAME: no .claude/settings.json found")
Expand Down
Loading
Loading