1
00:00:00,400 --> 00:00:04,320
If I haven't expressed it, I want to express 
one last time. Like effect systems are [ __ ]

2
00:00:04,320 --> 00:00:09,600
perfect. Promises are junk. They're straight 
hot garbage. Programming is in this sort of

3
00:00:09,600 --> 00:00:13,520
a this this local maximum that it's been 
is hanging around in. And there have been

4
00:00:13,520 --> 00:00:17,280
better ways of programming that have been 
sort of embraced in these niche languages

5
00:00:17,280 --> 00:00:22,560
which were too weird to sort of penetrate 
the mainstream. And bless Michael Arnaldi

6
00:00:22,560 --> 00:00:27,600
for bringing effect into Typescript because 
it has allowed it to be viable. every language

7
00:00:27,600 --> 00:00:32,400
where an effect system was introduced in, it 
did become the dominant way of writing in that

8
00:00:32,400 --> 00:00:36,320
language. Never before has it been introduced 
into something as ginormous as as TypeScript,

9
00:00:36,320 --> 00:00:42,880
but I feel like we're on that 
hockey stick growth curve. [music]

10
00:00:42,880 --> 00:00:47,520
Hey Kit, I'm so excited to finally have you on 
the podcast. We've been planning this for quite

11
00:00:47,520 --> 00:00:53,280
a while. Finally happening. Welcome. You finally 
caught me. I guess I have to be here now. What an

12
00:00:53,280 --> 00:01:01,520
awful day in my life. So, for folks who probably 
have seen one of your videos, uh, by now they have

13
00:01:01,520 --> 00:01:07,200
recognized your voice and you're you're finally 
here. For those of you who don't know who you are,

14
00:01:07,200 --> 00:01:12,400
would you mind giving a brief introduction who you 
are, what you have to do with effect, and what you

15
00:01:12,400 --> 00:01:18,400
currently do. Yeah. Yeah. Yeah. Hi, everyone. I'm 
I'm Kit. I don't always sound like this, but I'm

16
00:01:18,400 --> 00:01:22,320
very close to my microphone. That's the trick 
to ASMR. You just get really close to your mic,

17
00:01:22,320 --> 00:01:28,320
by the way. And if you go back, you kind of sound 
normal. It's my normal voice. But yeah. Um, just

18
00:01:28,320 --> 00:01:33,840
get back just get close to the mic and it'll all 
work out for you. Um, yeah. Uh, my name is Kit. I

19
00:01:33,840 --> 00:01:41,760
was uh I've been a longtime effect system fanatic. 
Uh, it it bit me around I don't know, eight years

20
00:01:41,760 --> 00:01:49,040
ago. And ever since I've been doomed career-wise 
uh to to live in a increasingly diminishing niche

21
00:01:49,040 --> 00:01:54,880
of irrelevancy and and functional perfection to 
sort of wrap build a cocoon around myself and die

22
00:01:54,880 --> 00:02:02,560
in it was my fate. But then the robots came and 
I got scared. So I decided to flee to the very

23
00:02:02,560 --> 00:02:09,360
uh welcoming giant uh tower of of Typescript. 
And uh turns out there's like nice people

24
00:02:09,360 --> 00:02:15,760
there and there are the jobs and stuff. So, 
luckily it's been saved from my doom fate. Um,

25
00:02:15,760 --> 00:02:21,840
so I'm a big effect systems fan, big effect fellow 
like effect like effect systems of all kinds, but

26
00:02:21,840 --> 00:02:27,280
um, effect is the first one that seems to have 
a shot at mainstream relevancy and I want to,

27
00:02:27,280 --> 00:02:32,320
you know, I want to curse the world with 
my same disease. Yes, that's it. Yeah. So,

28
00:02:32,320 --> 00:02:38,480
if if anyone hasn't checked out Kit's videos yet 
on on YouTube, definitely check those out. We're

29
00:02:38,480 --> 00:02:45,120
going to put those links in in the description. 
But aside for your interest in effect systems,

30
00:02:45,120 --> 00:02:51,840
you're also currently working on OpenCode. So, uh, 
how did that come to be? So, that I think that was

31
00:02:51,840 --> 00:02:57,200
a direct I'll have to ask Dax. Uh, you'll have 
to have Dax on at some point. He's been, I think,

32
00:02:57,200 --> 00:03:05,040
at this point, uh, thoroughly effectilled, as they 
say, by himself, too. I I I've learned my lesson.

33
00:03:05,040 --> 00:03:10,240
I think I might have the record for rewriting is 
the most systems in in the world into some form

34
00:03:10,240 --> 00:03:14,080
of effect system just because it's niche enough 
of a technology and I've done it at like five

35
00:03:14,080 --> 00:03:18,640
jobs now. So I've had enough experience trying to 
convince people and you can lead a horse to water

36
00:03:18,640 --> 00:03:22,720
etc. I mean I mean you can really just sort of 
dump water all around them and make it so that

37
00:03:22,720 --> 00:03:26,240
they can only step in water. That's kind of 
my technique. And just like drink the water

38
00:03:26,240 --> 00:03:32,640
in front of them and say m water so good. Uh this 
water is pure. But you can't make them drink. So

39
00:03:32,640 --> 00:03:37,920
that technique seems to have worked with Dax even 
though he I think he he wanted me to join because

40
00:03:37,920 --> 00:03:43,520
of uh he knew what I was get he was getting rather 
um I wasn't hiding my effect passion on the on

41
00:03:43,520 --> 00:03:49,760
the timeline as it were and so I think I I came 
across his timeline with um uh I made this thing

42
00:03:49,760 --> 00:03:57,920
called effect.institute which is sort of a an ASMR 
effect tutorial interactive tutorial thing that's

43
00:03:57,920 --> 00:04:01,120
kind of weird. Yeah, we can I know we wanted 
to make this interactive so I could show off

44
00:04:01,120 --> 00:04:05,040
some of these things as we talk about them, but 
I mean you you've you've now mentioned it a few

45
00:04:05,040 --> 00:04:10,560
times. Let's take a look. And for for those of you 
who are just listening, uh definitely check out

46
00:04:10,560 --> 00:04:16,960
the the link later is definitely worthwhile your 
time, particularly if you're rather new to effect.

47
00:04:16,960 --> 00:04:24,240
Effect has always been like mindblowing, but it 
took a little while until it kind of clicked if

48
00:04:24,240 --> 00:04:30,480
you're new to effect. And effect institute 
lowers the bar so much by like just making

49
00:04:30,480 --> 00:04:37,200
it much more accessible. It reminds me to like 
some of the feelings I had when I tried out like

50
00:04:37,200 --> 00:04:43,920
um Rails for Zombies uh back in the days and I 
was always hoping there would be something like

51
00:04:43,920 --> 00:04:51,360
that for for effects and then Kit came along and 
did it. Yeah. Yeah. Yeah. I I do like I did love

52
00:04:51,360 --> 00:04:55,520
Rails for zombies. Yeah. The goal is to make it 
such that you would want to go through it even

53
00:04:55,520 --> 00:05:00,560
if you don't know what effect is. Like even if 
you hate effect, you'll want to still interact

54
00:05:00,560 --> 00:05:07,680
with the website. Um, so yeah, this is this is my 
newest effect tutorial. I have some real feedback

55
00:05:07,680 --> 00:05:14,640
here. I'm a wizard. That's Wow, it's really great. 
I have the man I have the mandate. Yeah, I have

56
00:05:14,640 --> 00:05:18,320
the mandate. That's that's my goal is to have 
the mandate. As you can see, there are lots of

57
00:05:18,320 --> 00:05:23,840
uh many pending lessons here. little effect or die 
reference at the bottom. But yeah, I'll I'll just

58
00:05:23,840 --> 00:05:30,080
click on this thing. It's [laughter] so I made 
my screen ginormous or my my display resolution

59
00:05:30,080 --> 00:05:34,240
very low. Uh but yeah, it's a sort of interactive 
thing. I'll just click through this. You see, use

60
00:05:34,240 --> 00:05:38,720
the arrow keys to navigate between these different 
lessons. And when you hit space, you will hear my

61
00:05:38,720 --> 00:05:47,280
voice speaking to you in maximal uh narration 
mode. Welcome to the effect institute. I'm Kit

62
00:05:47,280 --> 00:05:56,320
and I want to teach you effect. But first, the 
briefest of tutorials. Pressing space, as you may

63
00:05:56,320 --> 00:06:01,520
have discovered, will play or pause the See, it 
just paused it. So, you can see that there's some

64
00:06:01,520 --> 00:06:06,080
animations that sync to the narration, and it's 
more interesting. I can you can also command click

65
00:06:06,080 --> 00:06:14,720
between sections. When we call it, a promise has 
but one failure. Check out fail. And if it does,

66
00:06:14,720 --> 00:06:19,760
so I'll pause it there. Can you hear that, by the 
way? Is that too loud? This is uh Yeah, perfectly

67
00:06:19,760 --> 00:06:24,960
audible. And I would encourage everyone to check 
it out by themselves. Probably even better audio

68
00:06:24,960 --> 00:06:32,080
quality. You can play around, see those like 
amazing detail, both not just visual details,

69
00:06:32,080 --> 00:06:39,440
but actually also audio details. Those [clears 
throat] just uh craftsmanships at its finest. So,

70
00:06:39,440 --> 00:06:45,280
uh, it is it's almost so good that it distracts 
you from learning it. [laughter] That's the good

71
00:06:45,280 --> 00:06:49,040
that was the goal is to find that that boundary. 
Um, yeah, and there's some nice animated effects.

72
00:06:49,040 --> 00:06:53,440
It's the last thing I'll show off is that oh, 
there's some like uh nice little pretty things

73
00:06:53,440 --> 00:06:58,160
that are animated with W web GPU, which I'm pretty 
happy with. Uh, anyway, yeah, I'll I'll leave that

74
00:06:58,160 --> 00:07:05,920
for the uh the viewers to indulge in. and and 
so effect institute is built uh sort of like

75
00:07:05,920 --> 00:07:12,480
as a sequential project for some of your your 
previous related work. Let's let's just dive in

76
00:07:12,480 --> 00:07:17,040
and we'll talk about OpenCode in a moment. But 
effect institute is sort of like a successor

77
00:07:17,040 --> 00:07:24,480
project that builds on top of like visual effect 
visual types etc. Is that the the way how I should

78
00:07:24,480 --> 00:07:29,520
think about it? Yeah. Yeah. Yeah. I've basically 
been building weird visual we can tie this in I

79
00:07:29,520 --> 00:07:34,480
guess to my my weird history too but um my first 
I joined a bootcamp that was my entry entry point

80
00:07:34,480 --> 00:07:40,800
into programming and then they hired me. So from 
day one at my job I was always doing some amount

81
00:07:40,800 --> 00:07:46,640
of teaching and creating visualizations cuz I 
found that to be fun. Like I I went to school for

82
00:07:46,640 --> 00:07:53,440
illustration and so I I like to keep some sort of 
visual elements and build full stacky things. I

83
00:07:53,440 --> 00:07:58,480
like it all. I just want to do all of it and and 
a good way to force everything into every project

84
00:07:58,480 --> 00:08:02,800
is to build, you know, some kind of full stack 
animated application which kind of lets me shove

85
00:08:02,800 --> 00:08:07,520
all my interests in there uh as best I can. So 
that's kind of why everything takes on this kind

86
00:08:07,520 --> 00:08:12,960
of shape. I actually back in the day when I um 
we'll get to this a while ago, but I started my

87
00:08:12,960 --> 00:08:17,040
effect system journey in Haskell and then quickly 
ended up in Scala and there's this library called

88
00:08:17,040 --> 00:08:22,640
Zo. You can see right away that this looks 
terribly ugly, but there's this thing I made,

89
00:08:22,640 --> 00:08:28,320
which is this visual Zio animation. It tries 
to teach you Zio and give you a sense of how

90
00:08:28,320 --> 00:08:33,680
things work, help you build an intuition with some 
incredible animations. Obviously, this looks like

91
00:08:33,680 --> 00:08:40,880
hot garbage because I made it in 2019. But, you 
know, it is working and it's using Scolletjs. So,

92
00:08:40,880 --> 00:08:45,600
it's actually running this effect system called 
Zio in the browser and letting you visualize

93
00:08:45,600 --> 00:08:48,800
various things. There's some things at the bottom 
here that don't look as bad. So there's this,

94
00:08:48,800 --> 00:08:55,760
you know, visual stream uh implementation. So if 
you uh map over a stream, multiplying it by two,

95
00:08:55,760 --> 00:09:00,880
you'll see sort of the resultant stream is double 
the first stream. If you zip a stream with an

96
00:09:00,880 --> 00:09:05,920
index, you'll see it uh zipped with its index in 
the list. So there's some some ideas here that are

97
00:09:05,920 --> 00:09:10,800
not too different than what I end up doing later 
on. It's just I think generally much uglier. Got

98
00:09:10,800 --> 00:09:13,920
a little It turns out if you make a bunch of 
projects, you get a little better at visual

99
00:09:13,920 --> 00:09:20,560
design. So I made that about yeah a long time 
ago this library that effect was based on called

100
00:09:20,560 --> 00:09:27,440
uh Zio and then about last I think around almost 
exactly a year ago uh effect became impossible to

101
00:09:27,440 --> 00:09:34,480
ignore and Scala became increasingly to me felt 
like I was increasingly irrelevant in the world

102
00:09:34,480 --> 00:09:39,680
at large. So I decided to jettison and and and 
at least try actually it was simpler than that.

103
00:09:39,680 --> 00:09:44,080
I just wanted to try out effect and I thought 
I could remake um this project basically an

104
00:09:44,080 --> 00:09:49,280
effect. So I made a visual effect. So if you 
go to effect.kitlangton.com and you'll see it's

105
00:09:49,280 --> 00:09:54,240
uh it's prettier and you get this little spinning 
uh orb up there. It's pretty nice. And basically

106
00:09:54,240 --> 00:10:00,320
you click and you see a visualization of 
different uh effect syntax. So these are

107
00:10:00,320 --> 00:10:05,360
sort of the basic constructors. You can effect 
can succeed. It's green. They're sound effects.

108
00:10:05,360 --> 00:10:13,040
They can fail. It's red. They're sound effects. 
And then it can die. This one's fun. So yeah,

109
00:10:13,040 --> 00:10:20,320
I definitely got carried away with everything. Um 
I'll I'll skip off to just for for time reference.

110
00:10:20,320 --> 00:10:27,920
I think you built this one pre- AI uh or like 
th this one was probably like Claude Code or

111
00:10:27,920 --> 00:10:34,800
whatever was not as widely available. It was this 
was a year ago. It was definitely AI helped. Um,

112
00:10:34,800 --> 00:10:40,720
but also this is like the architecture I kind of g 
I've just been pulling code forward from all those

113
00:10:40,720 --> 00:10:48,240
past projects. So you could certainly not oneshot 
this. And so there's like real artisan handcrafted

114
00:10:48,240 --> 00:10:53,680
love going into this. There is some handcrafted 
love and and I think you can also bring as a as

115
00:10:53,680 --> 00:11:00,400
a very brief tangent I'm sure everyone's seen on 
the timeline uh much slop in the world. People

116
00:11:00,400 --> 00:11:07,280
use AI to just build more and that's great. But I 
feel like to really take the most advantage of AI,

117
00:11:07,280 --> 00:11:12,480
you should use it to iterate even more and to push 
things further instead of just letting you sort

118
00:11:12,480 --> 00:11:19,200
of poop out more content that just sort of meets 
the minimum bar of legibility of of sort of okay,

119
00:11:19,200 --> 00:11:23,360
this vaguely feels like a blog post that 
might have been published 10 years ago. Well,

120
00:11:23,360 --> 00:11:27,600
now everyone can do that. So there's all this 
slop and I think people are getting a little

121
00:11:27,600 --> 00:11:32,160
more perceptive around identifying it. There was 
definitely a time where you would be rewarded for

122
00:11:32,160 --> 00:11:37,840
po publishing slo blog posts but I think that 
the sort of the telltale indicators of AI I

123
00:11:37,840 --> 00:11:43,520
mean it's always changing right purple gradients 
different fonts like it's adapting but if if you

124
00:11:43,520 --> 00:11:47,520
if you view a lot of stuff I think I think the 
general consuming public my hope is that they

125
00:11:47,520 --> 00:11:53,280
become perceptive to that and seek sort of higher 
taste content higher quality content and you as

126
00:11:53,280 --> 00:11:57,280
a person who's making stuff has more opportunity 
to iterate further and further so even if you're

127
00:11:57,280 --> 00:12:03,200
using AI to do things just like raise your 
bar a lot uh and and really cuz if anything

128
00:12:03,200 --> 00:12:07,680
uh looks off to you just just you know shoot off 
another prompt and and make it better. Isn't it

129
00:12:07,680 --> 00:12:14,160
amazing that we can now go the extra mile with 
like so little energy we need to put into it?

130
00:12:14,160 --> 00:12:20,080
Uh I think for for perfectionists is like the 
the best time ever. Yeah. And I think maybe the

131
00:12:20,080 --> 00:12:26,960
only counterveailing force there is that there's 
also this newfound pressure to produce more. So

132
00:12:26,960 --> 00:12:34,080
it's like okay I could perfect one thing or I can 
produce 100 awful things. So I mean it's the same

133
00:12:34,080 --> 00:12:39,760
balance that's always been there of like explore 
and exploit uh except maybe there's increasing

134
00:12:39,760 --> 00:12:45,680
pressure from the outside. But yeah I'd say it's 
more satisfying like do you can explore more but

135
00:12:45,680 --> 00:12:50,400
when you finally do find something that uh you 
know interests you and titilates you that you

136
00:12:50,400 --> 00:12:57,920
feel like there's some promise there definitely 
go deep on exploitation. So speaking of promises,

137
00:12:57,920 --> 00:13:04,000
let's zoom out a little bit. Like highly recommend 
to anyone like check out those various projects

138
00:13:04,000 --> 00:13:10,080
that you've just just demoed in case you're 
just listening to this right now. But you've

139
00:13:10,080 --> 00:13:15,760
um about when was it like half a year ago or so 
and we're recording this at the end of April.

