python3, so they work on desktop and on Qualia Cloud: block rm -rf in shell commands, log shell commands and file edits to .quadrillion/hook-log.jsonl, and check Python syntax before the agent finishes. Using a template adds its hooks to Workspace hooks as an unsaved draft and keeps the hooks already in the file. The Templates menu in the editor adds the same ones to the file you are editing. If the file is not valid JSON, Qualia asks before replacing it with the template.
To format code or run your tests, see Examples.
Workspace and personal hooks
- Workspace hooks are stored with the project in
.quadrillion/hooks.json, so collaborators get the same file. - Personal hooks apply across all your workspaces. On desktop they live in Qualia’s configuration directory; on Qualia Cloud they are stored with your account.
Review before hooks run
A hook file does nothing until you enable it. After saving, click Enable reviewed hooks. Qualia remembers the exact version you enabled, separately for each person. If the file changes afterwards, for example because a collaborator edited it, its hooks stop running until you review and enable the new version. The agent notes in chat when hooks were skipped for this reason, and also warns in chat when a hook file you had enabled has been deleted. Ifhooks.json changes on disk while you are editing it, Save fails and asks you to reload. The error offers Copy edits so you can keep your draft; Reload asks before it discards unsaved edits.
Configuration
matcher and one or more commands.
Command options:
A file can hold up to 32 commands.
Matchers
A matcher selects tools by name. Separate alternatives with| and use * as a wildcard. An empty matcher, *, or .* matches every tool. The agent’s replies to you are not tool calls, so no matcher selects them and they always stream; use a Stop hook to act when the agent finishes.
You can use Qualia’s tool names (such as bash_command or edit_cell) or these common names: Bash/Shell for shell commands, Read, Write, and Edit for file tools, and mcp__<server>__<tool> for MCP tools. Stop groups take no matcher.
While a
PreToolUse hook matches a tool, that tool’s output does not stream live. It appears once the hook has allowed it, so the hook runs before anything changes. A PreToolUse group that matches every tool (an empty matcher, *, or .*) holds back every cell, edit, and write until the hook approves it, and the Hooks editor shows a note when your file has one. Narrow the matcher to keep live streaming for the other tools.What your command receives
Each command gets a JSON object on standard input withhook_event_name, session_id, cwd, tool_name, tool_input, and, after a tool runs, tool_response. Shell and file tools also include tool_input.command or tool_input.file_path.
tool_name uses the common name when a tool has one (Bash, Read, Write, Edit, or mcp__<server>__<tool>), and qualia_tool_name always holds Qualia’s own name, such as bash_command. Tool events also include tool_use_id, which identifies the call. stop_hook_active is true once a Stop hook has already sent the agent back to work in this turn. The environment variables QUALIA_PROJECT_DIR and CLAUDE_PROJECT_DIR hold the workspace folder. Qualia does not provide a transcript_path, so scripts that read the conversation transcript will not work unchanged.
The input is capped at 96 KiB. When a tool’s input or response is larger, Qualia shortens its long strings and adds "truncated": true at the top level, so check that field before trusting the full content.
Responding
- Exit code 0 allows the action. Output that is a JSON object can carry a decision (see below).
- Exit code 2 blocks a
PreToolUsetool, or sends the agent back to work from aStophook. FromPostToolUseorPostToolUseFailure, it passes the reason to the agent and keeps it working; the tool has already run. Standard error becomes the reason shown to the agent. - Any other exit code counts as a hook error. Errors are reported in chat and do not stop the agent, unless the command sets
fail_closed.
Qualia cannot ask for your approval from a hook or rewrite a tool’s input. A
PreToolUse response that asks for approval (permissionDecision: "ask") or returns updatedInput blocks the tool rather than running it unchanged. Responses follow the Claude Code format; fields Qualia does not use, including Cursor’s permission and followup_message, are ignored.
Where hooks run
On desktop, hooks run on your computer inside the same sandbox as the agent’s shell commands when sandboxing is on (Settings > Agents > Sandboxing). On Qualia Cloud, hooks run in your workspace’s cloud sandbox. Hooks can use the same programs as the agent’s shell commands. On desktop, that is what your shell finds on itsPATH. On Qualia Cloud, the sandbox has python3 and common shell tools, but not project tools such as pytest or ruff. Install them in the sandbox, or point the hook at a copy inside your project, such as .venv/bin/pytest.
Web search and page fetches run as the web_search and web_fetch tools, so hooks can match them like any other tool.
Examples
These hooks call tools that Qualia does not install, so installruff or pytest where hooks run first (see Where hooks run). If the tool is missing, each hook reports a hook error that names it and lets the agent carry on.
Format Python files with ruff after the agent edits them:
pytest before the agent finishes, and send it back with the last lines of the test output when tests fail. A project with no tests passes.
Importing from Claude Code or Codex
Click Import from Claude Code or Import from Codex to copy supported command hooks into the hooks you are editing. Workspace hooks read the project’s.claude/settings.json, .claude/settings.local.json, .codex/hooks.json, or .codex/config.toml. Personal hooks read only files in your home folder, and only on desktop: ~/.claude/settings.json, ~/.codex/hooks.json, and ~/.codex/config.toml. ~/.claude/settings.local.json is not read.
Each source shows a preview first. Click Add hook(s) to draft, then save, review, and enable the result as usual. A file holds at most 32 commands, so when your draft is nearly full the preview says how many fit and the rest are skipped. Imports only copy commands; the scripts they call are not copied, and later changes in Claude Code or Codex are not synced.
Unsupported events, options, and tools are skipped and listed in the preview. For example, MultiEdit in Write|Edit|MultiEdit is dropped and the rest of the matcher is kept. Claude Code tool names with a differently named Qualia tool are renamed: Grep to ripgrep, Glob to list, WebFetch to web_fetch, WebSearch to web_search, and NotebookEdit to edit_cell|append_cell. These tools take different input fields, so check scripts that read tool_input. Commands without a timeout, or with one above 120 seconds, get 120 seconds.
The preview also lists the response fields Qualia honors (see Responding). Before enabling imported PreToolUse guards, check whether their scripts ask for approval or return updatedInput; Qualia blocks the tool in both cases.
Testing
With a hook file enabled, open Test a hook below the editor and click Run test to send a sample event, such as aPreToolUse event for bash_command. Test runs execute your hook commands for real but never run the agent tool. Each result shows why a hook failed, such as a timeout, a nonzero exit status, or a response Qualia could not read.
