Cause & Effect

Get support from the Effect community

Kit Langton joins the podcast to talk about Effect, OpenCode, and what it takes to migrate a large TypeScript codebase to Effect. Enjoy a very Kit episode, technical, funny, opinionated, and full of love for effect systems.

Follow Kit:
- X
- YouTube
- GitHub

Mentioned in the video:
- effect.solutions
- effect.institute
- hex.kitlangton.com

Effect is an ecosystem of tools to build production-grade software in TypeScript.
#Effect #TypeScript #OpenCode #softwareDevelopment

Song: Dosi & Aisake - Cruising [NCS Release]
Music provided by NoCopyrightSounds
Free Download/Stream: http://ncs.io/Cruising
Watch: http://ncs.lnk.to/CruisingAT/youtube
  • (00:00) - Episode highlight: why effect systems matter
  • (00:43) - Meet Kit Langton
  • (03:49) - Effect Institute, Visual Effect, and interactive learning
  • (13:15) - Bringing Effect into OpenCode
  • (19:18) - Schema, branded IDs, and safer types
  • (27:35) - Effect services, layers, and architecture
  • (32:28) - Testing LLM workflows with Effect
  • (46:24) - Incremental adoption in a real TypeScript codebase
  • (50:44) - effect.solutions and agent-ready patterns
  • (01:00:36) - Layers, dependencies, observability, and telemetry
  • (01:16:58) - AI-first coding workflows
  • (01:34:35) - Using Effect v4 in OpenCode
  • (01:36:56) - What’s next for OpenCode
  • (01:42:33) - Closing thoughts

What is Cause & Effect?

Explore how software engineers use Effect to build reliable, production-ready software in TypeScript.

If I haven't expressed it, I want to express 
one last time. Like effect systems are [ __ ]

perfect. Promises are junk. They're straight 
hot garbage. Programming is in this sort of

a this this local maximum that it's been 
is hanging around in. And there have been

better ways of programming that have been 
sort of embraced in these niche languages

which were too weird to sort of penetrate 
the mainstream. And bless Michael Arnaldi

for bringing effect into Typescript because 
it has allowed it to be viable. every language

where an effect system was introduced in, it 
did become the dominant way of writing in that

language. Never before has it been introduced 
into something as ginormous as as TypeScript,

but I feel like we're on that 
hockey stick growth curve. [music]

Hey Kit, I'm so excited to finally have you on 
the podcast. We've been planning this for quite

a while. Finally happening. Welcome. You finally 
caught me. I guess I have to be here now. What an

awful day in my life. So, for folks who probably 
have seen one of your videos, uh, by now they have

recognized your voice and you're you're finally 
here. For those of you who don't know who you are,

would you mind giving a brief introduction who you 
are, what you have to do with effect, and what you

currently do. Yeah. Yeah. Yeah. Hi, everyone. I'm 
I'm Kit. I don't always sound like this, but I'm

very close to my microphone. That's the trick 
to ASMR. You just get really close to your mic,

by the way. And if you go back, you kind of sound 
normal. It's my normal voice. But yeah. Um, just

get back just get close to the mic and it'll all 
work out for you. Um, yeah. Uh, my name is Kit. I

was uh I've been a longtime effect system fanatic. 
Uh, it it bit me around I don't know, eight years

ago. And ever since I've been doomed career-wise 
uh to to live in a increasingly diminishing niche

of irrelevancy and and functional perfection to 
sort of wrap build a cocoon around myself and die

in it was my fate. But then the robots came and 
I got scared. So I decided to flee to the very

uh welcoming giant uh tower of of Typescript. 
And uh turns out there's like nice people

there and there are the jobs and stuff. So, 
luckily it's been saved from my doom fate. Um,

so I'm a big effect systems fan, big effect fellow 
like effect like effect systems of all kinds, but

um, effect is the first one that seems to have 
a shot at mainstream relevancy and I want to,

you know, I want to curse the world with 
my same disease. Yes, that's it. Yeah. So,

if if anyone hasn't checked out Kit's videos yet 
on on YouTube, definitely check those out. We're

going to put those links in in the description. 
But aside for your interest in effect systems,

you're also currently working on OpenCode. So, uh, 
how did that come to be? So, that I think that was

a direct I'll have to ask Dax. Uh, you'll have 
to have Dax on at some point. He's been, I think,

at this point, uh, thoroughly effectilled, as they 
say, by himself, too. I I I've learned my lesson.

I think I might have the record for rewriting is 
the most systems in in the world into some form

of effect system just because it's niche enough 
of a technology and I've done it at like five

jobs now. So I've had enough experience trying to 
convince people and you can lead a horse to water

etc. I mean I mean you can really just sort of 
dump water all around them and make it so that

they can only step in water. That's kind of 
my technique. And just like drink the water

in front of them and say m water so good. Uh this 
water is pure. But you can't make them drink. So

that technique seems to have worked with Dax even 
though he I think he he wanted me to join because

of uh he knew what I was get he was getting rather 
um I wasn't hiding my effect passion on the on

the timeline as it were and so I think I I came 
across his timeline with um uh I made this thing

called effect.institute which is sort of a an ASMR 
effect tutorial interactive tutorial thing that's

kind of weird. Yeah, we can I know we wanted 
to make this interactive so I could show off

some of these things as we talk about them, but 
I mean you you've you've now mentioned it a few

times. Let's take a look. And for for those of you 
who are just listening, uh definitely check out

the the link later is definitely worthwhile your 
time, particularly if you're rather new to effect.

Effect has always been like mindblowing, but it 
took a little while until it kind of clicked if

you're new to effect. And effect institute 
lowers the bar so much by like just making

it much more accessible. It reminds me to like 
some of the feelings I had when I tried out like

um Rails for Zombies uh back in the days and I 
was always hoping there would be something like

that for for effects and then Kit came along and 
did it. Yeah. Yeah. Yeah. I I do like I did love

Rails for zombies. Yeah. The goal is to make it 
such that you would want to go through it even

if you don't know what effect is. Like even if 
you hate effect, you'll want to still interact

with the website. Um, so yeah, this is this is my 
newest effect tutorial. I have some real feedback

here. I'm a wizard. That's Wow, it's really great. 
I have the man I have the mandate. Yeah, I have

the mandate. That's that's my goal is to have 
the mandate. As you can see, there are lots of

uh many pending lessons here. little effect or die 
reference at the bottom. But yeah, I'll I'll just

click on this thing. It's [laughter] so I made 
my screen ginormous or my my display resolution

very low. Uh but yeah, it's a sort of interactive 
thing. I'll just click through this. You see, use

the arrow keys to navigate between these different 
lessons. And when you hit space, you will hear my

voice speaking to you in maximal uh narration 
mode. Welcome to the effect institute. I'm Kit

and I want to teach you effect. But first, the 
briefest of tutorials. Pressing space, as you may

have discovered, will play or pause the See, it 
just paused it. So, you can see that there's some

animations that sync to the narration, and it's 
more interesting. I can you can also command click

between sections. When we call it, a promise has 
but one failure. Check out fail. And if it does,

so I'll pause it there. Can you hear that, by the 
way? Is that too loud? This is uh Yeah, perfectly

audible. And I would encourage everyone to check 
it out by themselves. Probably even better audio

quality. You can play around, see those like 
amazing detail, both not just visual details,

but actually also audio details. Those [clears 
throat] just uh craftsmanships at its finest. So,

uh, it is it's almost so good that it distracts 
you from learning it. [laughter] That's the good

that was the goal is to find that that boundary. 
Um, yeah, and there's some nice animated effects.

It's the last thing I'll show off is that oh, 
there's some like uh nice little pretty things

that are animated with W web GPU, which I'm pretty 
happy with. Uh, anyway, yeah, I'll I'll leave that

for the uh the viewers to indulge in. and and 
so effect institute is built uh sort of like

as a sequential project for some of your your 
previous related work. Let's let's just dive in

and we'll talk about OpenCode in a moment. But 
effect institute is sort of like a successor

project that builds on top of like visual effect 
visual types etc. Is that the the way how I should

think about it? Yeah. Yeah. Yeah. I've basically 
been building weird visual we can tie this in I

guess to my my weird history too but um my first 
I joined a bootcamp that was my entry entry point

into programming and then they hired me. So from 
day one at my job I was always doing some amount

of teaching and creating visualizations cuz I 
found that to be fun. Like I I went to school for

illustration and so I I like to keep some sort of 
visual elements and build full stacky things. I

like it all. I just want to do all of it and and 
a good way to force everything into every project

is to build, you know, some kind of full stack 
animated application which kind of lets me shove

all my interests in there uh as best I can. So 
that's kind of why everything takes on this kind

of shape. I actually back in the day when I um 
we'll get to this a while ago, but I started my

effect system journey in Haskell and then quickly 
ended up in Scala and there's this library called

Zo. You can see right away that this looks 
terribly ugly, but there's this thing I made,

which is this visual Zio animation. It tries 
to teach you Zio and give you a sense of how

things work, help you build an intuition with some 
incredible animations. Obviously, this looks like

hot garbage because I made it in 2019. But, you 
know, it is working and it's using Scolletjs. So,

it's actually running this effect system called 
Zio in the browser and letting you visualize

various things. There's some things at the bottom 
here that don't look as bad. So there's this,

you know, visual stream uh implementation. So if 
you uh map over a stream, multiplying it by two,

you'll see sort of the resultant stream is double 
the first stream. If you zip a stream with an

index, you'll see it uh zipped with its index in 
the list. So there's some some ideas here that are

not too different than what I end up doing later 
on. It's just I think generally much uglier. Got

a little It turns out if you make a bunch of 
projects, you get a little better at visual

design. So I made that about yeah a long time 
ago this library that effect was based on called

uh Zio and then about last I think around almost 
exactly a year ago uh effect became impossible to

ignore and Scala became increasingly to me felt 
like I was increasingly irrelevant in the world

at large. So I decided to jettison and and and 
at least try actually it was simpler than that.

I just wanted to try out effect and I thought 
I could remake um this project basically an

effect. So I made a visual effect. So if you 
go to effect.kitlangton.com and you'll see it's

uh it's prettier and you get this little spinning 
uh orb up there. It's pretty nice. And basically

you click and you see a visualization of 
different uh effect syntax. So these are

sort of the basic constructors. You can effect 
can succeed. It's green. They're sound effects.

They can fail. It's red. They're sound effects. 
And then it can die. This one's fun. So yeah,

I definitely got carried away with everything. Um 
I'll I'll skip off to just for for time reference.

I think you built this one pre- AI uh or like 
th this one was probably like Claude Code or

whatever was not as widely available. It was this 
was a year ago. It was definitely AI helped. Um,

but also this is like the architecture I kind of g 
I've just been pulling code forward from all those

past projects. So you could certainly not oneshot 
this. And so there's like real artisan handcrafted

love going into this. There is some handcrafted 
love and and I think you can also bring as a as

a very brief tangent I'm sure everyone's seen on 
the timeline uh much slop in the world. People

use AI to just build more and that's great. But I 
feel like to really take the most advantage of AI,