140
00:13:15,760 --> 00:13:22,720
You've joined the uh folks who are working 
at OpenCode or on OpenCode. I think Anomaly

141
00:13:22,720 --> 00:13:27,680
is the is the company behind it. Yes. Yes. Yes. 
It's not just called OpenCode but yes I I think

142
00:13:27,680 --> 00:13:35,840
you've joined them with the goal to free them of 
the the promises [laughter] and bring in effect

143
00:13:35,840 --> 00:13:43,040
to the OpenCode codebase. So, uh, I think there's 
a fascinating story behind this that I would love

144
00:13:43,040 --> 00:13:50,960
to unpack and learn more about. Like, OpenCode is 
probably an pretty sizable codebase, probably even

145
00:13:50,960 --> 00:13:57,120
larger so by now, but can you share how big it was 
when you when you joined and what the situation

146
00:13:57,120 --> 00:14:01,600
was like? So, actually, I I don't know. I should 
know the number of of lines of code, especially

147
00:14:01,600 --> 00:14:09,120
because I'm sure I've added to it with my various 
tests and parallel implementations. uh of things.

148
00:14:09,120 --> 00:14:14,480
But actually, it can kind of be nice when you're 
taking off maybe a potentially infinitelysized uh

149
00:14:14,480 --> 00:14:20,000
task to to not look ahead and just sort of let the 
uh the passion of the moment. If you're going to,

150
00:14:20,000 --> 00:14:26,000
let's say, run across Antarctica, you might just 
want to focus on the next 10 footfalls instead of

151
00:14:26,000 --> 00:14:32,800
the the entire breadth of of cold, harsh alien 
landscape ahead of you. So I I I didn't really

152
00:14:32,800 --> 00:14:38,560
consider just how much once I started converting 
it to effect uh how large that task would be.

153
00:14:38,560 --> 00:14:44,480
I actually I joined I think in February so it's 
only been a few months but it's felt it feels like

154
00:14:44,480 --> 00:14:51,200
uh a few years for various reasons. On a high 
level how concluded is the effect migration the

155
00:14:51,200 --> 00:14:57,360
effectification of OpenCode at this point? Uh 
it's getting really really close. I currently

156
00:14:57,360 --> 00:15:03,280
have a sort of a parallel implementation of all 
the routers. So a little bit about OpenCode's

157
00:15:03,280 --> 00:15:11,200
architecture is that for anyone who doesn't know 
it's it's basically a Claude Code like except it's

158
00:15:11,200 --> 00:15:17,440
all open source and it works with all different 
models. You can use it with your uh ChatGPT

159
00:15:17,440 --> 00:15:20,880
subscription, your pro subscription. You can just 
ooth in there. You used to be able to use it with

160
00:15:20,880 --> 00:15:26,560
your uh Anthropic subscription but uh they took 
that away. So they've they've been reducing what

161
00:15:26,560 --> 00:15:32,000
you can use that for but nonetheless and we have 
some subscriptions etc. But generally it's an open

162
00:15:32,000 --> 00:15:38,000
source uh agent which you know you you ask it code 
queries and it runs in a loop and can call various

163
00:15:38,000 --> 00:15:42,320
tool calls and work with all these different 
providers and it's open source and the I think

164
00:15:42,320 --> 00:15:48,480
the the distinguishing mark architecturally is 
that it it sort of is this client server model

165
00:15:48,480 --> 00:15:53,440
so that you can have multiple sessions uh you can 
have multiple clients all connected to the same

166
00:15:53,440 --> 00:15:57,200
server that runs the sessions and there's some 
been some recent work now there's we're sort of

167
00:15:57,200 --> 00:16:01,200
working on this control plane so you can have one 
running control plane and then possibly different

168
00:16:01,200 --> 00:16:06,480
workspaces running in different sandboxes etc. 
Nonetheless, client server architecture. And so

169
00:16:06,480 --> 00:16:10,560
there's a server is the point is what I'm trying 
to get to. And initially this was written with

170
00:16:10,560 --> 00:16:16,960
Hono which is uh a nice server library very 
efficient but it's not written in effect. And

171
00:16:16,960 --> 00:16:22,960
effect has its own uh server library. And one of 
the beautiful things about effect is that it is

172
00:16:22,960 --> 00:16:28,880
this sort of all-encompassing ecosystem uh that's 
all very high quality and interoperates with

173
00:16:28,880 --> 00:16:36,080
itself uh obviously more smoothly than another 
non-effect library will. And that there's a very

174
00:16:36,080 --> 00:16:40,480
a couple of reasons for this and and why you might 
want effect to wash over everything slowly. Not

175
00:16:40,480 --> 00:16:46,160
that it can't interoperate, but just that the more 
land mass it it claims, the happier you become.

176
00:16:46,160 --> 00:16:51,280
um because you get to preserve its those 
invariants that it has throughout larger

177
00:16:51,280 --> 00:16:57,760
swaths of your codebase. And another sort of piece 
of glue in in effect is the schema library which

178
00:16:57,760 --> 00:17:04,960
is if you're familiar with Zod, it's sort of the 
Zod of effect. So you design your data as these

179
00:17:04,960 --> 00:17:09,600
descriptions, these specifications and you get 
serialization and deserialization for free and

180
00:17:09,600 --> 00:17:15,600
other various things because uh that your types 
are sort of described as data very very clearly.

181
00:17:15,600 --> 00:17:22,880
It can also be used to generate uh many things 
like open API specifications uh servers clients

182
00:17:22,880 --> 00:17:28,000
etc. And it is all very type- safe. So once you 
switch over to effect, you probably are also

183
00:17:28,000 --> 00:17:32,720
going to want to design all of your data models uh 
using schema and do all of your data modeling with

184
00:17:32,720 --> 00:17:38,720
schema and also use it to generate your server and 
and open API docs. So some of that was done with

185
00:17:38,720 --> 00:17:43,600
Zod and Hono. So, I've just gotten the point where 
there's a parallel implementation of everything

186
00:17:43,600 --> 00:17:50,880
using effect server uh the the effect server um 
setup the HTTP API uh in parallel with Hono and

187
00:17:50,880 --> 00:17:55,840
I have a feature flag that either routes to the 
Hono implementation or the effect implementation.

188
00:17:55,840 --> 00:18:00,560
And if this works well for the next few days, I'm 
going to delete the Hono stuff. This is actually

189
00:18:00,560 --> 00:18:07,920
definitely a worthwhile uh tangent, which is how 
do you approach even organizing such a migration?

190
00:18:07,920 --> 00:18:13,920
So I I started off really timidly. Um I mean Dax 
did mostly give me the thumbs up. I guess my first

191
00:18:13,920 --> 00:18:18,880
I've been working on also in parallel this other 
project which will probably be revealed in time.

192
00:18:18,880 --> 00:18:24,960
So that's kind of what I spent my first month 
working on with some parallel uh uh commits to

193
00:18:24,960 --> 00:18:29,840
uh the main OpenCode codebase. And the original 
intention was actually to not necessarily involve

194
00:18:29,840 --> 00:18:35,120
effect there because it's an open source library 
because maybe that would alienate certain people

195
00:18:35,120 --> 00:18:39,680
just keep it basic TypeScript. But um I didn't 
even have to convince Dax. As I mentioned, I just

196
00:18:39,680 --> 00:18:44,560
kind of tried to really make a show of how much I 
enjoyed working with effect. And I wanted to make

197
00:18:44,560 --> 00:18:50,400
this other project a sort of a shining exemplar 
of effect and and let the quality of that uh sort

198
00:18:50,400 --> 00:18:56,640
of incept the idea of using effect everywhere. 
But he he we was I guess doing some parallel

199
00:18:56,640 --> 00:19:01,600
exploration and using it in some side projects and 
ended up convincing himself before I ever had to

200
00:19:01,600 --> 00:19:06,720
uh to to try too hard. So before long he was like 
you know what we'll just effectify everything. I

201
00:19:06,720 --> 00:19:11,600
know how these things go. It it'll it'll uh it'll 
come here eventually. We we want it too much. So

202
00:19:11,600 --> 00:19:18,400
once I was given the green light I started very 
timidly by uh just um boarding some identifiers.

203
00:19:18,400 --> 00:19:25,360
So one thing that effect has is with schema is the 
ability to have branded data types and that's very

204
00:19:25,360 --> 00:19:31,760
useful in in a codebased like effect for instance 
and sorry like OpenCode you have many identifiers

205
00:19:31,760 --> 00:19:38,640
for sessions for messages for um workspaces etc. 
And many of these are strings. They're like random

206
00:19:38,640 --> 00:19:43,920
UUID strings, but the type system says they're all 
strings. And these are passed around everywhere.

207
00:19:43,920 --> 00:19:49,120
And the trouble with just using raw strings is 
that you can easily sort of mistranspose them and

208
00:19:49,120 --> 00:19:55,920
and pass in a name like the model name instead of 
the model ID. And TypeScript won't care. And maybe

209
00:19:55,920 --> 00:20:01,120
this will even get serialized uh and saved to your 
your database and things will just kind of break

210
00:20:01,120 --> 00:20:07,600
in in weird ways. So, I've always been a fan of 
using the type system to help reduce the burden

211
00:20:07,600 --> 00:20:12,240
of and the possibility of of having these kinds 
of simple errors. Like types are really good at

212
00:20:12,240 --> 00:20:17,760
tracking sort of coloring data in various ways and 
making sure you don't use the wrong put the the

213
00:20:17,760 --> 00:20:23,120
square peg in the round hole. Simple stuff like 
this. to to add one more tangent to the stack is

214
00:20:23,120 --> 00:20:29,440
like my my meta thought about AI and what's good 
for agents is uh and maybe this is just selfish in

215
00:20:29,440 --> 00:20:34,960
my own own own worldview that I had previously but 
I think it applies is that what is good for humans

216
00:20:34,960 --> 00:20:39,120
is good for agents generally what is good for a 
hardworking engineer is also good for an agent

217
00:20:39,120 --> 00:20:43,440
because we're both context constrained agents are 
obviously context constrained in their windows

218
00:20:43,440 --> 00:20:47,040
nowadays they have like million context windows 
but still there's some kind of degradation that

219
00:20:47,040 --> 00:20:51,040
happens beyond 300,000 tokens in a lot of them 
and I don't know it's all it's is I'm sure it'll

220
00:20:51,040 --> 00:20:55,680
get better, but for the time being and maybe for 
the until the singularity in the event horizon,

221
00:20:55,680 --> 00:21:00,080
I think that will hold for a while. Why not be 
more context efficient? We obviously as humans

222
00:21:00,080 --> 00:21:04,640
are even more limited with our primate minds. 
There's this paper which is like the magic number

223
00:21:04,640 --> 00:21:08,160
seven plus or minus two, which is like we can 
hold basically five to nine discrete ideas in

224
00:21:08,160 --> 00:21:12,640
our heads. And we have all sorts of clever tricks 
of like chunking over time. Five discrete ideas

225
00:21:12,640 --> 00:21:16,880
collapse into like one idea. uh you know, driving 
a car at the beginning. It's like, "Oh my god,

226
00:21:16,880 --> 00:21:20,400
I've got to articulate each of my limbs in this 
particular position and put the pedal on the gas

227
00:21:20,400 --> 00:21:25,040
to accelerate and that I feel like I'm doing like 
quap." If you've ever played Qwop, everything is

228
00:21:25,040 --> 00:21:30,240
everything starts as quap basically. Uh let's find 
quap. Uh oh, I'll just play. It's an athletics

229
00:21:30,240 --> 00:21:36,480
game. So, you have different buttons. Qw controls 
the thighs and the calves. So, your goal is to

230
00:21:36,480 --> 00:21:42,000
start a And then I died. So, I made it 1.3 meters. 
And like we could just do this for the rest of the

231
00:21:42,000 --> 00:21:45,920
thing. I used to I I used to be okay at this game, 
but I haven't played this in decades. I'm going

232
00:21:45,920 --> 00:21:50,800
backwards. Uh so you can figure out different 
techniques, but uh yeah, I'm going the wrong way.

233
00:21:50,800 --> 00:21:55,760
Let's just Can I even kill myself here? Anyway, uh 
so this is how everything feels at the beginning.

234
00:21:55,760 --> 00:22:01,040
Um all skills to me, but it's eventually you 
just it it sort of collapses. It chunkifies and

235
00:22:01,040 --> 00:22:05,040
becomes walking. I don't know why I'm going 
into this learning psychology stuff. I was

236
00:22:05,040 --> 00:22:09,200
interested in this in the past when I was doing 
teaching. Nonetheless, we still are constrained

237
00:22:09,200 --> 00:22:15,680
dramatically. So what it what helped me in and 
why I was so drawn to um type systems and hasll

238
00:22:15,680 --> 00:22:21,680
originally was I started with Ruby on Rails which 
is great and fun but I felt this like deep anxiety

239
00:22:21,680 --> 00:22:26,480
uh building every time I wrote any code. It just 
felt wrong and scary. Basically you have to keep

240
00:22:26,480 --> 00:22:29,680
everything in your head. There are these implicit 
contracts that you're dealing with otherwise your

241
00:22:29,680 --> 00:22:33,760
code will just break at runtime. So there are 
always types. It's just whether or not you encode

242
00:22:33,760 --> 00:22:38,240
them in the type system or you just kind of use 
conventions and try to keep them in your head.

243
00:22:38,240 --> 00:22:42,880
I don't know how I ever kept it in my head. It's 
impressive and for people that can use dynamically

244
00:22:42,880 --> 00:22:46,640
typeyped systems like I think maybe there's 
some kind of brain atrophy that occurs when

245
00:22:46,640 --> 00:22:52,080
you go over to a static type system uh because it 
just feels like so impossible once you've embraced

246
00:22:52,080 --> 00:22:59,040
that crutch or exoskeleton or whatever that Gundam 
uh whatever neon evangelon suit or whatever of the

247
00:22:59,040 --> 00:23:03,440
mind it's it's super addicting and super fun. 
So I just kind of got addicting addicted to

248
00:23:03,440 --> 00:23:08,800
expressing more and more in the type system with 
the goal of enabling local reasoning which is

249
00:23:08,800 --> 00:23:11,680
uh basically to me what all of functional 
programming is for. There's lots of people

250
00:23:11,680 --> 00:23:16,640
who like to get a little onanistic about it and I 
think a lot of people like words like endofunctor

251
00:23:16,640 --> 00:23:21,600
and monad and profunctor optics and they can use 
these words to confuse and insultify people. We

252
00:23:21,600 --> 00:23:26,560
are not going to use the M word um because it's 
actually kind of simple really and that word does

253
00:23:26,560 --> 00:23:31,840
not help like you don't need it to teach people 
obviously. In fact, removing that from effect,

254
00:23:31,840 --> 00:23:36,160
people are learning way more effect than they 
ever learned the Haskell effect system or or

255
00:23:36,160 --> 00:23:42,160
some of the other uh more category theoretical 
embracing uh effect systems of the past. Not

256
00:23:42,160 --> 00:23:45,360
necessary. And in fact, it can be an obstacle. 
I think people can fall in love with that and

257
00:23:45,360 --> 00:23:49,600
they it's kind of arbitrary and anyway that's a 
whole other talk. I forget which stack I'm on now,

258
00:23:49,600 --> 00:23:55,280
but uh oh yes, why context? Like it allows you 
to forget more and more incidental complexity.

259
00:23:55,280 --> 00:23:59,760
The reason why we like pure functions is because 
it's input mapped to output. You can forget about

260
00:23:59,760 --> 00:24:03,360
global state. The second you have global mutable 
state or even a mutable input, you have to be you

261
00:24:03,360 --> 00:24:07,920
have to know now in your head, you have to load 
into your local RAM how everything is called, how

262
00:24:07,920 --> 00:24:11,840
instead of just being able to sort of zoom in on 
this one function, clear your mind and just solve

263
00:24:11,840 --> 00:24:16,000
the hard problem of what you're dealing with. But 
yeah, I mean there's so many related ideas there.

264
00:24:16,000 --> 00:24:22,000
But generally they uh to close one of those loops 
is that we're context constrained. The agents are

265
00:24:22,000 --> 00:24:27,920
context constrained. Type systems are are great 
for both of us. Um I'll trust an agent's code if

266
00:24:27,920 --> 00:24:32,800
it type checks afterwards, just as I would trust 
my own code more if it type checks afterwards. Um

267
00:24:32,800 --> 00:24:36,240
if it were a dynamically typed system and the 
agent made a bunch of changes, well, I would

268
00:24:36,240 --> 00:24:42,880
be very afraid. Uh just as I am with myself. I I 
couldn't work on just JavaScript codebases because

269
00:24:42,880 --> 00:24:48,080
it you don't refactor a JavaScript codebase. Like 
that's a horrifying proposition. But if you have

270
00:24:48,080 --> 00:24:51,760
types constraining you, you kind of can get to 
the point I know it's been a meme and people

271
00:24:51,760 --> 00:24:56,560
make fun of like if it compiles then it works. 
Not necessarily. There's still logic you can get

272
00:24:56,560 --> 00:25:02,000
wrong of course. But if you're just doing a pure 
refactoring, I'm much more confident that it does

273
00:25:02,000 --> 00:25:06,960
work if it compiles afterwards on either side. 
And I you still want to double check everything

274
00:25:06,960 --> 00:25:11,840
of course, but you can express a lot in the type 
system. So that that's useful. And even further,

275
00:25:11,840 --> 00:25:16,160
effect allows you to express even more in the type 
system and have more constraints and a whole bunch

276
00:25:16,160 --> 00:25:22,240
of other features, but basically it it allows me 
to use agents a little more uh maximally than I

277
00:25:22,240 --> 00:25:26,720
would otherwise to embrace them more and to be 
less afraid. And and also like there's two sides

278
00:25:26,720 --> 00:25:30,720
of it too. Like there's there's the there's the 
fact that you know if it makes a bunch of changes,

279
00:25:30,720 --> 00:25:36,400
it probably won't break anything if it if it does 
compile at the end. But also once you're you have

280
00:25:36,400 --> 00:25:42,560
a type you know you know certain things about it 
especially with with schema like there's an aspect

