[00:00] (0.00s)
When Enthropic announced hooks for
[00:01] (1.36s)
Claude Code, there was this comment from
[00:03] (3.28s)
Maximum Guide on the Claude AI
[00:05] (5.36s)
subreddit, and they said, "I'm going to
[00:07] (7.28s)
use this to make Claude meow. I've
[00:09] (9.28s)
always wanted a cat, but I'm allergic."
[00:11] (11.68s)
That felt like as good of a use case as
[00:13] (13.44s)
any to get started with. So, this is
[00:15] (15.52s)
what your cloud code can sound like when
[00:17] (17.12s)
you're running it in parallel.
[00:24] (24.40s)
Or maybe you prefer the old school
[00:32] (32.08s)
Or maybe you want Cloud Code to talk to
[00:33] (33.76s)
you. Editing ready for you bashing. Let
[00:37] (37.68s)
me quickly walk you through how I built
[00:39] (39.20s)
this. And I think this is a really great
[00:40] (40.72s)
project for getting started with Cloud
[00:42] (42.56s)
Code and hooks because when you assign
[00:44] (44.80s)
sounds to all of the different events,
[00:46] (46.80s)
you will start to understand when
[00:48] (48.56s)
they're getting triggered, which will
[00:50] (50.24s)
then help you come up with new ideas for
[00:52] (52.08s)
a bit more pragmatic ways that you can
[00:53] (53.92s)
use hooks, which is an incredibly
[00:55] (55.60s)
powerful addition to Claude Code. The
[00:57] (57.76s)
general idea here is that Claude has a
[01:00] (60.16s)
whole bunch of different types of events
[01:02] (62.00s)
and you can set up hooks to run custom
[01:04] (64.24s)
commands before or after or on those
[01:07] (67.20s)
different events. So some of those
[01:08] (68.80s)
events would be a pre-tool use. So
[01:11] (71.60s)
before it uses a tool, the tool includes
[01:14] (74.40s)
bash which you'll find out if you do
[01:16] (76.16s)
this is a lot of cloud code use. Uh it
[01:19] (79.20s)
is also editing files. It is reading
[01:21] (81.20s)
files. It is uh fetching stuff from the
[01:24] (84.00s)
web. Uh you can also do post tool use.
[01:26] (86.72s)
So this is letting you know after it's
[01:28] (88.32s)
finished that task. There's
[01:29] (89.68s)
notification. There's always been the
[01:31] (91.36s)
notification with cloud code that you
[01:32] (92.96s)
could set up with iTerm for instance to
[01:34] (94.80s)
beep when it's waiting for your approval
[01:36] (96.80s)
on something. But I found that it was
[01:38] (98.64s)
easy to miss this and didn't always work
[01:40] (100.24s)
great and I've really enjoyed being able
[01:41] (101.60s)
to customize that. There's stop. So this
[01:44] (104.00s)
is when cloud code's completed as its
[01:45] (105.52s)
task. I actually use this a lot in lie
[01:47] (107.76s)
of the notification. Uh and then there's
[01:50] (110.56s)
uh pre-ompact. So something that it's
[01:52] (112.16s)
going to do before it autocompacts all
[01:53] (113.92s)
of your history. Uh, so you can set up
[01:56] (116.88s)
uh Claude to run custom commands before
[01:59] (119.92s)
it does any of these actions. And the
[02:02] (122.32s)
way you're going to set that up is in
[02:03] (123.52s)
your settings.json. Now, anytime you're
[02:05] (125.84s)
editing your settings.json, you got to
[02:07] (127.44s)
figure out which one do you edit. And I
[02:09] (129.20s)
think this is a little confusing for
[02:10] (130.40s)
folks and probably worth a deep dive
[02:11] (131.84s)
later on. Uh, but generally for this use
[02:15] (135.04s)
case, I've been doing it in my
[02:16] (136.32s)
settings.json in my project. This way it
[02:19] (139.68s)
is committed to my repo and uh it will
[02:22] (142.80s)
be included on all of the uh work trees
[02:26] (146.80s)
that I'm running this on. I also have
[02:28] (148.80s)
created inside mycloud directory a hooks
[02:32] (152.88s)
directory where I'm storing all of the
[02:34] (154.88s)
files associated with these hooks here.
[02:38] (158.00s)
Uh and I suspect that I might end up
[02:40] (160.48s)
moving some of this stuff out to my user
[02:42] (162.96s)
settings, my uh user.cloud cloud
[02:45] (165.76s)
directory so that this is included in
[02:47] (167.36s)
all of my uh cloud usage across all my
[02:50] (170.40s)
projects. But for right now, I'm just
[02:51] (171.44s)
doing this on a single project. I did
[02:53] (173.20s)
not want to do it in my
[02:54] (174.08s)
settings.local.json because then it's
[02:55] (175.92s)
not committed to the repo and then I
[02:58] (178.16s)
don't get all of this across all the
[02:59] (179.52s)
different work trees. You've edited your
[03:01] (181.28s)
settings.json before. You've probably
[03:03] (183.68s)
just looked at the permissions. Uh and
[03:05] (185.92s)
this is a lot of permissions that I've
[03:07] (187.84s)
given Claude. Now we'll minimize those
[03:09] (189.60s)
for now. Uh and now we have hooks. So,
[03:13] (193.12s)
we're going to define the type of event
[03:15] (195.12s)
that we're going to trigger a hook on.
[03:17] (197.04s)
Hooks are a list and then uh a list of
[03:21] (201.12s)
uh dictionaries. And there's really I
[03:23] (203.60s)
think actually command is the only type
[03:25] (205.60s)
of hook that you can run. And for now,
[03:27] (207.84s)
the only thing I'm doing is running a
[03:29] (209.84s)
custom Python script. And so I'm running
[03:32] (212.32s)
Python 3 and then I'm passing the full
[03:34] (214.56s)
path of that script. So you can see that
[03:38] (218.32s)
here in my project I have claude hooks
[03:42] (222.00s)
and then the script called hook handler
[03:44] (224.08s)
and so I'm doing Python 3 users Greg
[03:47] (227.04s)
code YouTube tracker claude hooks etc.
[03:50] (230.32s)
All right so this means that anytime
[03:52] (232.08s)
that cla code needs to run the
[03:53] (233.68s)
notification it's running hook handler.
[03:55] (235.68s)
It means that anytime it's running stop
[03:58] (238.40s)
it triggers a stop event it's running
[04:00] (240.08s)
hook handler. Anytime it's running
[04:01] (241.76s)
pre-tool use it's running the hook
[04:03] (243.44s)
handler. I tried this a few different
[04:05] (245.36s)
ways. I tried writing different scripts
[04:07] (247.60s)
for different um events. Uh I have also
[04:11] (251.68s)
tried uh using the same script but
[04:13] (253.68s)
passing different arguments in uh like
[04:16] (256.32s)
command line arguments in. I found that
[04:18] (258.40s)
difficult to debug. Uh I found that what
[04:20] (260.48s)
I want to do is keep my settings.json as
[04:23] (263.52s)
simple as possible and then handle all
[04:26] (266.48s)
of the logic in the Python script
[04:28] (268.96s)
because there I have much better
[04:30] (270.16s)
debugging etc. All right, so let's take
[04:32] (272.40s)
a look at the Python script. This Python
[04:34] (274.96s)
script, by the way, uh I generated with
[04:37] (277.44s)
cloud code. I basically passed it the
[04:39] (279.68s)
URL for the hooks uh documentation and
[04:43] (283.20s)
told it what I want to do. I went
[04:44] (284.32s)
through several different iterations and
[04:45] (285.92s)
then I had it um uh refactor it several
[04:49] (289.76s)
times to make it as legible as possible.
[04:51] (291.76s)
And you can find this script at uh
[04:54] (294.08s)
highhigh.ai/hooks.
[04:56] (296.16s)
Um, but basically what's going to happen
[04:57] (297.92s)
here, first and foremost, let's just run
[05:00] (300.72s)
and log the data that cloud code is
[05:04] (304.00s)
passing into this script when it gets
[05:07] (307.28s)
triggered because that data is what will
[05:10] (310.16s)
help you decide what you want to do. You
[05:13] (313.04s)
can see under hook input, hooks receive
[05:14] (314.96s)
JSON data via standard in containing
[05:17] (317.20s)
session information and event specific
[05:18] (318.96s)
data. And it goes through some of the
[05:21] (321.60s)
specifics of what that looks like. All
[05:23] (323.44s)
right. And so, uh, let's just do this.
[05:26] (326.08s)
Another little tip that I found for
[05:27] (327.92s)
working with cloud code is you can just
[05:29] (329.76s)
say to cloud code, uh, do some stuff
[05:34] (334.64s)
to test out my hooks integration.
[05:41] (341.28s)
And then it will just do stuff. Uh, and
[05:44] (344.80s)
I think right now I have the beeps
[05:46] (346.00s)
turned on.
[05:48] (348.32s)
So, you can hear the various beeps that
[05:49] (349.76s)
it's doing. And then as that runs, you
[05:52] (352.48s)
can see that it was updating its to-dos
[05:54] (354.80s)
and it's reading a file now. So I'm
[05:57] (357.20s)
going to come over here and I'm going to
[05:58] (358.80s)
look into my hook handler.json L. Uh
[06:02] (362.88s)
because I have a function in my hook
[06:05] (365.04s)
handler called log hook data. It's right
[06:08] (368.32s)
here. Claw's going to keep making sounds
[06:10] (370.48s)
in the background as we go. Um which I
[06:12] (372.96s)
might need to turn off. Uh and so this
[06:15] (375.84s)
is basically just uh writing out the uh
[06:18] (378.64s)
data that's coming in via standard in.
[06:20] (380.32s)
So this is what that looks like. So you
[06:22] (382.16s)
can see there's a session ID. You can
[06:24] (384.00s)
see that uh we have an event name. We
[06:26] (386.48s)
have the tool name. So in this case it's
[06:28] (388.08s)
it's pre-tool use. So we have the tool
[06:30] (390.56s)
name and then the tool input. So this
[06:32] (392.72s)
gives us all the information we need to
[06:34] (394.88s)
know about what Claude is doing in order
[06:37] (397.52s)
to branch the logic to to do the various
[06:41] (401.04s)
stuff. Um, so let's uh come back in here
[06:44] (404.56s)
and we'll look at then what my hook
[06:46] (406.96s)
handler is doing. Uh, basically I have a
[06:52] (412.40s)
a few different directories here. I have
[06:54] (414.72s)
a sounds directory and I have um beeps
[06:58] (418.56s)
and I have voice and I think on a
[07:00] (420.40s)
different branch I had my meow sounds
[07:02] (422.16s)
although I may have actually
[07:04] (424.40s)
accidentally reverted that out after I
[07:06] (426.80s)
recorded the demo. But okay, we'll go
[07:08] (428.72s)
dig through uh git for that later. Uh
[07:10] (430.80s)
the way that I got these is I use uh
[07:13] (433.04s)
Epidemic Sound. Uh I use it in my
[07:15] (435.28s)
various YouTube videos. Um they have
[07:17] (437.52s)
music. Uh and then I also they also have
[07:20] (440.88s)
a sound effects section here. And so I
[07:22] (442.96s)
just came in here and I got there was a
[07:24] (444.72s)
section for uh beeps. And so I just
[07:28] (448.88s)
all sorts of fun beeps that you can play
[07:31] (451.52s)
with. Uh oh my god, that one's Let's
[07:34] (454.32s)
make that one stop right now. Sorry
[07:35] (455.76s)
about that. Uh they've got one for uh
[07:38] (458.48s)
you know they've got cats.
[07:43] (463.68s)
That's kind of nice.
[07:46] (466.08s)
All right. I feel like I only use sad
[07:49] (469.04s)
meows in mine. I should change that. Uh
[07:51] (471.92s)
I did some construction equipment once
[07:53] (473.76s)
for the tool use. Uh they also have this
[07:56] (476.08s)
new feature called voices which I played
[07:58] (478.16s)
around with. So you can they have these
[08:00] (480.16s)
voice actors who have donated their
[08:02] (482.56s)
voice to the AI and then you can make
[08:05] (485.04s)
them say things. So uh I used Sean here
[08:09] (489.84s)
because he's British. Seemed like Claude
[08:11] (491.36s)
might be British. Uh uh
[08:15] (495.28s)
say committing and you can create the
[08:18] (498.72s)
voice over.
[08:21] (501.36s)
Commiting.
[08:22] (502.40s)
Commiting. Okay. Uh I guess I did spell
[08:25] (505.04s)
that wrong. Let's try that again.
[08:30] (510.08s)
committing.
[08:30] (510.96s)
There we go. That's better. Uh, so you
[08:33] (513.04s)
can see how I did those. One, if you do
[08:35] (515.28s)
end up using these, one, um, just tip is
[08:38] (518.40s)
say they often will cram a whole bunch
[08:40] (520.48s)
of different, uh, sound effects on the
[08:43] (523.20s)
same one. And so you can see it here.
[08:47] (527.44s)
All right. So then if you go to
[08:48] (528.80s)
download, you can come to segment and
[08:51] (531.04s)
you can select just the segment of the
[08:53] (533.12s)
sound effect that you want to download.
[08:54] (534.72s)
So I'll take that down. you can get just
[08:56] (536.72s)
that. So, I did that. I played with a
[08:58] (538.96s)
different a few different ways of doing
[09:00] (540.72s)
this. The first iteration I did, um, I
[09:03] (543.20s)
just threw a bunch of random sound
[09:04] (544.32s)
effects into a folder and then I just
[09:06] (546.56s)
let it pick randomly. I do like
[09:08] (548.32s)
assigning specific sounds to specific
[09:10] (550.08s)
actions because I do find that it helps
[09:11] (551.76s)
me understand when Claude is doing
[09:16] (556.80s)
For instance, I didn't realize how often
[09:18] (558.96s)
Claude is updating its to-do list. Uh,
[09:21] (561.36s)
which I I thought was actually kind of
[09:22] (562.72s)
cool. I didn't realize initially before
[09:24] (564.96s)
I started doing this how many of the
[09:26] (566.56s)
commands that Claude runs is a bash
[09:28] (568.24s)
command and so initially I just had it
[09:30] (570.88s)
uh playing a sound for bash and then it
[09:32] (572.80s)
was the same sound over and over again
[09:34] (574.16s)
and then I realized that I needed to do
[09:35] (575.68s)
a pattern match on uh you know the
[09:38] (578.24s)
specific commands such as editing files
[09:40] (580.24s)
or reading files um or even you know it
[09:42] (582.88s)
runs bash for uh using the GitHub CLI um
[09:46] (586.32s)
and so doing all those different things
[09:47] (587.76s)
I think it just helped me understand
[09:49] (589.44s)
claude code and how it worked better. So
[09:51] (591.68s)
I have here um I've renamed these
[09:54] (594.96s)
various uh sounds to the command. So
[09:57] (597.92s)
here you can see with uh speaking
[10:01] (601.28s)
committing
[10:02] (602.88s)
or I have one for bash
[10:07] (607.36s)
bashing
[10:08] (608.48s)
or testing
[10:11] (611.44s)
running tests.
[10:12] (612.96s)
You go the PR
[10:15] (615.68s)
creating pull request.
[10:17] (617.36s)
See so uh pretty cool. Well, I I thought
[10:19] (619.92s)
that was great. And I mean, you can
[10:21] (621.60s)
imagine what this Python script's doing
[10:23] (623.12s)
here. Um, so basically, we just play the
[10:25] (625.44s)
sound. I have a little toggle up here,
[10:28] (628.48s)
sounds type, that I can set this to
[10:30] (630.88s)
meows or voices or beeps. Uh, and then I
[10:34] (634.16s)
just have a map uh telling it to map the
[10:37] (637.12s)
different event to the various uh sound
[10:40] (640.08s)
files. Uh, and then it will uh match go
[10:44] (644.32s)
in depth on uh the different bash
[10:46] (646.16s)
commands to figure out which sound it
[10:48] (648.00s)
should play for those. Um, and uh, this
[10:50] (650.64s)
was really fun and pretty easy to create
[10:52] (652.40s)
with Claude. And I think that this was
[10:55] (655.44s)
uh, a really cool foray into using hooks
[10:59] (659.28s)
because it helped me understand the
[11:00] (660.96s)
different event types by assigning the
[11:02] (662.48s)
different sounds, which has then given
[11:04] (664.48s)
me a lot more thoughts about different
[11:05] (665.92s)
ways that I can use hooks. I've seen a
[11:08] (668.56s)
lot of folks use them for instance to um
[11:11] (671.68s)
prevent some of the commands that
[11:13] (673.28s)
they're most concerned about. So for
[11:14] (674.48s)
instance, you could set up a hook to
[11:16] (676.32s)
look for a bash command that's running
[11:20] (680.24s)
for instance and to uh you know have it
[11:23] (683.12s)
not do that. Uh you could um a lot of
[11:26] (686.96s)
folks are using it to run llinters. A
[11:29] (689.04s)
lot of folks are using it to ensure that
[11:31] (691.36s)
the test suite is being run before uh
[11:34] (694.56s)
you open up a pull request. Um, and so
[11:36] (696.72s)
there's just a lot of really interesting
[11:38] (698.80s)
things you can do here that gives you a
[11:40] (700.24s)
lot a little bit more deterministic
[11:42] (702.24s)
control over cloud codes behavior. Uh,
[11:45] (705.28s)
but I did find that getting started by
[11:47] (707.44s)
doing the fun thing with sounds was a
[11:49] (709.36s)
great way to get started here. If you
[11:50] (710.88s)
want to see all this code, you can check
[11:52] (712.08s)
out hihigh.ai/hooks
[11:54] (714.40s)
and I put the code up there and would
[11:56] (716.00s)
love to hear what you're using hooks