you should use it to iterate even more and to push 
things further instead of just letting you sort

of poop out more content that just sort of meets 
the minimum bar of legibility of of sort of okay,

this vaguely feels like a blog post that 
might have been published 10 years ago. Well,

now everyone can do that. So there's all this 
slop and I think people are getting a little

more perceptive around identifying it. There was 
definitely a time where you would be rewarded for

po publishing slo blog posts but I think that 
the sort of the telltale indicators of AI I

mean it's always changing right purple gradients 
different fonts like it's adapting but if if you

if you view a lot of stuff I think I think the 
general consuming public my hope is that they

become perceptive to that and seek sort of higher 
taste content higher quality content and you as

a person who's making stuff has more opportunity 
to iterate further and further so even if you're

using AI to do things just like raise your 
bar a lot uh and and really cuz if anything

uh looks off to you just just you know shoot off 
another prompt and and make it better. Isn't it

amazing that we can now go the extra mile with 
like so little energy we need to put into it?

Uh I think for for perfectionists is like the 
the best time ever. Yeah. And I think maybe the

only counterveailing force there is that there's 
also this newfound pressure to produce more. So

it's like okay I could perfect one thing or I can 
produce 100 awful things. So I mean it's the same

balance that's always been there of like explore 
and exploit uh except maybe there's increasing

pressure from the outside. But yeah I'd say it's 
more satisfying like do you can explore more but

when you finally do find something that uh you 
know interests you and titilates you that you

feel like there's some promise there definitely 
go deep on exploitation. So speaking of promises,

let's zoom out a little bit. Like highly recommend 
to anyone like check out those various projects

that you've just just demoed in case you're 
just listening to this right now. But you've

um about when was it like half a year ago or so 
and we're recording this at the end of April.

You've joined the uh folks who are working 
at OpenCode or on OpenCode. I think Anomaly

is the is the company behind it. Yes. Yes. Yes. 
It's not just called OpenCode but yes I I think

you've joined them with the goal to free them of 
the the promises [laughter] and bring in effect

to the OpenCode codebase. So, uh, I think there's 
a fascinating story behind this that I would love

to unpack and learn more about. Like, OpenCode is 
probably an pretty sizable codebase, probably even

larger so by now, but can you share how big it was 
when you when you joined and what the situation

was like? So, actually, I I don't know. I should 
know the number of of lines of code, especially

because I'm sure I've added to it with my various 
tests and parallel implementations. uh of things.

But actually, it can kind of be nice when you're 
taking off maybe a potentially infinitelysized uh

task to to not look ahead and just sort of let the 
uh the passion of the moment. If you're going to,

let's say, run across Antarctica, you might just 
want to focus on the next 10 footfalls instead of

the the entire breadth of of cold, harsh alien 
landscape ahead of you. So I I I didn't really

consider just how much once I started converting 
it to effect uh how large that task would be.

I actually I joined I think in February so it's 
only been a few months but it's felt it feels like

uh a few years for various reasons. On a high 
level how concluded is the effect migration the

effectification of OpenCode at this point? Uh 
it's getting really really close. I currently

have a sort of a parallel implementation of all 
the routers. So a little bit about OpenCode's

architecture is that for anyone who doesn't know 
it's it's basically a Claude Code like except it's

all open source and it works with all different 
models. You can use it with your uh ChatGPT

subscription, your pro subscription. You can just 
ooth in there. You used to be able to use it with

your uh Anthropic subscription but uh they took 
that away. So they've they've been reducing what

you can use that for but nonetheless and we have 
some subscriptions etc. But generally it's an open

source uh agent which you know you you ask it code 
queries and it runs in a loop and can call various

tool calls and work with all these different 
providers and it's open source and the I think

the the distinguishing mark architecturally is 
that it it sort of is this client server model

so that you can have multiple sessions uh you can 
have multiple clients all connected to the same

server that runs the sessions and there's some 
been some recent work now there's we're sort of

working on this control plane so you can have one 
running control plane and then possibly different

workspaces running in different sandboxes etc. 
Nonetheless, client server architecture. And so

there's a server is the point is what I'm trying 
to get to. And initially this was written with

Hono which is uh a nice server library very 
efficient but it's not written in effect. And

effect has its own uh server library. And one of 
the beautiful things about effect is that it is

this sort of all-encompassing ecosystem uh that's 
all very high quality and interoperates with

itself uh obviously more smoothly than another 
non-effect library will. And that there's a very

a couple of reasons for this and and why you might 
want effect to wash over everything slowly. Not

that it can't interoperate, but just that the more 
land mass it it claims, the happier you become.

um because you get to preserve its those 
invariants that it has throughout larger

swaths of your codebase. And another sort of piece 
of glue in in effect is the schema library which

is if you're familiar with Zod, it's sort of the 
Zod of effect. So you design your data as these

descriptions, these specifications and you get 
serialization and deserialization for free and

other various things because uh that your types 
are sort of described as data very very clearly.

It can also be used to generate uh many things 
like open API specifications uh servers clients

etc. And it is all very type- safe. So once you 
switch over to effect, you probably are also

going to want to design all of your data models uh 
using schema and do all of your data modeling with

schema and also use it to generate your server and 
and open API docs. So some of that was done with

Zod and Hono. So, I've just gotten the point where 
there's a parallel implementation of everything

using effect server uh the the effect server um 
setup the HTTP API uh in parallel with Hono and

I have a feature flag that either routes to the 
Hono implementation or the effect implementation.

And if this works well for the next few days, I'm 
going to delete the Hono stuff. This is actually

definitely a worthwhile uh tangent, which is how 
do you approach even organizing such a migration?

So I I started off really timidly. Um I mean Dax 
did mostly give me the thumbs up. I guess my first

I've been working on also in parallel this other 
project which will probably be revealed in time.

So that's kind of what I spent my first month 
working on with some parallel uh uh commits to

uh the main OpenCode codebase. And the original 
intention was actually to not necessarily involve

effect there because it's an open source library 
because maybe that would alienate certain people

just keep it basic TypeScript. But um I didn't 
even have to convince Dax. As I mentioned, I just

kind of tried to really make a show of how much I 
enjoyed working with effect. And I wanted to make

this other project a sort of a shining exemplar 
of effect and and let the quality of that uh sort

of incept the idea of using effect everywhere. 
But he he we was I guess doing some parallel

exploration and using it in some side projects and 
ended up convincing himself before I ever had to

uh to to try too hard. So before long he was like 
you know what we'll just effectify everything. I

know how these things go. It it'll it'll uh it'll 
come here eventually. We we want it too much. So

once I was given the green light I started very 
timidly by uh just um boarding some identifiers.

So one thing that effect has is with schema is the 
ability to have branded data types and that's very

useful in in a codebased like effect for instance 
and sorry like OpenCode you have many identifiers

for sessions for messages for um workspaces etc. 
And many of these are strings. They're like random

UUID strings, but the type system says they're all 
strings. And these are passed around everywhere.

And the trouble with just using raw strings is 
that you can easily sort of mistranspose them and

and pass in a name like the model name instead of 
the model ID. And TypeScript won't care. And maybe

this will even get serialized uh and saved to your 
your database and things will just kind of break

in in weird ways. So, I've always been a fan of 
using the type system to help reduce the burden

of and the possibility of of having these kinds 
of simple errors. Like types are really good at

tracking sort of coloring data in various ways and 
making sure you don't use the wrong put the the

square peg in the round hole. Simple stuff like 
this. to to add one more tangent to the stack is

like my my meta thought about AI and what's good 
for agents is uh and maybe this is just selfish in

my own own own worldview that I had previously but 
I think it applies is that what is good for humans

is good for agents generally what is good for a 
hardworking engineer is also good for an agent

because we're both context constrained agents are 
obviously context constrained in their windows

nowadays they have like million context windows 
but still there's some kind of degradation that

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

get better, but for the time being and maybe for 
the until the singularity in the event horizon,

I think that will hold for a while. Why not be 
more context efficient? We obviously as humans

are even more limited with our primate minds. 
There's this paper which is like the magic number

seven plus or minus two, which is like we can 
hold basically five to nine discrete ideas in

our heads. And we have all sorts of clever tricks 
of like chunking over time. Five discrete ideas

collapse into like one idea. uh you know, driving 
a car at the beginning. It's like, "Oh my god,

I've got to articulate each of my limbs in this 
particular position and put the pedal on the gas

to accelerate and that I feel like I'm doing like 
quap." If you've ever played Qwop, everything is

everything starts as quap basically. Uh let's find 
quap. Uh oh, I'll just play. It's an athletics

game. So, you have different buttons. Qw controls 
the thighs and the calves. So, your goal is to

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

thing. I used to I I used to be okay at this game, 
but I haven't played this in decades. I'm going

backwards. Uh so you can figure out different 
techniques, but uh yeah, I'm going the wrong way.

Let's just Can I even kill myself here? Anyway, uh 
so this is how everything feels at the beginning.

Um all skills to me, but it's eventually you 
just it it sort of collapses. It chunkifies and

becomes walking. I don't know why I'm going 
into this learning psychology stuff. I was

interested in this in the past when I was doing 
teaching. Nonetheless, we still are constrained

dramatically. So what it what helped me in and 
why I was so drawn to um type systems and hasll

originally was I started with Ruby on Rails which 
is great and fun but I felt this like deep anxiety

uh building every time I wrote any code. It just 
felt wrong and scary. Basically you have to keep

everything in your head. There are these implicit 
contracts that you're dealing with otherwise your

code will just break at runtime. So there are 
always types. It's just whether or not you encode

them in the type system or you just kind of use 
conventions and try to keep them in your head.

I don't know how I ever kept it in my head. It's 
impressive and for people that can use dynamically

typeyped systems like I think maybe there's 
some kind of brain atrophy that occurs when

you go over to a static type system uh because it 
just feels like so impossible once you've embraced

that crutch or exoskeleton or whatever that Gundam 
uh whatever neon evangelon suit or whatever of the

mind it's it's super addicting and super fun. 
So I just kind of got addicting addicted to

expressing more and more in the type system with 
the goal of enabling local reasoning which is

uh basically to me what all of functional 
programming is for. There's lots of people

who like to get a little onanistic about it and I 
think a lot of people like words like endofunctor

and monad and profunctor optics and they can use 
these words to confuse and insultify people. We

are not going to use the M word um because it's 
actually kind of simple really and that word does

not help like you don't need it to teach people 
obviously. In fact, removing that from effect,

people are learning way more effect than they 
ever learned the Haskell effect system or or

some of the other uh more category theoretical 
embracing uh effect systems of the past. Not

necessary. And in fact, it can be an obstacle. 
I think people can fall in love with that and

they it's kind of arbitrary and anyway that's a 
whole other talk. I forget which stack I'm on now,

but uh oh yes, why context? Like it allows you 
to forget more and more incidental complexity.

The reason why we like pure functions is because 
it's input mapped to output. You can forget about

global state. The second you have global mutable 
state or even a mutable input, you have to be you

have to know now in your head, you have to load 
into your local RAM how everything is called, how