281
00:25:42,560 --> 00:25:47,440
of uh there's a principle or property known as 
being correct by construction. If you only expose

282
00:25:47,440 --> 00:25:51,840
a limited ways of constructing a type that might 
fail it's sort of like if your types are basically

283
00:25:51,840 --> 00:25:56,160
parsed you know that once you have an instance of 
that type certain properties are fulfilled which

284
00:25:56,160 --> 00:26:00,400
means I don't need to if I have just a string I 
don't need to peruse the rest of my codebase to

285
00:26:00,400 --> 00:26:04,960
know like what kind of string is this? what kind 
of properties does the string hold? I'll say, "Oh,

286
00:26:04,960 --> 00:26:10,960
it's this type. Therefore, I know it's a a valid 
UUID or I know it's a a positive integer." So,

287
00:26:10,960 --> 00:26:15,520
you just have to search less. You sort of there's 
more semantic meaning in a very specific type than

288
00:26:15,520 --> 00:26:20,240
there is string, which can really be anything, 
which means less context for me. Also, less like

289
00:26:20,240 --> 00:26:26,240
AIs know how uh hasll works and how type systems 
works, how effects work. So, they can also trust

290
00:26:26,240 --> 00:26:30,880
the type system. So it also helps them not have 
to once again like look at the whole codebase to

291
00:26:30,880 --> 00:26:37,840
understand any one aspect of it if it is if if it 
is sort of pure and self-contained. Okay. So we're

292
00:26:37,840 --> 00:26:45,520
basically just exploring how constraints help uh 
overall and how this has this like almost emergent

293
00:26:45,520 --> 00:26:53,040
positive effect for any codebase. So that's how 
you what you've used to um to start the migration.

294
00:26:53,040 --> 00:26:58,400
It's not necessarily that this is the core of 
effect yet. It's just that this is a primitive

295
00:26:58,400 --> 00:27:04,560
that the effect ecosystem provides. So you've used 
that to kick off the effect migration. What was

296
00:27:04,560 --> 00:27:11,760
the the next step after that? Yeah. Yes. Yes. 
So I I got increasingly gluttonous with my PRs

297
00:27:11,760 --> 00:27:18,080
once I sort of got enough confidence to that that 
I wouldn't break everything. [snorts] So I made a

298
00:27:18,080 --> 00:27:22,200
full few PRs. You know, the first two I was like, 
"Oh, please review this everyone. Review this one

299
00:27:22,200 --> 00:27:28,240
line commit." In short order, I was merging, you 
know, 20 commits myself. uh 20 PRs myself um at

300
00:27:28,240 --> 00:27:34,000
the same time. So all all the guardrails kind of 
flew off once I I was not breaking production for

301
00:27:34,000 --> 00:27:39,440
a few weeks. So yeah, I I sort of started with 
one service after that. So I did some some IDs

302
00:27:39,440 --> 00:27:44,800
fine that was good to have changed throughout 
the codebase pretty minimal just I think an

303
00:27:44,800 --> 00:27:50,720
increase in code quality but after that it was 
time to actually sort of make an effect service.

304
00:27:50,720 --> 00:27:56,560
I think that's a reasonable boundary. One of the 
reasons I like effect is because of I I wrote an

305
00:27:56,560 --> 00:28:02,000
article about this at some point. I think I just 
posted it on Twitter, my only Twitter article. I

306
00:28:02,000 --> 00:28:07,280
was trying to win a million dollars. Um but I 
I didn't. No one not enough people care about

307
00:28:07,280 --> 00:28:14,160
layers. But uh just kidding. Services are 
beautiful because they are very reg regular.

308
00:28:14,160 --> 00:28:18,960
They're they're fractal. They can express many 
things. It's it's a very reasonable module of

309
00:28:18,960 --> 00:28:24,480
a codebase. And and ideally why I was first 
drawn to effect systems particularly in Scala

310
00:28:24,480 --> 00:28:29,920
with the zeal library is because there was a way 
of writing code where every piece of your code

311
00:28:29,920 --> 00:28:35,040
was sort of self similar to every other piece of 
your code. Services were composed of services.

312
00:28:35,040 --> 00:28:40,480
It was turtles all the way down and back up and 
and all the files were were easy to navigate like

313
00:28:40,480 --> 00:28:46,560
it just felt clean and organized and uh whatever 
kind of OCD I have that only applies to code was

314
00:28:46,560 --> 00:28:53,280
deeply satisfied by that particular architecture. 
And so an analogy here might be for for those the

315
00:28:53,280 --> 00:28:59,840
most of us I guess who haven't done a lot of Scala 
in the in in the past but uh I think a more common

316
00:28:59,840 --> 00:29:05,920
analogy would be maybe react components where 
you've used the word like fractal or self similar

317
00:29:05,920 --> 00:29:10,800
uh when you look across like a large react 
codebase like it's everything is a react

318
00:29:10,800 --> 00:29:16,640
component and then you compose them together and 
like whatever react component you look at you have

319
00:29:16,640 --> 00:29:23,040
an intuition for like how the entire thing works 
and I think the same can't really be said for like

320
00:29:23,040 --> 00:29:29,120
free form TypeScript business logic particularly 
when it's async etc and I think what you're

321
00:29:29,120 --> 00:29:36,880
describing with a with a service is uh there we 
we get that sense of familiarity and composability

322
00:29:36,880 --> 00:29:43,440
etc is that right yeah yeah especially contrasting 
it with just vanilla TypeScript I wasn't I'm not

323
00:29:43,440 --> 00:29:48,560
too experienced in vanilla TypeScript codebases 
I've sort of avoided that uh like the plague

324
00:29:48,560 --> 00:29:52,320
for a long time like that's why I was a Scala 
engineer so I tried to you know live in my own

325
00:29:52,320 --> 00:29:57,360
little perfect bubble as long as possible but I 
have some you know I read about it in books what

326
00:29:57,360 --> 00:30:02,880
the real world is like and how it's very messy and 
I certainly peaked at some codebases and and was

327
00:30:02,880 --> 00:30:08,960
sort of mortified and horrified and disgusted 
and repelled by the standards that exists out

328
00:30:08,960 --> 00:30:14,320
there because basically without effect you have 
a few ways of doing things and and none of them

329
00:30:14,320 --> 00:30:18,480
are very good especially if you want to test your 
code. I I think the number one the obvious way is

330
00:30:18,480 --> 00:30:22,640
just to have okay have a file where you implement 
your service as a bunch of exported functions and

331
00:30:22,640 --> 00:30:27,600
if you have some shared state just put that in 
the file if you start up some connections just

332
00:30:27,600 --> 00:30:32,320
uh to to external resources uh whatever open up 
a websocket connection just do that in the file

333
00:30:32,320 --> 00:30:37,680
when the file loads I don't know and if you want 
to test it basically uh I think if either don't

334
00:30:37,680 --> 00:30:44,400
test it or use monkey patching like if you want 
to depend on a service that depends on something

335
00:30:44,400 --> 00:30:50,160
else well it's just it's importing it directly. 
So you the only way to really test it is to do

336
00:30:50,160 --> 00:30:55,920
some kind of monkey patching thing uh some kind 
of mock which is very brittle and not type safe

337
00:30:55,920 --> 00:31:01,200
at all as far as I can tell with the tools that I 
was using or exploring briefly and so you have to

338
00:31:01,200 --> 00:31:05,840
just make sure if you change the underlying logic 
of that dependency that you also update your tests

339
00:31:05,840 --> 00:31:10,400
and it's easy for these things to drift and fall 
out fall apart which once again like the anxiety

340
00:31:10,400 --> 00:31:16,400
comes flooding back in the second like if I on 
my tombstone uh maybe the word single source of

341
00:31:16,400 --> 00:31:21,600
truth is what I'll get as my my epitap. Not a good 
epitap actually, but it sounds sounds deep. Um,

342
00:31:21,600 --> 00:31:26,800
but that's what I find myself. It's like that's 
my northstar design principle because yes,

343
00:31:26,800 --> 00:31:31,280
there's just one way of expressing things. It's, 
you know, and once again, dynamic types fails

344
00:31:31,280 --> 00:31:35,760
that test because there are no contracts. They're 
implicit. So every time you if you try to do duct

345
00:31:35,760 --> 00:31:41,200
typing, there is no single source of truth of that 
contact contract every type. You just need to sort

346
00:31:41,200 --> 00:31:45,920
of manually make sure that you don't [ __ ] that 
implicit contract up. With a type system, you can

347
00:31:45,920 --> 00:31:49,440
have a trait, you can have an interface. That's 
the single source of truth for the structure of

348
00:31:49,440 --> 00:31:54,320
that type. Similarly, the reason I like scheas is 
there's a single source of truth for the structure

349
00:31:54,320 --> 00:31:59,440
of so many things. Everything is derived from 
that initial specification, servers, clients,

350
00:31:59,440 --> 00:32:04,960
etc. And so with services, you have an interface 
that represents that service and you can have

351
00:32:04,960 --> 00:32:10,080
multiple implementations of that uh which are 
described by this uh data type known as a layer,

352
00:32:10,080 --> 00:32:15,760
which is a sort of effectful constructor for a a 
service interface. And so you could easily make a

353
00:32:15,760 --> 00:32:20,800
test fake, a high quality test fake that you know 
does everything you could possibly want it to do

354
00:32:20,800 --> 00:32:24,960
per data type. Sometimes they're very simple. 
Sometimes you can do more complicated things in

355
00:32:24,960 --> 00:32:29,120
the effect codebase. One of our services, sorry, 
in the OpenCode codebase, one of our services

356
00:32:29,120 --> 00:32:37,280
is obviously the LLM service which wraps at the 
current moment um AI SDK, but that's we don't want

357
00:32:37,280 --> 00:32:42,080
to test necessarily against real LLM providers and 
and you know every time we run our tests we lose

358
00:32:42,080 --> 00:32:47,440
$100. That would be bad. So, one of the things I 
did is built a really nice test fake library where

359
00:32:47,440 --> 00:32:52,160
uh the rest of you could just run the main sort of 
session service and and call the prompt method on

360
00:32:52,160 --> 00:32:57,920
that and it'll run all the real production code, 
but when it gets to that LLM service, uh it it's

361
00:32:57,920 --> 00:33:04,160
feeding back pre sort of predetermined data that 
you determine in the test. So, I made a really

362
00:33:04,160 --> 00:33:07,760
nice test mock. So, first you can make prompt. 
It'll obviously block waiting for what would

363
00:33:07,760 --> 00:33:15,760
have been HTTP responses to come back in from say 
ChatGPT's uh model but instead on the next line I

364
00:33:15,760 --> 00:33:24,240
can say you know llm.text what's up and then that 
will get fed back to it it'll sort of be streamed

365
00:33:24,240 --> 00:33:28,960
in as the response uh to the the session service. 
So you can do all sorts of really beautiful things

366
00:33:28,960 --> 00:33:34,400
that I don't even know my theory is just people 
just don't really do it at all. They just don't

367
00:33:34,400 --> 00:33:39,280
test it. That seems to be the case. That 
seems to be why so much software is just

368
00:33:39,280 --> 00:33:44,320
um I'm I'm trying to think of a better word than 
dog [ __ ] but that's the one that comes to mind.

369
00:33:44,320 --> 00:33:50,000
So, [laughter] I don't know. Have you felt this? 
I've noticed that like catchy.com for instance, so

370
00:33:50,000 --> 00:33:55,840
often I'll type a message, I want to type a second 
message, I can't hit the submit button anymore.

371
00:33:55,840 --> 00:34:00,560
Some stream has gotten lost. And with my effect 
oriented mind, I just see like a leaked resource

372
00:34:00,560 --> 00:34:06,000
or an unclosed stream. An abort signal that 
wasn't propagated as most likely uh the culprit

373
00:34:06,000 --> 00:34:09,920
cuz that's hard to do right and you have to do it 
all the time everywhere and be very careful about

374
00:34:09,920 --> 00:34:17,040
it. And there's so many sort of foot guns. It's 
just a sort of a golem consed entirely out of foot

375
00:34:17,040 --> 00:34:26,080
guns. [laughter] So just to bring this back, we're 
basically uh walking through the the the migration

376
00:34:26,080 --> 00:34:33,680
from uh the OpenCode codebase with like pre-effect 
to increasingly effectified where you've mentioned

377
00:34:33,680 --> 00:34:38,960
that by now you basically have a parallel 
implementation of pretty much everything that's

378
00:34:38,960 --> 00:34:45,440
fully effectified and you're about to flip this 
over completely. But I think you're still walking

379
00:34:45,440 --> 00:34:52,800
through the early stages of like how did you kick 
things off? Also, how did you uh win the trust of

380
00:34:52,800 --> 00:35:01,200
the of the rest of the the OpenCode team to like 
get get on board with this to change the way the

381
00:35:01,200 --> 00:35:08,160
at that point status quo way of writing TypeScript 
to now embracing this. Yes. Okay. Thank you. Yeah,

382
00:35:08,160 --> 00:35:13,360
I'm sort of turning this accidentally into Zeno's 
podcast or Zeno's Paradox podcast where Oh, I'm

383
00:35:13,360 --> 00:35:17,120
We'll never get through the first question. 
We're going to keep getting halfway there and

384
00:35:17,120 --> 00:35:22,800
going off on tangents, but hopefully it'll be a 
good uh journey to nowhere. Yeah. So, services,

385
00:35:22,800 --> 00:35:28,720
I I implemented a service. So, uh some tangential 
service, a new service that involved this other

386
00:35:28,720 --> 00:35:34,320
project that I was working on, some kind of uh 
service that was logging into that. Dax wrote

387
00:35:34,320 --> 00:35:39,040
the original version uh had a PR. I knew it wasn't 
connected to the rest of the infrastructure. So,

388
00:35:39,040 --> 00:35:44,640
I basically effectified that, turned it into 
a service. It went well and from there I tried

389
00:35:44,640 --> 00:35:49,760
to just hunt through the rest of the codebase. 
I mean many codebases are oriented as services

390
00:35:49,760 --> 00:35:54,000
even if they're not effect services even if 
they don't make their boundaries too clear.

391
00:35:54,000 --> 00:35:57,840
Every file perhaps is a module. There's some 
kind of internal dependency graph that you can

392
00:35:57,840 --> 00:36:04,400
track. So I try to find a good inlet there and 
I think you know generally starting at either

393
00:36:04,400 --> 00:36:10,080
the bottom or the top is is good. Um burning the 
candle at at both ends can work but but also you

394
00:36:10,080 --> 00:36:14,960
can start really anywhere. I tried to find some 
simple services. I think I can show off some

395
00:36:14,960 --> 00:36:20,880
code actually at this point. Um, not that it's 
going to see if it if it's easy enough to to to

396
00:36:20,880 --> 00:36:26,800
understand. Yeah. Yeah. Yeah. It's not Mhm. While 
we're pulling this up, I'm curious like how did

397
00:36:26,800 --> 00:36:34,800
you choose that service? Um like what I've seen a 
lot is that people adopt effect really motivated

398
00:36:34,800 --> 00:36:42,080
um centered around a particularly burning 
problem and like often it has to do something

399
00:36:42,080 --> 00:36:49,840
uh with testing. Um, so I'm curious what was that 
burning problem that you were reaching for like a

400
00:36:49,840 --> 00:36:55,680
services abstraction right away and uh that is 
probably also buying you some some trust and

401
00:36:55,680 --> 00:37:03,040
goodwill from new colleagues who um who are well 
aware of this problem and might be skeptical of

402
00:37:03,040 --> 00:37:10,240
like new technologies. and seeing it like solve a 
real problem probably goes a long way to to build

403
00:37:10,240 --> 00:37:16,160
up a lot of trust and to to get the goodwill to 
to do the effect migration. Yeah, luckily I had

404
00:37:16,160 --> 00:37:24,560
some cover because well I was hired knowing that I 
was uh totally deranged by effect and that I there

405
00:37:24,560 --> 00:37:32,000
would be no stopping me. So I took I took that uh 
as as some encouragement. And then yeah, I I was

406
00:37:32,000 --> 00:37:37,600
mostly optimizing for something that wouldn't 
break everything. I think I was more afraid of

407
00:37:37,600 --> 00:37:44,880
uh making like I already had enough goodwill and 
trust to do this. They were already sort of sold

408
00:37:44,880 --> 00:37:51,040
in effect. The only thing I I could see sort 
of undoing that was if I destroyed OpenCode for

409
00:37:51,040 --> 00:37:56,960
millions of users. So it was more like minimizing 
the impact at least at the beginning. I knew the

410
00:37:56,960 --> 00:38:01,520
benefits would come and things would become more 
testable. I think one service I started with

411
00:38:01,520 --> 00:38:05,440
uh I might be wrong on the order the PR it's all 
open source so you can track all the PRs if you

412
00:38:05,440 --> 00:38:10,960
want and go through the history of whatever 400 
PRs I opened in the last couple months but I think

413
00:38:10,960 --> 00:38:16,400
there was these there's permission and question 
uh services so I'll just start with uh question

414
00:38:16,400 --> 00:38:20,880
so this is like the ask user question tool right 
so I can say something just for the the folks who

415
00:38:20,880 --> 00:38:27,120
are just only listening uh we're basically just 
navigating through the OpenCode uh codebase at

416
00:38:27,120 --> 00:38:34,800
this point and We're looking at a few different 
modules. I think you're you're using zed here and

417
00:38:34,800 --> 00:38:42,880
uh obviously also running OpenCode uh on on the 
side to get some some more information about

418
00:38:42,880 --> 00:38:48,240
uh the the codebase as uh as we do these days. We 
don't like look things up ourselves anymore, but

419
00:38:48,240 --> 00:38:56,080
we get it explained. Um, and so yeah, we're we're 
looking here at a few schema definitions, which I

420
00:38:56,080 --> 00:39:02,800
suppose is related to some of the the early work 
you've been doing. Yep, exactly. Uh, so we're

421
00:39:02,800 --> 00:39:07,840
looking at the question service. I'm sorry for the 
audio people. This might be a little weird. Uh but

422
00:39:07,840 --> 00:39:13,120
we I'm sure we'll go on many tangents that are 
more amendable to just the spoken word. But um

