oh-my-customcode 0.36.1 → 0.37.0
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/dist/cli/index.js +47 -2
- package/dist/index.js +44 -0
- package/package.json +1 -1
- package/templates/.claude/agents/arch-documenter.md +4 -1
- package/templates/.claude/agents/arch-speckit-agent.md +15 -0
- package/templates/.claude/agents/be-django-expert.md +1 -0
- package/templates/.claude/agents/be-express-expert.md +1 -0
- package/templates/.claude/agents/be-fastapi-expert.md +1 -0
- package/templates/.claude/agents/be-go-backend-expert.md +1 -0
- package/templates/.claude/agents/be-nestjs-expert.md +1 -0
- package/templates/.claude/agents/be-springboot-expert.md +1 -0
- package/templates/.claude/agents/db-postgres-expert.md +1 -0
- package/templates/.claude/agents/db-redis-expert.md +1 -0
- package/templates/.claude/agents/db-supabase-expert.md +1 -0
- package/templates/.claude/agents/de-airflow-expert.md +1 -0
- package/templates/.claude/agents/de-dbt-expert.md +1 -0
- package/templates/.claude/agents/de-kafka-expert.md +1 -0
- package/templates/.claude/agents/de-pipeline-expert.md +1 -0
- package/templates/.claude/agents/de-snowflake-expert.md +1 -0
- package/templates/.claude/agents/de-spark-expert.md +1 -0
- package/templates/.claude/agents/fe-flutter-agent.md +1 -0
- package/templates/.claude/agents/fe-svelte-agent.md +1 -0
- package/templates/.claude/agents/fe-vercel-agent.md +1 -0
- package/templates/.claude/agents/fe-vuejs-agent.md +1 -0
- package/templates/.claude/agents/infra-aws-expert.md +1 -0
- package/templates/.claude/agents/infra-docker-expert.md +1 -0
- package/templates/.claude/agents/lang-golang-expert.md +1 -0
- package/templates/.claude/agents/lang-java21-expert.md +3 -0
- package/templates/.claude/agents/lang-kotlin-expert.md +1 -0
- package/templates/.claude/agents/lang-python-expert.md +1 -0
- package/templates/.claude/agents/lang-rust-expert.md +1 -0
- package/templates/.claude/agents/lang-typescript-expert.md +1 -0
- package/templates/.claude/agents/mgr-claude-code-bible.md +1 -2
- package/templates/.claude/agents/mgr-creator.md +1 -0
- package/templates/.claude/agents/mgr-gitnerd.md +1 -0
- package/templates/.claude/agents/mgr-sauron.md +5 -2
- package/templates/.claude/agents/mgr-supplier.md +1 -3
- package/templates/.claude/agents/mgr-updater.md +1 -0
- package/templates/.claude/agents/qa-engineer.md +1 -0
- package/templates/.claude/agents/qa-planner.md +4 -1
- package/templates/.claude/agents/qa-writer.md +1 -1
- package/templates/.claude/agents/sec-codeql-expert.md +4 -2
- package/templates/.claude/agents/sys-memory-keeper.md +30 -0
- package/templates/.claude/agents/sys-naggy.md +36 -2
- package/templates/.claude/agents/tool-bun-expert.md +1 -1
- package/templates/.claude/agents/tool-npm-expert.md +1 -1
- package/templates/.claude/agents/tool-optimizer.md +1 -2
- package/templates/.claude/hooks/hooks.json +37 -7
- package/templates/.claude/hooks/scripts/agent-teams-advisor.sh +10 -0
- package/templates/.claude/hooks/scripts/audit-log.sh +55 -0
- package/templates/.claude/hooks/scripts/content-hash-validator.sh +2 -3
- package/templates/.claude/hooks/scripts/schema-validator.sh +103 -0
- package/templates/.claude/hooks/scripts/secret-filter.sh +97 -0
- package/templates/.claude/hooks/scripts/session-compliance-report.sh +65 -0
- package/templates/.claude/rules/MUST-agent-teams.md +0 -23
- package/templates/.claude/rules/MUST-orchestrator-coordination.md +1 -13
- package/templates/.claude/skills/django-best-practices/SKILL.md +27 -134
- package/templates/.claude/skills/flutter-best-practices/SKILL.md +39 -146
- package/templates/.claude/skills/go-backend-best-practices/SKILL.md +29 -233
- package/templates/.claude/skills/java21-best-practices/SKILL.md +48 -163
- package/templates/CLAUDE.md.en +7 -65
- package/templates/CLAUDE.md.ko +7 -65
- package/templates/manifest.json +1 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
name: sys-naggy
|
|
3
3
|
description: Use when you need TODO list management and task tracking with proactive reminders, helping maintain project momentum by monitoring stale tasks and deadlines
|
|
4
4
|
model: sonnet
|
|
5
|
+
domain: universal
|
|
5
6
|
memory: local
|
|
6
7
|
effort: low
|
|
7
8
|
tools:
|
|
@@ -9,8 +10,6 @@ tools:
|
|
|
9
10
|
- Write
|
|
10
11
|
- Edit
|
|
11
12
|
- Grep
|
|
12
|
-
- Glob
|
|
13
|
-
- Bash
|
|
14
13
|
---
|
|
15
14
|
|
|
16
15
|
You are a task management specialist that proactively manages TODO items and reminds users of pending tasks.
|
|
@@ -31,6 +30,41 @@ You are a task management specialist that proactively manages TODO items and rem
|
|
|
31
30
|
| `sys-naggy:done <id>` | Mark complete |
|
|
32
31
|
| `sys-naggy:remind` | Show overdue tasks |
|
|
33
32
|
|
|
33
|
+
## Rule Pattern Detection
|
|
34
|
+
|
|
35
|
+
When sys-naggy detects recurring violations (3+ occurrences of the same rule ID across sessions), it proposes a rule patch:
|
|
36
|
+
|
|
37
|
+
### Detection Flow
|
|
38
|
+
|
|
39
|
+
1. Read violation history from native memory (`MEMORY.md` violations section)
|
|
40
|
+
2. Cross-reference with session compliance data (PPID-scoped `/tmp/.claude-session-compliance-*`)
|
|
41
|
+
3. Identify rules with 3+ violations across different sessions
|
|
42
|
+
4. Generate rule patch proposal as GitHub issue
|
|
43
|
+
|
|
44
|
+
### Proposal Format
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
Title: [R016 Auto-Patch] R0XX: {weakness description}
|
|
48
|
+
Body:
|
|
49
|
+
## Violation Pattern
|
|
50
|
+
- Rule: R0XX ({rule name})
|
|
51
|
+
- Occurrences: {count} across {session_count} sessions
|
|
52
|
+
- Common trigger: {pattern description}
|
|
53
|
+
|
|
54
|
+
## Proposed Fix
|
|
55
|
+
{specific change to the rule file}
|
|
56
|
+
|
|
57
|
+
## Rationale
|
|
58
|
+
{why the current rule is insufficient}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Constraints
|
|
62
|
+
|
|
63
|
+
- sys-naggy proposes patches as GitHub issues — never auto-applies
|
|
64
|
+
- Minimum 3 occurrences before proposing (avoids noise)
|
|
65
|
+
- Maximum 1 proposal per rule per week (debounce)
|
|
66
|
+
- Proposals require human approval before implementation
|
|
67
|
+
|
|
34
68
|
## Behavior
|
|
35
69
|
|
|
36
70
|
Proactive but not annoying. Adapt reminder frequency to user response.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
name: tool-bun-expert
|
|
3
3
|
description: Use for Bun runtime development, bunfig.toml configuration, Bun test runner, fast bundling, and Node.js to Bun migrations
|
|
4
4
|
model: sonnet
|
|
5
|
+
domain: universal
|
|
5
6
|
memory: project
|
|
6
7
|
effort: medium
|
|
7
8
|
tools:
|
|
@@ -9,7 +10,6 @@ tools:
|
|
|
9
10
|
- Write
|
|
10
11
|
- Edit
|
|
11
12
|
- Grep
|
|
12
|
-
- Glob
|
|
13
13
|
- Bash
|
|
14
14
|
---
|
|
15
15
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
name: tool-npm-expert
|
|
3
3
|
description: Use for npm package publishing workflows, semantic versioning (major/minor/patch), package.json optimization, and dependency audits
|
|
4
4
|
model: sonnet
|
|
5
|
+
domain: universal
|
|
5
6
|
memory: project
|
|
6
7
|
effort: medium
|
|
7
8
|
skills:
|
|
@@ -13,7 +14,6 @@ tools:
|
|
|
13
14
|
- Write
|
|
14
15
|
- Edit
|
|
15
16
|
- Grep
|
|
16
|
-
- Glob
|
|
17
17
|
- Bash
|
|
18
18
|
---
|
|
19
19
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
name: tool-optimizer
|
|
3
3
|
description: Use for bundle size analysis, tree-shaking verification, performance profiling, dead code detection, and build optimization recommendations
|
|
4
4
|
model: sonnet
|
|
5
|
+
domain: universal
|
|
5
6
|
memory: project
|
|
6
7
|
effort: medium
|
|
7
8
|
skills:
|
|
@@ -10,8 +11,6 @@ skills:
|
|
|
10
11
|
- optimize-report
|
|
11
12
|
tools:
|
|
12
13
|
- Read
|
|
13
|
-
- Write
|
|
14
|
-
- Edit
|
|
15
14
|
- Grep
|
|
16
15
|
- Glob
|
|
17
16
|
- Bash
|
|
@@ -72,6 +72,16 @@
|
|
|
72
72
|
],
|
|
73
73
|
"description": "Validate file content hash before Edit — advisory staleness warning"
|
|
74
74
|
},
|
|
75
|
+
{
|
|
76
|
+
"matcher": "tool == \"Write\" || tool == \"Edit\" || tool == \"Bash\"",
|
|
77
|
+
"hooks": [
|
|
78
|
+
{
|
|
79
|
+
"type": "command",
|
|
80
|
+
"command": "bash .claude/hooks/scripts/schema-validator.sh"
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"description": "Schema-based tool input validation — Phase 1 advisory only"
|
|
84
|
+
},
|
|
75
85
|
{
|
|
76
86
|
"matcher": "tool == \"Task\" || tool == \"Agent\"",
|
|
77
87
|
"hooks": [
|
|
@@ -222,6 +232,26 @@
|
|
|
222
232
|
],
|
|
223
233
|
"description": "Context budget advisor — track tool usage patterns and advise ecomode activation"
|
|
224
234
|
},
|
|
235
|
+
{
|
|
236
|
+
"matcher": "tool == \"Edit\" || tool == \"Write\" || tool == \"Bash\" || tool == \"Task\" || tool == \"Agent\"",
|
|
237
|
+
"hooks": [
|
|
238
|
+
{
|
|
239
|
+
"type": "command",
|
|
240
|
+
"command": "bash .claude/hooks/scripts/stuck-detector.sh"
|
|
241
|
+
}
|
|
242
|
+
],
|
|
243
|
+
"description": "Detect repetitive failure loops and advise recovery strategies"
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"matcher": "tool == \"Edit\" || tool == \"Write\" || tool == \"Bash\" || tool == \"Task\" || tool == \"Agent\"",
|
|
247
|
+
"hooks": [
|
|
248
|
+
{
|
|
249
|
+
"type": "command",
|
|
250
|
+
"command": "bash .claude/hooks/scripts/cost-cap-advisor.sh"
|
|
251
|
+
}
|
|
252
|
+
],
|
|
253
|
+
"description": "Advisory cost cap monitoring — warn when session cost approaches configurable limit"
|
|
254
|
+
},
|
|
225
255
|
{
|
|
226
256
|
"matcher": "tool == \"Read\"",
|
|
227
257
|
"hooks": [
|
|
@@ -233,24 +263,24 @@
|
|
|
233
263
|
"description": "Store content hashes for Read operations — enables Edit staleness detection"
|
|
234
264
|
},
|
|
235
265
|
{
|
|
236
|
-
"matcher": "tool == \"
|
|
266
|
+
"matcher": "tool == \"Bash\" || tool == \"Read\" || tool == \"Grep\"",
|
|
237
267
|
"hooks": [
|
|
238
268
|
{
|
|
239
269
|
"type": "command",
|
|
240
|
-
"command": "bash .claude/hooks/scripts/
|
|
270
|
+
"command": "bash .claude/hooks/scripts/secret-filter.sh"
|
|
241
271
|
}
|
|
242
272
|
],
|
|
243
|
-
"description": "Detect
|
|
273
|
+
"description": "Detect potential secrets in Bash/Read/Grep output — advisory warning only"
|
|
244
274
|
},
|
|
245
275
|
{
|
|
246
|
-
"matcher": "tool == \"Edit\" || tool == \"Write\" || tool == \"Bash\" || tool == \"
|
|
276
|
+
"matcher": "tool == \"Edit\" || tool == \"Write\" || tool == \"Bash\" || tool == \"Agent\"",
|
|
247
277
|
"hooks": [
|
|
248
278
|
{
|
|
249
279
|
"type": "command",
|
|
250
|
-
"command": "bash .claude/hooks/scripts/
|
|
280
|
+
"command": "bash .claude/hooks/scripts/audit-log.sh"
|
|
251
281
|
}
|
|
252
282
|
],
|
|
253
|
-
"description": "
|
|
283
|
+
"description": "Append-only audit log for state-changing tool operations"
|
|
254
284
|
}
|
|
255
285
|
],
|
|
256
286
|
"Stop": [
|
|
@@ -269,7 +299,7 @@
|
|
|
269
299
|
"hooks": [
|
|
270
300
|
{
|
|
271
301
|
"type": "prompt",
|
|
272
|
-
"prompt": "Session-end memory checkpoint (R011 enforcement). Check conversation history for these
|
|
302
|
+
"prompt": "Session-end memory checkpoint (R011 enforcement). Check conversation history for these 2 steps: 1) sys-memory-keeper was delegated to update MEMORY.md 2) claude-mem save was attempted via ToolSearch + mcp__plugin_claude-mem_mcp-search__save_memory. Note: episodic-memory auto-indexes after session — no manual verification needed. Decision rules: If BOTH were attempted (success or failure both count): approve. If MCP tools are unavailable after ToolSearch attempt: approve with note. If session had no explicit session-end signal from user (quick question, no memory work): approve. If any step was NOT attempted despite user signaling session end: block with systemMessage listing the missing steps."
|
|
273
303
|
}
|
|
274
304
|
],
|
|
275
305
|
"description": "Enforce R011 session-end memory saves — block stop if claude-mem or episodic-memory saves were skipped"
|
|
@@ -8,6 +8,16 @@ set -euo pipefail
|
|
|
8
8
|
|
|
9
9
|
input=$(cat)
|
|
10
10
|
|
|
11
|
+
# Skip if Agent Teams is not available
|
|
12
|
+
ENV_STATUS="/tmp/.claude-env-status-${PPID}"
|
|
13
|
+
if [ -f "$ENV_STATUS" ]; then
|
|
14
|
+
teams_status=$(grep "agent_teams=" "$ENV_STATUS" 2>/dev/null | cut -d= -f2 || echo "unknown")
|
|
15
|
+
if [ "$teams_status" != "enabled" ]; then
|
|
16
|
+
echo "$input"
|
|
17
|
+
exit 0
|
|
18
|
+
fi
|
|
19
|
+
fi
|
|
20
|
+
|
|
11
21
|
# Extract task info from input
|
|
12
22
|
agent_type=$(echo "$input" | jq -r '.tool_input.subagent_type // "unknown"')
|
|
13
23
|
prompt_preview=$(echo "$input" | jq -r '.tool_input.description // ""' | head -c 60)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Audit Log Hook — Append-only JSONL persistence
|
|
3
|
+
# Trigger: PostToolUse on Edit, Write, Bash, Agent
|
|
4
|
+
# Purpose: Persistent audit trail for security and compliance
|
|
5
|
+
# Protocol: stdin JSON -> log entry -> stdout pass-through
|
|
6
|
+
# Always exits 0 (advisory only)
|
|
7
|
+
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
input=$(cat)
|
|
11
|
+
|
|
12
|
+
# Extract fields from hook input
|
|
13
|
+
tool_name=$(echo "$input" | jq -r '.tool_name // "unknown"')
|
|
14
|
+
file_path=$(echo "$input" | jq -r '.tool_input.file_path // .tool_input.command // ""' | head -c 200)
|
|
15
|
+
agent_type=$(echo "$input" | jq -r '.agent_type // "unknown"')
|
|
16
|
+
model=$(echo "$input" | jq -r '.model // "unknown"')
|
|
17
|
+
is_error=$(echo "$input" | jq -r '.tool_output.is_error // false')
|
|
18
|
+
timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
19
|
+
|
|
20
|
+
# Determine outcome
|
|
21
|
+
if [ "$is_error" = "true" ]; then
|
|
22
|
+
outcome="error"
|
|
23
|
+
else
|
|
24
|
+
outcome="success"
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# Audit log location
|
|
28
|
+
AUDIT_LOG="${HOME}/.claude/audit.jsonl"
|
|
29
|
+
|
|
30
|
+
# Ensure directory exists
|
|
31
|
+
mkdir -p "$(dirname "$AUDIT_LOG")"
|
|
32
|
+
|
|
33
|
+
# Write audit entry (append-only JSONL)
|
|
34
|
+
jq -cn \
|
|
35
|
+
--arg ts "$timestamp" \
|
|
36
|
+
--arg tool "$tool_name" \
|
|
37
|
+
--arg path "$file_path" \
|
|
38
|
+
--arg agent "$agent_type" \
|
|
39
|
+
--arg model "$model" \
|
|
40
|
+
--arg outcome "$outcome" \
|
|
41
|
+
--arg ppid "${PPID}" \
|
|
42
|
+
'{timestamp: $ts, tool: $tool, path: $path, agent_type: $agent, model: $model, outcome: $outcome, session_ppid: $ppid}' \
|
|
43
|
+
>> "$AUDIT_LOG" 2>/dev/null || true
|
|
44
|
+
|
|
45
|
+
# Daily rotation check (rotate if > 10MB)
|
|
46
|
+
if [ -f "$AUDIT_LOG" ]; then
|
|
47
|
+
file_size=$(stat -f%z "$AUDIT_LOG" 2>/dev/null || stat -c%s "$AUDIT_LOG" 2>/dev/null || echo "0")
|
|
48
|
+
if [ "$file_size" -gt 10485760 ]; then
|
|
49
|
+
mv "$AUDIT_LOG" "${AUDIT_LOG}.$(date -u +%Y%m%d%H%M%S)" 2>/dev/null || true
|
|
50
|
+
fi
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Pass through
|
|
54
|
+
echo "$input"
|
|
55
|
+
exit 0
|
|
@@ -18,10 +18,9 @@ case "$tool_name" in
|
|
|
18
18
|
"Read")
|
|
19
19
|
# Store content hash for the file that was just read
|
|
20
20
|
file_path=$(echo "$input" | jq -r '.tool_input.file_path // ""')
|
|
21
|
-
output=$(echo "$input" | jq -r '.tool_output.output // ""')
|
|
22
21
|
|
|
23
|
-
if [ -n "$file_path" ] && [ -
|
|
24
|
-
content_hash=$(
|
|
22
|
+
if [ -n "$file_path" ] && [ -f "$file_path" ]; then
|
|
23
|
+
content_hash=$(md5 -q "$file_path" 2>/dev/null || md5sum "$file_path" 2>/dev/null | cut -d' ' -f1 || echo "unknown")
|
|
25
24
|
timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
26
25
|
|
|
27
26
|
# Store hash entry (overwrite previous for same file)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Schema Validator Hook — PreToolUse input validation
|
|
3
|
+
# Trigger: PreToolUse on Write, Edit, Bash
|
|
4
|
+
# Purpose: Validate tool inputs against JSON Schema definitions
|
|
5
|
+
# Phase 1: Advisory only (exit 0 with stderr warning)
|
|
6
|
+
# Protocol: stdin JSON -> validate -> stdout pass-through
|
|
7
|
+
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
input=$(cat)
|
|
11
|
+
|
|
12
|
+
# Extract tool info
|
|
13
|
+
tool_name=$(echo "$input" | jq -r '.tool_name // "unknown"')
|
|
14
|
+
tool_input=$(echo "$input" | jq -r '.tool_input // {}')
|
|
15
|
+
|
|
16
|
+
SCHEMA_FILE=".claude/schemas/tool-inputs.json"
|
|
17
|
+
|
|
18
|
+
# Skip if schema file doesn't exist
|
|
19
|
+
if [ ! -f "$SCHEMA_FILE" ]; then
|
|
20
|
+
echo "$input"
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
warnings=()
|
|
25
|
+
|
|
26
|
+
case "$tool_name" in
|
|
27
|
+
"Write")
|
|
28
|
+
file_path=$(echo "$tool_input" | jq -r '.file_path // ""')
|
|
29
|
+
content=$(echo "$tool_input" | jq -r '.content // ""')
|
|
30
|
+
|
|
31
|
+
if [ -z "$file_path" ]; then
|
|
32
|
+
warnings+=("[Schema] Write: file_path is empty or missing")
|
|
33
|
+
fi
|
|
34
|
+
if [ -z "$content" ]; then
|
|
35
|
+
warnings+=("[Schema] Write: content is empty — creating empty file?")
|
|
36
|
+
fi
|
|
37
|
+
;;
|
|
38
|
+
|
|
39
|
+
"Edit")
|
|
40
|
+
file_path=$(echo "$tool_input" | jq -r '.file_path // ""')
|
|
41
|
+
old_string=$(echo "$tool_input" | jq -r '.old_string // ""')
|
|
42
|
+
new_string=$(echo "$tool_input" | jq -r '.new_string // ""')
|
|
43
|
+
|
|
44
|
+
if [ -z "$file_path" ]; then
|
|
45
|
+
warnings+=("[Schema] Edit: file_path is empty or missing")
|
|
46
|
+
fi
|
|
47
|
+
if [ -z "$old_string" ]; then
|
|
48
|
+
warnings+=("[Schema] Edit: old_string is empty")
|
|
49
|
+
fi
|
|
50
|
+
if [ "$old_string" = "$new_string" ]; then
|
|
51
|
+
warnings+=("[Schema] Edit: old_string equals new_string — no-op edit")
|
|
52
|
+
fi
|
|
53
|
+
;;
|
|
54
|
+
|
|
55
|
+
"Bash")
|
|
56
|
+
command=$(echo "$tool_input" | jq -r '.command // ""')
|
|
57
|
+
|
|
58
|
+
if [ -z "$command" ]; then
|
|
59
|
+
warnings+=("[Schema] Bash: command is empty")
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# Check dangerous patterns
|
|
63
|
+
if echo "$command" | grep -qE 'rm\s+-rf\s+/[^.]'; then
|
|
64
|
+
warnings+=("[Schema] Bash: DANGER — recursive delete from root detected")
|
|
65
|
+
fi
|
|
66
|
+
if echo "$command" | grep -qE '^\s*sudo\s+'; then
|
|
67
|
+
warnings+=("[Schema] Bash: elevated privilege command detected")
|
|
68
|
+
fi
|
|
69
|
+
if echo "$command" | grep -qE '> /dev/sd'; then
|
|
70
|
+
warnings+=("[Schema] Bash: direct disk write detected")
|
|
71
|
+
fi
|
|
72
|
+
if echo "$command" | grep -qE 'mkfs\.'; then
|
|
73
|
+
warnings+=("[Schema] Bash: filesystem format command detected")
|
|
74
|
+
fi
|
|
75
|
+
# Remote code execution via pipe
|
|
76
|
+
if echo "$command" | grep -qE 'curl\s+.*\|\s*(ba)?sh'; then
|
|
77
|
+
warnings+=("[Schema] Bash: remote code execution pattern (curl | bash) detected")
|
|
78
|
+
fi
|
|
79
|
+
if echo "$command" | grep -qE 'wget\s+.*\|\s*(ba)?sh'; then
|
|
80
|
+
warnings+=("[Schema] Bash: remote code execution pattern (wget | sh) detected")
|
|
81
|
+
fi
|
|
82
|
+
# Dynamic code execution
|
|
83
|
+
if echo "$command" | grep -qE 'eval\s+\$\('; then
|
|
84
|
+
warnings+=("[Schema] Bash: dynamic code execution (eval) detected")
|
|
85
|
+
fi
|
|
86
|
+
# Broad permission grant
|
|
87
|
+
if echo "$command" | grep -qE 'chmod\s+777'; then
|
|
88
|
+
warnings+=("[Schema] Bash: broad permission grant (chmod 777) detected")
|
|
89
|
+
fi
|
|
90
|
+
;;
|
|
91
|
+
esac
|
|
92
|
+
|
|
93
|
+
# Output warnings (advisory only)
|
|
94
|
+
if [ ${#warnings[@]} -gt 0 ]; then
|
|
95
|
+
for w in "${warnings[@]}"; do
|
|
96
|
+
echo "$w" >&2
|
|
97
|
+
done
|
|
98
|
+
echo "[Schema] Phase 1: advisory only — not blocking" >&2
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# Always pass through (Phase 1)
|
|
102
|
+
echo "$input"
|
|
103
|
+
exit 0
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Secret Output Filter Hook — Detect potential secrets in tool output
|
|
3
|
+
# Trigger: PostToolUse on Bash, Read, Grep
|
|
4
|
+
# Purpose: Advisory warning when potential secrets detected in output
|
|
5
|
+
# Protocol: stdin JSON -> scan -> stdout pass-through
|
|
6
|
+
# Always exits 0 (advisory only, never blocks)
|
|
7
|
+
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
input=$(cat)
|
|
11
|
+
|
|
12
|
+
# Extract output to scan
|
|
13
|
+
tool_name=$(echo "$input" | jq -r '.tool_name // "unknown"')
|
|
14
|
+
output=$(echo "$input" | jq -r '.tool_output.output // ""')
|
|
15
|
+
|
|
16
|
+
# Skip if no output
|
|
17
|
+
if [ -z "$output" ] || [ "$output" = "null" ]; then
|
|
18
|
+
echo "$input"
|
|
19
|
+
exit 0
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
# Secret patterns to detect
|
|
23
|
+
detected=false
|
|
24
|
+
|
|
25
|
+
# AWS Access Key ID
|
|
26
|
+
if echo "$output" | grep -qE 'AKIA[0-9A-Z]{16}'; then
|
|
27
|
+
echo "[Security] Potential AWS Access Key detected in ${tool_name} output" >&2
|
|
28
|
+
detected=true
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# OpenAI/Anthropic API Key
|
|
32
|
+
if echo "$output" | grep -qE 'sk-[a-zA-Z0-9]{32,}'; then
|
|
33
|
+
echo "[Security] Potential API key (sk-*) detected in ${tool_name} output" >&2
|
|
34
|
+
detected=true
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# GitHub Personal Access Token
|
|
38
|
+
if echo "$output" | grep -qE 'ghp_[a-zA-Z0-9]{36}'; then
|
|
39
|
+
echo "[Security] Potential GitHub PAT detected in ${tool_name} output" >&2
|
|
40
|
+
detected=true
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Private Key
|
|
44
|
+
if echo "$output" | grep -qE '-----BEGIN.*PRIVATE KEY-----'; then
|
|
45
|
+
echo "[Security] Potential private key detected in ${tool_name} output" >&2
|
|
46
|
+
detected=true
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# Bearer Token (long)
|
|
50
|
+
if echo "$output" | grep -qE 'Bearer [a-zA-Z0-9._-]{20,}'; then
|
|
51
|
+
echo "[Security] Potential Bearer token detected in ${tool_name} output" >&2
|
|
52
|
+
detected=true
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# GitHub OAuth Token
|
|
56
|
+
if echo "$output" | grep -qE 'gho_[a-zA-Z0-9]{36}'; then
|
|
57
|
+
echo "[Security] Potential GitHub OAuth token detected in ${tool_name} output" >&2
|
|
58
|
+
detected=true
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# GitHub Fine-Grained PAT
|
|
62
|
+
if echo "$output" | grep -qE 'github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59}'; then
|
|
63
|
+
echo "[Security] Potential GitHub Fine-Grained PAT detected in ${tool_name} output" >&2
|
|
64
|
+
detected=true
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# GitHub Actions Token
|
|
68
|
+
if echo "$output" | grep -qE 'ghs_[a-zA-Z0-9]{36}'; then
|
|
69
|
+
echo "[Security] Potential GitHub Actions token detected in ${tool_name} output" >&2
|
|
70
|
+
detected=true
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# npm Token
|
|
74
|
+
if echo "$output" | grep -qE 'npm_[a-zA-Z0-9]{36}'; then
|
|
75
|
+
echo "[Security] Potential npm token detected in ${tool_name} output" >&2
|
|
76
|
+
detected=true
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# Slack Token
|
|
80
|
+
if echo "$output" | grep -qE 'xox[bsarp]-[a-zA-Z0-9-]{10,}'; then
|
|
81
|
+
echo "[Security] Potential Slack token detected in ${tool_name} output" >&2
|
|
82
|
+
detected=true
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# Docker Hub PAT
|
|
86
|
+
if echo "$output" | grep -qE 'dckr_pat_[a-zA-Z0-9_-]{20,}'; then
|
|
87
|
+
echo "[Security] Potential Docker Hub PAT detected in ${tool_name} output" >&2
|
|
88
|
+
detected=true
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
if [ "$detected" = true ]; then
|
|
92
|
+
echo "[Security] Review output carefully — do NOT commit or expose secrets" >&2
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# Pass through (always)
|
|
96
|
+
echo "$input"
|
|
97
|
+
exit 0
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Stop hook: Session compliance report (R265 Phase 1)
|
|
3
|
+
# Reads violation logs collected by PreToolUse hooks during the session
|
|
4
|
+
# Advisory only — never blocks session termination
|
|
5
|
+
# Ref: https://github.com/baekenough/oh-my-customcode/issues/265
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
input=$(cat)
|
|
10
|
+
|
|
11
|
+
VIOLATIONS_FILE="/tmp/.claude-violations-${PPID}"
|
|
12
|
+
TASK_COUNT_FILE="/tmp/.claude-task-count-${PPID}"
|
|
13
|
+
|
|
14
|
+
echo "" >&2
|
|
15
|
+
echo "╔══════════════════════════════════════════════╗" >&2
|
|
16
|
+
echo "║ Session Compliance Report ║" >&2
|
|
17
|
+
echo "╚══════════════════════════════════════════════╝" >&2
|
|
18
|
+
|
|
19
|
+
# Count total Agent/Task calls
|
|
20
|
+
if [ -f "$TASK_COUNT_FILE" ]; then
|
|
21
|
+
TOTAL_TASKS=$(cat "$TASK_COUNT_FILE")
|
|
22
|
+
echo "[Compliance] Agent/Task calls this session: ${TOTAL_TASKS}" >&2
|
|
23
|
+
else
|
|
24
|
+
TOTAL_TASKS=0
|
|
25
|
+
echo "[Compliance] Agent/Task calls this session: 0" >&2
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Check violations
|
|
29
|
+
if [ -f "$VIOLATIONS_FILE" ] && [ -s "$VIOLATIONS_FILE" ]; then
|
|
30
|
+
VIOLATION_COUNT=$(wc -l < "$VIOLATIONS_FILE" | tr -d ' ')
|
|
31
|
+
echo "[Compliance] Violations detected: ${VIOLATION_COUNT}" >&2
|
|
32
|
+
echo "" >&2
|
|
33
|
+
|
|
34
|
+
# Group by rule
|
|
35
|
+
R010_COUNT=$(grep -c '"rule":"R010"' "$VIOLATIONS_FILE" 2>/dev/null || echo "0")
|
|
36
|
+
R018_COUNT=$(grep -c '"rule":"R018"' "$VIOLATIONS_FILE" 2>/dev/null || echo "0")
|
|
37
|
+
|
|
38
|
+
if [ "$R010_COUNT" -gt 0 ]; then
|
|
39
|
+
echo " R010 (Git Delegation): ${R010_COUNT} violation(s)" >&2
|
|
40
|
+
grep '"rule":"R010"' "$VIOLATIONS_FILE" | jq -r '.detail' 2>/dev/null | while read -r detail; do
|
|
41
|
+
echo " - ${detail}" >&2
|
|
42
|
+
done
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
if [ "$R018_COUNT" -gt 0 ]; then
|
|
46
|
+
echo " R018 (Agent Teams): ${R018_COUNT} violation(s)" >&2
|
|
47
|
+
grep '"rule":"R018"' "$VIOLATIONS_FILE" | jq -r '.detail' 2>/dev/null | while read -r detail; do
|
|
48
|
+
echo " - ${detail}" >&2
|
|
49
|
+
done
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
echo "" >&2
|
|
53
|
+
echo "[Compliance] Review violations above and consider rule updates per R016." >&2
|
|
54
|
+
else
|
|
55
|
+
echo "[Compliance] No violations detected. All clear!" >&2
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
echo "────────────────────────────────────────────────" >&2
|
|
59
|
+
|
|
60
|
+
# Cleanup temp files (best effort)
|
|
61
|
+
rm -f "$VIOLATIONS_FILE" 2>/dev/null || true
|
|
62
|
+
|
|
63
|
+
# CRITICAL: Always pass through input and exit 0
|
|
64
|
+
echo "$input"
|
|
65
|
+
exit 0
|
|
@@ -104,17 +104,6 @@ All members must be spawned in a single message. Partial spawning needs correcti
|
|
|
104
104
|
implementer → fixes → SendMessage(reviewer, "fixed")
|
|
105
105
|
reviewer → re-reviews → done
|
|
106
106
|
|
|
107
|
-
❌ WRONG: Multi-expert task without coordination
|
|
108
|
-
Agent(lang-typescript-expert) → "Implement frontend"
|
|
109
|
-
Agent(be-express-expert) → "Implement API"
|
|
110
|
-
(no shared state, results manually combined)
|
|
111
|
-
|
|
112
|
-
✓ CORRECT: Agent Teams for cross-domain work
|
|
113
|
-
TeamCreate("fullstack")
|
|
114
|
-
Agent(frontend-dev) + Agent(backend-dev) → team members
|
|
115
|
-
Shared TaskList for interface contracts
|
|
116
|
-
SendMessage for API schema coordination
|
|
117
|
-
|
|
118
107
|
❌ WRONG: Spawning team members one at a time
|
|
119
108
|
TeamCreate("research-team")
|
|
120
109
|
Message 1: Agent(researcher-1) → Analysis 1 (only 1/3 spawned)
|
|
@@ -127,18 +116,6 @@ All members must be spawned in a single message. Partial spawning needs correcti
|
|
|
127
116
|
Agent(researcher-1) → Analysis 1 ┐
|
|
128
117
|
Agent(researcher-2) → Analysis 2 ├─ ALL spawned together
|
|
129
118
|
Agent(researcher-3) → Analysis 3 ┘
|
|
130
|
-
|
|
131
|
-
❌ WRONG: Multi-issue batch as independent agents
|
|
132
|
-
Agent(general-purpose) → "Fix issue #1"
|
|
133
|
-
Agent(general-purpose) → "Fix issue #2"
|
|
134
|
-
Agent(general-purpose) → "Fix issue #3"
|
|
135
|
-
(no coordination, no shared task tracking)
|
|
136
|
-
|
|
137
|
-
✓ CORRECT: Agent Teams for multi-issue batches
|
|
138
|
-
TeamCreate("release-fixes")
|
|
139
|
-
TaskCreate for each issue
|
|
140
|
-
Agent(fixer-1) + Agent(fixer-2) + Agent(fixer-3) → team members
|
|
141
|
-
Shared task list tracks progress across all issues
|
|
142
119
|
```
|
|
143
120
|
|
|
144
121
|
## Cost Guidelines
|
|
@@ -95,12 +95,6 @@ Main Conversation (orchestrator)
|
|
|
95
95
|
Main conversation → Agent(mgr-gitnerd) → git commit
|
|
96
96
|
Main conversation → Agent(mgr-gitnerd) → git push
|
|
97
97
|
|
|
98
|
-
❌ WRONG: Using general-purpose when specialist exists
|
|
99
|
-
Main conversation → Agent(general-purpose) → "Write Go code"
|
|
100
|
-
|
|
101
|
-
✓ CORRECT: Using the right specialist
|
|
102
|
-
Main conversation → Agent(lang-golang-expert) → "Write Go code"
|
|
103
|
-
|
|
104
98
|
❌ WRONG: Orchestrator creates files "just this once"
|
|
105
99
|
"It's just a small config file, I'll write it directly..."
|
|
106
100
|
|
|
@@ -110,15 +104,9 @@ Main Conversation (orchestrator)
|
|
|
110
104
|
❌ WRONG: Bundling git operations with file editing in non-gitnerd agent
|
|
111
105
|
Main conversation → Agent(general-purpose) → "git revert + edit file + git commit"
|
|
112
106
|
Main conversation → Agent(lang-typescript-expert) → "fix bug and commit"
|
|
113
|
-
|
|
114
|
-
✓ CORRECT: Separate file editing from git operations
|
|
115
|
-
Main conversation → Agent(lang-typescript-expert) → "fix bug" (file edit only)
|
|
116
|
-
Main conversation → Agent(mgr-gitnerd) → "git commit" (git operation only)
|
|
117
|
-
|
|
118
|
-
❌ WRONG: Including git commands in non-gitnerd agent prompt for "convenience"
|
|
119
107
|
Agent(general-purpose, prompt="revert the last commit, edit the file, then commit the fix")
|
|
120
108
|
|
|
121
|
-
✓ CORRECT:
|
|
109
|
+
✓ CORRECT: Separate file editing from git operations, split delegations
|
|
122
110
|
Agent(mgr-gitnerd, prompt="revert the last commit")
|
|
123
111
|
Agent(appropriate-expert, prompt="edit the file to fix the issue")
|
|
124
112
|
Agent(mgr-gitnerd, prompt="commit the fix")
|