instead of just being able to sort of zoom in on 
this one function, clear your mind and just solve

the hard problem of what you're dealing with. But 
yeah, I mean there's so many related ideas there.

But generally they uh to close one of those loops 
is that we're context constrained. The agents are

context constrained. Type systems are are great 
for both of us. Um I'll trust an agent's code if

it type checks afterwards, just as I would trust 
my own code more if it type checks afterwards. Um

if it were a dynamically typed system and the 
agent made a bunch of changes, well, I would

be very afraid. Uh just as I am with myself. I I 
couldn't work on just JavaScript codebases because

it you don't refactor a JavaScript codebase. Like 
that's a horrifying proposition. But if you have

types constraining you, you kind of can get to 
the point I know it's been a meme and people

make fun of like if it compiles then it works. 
Not necessarily. There's still logic you can get

wrong of course. But if you're just doing a pure 
refactoring, I'm much more confident that it does

work if it compiles afterwards on either side. 
And I you still want to double check everything

of course, but you can express a lot in the type 
system. So that that's useful. And even further,

effect allows you to express even more in the type 
system and have more constraints and a whole bunch

of other features, but basically it it allows me 
to use agents a little more uh maximally than I

would otherwise to embrace them more and to be 
less afraid. And and also like there's two sides

of it too. Like there's there's the there's the 
fact that you know if it makes a bunch of changes,

it probably won't break anything if it if it does 
compile at the end. But also once you're you have

a type you know you know certain things about it 
especially with with schema like there's an aspect

of uh there's a principle or property known as 
being correct by construction. If you only expose

a limited ways of constructing a type that might 
fail it's sort of like if your types are basically

parsed you know that once you have an instance of 
that type certain properties are fulfilled which

means I don't need to if I have just a string I 
don't need to peruse the rest of my codebase to

know like what kind of string is this? what kind 
of properties does the string hold? I'll say, "Oh,

it's this type. Therefore, I know it's a a valid 
UUID or I know it's a a positive integer." So,

you just have to search less. You sort of there's 
more semantic meaning in a very specific type than

there is string, which can really be anything, 
which means less context for me. Also, less like

AIs know how uh hasll works and how type systems 
works, how effects work. So, they can also trust

the type system. So it also helps them not have 
to once again like look at the whole codebase to

understand any one aspect of it if it is if if it 
is sort of pure and self-contained. Okay. So we're

basically just exploring how constraints help uh 
overall and how this has this like almost emergent

positive effect for any codebase. So that's how 
you what you've used to um to start the migration.

It's not necessarily that this is the core of 
effect yet. It's just that this is a primitive

that the effect ecosystem provides. So you've used 
that to kick off the effect migration. What was

the the next step after that? Yeah. Yes. Yes. 
So I I got increasingly gluttonous with my PRs

once I sort of got enough confidence to that that 
I wouldn't break everything. [snorts] So I made a

full few PRs. You know, the first two I was like, 
"Oh, please review this everyone. Review this one

line commit." In short order, I was merging, you 
know, 20 commits myself. uh 20 PRs myself um at

the same time. So all all the guardrails kind of 
flew off once I I was not breaking production for

a few weeks. So yeah, I I sort of started with 
one service after that. So I did some some IDs

fine that was good to have changed throughout 
the codebase pretty minimal just I think an

increase in code quality but after that it was 
time to actually sort of make an effect service.

I think that's a reasonable boundary. One of the 
reasons I like effect is because of I I wrote an

article about this at some point. I think I just 
posted it on Twitter, my only Twitter article. I

was trying to win a million dollars. Um but I 
I didn't. No one not enough people care about

layers. But uh just kidding. Services are 
beautiful because they are very reg regular.

They're they're fractal. They can express many 
things. It's it's a very reasonable module of

a codebase. And and ideally why I was first 
drawn to effect systems particularly in Scala

with the zeal library is because there was a way 
of writing code where every piece of your code

was sort of self similar to every other piece of 
your code. Services were composed of services.

It was turtles all the way down and back up and 
and all the files were were easy to navigate like

it just felt clean and organized and uh whatever 
kind of OCD I have that only applies to code was

deeply satisfied by that particular architecture. 
And so an analogy here might be for for those the

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

analogy would be maybe react components where 
you've used the word like fractal or self similar

uh when you look across like a large react 
codebase like it's everything is a react

component and then you compose them together and 
like whatever react component you look at you have

an intuition for like how the entire thing works 
and I think the same can't really be said for like

free form TypeScript business logic particularly 
when it's async etc and I think what you're

describing with a with a service is uh there we 
we get that sense of familiarity and composability

etc is that right yeah yeah especially contrasting 
it with just vanilla TypeScript I wasn't I'm not

too experienced in vanilla TypeScript codebases 
I've sort of avoided that uh like the plague

for a long time like that's why I was a Scala 
engineer so I tried to you know live in my own

little perfect bubble as long as possible but I 
have some you know I read about it in books what

the real world is like and how it's very messy and 
I certainly peaked at some codebases and and was

sort of mortified and horrified and disgusted 
and repelled by the standards that exists out

there because basically without effect you have 
a few ways of doing things and and none of them

are very good especially if you want to test your 
code. I I think the number one the obvious way is

just to have okay have a file where you implement 
your service as a bunch of exported functions and

if you have some shared state just put that in 
the file if you start up some connections just

uh to to external resources uh whatever open up 
a websocket connection just do that in the file

when the file loads I don't know and if you want 
to test it basically uh I think if either don't

test it or use monkey patching like if you want 
to depend on a service that depends on something

else well it's just it's importing it directly. 
So you the only way to really test it is to do

some kind of monkey patching thing uh some kind 
of mock which is very brittle and not type safe

at all as far as I can tell with the tools that I 
was using or exploring briefly and so you have to

just make sure if you change the underlying logic 
of that dependency that you also update your tests

and it's easy for these things to drift and fall 
out fall apart which once again like the anxiety

comes flooding back in the second like if I on 
my tombstone uh maybe the word single source of

truth is what I'll get as my my epitap. Not a good 
epitap actually, but it sounds sounds deep. Um,

but that's what I find myself. It's like that's 
my northstar design principle because yes,

there's just one way of expressing things. It's, 
you know, and once again, dynamic types fails

that test because there are no contracts. They're 
implicit. So every time you if you try to do duct

typing, there is no single source of truth of that 
contact contract every type. You just need to sort

of manually make sure that you don't [ __ ] that 
implicit contract up. With a type system, you can

have a trait, you can have an interface. That's 
the single source of truth for the structure of

that type. Similarly, the reason I like scheas is 
there's a single source of truth for the structure

of so many things. Everything is derived from 
that initial specification, servers, clients,

etc. And so with services, you have an interface 
that represents that service and you can have

multiple implementations of that uh which are 
described by this uh data type known as a layer,

which is a sort of effectful constructor for a a 
service interface. And so you could easily make a

test fake, a high quality test fake that you know 
does everything you could possibly want it to do

per data type. Sometimes they're very simple. 
Sometimes you can do more complicated things in

the effect codebase. One of our services, sorry, 
in the OpenCode codebase, one of our services

is obviously the LLM service which wraps at the 
current moment um AI SDK, but that's we don't want

to test necessarily against real LLM providers and 
and you know every time we run our tests we lose

$100. That would be bad. So, one of the things I 
did is built a really nice test fake library where

uh the rest of you could just run the main sort of 
session service and and call the prompt method on

that and it'll run all the real production code, 
but when it gets to that LLM service, uh it it's

feeding back pre sort of predetermined data that 
you determine in the test. So, I made a really

nice test mock. So, first you can make prompt. 
It'll obviously block waiting for what would

have been HTTP responses to come back in from say 
ChatGPT's uh model but instead on the next line I

can say you know llm.text what's up and then that 
will get fed back to it it'll sort of be streamed

in as the response uh to the the session service. 
So you can do all sorts of really beautiful things

that I don't even know my theory is just people 
just don't really do it at all. They just don't

test it. That seems to be the case. That 
seems to be why so much software is just

um I'm I'm trying to think of a better word than 
dog [ __ ] but that's the one that comes to mind.

So, [laughter] I don't know. Have you felt this? 
I've noticed that like catchy.com for instance, so

often I'll type a message, I want to type a second 
message, I can't hit the submit button anymore.

Some stream has gotten lost. And with my effect 
oriented mind, I just see like a leaked resource

or an unclosed stream. An abort signal that 
wasn't propagated as most likely uh the culprit

cuz that's hard to do right and you have to do it 
all the time everywhere and be very careful about

it. And there's so many sort of foot guns. It's 
just a sort of a golem consed entirely out of foot

guns. [laughter] So just to bring this back, we're 
basically uh walking through the the the migration

from uh the OpenCode codebase with like pre-effect 
to increasingly effectified where you've mentioned

that by now you basically have a parallel 
implementation of pretty much everything that's

fully effectified and you're about to flip this 
over completely. But I think you're still walking

through the early stages of like how did you kick 
things off? Also, how did you uh win the trust of

the of the rest of the the OpenCode team to like 
get get on board with this to change the way the

at that point status quo way of writing TypeScript 
to now embracing this. Yes. Okay. Thank you. Yeah,

I'm sort of turning this accidentally into Zeno's 
podcast or Zeno's Paradox podcast where Oh, I'm

We'll never get through the first question. 
We're going to keep getting halfway there and

going off on tangents, but hopefully it'll be a 
good uh journey to nowhere. Yeah. So, services,

I I implemented a service. So, uh some tangential 
service, a new service that involved this other

project that I was working on, some kind of uh 
service that was logging into that. Dax wrote

the original version uh had a PR. I knew it wasn't 
connected to the rest of the infrastructure. So,

I basically effectified that, turned it into 
a service. It went well and from there I tried

to just hunt through the rest of the codebase. 
I mean many codebases are oriented as services

even if they're not effect services even if 
they don't make their boundaries too clear.

Every file perhaps is a module. There's some 
kind of internal dependency graph that you can

track. So I try to find a good inlet there and 
I think you know generally starting at either

the bottom or the top is is good. Um burning the 
candle at at both ends can work but but also you

can start really anywhere. I tried to find some 
simple services. I think I can show off some

code actually at this point. Um, not that it's 
going to see if it if it's easy enough to to to

understand. Yeah. Yeah. Yeah. It's not Mhm. While 
we're pulling this up, I'm curious like how did

you choose that service? Um like what I've seen a 
lot is that people adopt effect really motivated

um centered around a particularly burning 
problem and like often it has to do something

uh with testing. Um, so I'm curious what was that 
burning problem that you were reaching for like a

services abstraction right away and uh that is 
probably also buying you some some trust and

goodwill from new colleagues who um who are well 
aware of this problem and might be skeptical of

like new technologies. and seeing it like solve a 
real problem probably goes a long way to to build

up a lot of trust and to to get the goodwill to 
to do the effect migration. Yeah, luckily I had

some cover because well I was hired knowing that I 
was uh totally deranged by effect and that I there

would be no stopping me. So I took I took that uh 
as as some encouragement. And then yeah, I I was

mostly optimizing for something that wouldn't 
break everything. I think I was more afraid of