423
00:39:13,120 --> 00:39:17,360
the question service is basically there's this ask 
user question tool that I think Claude Code first

424
00:39:17,360 --> 00:39:24,480
had where the agent has a tool call available to 
you where it can submit questions and then you

425
00:39:24,480 --> 00:39:31,680
see in your UI a in this case a numbered list 
of of possible answers that you as the user uh

426
00:39:31,680 --> 00:39:39,920
can can answer or you can form in as a tuy. Yes, a 
little TUI form here. So, uh I I asked OpenCode to

427
00:39:39,920 --> 00:39:44,240
ask me a bunch of questions. It's obviously pretty 
random questions because I it has no context. It's

428
00:39:44,240 --> 00:39:48,480
a new chat. So, it asks me for my current goal. 
What would you like me to help with right now? I

429
00:39:48,480 --> 00:39:53,600
don't know. Let's say review some code. So, I can 
hit three there. Uh how much detail? Detailed.

430
00:39:53,600 --> 00:39:59,280
Okay. Um whatever. And then research only. Fine. 
And then I can confirm these results and it'll

431
00:39:59,280 --> 00:40:05,520
get those results and continue looping with that. 
I'll interrupt it here. But the question service

432
00:40:05,520 --> 00:40:11,040
is the one that tracks which questions have been 
answered um the user's responses and when it's all

433
00:40:11,040 --> 00:40:17,600
all done. So there's a bit of asynchronicity here 
which is always a good place to to use effect. Um

434
00:40:17,600 --> 00:40:21,360
once again that wasn't the primary service. I 
wanted to start by not destroying the codebase

435
00:40:21,360 --> 00:40:27,840
and ruining my credibility but I I there there 
is also a little bit of extra benefit here.

436
00:40:27,840 --> 00:40:34,720
um something that there's some somewhat meaty 
uh immorsely uh about about this with regards

437
00:40:34,720 --> 00:40:40,720
to concurrency and asynchronicity. So at the top 
I do have some schemas. So the the optic question

438
00:40:40,720 --> 00:40:47,360
option uh there's like a label and a description. 
So I I guess that's sort of what is is actually

439
00:40:47,360 --> 00:40:53,680
I forget what what is indeed what here. Um I 
should look at this exactly again. I think yeah

440
00:40:53,680 --> 00:40:59,760
the answer is is what I'm offered. So we're we're 
effectively modeling our situation here. So if you

441
00:40:59,760 --> 00:41:05,360
think about this form, we have questions, we have 
like different options to answer that question and

442
00:41:05,360 --> 00:41:10,880
then we get answers hopefully. Exactly. Yeah. 
And and the nice thing is that some of this was

443
00:41:10,880 --> 00:41:17,760
already designed albeit in Zod and raw promise 
raw promises. So I I didn't have to think about

444
00:41:17,760 --> 00:41:21,680
the design of the system just yet. I'm excited 
for multiple passes where I can improve things

445
00:41:21,680 --> 00:41:27,120
uh or or sort of apply my taste and opinions 
to the overall uh data modeling. But my goal

446
00:41:27,120 --> 00:41:30,560
originally was like don't do two things at 
once. If you're going to be refactoring a

447
00:41:30,560 --> 00:41:37,920
giant hundreds hundreds of thousands of lines of 
code into a new paradigm, don't also inter interle

448
00:41:37,920 --> 00:41:43,600
uh sort of semantic logic changes because if 
something breaks, I didn't want to like not know,

449
00:41:43,600 --> 00:41:48,400
okay, was it the effect migration that broke it or 
was it my other uh logical change that I couldn't

450
00:41:48,400 --> 00:41:53,280
resist? Um don't change too many variables all 
at once. Yeah, that would be very frightening.

451
00:41:53,280 --> 00:41:58,800
Uh need to isolate the variables as you as you'll 
see here. I also on a lot of these schemas I tend

452
00:41:58,800 --> 00:42:03,520
to use schema.class just I don't know I like the 
way that that reads. One of the the downsides of

453
00:42:03,520 --> 00:42:08,560
Typescript is sort of its general verbosity. 
This is why I was sort of stuck in Scala for

454
00:42:08,560 --> 00:42:13,120
so long is that you do have to sort of repeat 
uh various identifiers multiple times for for

455
00:42:13,120 --> 00:42:18,480
various reasons. Luckily um and this is something 
another tangent we can go on down the line is like

456
00:42:18,480 --> 00:42:24,640
AI I think not only helped affect adoption 
but also well yeah AI for me personally made

457
00:42:24,640 --> 00:42:31,840
effect [clears throat] more feasible. I was such a 
chromogen uh that I I loved Scala's terseness and

458
00:42:31,840 --> 00:42:36,720
and expressivity as as they like to say which 
basically just means you can you don't have to

459
00:42:36,720 --> 00:42:40,240
write a lot of redundant code. It's kind of that 
single source of truth principle except even at

460
00:42:40,240 --> 00:42:45,280
the syntactic level just like you write the bare 
minimum that expresses the idea with TypeScript.

461
00:42:45,280 --> 00:42:52,400
Sometimes you have to uh duplicate yourself. 
However, agents make this painful. Exactly.

462
00:42:52,400 --> 00:42:58,560
Like now it basically you no longer need to write 
it yourself. So the when you had to suffer twice

463
00:42:58,560 --> 00:43:04,800
before where you had to like by hand write out 
the duplication then still read the duplication.

464
00:43:04,800 --> 00:43:09,760
Now we only have to bear with the uh reading 
the duplication which is more tolerable. It's

465
00:43:09,760 --> 00:43:14,320
more tolerable and also the brain's really good at 
pattern matching. So once this you know your brain

466
00:43:14,320 --> 00:43:19,920
recogn I like all I see now is just okay there's 
an option thing there's opt option everything else

467
00:43:19,920 --> 00:43:25,760
kind of blurs out in the background and and of 
course maybe one day we'll have uh in our idees

468
00:43:25,760 --> 00:43:31,120
sort of projectors that can uh instead of just 
syntax highlighting we can sort of restructure the

469
00:43:31,120 --> 00:43:36,000
syntax because if we're not editing the code we 
can just sort of read a simplified projection. We

470
00:43:36,000 --> 00:43:39,520
could project this into another language that we 
like. So I could read this as H hasll or whatever.

471
00:43:39,520 --> 00:43:43,440
The Unison programming language kind of had 
support for this, but but anyway, that's not here

472
00:43:43,440 --> 00:43:46,720
yet. Maybe that'll never get here. It probably 
doesn't matter because this this isn't really

473
00:43:46,720 --> 00:43:50,880
a pain in reality. I'm I get better at reading 
TypeScript. But you'll see that each of these

474
00:43:50,880 --> 00:43:55,040
does have a static readonly Zod property because I 
have a I should probably open source this. I mean,

475
00:43:55,040 --> 00:43:59,200
it is open source. It's just all in line, but 
there's a there's an effect to Zod converter.

476
00:43:59,200 --> 00:44:05,120
So there's the schema to odd converter because we 
need this at the boundary for the Hono uh server

477
00:44:05,120 --> 00:44:12,160
so it can generate its API documentation and parse 
things. That's how you basically created this like

478
00:44:12,160 --> 00:44:17,600
still lasting bridge between the old world and the 
new world where you didn't have to do a big bang

479
00:44:17,600 --> 00:44:24,080
migration, but you could essentially still have a 
single source of truth throughout the migration,

480
00:44:24,080 --> 00:44:30,720
but still like feed it into the old system and 
use it in the new system or vice versa. Exactly.

481
00:44:30,720 --> 00:44:34,800
So yeah, we have this this boundary problem 
and and generally I mean effect makes this

482
00:44:34,800 --> 00:44:39,360
fairly painless, right? So you need a way from 
going from the promise boundary to the effect

483
00:44:39,360 --> 00:44:43,680
boundary and then from the effect boundary back 
to the promise boundary. So you can run effects

484
00:44:43,680 --> 00:44:49,840
as promises and you can wrap promises as effects. 
So effect.promise can uh it actually gives you an

485
00:44:49,840 --> 00:44:53,600
abort signal which is really nice even though most 
people don't use that in their promise code. And

486
00:44:53,600 --> 00:44:59,280
then you can call out to some other you know AI 
generate text and you can pass in the uh signal

487
00:44:59,280 --> 00:45:03,920
the abort signal as as an option or something 
and that'll turn that into a promise. And of

488
00:45:03,920 --> 00:45:10,960
course you can also do Effect.runPromise and take 
some effect and get back a promise of its uh its

489
00:45:10,960 --> 00:45:14,800
result or whatever. So you have to do these at the 
boundaries and there's some tricks that I that you

490
00:45:14,800 --> 00:45:19,440
might have to do in in in a large codebase like 
this and we can get to that later on. I mean

491
00:45:19,440 --> 00:45:25,200
it's all open source once again. So there's some 
details there if if there is some complexity which

492
00:45:25,200 --> 00:45:30,480
this codebase does definitely have. Uh and then 
I had that same problem with Zod and schema. So

493
00:45:30,480 --> 00:45:36,560
I don't think I ever go from Zod to schema. Uh I 
just because you have less of these stacks, right?

494
00:45:36,560 --> 00:45:41,360
So I just uh defined the base implementation. I 
just started at the leave nodes instead of like

495
00:45:41,360 --> 00:45:46,560
having Zod then schema then Zod. I started the 
leaf nodes and built myself back up converting

496
00:45:46,560 --> 00:45:52,800
to Zod at the boundary so that we could use it in 
the uh the Hono uh server. And that's basically so

497
00:45:52,800 --> 00:45:59,280
earlier you asked before about the Hono server. So 
I do these days have an HTTP uh API but basically

498
00:45:59,280 --> 00:46:05,200
um both are pointing to the same underlying 
at this point effectified services. This one

499
00:46:05,200 --> 00:46:10,640
just calls uh Effect.runPromise basically before 
calling these things. Uh or I have a I have an app

500
00:46:10,640 --> 00:46:17,200
runtime.runPromise on the uh the effect services. 
Whereas the HTTP API can just sort of yield

501
00:46:17,200 --> 00:46:23,920
whatever kind of uh service I'm usingdo thing 
directly instead of having to run to a promise.

502
00:46:24,560 --> 00:46:31,760
And I think that's like really highlighting one of 
the the most important things about using effect

503
00:46:31,760 --> 00:46:37,600
not in a vacuum where like you like one Sunday 
you start a new project and you decide to write

504
00:46:37,600 --> 00:46:43,600
the first line of code in effect and like you're 
you're already in that universe. But uh when you

505
00:46:43,600 --> 00:46:50,080
have a codebase that probably has like hundreds 
of thousands of lines of code with like that has

506
00:46:50,080 --> 00:46:57,360
real complexity like everything kind of interwoven 
with each other. Now you want to like you maybe

507
00:46:57,360 --> 00:47:02,320
you have all the agreement that in a year from 
now everything should be effect but how do you

508
00:47:02,320 --> 00:47:08,560
go from like today to there in a way where 
you don't like freeze everything now you need

509
00:47:08,560 --> 00:47:14,560
incremental adoption and I think this is where 
there's like multiple ways to to go about this

510
00:47:14,560 --> 00:47:21,600
but interoperability is like helping so much this 
is why I think converting a code ba an existing

511
00:47:21,600 --> 00:47:28,400
TypeScript codebase to effect is just making 
that's so easy is like very far away from let's

512
00:47:28,400 --> 00:47:35,680
say porting something from Go or Java into effect 
because you can still like reuse all the chunky

513
00:47:35,680 --> 00:47:41,840
bits of your code as little or as much as you want 
or or say like to use a TypeScript uh library as

514
00:47:41,840 --> 00:47:46,480
well like to to make fun of RxJS more like if I 
were trying to do this I don't think this would

515
00:47:46,480 --> 00:47:51,440
work very well like going from promise to RxJS 
that might be possible but it's it's a it's a

516
00:47:51,440 --> 00:47:56,160
very different paradigm right this always operates 
the level of streams. Everything is going to be

517
00:47:56,160 --> 00:48:03,520
a stream. Not all promise code fits into these 
oneshot streams very well. It's it's a weird uh

518
00:48:03,520 --> 00:48:12,400
impedance mismatch to fill out your bingo card. Um 
yeah, whereas effect uh is represents basically a

519
00:48:12,400 --> 00:48:18,640
computation that might succeed or fail. It's it's 
strictly a supererset of of a promise basically.

520
00:48:18,640 --> 00:48:23,040
And then you have a separate streaming abstraction 
for when you want streams. So yeah, it's pretty

521
00:48:23,040 --> 00:48:27,120
painless. Uh overall, there are a few nuances. 
They'd probably be boring in this context,

522
00:48:27,120 --> 00:48:32,320
but I definitely will write something up um at 
some point or make or add a add a chapter to my

523
00:48:32,320 --> 00:48:38,880
effect institute on some of the more uh low-level 
gotchas or details. But uh I think most of that is

524
00:48:38,880 --> 00:48:42,960
only because of the some particular patterns that 
we were using in OpenCode that aren't necessarily

525
00:48:42,960 --> 00:48:49,040
even very common. So, so if we zoom out a little 
bit, so this this questions module has been like

526
00:48:49,040 --> 00:48:55,040
one of the the first targets that you've converted 
and sort of like introduced the effect patterns

527
00:48:55,040 --> 00:49:00,320
and prove that this is working. Um, if we zoom 
out a little bit and like over the course of now

528
00:49:00,320 --> 00:49:06,880
a few weeks and months, how did the migration 
progress? Which sort of issues did like at some

529
00:49:06,880 --> 00:49:12,560
point you probably uh started looking into more 
thorny areas of the the codebase? I think you've

530
00:49:12,560 --> 00:49:18,880
mentioned something that uh before that there were 
like pre-existing abstractions that you had to

531
00:49:18,880 --> 00:49:26,320
like translate a little bit uh a little bit more. 
Um so which sort of challenges were you facing and

532
00:49:26,320 --> 00:49:32,320
how did you overcome them? Yeah. Yeah. Yeah. I'm 
actually going to have OpenCode here uh render a

533
00:49:32,320 --> 00:49:37,600
little service tree of of uh all the services that 
I've effectified. Hopefully that will help because

534
00:49:37,600 --> 00:49:43,280
this is just one note of of many. uh the sort of 
the core of it is definitely the the core session

535
00:49:43,280 --> 00:49:49,120
service that ends up transitively depending on all 
all of these other ones and just to sort of round

536
00:49:49,120 --> 00:49:54,640
off like so at the top I had the schemas which is 
is great but then we we try to make all the files

537
00:49:54,640 --> 00:49:58,320
there are many ways of doing this but um once 
again self similar and consistent so that if I

538
00:49:58,320 --> 00:50:02,880
have an agent port another file it's a fairly 
mechanical process so at the beginning I would

539
00:50:02,880 --> 00:50:07,840
recommend doing this is the approach that worked 
at least for me when migrating a large codebase

540
00:50:07,840 --> 00:50:13,120
or doing any kind of repetitive task is like walk 
walk through the very first couple of iterations,

541
00:50:13,120 --> 00:50:18,880
the example set very carefully, maybe handcode 
them or at least go through a bunch of iterations

542
00:50:18,880 --> 00:50:23,440
until you're very happy with the way everything 
looks and then use that as sort of a seed as a

543
00:50:23,440 --> 00:50:27,840
reference point for the agent as you tell it to 
do other ones and eventually you can see that it

544
00:50:27,840 --> 00:50:32,480
gets to a point where it almost does what you need 
on the first shot or the second shot. And so yeah,

545
00:50:32,480 --> 00:50:36,000
really paying attention to those first few 
examples because it agents are pretty good

546
00:50:36,000 --> 00:50:40,800
at copying and extrapolating existing patterns. 
So you want to make sure that the the data set

547
00:50:40,800 --> 00:50:46,560
you're feeding it is is really high quality. So 
if someone doesn't have that in their own codebase

548
00:50:46,560 --> 00:50:54,160
yet, would you uh have any advice for references? 
What people should check out as a maybe pointing

549
00:50:54,160 --> 00:50:59,280
their agent to as a reference? Should should 
they just look at the OpenCode codebase or are

550
00:50:59,280 --> 00:51:05,280
there other simpler reference apps that that you 
would point people to? So I did I did make that

551
00:51:05,280 --> 00:51:10,400
effect.solutions website for sort of that purpose. 
I could briefly share that again. I actually don't

552
00:51:10,400 --> 00:51:14,480
think I shared this the first time. So let me 
just share it. Um I do need to update this.

553
00:51:14,480 --> 00:51:19,440
I think I just did update it for the newest 
effect v4. But basically this is just kind of

554
00:51:19,440 --> 00:51:25,280
um yeah I was trying to with all my effect work 
uh effect tutorialization work. I was trying to

555
00:51:25,280 --> 00:51:32,160
hit a couple of different um what I saw thought 
of as GA gaps. One was just to as I was mentioning

556
00:51:32,160 --> 00:51:38,000
before just like highquality uh content that 
would have been enticing even for its own sake

557
00:51:38,000 --> 00:51:41,360
regardless of effect just to expose it to more 
people so that they would share it and say like

558
00:51:41,360 --> 00:51:46,160
I don't even know care about effect but here mom 
watch this uh this this will be interesting this

559
00:51:46,160 --> 00:51:50,880
will make your brain tickle or something. And the 
other one was, so the existing docs are great,

560
00:51:50,880 --> 00:51:54,960
but they're very encyclopedic and they kind of 
start from first principles and it just gets

561
00:51:54,960 --> 00:52:00,160
into the details really quickly. I wanted a much 
higher level view almost like an almanac or a a

562
00:52:00,160 --> 00:52:04,880
best practice guide of just like don't worry about 
how this works. Uh you can read the docs if you

563
00:52:04,880 --> 00:52:10,480
want to know that or you can ask your agents for 
this is sort of low-level toutelage, but why don't

564
00:52:10,480 --> 00:52:15,040
I just tell you what to do. Yeah. And obviously 
that's not going to apply to every situation,

565
00:52:15,040 --> 00:52:19,360
but if you're a newcomer, like what what fulfills 
the paro principle of like here's 20% of the sides

