@g3nomaly/skills 0.3.0 → 1.0.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/LICENSE +95 -0
- package/dist/cli/adapter.d.ts +30 -0
- package/dist/cli/adapter.d.ts.map +1 -0
- package/dist/cli/adapter.js +86 -0
- package/dist/cli/adapter.js.map +1 -0
- package/dist/cli/commands/add.d.ts +17 -0
- package/dist/cli/commands/add.d.ts.map +1 -0
- package/dist/cli/commands/add.js +108 -0
- package/dist/cli/commands/add.js.map +1 -0
- package/dist/cli/commands/hook.d.ts +6 -0
- package/dist/cli/commands/hook.d.ts.map +1 -0
- package/dist/cli/commands/hook.js +18 -0
- package/dist/cli/commands/hook.js.map +1 -0
- package/dist/cli/commands/init.d.ts +22 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +119 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/ls.d.ts +4 -0
- package/dist/cli/commands/ls.d.ts.map +1 -0
- package/dist/cli/commands/ls.js +8 -0
- package/dist/cli/commands/ls.js.map +1 -0
- package/dist/cli/commands/remove.d.ts +12 -0
- package/dist/cli/commands/remove.d.ts.map +1 -0
- package/dist/cli/commands/remove.js +60 -0
- package/dist/cli/commands/remove.js.map +1 -0
- package/dist/cli/commands/update.d.ts +13 -0
- package/dist/cli/commands/update.d.ts.map +1 -0
- package/dist/cli/commands/update.js +49 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +72 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/decisions/index.d.ts +6 -0
- package/dist/decisions/index.d.ts.map +1 -0
- package/dist/decisions/index.js +5 -0
- package/dist/decisions/index.js.map +1 -0
- package/dist/decisions/paths.d.ts +4 -0
- package/dist/decisions/paths.d.ts.map +1 -0
- package/dist/decisions/paths.js +12 -0
- package/dist/decisions/paths.js.map +1 -0
- package/dist/decisions/read.d.ts +18 -0
- package/dist/decisions/read.d.ts.map +1 -0
- package/dist/decisions/read.js +45 -0
- package/dist/decisions/read.js.map +1 -0
- package/dist/decisions/write.d.ts +20 -0
- package/dist/decisions/write.d.ts.map +1 -0
- package/dist/decisions/write.js +48 -0
- package/dist/decisions/write.js.map +1 -0
- package/dist/filetree/ensure.d.ts +7 -0
- package/dist/filetree/ensure.d.ts.map +1 -0
- package/dist/filetree/ensure.js +36 -0
- package/dist/filetree/ensure.js.map +1 -0
- package/dist/filetree/entries.d.ts +9 -0
- package/dist/filetree/entries.d.ts.map +1 -0
- package/dist/filetree/entries.js +49 -0
- package/dist/filetree/entries.js.map +1 -0
- package/dist/filetree/frontmatter.d.ts +16 -0
- package/dist/filetree/frontmatter.d.ts.map +1 -0
- package/dist/filetree/frontmatter.js +43 -0
- package/dist/filetree/frontmatter.js.map +1 -0
- package/dist/filetree/generate.d.ts +16 -0
- package/dist/filetree/generate.d.ts.map +1 -0
- package/dist/filetree/generate.js +62 -0
- package/dist/filetree/generate.js.map +1 -0
- package/dist/filetree/index.d.ts +17 -0
- package/dist/filetree/index.d.ts.map +1 -0
- package/dist/filetree/index.js +13 -0
- package/dist/filetree/index.js.map +1 -0
- package/dist/filetree/levels.d.ts +25 -0
- package/dist/filetree/levels.d.ts.map +1 -0
- package/dist/filetree/levels.js +45 -0
- package/dist/filetree/levels.js.map +1 -0
- package/dist/filetree/locate.d.ts +44 -0
- package/dist/filetree/locate.d.ts.map +1 -0
- package/dist/filetree/locate.js +76 -0
- package/dist/filetree/locate.js.map +1 -0
- package/dist/filetree/paths.d.ts +15 -0
- package/dist/filetree/paths.d.ts.map +1 -0
- package/dist/filetree/paths.js +38 -0
- package/dist/filetree/paths.js.map +1 -0
- package/dist/filetree/read.d.ts +23 -0
- package/dist/filetree/read.d.ts.map +1 -0
- package/dist/filetree/read.js +36 -0
- package/dist/filetree/read.js.map +1 -0
- package/dist/filetree/remove.d.ts +9 -0
- package/dist/filetree/remove.d.ts.map +1 -0
- package/dist/filetree/remove.js +17 -0
- package/dist/filetree/remove.js.map +1 -0
- package/dist/filetree/root.d.ts +9 -0
- package/dist/filetree/root.d.ts.map +1 -0
- package/dist/filetree/root.js +15 -0
- package/dist/filetree/root.js.map +1 -0
- package/dist/filetree/status.d.ts +21 -0
- package/dist/filetree/status.d.ts.map +1 -0
- package/dist/filetree/status.js +55 -0
- package/dist/filetree/status.js.map +1 -0
- package/dist/hooks/cli.d.ts +29 -0
- package/dist/hooks/cli.d.ts.map +1 -0
- package/dist/hooks/cli.js +65 -0
- package/dist/hooks/cli.js.map +1 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/grilling/.claude-plugin/plugin.json +7 -0
- package/dist/plugins/grilling/skills/domain-modeling/ADR-FORMAT.md +47 -0
- package/dist/plugins/grilling/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
- package/dist/plugins/grilling/skills/domain-modeling/SKILL.md +74 -0
- package/dist/plugins/grilling/skills/domain-modeling/agents/openai.yaml +3 -0
- package/dist/plugins/grilling/skills/grill-me/SKILL.md +7 -0
- package/dist/plugins/grilling/skills/grill-me/agents/openai.yaml +5 -0
- package/dist/plugins/grilling/skills/grill-with-docs/SKILL.md +7 -0
- package/dist/plugins/grilling/skills/grill-with-docs/agents/openai.yaml +5 -0
- package/dist/plugins/grilling/skills/grilling/SKILL.md +12 -0
- package/dist/plugins/grilling/skills/grilling/agents/openai.yaml +3 -0
- package/dist/plugins/speech/.claude-plugin/plugin.json +7 -0
- package/dist/plugins/speech/skills/emphasise/SKILL.md +49 -0
- package/dist/plugins/speech/skills/emphasise/agents/openai.yaml +5 -0
- package/dist/plugins/speech/skills/unslop/SKILL.md +80 -0
- package/dist/plugins/task-manager/.claude-plugin/plugin.json +11 -0
- package/dist/plugins/task-manager/hooks/hooks.json +19 -0
- package/dist/plugins/task-manager/skills/decisions/SKILL.md +39 -0
- package/dist/plugins/task-manager/skills/decisions/agents/openai.yaml +5 -0
- package/dist/plugins/task-manager/skills/decisions/references/usage.md +26 -0
- package/dist/plugins/task-manager/skills/task-manager/SKILL.md +99 -0
- package/dist/plugins/task-manager/skills/vocabulary/SKILL.md +42 -0
- package/dist/plugins/task-manager/skills/vocabulary/agents/openai.yaml +5 -0
- package/dist/plugins/task-manager/skills/vocabulary/references/usage.md +26 -0
- package/dist/plugins/using-hooks/.claude-plugin/plugin.json +7 -0
- package/dist/plugins/using-hooks/skills/hook-post-tool-use/SKILL.md +79 -0
- package/dist/plugins/using-hooks/skills/hook-post-tool-use/agents/openai.yaml +5 -0
- package/dist/plugins/using-hooks/skills/hook-pre-tool-use/SKILL.md +84 -0
- package/dist/plugins/using-hooks/skills/hook-pre-tool-use/agents/openai.yaml +5 -0
- package/dist/plugins/using-hooks/skills/hook-stop/SKILL.md +69 -0
- package/dist/plugins/using-hooks/skills/hook-stop/agents/openai.yaml +5 -0
- package/dist/plugins/using-hooks/skills/hook-user-prompt-submit/SKILL.md +64 -0
- package/dist/plugins/using-hooks/skills/hook-user-prompt-submit/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/.claude-plugin/plugin.json +16 -0
- package/dist/plugins/workflow/agents/reviewer.md +9 -0
- package/dist/plugins/workflow/skills/execute/SKILL.md +21 -0
- package/dist/plugins/workflow/skills/execute/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/skills/orchestrator/SKILL.md +27 -0
- package/dist/plugins/workflow/skills/orchestrator/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/skills/plan/SKILL.md +18 -0
- package/dist/plugins/workflow/skills/plan/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/skills/plan/references/task-frontmatter.md +33 -0
- package/dist/plugins/workflow/skills/review/SKILL.md +25 -0
- package/dist/plugins/workflow/skills/review/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/skills/run/SKILL.md +33 -0
- package/dist/plugins/workflow/skills/run/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/skills/run/references/sub-agents.md +46 -0
- package/dist/plugins/workflow/skills/sync/SKILL.md +18 -0
- package/dist/plugins/workflow/skills/sync/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/skills/worktree/SKILL.md +38 -0
- package/dist/plugins/workflow/skills/worktree/agents/openai.yaml +5 -0
- package/dist/plugins/workflow/skills/worktree/references/git-commands.md +27 -0
- package/dist/plugins/writing/.claude-plugin/plugin.json +7 -0
- package/dist/plugins/writing/skills/writing-great-hooks/SKILL.md +192 -0
- package/dist/plugins/writing/skills/writing-great-hooks/agents/openai.yaml +5 -0
- package/dist/plugins/writing/skills/writing-great-skills/GLOSSARY.md +201 -0
- package/dist/plugins/writing/skills/writing-great-skills/SKILL.md +92 -0
- package/dist/plugins/writing/skills/writing-great-skills/agents/openai.yaml +5 -0
- package/dist/plugins/writing/skills/writing-great-tasks/SKILL.md +136 -0
- package/dist/plugins/writing/skills/writing-great-tasks/agents/openai.yaml +5 -0
- package/dist/plugins/writing/skills/writing-great-tasks/templates/template_task.md +108 -0
- package/dist/registry/index.d.ts +5 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +6 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/loadPackageRegistry.d.ts +14 -0
- package/dist/registry/loadPackageRegistry.d.ts.map +1 -0
- package/dist/registry/loadPackageRegistry.js +59 -0
- package/dist/registry/loadPackageRegistry.js.map +1 -0
- package/dist/registry/readSkillDir.d.ts +12 -0
- package/dist/registry/readSkillDir.d.ts.map +1 -0
- package/dist/registry/readSkillDir.js +59 -0
- package/dist/registry/readSkillDir.js.map +1 -0
- package/dist/registry/types.d.ts +53 -0
- package/dist/registry/types.d.ts.map +1 -0
- package/dist/registry/types.js +35 -0
- package/dist/registry/types.js.map +1 -0
- package/dist/registry/userManifest.d.ts +7 -0
- package/dist/registry/userManifest.d.ts.map +1 -0
- package/dist/registry/userManifest.js +21 -0
- package/dist/registry/userManifest.js.map +1 -0
- package/dist/remote/fetch.d.ts +16 -0
- package/dist/remote/fetch.d.ts.map +1 -0
- package/dist/remote/fetch.js +41 -0
- package/dist/remote/fetch.js.map +1 -0
- package/dist/remote/index.d.ts +7 -0
- package/dist/remote/index.d.ts.map +1 -0
- package/dist/remote/index.js +5 -0
- package/dist/remote/index.js.map +1 -0
- package/dist/remote/manifest.d.ts +23 -0
- package/dist/remote/manifest.d.ts.map +1 -0
- package/dist/remote/manifest.js +116 -0
- package/dist/remote/manifest.js.map +1 -0
- package/dist/remote/registry.d.ts +18 -0
- package/dist/remote/registry.d.ts.map +1 -0
- package/dist/remote/registry.js +58 -0
- package/dist/remote/registry.js.map +1 -0
- package/dist/schemas/config.d.ts +3 -0
- package/dist/schemas/config.d.ts.map +1 -0
- package/dist/schemas/config.js +3 -0
- package/dist/schemas/config.js.map +1 -0
- package/dist/schemas/decision.d.ts +43 -0
- package/dist/schemas/decision.d.ts.map +1 -0
- package/dist/schemas/decision.js +24 -0
- package/dist/schemas/decision.js.map +1 -0
- package/dist/schemas/index.d.ts +17 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +10 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/phase.d.ts +46 -0
- package/dist/schemas/phase.d.ts.map +1 -0
- package/dist/schemas/phase.js +16 -0
- package/dist/schemas/phase.js.map +1 -0
- package/dist/schemas/plan.d.ts +44 -0
- package/dist/schemas/plan.d.ts.map +1 -0
- package/dist/schemas/plan.js +15 -0
- package/dist/schemas/plan.js.map +1 -0
- package/dist/schemas/primitives.d.ts +38 -0
- package/dist/schemas/primitives.d.ts.map +1 -0
- package/dist/schemas/primitives.js +33 -0
- package/dist/schemas/primitives.js.map +1 -0
- package/dist/schemas/task.d.ts +70 -0
- package/dist/schemas/task.d.ts.map +1 -0
- package/dist/schemas/task.js +19 -0
- package/dist/schemas/task.js.map +1 -0
- package/dist/schemas/term.d.ts +17 -0
- package/dist/schemas/term.d.ts.map +1 -0
- package/dist/schemas/term.js +22 -0
- package/dist/schemas/term.js.map +1 -0
- package/dist/schemas/validation.d.ts +24 -0
- package/dist/schemas/validation.d.ts.map +1 -0
- package/dist/schemas/validation.js +39 -0
- package/dist/schemas/validation.js.map +1 -0
- package/dist/task-manager/hooks/add-decision.d.ts +2 -0
- package/dist/task-manager/hooks/add-decision.d.ts.map +1 -0
- package/dist/task-manager/hooks/add-decision.js +19 -0
- package/dist/task-manager/hooks/add-decision.js.map +1 -0
- package/dist/task-manager/hooks/cleanup.d.ts +2 -0
- package/dist/task-manager/hooks/cleanup.d.ts.map +1 -0
- package/dist/task-manager/hooks/cleanup.js +27 -0
- package/dist/task-manager/hooks/cleanup.js.map +1 -0
- package/dist/task-manager/hooks/get-decision.d.ts +2 -0
- package/dist/task-manager/hooks/get-decision.d.ts.map +1 -0
- package/dist/task-manager/hooks/get-decision.js +11 -0
- package/dist/task-manager/hooks/get-decision.js.map +1 -0
- package/dist/task-manager/hooks/get-entry.d.ts +2 -0
- package/dist/task-manager/hooks/get-entry.d.ts.map +1 -0
- package/dist/task-manager/hooks/get-entry.js +20 -0
- package/dist/task-manager/hooks/get-entry.js.map +1 -0
- package/dist/task-manager/hooks/get-term.d.ts +2 -0
- package/dist/task-manager/hooks/get-term.d.ts.map +1 -0
- package/dist/task-manager/hooks/get-term.js +13 -0
- package/dist/task-manager/hooks/get-term.js.map +1 -0
- package/dist/task-manager/hooks/guard-tree.d.ts +2 -0
- package/dist/task-manager/hooks/guard-tree.d.ts.map +1 -0
- package/dist/task-manager/hooks/guard-tree.js +63 -0
- package/dist/task-manager/hooks/guard-tree.js.map +1 -0
- package/dist/task-manager/hooks/index.d.ts +4 -0
- package/dist/task-manager/hooks/index.d.ts.map +1 -0
- package/dist/task-manager/hooks/index.js +32 -0
- package/dist/task-manager/hooks/index.js.map +1 -0
- package/dist/task-manager/hooks/list-decisions.d.ts +2 -0
- package/dist/task-manager/hooks/list-decisions.d.ts.map +1 -0
- package/dist/task-manager/hooks/list-decisions.js +20 -0
- package/dist/task-manager/hooks/list-decisions.js.map +1 -0
- package/dist/task-manager/hooks/list-entries.d.ts +2 -0
- package/dist/task-manager/hooks/list-entries.d.ts.map +1 -0
- package/dist/task-manager/hooks/list-entries.js +19 -0
- package/dist/task-manager/hooks/list-entries.js.map +1 -0
- package/dist/task-manager/hooks/list-terms.d.ts +2 -0
- package/dist/task-manager/hooks/list-terms.d.ts.map +1 -0
- package/dist/task-manager/hooks/list-terms.js +8 -0
- package/dist/task-manager/hooks/list-terms.js.map +1 -0
- package/dist/task-manager/hooks/next-entry.d.ts +2 -0
- package/dist/task-manager/hooks/next-entry.d.ts.map +1 -0
- package/dist/task-manager/hooks/next-entry.js +23 -0
- package/dist/task-manager/hooks/next-entry.js.map +1 -0
- package/dist/task-manager/hooks/remove-term.d.ts +2 -0
- package/dist/task-manager/hooks/remove-term.d.ts.map +1 -0
- package/dist/task-manager/hooks/remove-term.js +15 -0
- package/dist/task-manager/hooks/remove-term.js.map +1 -0
- package/dist/task-manager/hooks/set-state.d.ts +2 -0
- package/dist/task-manager/hooks/set-state.d.ts.map +1 -0
- package/dist/task-manager/hooks/set-state.js +15 -0
- package/dist/task-manager/hooks/set-state.js.map +1 -0
- package/dist/task-manager/hooks/set-term.d.ts +2 -0
- package/dist/task-manager/hooks/set-term.d.ts.map +1 -0
- package/dist/task-manager/hooks/set-term.js +27 -0
- package/dist/task-manager/hooks/set-term.js.map +1 -0
- package/dist/task-manager/hooks/sync-tree.d.ts +2 -0
- package/dist/task-manager/hooks/sync-tree.d.ts.map +1 -0
- package/dist/task-manager/hooks/sync-tree.js +28 -0
- package/dist/task-manager/hooks/sync-tree.js.map +1 -0
- package/dist/task-manager/index.d.ts +2 -0
- package/dist/task-manager/index.d.ts.map +1 -0
- package/dist/task-manager/index.js +3 -0
- package/dist/task-manager/index.js.map +1 -0
- package/dist/vocabulary/file.d.ts +15 -0
- package/dist/vocabulary/file.d.ts.map +1 -0
- package/dist/vocabulary/file.js +80 -0
- package/dist/vocabulary/file.js.map +1 -0
- package/dist/vocabulary/index.d.ts +4 -0
- package/dist/vocabulary/index.d.ts.map +1 -0
- package/dist/vocabulary/index.js +4 -0
- package/dist/vocabulary/index.js.map +1 -0
- package/dist/vocabulary/match.d.ts +22 -0
- package/dist/vocabulary/match.d.ts.map +1 -0
- package/dist/vocabulary/match.js +31 -0
- package/dist/vocabulary/match.js.map +1 -0
- package/dist/workflow/gates.d.ts +24 -0
- package/dist/workflow/gates.d.ts.map +1 -0
- package/dist/workflow/gates.js +34 -0
- package/dist/workflow/gates.js.map +1 -0
- package/dist/workflow/hooks/advance-step.d.ts +2 -0
- package/dist/workflow/hooks/advance-step.d.ts.map +1 -0
- package/dist/workflow/hooks/advance-step.js +51 -0
- package/dist/workflow/hooks/advance-step.js.map +1 -0
- package/dist/workflow/hooks/current-step.d.ts +2 -0
- package/dist/workflow/hooks/current-step.d.ts.map +1 -0
- package/dist/workflow/hooks/current-step.js +24 -0
- package/dist/workflow/hooks/current-step.js.map +1 -0
- package/dist/workflow/hooks/index.d.ts +4 -0
- package/dist/workflow/hooks/index.d.ts.map +1 -0
- package/dist/workflow/hooks/index.js +10 -0
- package/dist/workflow/hooks/index.js.map +1 -0
- package/dist/workflow/hooks/ready-phases.d.ts +2 -0
- package/dist/workflow/hooks/ready-phases.d.ts.map +1 -0
- package/dist/workflow/hooks/ready-phases.js +15 -0
- package/dist/workflow/hooks/ready-phases.js.map +1 -0
- package/dist/workflow/index.d.ts +8 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/index.js +6 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow/phase.d.ts +16 -0
- package/dist/workflow/phase.d.ts.map +1 -0
- package/dist/workflow/phase.js +22 -0
- package/dist/workflow/phase.js.map +1 -0
- package/dist/workflow/steps.d.ts +15 -0
- package/dist/workflow/steps.d.ts.map +1 -0
- package/dist/workflow/steps.js +32 -0
- package/dist/workflow/steps.js.map +1 -0
- package/package.json +62 -3
- package/README.md +0 -3
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"hooks": [
|
|
6
|
+
{ "type": "command", "command": "g3n-skills hook sync-tree", "timeout": 30 }
|
|
7
|
+
]
|
|
8
|
+
}
|
|
9
|
+
],
|
|
10
|
+
"PreToolUse": [
|
|
11
|
+
{
|
|
12
|
+
"matcher": "Read|Grep|Glob",
|
|
13
|
+
"hooks": [
|
|
14
|
+
{ "type": "command", "command": "g3n-skills hook guard-tree", "timeout": 10 }
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: decisions
|
|
3
|
+
description: Record and look up the decisions a plan has made, stored as numbered files inside the plan and reached through hooks. Use when a hard-to-reverse choice is made while planning or working a phase, when a choice replaces an earlier one, when the user asks why something was done a certain way, or when another skill needs a plan's decisions.
|
|
4
|
+
registryDependencies: [task-manager, domain-modeling]
|
|
5
|
+
disable-model-invocation: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
A **decision** is one paragraph saying what was chosen and why, filed under the plan it belongs to. Its job is to stop the next session from reopening a question this one closed.
|
|
9
|
+
|
|
10
|
+
The hooks come from the `/task-manager` skill. Load it first when `g3n-skills` is not on `PATH`.
|
|
11
|
+
|
|
12
|
+
**Reach decisions through the hooks only.** They sit inside the tree, in `<plan>/decisions/<id>.md`, so `guard-tree` denies a direct read.
|
|
13
|
+
|
|
14
|
+
| Hook | Does | Use it when |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| `list-decisions` | Returns a plan's decisions in numbered order, metadata only | starting a phase, or checking whether a question is already closed |
|
|
17
|
+
| `get-decision` | Returns one decision in full | the title is not enough |
|
|
18
|
+
| `add-decision` | Numbers, dates and writes a new decision from stdin. **Writes.** | a choice passed the three tests below |
|
|
19
|
+
|
|
20
|
+
Copy each invocation from [`references/usage.md`](references/usage.md). `add-decision` takes the decision text on stdin, as shown there.
|
|
21
|
+
|
|
22
|
+
- **`--in <plan>`** is required everywhere. Numbers restart per plan.
|
|
23
|
+
- **`--status`** is `proposed`, `accepted`, `deprecated` or `superseded`. `add-decision` defaults to `accepted`. `list-decisions` filters by it.
|
|
24
|
+
- **`--supersedes <id>`** also moves the named decision to `superseded`.
|
|
25
|
+
- `get-decision` exits `1` for an unknown id. `list-decisions` prints `[]` for a plan with none. `add-decision` exits `1` when nothing was piped in.
|
|
26
|
+
|
|
27
|
+
## When to record
|
|
28
|
+
|
|
29
|
+
All three must hold. The `/domain-modeling` skill argues each one in its ADR format, with examples of what qualifies.
|
|
30
|
+
|
|
31
|
+
1. **Hard to reverse.** Changing course later costs real work.
|
|
32
|
+
2. **Surprising without context.** A reader of the code would ask why.
|
|
33
|
+
3. **A real trade-off.** There was an alternative, and it lost for a reason.
|
|
34
|
+
|
|
35
|
+
## Writing one
|
|
36
|
+
|
|
37
|
+
One to three sentences: the context, the choice, the reason. Name the alternative that lost. The title is the choice itself in a few words, because `list-decisions` shows titles only and the title has to close the question unaided.
|
|
38
|
+
|
|
39
|
+
**A decision is never edited.** A changed mind is a new decision with `--supersedes`, so the trail of reasons stays readable.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Decision hooks — usage
|
|
2
|
+
|
|
3
|
+
Where decisions sit and how each hook is called. This is the disclosed reference for the [`decisions`](../SKILL.md) skill.
|
|
4
|
+
|
|
5
|
+
## On disk
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
docs/task-manager/auth-rework/
|
|
9
|
+
├── auth-rework.md
|
|
10
|
+
└── decisions/
|
|
11
|
+
├── 0001-use-jwt-for-sessions.md
|
|
12
|
+
└── 0002-use-opaque-tokens.md
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Invocations
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
g3n-skills hook list-decisions --in auth-rework --status accepted
|
|
19
|
+
g3n-skills hook get-decision --in auth-rework --id 0001-use-jwt-for-sessions
|
|
20
|
+
|
|
21
|
+
g3n-skills hook add-decision --in auth-rework --title "Use opaque tokens" \
|
|
22
|
+
--supersedes 0001-use-jwt-for-sessions <<'TEXT'
|
|
23
|
+
Sessions move to opaque tokens looked up per request. Revoking a JWT before
|
|
24
|
+
expiry needed a denylist, which cost the statelessness we chose JWTs for.
|
|
25
|
+
TEXT
|
|
26
|
+
```
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: task-manager
|
|
3
|
+
description: Query and drive a tree of plans, phases and tasks that lives on disk as folders of Markdown files with a rebuilt index per folder. Use whenever the user asks what to work on next, refers to a plan, phase or task by name or TASK-### id, wants something moved to open, in-progress, in-review, completed or blocked, or wants finished work cleared out. Every read and every write goes through the `g3n-skills hook` commands — never open a tree file directly.
|
|
4
|
+
disable-model-invocation: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Before anything else
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
command -v g3n-skills >/dev/null 2>&1 || bun add -g @g3nomaly/skills
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
If the command exists, print nothing and carry on.
|
|
14
|
+
|
|
15
|
+
The tree is **three levels deep** and nothing else: the root holds **plans**, a plan holds **phases**, a phase holds **tasks**.
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
docs/task-manager/ # set by skills.settings.filetreeRoot
|
|
19
|
+
├── root-index.json # the plans, in order
|
|
20
|
+
└── auth-rework/
|
|
21
|
+
├── auth-rework.md # the plan itself
|
|
22
|
+
├── plan-index.json # the phases, in order
|
|
23
|
+
└── 01-schema/
|
|
24
|
+
├── 01-schema.md # the phase itself
|
|
25
|
+
├── phase-index.json # the tasks, in order
|
|
26
|
+
└── tasks/
|
|
27
|
+
└── TASK-006.md
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Every `.md` file opens with frontmatter carrying exactly the fields its index entry carries. **The index is rebuilt from the files, never edited** — a hand-written index is overwritten on the next sync.
|
|
31
|
+
|
|
32
|
+
**Order is the alphabetical order of the names on disk.** There is no rank field, no queue number and nothing to renumber: `01-schema` runs before `02-api` because `0` sorts before `2`. To reorder, rename.
|
|
33
|
+
|
|
34
|
+
**States** are `open`, `in-progress`, `in-review`, `completed` and `blocked`, and every level uses the same five.
|
|
35
|
+
|
|
36
|
+
## Never open a tree file
|
|
37
|
+
|
|
38
|
+
`Read`, `Grep` and `Glob` are the wrong tools here — **`guard-tree` denies them** on anything inside the tree, and says which hook to run instead. They are the interface: each one names its flags in this table and reports what went wrong on stderr.
|
|
39
|
+
|
|
40
|
+
| Hook | Does | Use it when |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `next-entry` | Returns the first entry of a queue that is not `completed` or `blocked`, in full | starting work — "what's next", "give me the next task" |
|
|
43
|
+
| `get-entry` | Returns one named plan, phase or task, in full | the user names something — "open auth-rework", "show TASK-006" |
|
|
44
|
+
| `list-entries` | Returns one folder's entries in queue order, metadata only | surveying — "what phases are in this plan", "what's blocked" |
|
|
45
|
+
| `set-state` | Moves one entry to a new state and rebuilds its index | work starts, stalls, lands, or goes up for review |
|
|
46
|
+
| `cleanup` | Deletes every `completed` entry, and `blocked` too with `--blocked` | the tree has filled up with finished work |
|
|
47
|
+
| `sync-tree` | Creates what is missing and rebuilds every index | a file was added or renamed by hand; otherwise it runs itself |
|
|
48
|
+
| `guard-tree` | Denies a file tool aimed at the tree | never by hand — the harness fires it |
|
|
49
|
+
|
|
50
|
+
The last two are **registered in `hooks/hooks.json` and fire on their own**; never invoke them as a step:
|
|
51
|
+
|
|
52
|
+
| Hook | Event | Matcher | What it does |
|
|
53
|
+
|---|---|---|---|
|
|
54
|
+
| `sync-tree` | `SessionStart` | — | Rebuilds every index. Exit `1` is non-blocking: the session opens with stale indexes and the reason goes to the user. |
|
|
55
|
+
| `guard-tree` | `PreToolUse` | `Read\|Grep\|Glob` | Returns `deny` for a guarded path, nothing otherwise. Only a path the call states outright is checked, so an unscoped `Grep` still runs. |
|
|
56
|
+
|
|
57
|
+
Run the other four from the plugin root:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
g3n-skills hook next-entry --in auth-rework --pretty
|
|
61
|
+
g3n-skills hook get-entry --id TASK-006
|
|
62
|
+
g3n-skills hook list-entries --in auth-rework --status blocked
|
|
63
|
+
g3n-skills hook set-state --id TASK-006 --to in-progress
|
|
64
|
+
g3n-skills hook cleanup --blocked --dry-run --pretty
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Flags they share
|
|
68
|
+
|
|
69
|
+
- **`--project <dir>`** — the folder holding `.g3n.config.json`, default the working directory. The tree root comes from `skills.settings.filetreeRoot` in it.
|
|
70
|
+
- **`--root <dir>`** — the tree folder verbatim, skipping the config. Use it only when there is no config to read.
|
|
71
|
+
- **`--pretty`** — indented JSON. Leave it off when piping.
|
|
72
|
+
- **`--id <name>`** — a plan or phase name, or a task id like `TASK-006`. One name is searched for across the whole tree; two entries answering to it is an error, not a choice to make.
|
|
73
|
+
- **`--in <name>`** — whose entries to list. Omit it for the plans at the root.
|
|
74
|
+
|
|
75
|
+
Where they deliberately differ:
|
|
76
|
+
|
|
77
|
+
- `next-entry` and `get-entry` **return exactly one thing**, so nothing found is a failure — exit `1`.
|
|
78
|
+
- `list-entries` and `cleanup` **return a list**, so `[]` is a real answer — exit `0`.
|
|
79
|
+
- `get-entry`, `next-entry` and `list-entries` are read-only; **`set-state`, `cleanup` and `sync-tree` write to disk.** Run `cleanup` with `--dry-run` before running it for real.
|
|
80
|
+
|
|
81
|
+
## Terms and decisions
|
|
82
|
+
|
|
83
|
+
Two more things live in the tree, each with its own hooks and its own skill:
|
|
84
|
+
|
|
85
|
+
- **The vocabulary**, one file at the tree root. `get-entry` and `next-entry` attach a `vocabulary` array naming every term the entry mentions. Use the `/vocabulary` skill to read that array, look a word up, or record one.
|
|
86
|
+
- **A plan's decisions**, in `<plan>/decisions/`. Use the `/decisions` skill to list, read or record them.
|
|
87
|
+
|
|
88
|
+
## What the hooks will not do
|
|
89
|
+
|
|
90
|
+
- **A state change is only the `status:` line.** What the transition implies — the reason a task is blocked, the outcome written into the body — is prose, and prose is written afterwards with an ordinary edit to the body of that one file.
|
|
91
|
+
- **Creating a plan, phase or task is not a hook.** Write the `.md` file where the tree expects it, then run `sync-tree`; the index picks it up.
|
|
92
|
+
- **`cleanup` deletes.** A removed plan takes its phases and tasks with it. Confirm with the user before running it without `--dry-run`.
|
|
93
|
+
|
|
94
|
+
## When it goes wrong
|
|
95
|
+
|
|
96
|
+
Everything is checked against its schema on the way in, and a failure names the file and the field. Two are worth recognising:
|
|
97
|
+
|
|
98
|
+
- _`"<name>" is ambiguous`_ — two entries share a name. Rename one; nothing else will work until then.
|
|
99
|
+
- _`is "X" but it was read as "Y"`_ — the `name` or `id` in the frontmatter disagrees with the folder or file holding it. Fix the frontmatter, or rename the file, then `sync-tree`.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vocabulary
|
|
3
|
+
description: Keep one word per concept across sessions, stored in the task-manager tree and reached through hooks. Use when about to name a domain concept in code, a task or a doc, when the user corrects a word, when two words are in use for one thing, or when another skill needs a term looked up or recorded.
|
|
4
|
+
registryDependencies: [task-manager, domain-modeling]
|
|
5
|
+
disable-model-invocation: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Every session starts without the last one's words, so names _drift_: the _phase_ of Monday is the _stage_ of Tuesday, and by Friday the code has both. The vocabulary is the one list that stops it. Each **term** carries a definition and the **avoided words** it replaces.
|
|
9
|
+
|
|
10
|
+
The hooks come from the `/task-manager` skill. Load it first when `g3n-skills` is not on `PATH`.
|
|
11
|
+
|
|
12
|
+
The terms live in `vocabulary.md` at the tree root. **Reach them through the hooks only.** `guard-tree` denies a direct read, and a hand edit is overwritten by the next `set-term`.
|
|
13
|
+
|
|
14
|
+
| Hook | Does | Use it when |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| `get-term` | Returns one term, found by its name or by an avoided word | about to use a word for a domain concept |
|
|
17
|
+
| `list-terms` | Returns every term, sorted by name | starting work in an unfamiliar area |
|
|
18
|
+
| `set-term` | Adds a term, or replaces its definition and avoided words. **Writes.** | a concept got a name, or a name got sharper |
|
|
19
|
+
| `remove-term` | Deletes one term. **Writes.** | the concept left the project |
|
|
20
|
+
|
|
21
|
+
Copy each invocation from [`references/usage.md`](references/usage.md).
|
|
22
|
+
|
|
23
|
+
They share `--project`, `--root` and `--pretty` with the task-manager hooks. `get-term` and `remove-term` exit `1` when nothing answers to the name. `list-terms` prints `[]` for an empty vocabulary.
|
|
24
|
+
|
|
25
|
+
## Reading an answer
|
|
26
|
+
|
|
27
|
+
`get-term` reports how it found the term in `matched`:
|
|
28
|
+
|
|
29
|
+
- **`"term"`** means the word is the right one. Use it as spelled.
|
|
30
|
+
- **`"avoid"`** means the word is a retired synonym. Use the returned `term` instead, in prose and in identifiers alike.
|
|
31
|
+
|
|
32
|
+
`get-entry` and `next-entry` attach a `vocabulary` array to every plan, phase and task they return. It lists each term the entry mentions, and under `avoided` the retired words the entry still uses. Treat a non-empty `avoided` as a defect in the entry and write the term in whatever you produce from it.
|
|
33
|
+
|
|
34
|
+
## Recording a term
|
|
35
|
+
|
|
36
|
+
**Record on the second sighting.** One use of a word is prose. The same concept named twice, or named differently by two people, is a term. A correction from the user is always a term.
|
|
37
|
+
|
|
38
|
+
- **Definition.** One or two sentences saying what the thing _is_. Leave out how it is built.
|
|
39
|
+
- **`--avoid`.** The synonyms actually seen, comma-separated. `set-term` refuses a word another term already owns, which is how two terms are kept from claiming one meaning.
|
|
40
|
+
- **`set-term` replaces.** Pass the full definition and the full avoid list every time, since flags left out are cleared.
|
|
41
|
+
|
|
42
|
+
A term whose meaning is still contested is sharpened with the `/domain-modeling` skill first, then stored here.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Term hooks — usage
|
|
2
|
+
|
|
3
|
+
How each hook is called, and what the file they write looks like. This is the disclosed reference for the [`vocabulary`](../SKILL.md) skill.
|
|
4
|
+
|
|
5
|
+
## Invocations
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
g3n-skills hook get-term --term stage
|
|
9
|
+
g3n-skills hook list-terms --pretty
|
|
10
|
+
g3n-skills hook set-term --term Phase --definition "One step of a plan, holding tasks." --avoid "stage, milestone"
|
|
11
|
+
g3n-skills hook remove-term --term Phase
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## The file
|
|
15
|
+
|
|
16
|
+
`set-term` and `remove-term` rewrite `vocabulary.md` whole, terms sorted by name:
|
|
17
|
+
|
|
18
|
+
```md
|
|
19
|
+
# Vocabulary
|
|
20
|
+
|
|
21
|
+
## Phase
|
|
22
|
+
|
|
23
|
+
One step of a plan, holding tasks.
|
|
24
|
+
|
|
25
|
+
_Avoid_: stage, milestone
|
|
26
|
+
```
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "using-hooks",
|
|
3
|
+
"description": "How to write each Claude Code lifecycle hook.",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"skills": ["./skills/hook-pre-tool-use", "./skills/hook-post-tool-use", "./skills/hook-stop", "./skills/hook-user-prompt-submit"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hook-post-tool-use
|
|
3
|
+
description: Writing a PostToolUse lifecycle hook — the one that reacts to a finished tool call and can feed the result back to the agent.
|
|
4
|
+
registryDependencies: [writing-great-hooks]
|
|
5
|
+
disable-model-invocation: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Shared rules for every hook — the invariants, the script mechanics, registration: [`writing-great-hooks`](../writing-great-hooks/SKILL.md).
|
|
9
|
+
|
|
10
|
+
`PostToolUse` fires immediately after a tool has run. **The work is already done** — nothing this hook returns can undo it. What it can do is see the result and put a consequence in front of the agent, which makes it the event for verification, bookkeeping, and anything that must happen _because_ a file changed.
|
|
11
|
+
|
|
12
|
+
## Payload
|
|
13
|
+
|
|
14
|
+
The four common fields, the call, and what came back:
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"session_id": "abc123",
|
|
19
|
+
"transcript_path": "/home/you/.claude/projects/<slug>/<session>.jsonl",
|
|
20
|
+
"cwd": "/home/you/project",
|
|
21
|
+
"hook_event_name": "PostToolUse",
|
|
22
|
+
"tool_name": "Edit",
|
|
23
|
+
"tool_input": { "file_path": "/home/you/project/src/index.ts", "old_string": "…", "new_string": "…" },
|
|
24
|
+
"tool_response": { "filePath": "/home/you/project/src/index.ts", "success": true }
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`tool_input` and `tool_response` are both shaped by the tool. Branch on `tool_name` before reading either.
|
|
29
|
+
|
|
30
|
+
## Matcher
|
|
31
|
+
|
|
32
|
+
Same tool-name regex as [`hook-pre-tool-use`](../hook-pre-tool-use/SKILL.md), and the same reason to keep it tight:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"matcher": "Edit|MultiEdit|Write",
|
|
37
|
+
"hooks": [{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/format-edited-file.ts" }]
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## What the exit code does
|
|
42
|
+
|
|
43
|
+
- **`0` — nothing further happens.** stdout goes to the transcript, not to the agent.
|
|
44
|
+
- **`2` — stderr is fed to the agent** as something it must address. The tool result still stands; this is a correction, not a rollback.
|
|
45
|
+
- **anything else** — a non-blocking error; stderr goes to the user.
|
|
46
|
+
|
|
47
|
+
The JSON form does the same job with a reason attached:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"decision": "block",
|
|
52
|
+
"reason": "tsc reported 2 errors in src/index.ts:\n L14 Property 'id' does not exist on type 'Order'\n L22 Object is possibly 'undefined'"
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
To hand the agent information without framing it as a failure, use `hookSpecificOutput.additionalContext` instead — it lands in context without asserting that something went wrong.
|
|
57
|
+
|
|
58
|
+
_Return the diagnostic, not the fact of it._ "Typecheck failed" costs the agent a whole turn rediscovering what this hook already knew; the compiler's actual lines let it fix the problem immediately.
|
|
59
|
+
|
|
60
|
+
## What it is for
|
|
61
|
+
|
|
62
|
+
- **Formatting and linting what was just edited** — the deterministic pass that should never be a request in prose.
|
|
63
|
+
- **Typechecking the touched file** and returning the errors, so a broken edit is corrected in the same turn it was made.
|
|
64
|
+
- **Tracking what changed.** Recording edited paths gives later turns, and a `Stop` hook, something concrete to act on.
|
|
65
|
+
- **Feeding back a consequence the agent cannot see** — a failing test, a schema that no longer matches, a generated file now stale.
|
|
66
|
+
|
|
67
|
+
## What it is not for
|
|
68
|
+
|
|
69
|
+
**Do not use it to prevent anything.** The tool has run; a hook that reads like a guard here is a guard that arrives too late. Prevention is [`hook-pre-tool-use`](../hook-pre-tool-use/SKILL.md).
|
|
70
|
+
|
|
71
|
+
Be careful making it write. A hook that reformats the file the agent just edited changes content the agent believes it knows, and the next edit is built on a stale picture. Either keep the rewrite small and mechanical, or report instead of rewriting.
|
|
72
|
+
|
|
73
|
+
## Failure modes
|
|
74
|
+
|
|
75
|
+
- _Whole-project work on one file's event._ Typechecking the entire monorepo because one file changed. It fires on every edit; scope it to `tool_input.file_path` or don't do it here.
|
|
76
|
+
- _Verdict without evidence._ Blocking with "lint failed" and swallowing the output. The agent has to re-run the tool it can't see to learn what this hook already had.
|
|
77
|
+
- _Silent rewrite._ Reformatting the edited file and returning `0`. The agent's next edit targets text that no longer exists, and the failure looks like the agent's mistake.
|
|
78
|
+
- _Blocking on the expected._ Returning `decision: "block"` for a condition that is normal mid-task — a half-written module that doesn't typecheck yet. The agent is dragged into fixing something it was already about to finish.
|
|
79
|
+
- _Assuming success._ Reading `tool_response` without checking whether the call actually succeeded, then reporting failures caused by a tool that never ran.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hook-pre-tool-use
|
|
3
|
+
description: Writing a PreToolUse lifecycle hook — the one that can allow, deny, or escalate a tool call before it runs.
|
|
4
|
+
registryDependencies: [writing-great-hooks]
|
|
5
|
+
disable-model-invocation: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Shared rules for every hook — the invariants, the script mechanics, registration: [`writing-great-hooks`](../writing-great-hooks/SKILL.md).
|
|
9
|
+
|
|
10
|
+
`PreToolUse` fires after the agent has chosen a tool and filled in its arguments, but **before the tool runs**. It is the only event that can stop an action from happening at all, which makes it the place for guardrails and policy, and the wrong place for anything that merely wants to observe.
|
|
11
|
+
|
|
12
|
+
## Payload
|
|
13
|
+
|
|
14
|
+
The four common fields, plus the call about to be made:
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"session_id": "abc123",
|
|
19
|
+
"transcript_path": "/home/you/.claude/projects/<slug>/<session>.jsonl",
|
|
20
|
+
"cwd": "/home/you/project",
|
|
21
|
+
"hook_event_name": "PreToolUse",
|
|
22
|
+
"tool_name": "Write",
|
|
23
|
+
"tool_input": { "file_path": "/home/you/project/src/index.ts", "content": "…" }
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`tool_input` is shaped by the tool, so a hook matching more than one tool must branch on `tool_name` before reading a field. Never assume `file_path` exists.
|
|
28
|
+
|
|
29
|
+
## Matcher
|
|
30
|
+
|
|
31
|
+
This event selects by tool name, as a regex:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"matcher": "Edit|MultiEdit|Write",
|
|
36
|
+
"hooks": [{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/guard-protected-paths.ts" }]
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Omit `matcher` to see every tool call. **Scope it as tightly as the rule allows** — an unmatched hook is a process spawned on every tool call for the life of the session.
|
|
41
|
+
|
|
42
|
+
## What the exit code does
|
|
43
|
+
|
|
44
|
+
- **`0` — the call proceeds.** stdout goes to the transcript, not to the agent.
|
|
45
|
+
- **`2` — the call is denied**, and stderr is fed to the agent as the reason. This is the veto, and the agent can read the reason and try something else.
|
|
46
|
+
- **anything else** — a non-blocking error: the call still runs, and stderr goes to the user.
|
|
47
|
+
|
|
48
|
+
For the full decision, print JSON and exit `0`:
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"hookSpecificOutput": {
|
|
53
|
+
"hookEventName": "PreToolUse",
|
|
54
|
+
"permissionDecision": "deny",
|
|
55
|
+
"permissionDecisionReason": "src/generated/ is written by `bun run codegen`. Edit the template instead."
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- **`allow`** runs the call and skips the permission prompt the user would otherwise see.
|
|
61
|
+
- **`deny`** blocks it and hands the reason to the agent.
|
|
62
|
+
- **`ask`** puts it to the user, whatever the current permission mode would have done.
|
|
63
|
+
|
|
64
|
+
_Write the reason to the agent, not to a log._ It is the only thing the agent gets, and a good one turns a dead end into a corrected second attempt: name what was refused and what to do instead.
|
|
65
|
+
|
|
66
|
+
## What it is for
|
|
67
|
+
|
|
68
|
+
- **Protecting paths and resources** — generated directories, lockfiles, anything with a real source elsewhere.
|
|
69
|
+
- **Steering to the project's own tooling.** This repo registers a `PreToolUse` guard on `Bash|Grep` and `Read|Glob` that pushes the agent to query the graph before raw searching — policy that would otherwise be a paragraph of prose the agent may or may not honour.
|
|
70
|
+
- **Pre-flight validation** — refusing a command whose arguments are malformed, out of scope, or aimed outside the project.
|
|
71
|
+
|
|
72
|
+
## What it is not for
|
|
73
|
+
|
|
74
|
+
**Do not put a slow check here.** Every matching tool call waits on it, and the agent is idle while it runs. Verification of a result belongs in [`hook-post-tool-use`](../hook-post-tool-use/SKILL.md), which pays its cost after the work rather than in front of it.
|
|
75
|
+
|
|
76
|
+
Nor should it encode judgement. A hard rule — this path is generated, that command is forbidden — is a guardrail. "Is this edit a good idea" is not, and hardcoding it produces a veto nobody can see or argue with.
|
|
77
|
+
|
|
78
|
+
## Failure modes
|
|
79
|
+
|
|
80
|
+
- _Blanket matcher._ No `matcher`, or `.*`, for a rule that concerns two tools. Every call in the session now pays for it.
|
|
81
|
+
- _Wrong field, wrong tool._ Reading `tool_input.file_path` on a `Bash` call, getting `undefined`, and treating that as "not a protected path". Branch on `tool_name` first, and fail closed when the shape is unfamiliar.
|
|
82
|
+
- _Reasonless denial._ Exit `2` with an empty stderr, or a JSON `deny` with no `permissionDecisionReason`. The agent knows only that it was stopped, so it retries the same thing.
|
|
83
|
+
- _Path comparison by string._ Matching `"src/generated"` against a raw argument, which `./src/../src/generated` and an absolute path both defeat. Resolve, then compare.
|
|
84
|
+
- _Shell interpolation._ Pasting a payload field into a shell command. The agent's arguments reach a shell running with the user's credentials.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hook-stop
|
|
3
|
+
description: Writing a Stop lifecycle hook — the one that can refuse to let the agent end its turn, and the one that can loop forever if written carelessly.
|
|
4
|
+
registryDependencies: [writing-great-hooks]
|
|
5
|
+
disable-model-invocation: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Shared rules for every hook — the invariants, the script mechanics, registration: [`writing-great-hooks`](../writing-great-hooks/SKILL.md).
|
|
9
|
+
|
|
10
|
+
`Stop` fires when the agent is about to finish its response. Its power is refusal: exit `2` and the turn does not end — the agent reads your reason and keeps working. That makes it the place for "not done until…" conditions, and the one event that can trap a session in a loop.
|
|
11
|
+
|
|
12
|
+
It takes **no matcher**. `SubagentStop` is the sibling event for subagents finishing, and needs its own registration.
|
|
13
|
+
|
|
14
|
+
## Payload
|
|
15
|
+
|
|
16
|
+
The four common fields, plus the loop guard:
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"session_id": "abc123",
|
|
21
|
+
"transcript_path": "/home/you/.claude/projects/<slug>/<session>.jsonl",
|
|
22
|
+
"cwd": "/home/you/project",
|
|
23
|
+
"hook_event_name": "Stop",
|
|
24
|
+
"stop_hook_active": false
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**`stop_hook_active` is `true` when the agent is only still running because this hook already blocked it.** Check it first and let the stop through when it is set. Without that guard, a condition the agent cannot satisfy — a test failing for an unrelated reason, a check with a bug — blocks, prompts, blocks again, and never terminates.
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
if (payload.stop_hook_active) process.exit(0);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## What the exit code does
|
|
35
|
+
|
|
36
|
+
- **`0` — the turn ends** as it was going to.
|
|
37
|
+
- **`2` — the agent is not allowed to stop**, and stderr becomes its instruction for what to do next.
|
|
38
|
+
- **anything else** — a non-blocking error; the turn ends and stderr goes to the user.
|
|
39
|
+
|
|
40
|
+
The JSON form requires the reason, because the reason _is_ the next instruction:
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"decision": "block",
|
|
45
|
+
"reason": "bun test failed in packages/core: 2 failing in tests/registry/io.test.ts. Fix these before finishing."
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
A blocked stop with a vague reason is worse than no hook: the agent knows only that it may not stop, so it produces filler and tries again.
|
|
50
|
+
|
|
51
|
+
## What it is for
|
|
52
|
+
|
|
53
|
+
- **Refusing to finish over a broken build** — a failing typecheck or test suite in the package that was touched this turn.
|
|
54
|
+
- **Enforcing a completion criterion the agent tends to skip** — the changelog entry, the regenerated artifact, the doc updated alongside the code.
|
|
55
|
+
- **Closing the loop on tracked work**, using the paths a [`hook-post-tool-use`](../hook-post-tool-use/SKILL.md) hook recorded, so the check only covers what actually changed.
|
|
56
|
+
|
|
57
|
+
## What it is not for
|
|
58
|
+
|
|
59
|
+
**Do not use it as a chore runner.** Blocking is expensive — it spends a full turn of the agent's attention and the user's time. If the work is mechanical and does not need the agent's judgement, do it in the hook and exit `0`.
|
|
60
|
+
|
|
61
|
+
And keep it cheap on the common path. It runs at the end of every turn, including the ones that only answered a question; a full test suite there taxes the entire session. Check whether anything relevant changed before doing real work.
|
|
62
|
+
|
|
63
|
+
## Failure modes
|
|
64
|
+
|
|
65
|
+
- _The infinite loop._ Blocking without honouring `stop_hook_active`, on a condition the agent cannot fix. This is the defining failure of the event and the reason the field exists.
|
|
66
|
+
- _Blocking on the pre-existing._ Refusing the stop over a test that was already failing before the turn started. The agent is held responsible for something it did not touch and cannot resolve.
|
|
67
|
+
- _Reason without a next step._ `"Checks failed."` The agent cannot act on it, so it stalls or invents work.
|
|
68
|
+
- _Turn-end tax._ A full build on every stop, including turns that changed nothing. Gate on the tracked file list first.
|
|
69
|
+
- _Silent success._ Exiting `0` when the check itself errored — a missing binary, a bad path — so a hook that has quietly stopped working looks exactly like a passing one. Report the breakage as a non-blocking error instead.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hook-user-prompt-submit
|
|
3
|
+
description: Writing a UserPromptSubmit lifecycle hook — the one that can add context to a prompt or reject it before the agent reads it.
|
|
4
|
+
registryDependencies: [writing-great-hooks]
|
|
5
|
+
disable-model-invocation: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Shared rules for every hook — the invariants, the script mechanics, registration: [`writing-great-hooks`](../writing-great-hooks/SKILL.md).
|
|
9
|
+
|
|
10
|
+
`UserPromptSubmit` fires the instant the user submits, **before the agent has seen the prompt**. That position is the whole point: it is the only event that can put words in front of the agent that nobody typed, and the only one that can make a prompt never happen.
|
|
11
|
+
|
|
12
|
+
It takes **no matcher** — there is no tool to match. Register it with an entry that has only a `hooks` array.
|
|
13
|
+
|
|
14
|
+
## Payload
|
|
15
|
+
|
|
16
|
+
The four common fields, plus the prompt itself:
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"session_id": "abc123",
|
|
21
|
+
"transcript_path": "/home/you/.claude/projects/<slug>/<session>.jsonl",
|
|
22
|
+
"cwd": "/home/you/project",
|
|
23
|
+
"hook_event_name": "UserPromptSubmit",
|
|
24
|
+
"prompt": "add a migration for the orders table"
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## What the exit code does
|
|
29
|
+
|
|
30
|
+
- **`0` — stdout is injected into the agent's context.** This event and `SessionStart` are the only places where plain stdout reaches the agent as content rather than transcript noise. Print nothing and nothing is added.
|
|
31
|
+
- **`2` — the prompt is blocked and erased.** It never reaches the agent, and stderr is shown to the user alone. Use it to refuse, not to advise.
|
|
32
|
+
- **anything else** — the prompt proceeds untouched; stderr goes to the user as a non-blocking error.
|
|
33
|
+
|
|
34
|
+
Because bare stdout is already the injection channel, the simplest useful hook is an `echo` and an exit `0`. Reach for JSON when you need a field the plain channel can't express:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"hookSpecificOutput": {
|
|
39
|
+
"hookEventName": "UserPromptSubmit",
|
|
40
|
+
"additionalContext": "Current sprint: S-42. Active branch: fix/orders-migration."
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
To reject from JSON instead of exit `2`, print `{"decision": "block", "reason": "..."}` — the reason is shown to the user in place of the prompt.
|
|
46
|
+
|
|
47
|
+
## What it is for
|
|
48
|
+
|
|
49
|
+
- **Injecting state the agent cannot see** — current branch, sprint, ticket, today's date, which service the user is in. Cheap, and it lands before the first token of reasoning.
|
|
50
|
+
- **Routing to skills.** Match the prompt against trigger patterns and inject a line naming the skill that fits, so activation stops depending on the agent noticing.
|
|
51
|
+
- **Refusing prompts that must not run** — a production-touching phrase, a missing ticket reference — by exiting `2` with a reason.
|
|
52
|
+
|
|
53
|
+
## What it is not for
|
|
54
|
+
|
|
55
|
+
**Do not use it to rewrite what the user meant.** Injected context is invisible to the person who typed the prompt: they see their words, the agent sees yours, and every downstream surprise is unattributable. Add facts, not instructions that contradict the prompt.
|
|
56
|
+
|
|
57
|
+
Keep it fast. It sits between the user pressing enter and anything at all happening, so its latency is felt directly on every single turn.
|
|
58
|
+
|
|
59
|
+
## Failure modes
|
|
60
|
+
|
|
61
|
+
- _Silent hijack._ Injected text that redirects the task rather than informing it. The user cannot see it, cannot tell why the agent went sideways, and cannot turn it off.
|
|
62
|
+
- _Context creep._ A paragraph injected on every prompt, most of it irrelevant to this one. It is paid on every turn for the whole session — inject the fields that change, not a status dump.
|
|
63
|
+
- _Blocking too eagerly._ Exit `2` on a pattern that also matches innocent prompts. The user has no override and the prompt is already gone; prefer injecting a warning unless the action is genuinely unrecoverable.
|
|
64
|
+
- _Leaking the payload._ Echoing the whole prompt into a log or an error message. Prompts carry secrets, and this hook sees every one of them.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "workflow",
|
|
3
|
+
"description": "Work a phase of a plan through plan, execute, review and sync, one agent per step, with hooks deciding when a step is finished.",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"dependencies": ["task-manager@g3n"],
|
|
7
|
+
"skills": [
|
|
8
|
+
"./skills/run",
|
|
9
|
+
"./skills/plan",
|
|
10
|
+
"./skills/execute",
|
|
11
|
+
"./skills/review",
|
|
12
|
+
"./skills/sync",
|
|
13
|
+
"./skills/orchestrator",
|
|
14
|
+
"./skills/worktree"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reviewer
|
|
3
|
+
description: Read-only reviewer for the review step of the workflow. Judges each in-review task of a phase against its own brief and moves it to completed or back to in-progress. Use for the review step of a workflow run.
|
|
4
|
+
disallowedTools: Edit, Write, NotebookEdit
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You review the tasks of one phase by following the `/review` skill. Load it before anything else.
|
|
8
|
+
|
|
9
|
+
You change no file. The only state you move is a task's status, through `g3n-skills hook set-state`. Your findings go into your final report, which is the one thing the agent that spawned you will read, so each finding names the file and line, what is wrong, and what done looks like.
|