uh making like I already had enough goodwill and 
trust to do this. They were already sort of sold

in effect. The only thing I I could see sort 
of undoing that was if I destroyed OpenCode for

millions of users. So it was more like minimizing 
the impact at least at the beginning. I knew the

benefits would come and things would become more 
testable. I think one service I started with

uh I might be wrong on the order the PR it's all 
open source so you can track all the PRs if you

want and go through the history of whatever 400 
PRs I opened in the last couple months but I think

there was these there's permission and question 
uh services so I'll just start with uh question

so this is like the ask user question tool right 
so I can say something just for the the folks who

are just only listening uh we're basically just 
navigating through the OpenCode uh codebase at

this point and We're looking at a few different 
modules. I think you're you're using zed here and

uh obviously also running OpenCode uh on on the 
side to get some some more information about

uh the the codebase as uh as we do these days. We 
don't like look things up ourselves anymore, but

we get it explained. Um, and so yeah, we're we're 
looking here at a few schema definitions, which I

suppose is related to some of the the early work 
you've been doing. Yep, exactly. Uh, so we're

looking at the question service. I'm sorry for the 
audio people. This might be a little weird. Uh but

we I'm sure we'll go on many tangents that are 
more amendable to just the spoken word. But um

the question service is basically there's this ask 
user question tool that I think Claude Code first

had where the agent has a tool call available to 
you where it can submit questions and then you

see in your UI a in this case a numbered list 
of of possible answers that you as the user uh

can can answer or you can form in as a tuy. Yes, a 
little TUI form here. So, uh I I asked OpenCode to

ask me a bunch of questions. It's obviously pretty 
random questions because I it has no context. It's

a new chat. So, it asks me for my current goal. 
What would you like me to help with right now? I

don't know. Let's say review some code. So, I can 
hit three there. Uh how much detail? Detailed.

Okay. Um whatever. And then research only. Fine. 
And then I can confirm these results and it'll

get those results and continue looping with that. 
I'll interrupt it here. But the question service

is the one that tracks which questions have been 
answered um the user's responses and when it's all

all done. So there's a bit of asynchronicity here 
which is always a good place to to use effect. Um

once again that wasn't the primary service. I 
wanted to start by not destroying the codebase

and ruining my credibility but I I there there 
is also a little bit of extra benefit here.

um something that there's some somewhat meaty 
uh immorsely uh about about this with regards

to concurrency and asynchronicity. So at the top 
I do have some schemas. So the the optic question

option uh there's like a label and a description. 
So I I guess that's sort of what is is actually

I forget what what is indeed what here. Um I 
should look at this exactly again. I think yeah

the answer is is what I'm offered. So we're we're 
effectively modeling our situation here. So if you

think about this form, we have questions, we have 
like different options to answer that question and

then we get answers hopefully. Exactly. Yeah. 
And and the nice thing is that some of this was

already designed albeit in Zod and raw promise 
raw promises. So I I didn't have to think about

the design of the system just yet. I'm excited 
for multiple passes where I can improve things

uh or or sort of apply my taste and opinions 
to the overall uh data modeling. But my goal

originally was like don't do two things at 
once. If you're going to be refactoring a

giant hundreds hundreds of thousands of lines of 
code into a new paradigm, don't also inter interle

uh sort of semantic logic changes because if 
something breaks, I didn't want to like not know,

okay, was it the effect migration that broke it or 
was it my other uh logical change that I couldn't

resist? Um don't change too many variables all 
at once. Yeah, that would be very frightening.

Uh need to isolate the variables as you as you'll 
see here. I also on a lot of these schemas I tend

to use schema.class just I don't know I like the 
way that that reads. One of the the downsides of

Typescript is sort of its general verbosity. 
This is why I was sort of stuck in Scala for

so long is that you do have to sort of repeat 
uh various identifiers multiple times for for

various reasons. Luckily um and this is something 
another tangent we can go on down the line is like

AI I think not only helped affect adoption 
but also well yeah AI for me personally made

effect [clears throat] more feasible. I was such a 
chromogen uh that I I loved Scala's terseness and

and expressivity as as they like to say which 
basically just means you can you don't have to

write a lot of redundant code. It's kind of that 
single source of truth principle except even at

the syntactic level just like you write the bare 
minimum that expresses the idea with TypeScript.

Sometimes you have to uh duplicate yourself. 
However, agents make this painful. Exactly.

Like now it basically you no longer need to write 
it yourself. So the when you had to suffer twice

before where you had to like by hand write out 
the duplication then still read the duplication.

Now we only have to bear with the uh reading 
the duplication which is more tolerable. It's

more tolerable and also the brain's really good at 
pattern matching. So once this you know your brain

recogn I like all I see now is just okay there's 
an option thing there's opt option everything else

kind of blurs out in the background and and of 
course maybe one day we'll have uh in our idees

sort of projectors that can uh instead of just 
syntax highlighting we can sort of restructure the

syntax because if we're not editing the code we 
can just sort of read a simplified projection. We

could project this into another language that we 
like. So I could read this as H hasll or whatever.

The Unison programming language kind of had 
support for this, but but anyway, that's not here

yet. Maybe that'll never get here. It probably 
doesn't matter because this this isn't really

a pain in reality. I'm I get better at reading 
TypeScript. But you'll see that each of these

does have a static readonly Zod property because I 
have a I should probably open source this. I mean,

it is open source. It's just all in line, but 
there's a there's an effect to Zod converter.

So there's the schema to odd converter because we 
need this at the boundary for the Hono uh server

so it can generate its API documentation and parse 
things. That's how you basically created this like

still lasting bridge between the old world and the 
new world where you didn't have to do a big bang

migration, but you could essentially still have a 
single source of truth throughout the migration,

but still like feed it into the old system and 
use it in the new system or vice versa. Exactly.

So yeah, we have this this boundary problem 
and and generally I mean effect makes this

fairly painless, right? So you need a way from 
going from the promise boundary to the effect

boundary and then from the effect boundary back 
to the promise boundary. So you can run effects

as promises and you can wrap promises as effects. 
So effect.promise can uh it actually gives you an

abort signal which is really nice even though most 
people don't use that in their promise code. And

then you can call out to some other you know AI 
generate text and you can pass in the uh signal

the abort signal as as an option or something 
and that'll turn that into a promise. And of

course you can also do Effect.runPromise and take 
some effect and get back a promise of its uh its

result or whatever. So you have to do these at the 
boundaries and there's some tricks that I that you

might have to do in in in a large codebase like 
this and we can get to that later on. I mean

it's all open source once again. So there's some 
details there if if there is some complexity which

this codebase does definitely have. Uh and then 
I had that same problem with Zod and schema. So

I don't think I ever go from Zod to schema. Uh I 
just because you have less of these stacks, right?

So I just uh defined the base implementation. I 
just started at the leave nodes instead of like

having Zod then schema then Zod. I started the 
leaf nodes and built myself back up converting

to Zod at the boundary so that we could use it in 
the uh the Hono uh server. And that's basically so

earlier you asked before about the Hono server. So 
I do these days have an HTTP uh API but basically

um both are pointing to the same underlying 
at this point effectified services. This one

just calls uh Effect.runPromise basically before 
calling these things. Uh or I have a I have an app

runtime.runPromise on the uh the effect services. 
Whereas the HTTP API can just sort of yield

whatever kind of uh service I'm usingdo thing 
directly instead of having to run to a promise.

And I think that's like really highlighting one of 
the the most important things about using effect

not in a vacuum where like you like one Sunday 
you start a new project and you decide to write

the first line of code in effect and like you're 
you're already in that universe. But uh when you

have a codebase that probably has like hundreds 
of thousands of lines of code with like that has

real complexity like everything kind of interwoven 
with each other. Now you want to like you maybe

you have all the agreement that in a year from 
now everything should be effect but how do you

go from like today to there in a way where 
you don't like freeze everything now you need

incremental adoption and I think this is where 
there's like multiple ways to to go about this

but interoperability is like helping so much this 
is why I think converting a code ba an existing

TypeScript codebase to effect is just making 
that's so easy is like very far away from let's

say porting something from Go or Java into effect 
because you can still like reuse all the chunky

bits of your code as little or as much as you want 
or or say like to use a TypeScript uh library as

well like to to make fun of RxJS more like if I 
were trying to do this I don't think this would

work very well like going from promise to RxJS 
that might be possible but it's it's a it's a

very different paradigm right this always operates 
the level of streams. Everything is going to be

a stream. Not all promise code fits into these 
oneshot streams very well. It's it's a weird uh

impedance mismatch to fill out your bingo card. Um 
yeah, whereas effect uh is represents basically a

computation that might succeed or fail. It's it's 
strictly a supererset of of a promise basically.

And then you have a separate streaming abstraction 
for when you want streams. So yeah, it's pretty

painless. Uh overall, there are a few nuances. 
They'd probably be boring in this context,

but I definitely will write something up um at 
some point or make or add a add a chapter to my

effect institute on some of the more uh low-level 
gotchas or details. But uh I think most of that is

only because of the some particular patterns that 
we were using in OpenCode that aren't necessarily

even very common. So, so if we zoom out a little 
bit, so this this questions module has been like

one of the the first targets that you've converted 
and sort of like introduced the effect patterns

and prove that this is working. Um, if we zoom 
out a little bit and like over the course of now

a few weeks and months, how did the migration 
progress? Which sort of issues did like at some

point you probably uh started looking into more 
thorny areas of the the codebase? I think you've

mentioned something that uh before that there were 
like pre-existing abstractions that you had to

like translate a little bit uh a little bit more. 
Um so which sort of challenges were you facing and

how did you overcome them? Yeah. Yeah. Yeah. I'm 
actually going to have OpenCode here uh render a

little service tree of of uh all the services that 
I've effectified. Hopefully that will help because

this is just one note of of many. uh the sort of 
the core of it is definitely the the core session

service that ends up transitively depending on all 
all of these other ones and just to sort of round

off like so at the top I had the schemas which is 
is great but then we we try to make all the files

there are many ways of doing this but um once 
again self similar and consistent so that if I

have an agent port another file it's a fairly 
mechanical process so at the beginning I would

recommend doing this is the approach that worked 
at least for me when migrating a large codebase

or doing any kind of repetitive task is like walk 
walk through the very first couple of iterations,

the example set very carefully, maybe handcode 
them or at least go through a bunch of iterations

until you're very happy with the way everything 
looks and then use that as sort of a seed as a

reference point for the agent as you tell it to 
do other ones and eventually you can see that it

gets to a point where it almost does what you need 
on the first shot or the second shot. And so yeah,

really paying attention to those first few 
examples because it agents are pretty good

at copying and extrapolating existing patterns. 
So you want to make sure that the the data set

you're feeding it is is really high quality. So 
if someone doesn't have that in their own codebase

yet, would you uh have any advice for references? 
What people should check out as a maybe pointing

their agent to as a reference? Should should 
they just look at the OpenCode codebase or are

there other simpler reference apps that that you 
would point people to? So I did I did make that

effect.solutions website for sort of that purpose. 
I could briefly share that again. I actually don't