566
00:52:19,360 --> 00:52:24,160
of the documentation that satisfies most of 
what you need. So like here's basically sort of

567
00:52:24,160 --> 00:52:29,360
very prescriptive organize your stuff like this. 
And there are many ways of doing this. In fact,

568
00:52:29,360 --> 00:52:34,320
in OpenCode, I I've changed this. I pull 
this out into a separate interface. But

569
00:52:34,320 --> 00:52:38,800
it's really that that's a matter of taste. This 
is perfectly viable. And I would just recommend

570
00:52:38,800 --> 00:52:42,880
being consistent picking something that you that 
you want. And there's a whole bunch of examples

571
00:52:42,880 --> 00:52:48,320
in here. So effect.solutions has one take of this. 
Uh and it also of course because everything does

572
00:52:48,320 --> 00:52:52,240
there's this copy agent instructions button. So 
if you click this and paste it into whatever agent

573
00:52:52,240 --> 00:53:00,080
you want, it basically tells the agent how to um 
install a CLI and set up your codebase with like

574
00:53:00,080 --> 00:53:07,760
the effect LSP server and the right TypeScript 
settings and how to basically read these docs.

575
00:53:07,760 --> 00:53:11,200
That seemed to be the lowest friction way of doing 
it. just like a copy paste into your agent instead

576
00:53:11,200 --> 00:53:15,920
of an MCP or something which is just more friction 
at the end of the day just like click copy pasta

577
00:53:15,920 --> 00:53:20,960
people can copy pasta since the beginning of 
time so I trust them to continue doing that

578
00:53:20,960 --> 00:53:27,040
um got it and so that basically contains all the 
patterns that are like yeah parto principle style

579
00:53:27,040 --> 00:53:33,200
that you might encounter as a foundation uh 
just to to get things going and at that point

580
00:53:33,200 --> 00:53:40,720
you probably develop your own tastes and your own 
like preferences how what is like your Acme Corp

581
00:53:40,720 --> 00:53:46,800
uh way of doing things and then you can mold it 
and like tell the agent like maybe create your own

582
00:53:46,800 --> 00:53:51,360
skill file or something. Yeah, that's basically 
the equivalent of my skill file except as a as a

583
00:53:51,360 --> 00:53:55,360
website and not as a skill because I think at 
the time I made it skills weren't universally

584
00:53:55,360 --> 00:54:00,960
adopted. I think we were still unskilled. We 
were unskilled. Uh but yeah, it's basically

585
00:54:00,960 --> 00:54:06,880
I was I was constantly sending paths to my agents 
of other codebases where I done this. I was like,

586
00:54:06,880 --> 00:54:11,040
let me just uh sort of collect this into some a 
useful thing that I can distribute both to future

587
00:54:11,040 --> 00:54:17,440
versions of myself as well as uh the general 
public. Um and yeah, in there I I basically

588
00:54:17,440 --> 00:54:22,720
recommend okay, always use schema for all your 
data modeling because yeah, it's principled it

589
00:54:22,720 --> 00:54:27,600
works well. That's just something I was missing 
from Scala is just a you could basically define

590
00:54:27,600 --> 00:54:33,600
any kind of data in the world as a combination 
as a sort of a composition of what the functional

591
00:54:33,600 --> 00:54:38,800
programming language people called product and sum 
types. But it's like and types and or types like

592
00:54:38,800 --> 00:54:44,400
uh for instance uh you can think of a boolean 
that's that's sort of the canonical most simple or

593
00:54:44,400 --> 00:54:52,000
type. It's either it has two values false or true. 
But a person might be a composition of uh you know

594
00:54:52,000 --> 00:55:00,160
um an uh is alive which is a boolean and their 
name which is a string anyway. And you can have

595
00:55:00,160 --> 00:55:05,200
infinite types and all that stuff. But basically 
that that's uh these two very simple composable

596
00:55:05,200 --> 00:55:09,600
primitives are enough to basically define any kind 
of data type you want in the world. Like bits are

597
00:55:09,600 --> 00:55:16,080
essentially booleans. All right. On or off, true 
or false. And then you just have a bunch of them

598
00:55:16,080 --> 00:55:20,800
anded together, right? A bite is is whatever 
eight of them. Um and out of that, of course,

599
00:55:20,800 --> 00:55:26,640
everything uh computable calls. So it's definitely 
powerful enough and and simple enough. Um yeah,

600
00:55:26,640 --> 00:55:31,280
it's orthogonal. It's it's got everything I like 
about um API design like maybe one of the top

601
00:55:31,280 --> 00:55:36,720
principles of good APIs in my in my estimation is 
orthogonality that you don't have too many things

602
00:55:36,720 --> 00:55:40,400
doing the same thing. You have you can achieve 
a lot of power but through compositionality and

603
00:55:40,400 --> 00:55:45,840
orthogonality and I think just product and 
subtypes are a good example of that. We're

604
00:55:45,840 --> 00:55:49,680
not going to go in a in a separate tangent 
of this, but just a call out also for like

605
00:55:49,680 --> 00:55:57,840
your visual types project, which like beautifully 
also like highlights the the the various goodies

606
00:55:57,840 --> 00:56:04,080
of Typescript on a on a type level. I I think we 
we're going to like see a a brief demonstration of

607
00:56:04,080 --> 00:56:10,000
that, but like please go check it out like in 
your own time. This is uh like I think mostly

608
00:56:10,000 --> 00:56:17,680
decoupled from effect but if you uh I think 
it's gives you like a deeper understanding of

609
00:56:17,680 --> 00:56:22,400
um like effect by just knowing the basics 
of it. Yeah. Yeah. Yeah. So this is just

610
00:56:22,400 --> 00:56:25,920
another fun thing. I was as I mentioned newer to 
typescript and there are some details to the type

611
00:56:25,920 --> 00:56:31,040
system. So I kind of did this as a little um 
both to have fun with animations but also to

612
00:56:31,040 --> 00:56:37,360
uh teach myself um type. So yeah, you can hit the 
arrow keys again to like navigate between. Okay,

613
00:56:37,360 --> 00:56:41,280
this is the concept of types are sets, which 
is kind of what I was alluding to. So boolean

614
00:56:41,280 --> 00:56:47,280
is a set of true or false. Direction, northeast, 
south, west. So these are sort of these sum types,

615
00:56:47,280 --> 00:56:55,040
these ore types. Uh and number you can really 
think of as an infinite set of well of ores. Um

616
00:56:55,040 --> 00:56:59,440
so it still it still works there. Anyway, there's 
a whole bunch of fancy animations and where's the

617
00:56:59,440 --> 00:57:04,880
vin diagram? This is my favorite one. Um, 
but yeah, I'll stop sharing that one. Um,

618
00:57:04,880 --> 00:57:13,040
check it out. It's too too good to ignore. 
[laughter] I got going going back to to the to

619
00:57:13,040 --> 00:57:22,480
the migration and I think you're by now um GP 5.5 
has given us a good list of like all the modules

620
00:57:22,480 --> 00:57:30,720
we need to scroll quite a bit. So this is the the 
domain of uh of OpenCode. Yeah. Yeah. It's kind of

621
00:57:30,720 --> 00:57:35,520
is it's sort of uh it's not done it in the nicely 
nested way that I would have wanted. It's kind of

622
00:57:35,520 --> 00:57:41,040
showing each we have to reconstruct and traverse 
the graph here. It's just giving us a bunch of

623
00:57:41,040 --> 00:57:46,400
edges basically like okay agent define depends on 
plugin but we would have to find plugin. I'm going

624
00:57:46,400 --> 00:57:50,720
to give it one more chance and plugin depends 
on bus and config etc. I want to actually here

625
00:57:50,720 --> 00:58:01,120
we go. So okay so there's the the main app layer. 
Uh let me go to where's the the session and and I

626
00:58:01,120 --> 00:58:07,280
think just like looking at this ignoring which 
technology this is we might be writing rust we

627
00:58:07,280 --> 00:58:12,560
might be writing something else but I think this 
gives you OpenCode is like a complex product

628
00:58:12,560 --> 00:58:19,920
um and a complex codebase project etc and this 
gives us a good semanticformational overview over

629
00:58:19,920 --> 00:58:25,680
like the involved concepts almost like a glossery 
page that explains the the various concepts

630
00:58:26,320 --> 00:58:32,080
and doing that in a hierarchical way. And like 
the cool thing is like those those concepts now

631
00:58:32,080 --> 00:58:39,120
correlate very elegantly, very concisely with 
effect services that actually give you the

632
00:58:39,120 --> 00:58:43,680
implementation for that concept. Yeah, basically 
each of these is an effect service. So every file

633
00:58:43,680 --> 00:58:47,760
is laid out the same way. And once again I you 
know if I do come up with a better pattern I

634
00:58:47,760 --> 00:58:52,160
could this is a very parallelizable agent happy 
refactoring where it's like oh let's rename

635
00:58:52,160 --> 00:58:56,160
all interfaces to something else like okay I'm 
exporting the interface as interface that's kind

636
00:58:56,160 --> 00:58:59,840
of silly but why not? I was trying to think should 
I come up with a better word like what should I

637
00:58:59,840 --> 00:59:05,280
call this? Well it is an interface so why don't I 
just call it the interface [snorts] and it's per

638
00:59:05,280 --> 00:59:09,760
file so it it ends up working out just fine. 
And so yeah there's there's always a service

639
00:59:09,760 --> 00:59:15,840
context.service service um that has this interface 
and then there if there is a main layer sort of a

640
00:59:15,840 --> 00:59:22,000
main implementation which most of them have just 
one it's defined here as as layer which uh all

641
00:59:22,000 --> 00:59:26,960
like the way you construct these things or the way 
I always do is at at the top you always uh import

642
00:59:26,960 --> 00:59:32,160
transitive uh dependencies or sort of you I guess 
yield your transitive dependencies so these are

643
00:59:32,160 --> 00:59:38,560
other services so by yielding this we're going to 
get a a dependency on bus service so we'll need to

644
00:59:38,560 --> 00:59:43,440
come up with an implementation of that to provide 
later. But of course, bus service has its own

645
00:59:43,440 --> 00:59:48,640
layer. So, we can just to linger on this and like 
if this is the first time someone is seeing this

646
00:59:48,640 --> 00:59:53,200
and highly recommend maybe switching to a video 
at this point if you're if you're still just

647
00:59:53,200 --> 00:59:58,880
listening. The the magic that we're seeing here 
and I think that's really novel about effects,

648
00:59:58,880 --> 01:00:04,800
at least when effects started uh coming out. No 
other technology that I was aware of in Typescript

649
01:00:04,800 --> 01:00:11,600
did this is that if you're using one thing um 
like here in like we're we're using the this

650
01:00:11,600 --> 01:00:21,600
service for our thing that we're building now 
we know like A requires B to to B and like this

651
01:00:21,600 --> 01:00:29,600
um transitive dependency like and u that that just 
like builds up uh implicitly without you having to

652
01:00:29,600 --> 01:00:35,760
write down like be disciplined and write all of 
this down like this just composes automatically.

653
01:00:35,760 --> 01:00:41,520
Uh I think that's like one of the most beautiful 
things about effect and that's really like through

654
01:00:41,520 --> 01:00:47,520
composition you can break down the complexity 
of your of your codebase. I mean yeah the agent

655
01:00:47,520 --> 01:00:52,880
was fairly uh quickly able to come up with this 
outline all by itself. I wonder if this were in

656
01:00:52,880 --> 01:00:56,960
the old style if it would have been able to figure 
out this exact structure because it's able to just

657
01:00:56,960 --> 01:01:02,480
look at these values and these types directly 
because basically every file also has I kind of

658
01:01:02,480 --> 01:01:08,080
stole this pattern from effect itself the previous 
iteration just always also exporting a default

659
01:01:08,080 --> 01:01:12,880
layer that takes the layer and just provides a 
good reasonable default. So you'll see that if

660
01:01:12,880 --> 01:01:17,120
this is imported anywhere, which I'm sure it 
is. Okay, so the server like the main server

661
01:01:17,120 --> 01:01:20,960
just imports the top level of default layers 
for everything and if and if these have other

662
01:01:20,960 --> 01:01:25,840
dependencies, they're going to depend on their 
default layers and so on transitively. So you

663
01:01:25,840 --> 01:01:30,400
don't have to provide everything. Everything 
defines a default layer and you basically just

664
01:01:30,400 --> 01:01:33,760
use those at the top of your application. And 
just to make this a bit more concrete, if you

665
01:01:33,760 --> 01:01:38,880
can go back to the place where you're constructing 
all of the the layers and compose them together,

666
01:01:38,880 --> 01:01:44,800
this is like this is probably the like routes you 
you probably instantiate somewhere and then you

667
01:01:44,800 --> 01:01:52,560
run the real thing. But let's say we're in a test 
now. You might not want to maybe use like the real

668
01:01:52,560 --> 01:02:00,240
LLM layer, but now you might want to use the the 
mock in memory LLM layer. And just by switching

669
01:02:00,240 --> 01:02:07,440
this out, like you're still satisfying that you 
need an LLM service, but now you're providing one

670
01:02:07,440 --> 01:02:13,440
that doesn't cost a gazillion dollars per run, 
but like one that you can run instantly uh while

671
01:02:13,440 --> 01:02:22,000
being offline, maybe. And this just replacing the 
need for like crazy monkey patching, etc., is like

672
01:02:22,000 --> 01:02:29,040
one of the the many killer features here. these 
data stripes I recently added to Zed uh if you

673
01:02:29,040 --> 01:02:33,360
launch OpenCode within Zed you see the selected 
line ranges down here which is kind of useful so

674
01:02:33,360 --> 01:02:38,160
you get that as context in the thing and I just 
wanted to use that new feature show it off uh

675
01:02:38,160 --> 01:02:42,880
because I'm happy about it because I use Zed and 
OpenCode all the time so I was missing this sort

676
01:02:42,880 --> 01:02:49,680
of explain the data types and how they interrelate 
um is nice because now it has the context sent

677
01:02:49,680 --> 01:02:55,280
there and it knows what I'm talking about yeah so 
now if I was confused about exactly what it would

678
01:02:55,920 --> 01:03:04,560
Okay. Uh whatever. Um it's nice. Okay. So, uh 
but yeah, so the structure of these layers is you

679
01:03:04,560 --> 01:03:08,480
yield to transitive dependencies. Then you have 
some internal helpers potentially. These are not

680
01:03:08,480 --> 01:03:16,160
part of the public API. And then I always sort of 
define the public API as Effect.fn calls. And the

681
01:03:16,160 --> 01:03:20,400
reason for this is that well you give it a nice 
little label here. This is used as a telemetry

682
01:03:20,400 --> 01:03:27,760
span. So, one of the cool things we got working in 
in OpenCode is if I go to this little local thing

683
01:03:27,760 --> 01:03:34,800
I have is I made my own little TUI for looking at 
traces called motel. Huh. Um, and so I can make

684
01:03:34,800 --> 01:03:42,080
this larger or smaller. Uh, let me make it larger. 
Yeah, let's look into this. And like before we go

685
01:03:42,080 --> 01:03:48,880
uh more into this uh just for for those who've 
like hearing about hotel or open telemetry the

686
01:03:48,880 --> 01:03:54,800
the first time it's basically if you're still 
just console logging and like you're you're tired

687
01:03:54,800 --> 01:04:01,120
of just like looking through like ton pages and 
pages of like console log like and you want a more

688
01:04:01,120 --> 01:04:06,560
structured way like typically your code runs in a 
hierarchical way and this is probably also the way

689
01:04:06,560 --> 01:04:13,440
how you're thinking about this. Uh, open telemetry 
is a like by at this point like a pretty long

690
01:04:13,440 --> 01:04:22,000
established common standard that allows you to 
define things called traces um, logs and metrics.

691
01:04:22,000 --> 01:04:28,640
Effect natively integrates with all of this and 
uh, it can be emitted anywhere. It can be uh,

692
01:04:28,640 --> 01:04:35,600
emitted into data dog or sentry or wherever like 
all of those technologies support that. But what

693
01:04:35,600 --> 01:04:41,360
Kit has built here is a version that runs 
completely locally and that gives you a much

694
01:04:41,360 --> 01:04:48,960
more intuitive way to see what has your complex 
program actually done and why is it so slow. Yeah.

695
01:04:48,960 --> 01:04:54,880
Yeah. And so one of the things obviously before 
effect that we did have some log files but lots

696
01:04:54,880 --> 01:04:59,840
of things weren't logged and you don't get spans. 
It's actually really difficult to do I think open

697
01:04:59,840 --> 01:05:04,240
telemetry integration without effect. I actually 
I guess I've never tried it before because I'd

698
01:05:04,240 --> 01:05:11,440
imagine not just only difficult it's very gross 
because you you have like the happy path. So like

699
01:05:11,440 --> 01:05:16,960
the the thing you need to care about with open 
telemetry when you want traces is you need to wrap

700
01:05:16,960 --> 01:05:23,280
everything in little things called spans and that 
then you can have like in the same way as you have

701
01:05:23,280 --> 01:05:29,360
a function and in that function you call other 
functions etc. And sometimes they run in parallel.

702
01:05:29,360 --> 01:05:34,560
Now you have a little wrapper thingy that is 
language independent that's called a span and

703
01:05:34,560 --> 01:05:40,080
where you have subspans etc. Now you need to 
basically wrap and instrument your entire code

704
01:05:40,080 --> 01:05:48,640
with like spans and that's okay for the happy path 
but you also need to consider things like error

705
01:05:48,640 --> 01:05:54,880
handling or you need to consider things such as 
like interruption etc. And this is where you just

706
01:05:54,880 --> 01:06:01,120
like keep wrapping and wrapping and wrapping your 
code until from like single beautiful functions

707
01:06:01,120 --> 01:06:09,120
you have now four layers of uh brace indentation 
and you just uh like either you regret doing this

708
01:06:09,120 --> 01:06:15,840
uh like hotel instrumentation because your code 
is like no longer readable or or you do it and

709
01:06:15,840 --> 01:06:21,520
you like you hate you hate this entire thing uh 
either way and with effect you basically get it

