EONYX Hooks: Automation Around Tool Calls
Hooks are shell commands that EONYX runs around tool calls: before (before) and after (after). They are a convenient way to bolt on auto-formatting, auditing, checks and guardrails without touching the agent’s code.
1 How hooks work
A hook is declared in the config and fires around a tool call — below are the record format, the before/after phases and how to pass context into a hook.
1.1 Format
Hooks are set in eonyx.json as an object where the key is the tool name and the value is before and/or after:
"hooks": {
"write": {
"before": "echo \"writing: $EONYX_INPUT\" >> .eonyx/audit.log",
"after": "gofmt -l ."
},
"edit": {
"after": "gofmt -l ."
}
}No “events” and no “matchers” — everything is tied to the tool name (write, edit, bash, git_commit, MCP tools and so on).
1.2 The before and after phases
| Phase | When | Effect |
|---|---|---|
before | before the tool | a non-zero exit code blocks the tool; the error goes to the model |
after | after a successful call | the output (stdout and stderr) is appended to the tool result (the model sees it) |
- An empty/missing hook is a no-op.
- An error in an
afterhook does not break the result: it is kept with a(hook after <tool> failed: …)note. afterdoes not run if the tool itself failed.- Every hook runs in the shared shell session with a 30 second timeout.
before hook is a guardrail. For example, forbid git_commit when tests have not been run, or bash in a dangerous directory.1.3 Context through variables
Data is passed to the hook through environment variables, not by substitution into the command text — so the contents of the input/result cannot “break” your command (injection is impossible):
| Variable | What it holds |
|---|---|
EONYX_TOOL | tool name |
EONYX_PHASE | before or after |
EONYX_CWD | the shell’s current working directory |
EONYX_INPUT | the tool’s raw JSON input |
EONYX_RESULT | the tool result (only in after) |
2 Recipes
A few ready-made scenarios — auto-formatting, an audit log and blocking commits without green tests.
Format the code after every edit:
"hooks": {
"write": { "after": "gofmt -w ." },
"edit": { "after": "gofmt -w ." },
"multi_edit": { "after": "gofmt -w ." }
}Log every shell command:
"hooks": {
"bash": { "before": "echo \"[$(date -Is)] $EONYX_INPUT\" >> .eonyx/bash-audit.log" }
}Do not allow commits until the tests are green:
"hooks": {
"git_commit": { "before": "go test ./... >/dev/null 2>&1 || { echo 'tests failing'; exit 1; }" }
}A non-zero exit will block the commit, and the message will go to the model.
bash tool), with your privileges. Write them as carefully as any other script: keep them fast (30s limit) and idempotent.3 Summary
- Format
- the key is the tool name, the value is
before/after - no events and no matchers
- the key is the tool name, the value is
- Phases
beforeblocks the tool with a non-zero exit codeafterappends its output to the result
- Context
- passed through
EONYX_*variables - no substitution into the text — injection is impossible
- passed through
- Limits
- 30s timeout, shared shell session
aftererrors do not break the result
- Recipes
- auto-format, audit log, blocking commits without tests