think I shared this the first time. So let me 
just share it. Um I do need to update this.

I think I just did update it for the newest 
effect v4. But basically this is just kind of

um yeah I was trying to with all my effect work 
uh effect tutorialization work. I was trying to

hit a couple of different um what I saw thought 
of as GA gaps. One was just to as I was mentioning

before just like highquality uh content that 
would have been enticing even for its own sake

regardless of effect just to expose it to more 
people so that they would share it and say like

I don't even know care about effect but here mom 
watch this uh this this will be interesting this

will make your brain tickle or something. And the 
other one was, so the existing docs are great,

but they're very encyclopedic and they kind of 
start from first principles and it just gets

into the details really quickly. I wanted a much 
higher level view almost like an almanac or a a

best practice guide of just like don't worry about 
how this works. Uh you can read the docs if you

want to know that or you can ask your agents for 
this is sort of low-level toutelage, but why don't

I just tell you what to do. Yeah. And obviously 
that's not going to apply to every situation,

but if you're a newcomer, like what what fulfills 
the paro principle of like here's 20% of the sides

of the documentation that satisfies most of 
what you need. So like here's basically sort of

very prescriptive organize your stuff like this. 
And there are many ways of doing this. In fact,

in OpenCode, I I've changed this. I pull 
this out into a separate interface. But

it's really that that's a matter of taste. This 
is perfectly viable. And I would just recommend

being consistent picking something that you that 
you want. And there's a whole bunch of examples

in here. So effect.solutions has one take of this. 
Uh and it also of course because everything does

there's this copy agent instructions button. So 
if you click this and paste it into whatever agent

you want, it basically tells the agent how to um 
install a CLI and set up your codebase with like

the effect LSP server and the right TypeScript 
settings and how to basically read these docs.

That seemed to be the lowest friction way of doing 
it. just like a copy paste into your agent instead

of an MCP or something which is just more friction 
at the end of the day just like click copy pasta

people can copy pasta since the beginning of 
time so I trust them to continue doing that

um got it and so that basically contains all the 
patterns that are like yeah parto principle style

that you might encounter as a foundation uh 
just to to get things going and at that point

you probably develop your own tastes and your own 
like preferences how what is like your Acme Corp

uh way of doing things and then you can mold it 
and like tell the agent like maybe create your own

skill file or something. Yeah, that's basically 
the equivalent of my skill file except as a as a

website and not as a skill because I think at 
the time I made it skills weren't universally

adopted. I think we were still unskilled. We 
were unskilled. Uh but yeah, it's basically

I was I was constantly sending paths to my agents 
of other codebases where I done this. I was like,

let me just uh sort of collect this into some a 
useful thing that I can distribute both to future

versions of myself as well as uh the general 
public. Um and yeah, in there I I basically

recommend okay, always use schema for all your 
data modeling because yeah, it's principled it

works well. That's just something I was missing 
from Scala is just a you could basically define

any kind of data in the world as a combination 
as a sort of a composition of what the functional

programming language people called product and sum 
types. But it's like and types and or types like

uh for instance uh you can think of a boolean 
that's that's sort of the canonical most simple or

type. It's either it has two values false or true. 
But a person might be a composition of uh you know

um an uh is alive which is a boolean and their 
name which is a string anyway. And you can have

infinite types and all that stuff. But basically 
that that's uh these two very simple composable

primitives are enough to basically define any kind 
of data type you want in the world. Like bits are

essentially booleans. All right. On or off, true 
or false. And then you just have a bunch of them

anded together, right? A bite is is whatever 
eight of them. Um and out of that, of course,

everything uh computable calls. So it's definitely 
powerful enough and and simple enough. Um yeah,

it's orthogonal. It's it's got everything I like 
about um API design like maybe one of the top

principles of good APIs in my in my estimation is 
orthogonality that you don't have too many things

doing the same thing. You have you can achieve 
a lot of power but through compositionality and

orthogonality and I think just product and 
subtypes are a good example of that. We're

not going to go in a in a separate tangent 
of this, but just a call out also for like

your visual types project, which like beautifully 
also like highlights the the the various goodies

of Typescript on a on a type level. I I think we 
we're going to like see a a brief demonstration of

that, but like please go check it out like in 
your own time. This is uh like I think mostly

decoupled from effect but if you uh I think 
it's gives you like a deeper understanding of

um like effect by just knowing the basics 
of it. Yeah. Yeah. Yeah. So this is just

another fun thing. I was as I mentioned newer to 
typescript and there are some details to the type

system. So I kind of did this as a little um 
both to have fun with animations but also to

uh teach myself um type. So yeah, you can hit the 
arrow keys again to like navigate between. Okay,

this is the concept of types are sets, which 
is kind of what I was alluding to. So boolean

is a set of true or false. Direction, northeast, 
south, west. So these are sort of these sum types,

these ore types. Uh and number you can really 
think of as an infinite set of well of ores. Um

so it still it still works there. Anyway, there's 
a whole bunch of fancy animations and where's the

vin diagram? This is my favorite one. Um, 
but yeah, I'll stop sharing that one. Um,

check it out. It's too too good to ignore. 
[laughter] I got going going back to to the to

the migration and I think you're by now um GP 5.5 
has given us a good list of like all the modules

we need to scroll quite a bit. So this is the the 
domain of uh of OpenCode. Yeah. Yeah. It's kind of

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

showing each we have to reconstruct and traverse 
the graph here. It's just giving us a bunch of

edges basically like okay agent define depends on 
plugin but we would have to find plugin. I'm going

to give it one more chance and plugin depends 
on bus and config etc. I want to actually here

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

think just like looking at this ignoring which 
technology this is we might be writing rust we

might be writing something else but I think this 
gives you OpenCode is like a complex product

um and a complex codebase project etc and this 
gives us a good semanticformational overview over

like the involved concepts almost like a glossery 
page that explains the the various concepts

and doing that in a hierarchical way. And like 
the cool thing is like those those concepts now

correlate very elegantly, very concisely with 
effect services that actually give you the

implementation for that concept. Yeah, basically 
each of these is an effect service. So every file

is laid out the same way. And once again I you 
know if I do come up with a better pattern I

could this is a very parallelizable agent happy 
refactoring where it's like oh let's rename

all interfaces to something else like okay I'm 
exporting the interface as interface that's kind

of silly but why not? I was trying to think should 
I come up with a better word like what should I

call this? Well it is an interface so why don't I 
just call it the interface [snorts] and it's per

file so it it ends up working out just fine. 
And so yeah there's there's always a service

context.service service um that has this interface 
and then there if there is a main layer sort of a

main implementation which most of them have just 
one it's defined here as as layer which uh all

like the way you construct these things or the way 
I always do is at at the top you always uh import

transitive uh dependencies or sort of you I guess 
yield your transitive dependencies so these are

other services so by yielding this we're going to 
get a a dependency on bus service so we'll need to

come up with an implementation of that to provide 
later. But of course, bus service has its own

layer. So, we can just to linger on this and like 
if this is the first time someone is seeing this

and highly recommend maybe switching to a video 
at this point if you're if you're still just

listening. The the magic that we're seeing here 
and I think that's really novel about effects,

at least when effects started uh coming out. No 
other technology that I was aware of in Typescript

did this is that if you're using one thing um 
like here in like we're we're using the this

service for our thing that we're building now 
we know like A requires B to to B and like this

um transitive dependency like and u that that just 
like builds up uh implicitly without you having to

write down like be disciplined and write all of 
this down like this just composes automatically.

Uh I think that's like one of the most beautiful 
things about effect and that's really like through

composition you can break down the complexity 
of your of your codebase. I mean yeah the agent

was fairly uh quickly able to come up with this 
outline all by itself. I wonder if this were in

the old style if it would have been able to figure 
out this exact structure because it's able to just

look at these values and these types directly 
because basically every file also has I kind of

stole this pattern from effect itself the previous 
iteration just always also exporting a default

layer that takes the layer and just provides a 
good reasonable default. So you'll see that if

this is imported anywhere, which I'm sure it 
is. Okay, so the server like the main server

just imports the top level of default layers 
for everything and if and if these have other

dependencies, they're going to depend on their 
default layers and so on transitively. So you

don't have to provide everything. Everything 
defines a default layer and you basically just

use those at the top of your application. And 
just to make this a bit more concrete, if you

can go back to the place where you're constructing 
all of the the layers and compose them together,

this is like this is probably the like routes you 
you probably instantiate somewhere and then you

run the real thing. But let's say we're in a test 
now. You might not want to maybe use like the real

LLM layer, but now you might want to use the the 
mock in memory LLM layer. And just by switching

this out, like you're still satisfying that you 
need an LLM service, but now you're providing one

that doesn't cost a gazillion dollars per run, 
but like one that you can run instantly uh while

being offline, maybe. And this just replacing the 
need for like crazy monkey patching, etc., is like

one of the the many killer features here. these 
data stripes I recently added to Zed uh if you

launch OpenCode within Zed you see the selected 
line ranges down here which is kind of useful so

you get that as context in the thing and I just 
wanted to use that new feature show it off uh

because I'm happy about it because I use Zed and 
OpenCode all the time so I was missing this sort

of explain the data types and how they interrelate 
um is nice because now it has the context sent

there and it knows what I'm talking about yeah so 
now if I was confused about exactly what it would

Okay. Uh whatever. Um it's nice. Okay. So, uh 
but yeah, so the structure of these layers is you

yield to transitive dependencies. Then you have 
some internal helpers potentially. These are not

part of the public API. And then I always sort of 
define the public API as Effect.fn calls. And the

reason for this is that well you give it a nice 
little label here. This is used as a telemetry

span. So, one of the cool things we got working in 
in OpenCode is if I go to this little local thing

I have is I made my own little TUI for looking at 
traces called motel. Huh. Um, and so I can make

this larger or smaller. Uh, let me make it larger. 
Yeah, let's look into this. And like before we go

uh more into this uh just for for those who've 
like hearing about hotel or open telemetry the

the first time it's basically if you're still 
just console logging and like you're you're tired

of just like looking through like ton pages and 
pages of like console log like and you want a more

structured way like typically your code runs in a 
hierarchical way and this is probably also the way

how you're thinking about this. Uh, open telemetry 
is a like by at this point like a pretty long

established common standard that allows you to 
define things called traces um, logs and metrics.

Effect natively integrates with all of this and 
uh, it can be emitted anywhere. It can be uh,

emitted into data dog or sentry or wherever like 
all of those technologies support that. But what

Kit has built here is a version that runs 
completely locally and that gives you a much

more intuitive way to see what has your complex 
program actually done and why is it so slow. Yeah.

Yeah. And so one of the things obviously before 
effect that we did have some log files but lots

of things weren't logged and you don't get spans. 
It's actually really difficult to do I think open

telemetry integration without effect. I actually 
I guess I've never tried it before because I'd

imagine not just only difficult it's very gross 
because you you have like the happy path. So like

the the thing you need to care about with open 
telemetry when you want traces is you need to wrap

everything in little things called spans and that 
then you can have like in the same way as you have

