@delorenj/pjangler 1.1.5 → 1.2.2
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/.mise/scripts/link-agentfiles.sh +9 -0
- package/dist/index.js +1492 -358
- package/dist/mcp-server.js +2391 -290
- package/package.json +5 -2
- package/templates/commonproject/.mise/scripts/create-plane-project.sh +26 -0
- package/templates/commonproject/copier.yml +2 -0
- package/templates/commonproject/template/.agents/hooks/README.md +151 -0
- package/templates/commonproject/template/.agents/hooks/hermes/hindsight-hook.sh +63 -0
- package/templates/commonproject/template/.agents/hooks/hindsight/hindsight-journal-write.sh +327 -0
- package/templates/commonproject/template/.agents/hooks/hindsight/hindsight-recall.sh +180 -0
- package/templates/commonproject/template/.agents/hooks/hindsight/hindsight-retain.sh +74 -0
- package/templates/commonproject/template/.agents/hooks/hindsight/hindsight-session-end.sh +57 -0
- package/templates/commonproject/template/.agents/hooks/hindsight/lib/hindsight-bank.sh +57 -0
- package/templates/commonproject/template/.agents/hooks/hindsight/lib/hindsight-journal.sh +48 -0
- package/templates/commonproject/template/.agents/hooks/hooks.master.json +97 -0
- package/templates/commonproject/template/.agents/hooks/lib/hook-guard.sh +30 -0
- package/templates/commonproject/template/.agents/hooks/lib/local-config.sh +51 -0
- package/templates/commonproject/template/.agents/hooks/reminder-for-skill-check.sh +20 -0
- package/templates/commonproject/template/.agents/hooks/sync.py +618 -0
- package/templates/commonproject/template/.agents/local.example.json +15 -0
- package/templates/commonproject/template/.mise/scripts/hindsight-setup.sh +62 -0
- package/templates/commonproject/template/.mise/scripts/link-project-skills-to-clis.sh +110 -0
- package/templates/commonproject/template/.mise/scripts/unlink-project-skills-from-clis.sh +45 -0
- package/templates/commonproject/template/mise.toml.jinja +42 -0
- package/templates/hermes-agent/.codegraph/daemon.pid +6 -0
- package/templates/hermes-agent/.omo/run-continuation/ses_0e5b28303ffeXxL53hZjKggXDW.json +10 -0
- package/templates/hermes-agent/README.md +16 -14
- package/templates/hermes-agent/copier.yml +7 -25
- package/templates/hermes-agent/docs/architecture.md +16 -18
- package/templates/hermes-agent/docs/fleet-control-plane/README.md +35 -0
- package/templates/hermes-agent/docs/fleet-control-plane/architecture.md +253 -0
- package/templates/hermes-agent/docs/fleet-control-plane/epics-and-stories.md +280 -0
- package/templates/hermes-agent/docs/fleet-control-plane/implementation-readiness-report-2026-06-27.md +118 -0
- package/templates/hermes-agent/docs/fleet-control-plane/prd.md +141 -0
- package/templates/hermes-agent/docs/operations.md +17 -19
- package/templates/hermes-agent/docs/runbooks/runtime-checkpoint-repair.md +17 -13
- package/templates/hermes-agent/docs/{scrum-master → sentinel}/README.md +47 -46
- package/templates/hermes-agent/docs/{scrum-master → sentinel}/architecture.md +39 -38
- package/templates/hermes-agent/docs/{scrum-master → sentinel}/development.md +63 -99
- package/templates/hermes-agent/docs/{scrum-master → sentinel}/providers.md +2 -2
- package/templates/hermes-agent/docs/sentinel.md +18 -0
- package/templates/hermes-agent/install-local.sh +22 -20
- package/templates/hermes-agent/runtime-scaffold/README.md +10 -9
- package/templates/hermes-agent/scripts/backfill-fleet-sot.sh +12 -21
- package/templates/hermes-agent/scripts/fleet-sync.sh +369 -0
- package/templates/hermes-agent/scripts/migrate-unify.sh +252 -0
- package/templates/hermes-agent/scripts/unify-pm.sh +148 -0
- package/templates/hermes-agent/template/.runtime-scaffold/README.md +10 -9
- package/templates/hermes-agent/template/.scripts/01-config.sh +2 -3
- package/templates/hermes-agent/template/.scripts/05-fleet-env.sh +0 -2
- package/templates/hermes-agent/template/.scripts/10-hermes-profile.sh +47 -19
- package/templates/hermes-agent/template/.scripts/20-runtime-repo.sh +71 -27
- package/templates/hermes-agent/template/.scripts/30-telegram.sh +3 -3
- package/templates/hermes-agent/template/.scripts/42-ticket-provider.sh +3 -3
- package/templates/hermes-agent/template/.scripts/70-systemd.sh +48 -43
- package/templates/hermes-agent/template/.scripts/80-registry.sh +2 -2
- package/templates/hermes-agent/template/.scripts/99-summary.sh +3 -4
- package/templates/hermes-agent/template/.scripts/_lib.sh +4 -19
- package/templates/hermes-agent/template/.scripts/checkpoint.sh +36 -0
- package/templates/hermes-agent/template/.scripts/config.example.toml +11 -5
- package/templates/hermes-agent/template/.scripts/{scrum-master/continuous-ticket-sentinel.sh → heartbeat.sh} +84 -31
- package/templates/hermes-agent/template/.scripts/lib/ticket-provider.sh +1 -1
- package/templates/hermes-agent/template/.scripts/providers/plane.sh +9 -3
- package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/bin/emit-event.py +5 -5
- package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/bin/issue-autonomous-review.sh +6 -6
- package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/bin/issue-close-gate.sh +2 -2
- package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/docs/autonomous-delegated-review.md +7 -7
- package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/docs/bloodbank-events.md +3 -3
- package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/docs/continuous-ticket-orchestration.md +6 -6
- package/templates/hermes-agent/template/.scripts/{scrum-master/continuous-ticket-sentinel.prompt.md.jinja → sentinel.prompt.md.jinja} +5 -4
- package/templates/hermes-agent/template/SOUL.md.jinja +3 -6
- package/templates/hermes-agent/template/hermes.jinja +6 -15
- package/templates/hermes-agent/template/role.yaml.jinja +9 -8
- package/templates/commonproject/.claude/commands/bmad/bmb/agents/agent-builder.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmb/agents/module-builder.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmb/agents/workflow-builder.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmb/workflows/agent.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmb/workflows/module.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmb/workflows/workflow.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/analyst.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/architect.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/dev.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/pm.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/quick-flow-solo-dev.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/sm.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/tea.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/tech-writer.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/ux-designer.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/check-implementation-readiness.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/code-review.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/correct-course.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-architecture.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-epics-and-stories.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-excalidraw-dataflow.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-excalidraw-diagram.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-excalidraw-flowchart.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-excalidraw-wireframe.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-product-brief.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-story.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-ux-design.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/dev-story.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/document-project.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/generate-project-context.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/prd.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/quick-dev.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/quick-spec.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/research.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/retrospective.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/sprint-planning.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/sprint-status.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-atdd.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-automate.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-ci.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-framework.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-nfr.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-test-design.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-test-review.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-trace.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/workflow-init.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/workflow-status.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/cis/agents/brainstorming-coach.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/cis/agents/creative-problem-solver.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/cis/agents/design-thinking-coach.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/cis/agents/innovation-strategist.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/cis/agents/presentation-master.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/cis/agents/storyteller.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/cis/workflows/design-thinking.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/cis/workflows/innovation-strategy.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/cis/workflows/problem-solving.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/cis/workflows/storytelling.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/core/agents/bmad-master.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/core/tasks/index-docs.md +0 -9
- package/templates/commonproject/.claude/commands/bmad/core/tasks/shard-doc.md +0 -9
- package/templates/commonproject/.claude/commands/bmad/core/workflows/brainstorming.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/core/workflows/party-mode.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/custom/workflows/ticket-lifecycle.md +0 -5
- package/templates/hermes-agent/docs/scrum-master-sentinel.md +0 -17
- package/templates/hermes-agent/template/.scripts/75-scrum-master.sh +0 -117
- package/templates/hermes-agent/template/.scripts/90-chain-scrum-master.sh +0 -45
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claude Code UserPromptSubmit hook: recall Hindsight memories.
|
|
3
|
+
# Reads JSON from stdin (Claude hook contract), outputs context to stdout.
|
|
4
|
+
# Gracefully exits if hindsight CLI is not installed.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
HS_BIN="${HOME}/.local/bin/hindsight"
|
|
8
|
+
|
|
9
|
+
# Parse Claude's JSON stdin
|
|
10
|
+
INPUT=$(cat)
|
|
11
|
+
PROMPT=$(echo "$INPUT" | jq -r '.prompt // .message // empty' 2>/dev/null || echo "")
|
|
12
|
+
|
|
13
|
+
# Load journal telemetry helper (no-ops gracefully on its own)
|
|
14
|
+
# shellcheck source=lib/hindsight-journal.sh
|
|
15
|
+
source "$(dirname "${BASH_SOURCE[0]}")/lib/hindsight-journal.sh"
|
|
16
|
+
SESSION_ID=$(journal_session_id_from "$INPUT")
|
|
17
|
+
PROMPT_FIRST120=$(printf '%s' "$PROMPT" | head -c 120)
|
|
18
|
+
|
|
19
|
+
# Skip if hindsight CLI is missing — but still log the skip for the journal.
|
|
20
|
+
if [[ ! -x "$HS_BIN" ]]; then
|
|
21
|
+
journal_log "$SESSION_ID" "$(jq -nc \
|
|
22
|
+
--arg p "$PROMPT_FIRST120" \
|
|
23
|
+
--argjson plen ${#PROMPT} \
|
|
24
|
+
'{event:"recall_skipped", reason:"hindsight_binary_missing", prompt_len:$plen, prompt_first120:$p}')"
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Skip empty or noisy prompts — but still log the skip.
|
|
29
|
+
if [[ -z "$PROMPT" ]] || [[ ${#PROMPT} -lt 24 ]]; then
|
|
30
|
+
journal_log "$SESSION_ID" "$(jq -nc \
|
|
31
|
+
--arg p "$PROMPT_FIRST120" \
|
|
32
|
+
--argjson plen ${#PROMPT} \
|
|
33
|
+
'{event:"recall_skipped", reason:(if $plen==0 then "empty_prompt" else "prompt_under_min_length" end), min_length:24, prompt_len:$plen, prompt_first120:$p}')"
|
|
34
|
+
exit 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# Detect bank via shared resolver (GitHub remote name → repo basename → "general")
|
|
38
|
+
# shellcheck source=lib/hindsight-bank.sh
|
|
39
|
+
source "$(dirname "${BASH_SOURCE[0]}")/lib/hindsight-bank.sh"
|
|
40
|
+
BANK=$(resolve_bank)
|
|
41
|
+
|
|
42
|
+
# Per-source line caps keep total bounded without starving later layers.
|
|
43
|
+
PRIMARY_LINES="${HINDSIGHT_PRIMARY_LINES:-30}"
|
|
44
|
+
FALLBACK_LINES="${HINDSIGHT_FALLBACK_LINES:-15}"
|
|
45
|
+
LINKED_LINES_PER_BANK="${HINDSIGHT_LINKED_LINES:-12}"
|
|
46
|
+
|
|
47
|
+
recall_cli() {
|
|
48
|
+
NO_COLOR=1 \
|
|
49
|
+
CLICOLOR=0 \
|
|
50
|
+
CLICOLOR_FORCE=0 \
|
|
51
|
+
FORCE_COLOR=0 \
|
|
52
|
+
TERM=dumb \
|
|
53
|
+
COLORTERM= \
|
|
54
|
+
RICH_NO_COLOR=1 \
|
|
55
|
+
HINDSIGHT_NO_COLOR=1 \
|
|
56
|
+
HINDSIGHT_NO_SPINNER=1 \
|
|
57
|
+
HINDSIGHT_DISABLE_SPINNER=1 \
|
|
58
|
+
"$HS_BIN" memory recall "$@"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
sanitize_recall_output() {
|
|
62
|
+
if command -v perl >/dev/null 2>&1; then
|
|
63
|
+
perl -pe 's/\e\][^\a]*(?:\a|\e\\)//g; s/\e\[[0-?]*[ -\/]*[@-~]//g; s/[^\r\n]*\r//g; s/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]//g'
|
|
64
|
+
else
|
|
65
|
+
sed -E $'s|\x1B\\[[0-?]*[ -/]*[@-~]||g; s|\x1B\\][^\a]*(\a|\x1B\\\\)||g' | tr '\r' '\n'
|
|
66
|
+
fi
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
cap() { sanitize_recall_output | sed '/^[[:space:]]*$/d' | head -n "$1"; }
|
|
70
|
+
|
|
71
|
+
# Primary bank recall
|
|
72
|
+
MEMORIES=$(recall_cli "$BANK" "$PROMPT" 2>/dev/null | cap "$PRIMARY_LINES" || echo "")
|
|
73
|
+
|
|
74
|
+
# Fallback to general if primary bank is different
|
|
75
|
+
FALLBACK=""
|
|
76
|
+
if [[ "$BANK" != "general" ]]; then
|
|
77
|
+
FALLBACK=$(recall_cli "general" "$PROMPT" 2>/dev/null | cap "$FALLBACK_LINES" || echo "")
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# Always-on global banks — cross-project knowledge that should surface
|
|
81
|
+
# regardless of which repo we're in (homelab routing, infra conventions, etc).
|
|
82
|
+
# Override via HINDSIGHT_GLOBAL_BANKS="infra dotfiles ..." (space-separated).
|
|
83
|
+
GLOBAL_BANKS="${HINDSIGHT_GLOBAL_BANKS:-infra}"
|
|
84
|
+
GLOBAL=""
|
|
85
|
+
for gb in $GLOBAL_BANKS; do
|
|
86
|
+
[[ "$gb" == "$BANK" || "$gb" == "general" ]] && continue
|
|
87
|
+
gout=$(recall_cli "$gb" "$PROMPT" --budget low 2>/dev/null | cap "$FALLBACK_LINES" || echo "")
|
|
88
|
+
if [[ -n "$gout" ]]; then
|
|
89
|
+
GLOBAL="${GLOBAL}
|
|
90
|
+
<!-- global-bank: $gb -->
|
|
91
|
+
${gout}"
|
|
92
|
+
fi
|
|
93
|
+
done
|
|
94
|
+
|
|
95
|
+
# Linked-bank fanout via Dream's graph cache.
|
|
96
|
+
# Cache path/threshold/fanout cap are env-tunable; set HINDSIGHT_FANOUT=0 to disable.
|
|
97
|
+
LINKED=""
|
|
98
|
+
GRAPH_CACHE="${HINDSIGHT_DREAM_GRAPH:-${HOME}/.hindsight/dream/bank-graph.json}"
|
|
99
|
+
FANOUT_ENABLED="${HINDSIGHT_FANOUT:-1}"
|
|
100
|
+
FANOUT_MAX="${HINDSIGHT_FANOUT_MAX:-2}"
|
|
101
|
+
FANOUT_MIN_SCORE="${HINDSIGHT_FANOUT_MIN_SCORE:-0.1}"
|
|
102
|
+
|
|
103
|
+
LINKED_BANKS_USED=()
|
|
104
|
+
if [[ "$FANOUT_ENABLED" != "0" ]] && [[ -f "$GRAPH_CACHE" ]] && command -v jq &>/dev/null; then
|
|
105
|
+
LINKED_BANKS=$(jq -r --arg b "$BANK" --argjson min "$FANOUT_MIN_SCORE" --argjson n "$FANOUT_MAX" \
|
|
106
|
+
'(.graph[$b] // []) | map(select(.score >= $min)) | .[:$n] | .[].bank' \
|
|
107
|
+
"$GRAPH_CACHE" 2>/dev/null || true)
|
|
108
|
+
for linked in $LINKED_BANKS; do
|
|
109
|
+
[[ -z "$linked" || "$linked" == "$BANK" || "$linked" == "general" ]] && continue
|
|
110
|
+
out=$(recall_cli "$linked" "$PROMPT" --budget low --max-tokens 1024 2>/dev/null | cap "$LINKED_LINES_PER_BANK" || echo "")
|
|
111
|
+
if [[ -n "$out" ]]; then
|
|
112
|
+
LINKED="${LINKED}
|
|
113
|
+
<!-- linked-bank: $linked -->
|
|
114
|
+
${out}"
|
|
115
|
+
LINKED_BANKS_USED+=("$linked")
|
|
116
|
+
fi
|
|
117
|
+
done
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
ALL=""
|
|
121
|
+
[[ -n "$MEMORIES" ]] && ALL="${MEMORIES}"
|
|
122
|
+
[[ -n "$FALLBACK" ]] && ALL="${ALL}
|
|
123
|
+
${FALLBACK}"
|
|
124
|
+
[[ -n "$GLOBAL" ]] && ALL="${ALL}
|
|
125
|
+
${GLOBAL}"
|
|
126
|
+
[[ -n "$LINKED" ]] && ALL="${ALL}
|
|
127
|
+
${LINKED}"
|
|
128
|
+
|
|
129
|
+
# Final overall guard so we never dump unbounded recall output.
|
|
130
|
+
ALL=$({ printf '%s\n' "$ALL" | sanitize_recall_output | sed '/^[[:space:]]*$/d' | head -100; } || true)
|
|
131
|
+
|
|
132
|
+
if [[ -n "$ALL" ]]; then
|
|
133
|
+
printf '\n'
|
|
134
|
+
printf '<!-- hindsight:recall bank=%s -->\n' "$BANK"
|
|
135
|
+
printf '%s\n' "$ALL"
|
|
136
|
+
printf '<!-- /hindsight:recall -->\n'
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
# --- Journal telemetry: record what we asked and what we got back ---
|
|
140
|
+
count_nonempty() { printf '%s\n' "$1" | awk 'NF{c++} END{print c+0}'; }
|
|
141
|
+
primary_lines=$(count_nonempty "$MEMORIES")
|
|
142
|
+
fallback_lines=$(count_nonempty "$FALLBACK")
|
|
143
|
+
global_lines=$(count_nonempty "$GLOBAL")
|
|
144
|
+
linked_lines=$(count_nonempty "$LINKED")
|
|
145
|
+
total_lines=$(count_nonempty "$ALL")
|
|
146
|
+
total_chars=${#ALL}
|
|
147
|
+
# Empty array if no linked banks; otherwise JSON array of names.
|
|
148
|
+
if [[ ${#LINKED_BANKS_USED[@]} -eq 0 ]]; then
|
|
149
|
+
linked_json='[]'
|
|
150
|
+
else
|
|
151
|
+
linked_json=$(printf '%s\n' "${LINKED_BANKS_USED[@]}" | jq -R . | jq -sc .)
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
journal_log "$SESSION_ID" "$(jq -nc \
|
|
155
|
+
--arg bank "$BANK" \
|
|
156
|
+
--arg p "$PROMPT_FIRST120" \
|
|
157
|
+
--argjson plen ${#PROMPT} \
|
|
158
|
+
--argjson pl "$primary_lines" \
|
|
159
|
+
--argjson fl "$fallback_lines" \
|
|
160
|
+
--argjson gl "$global_lines" \
|
|
161
|
+
--argjson ll "$linked_lines" \
|
|
162
|
+
--argjson tl "$total_lines" \
|
|
163
|
+
--argjson tc "$total_chars" \
|
|
164
|
+
--argjson linked "$linked_json" \
|
|
165
|
+
--arg global "$GLOBAL_BANKS" \
|
|
166
|
+
'{
|
|
167
|
+
event: "recall",
|
|
168
|
+
bank: $bank,
|
|
169
|
+
prompt_len: $plen,
|
|
170
|
+
prompt_first120: $p,
|
|
171
|
+
primary_lines: $pl,
|
|
172
|
+
fallback_lines: $fl,
|
|
173
|
+
global_lines: $gl,
|
|
174
|
+
linked_lines: $ll,
|
|
175
|
+
total_lines: $tl,
|
|
176
|
+
total_chars: $tc,
|
|
177
|
+
linked_banks: $linked,
|
|
178
|
+
global_banks: $global,
|
|
179
|
+
returned_anything: ($tl > 0)
|
|
180
|
+
}')"
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claude Code PostToolUse hook: retain file edits in Hindsight.
|
|
3
|
+
# Reads JSON from stdin (Claude hook contract), fire-and-forget.
|
|
4
|
+
# Gracefully exits if hindsight CLI is not installed.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
HS_BIN="${HOME}/.local/bin/hindsight"
|
|
8
|
+
if [[ ! -x "$HS_BIN" ]]; then
|
|
9
|
+
exit 0
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
INPUT=$(cat)
|
|
13
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty' 2>/dev/null || echo "")
|
|
14
|
+
|
|
15
|
+
if [[ -z "$FILE_PATH" ]]; then
|
|
16
|
+
exit 0
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
CONTENT=$(echo "$INPUT" | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null || echo "")
|
|
20
|
+
CONTENT_LEN=${#CONTENT}
|
|
21
|
+
|
|
22
|
+
if [[ $CONTENT_LEN -lt 50 ]]; then
|
|
23
|
+
exit 0
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
|
27
|
+
if [[ -n "$REPO_ROOT" ]]; then
|
|
28
|
+
REL_PATH="${FILE_PATH#$REPO_ROOT/}"
|
|
29
|
+
else
|
|
30
|
+
REL_PATH="$FILE_PATH"
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
EXT="${FILE_PATH##*.}"
|
|
34
|
+
SNIPPET=$(echo "$CONTENT" | head -5 | tr '\n' ' ' | cut -c1-200)
|
|
35
|
+
|
|
36
|
+
# Detect bank via shared resolver (GitHub remote name → repo basename → "general")
|
|
37
|
+
# shellcheck source=lib/hindsight-bank.sh
|
|
38
|
+
source "$(dirname "${BASH_SOURCE[0]}")/lib/hindsight-bank.sh"
|
|
39
|
+
BANK=$(resolve_bank)
|
|
40
|
+
|
|
41
|
+
# Load journal telemetry helper
|
|
42
|
+
# shellcheck source=lib/hindsight-journal.sh
|
|
43
|
+
source "$(dirname "${BASH_SOURCE[0]}")/lib/hindsight-journal.sh"
|
|
44
|
+
SESSION_ID=$(journal_session_id_from "$INPUT")
|
|
45
|
+
|
|
46
|
+
RETAIN_TEXT="Edited ${REL_PATH} (${EXT}): ${SNIPPET}"
|
|
47
|
+
|
|
48
|
+
# Fire-and-forget retain
|
|
49
|
+
"$HS_BIN" memory retain "$BANK" "$RETAIN_TEXT" \
|
|
50
|
+
--context "code-edit" &>/dev/null &
|
|
51
|
+
|
|
52
|
+
# Journal telemetry: record what we retained
|
|
53
|
+
journal_log "$SESSION_ID" "$(jq -nc \
|
|
54
|
+
--arg bank "$BANK" \
|
|
55
|
+
--arg file "$REL_PATH" \
|
|
56
|
+
--arg ext "$EXT" \
|
|
57
|
+
--arg ctx "code-edit" \
|
|
58
|
+
--arg text "$RETAIN_TEXT" \
|
|
59
|
+
--arg snippet "$SNIPPET" \
|
|
60
|
+
--argjson len $CONTENT_LEN \
|
|
61
|
+
--argjson auto true \
|
|
62
|
+
'{
|
|
63
|
+
event: "retain",
|
|
64
|
+
bank: $bank,
|
|
65
|
+
context: $ctx,
|
|
66
|
+
file: $file,
|
|
67
|
+
ext: $ext,
|
|
68
|
+
content_len: $len,
|
|
69
|
+
snippet: $snippet,
|
|
70
|
+
retained_text: $text,
|
|
71
|
+
source: "auto_posttooluse"
|
|
72
|
+
}')"
|
|
73
|
+
|
|
74
|
+
exit 0
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Claude Code Stop hook: capture session summary in Hindsight + write journal entry.
|
|
3
|
+
# Gracefully exits if hindsight CLI is not installed.
|
|
4
|
+
#
|
|
5
|
+
# Hardening notes (2026-05-11):
|
|
6
|
+
# - Every external call is wrapped in `timeout` so a wedged Hindsight API
|
|
7
|
+
# (or any other downstream) can't anchor the hook beyond a known bound.
|
|
8
|
+
# - The journal-writer pipe was bugged: `printf ... | setsid CMD </dev/null`
|
|
9
|
+
# had its pipe data discarded because the explicit /dev/null redirect on
|
|
10
|
+
# the setsid command overrode the pipe. Fixed by writing $INPUT to a temp
|
|
11
|
+
# file and feeding it via `< $tmp` (no pipe → no override).
|
|
12
|
+
# - Claude Code's hook contract waits for the foreground process AND any
|
|
13
|
+
# inherited stdio fds to close. setsid+nohup+disown handles process
|
|
14
|
+
# detachment; the explicit fd redirects (now ordered correctly) close out
|
|
15
|
+
# the parent's pipe so the harness can return immediately.
|
|
16
|
+
set -uo pipefail
|
|
17
|
+
|
|
18
|
+
HS_BIN="${HOME}/.local/bin/hindsight"
|
|
19
|
+
|
|
20
|
+
# Stdin holds the Stop hook JSON ({session_id, transcript_path, cwd, ...}).
|
|
21
|
+
# Persist it to a temp file so we can deliver it to a detached child via
|
|
22
|
+
# fd redirect (not a pipe — see header note).
|
|
23
|
+
INPUT_TMP=$(mktemp -t hindsight-stop-input.XXXXXX)
|
|
24
|
+
cat > "$INPUT_TMP" 2>/dev/null || echo "{}" > "$INPUT_TMP"
|
|
25
|
+
|
|
26
|
+
# Best-effort cleanup. The journal writer reads $INPUT_TMP early in its run,
|
|
27
|
+
# so a short delay before unlinking is safe; we just trust the OS to GC the
|
|
28
|
+
# inode after both readers exit. No trap needed.
|
|
29
|
+
|
|
30
|
+
# 1. Write the journal entry (uses per-session telemetry log).
|
|
31
|
+
# Fully daemonize: setsid + nohup + closed std fds so the writer survives
|
|
32
|
+
# after this hook returns. The reflect step can take 30+ seconds, and
|
|
33
|
+
# Claude Code reaps the hook's process group when the foreground command
|
|
34
|
+
# returns — without setsid the writer gets SIGHUP'd mid-call.
|
|
35
|
+
JOURNAL_WRITER="$(dirname "${BASH_SOURCE[0]}")/hindsight-journal-write.sh"
|
|
36
|
+
if [[ -x "$JOURNAL_WRITER" ]]; then
|
|
37
|
+
setsid nohup "$JOURNAL_WRITER" \
|
|
38
|
+
< "$INPUT_TMP" \
|
|
39
|
+
> /dev/null 2>&1 &
|
|
40
|
+
disown 2>/dev/null || true
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# 2. Record a session-end marker memory (legacy behavior). Same detach pattern.
|
|
44
|
+
# Wrapped in `timeout 3` defensively even though it's already detached:
|
|
45
|
+
# if a future change ever runs this synchronously, the bound still holds.
|
|
46
|
+
if [[ -x "$HS_BIN" ]]; then
|
|
47
|
+
# shellcheck source=lib/hindsight-bank.sh
|
|
48
|
+
source "$(dirname "${BASH_SOURCE[0]}")/lib/hindsight-bank.sh"
|
|
49
|
+
BANK=$(resolve_bank)
|
|
50
|
+
setsid nohup timeout 30 "$HS_BIN" memory retain "$BANK" \
|
|
51
|
+
"Session ended at $(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
52
|
+
--context "session-summary" \
|
|
53
|
+
< /dev/null > /dev/null 2>&1 &
|
|
54
|
+
disown 2>/dev/null || true
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
exit 0
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Shared bank resolver for Hindsight hooks.
|
|
3
|
+
# Source this file, then call: BANK=$(resolve_bank)
|
|
4
|
+
#
|
|
5
|
+
# Resolution order (first non-empty wins):
|
|
6
|
+
# 1. .hindsight/bank file in repo root (explicit override; written by Dream agent or by hand)
|
|
7
|
+
# 2. HINDSIGHT_BANK env var (per-shell override; useful for ad-hoc routing)
|
|
8
|
+
# 3. GitHub remote repo name (origin) e.g. "delorenj/claude-runtime" -> "claude-runtime"
|
|
9
|
+
# 4. Local repo root basename (fallback when no remote configured)
|
|
10
|
+
# 5. "general" (when not in a git repo at all)
|
|
11
|
+
#
|
|
12
|
+
# The override file format is a single line containing the bank name. Whitespace
|
|
13
|
+
# and a trailing newline are stripped. Lines starting with '#' are treated as
|
|
14
|
+
# comments and ignored.
|
|
15
|
+
|
|
16
|
+
resolve_bank() {
|
|
17
|
+
local url name root override
|
|
18
|
+
|
|
19
|
+
root=$(git rev-parse --show-toplevel 2>/dev/null || true)
|
|
20
|
+
|
|
21
|
+
# 1. Repo-local override file
|
|
22
|
+
if [[ -n "$root" && -f "$root/.hindsight/bank" ]]; then
|
|
23
|
+
override=$(grep -v '^[[:space:]]*#' "$root/.hindsight/bank" 2>/dev/null \
|
|
24
|
+
| head -n1 \
|
|
25
|
+
| tr -d '[:space:]')
|
|
26
|
+
if [[ -n "$override" ]]; then
|
|
27
|
+
echo "$override"
|
|
28
|
+
return
|
|
29
|
+
fi
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# 2. Env var override
|
|
33
|
+
if [[ -n "${HINDSIGHT_BANK:-}" ]]; then
|
|
34
|
+
echo "$HINDSIGHT_BANK"
|
|
35
|
+
return
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# 3. GitHub remote name
|
|
39
|
+
url=$(git remote get-url origin 2>/dev/null || true)
|
|
40
|
+
if [[ -n "$url" ]]; then
|
|
41
|
+
url="${url%.git}"
|
|
42
|
+
name="${url##*/}"
|
|
43
|
+
if [[ -n "$name" ]]; then
|
|
44
|
+
echo "$name"
|
|
45
|
+
return
|
|
46
|
+
fi
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# 4. Repo root basename
|
|
50
|
+
if [[ -n "$root" ]]; then
|
|
51
|
+
basename "$root"
|
|
52
|
+
return
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# 5. Final fallback
|
|
56
|
+
echo "general"
|
|
57
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Shared telemetry-logging helpers for the Hindsight journal pipeline.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# source "~/.agents/hooks/lib/hindsight-journal.sh"
|
|
6
|
+
# journal_log "$SESSION_ID" '{"event":"recall","bank":"foo",...}'
|
|
7
|
+
#
|
|
8
|
+
# Each session's events are appended to a per-session JSONL file:
|
|
9
|
+
# ~/.agents/journal/sessions/<session_id>.jsonl
|
|
10
|
+
#
|
|
11
|
+
# The Stop hook reads this file at session-end to synthesize the journal entry,
|
|
12
|
+
# then the file is left in place (for forensics) or pruned by a separate sweeper.
|
|
13
|
+
|
|
14
|
+
HS_JOURNAL_DIR="${HS_JOURNAL_DIR:-${HOME}/.agents/journal}"
|
|
15
|
+
HS_JOURNAL_SESSIONS_DIR="${HS_JOURNAL_DIR}/sessions"
|
|
16
|
+
|
|
17
|
+
# Append one event (a JSON object string) to the current session's log.
|
|
18
|
+
# Silently no-ops if session_id is empty or jq is unavailable.
|
|
19
|
+
journal_log() {
|
|
20
|
+
local session_id="$1"
|
|
21
|
+
local event_json="$2"
|
|
22
|
+
|
|
23
|
+
[[ -z "$session_id" ]] && return 0
|
|
24
|
+
[[ -z "$event_json" ]] && return 0
|
|
25
|
+
command -v jq >/dev/null 2>&1 || return 0
|
|
26
|
+
|
|
27
|
+
mkdir -p "$HS_JOURNAL_SESSIONS_DIR" 2>/dev/null || return 0
|
|
28
|
+
|
|
29
|
+
local log_file="${HS_JOURNAL_SESSIONS_DIR}/${session_id}.jsonl"
|
|
30
|
+
local ts
|
|
31
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
32
|
+
|
|
33
|
+
# Validate + inject timestamp; drop the event silently if it isn't valid JSON.
|
|
34
|
+
printf '%s' "$event_json" |
|
|
35
|
+
jq -c --arg ts "$ts" '. + {ts: $ts}' >>"$log_file" 2>/dev/null ||
|
|
36
|
+
true
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Extract session_id from Claude Code hook JSON on stdin.
|
|
40
|
+
# Echoes the id (or empty string). The caller is expected to have already cat'd stdin.
|
|
41
|
+
journal_session_id_from() {
|
|
42
|
+
local input="$1"
|
|
43
|
+
command -v jq >/dev/null 2>&1 || {
|
|
44
|
+
echo ""
|
|
45
|
+
return 0
|
|
46
|
+
}
|
|
47
|
+
echo "$input" | jq -r '.session_id // empty' 2>/dev/null || echo ""
|
|
48
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "SINGLE SOURCE OF TRUTH for this repo's project-scoped agent hooks. Hand-edit ONLY this file, then run `mise run hooks-sync` (or re-cd into the repo) to regenerate every per-agent config. Generated files are NOT hand-edited. Pattern: the /ssot-fanout skill. See .agents/hooks/README.md.",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"marker": "project-agent-hooks",
|
|
5
|
+
"hooks": [
|
|
6
|
+
{
|
|
7
|
+
"id": "skill-check-reminder",
|
|
8
|
+
"lifecycle": "user_prompt",
|
|
9
|
+
"script": "reminder-for-skill-check.sh",
|
|
10
|
+
"timeout_s": 3,
|
|
11
|
+
"reads_stdin": false,
|
|
12
|
+
"description": "Inject a project-skills + BMAD-recap reminder into each prompt."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "hindsight-recall",
|
|
16
|
+
"lifecycle": "user_prompt",
|
|
17
|
+
"script": "hindsight/hindsight-recall.sh",
|
|
18
|
+
"timeout_s": 5,
|
|
19
|
+
"reads_stdin": true,
|
|
20
|
+
"description": "Recall Hindsight memories for the prompt (no-ops gracefully if the hindsight CLI is absent)."
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"id": "hindsight-retain",
|
|
24
|
+
"lifecycle": "post_tool",
|
|
25
|
+
"script": "hindsight/hindsight-retain.sh",
|
|
26
|
+
"matcher": "Write|Edit|MultiEdit",
|
|
27
|
+
"timeout_s": 5,
|
|
28
|
+
"reads_stdin": true,
|
|
29
|
+
"description": "Retain file edits into Hindsight after Write/Edit/MultiEdit."
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "hindsight-session-end",
|
|
33
|
+
"lifecycle": "session_end",
|
|
34
|
+
"script": "hindsight/hindsight-session-end.sh",
|
|
35
|
+
"timeout_s": 5,
|
|
36
|
+
"reads_stdin": true,
|
|
37
|
+
"description": "Capture a session summary + write a Hindsight journal entry on stop."
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"agents": {
|
|
41
|
+
"claude": {
|
|
42
|
+
"enabled": true,
|
|
43
|
+
"dialect": "claude_settings",
|
|
44
|
+
"config_target": ".claude/settings.json",
|
|
45
|
+
"base_dir": "$CLAUDE_PROJECT_DIR/.agents/hooks",
|
|
46
|
+
"timeout_unit": "s",
|
|
47
|
+
"owns_hooks_key": true,
|
|
48
|
+
"lifecycle_events": {
|
|
49
|
+
"user_prompt": "UserPromptSubmit",
|
|
50
|
+
"post_tool": "PostToolUse",
|
|
51
|
+
"session_end": "Stop"
|
|
52
|
+
},
|
|
53
|
+
"notes": "Committed to the repo, so every dev gets these automatically with NO bootstrap. Claude expands $CLAUDE_PROJECT_DIR in hook commands at runtime. sync owns the entire `hooks` key of this file."
|
|
54
|
+
},
|
|
55
|
+
"codex": {
|
|
56
|
+
"enabled": true,
|
|
57
|
+
"dialect": "codex_hooks",
|
|
58
|
+
"config_target": "~/.codex/hooks.json",
|
|
59
|
+
"base_dir": "{repo}/.agents/hooks",
|
|
60
|
+
"timeout_unit": "ms",
|
|
61
|
+
"lifecycle_events": {
|
|
62
|
+
"user_prompt": "UserPromptSubmit",
|
|
63
|
+
"post_tool": "PostToolUse",
|
|
64
|
+
"session_end": "Stop"
|
|
65
|
+
},
|
|
66
|
+
"notes": "Codex has no project-scoped hook file, so sync INJECTS absolute-path entries into the per-user ~/.codex/hooks.json on `mise enter` and REMOVES them on `mise leave`. Idempotent; backs up to ~/.codex/hooks.json.caf-bak before first write. Set CAF_HOOKS_SKIP_CODEX=1 to opt out (e.g. if you already run these hooks globally)."
|
|
67
|
+
},
|
|
68
|
+
"hermes": {
|
|
69
|
+
"enabled": true,
|
|
70
|
+
"dialect": "hermes_config",
|
|
71
|
+
"config_target": "agents/hermes/pm/runtime/config.yaml",
|
|
72
|
+
"allowlist_target": "agents/hermes/pm/runtime/shell-hooks-allowlist.json",
|
|
73
|
+
"adapter": "hermes/hindsight-hook.sh",
|
|
74
|
+
"runner": "bash {repo}/.agents/hooks/hermes/hindsight-hook.sh",
|
|
75
|
+
"timeout_s": 5,
|
|
76
|
+
"lifecycle_events": {
|
|
77
|
+
"post_tool": "post_tool_call",
|
|
78
|
+
"session_end": "on_session_end"
|
|
79
|
+
},
|
|
80
|
+
"notes": "Hermes runs hooks shell=False (argv) with the payload as JSON on stdin and requires commands in shell-hooks-allowlist.json. It has NO user-prompt event, so hindsight-recall is not wired. Instead of the Claude-shaped scripts, Hermes uses the ADAPTER (hermes/hindsight-hook.sh) which translates the Hermes payload and pins the project bank (repo basename) (resolve_bank from the runtime cwd would resolve to the PM submodule). sync merges into the per-deployment runtime config.yaml + allowlist (idempotent, backed up, skipped if the runtime is absent). Disable per-dev via local.json disabled_agents:[\"hermes\"]."
|
|
81
|
+
},
|
|
82
|
+
"kimi": {
|
|
83
|
+
"enabled": true,
|
|
84
|
+
"dialect": "kimi_config",
|
|
85
|
+
"config_target": "~/.kimi-code/config.toml",
|
|
86
|
+
"config_home_env": "KIMI_CODE_HOME",
|
|
87
|
+
"base_dir": "{repo}/.agents/hooks",
|
|
88
|
+
"timeout_unit": "s",
|
|
89
|
+
"lifecycle_events": {
|
|
90
|
+
"user_prompt": "UserPromptSubmit",
|
|
91
|
+
"post_tool": "PostToolUse",
|
|
92
|
+
"session_end": "Stop"
|
|
93
|
+
},
|
|
94
|
+
"notes": "Kimi Code CLI hooks live in the per-user ~/.kimi-code/config.toml (KIMI_CODE_HOME overrides) as a `hooks` array of {event,command,matcher?,timeout}. Kimi is Claude-compatible: identical event names, payload {hook_event_name,session_id,cwd,prompt} / {tool_name,tool_input} on stdin, shell:true commands, timeout in SECONDS, edit tools named Write/Edit. So it reuses the SAME scripts (guard-wrapped) as claude/codex. No project-local config.toml exists, so sync INJECTS a sentinel-bounded [[hooks]] block on enter and removes it on leave (idempotent text-merge, backs up to config.toml.caf-bak). Disable per-dev via local.json disabled_agents:[\"kimi\"]."
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Per-dev runtime opt-out wrapper for a single hook.
|
|
3
|
+
#
|
|
4
|
+
# hook-guard.sh <hook-id> <command> [args...]
|
|
5
|
+
#
|
|
6
|
+
# If <hook-id> is listed in .agents/local.json `.hooks.disabled[]`, exits 0
|
|
7
|
+
# WITHOUT running the command (silent success — no "hook failed" noise in the
|
|
8
|
+
# agent). Otherwise execs the command, passing stdin straight through so the
|
|
9
|
+
# real hook still receives its JSON payload.
|
|
10
|
+
#
|
|
11
|
+
# This is how a dev disables an individual hook even for Claude, whose hook
|
|
12
|
+
# config is committed (and therefore the same for everyone): the committed
|
|
13
|
+
# command is the guarded form, and the guard consults each dev's local.json at
|
|
14
|
+
# runtime.
|
|
15
|
+
set -uo pipefail
|
|
16
|
+
|
|
17
|
+
HOOK_ID="${1:-}"
|
|
18
|
+
shift || true
|
|
19
|
+
|
|
20
|
+
# shellcheck source=local-config.sh
|
|
21
|
+
source "$(dirname "${BASH_SOURCE[0]}")/local-config.sh"
|
|
22
|
+
|
|
23
|
+
if [[ -n "$HOOK_ID" ]] && hook_disabled "$HOOK_ID"; then
|
|
24
|
+
exit 0
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# Nothing to run (defensive) — succeed quietly.
|
|
28
|
+
[[ $# -eq 0 ]] && exit 0
|
|
29
|
+
|
|
30
|
+
exec "$@"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Sourceable helpers for per-dev `.agents/local.json` overrides.
|
|
3
|
+
#
|
|
4
|
+
# Source this, then call:
|
|
5
|
+
# hook_disabled <hook-id> # true if .hooks.disabled[] contains the id
|
|
6
|
+
# agent_disabled <agent> # true if .hooks.disabled_agents[] contains the agent
|
|
7
|
+
# skill_disabled <skill-name> # true if .skills.disabled[] contains the name
|
|
8
|
+
#
|
|
9
|
+
# All FAIL OPEN (return 1 = "not disabled") when `.agents/local.json` or `jq` is
|
|
10
|
+
# absent, so a missing/garbled local config can never silently kill hooks/skills.
|
|
11
|
+
#
|
|
12
|
+
# `.agents/local.json` is gitignored — each dev owns their own. See
|
|
13
|
+
# `.agents/local.example.json` for the schema.
|
|
14
|
+
|
|
15
|
+
# Repo root, resolved from this lib's location (.agents/hooks/lib/ -> ../../..).
|
|
16
|
+
_caf_local_json() {
|
|
17
|
+
local d
|
|
18
|
+
d="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." 2>/dev/null && pwd)" || return 1
|
|
19
|
+
printf '%s/.agents/local.json' "$d"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# _caf_listed <jq-array-path> <value> -> 0 if value is in the array.
|
|
23
|
+
_caf_listed() {
|
|
24
|
+
local jq_path="$1" val="$2" f
|
|
25
|
+
f="$(_caf_local_json)" || return 1
|
|
26
|
+
[[ -f "$f" ]] || return 1
|
|
27
|
+
command -v jq >/dev/null 2>&1 || return 1
|
|
28
|
+
jq -e --arg v "$val" "((${jq_path} // []) | index(\$v)) != null" "$f" >/dev/null 2>&1
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
hook_disabled() { _caf_listed '.hooks.disabled' "$1"; }
|
|
32
|
+
agent_disabled() { _caf_listed '.hooks.disabled_agents' "$1"; }
|
|
33
|
+
skill_disabled() { _caf_listed '.skills.disabled' "$1"; }
|
|
34
|
+
|
|
35
|
+
# True if the dev opted to let their GLOBAL agent system (~/.agents/skills) provide
|
|
36
|
+
# any overlapping skill, so the project linker should skip it (no duplicates).
|
|
37
|
+
# Teammates with no global layer omit this and inherit the full project set.
|
|
38
|
+
skills_defer_to_global() {
|
|
39
|
+
local f
|
|
40
|
+
f="$(_caf_local_json)" || return 1
|
|
41
|
+
[[ -f "$f" ]] || return 1
|
|
42
|
+
command -v jq >/dev/null 2>&1 || return 1
|
|
43
|
+
jq -e '.skills.defer_to_global == true' "$f" >/dev/null 2>&1
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# True if <skill-name> is provided by the global agent SSOT. `-e` follows the
|
|
47
|
+
# ~/.agents/skills symlink (-> skillex/skill-sets/global) and its entries.
|
|
48
|
+
skill_is_global() {
|
|
49
|
+
local name="$1" gdir="${AGENTS_GLOBAL_SKILLS_DIR:-$HOME/.agents/skills}"
|
|
50
|
+
[[ -e "${gdir}/${name}" ]]
|
|
51
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# UserPromptSubmit hook (PROJECT-SCOPED).
|
|
3
|
+
#
|
|
4
|
+
# Nudges the agent to check this project's skills and resume BMAD context.
|
|
5
|
+
# Portable across developers: the project's skills directory is resolved
|
|
6
|
+
# RELATIVE to this script's location, not a hardcoded home path — so the same
|
|
7
|
+
# committed copy works for every dev who clones the repo.
|
|
8
|
+
#
|
|
9
|
+
# stdout from a UserPromptSubmit hook is injected into the prompt as context.
|
|
10
|
+
set -uo pipefail
|
|
11
|
+
|
|
12
|
+
# This script lives at <repo>/.agents/hooks/reminder-for-skill-check.sh
|
|
13
|
+
HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
|
+
PROJECT_ROOT="$(cd "${HOOK_DIR}/../.." && pwd)"
|
|
15
|
+
SKILLS_DIR="${PROJECT_ROOT}/.agents/skills"
|
|
16
|
+
|
|
17
|
+
echo "⚡ REMINDER: Before starting, check if any skills in ${SKILLS_DIR}/ are relevant to this request."
|
|
18
|
+
echo " - If this project uses the BMAD method (a ./_bmad* folder exists) start the session with a brief recap of where the last session left off and suggest the next logical step. If there are options, lay them out, think it through, then offer your recommendation. ⚡"
|
|
19
|
+
echo "> NOTE: Treat docs with a grain of salt — this is a fast-moving solo project, so stale data is likely. Gauge confidence with recency: run 'llr' (alias for 'fdfind --type f --hidden --exclude .git -X ls -lt --time=ctime -r --color=auto') and use mtime as a compass correlating mutation-recency with local relevance."
|
|
20
|
+
exit 0
|