Mohamed Ashraf Elsaed

Hooks designed to fail open for AI coding agents

By Mohamed Ashraf ElsaedPublished 2 min read

A memory tool that blocks your coding agent is worse than no memory at all. That one rule shaped Aletheia’s hooks: a hook should not stop the tool that called it, whatever goes wrong. The hooks are built to fail open. This post covers what that includes and what it does not.

The rule

A hook is a command a tool runs at fixed moments. Aletheia’s entry point is aletheia hook <tool> <event>. It reads one JSON payload on standard input. If anything fails, it prints nothing and exits with code 0. The host sees success and carries on. (When it works, the session-start hook does print the context block.)

What “anything” includes

Failure What happens
The database is locked by another process The hook waits up to 50 ms, then writes the item to a spool file and exits 0
The database file is missing or unreadable The item goes to the spool
The payload is not valid JSON or is empty Nothing is stored, exit 0
The project is excluded by configuration Nothing is stored, exit 0

The spool is a JSON-lines file in the data directory with mode 0600. The next hook that finds the database healthy drains it first. I tested both paths in a temporary home: a store made unavailable on purpose, and a write lock held by another process. In both, the next hook flushed the spool and a search found the rows. The payloads were written by hand, not sent by a real host.

One gap matters. A watchdog ends the hook after 150 ms. If it fires while a write is in flight, that item is not spooled and is lost (the hooks reference says so). I did not trigger it.

What it costs

In my tests a post-tool hook took 0.04 to 0.05 seconds, and about 0.1 seconds while another process held the write lock. Those are single measurements on one machine, not a benchmark.

The trade-off

Fail-open means a broken hook is silent. The answer is a check you run on purpose: aletheia doctor reports the server, the hooks, the spool and the last capture, and shows a failing spool as a failure. Silence in the hook, noise in the doctor.

A host-side surprise

Some hosts ask you to approve a hook before it runs. Codex reviews non-managed hooks and skips new or changed ones until you trust them, using its /hooks screen. An installed hook that is not trusted yet does nothing, which is easy to mistake for a broken hook.

What I would do differently

I would have built doctor before the hooks. Fail-open without a way to see failures is just hiding them.

Sources

This post was drafted with AI assistance. I reviewed every claim and ran the commands shown.

About the project: Aletheia.

Mohamed Ashraf Elsaed
Mohamed Ashraf Elsaed
Technical Lead at Convertedin, Cairo. I build tools for AI coding agents and write about Laravel, Node and engineering.