a function and in that function you call other 
functions etc. And sometimes they run in parallel.

Now you have a little wrapper thingy that is 
language independent that's called a span and

where you have subspans etc. Now you need to 
basically wrap and instrument your entire code

with like spans and that's okay for the happy path 
but you also need to consider things like error

handling or you need to consider things such as 
like interruption etc. And this is where you just

like keep wrapping and wrapping and wrapping your 
code until from like single beautiful functions

you have now four layers of uh brace indentation 
and you just uh like either you regret doing this

uh like hotel instrumentation because your code 
is like no longer readable or or you do it and

you like you hate you hate this entire thing uh 
either way and with effect you basically get it

for free. Yeah, all you have to do is just wrap 
your functions with Effect.fn, which is nice to do

anyway because it it sort of is an alternative to 
the other way you would have to wrap it. I mean,

you have to use generator functions to compose 
sequential effects anyway. So, all you have to

do in addition to that is basically just add a 
little label here and that becomes a telemetry

spin. You can see that they're nested because if a 
function is called if a if a annotated function is

called within another function, they get nested 
to their current parent and so on and so forth.

And you can see how long these uh things take. 
The prompt takes 23 seconds. Most of this time is

waiting for the the agent to to run and therefore 
most of the other little things are done at the

beginning and at the end of that of that run. 
So it's not terribly interesting in this case.

Uh but it can be useful to see okay what takes 
the longest. All right snapshot our snapshotting

takes 102 milliseconds. Is that worth looking into 
more? Like is there something that's really slow?

I can here sort by the slowest call. So, okay. 
Why does O all take uh 800? Clearly, there's some

kind of issue with this this uh this one because 
it takes 8,000 seconds. That's not exactly true.

I'm sure uh span must be getting left open. But 
one cool thing is I'm I'm using this to debug

uh OpenCode itself. So, every instance I start 
locally connects to that local telemetry store

which is this is like totally written in effect 
in Typescript and is all local data. uh and

it's using open tui which uh is the ti framework 
written in typescript that OpenCode uses lots of

dog fooding going on so honeym uh a great codebase 
to also check out if you want to build your own

like effectbased CLI effect has a great way to to 
write CLIs integrating that with a complex system

like uh open toy uh open toy open ti open that 
works yeah open whatever and then also connecting

it with like the way how you do state management 
uh in in effect apps which I suppose you're using

effect atom for this uh for for this I am yeah 
I've yet to get to the front end the TUI front

end in OpenCode but maybe but one day I'd like to 
do this once the back end is all clean up but yeah

I think this is using effect atom yeah um it is 
partially vivecoded this of course so I wouldn't

necessarily use this as a a shining example but 
um it does work which is nice so one of the Cool

things as well is that if you're running locally, 
so not in production, you get this uh this session

ID. So if I want to debug this very session, I 
can go here and filter by any sort of attribute

key. So I can find session ID and paste this in. 
And we see there there are five spans for it. And

then theoretically in here I might I might be able 
to find something like a question like let me look

for ask eight matches. Oh yeah, there's question 
ask. So I did ask twice. Where did ask? And just

to uh explain uh what what's going on here, we we 
were looking at that like effect code for that ask

questions form module in OpenCode and we've used 
it before. We filled out like some example data

for for that and uh that code has run and like in 
traditional system you might have like maybe some

log output in a in a console somewhere uh but like 
then that quickly turns into hundreds t thousands

tens of thousands of of lines and you're just 
maybe command effing through that but that gets uh

very boring very quickly. you probably don't have 
like timing information in there. And here we're

like looking at something that is like immediately 
intuitive. Like we immediately understand where

uh like time was spent and at every span that 
we focus on, we now have like some contextually

enriched data called span attributes that is 
relevant for for this particular span if we

choose to instrument it like this. Yeah, I should 
probably add some more attributes for question

ask because we don't see the questions here, but 
that's that's that's trivially uh addressable. Um,

one of one thing that obviously might be striking 
is that this took 228 seconds, but that's not

a problem actually because if you look at 
the implementation here, what ask is called

being slow. Yeah, it was me. It was me taking 228 
seconds to finally answer the these questions. Um,

which is interesting because it it shows off a 
little bit of the effect concurrency primitives

that we're using in here. uh like this isn't 
problem. This isn't blocking anybody. This is

just me semantically blocking uh and and not and 
taking a little while to resolve this uh deferred

um that was going to be done by me finally hitting 
submit on those three questions. We'll see that

it's called question.ask is called inside of tool 
execute which is called in session prompt resolve

tools which is eventually called in session prompt 
uh run. So if I just close this and we we can just

briefly look at the implementation here. I'll try 
to do my best to paint a picture. So we have this

question.ask function which is annotated labeled 
which is sort of trivially becoming that span

which just works with any open telemetry provider 
including my vibecoded semi vibecoded uh TUI

version. Then uh this takes session ID a set of 
questions and a tool. So these are basically the

questions that the agent asks. So this was parsed 
from the agent's JSON response and it's passed

into this function. And then there's this tool ID 
so we know what tool it it resolved to. And then

uh pending pending pending. So yeah, we have this 
it's a little interesting. I made this instance

state abstraction. This is probably one of the 
more complicated bespoke abstractions used inside

of the OpenCode codebase because OpenCode is 
that server and there might be multiple parallel

sessions going on uh in multiple projects in 
multiple folders and we wouldn't for various

reasons we want each sort of folder to manage its 
own state. So when you kill that session we can

release all of that state. So this instance state 
thing is basically keyed by the current implicit

session. So each session can store its own list 
of pending questions basically and the pending

entry is this. It's a particular request and 
there's this deferred abstraction and a deferred

abstraction is part of effect. It's very nice uh 
very useful for these kinds of interactions which

it's something that you can create and it's 
a value that you can manually either cause to

succeed or cause to fail later on. It's kind of 
similar to how a promise works actually um except

promise doesn't by default let you outside of 
the thing complete it or resolve it. But anyway,

so it's this value you get that you could store 
off and later on complete it with a value. So it's

really good for these kind of messaging systems 
where the agent wants to ask the user a question

and then it wants to wait for the user to answer 
it. So where this is called it's basically we call

the tool execute calls ask and then it it makes 
this new deferred which is either going to succeed

with a list of answers that the user selected or 
it's going to fail with a rejection error. So this

already like I kind of was forgetting what this 
did because I worked on this forever ago. But once

again nice types. These aren't just strings. These 
are nicely named types. It's like a read only

array of answers or it fails. And the other thing 
is that effect obviously lets you signify how

something might fail which is not sort of implicit 
in promised land. You don't know. You have to look

at the values. Here I can just look at the types 
and say oh yeah this makes a lot of sense. The

user either responds or they reject they hit 
escape and they cancel the question and they're

like I don't want to answer any of your questions 
robot. So this is really good as documentation.

And then we basically publish this uh event asked 
info question which will get sent to the TUI uh

so it knows that it's waiting on these questions 
and we update this local state um basically saying

that question ID is is has this deferred in it 
and when the user eventually replies to a question

with a particular question ID here we can get 
that state for this instance get get the existing

question and if there isn't one it'll it'll just 
fail uh it'll it'll short circuit but if there is

a question that it found, it'll delete it from 
the pending set and it will publish the set of

answers and then it will succeed the deferred. 
And by succeeding this deferred value, it allows

this bit which was waiting on for 228 seconds or 
something to finally resolve with that success.

So it depends on how this def it's awaiting this 
deferred. And so uh it's going to semantically

block here whatever code is calling this will 
semantically wait until this deferred is either

completed or or rejected. And I think there's a 
reject method as well which will find that same

question and then call fail with a rejected error. 
And of course this is type safe like I cannot just

fail with any error here because if I change this 
I believe this will cause yeah an error because uh

this deferred has to fail with rejected error not 
with error. So it's it's all really damn nice. You

can't like you can't get it wrong. Uh it's nice to 
be constrained in these ways. I can come back and

look at this after I think I did this three months 
ago and sort of piece together what it does again

uh live. And I think what is particularly nice 
is how it's all scoped locally. Like this is not

too large that uh we could still wrap our head 
around now walking through this as most of us

are not working on the OpenCode codebase and are 
not familiar with it. Yet looking at this like we

we can grasp it. It fits in our in into our head 
and yet it's like a a non-trivial um complexity

amount with like all those different cases but it 
is all locally scoped and like we can just compose

it like in the in the overall application and it 
doesn't leak out that complexity throughout the

entire codebase presumably but it's all contained 
here in the same way as if I'm thinking on a on a

high level building something like OpenCode 
there's at some point there's a little thing

that's responsible for for questions and then 
that's resolved and it get that gets out of the

way and I think that maps really nicely to to 
the code where I like this distinction between

existential complexity and exist existential 
complexity where existential complexity is

like all the things that you actually need to 
build your app that's the good stuff accidental

complexity is like that everything additionally 
gets more complex without adding any benefits to

your to your app and like that you want to have as 
little as possible and I think effect allows us to

to express that at the at like just the right uh 
cut off point. I certainly think so. I would like

to shift the topic slightly from like so far we've 
been looking at code kind of like the the old way

uh as we've been writing and reading code etc. 
And I think that's still important like whatever

um someone else or an agent etc is writing I think 
us as engineers we should still be able to somehow

load that in our head and make sense of it and 
ideally even be able to judge it whether can it

be improved is it good enough does it solve the 
problem etc. Um and uh Kit is having fun over

here with like uh with a vim mode in in Zed. Um 
and I think it's certainly still worthwhile today

to to learn vim as that as that's that little 
uh anecdote. But um what I'm curious about is

if we're now allowing ourselves to switch into 
like a fully AI pilled perspective where truth

be told I have written the last line of code uh 
me personally in October last year 2025. So since

then every line of code that uh I've shipped 
um I have had done by an agent. So, uh, I've

made the full hard switch and it's been great. 
It doesn't mean that I don't read any lines of

code anymore. Quite the opposite. Uh, and I'm more 
thankful than ever for effect because it allows me

to review in a much higher level whether whatever 
was produced here is actually good or not. And I'm

also very glad that I've had like years and years 
of prior hard work by hand experience uh writing

all of this by myself. So I know what uh good or 
worse looks like at least judging based on my own

standards. Um and uh I think that is just becoming 
increasingly the the new reality. like not

everyone has has to go like all the way over there 
yet. But I do think it's the new reality that

it's not just effect being an important thing for 
humans to decide for like hey are we using this as

a team or not but it also plays a big role where 
the agents are uh successful with it or not. So I

would like to hand back two questions to you like 
how much code are you still writing by yourself by

hand versus with coding agents working on a coding 
agent? Um and what is your perspective on whether

effect is an advantage or a disadvantage for 
coding agents? Yeah. Yeah. Um yeah it's a tr it's

a tricky question but I'll start by just answering 
it honestly which is that uh yeah mostly dictating

to the agent to write the code for me even in 
such uh sort of um embarrassing circumstances

as like you know rename that variable or add a 
parenthesy to line you know column 18 on line

149 or something like this. Uh so one thing I do 
all the time is I I made my own open source uh