710
01:06:21,520 --> 01:06:26,960
for free. Yeah, all you have to do is just wrap 
your functions with Effect.fn, which is nice to do

711
01:06:26,960 --> 01:06:31,920
anyway because it it sort of is an alternative to 
the other way you would have to wrap it. I mean,

712
01:06:31,920 --> 01:06:36,240
you have to use generator functions to compose 
sequential effects anyway. So, all you have to

713
01:06:36,240 --> 01:06:41,440
do in addition to that is basically just add a 
little label here and that becomes a telemetry

714
01:06:41,440 --> 01:06:47,200
spin. You can see that they're nested because if a 
function is called if a if a annotated function is

715
01:06:47,200 --> 01:06:51,440
called within another function, they get nested 
to their current parent and so on and so forth.

716
01:06:51,440 --> 01:06:56,160
And you can see how long these uh things take. 
The prompt takes 23 seconds. Most of this time is

717
01:06:56,160 --> 01:07:01,360
waiting for the the agent to to run and therefore 
most of the other little things are done at the

718
01:07:01,360 --> 01:07:06,320
beginning and at the end of that of that run. 
So it's not terribly interesting in this case.

719
01:07:06,320 --> 01:07:11,440
Uh but it can be useful to see okay what takes 
the longest. All right snapshot our snapshotting

720
01:07:11,440 --> 01:07:16,320
takes 102 milliseconds. Is that worth looking into 
more? Like is there something that's really slow?

721
01:07:16,320 --> 01:07:22,560
I can here sort by the slowest call. So, okay. 
Why does O all take uh 800? Clearly, there's some

722
01:07:22,560 --> 01:07:27,600
kind of issue with this this uh this one because 
it takes 8,000 seconds. That's not exactly true.

723
01:07:27,600 --> 01:07:33,280
I'm sure uh span must be getting left open. But 
one cool thing is I'm I'm using this to debug

724
01:07:33,280 --> 01:07:38,640
uh OpenCode itself. So, every instance I start 
locally connects to that local telemetry store

725
01:07:38,640 --> 01:07:44,720
which is this is like totally written in effect 
in Typescript and is all local data. uh and

726
01:07:44,720 --> 01:07:50,400
it's using open tui which uh is the ti framework 
written in typescript that OpenCode uses lots of

727
01:07:50,400 --> 01:07:57,360
dog fooding going on so honeym uh a great codebase 
to also check out if you want to build your own

728
01:07:57,360 --> 01:08:05,600
like effectbased CLI effect has a great way to to 
write CLIs integrating that with a complex system

729
01:08:05,600 --> 01:08:14,400
like uh open toy uh open toy open ti open that 
works yeah open whatever and then also connecting

730
01:08:14,400 --> 01:08:20,960
it with like the way how you do state management 
uh in in effect apps which I suppose you're using

731
01:08:20,960 --> 01:08:26,720
effect atom for this uh for for this I am yeah 
I've yet to get to the front end the TUI front

732
01:08:26,720 --> 01:08:32,160
end in OpenCode but maybe but one day I'd like to 
do this once the back end is all clean up but yeah

733
01:08:32,160 --> 01:08:37,120
I think this is using effect atom yeah um it is 
partially vivecoded this of course so I wouldn't

734
01:08:37,120 --> 01:08:43,760
necessarily use this as a a shining example but 
um it does work which is nice so one of the Cool

735
01:08:43,760 --> 01:08:48,080
things as well is that if you're running locally, 
so not in production, you get this uh this session

736
01:08:48,080 --> 01:08:54,240
ID. So if I want to debug this very session, I 
can go here and filter by any sort of attribute

737
01:08:54,240 --> 01:09:00,000
key. So I can find session ID and paste this in. 
And we see there there are five spans for it. And

738
01:09:00,000 --> 01:09:05,840
then theoretically in here I might I might be able 
to find something like a question like let me look

739
01:09:05,840 --> 01:09:13,520
for ask eight matches. Oh yeah, there's question 
ask. So I did ask twice. Where did ask? And just

740
01:09:13,520 --> 01:09:22,400
to uh explain uh what what's going on here, we we 
were looking at that like effect code for that ask

741
01:09:22,400 --> 01:09:29,040
questions form module in OpenCode and we've used 
it before. We filled out like some example data

742
01:09:29,040 --> 01:09:37,200
for for that and uh that code has run and like in 
traditional system you might have like maybe some

743
01:09:37,200 --> 01:09:44,400
log output in a in a console somewhere uh but like 
then that quickly turns into hundreds t thousands

744
01:09:44,400 --> 01:09:50,320
tens of thousands of of lines and you're just 
maybe command effing through that but that gets uh

745
01:09:50,320 --> 01:09:56,320
very boring very quickly. you probably don't have 
like timing information in there. And here we're

746
01:09:56,320 --> 01:10:03,360
like looking at something that is like immediately 
intuitive. Like we immediately understand where

747
01:10:03,360 --> 01:10:11,520
uh like time was spent and at every span that 
we focus on, we now have like some contextually

748
01:10:11,520 --> 01:10:17,840
enriched data called span attributes that is 
relevant for for this particular span if we

749
01:10:17,840 --> 01:10:21,440
choose to instrument it like this. Yeah, I should 
probably add some more attributes for question

750
01:10:21,440 --> 01:10:26,640
ask because we don't see the questions here, but 
that's that's that's trivially uh addressable. Um,

751
01:10:26,640 --> 01:10:31,440
one of one thing that obviously might be striking 
is that this took 228 seconds, but that's not

752
01:10:31,440 --> 01:10:37,120
a problem actually because if you look at 
the implementation here, what ask is called

753
01:10:37,120 --> 01:10:44,240
being slow. Yeah, it was me. It was me taking 228 
seconds to finally answer the these questions. Um,

754
01:10:44,240 --> 01:10:47,520
which is interesting because it it shows off a 
little bit of the effect concurrency primitives

755
01:10:47,520 --> 01:10:51,680
that we're using in here. uh like this isn't 
problem. This isn't blocking anybody. This is

756
01:10:51,680 --> 01:10:58,640
just me semantically blocking uh and and not and 
taking a little while to resolve this uh deferred

757
01:10:58,640 --> 01:11:03,040
um that was going to be done by me finally hitting 
submit on those three questions. We'll see that

758
01:11:03,040 --> 01:11:08,480
it's called question.ask is called inside of tool 
execute which is called in session prompt resolve

759
01:11:08,480 --> 01:11:14,960
tools which is eventually called in session prompt 
uh run. So if I just close this and we we can just

760
01:11:14,960 --> 01:11:19,840
briefly look at the implementation here. I'll try 
to do my best to paint a picture. So we have this

761
01:11:19,840 --> 01:11:24,640
question.ask function which is annotated labeled 
which is sort of trivially becoming that span

762
01:11:24,640 --> 01:11:30,720
which just works with any open telemetry provider 
including my vibecoded semi vibecoded uh TUI

763
01:11:30,720 --> 01:11:35,280
version. Then uh this takes session ID a set of 
questions and a tool. So these are basically the

764
01:11:35,280 --> 01:11:39,520
questions that the agent asks. So this was parsed 
from the agent's JSON response and it's passed

765
01:11:39,520 --> 01:11:45,760
into this function. And then there's this tool ID 
so we know what tool it it resolved to. And then

766
01:11:45,760 --> 01:11:50,480
uh pending pending pending. So yeah, we have this 
it's a little interesting. I made this instance

767
01:11:50,480 --> 01:11:55,120
state abstraction. This is probably one of the 
more complicated bespoke abstractions used inside

768
01:11:55,120 --> 01:12:00,560
of the OpenCode codebase because OpenCode is 
that server and there might be multiple parallel

769
01:12:00,560 --> 01:12:06,000
sessions going on uh in multiple projects in 
multiple folders and we wouldn't for various

770
01:12:06,000 --> 01:12:11,280
reasons we want each sort of folder to manage its 
own state. So when you kill that session we can

771
01:12:11,280 --> 01:12:17,600
release all of that state. So this instance state 
thing is basically keyed by the current implicit

772
01:12:17,600 --> 01:12:24,160
session. So each session can store its own list 
of pending questions basically and the pending

773
01:12:24,160 --> 01:12:29,440
entry is this. It's a particular request and 
there's this deferred abstraction and a deferred

774
01:12:29,440 --> 01:12:35,120
abstraction is part of effect. It's very nice uh 
very useful for these kinds of interactions which

775
01:12:35,120 --> 01:12:40,240
it's something that you can create and it's 
a value that you can manually either cause to

776
01:12:40,240 --> 01:12:46,000
succeed or cause to fail later on. It's kind of 
similar to how a promise works actually um except

777
01:12:46,000 --> 01:12:51,680
promise doesn't by default let you outside of 
the thing complete it or resolve it. But anyway,

778
01:12:51,680 --> 01:12:55,920
so it's this value you get that you could store 
off and later on complete it with a value. So it's

779
01:12:55,920 --> 01:13:00,800
really good for these kind of messaging systems 
where the agent wants to ask the user a question

780
01:13:00,800 --> 01:13:05,600
and then it wants to wait for the user to answer 
it. So where this is called it's basically we call

781
01:13:05,600 --> 01:13:11,680
the tool execute calls ask and then it it makes 
this new deferred which is either going to succeed

782
01:13:11,680 --> 01:13:18,240
with a list of answers that the user selected or 
it's going to fail with a rejection error. So this

783
01:13:18,240 --> 01:13:22,480
already like I kind of was forgetting what this 
did because I worked on this forever ago. But once

784
01:13:22,480 --> 01:13:26,320
again nice types. These aren't just strings. These 
are nicely named types. It's like a read only

785
01:13:26,320 --> 01:13:30,960
array of answers or it fails. And the other thing 
is that effect obviously lets you signify how

786
01:13:30,960 --> 01:13:35,360
something might fail which is not sort of implicit 
in promised land. You don't know. You have to look

787
01:13:35,360 --> 01:13:38,720
at the values. Here I can just look at the types 
and say oh yeah this makes a lot of sense. The

788
01:13:38,720 --> 01:13:43,520
user either responds or they reject they hit 
escape and they cancel the question and they're

789
01:13:43,520 --> 01:13:49,520
like I don't want to answer any of your questions 
robot. So this is really good as documentation.

790
01:13:49,520 --> 01:13:55,600
And then we basically publish this uh event asked 
info question which will get sent to the TUI uh

791
01:13:55,600 --> 01:14:00,480
so it knows that it's waiting on these questions 
and we update this local state um basically saying

792
01:14:00,480 --> 01:14:07,360
that question ID is is has this deferred in it 
and when the user eventually replies to a question

793
01:14:07,360 --> 01:14:13,600
with a particular question ID here we can get 
that state for this instance get get the existing

794
01:14:13,600 --> 01:14:19,280
question and if there isn't one it'll it'll just 
fail uh it'll it'll short circuit but if there is

795
01:14:19,280 --> 01:14:24,480
a question that it found, it'll delete it from 
the pending set and it will publish the set of

796
01:14:24,480 --> 01:14:30,000
answers and then it will succeed the deferred. 
And by succeeding this deferred value, it allows

797
01:14:30,000 --> 01:14:36,720
this bit which was waiting on for 228 seconds or 
something to finally resolve with that success.

798
01:14:36,720 --> 01:14:41,760
So it depends on how this def it's awaiting this 
deferred. And so uh it's going to semantically

799
01:14:41,760 --> 01:14:47,440
block here whatever code is calling this will 
semantically wait until this deferred is either

800
01:14:47,440 --> 01:14:53,040
completed or or rejected. And I think there's a 
reject method as well which will find that same

801
01:14:53,040 --> 01:14:58,080
question and then call fail with a rejected error. 
And of course this is type safe like I cannot just

802
01:14:58,080 --> 01:15:05,200
fail with any error here because if I change this 
I believe this will cause yeah an error because uh

803
01:15:05,200 --> 01:15:10,800
this deferred has to fail with rejected error not 
with error. So it's it's all really damn nice. You

804
01:15:10,800 --> 01:15:14,720
can't like you can't get it wrong. Uh it's nice to 
be constrained in these ways. I can come back and

805
01:15:14,720 --> 01:15:19,760
look at this after I think I did this three months 
ago and sort of piece together what it does again

806
01:15:19,760 --> 01:15:29,520
uh live. And I think what is particularly nice 
is how it's all scoped locally. Like this is not

807
01:15:29,520 --> 01:15:36,880
too large that uh we could still wrap our head 
around now walking through this as most of us

808
01:15:36,880 --> 01:15:42,720
are not working on the OpenCode codebase and are 
not familiar with it. Yet looking at this like we

809
01:15:42,720 --> 01:15:49,760
we can grasp it. It fits in our in into our head 
and yet it's like a a non-trivial um complexity

810
01:15:49,760 --> 01:15:57,840
amount with like all those different cases but it 
is all locally scoped and like we can just compose

811
01:15:57,840 --> 01:16:03,680
it like in the in the overall application and it 
doesn't leak out that complexity throughout the

812
01:16:03,680 --> 01:16:10,640
entire codebase presumably but it's all contained 
here in the same way as if I'm thinking on a on a

813
01:16:10,640 --> 01:16:15,840
high level building something like OpenCode 
there's at some point there's a little thing

814
01:16:15,840 --> 01:16:20,960
that's responsible for for questions and then 
that's resolved and it get that gets out of the

815
01:16:20,960 --> 01:16:26,880
way and I think that maps really nicely to to 
the code where I like this distinction between

816
01:16:26,880 --> 01:16:33,520
existential complexity and exist existential 
complexity where existential complexity is

817
01:16:33,520 --> 01:16:38,480
like all the things that you actually need to 
build your app that's the good stuff accidental

818
01:16:38,480 --> 01:16:44,800
complexity is like that everything additionally 
gets more complex without adding any benefits to

819
01:16:44,800 --> 01:16:51,120
your to your app and like that you want to have as 
little as possible and I think effect allows us to

820
01:16:51,120 --> 01:16:58,400
to express that at the at like just the right uh 
cut off point. I certainly think so. I would like

821
01:16:58,400 --> 01:17:05,680
to shift the topic slightly from like so far we've 
been looking at code kind of like the the old way

822
01:17:05,680 --> 01:17:11,440
uh as we've been writing and reading code etc. 
And I think that's still important like whatever

823
01:17:11,440 --> 01:17:21,200
um someone else or an agent etc is writing I think 
us as engineers we should still be able to somehow

824
01:17:21,200 --> 01:17:27,760
load that in our head and make sense of it and 
ideally even be able to judge it whether can it

825
01:17:27,760 --> 01:17:35,040
be improved is it good enough does it solve the 
problem etc. Um and uh Kit is having fun over

826
01:17:35,040 --> 01:17:41,280
here with like uh with a vim mode in in Zed. Um 
and I think it's certainly still worthwhile today

827
01:17:41,280 --> 01:17:48,640
to to learn vim as that as that's that little 
uh anecdote. But um what I'm curious about is

828
01:17:48,640 --> 01:17:55,920
if we're now allowing ourselves to switch into 
like a fully AI pilled perspective where truth

829
01:17:55,920 --> 01:18:04,400
be told I have written the last line of code uh 
me personally in October last year 2025. So since

830
01:18:04,400 --> 01:18:11,920
then every line of code that uh I've shipped 
um I have had done by an agent. So, uh, I've

831
01:18:11,920 --> 01:18:18,400
made the full hard switch and it's been great. 
It doesn't mean that I don't read any lines of

832
01:18:18,400 --> 01:18:25,920
code anymore. Quite the opposite. Uh, and I'm more 
thankful than ever for effect because it allows me

833
01:18:25,920 --> 01:18:32,800
to review in a much higher level whether whatever 
was produced here is actually good or not. And I'm

834
01:18:32,800 --> 01:18:41,520
also very glad that I've had like years and years 
of prior hard work by hand experience uh writing

835
01:18:41,520 --> 01:18:48,240
all of this by myself. So I know what uh good or 
worse looks like at least judging based on my own

836
01:18:48,240 --> 01:18:56,400
standards. Um and uh I think that is just becoming 
increasingly the the new reality. like not

837
01:18:56,400 --> 01:19:02,800
everyone has has to go like all the way over there 
yet. But I do think it's the new reality that

838
01:19:02,800 --> 01:19:09,280
it's not just effect being an important thing for 
humans to decide for like hey are we using this as

839
01:19:09,280 --> 01:19:16,560
a team or not but it also plays a big role where 
the agents are uh successful with it or not. So I

840
01:19:16,560 --> 01:19:21,200
would like to hand back two questions to you like 
how much code are you still writing by yourself by

841
01:19:21,200 --> 01:19:29,920
hand versus with coding agents working on a coding 
agent? Um and what is your perspective on whether

842
01:19:29,920 --> 01:19:36,640
effect is an advantage or a disadvantage for 
coding agents? Yeah. Yeah. Um yeah it's a tr it's

843
01:19:36,640 --> 01:19:43,120
a tricky question but I'll start by just answering 
it honestly which is that uh yeah mostly dictating

844
01:19:43,120 --> 01:19:49,760
to the agent to write the code for me even in 
such uh sort of um embarrassing circumstances

845
01:19:49,760 --> 01:19:56,240
as like you know rename that variable or add a 
parenthesy to line you know column 18 on line

846
01:19:56,240 --> 01:20:01,920
149 or something like this. Uh so one thing I do 
all the time is I I made my own open source uh

847
01:20:01,920 --> 01:20:10,240
hex.kitlangton.com. Uh what is this? Uh uh I type 
that out though. Um it is sad to see my skills

848
01:20:10,240 --> 01:20:14,720
slightly slightly. It like I miss it especially in 
these contexts. I I used to do these like weekly

849
01:20:14,720 --> 01:20:18,960
when I worked in the Zo world, these weekly videos 
where I do a bunch of live coding and it was super

850
01:20:18,960 --> 01:20:24,480
fun and I knew all the tricks and JetBrains 
and all the refactoring shortcuts uh and and

851
01:20:24,480 --> 01:20:30,640
took great pride in my Vim skills and and I I you 
know have a Dvorak keyboard layout. I went fully

852
01:20:30,640 --> 01:20:36,720
uh you know keyboard lifestyle, but of course a 
split keyboard these days. Yeah. I got my weird

