Skip to content

@tank/hook-creator

1.0.0
Skill

Description

Author Tank hook atoms that intercept agent lifecycle events. Covers canonical hook events, DSL and JS/TS handlers, manifest wiring, and production patterns.

Triggered by

create hookhook atomtank hookpre-stop hookDSL handlerJS handler
Download
Verified
tank install @tank/hook-creator

Tank Hook Creator

Core Philosophy

  1. Hooks are guardrails, not gods. A hook intercepts a single lifecycle event, makes a binary decision (block/allow/rewrite/inject), and exits. Keep them narrow and deterministic.

  2. DSL first, JS when forced. DSL handlers are portable across every adapter. Reach for JS/TS only when you need stateful logic, external delegation, or complex parsing. -> See references/handler-types.md

  3. Pre-events block, post-events observe. Pre-events (pre-stop, pre-tool-use, pre-command) can halt execution. Post-events (post-tool-use, post-file-write) can only inject context or trigger follow-up work.

  4. One hook, one concern. Separate safety gates, formatting hooks, and context injectors into distinct atoms. Composability beats monoliths.

  5. Canonical events only. Never invent event names. Use the 30+ events from the Tank specification. Adapters translate these to platform equivalents. -> See references/hook-events-catalog.md

Quick-Start: Common Problems

"Block the agent from stopping until tests pass"

  1. Choose event: pre-stop (blocking).
  2. Choose handler: JS (needs to run tests and parse output).
  3. Wire the atom in tank.json with "event": "pre-stop".
  4. In the handler, call ctx.continueWithMessage(...) to block, or return to allow. -> See references/worked-examples.md (Pre-Stop Blocker)

"Prevent dangerous shell commands"

  1. Choose event: pre-command.
  2. Choose handler: DSL with block action and match pattern.
  3. Add the atom: { "kind": "hook", "event": "pre-command", "handler": { "type": "dsl", "actions": [{ "action": "block", "match": "rm -rf /", "reason": "Destructive command" }] } } -> See references/worked-examples.md (Pre-Command Safety Gate)

"Auto-format files after the agent writes them"

  1. Choose event: post-file-write.
  2. Choose handler: JS (needs to detect file type and run formatter).
  3. In the handler, inspect the written file path, run the appropriate formatter, report results via context injection. -> See references/worked-examples.md (Post-File-Write Auto-Formatter)

"Inject project context when a session starts"

  1. Choose event: session-created.
  2. Choose handler: DSL with injectContext action, or JS for dynamic context.
  3. Provide the context string or file path in the action payload. -> See references/worked-examples.md (Session-Start Context Injector)

Decision Trees

Handler Type Selection

SignalUse DSLUse JS/TS
Simple string match (block/allow)YesOverkill
Static context injectionYesOverkill
Need to run shell commandsNoYes
Need to parse structured outputNoYes
Need to delegate to another agentNoYes
Need state across multiple invocationsNoYes
Portability across all adapters is criticalYesRisky

Event Category Selection

GoalEvent CategoryKey Events
Gate agent actionsTool / Shellpre-tool-use, pre-command
Quality checks before completionStoppre-stop
React to file changesFilepost-file-write, file-edited
Inject context at startSessionsession-created
Transform system promptsSystem promptsystem-prompt-transform
Monitor subagent behaviorSubagentsubagent-tool-use
Enforce permissionsPermissionspermission-asked

Manifest Wiring

ComponentLocation in tank.json
Hook atomatoms[] with kind: "hook"
Event bindingevent field on the hook atom
DSL handlerhandler: { type: "dsl", actions: [] }
JS handlerhandler: { type: "js", entry: "..." }
Companion agentSeparate atom with kind: "agent"

Reference Index

FileContents
references/hook-events-catalog.mdAll 30+ canonical events with when-to-use guidance
references/handler-types.mdDSL vs JS handlers, actions, canonical tool names
references/worked-examples.md4+ production hook patterns with full code

Command Palette

Search packages, docs, and navigate Tank