hex.kitlangton.com. Uh what is this? Uh uh I type 
that out though. Um it is sad to see my skills

slightly slightly. It like I miss it especially in 
these contexts. I I used to do these like weekly

when I worked in the Zo world, these weekly videos 
where I do a bunch of live coding and it was super

fun and I knew all the tricks and JetBrains 
and all the refactoring shortcuts uh and and

took great pride in my Vim skills and and I I you 
know have a Dvorak keyboard layout. I went fully

uh you know keyboard lifestyle, but of course a 
split keyboard these days. Yeah. I got my weird

my weird uh double halved uh broken in half. Uh it 
doesn't even have labels on the keys which is Oh

yeah. Uh which uh impresses no one because no one 
sees it except for my wife who's not impressed by.

And also once in a while if I like need to figure 
out how to do something uh with the keyboard like

it doesn't pair with Bluetooth, I need to look at 
the manual and it's like oh just hit command shift

option P. I'm like okay but where's the where's 
which one's the command key or which one's the

meta key? So I have to pull up the the di anyway. 
It's very embarrassing in those moments. Um what

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

tons of apps that do this. There's another good 
open source one called Handy. I made one called

hex just to fulfill my own specific needs and 
desires where I just like basically let's say

hey can you delete all the comments I added in 
this file please uh I want to restore this file

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

it's an Nvidia text to speech to text model and 
there it goes it left some new lines in whatever

you know I'll and and with this newfound ability 
to know what line I'm selecting I could just sort

of purely with Vim I don't know why I clicked I 
can just navigate between these windows, go to

line 135, select this, go back here, hit option 
and say, "Hey, let's rename the bus variable to

uh vehicle and it'll do that for me." And then 
while it's doing that, I'll, you know, be able to

look around at some other things, and it'll make 
the change. Uh, so yeah, like, okay, maybe I could

have actually sometimes for renames I will use my 
let me make that back to bus using this trick. Uh

but really if if sometimes there are consequences 
of renaming things where you have to also update

it in a comment that the renamer doesn't catch. 
So yeah for efficiency sake I end up do just

dictating everything. If if you do not yet dictate 
I highly recommend dictating because there is some

friction with typing like I did my I did my monkey 
type. I have at my peak I had a pretty good words

per minute. I'm sure that's atrophied somewhat 
embarrassingly now and I have more typos. Luckily,

agents don't really care about typos. So, you 
can type like an idiot and it'll figure out

what you're saying. Uh, what did I just say? Um, 
and so like you can just degrade even more even by

typing yourself. But there's there's a bit of 
a friction there to just typing. Like it took

me way slower to type that. I didn't actually 
Oh, I did say it still understands I think. Um,

I don't even how did it know that that I didn't 
Anyway, I thought it was just devolved into just

random letters at that point, but maybe it 
just autocompleted the obvious intention of

it. [laughter] Uh, and nonetheless, agents don't 
really care about typos. They can so you can type

like an idiot. It still understands. Uh, yes. 
Um, and even there even some dictation typos,

if you will, uh, misunderstandings, but it doesn't 
matter. The agents get it. Even if you dictate one

thing and it it doesn't understand how to say, 
you know, two, okay, you know, two weeks. It's

not two weeks instead of two, but if I say I'm 
working on an agentic 2. What do you think? Um,

okay. Agentic UI. Okay, fine. So, it'll figure 
it out. And if you're in the right context,

it doesn't even really matter. So, you can 
just quickly brain dump so much more context

verbally than you could u bottleneck through, 
you know, your your digits. As fun as typing is,

as much as I miss the experience and the time 
where that was a sort of a differentiator, I I

can just brain dump and and and it I tend to have 
better results. I I will sort of secretly subtly

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

lazy. So, it might be it'll it'll be misspelled 
anyway because my typing is atrophied. So, highly

recommend dictating. That's so that's kind of my 
answer. I mostly dictating to an OpenCode agent

or multiple OpenCode agents. I I like to use tabs 
and have multiple in this project. Another thing

I've been doing lately um is having it create work 
trees for different uh right lines of work. Like

if I have a refactoring that spans multiple files, 
I'll just tell OpenCode to create a bunch of work

trees. And it doesn't need any special feature 
for that. It can just create a git work tree,

CD into that directory, and then work there. 
And then I have it open up a pull request and

then I look at that in the browser. So you know 
make a new work tree where you rename the const

bus. Select this line here to vehicle and open 
up a pull request. Yeah. And then open that pull

request in my browser. So maybe I'll do something 
like that except with an actual uh work task. And

then we'll see that it is going to you know make 
some to-dos. Okay. So do some [ __ ] So that

that gives us a pretty good sense of your current 
workflow. um as it relates to effect, how do you

think using coding agents etc. um how does that 
compare to working in a completely uneffectified

codebase? Do you have any comparison there uh or 
any intuition? I mean unfortunately or fortunately

for myself I've been so thoroughly effectilled 
for so long that I haven't really worked on a

non-effect codebase in a while. But I I mean I was 
already once again like horrified and recoiled and

in terror to work on them before agents just for 
my own productivity. Oh, something that I I that

slipped my mind earlier which uh when talking 
about the nice constraints of these things is

that if you do not have the constraints of of a 
type system just like sort of that sort of subtle

uh pernitious tendency to when typing anytimes 
there's friction like we're really lazy creatures

right we're trying to preserve energy all the 
time it takes a lot of effort to to to be less

lazy um convenience sort of trumps everything we 
we will express less now okay just open up the PR

for the bus rename there it's very bus binding 
is open. So I then would like open up the tab

here and review it. Maybe I can leave comments and 
then have the agent look at the comments. So I'll

say in here I'll dictate what have you done? Why 
did you rename this? I don't want you to do this

at all. Actually close everything. Um so I'll add 
that comment and then I will say read the comment

I left and uh fulfill it. Anyway, it'll do that in 
the background. So just as uh if by dictating I'm

able to uh I just naturally end up being more 
encompassing with all of my thoughts and I and

I don't sort of drop them on the floor because 
I'm bottlenecked by my typing speed. Similarly,

if it is difficult to refactor a codebase, which 
it is if it's dynamically typed, you will just

simply refactor less. You might not think that 
you're avoiding refactoring, but it's it's a pain

in the butt and it's very scary. At least speaking 
for me, maybe some people do love it. Obviously,

DHH loves Ruby on Rails and I I get it. Like 
there's some beauty there, but for me personally,

that scares the big Jesus out of me. I just simply 
wouldn't refactor it very much. I'd maybe like

create a whole new codebase. And if you're not 
refactoring, like why do I refactor? I refactor

because I learned something about the code, about 
the problem space while I'm working on it. And

I want to encode that. I want to encode that 
constraint in the type system and the structure

of my code. I want to delete redundancies, sort of 
collapse duplication into better abstractions. And

I'm able to do that fearlessly with the backing 
of a type system doubly triply so with a library

like effect which allows me to encode even more in 
the type system and have even more constraints. So

I I end up refactoring more and I end up making 
more beautiful codebases. So I think that just

becomes easier to work on these codebases anyway 
because they're better factored and they better

express the domain and I can make them regular. 
I can refactor so I can shape things similarly

without fear. And the more things are consistent, 
the easier it is for an agent to extrapolate on

those patterns just as it was easier for me to 
extrapolate on patterns or like a newcomer like

because you can also think of a of an agent as a 
fresh really smart fresh hire who already knows

about you know every library in existence. But if 
your codebase is a mishmash of different patterns,

how would a new how would like a day one like 
they're always sort of spawned into existence the

second you have a fresh session. I mean whatever 
module your agents.md files uh how well are they

going to be able to perform the implicit 
context of your entire codebase will guide

them even more than the agents files. So yeah, 
it's it's easier to in a library like effect,

it's easier to refactor. Therefore, it's easier 
to maintain a higher quality codebase that is sort

of made consistent and then agents will sort of 
extrapolate on that better. And because of this,

the regularity, the self similarity, the fact that 
each of these files look the same, I could open up

five parallel PRs, something basic obviously, 
and I could sort of scan over it and just the

patterns if there is an aberration, an anomaly if 
you will, that'll become that'll be immediately

evident just by almost the structure of the 
code itself. Like one thing I can do is let's

say in here like I I can start from the interface 
basically. I can have a uh I can make it sort of

a to-do interface and and I can I can hand type 
this if I feel like hand typing it. I could I'm

at this point sometimes I actually do mistyping 
because uh and I try to do a little bit to b make

asy diagrams. You saw me do a little bit of that 
during this this uh this this talk. I used to do

this a lot when I was doing live coding. it it can 
be even more compact sometimes to express things

diagrammatically in in you know ASCII. So I might 
just be able to say like okay what what do I want?

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

could describe it as the interface. Sorry. No, the 
way how I think about it is like whatever is like

the highest signal noise ratio that you can sort 
of like give as intent to the agent like just use

that. Sometimes it is like you copy pasting like 
the old code and the new code you know exactly

how you want the new code to be then just write 
it out paste it in say like hey let's make this

happen everywhere consistently. Uh, and sometimes 
it's like a little uh like a little scribble on

like a piece of paper and like I airdrop the the 
picture into the coding agent and say like, "Hey,

have this idea for this better architecture. What 
do you think?" And like whatever is like the the

best signal like I I think the the mental model 
I like is what if you would uh show something to

your like favorite colleague who's like very 
experienced like immediately gets everything

without you having to explain everything. and you 
what is the thing you tell them and I think that

works pretty well for for coding agents and uh 
that I I love the the idea of like doing something

at a speed of thought and I think now we now we 
can yeah it's it's uh it's pretty fun obviously

they can go off the rails and do all sorts of 
crazy things so like I don't foresee myself being

taken out of a job anytime soon but I can I can 
definitely by using them often you get a sense of

what their limits are and those bound boundaries 
are always shifting. I mean, I've been using

them maximally since they first came out and you 
know, the first version of it was called Codeex,

right? The autocomplete model and I ran it in 
Jetbrains. I was doing some pretty complicated

type level stuff in Scala and it it it was able 
to extrapolate and like auto I could tab complete

and it would do the next arity of the the method 
or whatever or it would it would it would fulfill

some pretty interesting patterns that weren't 
just boilerplate. So I think I think there is

something about the models where they are really 
good at logic programming and and these kinds of

sort of mathematical patterns and they deal well 
with types right I mean because whatever the curry

Howard isomeorphism types are logic etc. They seem 
to be pretty good at this at this domain. Uh and

my experience has borne that out. So so yeah what 
I might do in this case is just yeah let me let me

uh maybe I would have just dictated this to make a 
new effect to do interface. But sometimes it could

be fun if I do want to be very specific. I could 
do this iteratively like now that I have this

file I could say um just turn these into actual 
functions on the interface please uh effectful

functions and we'll see what it does. Uh it should 
be able to do this pretty quickly and then once it

does uh yeah maybe it'll look at other files. Oh 
it's it's loading my whole effect skill because I

do have an effect skill that tells it to look at 
the effect. Speaking of that effect skill is that

public? So this there is one in the codebase 
that it found actually if I go to effect seal