853
01:20:36,720 --> 01:20:42,880
my weird uh double halved uh broken in half. Uh it 
doesn't even have labels on the keys which is Oh

854
01:20:42,880 --> 01:20:48,640
yeah. Uh which uh impresses no one because no one 
sees it except for my wife who's not impressed by.

855
01:20:48,640 --> 01:20:54,000
And also once in a while if I like need to figure 
out how to do something uh with the keyboard like

856
01:20:54,000 --> 01:20:58,000
it doesn't pair with Bluetooth, I need to look at 
the manual and it's like oh just hit command shift

857
01:20:58,000 --> 01:21:03,360
option P. I'm like okay but where's the where's 
which one's the command key or which one's the

858
01:21:03,360 --> 01:21:08,000
meta key? So I have to pull up the the di anyway. 
It's very embarrassing in those moments. Um what

859
01:21:08,000 --> 01:21:13,520
was I saying? Oh yeah. So I I'm very sad to admit 
that most of the time I dictate. So I mean there's

860
01:21:13,520 --> 01:21:17,440
tons of apps that do this. There's another good 
open source one called Handy. I made one called

861
01:21:17,440 --> 01:21:23,600
hex just to fulfill my own specific needs and 
desires where I just like basically let's say

862
01:21:23,600 --> 01:21:28,640
hey can you delete all the comments I added in 
this file please uh I want to restore this file

863
01:21:28,640 --> 01:21:34,560
and so I'll just do that yeah yeah it's super fast 
it use it's not me it's it uses a parakeet v2 from

864
01:21:34,560 --> 01:21:40,480
it's an Nvidia text to speech to text model and 
there it goes it left some new lines in whatever

865
01:21:40,480 --> 01:21:44,960
you know I'll and and with this newfound ability 
to know what line I'm selecting I could just sort

866
01:21:44,960 --> 01:21:49,200
of purely with Vim I don't know why I clicked I 
can just navigate between these windows, go to

867
01:21:49,200 --> 01:21:54,320
line 135, select this, go back here, hit option 
and say, "Hey, let's rename the bus variable to

868
01:21:54,320 --> 01:22:00,000
uh vehicle and it'll do that for me." And then 
while it's doing that, I'll, you know, be able to

869
01:22:00,000 --> 01:22:07,840
look around at some other things, and it'll make 
the change. Uh, so yeah, like, okay, maybe I could

870
01:22:07,840 --> 01:22:14,320
have actually sometimes for renames I will use my 
let me make that back to bus using this trick. Uh

871
01:22:14,320 --> 01:22:20,240
but really if if sometimes there are consequences 
of renaming things where you have to also update

872
01:22:20,240 --> 01:22:26,000
it in a comment that the renamer doesn't catch. 
So yeah for efficiency sake I end up do just

873
01:22:26,000 --> 01:22:31,440
dictating everything. If if you do not yet dictate 
I highly recommend dictating because there is some

874
01:22:31,440 --> 01:22:36,320
friction with typing like I did my I did my monkey 
type. I have at my peak I had a pretty good words

875
01:22:36,320 --> 01:22:41,280
per minute. I'm sure that's atrophied somewhat 
embarrassingly now and I have more typos. Luckily,

876
01:22:41,280 --> 01:22:50,160
agents don't really care about typos. So, you 
can type like an idiot and it'll figure out

877
01:22:50,160 --> 01:22:57,600
what you're saying. Uh, what did I just say? Um, 
and so like you can just degrade even more even by

878
01:22:57,600 --> 01:23:01,360
typing yourself. But there's there's a bit of 
a friction there to just typing. Like it took

879
01:23:01,360 --> 01:23:06,640
me way slower to type that. I didn't actually 
Oh, I did say it still understands I think. Um,

880
01:23:06,640 --> 01:23:11,600
I don't even how did it know that that I didn't 
Anyway, I thought it was just devolved into just

881
01:23:11,600 --> 01:23:14,640
random letters at that point, but maybe it 
just autocompleted the obvious intention of

882
01:23:14,640 --> 01:23:19,920
it. [laughter] Uh, and nonetheless, agents don't 
really care about typos. They can so you can type

883
01:23:19,920 --> 01:23:26,320
like an idiot. It still understands. Uh, yes. 
Um, and even there even some dictation typos,

884
01:23:26,320 --> 01:23:30,560
if you will, uh, misunderstandings, but it doesn't 
matter. The agents get it. Even if you dictate one

885
01:23:30,560 --> 01:23:35,440
thing and it it doesn't understand how to say, 
you know, two, okay, you know, two weeks. It's

886
01:23:35,440 --> 01:23:41,280
not two weeks instead of two, but if I say I'm 
working on an agentic 2. What do you think? Um,

887
01:23:41,280 --> 01:23:46,000
okay. Agentic UI. Okay, fine. So, it'll figure 
it out. And if you're in the right context,

888
01:23:46,000 --> 01:23:50,720
it doesn't even really matter. So, you can 
just quickly brain dump so much more context

889
01:23:50,720 --> 01:23:55,280
verbally than you could u bottleneck through, 
you know, your your digits. As fun as typing is,

890
01:23:55,280 --> 01:24:00,560
as much as I miss the experience and the time 
where that was a sort of a differentiator, I I

891
01:24:00,560 --> 01:24:07,840
can just brain dump and and and it I tend to have 
better results. I I will sort of secretly subtly

892
01:24:07,840 --> 01:24:13,360
uh not encode as much of what I'm thinking if I'm 
typing because I'm I'm it takes too long and I'm

893
01:24:13,360 --> 01:24:18,800
lazy. So, it might be it'll it'll be misspelled 
anyway because my typing is atrophied. So, highly

894
01:24:18,800 --> 01:24:24,160
recommend dictating. That's so that's kind of my 
answer. I mostly dictating to an OpenCode agent

895
01:24:24,160 --> 01:24:29,520
or multiple OpenCode agents. I I like to use tabs 
and have multiple in this project. Another thing

896
01:24:29,520 --> 01:24:35,680
I've been doing lately um is having it create work 
trees for different uh right lines of work. Like

897
01:24:35,680 --> 01:24:41,040
if I have a refactoring that spans multiple files, 
I'll just tell OpenCode to create a bunch of work

898
01:24:41,040 --> 01:24:45,040
trees. And it doesn't need any special feature 
for that. It can just create a git work tree,

899
01:24:45,040 --> 01:24:49,120
CD into that directory, and then work there. 
And then I have it open up a pull request and

900
01:24:49,120 --> 01:24:54,560
then I look at that in the browser. So you know 
make a new work tree where you rename the const

901
01:24:54,560 --> 01:25:01,920
bus. Select this line here to vehicle and open 
up a pull request. Yeah. And then open that pull

902
01:25:01,920 --> 01:25:06,640
request in my browser. So maybe I'll do something 
like that except with an actual uh work task. And

903
01:25:06,640 --> 01:25:11,840
then we'll see that it is going to you know make 
some to-dos. Okay. So do some [ __ ] So that

904
01:25:11,840 --> 01:25:18,880
that gives us a pretty good sense of your current 
workflow. um as it relates to effect, how do you

905
01:25:18,880 --> 01:25:28,720
think using coding agents etc. um how does that 
compare to working in a completely uneffectified

906
01:25:28,720 --> 01:25:36,720
codebase? Do you have any comparison there uh or 
any intuition? I mean unfortunately or fortunately

907
01:25:36,720 --> 01:25:41,360
for myself I've been so thoroughly effectilled 
for so long that I haven't really worked on a

908
01:25:41,360 --> 01:25:46,960
non-effect codebase in a while. But I I mean I was 
already once again like horrified and recoiled and

909
01:25:46,960 --> 01:25:52,240
in terror to work on them before agents just for 
my own productivity. Oh, something that I I that

910
01:25:52,240 --> 01:25:57,280
slipped my mind earlier which uh when talking 
about the nice constraints of these things is

911
01:25:57,280 --> 01:26:03,360
that if you do not have the constraints of of a 
type system just like sort of that sort of subtle

912
01:26:03,360 --> 01:26:07,920
uh pernitious tendency to when typing anytimes 
there's friction like we're really lazy creatures

913
01:26:07,920 --> 01:26:12,640
right we're trying to preserve energy all the 
time it takes a lot of effort to to to be less

914
01:26:12,640 --> 01:26:18,720
lazy um convenience sort of trumps everything we 
we will express less now okay just open up the PR

915
01:26:18,720 --> 01:26:23,520
for the bus rename there it's very bus binding 
is open. So I then would like open up the tab

916
01:26:23,520 --> 01:26:27,760
here and review it. Maybe I can leave comments and 
then have the agent look at the comments. So I'll

917
01:26:27,760 --> 01:26:31,280
say in here I'll dictate what have you done? Why 
did you rename this? I don't want you to do this

918
01:26:31,280 --> 01:26:36,240
at all. Actually close everything. Um so I'll add 
that comment and then I will say read the comment

919
01:26:36,240 --> 01:26:42,960
I left and uh fulfill it. Anyway, it'll do that in 
the background. So just as uh if by dictating I'm

920
01:26:42,960 --> 01:26:48,320
able to uh I just naturally end up being more 
encompassing with all of my thoughts and I and

921
01:26:48,320 --> 01:26:52,640
I don't sort of drop them on the floor because 
I'm bottlenecked by my typing speed. Similarly,

922
01:26:52,640 --> 01:26:57,200
if it is difficult to refactor a codebase, which 
it is if it's dynamically typed, you will just

923
01:26:57,200 --> 01:27:00,480
simply refactor less. You might not think that 
you're avoiding refactoring, but it's it's a pain

924
01:27:00,480 --> 01:27:05,840
in the butt and it's very scary. At least speaking 
for me, maybe some people do love it. Obviously,

925
01:27:05,840 --> 01:27:11,760
DHH loves Ruby on Rails and I I get it. Like 
there's some beauty there, but for me personally,

926
01:27:11,760 --> 01:27:15,200
that scares the big Jesus out of me. I just simply 
wouldn't refactor it very much. I'd maybe like

927
01:27:15,200 --> 01:27:20,800
create a whole new codebase. And if you're not 
refactoring, like why do I refactor? I refactor

928
01:27:20,800 --> 01:27:25,760
because I learned something about the code, about 
the problem space while I'm working on it. And

929
01:27:25,760 --> 01:27:29,360
I want to encode that. I want to encode that 
constraint in the type system and the structure

930
01:27:29,360 --> 01:27:34,160
of my code. I want to delete redundancies, sort of 
collapse duplication into better abstractions. And

931
01:27:34,160 --> 01:27:40,880
I'm able to do that fearlessly with the backing 
of a type system doubly triply so with a library

932
01:27:40,880 --> 01:27:44,960
like effect which allows me to encode even more in 
the type system and have even more constraints. So

933
01:27:44,960 --> 01:27:49,680
I I end up refactoring more and I end up making 
more beautiful codebases. So I think that just

934
01:27:49,680 --> 01:27:54,240
becomes easier to work on these codebases anyway 
because they're better factored and they better

935
01:27:54,240 --> 01:27:59,440
express the domain and I can make them regular. 
I can refactor so I can shape things similarly

936
01:27:59,440 --> 01:28:04,240
without fear. And the more things are consistent, 
the easier it is for an agent to extrapolate on

937
01:28:04,240 --> 01:28:09,200
those patterns just as it was easier for me to 
extrapolate on patterns or like a newcomer like

938
01:28:09,200 --> 01:28:14,480
because you can also think of a of an agent as a 
fresh really smart fresh hire who already knows

939
01:28:14,480 --> 01:28:19,760
about you know every library in existence. But if 
your codebase is a mishmash of different patterns,

940
01:28:19,760 --> 01:28:23,680
how would a new how would like a day one like 
they're always sort of spawned into existence the

941
01:28:23,680 --> 01:28:30,400
second you have a fresh session. I mean whatever 
module your agents.md files uh how well are they

942
01:28:30,400 --> 01:28:34,080
going to be able to perform the implicit 
context of your entire codebase will guide

943
01:28:34,080 --> 01:28:39,200
them even more than the agents files. So yeah, 
it's it's easier to in a library like effect,

944
01:28:39,200 --> 01:28:43,120
it's easier to refactor. Therefore, it's easier 
to maintain a higher quality codebase that is sort

945
01:28:43,120 --> 01:28:47,680
of made consistent and then agents will sort of 
extrapolate on that better. And because of this,

946
01:28:47,680 --> 01:28:51,360
the regularity, the self similarity, the fact that 
each of these files look the same, I could open up

947
01:28:51,360 --> 01:28:58,400
five parallel PRs, something basic obviously, 
and I could sort of scan over it and just the

948
01:28:58,400 --> 01:29:03,280
patterns if there is an aberration, an anomaly if 
you will, that'll become that'll be immediately

949
01:29:03,280 --> 01:29:08,240
evident just by almost the structure of the 
code itself. Like one thing I can do is let's

950
01:29:08,240 --> 01:29:14,400
say in here like I I can start from the interface 
basically. I can have a uh I can make it sort of

951
01:29:14,400 --> 01:29:20,720
a to-do interface and and I can I can hand type 
this if I feel like hand typing it. I could I'm

952
01:29:20,720 --> 01:29:26,560
at this point sometimes I actually do mistyping 
because uh and I try to do a little bit to b make

953
01:29:26,560 --> 01:29:30,960
asy diagrams. You saw me do a little bit of that 
during this this uh this this talk. I used to do

954
01:29:30,960 --> 01:29:36,960
this a lot when I was doing live coding. it it can 
be even more compact sometimes to express things

955
01:29:36,960 --> 01:29:42,400
diagrammatically in in you know ASCII. So I might 
just be able to say like okay what what do I want?

956
01:29:42,400 --> 01:29:49,680
I want a create to-do I want a list and I want a 
toggle to-do method. So I could do that here or I

957
01:29:49,680 --> 01:29:54,560
could describe it as the interface. Sorry. No, the 
way how I think about it is like whatever is like

958
01:29:54,560 --> 01:30:01,760
the highest signal noise ratio that you can sort 
of like give as intent to the agent like just use

959
01:30:01,760 --> 01:30:07,200
that. Sometimes it is like you copy pasting like 
the old code and the new code you know exactly

960
01:30:07,200 --> 01:30:12,400
how you want the new code to be then just write 
it out paste it in say like hey let's make this

961
01:30:12,400 --> 01:30:19,600
happen everywhere consistently. Uh, and sometimes 
it's like a little uh like a little scribble on

962
01:30:19,600 --> 01:30:25,200
like a piece of paper and like I airdrop the the 
picture into the coding agent and say like, "Hey,

963
01:30:25,200 --> 01:30:29,760
have this idea for this better architecture. What 
do you think?" And like whatever is like the the

964
01:30:29,760 --> 01:30:37,440
best signal like I I think the the mental model 
I like is what if you would uh show something to

965
01:30:37,440 --> 01:30:41,760
your like favorite colleague who's like very 
experienced like immediately gets everything

966
01:30:41,760 --> 01:30:48,000
without you having to explain everything. and you 
what is the thing you tell them and I think that

967
01:30:48,000 --> 01:30:55,200
works pretty well for for coding agents and uh 
that I I love the the idea of like doing something

968
01:30:55,200 --> 01:31:02,400
at a speed of thought and I think now we now we 
can yeah it's it's uh it's pretty fun obviously

969
01:31:02,400 --> 01:31:07,440
they can go off the rails and do all sorts of 
crazy things so like I don't foresee myself being

970
01:31:07,440 --> 01:31:12,160
taken out of a job anytime soon but I can I can 
definitely by using them often you get a sense of

971
01:31:12,160 --> 01:31:15,120
what their limits are and those bound boundaries 
are always shifting. I mean, I've been using

972
01:31:15,120 --> 01:31:19,760
them maximally since they first came out and you 
know, the first version of it was called Codeex,

973
01:31:19,760 --> 01:31:24,000
right? The autocomplete model and I ran it in 
Jetbrains. I was doing some pretty complicated

974
01:31:24,000 --> 01:31:30,240
type level stuff in Scala and it it it was able 
to extrapolate and like auto I could tab complete

975
01:31:30,240 --> 01:31:34,880
and it would do the next arity of the the method 
or whatever or it would it would it would fulfill

976
01:31:34,880 --> 01:31:39,520
some pretty interesting patterns that weren't 
just boilerplate. So I think I think there is

977
01:31:39,520 --> 01:31:43,040
something about the models where they are really 
good at logic programming and and these kinds of

978
01:31:43,040 --> 01:31:47,440
sort of mathematical patterns and they deal well 
with types right I mean because whatever the curry

979
01:31:47,440 --> 01:31:52,800
Howard isomeorphism types are logic etc. They seem 
to be pretty good at this at this domain. Uh and

980
01:31:52,800 --> 01:31:59,840
my experience has borne that out. So so yeah what 
I might do in this case is just yeah let me let me

981
01:31:59,840 --> 01:32:03,680
uh maybe I would have just dictated this to make a 
new effect to do interface. But sometimes it could

982
01:32:03,680 --> 01:32:07,600
be fun if I do want to be very specific. I could 
do this iteratively like now that I have this

983
01:32:07,600 --> 01:32:12,640
file I could say um just turn these into actual 
functions on the interface please uh effectful

984
01:32:12,640 --> 01:32:18,160
functions and we'll see what it does. Uh it should 
be able to do this pretty quickly and then once it

985
01:32:18,160 --> 01:32:23,200
does uh yeah maybe it'll look at other files. Oh 
it's it's loading my whole effect skill because I

986
01:32:23,200 --> 01:32:27,680
do have an effect skill that tells it to look at 
the effect. Speaking of that effect skill is that

987
01:32:27,680 --> 01:32:32,080
public? So this there is one in the codebase 
that it found actually if I go to effect seal

988
01:32:32,080 --> 01:32:37,280
and it's very basic and it just basically says do 
clone. So obviously I'm sure you've mentioned this

989
01:32:37,280 --> 01:32:43,920
trick before in this podcast but if not clone 
the effect v4 I'm using effect v4 in here. So

