Hook System
Lifecycle shell scripts that run at key points in every agent session — inject context, block dangerous tools, or log activity automatically.
Overview
Hooks are plain shell scripts placed in .misar/hooks/. The agent runtime executes them at defined lifecycle events, letting you extend agent behaviour without modifying any extension settings.
.misar/
└── hooks/
├── session-start.sh # Runs once when a session begins
├── pre-tool-use.sh # Runs before every tool call
└── post-tool-use.sh # Runs after every tool call
All scripts must be executable:
chmod +x .misar/hooks/*.sh
Hook Reference
| Hook | Trigger | Can block? | Timeout |
|------|---------|------------|---------|
| session-start.sh | Extension activation, new session, clear, compact | No | None |
| pre-tool-use.sh | Before each tool call | Yes (exit 1) | 5 seconds |
| post-tool-use.sh | After each tool call | No | Fire-and-forget |
session-start.sh
Runs once at the beginning of a session. Stdout is injected directly into the agent's system context.
Arguments:
$1— event type:startup|resume|clear|compact
Environment variables:
MISAR_SESSION_EVENT— same value as$1MISAR_WORKSPACE— absolute path to the current workspace
#!/bin/bash
# .misar/hooks/session-start.sh
# Inject dynamic project context at session start
echo "Branch: $(git branch --show-current 2>/dev/null || echo 'unknown')"
echo "Uncommitted files: $(git status --short 2>/dev/null | wc -l | tr -d ' ')"
echo "Node version: $(node --version 2>/dev/null || echo 'not installed')"
echo "Last deployment: $(cat .misar/last-deploy.txt 2>/dev/null || echo 'none')"
On compact events the session context has been summarised. Use this to re-inject any critical facts that may have been trimmed.
pre-tool-use.sh
Runs before every tool call. You control whether the tool is allowed to execute.
Arguments:
$1— tool name (e.g.run_command,write_file,bash)
Stdin: JSON payload with tool arguments.
Exit codes:
0— allow the tool call to proceed1— block the tool call; stderr is shown to the agent as the reason
Stdout: Optional JSON with additionalContext injected into the agent's next message:
{ "additionalContext": "extra context for agent" }
#!/bin/bash
# .misar/hooks/pre-tool-use.sh
TOOL=$1
ARGS=$(cat)
# Block rm -rf on production paths
if [ "$TOOL" = "run_command" ]; then
CMD=$(echo "$ARGS" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('command',''))" 2>/dev/null)
if echo "$CMD" | grep -qE "rm\s+-rf\s+/"; then
echo "Blocked: recursive delete from root is not allowed." >&2
exit 1
fi
fi
# Inject lint status before any file write
if [ "$TOOL" = "write_file" ] || [ "$TOOL" = "edit_file" ]; then
LINT=$(pnpm lint --silent 2>&1 | tail -5)
echo "{\"additionalContext\": \"Current lint status: $LINT\"}"
fi
exit 0
The 5-second timeout applies to the entire hook execution. Keep pre-tool-use hooks fast to avoid slowing down the agent loop.
post-tool-use.sh
Runs after every tool call. Fire-and-forget — the agent does not wait for it and it cannot affect the result.
Arguments:
$1— tool name
Stdin: JSON payload with tool name, arguments, and result.
#!/bin/bash
# .misar/hooks/post-tool-use.sh
TOOL=$1
PAYLOAD=$(cat)
# Auto-lint after file writes
if [ "$TOOL" = "write_file" ] || [ "$TOOL" = "edit_file" ]; then
FILE=$(echo "$PAYLOAD" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('path',''))" 2>/dev/null)
if [ -n "$FILE" ]; then
pnpm eslint --fix "$FILE" > /dev/null 2>&1 &
fi
fi
# Log tool usage to a local audit file
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) $TOOL" >> .misar/tool-log.txt
Use Cases
Inject Git Context
Surface the current branch, recent commits, or diff stats into every session automatically.
Block Dangerous Commands
Intercept run_command calls and block patterns like rm -rf, force push, or production database writes.
Auto-lint on Write
Run your formatter or linter after every file edit so code is always clean without manual runs.
Audit Trail
Log every tool call with timestamp to a local file for compliance or debugging purposes.
Debugging Hooks
If a hook behaves unexpectedly, run it manually with the expected arguments:
# Test session-start with a startup event
bash .misar/hooks/session-start.sh startup
# Test pre-tool-use with a synthetic payload
echo '{"command": "ls -la"}' | bash .misar/hooks/pre-tool-use.sh run_command
echo $? # 0 = allowed, 1 = blocked
Hook errors are surfaced in the VS Code Output panel under Misar Code. If pre-tool-use.sh exits non-zero unexpectedly, the tool call is blocked and the agent reports the stderr message.