and it's very basic and it just basically says do 
clone. So obviously I'm sure you've mentioned this

trick before in this podcast but if not clone 
the effect v4 I'm using effect v4 in here. So

that's effect small uh under the effect-ts uh or 
clone that somewhere and just tell the agent to

look at it. Right. Yeah. I I [clears throat] think 
that's one of the most reliable patterns not just

for effect but for like any uh any technology that 
the coding agents might not be like born with yet.

And I I think that's that's a great uh a great 
concept or a great method to embrace. However,

I do think that it's still worthwhile pairing that 
with a skill um particularly to show very specific

usage oriented patterns and maybe your preferences 
since like effect is uh such a wide ecosystem.

Sometimes there's multiple ways to do the same 
thing. So for example, if you want to build an

HTTP API, you could do it over RP over effect RPC. 
You could do it over the effect HTTP API module.

You can also do it like more lowle. And maybe you 
have certain preferences for your codebase. So I

think being in the effect skill being it making 
it more yours being more specific about like

hey other people might be doing this but we we're 
doing this here like writing this out concisely.

I've had good success with in for for the for 
my own effect skill. Yeah it's not it's not

we don't do anything too complicated. It's mostly 
like agents files. I think the skill was recently

added. Um in the agents file I do have some 
basic things like use Effect.gen use Effect.fn

etc. Like use date time instead of new date. 
There's some basic things, right? If if you see

the agent making a mistake a bunch of times, just 
throw it in your agents file or ask an agent to

make that change. May maybe one other topic before 
closing out. You've mentioned that you're using

uh effect 4 or effect small as it started and 
still called this way at least of as of today. Um,

did you start the migration with effect 4 right 
away or did you start with effect three and like

upgrade it to effect 4 at some point? No, I I you 
know laser less rule. I just I just went with it

um the the beta version. I think I asked Dax, oh, 
you know, it was it was still pretty early on, so

I was afraid. I'm like, uh, there's a beta version 
that just came out. Should uh I can use the old

version. What what would make you feel the safest? 
And Dax did not uh did not flinch. was like,

"Yeah, just use the use the beta version." What's 
your experience with Effect 4 at this point? Or

do don't you really have like too many reference 
points to to the old version? It's it's I mean,

the agents do great. Um I think there were a 
couple of naming flips that went back and forth.

The like everything just works so well. I forget 
what really ch it's pretty seamless. Obviously,

the bundle size has been improved. Tree shaking 
is improved. Uh schema is improved. But so so

far pretty seamless. I like Context.Service. 
I use that all the time. Uh it's better than

what was it before? Context.key, I think, or 
context. I think it was Context.Tag was before

and effect. Yeah. Finally, we're we're we're 
going to simplify things. Yeah. I think this

is temporarily service map, but got shifted back 
to context, which is great because that's that's

a good metaphor from the React world for how these 
things propagate. Um I wouldn't even mind somehow

magically having it be service, but this is fine 
or effect. Uh yeah. No, I mean it's barely noticed

that it's a beta. There were a couple of those 
naming changes, but I think those have mostly

uh landed. It's great. I mean, it it's mostly 
the same API as as V3, just better internals and

uh yeah, a whole bunch of small breaking changes, 
but for the those those methods that were being

hit all the time or whatever, the paro principle 
methods, it's not too different of an interface.

I can't really recall anything off the top 
of my head that's dramatically different.

So you've been showing off uh a bit of OpenCode 
here during this demo and I think it it really uh

showed off like what an amazing workflow can look 
like particularly when paired with an open editor

that's integrated now with said and maybe also for 
for other editors um also what you've shown with

voice dictation which I also use heavily uh I'm 
curious what is coming up for for OpenCode as it

relates to effect or maybe as it doesn't relate to 
effect. What are what are you most excited about?

Yeah. Yeah. So, definitely a thousand different 
things. Uh yeah, I've been mostly working on this

effect migration. I did some other fancy uh 
things like on the weekends. Now, if you hold

click and hold on the OpenCode logo, [laughter] 
boom. Uh make some different fun effects. Uh

there's some other animations I snuck in there 
on secret screens. Uh, we have the desktop app

that I added some animations to, but that's kind 
of being refactored at the moment as well. So, I'm

excited to get back to some more product work. I 
did just recently add this Zed integration uh and

and my co colleague uh James Long, who is known 
as the uh well, I don't know if he's known as it,

but I'll tell you he's the he created prettier. 
He's sort of working on some stuff right now with

regards to work trees and workspaces. So, you can 
I don't think I have this set up locally. It's

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

had him on my other local first podcast uh quite a 
while back and I'm very excited for you all to to

have a chance working with working with James. Oh 
yeah, he's great. We just we just hung out for a

week in in Miami uh the whole team or most of the 
team which has been was just really fun. But yeah,

he's great. You should definitely have him on 
at some point. He's you could learn about his

effect journey because he's kind of new to 
it. But I think he's he the pills have taken

hold after some time. So he's working on a bunch 
of stuff with regard to syncing and workspaces

that I think it'll make it really nice because 
generally each OpenCode instance right now is

while there is that server client architecture 
if you just run it naively like this it's kind

of all encapsulated. It's it's serving it's not 
even exposed. It's internal to the process. So

there is the server server client architecture 
but it's not necessarily used in this case.

You can start it as a you can do OC serve and just 
start it as a server and then connect to this from

other clients. Some companies like I think Ramp 
famously has built a whole bunch of its internal

uh agentic tooling off of OpenCode using this this 
feature. Uh one thing that I really want to have

that James' work is going to be a foundation for 
is that like basically OpenCode server can be this

control plane can be like a demon process in your 
computer and all the clients just go into that and

that'll help with things like memory usage because 
instead of having multiple servers it'll just be

one. Similarly whenever you run Claude Code like 
each time it's starting a uh it's starting its own

server process and you you see the screenshots 
on Twitter whatever of like 27 different Claude

Code or OpenCode processes. Um so that that'll be 
really nice as a user experience and to be able

to sort of switch to different uh sessions. Yeah, 
I just want to get back to product work. I have a

thousand ideas. I wanted to first get this effect 
infrastructure like I don't like refactor as as

I sort of I think I've expressed a few times I'm 
terrified of refactoring uh non-effectful code or

making dramatic changes to it. So once everything 
is beautiful perfect self-similar fractal effect

perfection then I can I'll probably make a second 
pass sort of embracing uh pushing it even further

really making the most out of typed error messages 
etc. And then once I'm super happy I will add a

bunch of features. So something I I really want 
to add that I have a bit of a few spikes exploring

is background sessions. Sorry, background agents 
and background bash tools. Vision's pretty good

at dealing with that anyway, but right now if I 
have if I have it spawn multiple sub aents, it it

blocks the main session. You can get around this 
with plugins, but yeah, basically making the the

SDK nicer and also uh some of those some of those 
little uh paper cuts like a really nice experience

for for that. There's there's a thousand other 
things that everybody else is working on, but uh

those were sort of my own um little pain points 
that I want to address after the architecture is

uh crystalline uh scintillating apogee of of 
types. Yeah, I'm I'm particularly excited for

OpenCode to be open like that other people can 
learn from it like follow the journey. Now we

probably OpenCode is probably like one of the 
largest codebases that has migrated to effect

or is in the process of migrating to effect and I 
think that gives you a really great like reference

how you can do the migration what a full fully 
effectified codebase looks like and thank you

definitely also for that. Yeah I know leaving 
off here on a on a great cute demo. What are we

looking at here? So, so [laughter] uh um my other 
colleague uh Sebastian known as KMDR commander

I call him because I call everyone by their uh 
their I guess Twitter handles because that's what

my brain sort of brings into my uh awareness uh 
primarily is is he added this plug-in capability

to OpenCode. I mean it's been there always but 
TUI plugins that can also interoperate with server

plugins. So uh when I when I now prompt it will 
its eyes will glow. This is goblin mode. Sort of,

you know, I decided to make a novelty plugin based 
on the uh the trending meme of of GPT's goblin

issue. So, this introduced obviously I said tell 
us tell me a story. You know, it injects something

into system prompt to to tell it to, you know, not 
shy away from its uh innate love of goblins and

raccoons and such. And then when you're typing, 
it'll add this little beautiful it looks like a

cat, but a goblin animation here. Uh so, pretty 
stupid, but you know, it's it's easy. I prompted

this with like three pro prompts and it made a 2 
plugin for me. So I can I think there's a way to

get um yeah plugins here and I can disable or 
enable a lot of the APIs. The UI is actually

built on top of uh plugins now. So we're trying 
to make it even more pluggable which is a fun

thing to have. But anyway, that was I just thought 
I'd throw that up in the background for silliness

as we as we leave. But yeah, it's an honor to 
uh be able to contribute back to effect and to

be part of this thing. I mean it's if I haven't 
expressed it I want to express one last time like

effect systems are [ __ ] perfect and and there 
it fulfills the whatever the the the criterion of

being 10 times more uh powerful and just better 
than the competition. Like promises are junk.

They're straight hot garbage. Programming is in 
this sort of uh it's this this local maximum that

it's been is hanging around in. And there have 
been better ways of programming that have been

sort of embraced in these niche languages which 
were too weird to to sort of uh penetrate the

mainstream. And bless uh the Italian uh vampire 
Michael Arnaldi, the true creator of effect,

I I'll say it uh for for bringing effect into 
Typescript because it it has allowed it to be

viable. Um and one thing I like to think a little 
thought experiment is that every language where a

type system an effect system was introduced in, it 
did become the dominant uh way of writing in that

language. Um, never before has it been introduced 
into something as ginormous as as TypeScript,

but I I I feel like we're on that hockey uh stick 
growth curve. And it's it's just better. Like I

don't we don't need to really pitch to anybody. We 
need to like tantalize them with some ASMR [ __ ]

But they'll realize uh either by the quality I 
hope to make OpenCode so much better and so much

more reliable and and memory efficient and fast 
and delightful to iterate on as everybody else

sort of just uses agents to write JavaScript slop. 
they'll become uh they'll be weltering in their

own slop and we will be uh you know iterating in 
our golden crystalline palaces in the sky made of

pure uh thought. Uh that's that's the idea that 
we can like really show the proof in the pudding

uh by covering ourselves in pudding and running 
out into the streets naked and then all of us

everyone will join in in the pudding party. 
Beautifully said. Well, Kit, it's been a true

pleasure uh having you on the show. We've spent 
quite a bit of time together. So thank you so

much for for giving that to to me and to all of 
us here and sharing that journey how you came

to effect how you're effectifying OpenCode and 
can't see to to see where this goes. [music] I'm

I'm super excited. Thanks for having me on. Thank 
you so much. Take care. Bye. Peace. Thank you for

listening to the cause and effect podcast. [music] 
If you've enjoyed this episode, please subscribe,

leave a review, and share it with your friends. 
If you haven't done so already, you can join our

Discord community. And if you have any questions, 
feedback, or suggestions [music] about this

episode or about effect in general, don't hesitate 
to get in touch. See you in the next episode.

[music]

[music]