990
01:32:43,920 --> 01:32:50,640
that's effect small uh under the effect-ts uh or 
clone that somewhere and just tell the agent to

991
01:32:50,640 --> 01:32:56,320
look at it. Right. Yeah. I I [clears throat] think 
that's one of the most reliable patterns not just

992
01:32:56,320 --> 01:33:05,360
for effect but for like any uh any technology that 
the coding agents might not be like born with yet.

993
01:33:05,360 --> 01:33:13,440
And I I think that's that's a great uh a great 
concept or a great method to embrace. However,

994
01:33:13,440 --> 01:33:22,480
I do think that it's still worthwhile pairing that 
with a skill um particularly to show very specific

995
01:33:22,480 --> 01:33:31,440
usage oriented patterns and maybe your preferences 
since like effect is uh such a wide ecosystem.

996
01:33:31,440 --> 01:33:35,920
Sometimes there's multiple ways to do the same 
thing. So for example, if you want to build an

997
01:33:35,920 --> 01:33:44,640
HTTP API, you could do it over RP over effect RPC. 
You could do it over the effect HTTP API module.

998
01:33:44,640 --> 01:33:51,200
You can also do it like more lowle. And maybe you 
have certain preferences for your codebase. So I

999
01:33:51,200 --> 01:33:57,680
think being in the effect skill being it making 
it more yours being more specific about like

1000
01:33:57,680 --> 01:34:04,320
hey other people might be doing this but we we're 
doing this here like writing this out concisely.

1001
01:34:04,320 --> 01:34:09,760
I've had good success with in for for the for 
my own effect skill. Yeah it's not it's not

1002
01:34:09,760 --> 01:34:13,520
we don't do anything too complicated. It's mostly 
like agents files. I think the skill was recently

1003
01:34:13,520 --> 01:34:20,080
added. Um in the agents file I do have some 
basic things like use Effect.gen use Effect.fn

1004
01:34:21,840 --> 01:34:27,360
etc. Like use date time instead of new date. 
There's some basic things, right? If if you see

1005
01:34:27,360 --> 01:34:31,200
the agent making a mistake a bunch of times, just 
throw it in your agents file or ask an agent to

1006
01:34:31,200 --> 01:34:36,640
make that change. May maybe one other topic before 
closing out. You've mentioned that you're using

1007
01:34:36,640 --> 01:34:43,520
uh effect 4 or effect small as it started and 
still called this way at least of as of today. Um,

1008
01:34:43,520 --> 01:34:50,000
did you start the migration with effect 4 right 
away or did you start with effect three and like

1009
01:34:50,000 --> 01:34:57,840
upgrade it to effect 4 at some point? No, I I you 
know laser less rule. I just I just went with it

1010
01:34:57,840 --> 01:35:02,480
um the the beta version. I think I asked Dax, oh, 
you know, it was it was still pretty early on, so

1011
01:35:02,480 --> 01:35:06,640
I was afraid. I'm like, uh, there's a beta version 
that just came out. Should uh I can use the old

1012
01:35:06,640 --> 01:35:11,520
version. What what would make you feel the safest? 
And Dax did not uh did not flinch. was like,

1013
01:35:11,520 --> 01:35:16,640
"Yeah, just use the use the beta version." What's 
your experience with Effect 4 at this point? Or

1014
01:35:16,640 --> 01:35:21,680
do don't you really have like too many reference 
points to to the old version? It's it's I mean,

1015
01:35:21,680 --> 01:35:25,760
the agents do great. Um I think there were a 
couple of naming flips that went back and forth.

1016
01:35:25,760 --> 01:35:30,880
The like everything just works so well. I forget 
what really ch it's pretty seamless. Obviously,

1017
01:35:30,880 --> 01:35:38,640
the bundle size has been improved. Tree shaking 
is improved. Uh schema is improved. But so so

1018
01:35:38,640 --> 01:35:44,400
far pretty seamless. I like Context.Service. 
I use that all the time. Uh it's better than

1019
01:35:44,400 --> 01:35:49,040
what was it before? Context.key, I think, or 
context. I think it was Context.Tag was before

1020
01:35:49,040 --> 01:35:55,920
and effect. Yeah. Finally, we're we're we're 
going to simplify things. Yeah. I think this

1021
01:35:55,920 --> 01:35:59,600
is temporarily service map, but got shifted back 
to context, which is great because that's that's

1022
01:35:59,600 --> 01:36:04,560
a good metaphor from the React world for how these 
things propagate. Um I wouldn't even mind somehow

1023
01:36:04,560 --> 01:36:10,080
magically having it be service, but this is fine 
or effect. Uh yeah. No, I mean it's barely noticed

1024
01:36:10,080 --> 01:36:13,840
that it's a beta. There were a couple of those 
naming changes, but I think those have mostly

1025
01:36:13,840 --> 01:36:19,360
uh landed. It's great. I mean, it it's mostly 
the same API as as V3, just better internals and

1026
01:36:19,360 --> 01:36:24,720
uh yeah, a whole bunch of small breaking changes, 
but for the those those methods that were being

1027
01:36:24,720 --> 01:36:29,360
hit all the time or whatever, the paro principle 
methods, it's not too different of an interface.

1028
01:36:29,360 --> 01:36:33,680
I can't really recall anything off the top 
of my head that's dramatically different.

1029
01:36:33,680 --> 01:36:40,160
So you've been showing off uh a bit of OpenCode 
here during this demo and I think it it really uh

1030
01:36:40,160 --> 01:36:47,600
showed off like what an amazing workflow can look 
like particularly when paired with an open editor

1031
01:36:47,600 --> 01:36:53,600
that's integrated now with said and maybe also for 
for other editors um also what you've shown with

1032
01:36:53,600 --> 01:37:00,880
voice dictation which I also use heavily uh I'm 
curious what is coming up for for OpenCode as it

1033
01:37:00,880 --> 01:37:06,320
relates to effect or maybe as it doesn't relate to 
effect. What are what are you most excited about?

1034
01:37:06,320 --> 01:37:12,320
Yeah. Yeah. So, definitely a thousand different 
things. Uh yeah, I've been mostly working on this

1035
01:37:12,320 --> 01:37:16,880
effect migration. I did some other fancy uh 
things like on the weekends. Now, if you hold

1036
01:37:16,880 --> 01:37:23,920
click and hold on the OpenCode logo, [laughter] 
boom. Uh make some different fun effects. Uh

1037
01:37:23,920 --> 01:37:28,480
there's some other animations I snuck in there 
on secret screens. Uh, we have the desktop app

1038
01:37:28,480 --> 01:37:33,680
that I added some animations to, but that's kind 
of being refactored at the moment as well. So, I'm

1039
01:37:33,680 --> 01:37:39,680
excited to get back to some more product work. I 
did just recently add this Zed integration uh and

1040
01:37:39,680 --> 01:37:46,160
and my co colleague uh James Long, who is known 
as the uh well, I don't know if he's known as it,

1041
01:37:46,160 --> 01:37:50,320
but I'll tell you he's the he created prettier. 
He's sort of working on some stuff right now with

1042
01:37:50,320 --> 01:37:55,920
regards to work trees and workspaces. So, you can 
I don't think I have this set up locally. It's

1043
01:37:55,920 --> 01:38:03,040
still I think I've seen some demos uh on on X and 
like yeah, I'm a big fan of of James' work. I've

1044
01:38:03,040 --> 01:38:10,320
had him on my other local first podcast uh quite a 
while back and I'm very excited for you all to to

1045
01:38:10,320 --> 01:38:14,480
have a chance working with working with James. Oh 
yeah, he's great. We just we just hung out for a

1046
01:38:14,480 --> 01:38:19,680
week in in Miami uh the whole team or most of the 
team which has been was just really fun. But yeah,

1047
01:38:19,680 --> 01:38:22,560
he's great. You should definitely have him on 
at some point. He's you could learn about his

1048
01:38:22,560 --> 01:38:26,000
effect journey because he's kind of new to 
it. But I think he's he the pills have taken

1049
01:38:26,000 --> 01:38:30,560
hold after some time. So he's working on a bunch 
of stuff with regard to syncing and workspaces

1050
01:38:30,560 --> 01:38:34,880
that I think it'll make it really nice because 
generally each OpenCode instance right now is

1051
01:38:34,880 --> 01:38:38,800
while there is that server client architecture 
if you just run it naively like this it's kind

1052
01:38:38,800 --> 01:38:43,520
of all encapsulated. It's it's serving it's not 
even exposed. It's internal to the process. So

1053
01:38:43,520 --> 01:38:47,920
there is the server server client architecture 
but it's not necessarily used in this case.

1054
01:38:47,920 --> 01:38:53,280
You can start it as a you can do OC serve and just 
start it as a server and then connect to this from

1055
01:38:53,280 --> 01:38:58,960
other clients. Some companies like I think Ramp 
famously has built a whole bunch of its internal

1056
01:38:58,960 --> 01:39:04,480
uh agentic tooling off of OpenCode using this this 
feature. Uh one thing that I really want to have

1057
01:39:04,480 --> 01:39:08,880
that James' work is going to be a foundation for 
is that like basically OpenCode server can be this

1058
01:39:08,880 --> 01:39:13,440
control plane can be like a demon process in your 
computer and all the clients just go into that and

1059
01:39:13,440 --> 01:39:16,560
that'll help with things like memory usage because 
instead of having multiple servers it'll just be

1060
01:39:16,560 --> 01:39:21,040
one. Similarly whenever you run Claude Code like 
each time it's starting a uh it's starting its own

1061
01:39:21,040 --> 01:39:26,400
server process and you you see the screenshots 
on Twitter whatever of like 27 different Claude

1062
01:39:26,400 --> 01:39:30,720
Code or OpenCode processes. Um so that that'll be 
really nice as a user experience and to be able

1063
01:39:30,720 --> 01:39:34,240
to sort of switch to different uh sessions. Yeah, 
I just want to get back to product work. I have a

1064
01:39:34,240 --> 01:39:39,200
thousand ideas. I wanted to first get this effect 
infrastructure like I don't like refactor as as

1065
01:39:39,200 --> 01:39:45,520
I sort of I think I've expressed a few times I'm 
terrified of refactoring uh non-effectful code or

1066
01:39:45,520 --> 01:39:51,280
making dramatic changes to it. So once everything 
is beautiful perfect self-similar fractal effect

1067
01:39:51,280 --> 01:39:57,360
perfection then I can I'll probably make a second 
pass sort of embracing uh pushing it even further

1068
01:39:57,360 --> 01:40:02,880
really making the most out of typed error messages 
etc. And then once I'm super happy I will add a

1069
01:40:02,880 --> 01:40:07,360
bunch of features. So something I I really want 
to add that I have a bit of a few spikes exploring

1070
01:40:07,360 --> 01:40:12,800
is background sessions. Sorry, background agents 
and background bash tools. Vision's pretty good

1071
01:40:12,800 --> 01:40:17,120
at dealing with that anyway, but right now if I 
have if I have it spawn multiple sub aents, it it

1072
01:40:17,120 --> 01:40:22,800
blocks the main session. You can get around this 
with plugins, but yeah, basically making the the

1073
01:40:22,800 --> 01:40:28,320
SDK nicer and also uh some of those some of those 
little uh paper cuts like a really nice experience

1074
01:40:28,320 --> 01:40:32,560
for for that. There's there's a thousand other 
things that everybody else is working on, but uh

1075
01:40:32,560 --> 01:40:38,640
those were sort of my own um little pain points 
that I want to address after the architecture is

1076
01:40:38,640 --> 01:40:48,240
uh crystalline uh scintillating apogee of of 
types. Yeah, I'm I'm particularly excited for

1077
01:40:48,240 --> 01:40:55,040
OpenCode to be open like that other people can 
learn from it like follow the journey. Now we

1078
01:40:55,040 --> 01:41:01,360
probably OpenCode is probably like one of the 
largest codebases that has migrated to effect

1079
01:41:01,360 --> 01:41:08,080
or is in the process of migrating to effect and I 
think that gives you a really great like reference

1080
01:41:08,080 --> 01:41:14,880
how you can do the migration what a full fully 
effectified codebase looks like and thank you

1081
01:41:14,880 --> 01:41:21,280
definitely also for that. Yeah I know leaving 
off here on a on a great cute demo. What are we

1082
01:41:21,280 --> 01:41:29,120
looking at here? So, so [laughter] uh um my other 
colleague uh Sebastian known as KMDR commander

1083
01:41:29,120 --> 01:41:33,360
I call him because I call everyone by their uh 
their I guess Twitter handles because that's what

1084
01:41:33,360 --> 01:41:40,720
my brain sort of brings into my uh awareness uh 
primarily is is he added this plug-in capability

1085
01:41:40,720 --> 01:41:45,360
to OpenCode. I mean it's been there always but 
TUI plugins that can also interoperate with server

1086
01:41:45,360 --> 01:41:50,400
plugins. So uh when I when I now prompt it will 
its eyes will glow. This is goblin mode. Sort of,

1087
01:41:50,400 --> 01:41:56,800
you know, I decided to make a novelty plugin based 
on the uh the trending meme of of GPT's goblin

1088
01:41:56,800 --> 01:42:01,200
issue. So, this introduced obviously I said tell 
us tell me a story. You know, it injects something

1089
01:42:01,200 --> 01:42:06,480
into system prompt to to tell it to, you know, not 
shy away from its uh innate love of goblins and

1090
01:42:06,480 --> 01:42:10,880
raccoons and such. And then when you're typing, 
it'll add this little beautiful it looks like a

1091
01:42:10,880 --> 01:42:17,360
cat, but a goblin animation here. Uh so, pretty 
stupid, but you know, it's it's easy. I prompted

1092
01:42:17,360 --> 01:42:22,480
this with like three pro prompts and it made a 2 
plugin for me. So I can I think there's a way to

1093
01:42:22,480 --> 01:42:28,880
get um yeah plugins here and I can disable or 
enable a lot of the APIs. The UI is actually

1094
01:42:28,880 --> 01:42:32,960
built on top of uh plugins now. So we're trying 
to make it even more pluggable which is a fun

1095
01:42:32,960 --> 01:42:36,400
thing to have. But anyway, that was I just thought 
I'd throw that up in the background for silliness

1096
01:42:36,400 --> 01:42:41,440
as we as we leave. But yeah, it's an honor to 
uh be able to contribute back to effect and to

1097
01:42:41,440 --> 01:42:45,440
be part of this thing. I mean it's if I haven't 
expressed it I want to express one last time like

1098
01:42:45,440 --> 01:42:52,640
effect systems are [ __ ] perfect and and there 
it fulfills the whatever the the the criterion of

1099
01:42:52,640 --> 01:42:58,000
being 10 times more uh powerful and just better 
than the competition. Like promises are junk.

1100
01:42:58,000 --> 01:43:03,920
They're straight hot garbage. Programming is in 
this sort of uh it's this this local maximum that

1101
01:43:03,920 --> 01:43:07,440
it's been is hanging around in. And there have 
been better ways of programming that have been

1102
01:43:07,440 --> 01:43:12,960
sort of embraced in these niche languages which 
were too weird to to sort of uh penetrate the

1103
01:43:12,960 --> 01:43:19,040
mainstream. And bless uh the Italian uh vampire 
Michael Arnaldi, the true creator of effect,

1104
01:43:19,040 --> 01:43:24,480
I I'll say it uh for for bringing effect into 
Typescript because it it has allowed it to be

1105
01:43:24,480 --> 01:43:28,640
viable. Um and one thing I like to think a little 
thought experiment is that every language where a

1106
01:43:28,640 --> 01:43:34,000
type system an effect system was introduced in, it 
did become the dominant uh way of writing in that

1107
01:43:34,000 --> 01:43:38,240
language. Um, never before has it been introduced 
into something as ginormous as as TypeScript,

1108
01:43:38,240 --> 01:43:45,520
but I I I feel like we're on that hockey uh stick 
growth curve. And it's it's just better. Like I

1109
01:43:45,520 --> 01:43:49,440
don't we don't need to really pitch to anybody. We 
need to like tantalize them with some ASMR [ __ ]

1110
01:43:49,440 --> 01:43:54,320
But they'll realize uh either by the quality I 
hope to make OpenCode so much better and so much

1111
01:43:54,320 --> 01:43:59,040
more reliable and and memory efficient and fast 
and delightful to iterate on as everybody else

1112
01:43:59,040 --> 01:44:03,600
sort of just uses agents to write JavaScript slop. 
they'll become uh they'll be weltering in their

1113
01:44:03,600 --> 01:44:08,640
own slop and we will be uh you know iterating in 
our golden crystalline palaces in the sky made of

1114
01:44:08,640 --> 01:44:13,520
pure uh thought. Uh that's that's the idea that 
we can like really show the proof in the pudding

1115
01:44:13,520 --> 01:44:18,080
uh by covering ourselves in pudding and running 
out into the streets naked and then all of us

1116
01:44:18,080 --> 01:44:26,080
everyone will join in in the pudding party. 
Beautifully said. Well, Kit, it's been a true

1117
01:44:26,080 --> 01:44:30,880
pleasure uh having you on the show. We've spent 
quite a bit of time together. So thank you so

1118
01:44:30,880 --> 01:44:37,760
much for for giving that to to me and to all of 
us here and sharing that journey how you came

1119
01:44:37,760 --> 01:44:44,400
to effect how you're effectifying OpenCode and 
can't see to to see where this goes. [music] I'm

1120
01:44:44,400 --> 01:44:50,080
I'm super excited. Thanks for having me on. Thank 
you so much. Take care. Bye. Peace. Thank you for

1121
01:44:50,080 --> 01:44:55,040
listening to the cause and effect podcast. [music] 
If you've enjoyed this episode, please subscribe,

1122
01:44:55,040 --> 01:45:00,080
leave a review, and share it with your friends. 
If you haven't done so already, you can join our

1123
01:45:00,080 --> 01:45:04,960
Discord community. And if you have any questions, 
feedback, or suggestions [music] about this

1124
01:45:04,960 --> 01:45:25,440
episode or about effect in general, don't hesitate 
to get in touch. See you in the next episode.

1125
01:45:25,440 --> 01:45:25,841
[music]

1126
01:45:25,841 --> 01:45:26,341
[music]