When a checker finds an error, a hook can send that error to the agent, without you having to copy it into the conversation. In this video, we send a type error to the agent through a hook. Then we look at what the agent needs in order to inspect an image.
This function promises to return an integer, but it converts the sum to a string, so it returns text. After an edit, a hook runs the type checker, mypy, and saves its error to a log file. The checker has done its job. But saving a file does not, by itself, put that error in the model's context.
The handler puts the error message in the additional context field of a JSON response and prints that JSON to standard output. Claude Code reads the handler's standard output, extracts that field, and includes the error alongside the tool result in its next request to the model. The agent then has the information it needs to correct the Python function. The response should be short. Each message takes up space in the agent's context. The more detailed log can remain on disk for inspection.
If the agent repeats the mistake, first check whether the error message was included in the model's input. Then look at what the agent did next to see how it responded to the error.
This is the response our handler actually printed after that edit. It belongs to the Post Tool Use event. The edit has already succeeded, and the handler has checked the resulting code. The event name tells Claude Code which output format we are using.
The additional context field carries text for the model, alongside the tool result. Here it names the command that ran, the file and line, and the type mismatch, and it gives the path of the full log. For this event, simply printing ordinary output is not the same as adding text to the model's context.
There are two program results to distinguish here. The checker found a problem, so it exited with a failure status. The handler succeeded in reporting that problem. It exits with zero and prints a valid JSON response. Keep the handler's debug messages out of its standard output, so they do not corrupt that response.
A useful diagnostic tells the agent what ran, where the problem is, and what the checker reported. A message that only says "check failed" makes the agent reconstruct information we already have. So be sure to return the relevant error, with enough context to locate it.
A long run can produce much more output than the next correction needs. Our handler saves the complete output to a log file, and returns up to ten error lines together with the log's path. When the check passes, it adds nothing. A hook that runs after every edit should give the agent useful information, without filling the conversation with repeated success reports.
So far, the feedback has been a text error that the model can read. If the agent is working on a plot, it needs to see the rendered image to check its appearance. The additional context field accepts text, so we cannot use it to attach the image itself. Instead, the hook can render the image and return its path with an instruction to inspect it using Read, as shown here. Claude Code adds that message to the model's context. When the agent calls Read on the file, the tool supplies the image itself. The agent can then continue working to fix any visual problems it finds. The instruction does not make the Read call happen automatically. Check that the agent actually reads the image, and that after making a correction it inspects the new render.
With a synchronous hook, the agent waits for the hook to finish before continuing. A check that runs after every edit adds that wait each time. Start with a fast check and measure how long it takes in your project. A larger suite, such as the project's full check script, can run when the agent finishes, or in continuous integration, also called CI, on the server. There it does not delay every small change.
Test the handler itself. Try a file it should ignore, a path that contains spaces, broken source code, and an environment where the checker is missing. Broken code should come back as a defect in the code. A missing checker should come back as a setup failure, which says that the code was not checked.
You now know how to return a hook's results to the model's context. See you in the next video.