Skip to content

Effectifying OpenCode

Jun 19, 2026

#8: Effectifying OpenCode

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.

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:

Mentioned in the video:

Effect is an ecosystem of tools for building robust, production-grade applications in TypeScript.

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
  • (1:00:36) - Layers, dependencies, observability, and telemetry
  • (1:16:58) - AI-first coding workflows
  • (1:34:35) - Using Effect v4 in OpenCode
  • (1:36:56) - What’s next for OpenCode
  • (1:42:33) - Closing thoughts
Discuss this episode on Discord

Transcript

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

17:04descriptions, these specifications and you get  serialization and deserialization for free and

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

20:47happens 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

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

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

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

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

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

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

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

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

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

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

21:36start a And then I died. So, I made it 1.3 meters.  And like we could just do this for the rest of the

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

28:53most 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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

57:30is it's sort of uh it's not done it in the nicely  nested way that I would have wanted. It's kind of

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

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

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

57:50we go. So okay so there's the the main app layer.  Uh let me go to where's the the session and and I

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

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

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

58:19like the involved concepts almost like a glossery  page that explains the the various concepts

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

01:00:29write down like be disciplined and write all of  this down like this just composes automatically.

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

01:00:41composition you can break down the complexity  of your of your codebase. I mean yeah the agent

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

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

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

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

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

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

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

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

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

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

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

01:01:38this is like this is probably the like routes you  you probably instantiate somewhere and then you

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

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

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

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

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

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

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

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

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

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

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

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

01:03:04yield to transitive dependencies. Then you have  some internal helpers potentially. These are not

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

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

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

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

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

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

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

01:03:54of just like looking through like ton pages and  pages of like console log like and you want a more

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

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

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

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

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

01:04:35Kit has built here is a version that runs  completely locally and that gives you a much

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

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

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

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

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

01:05:11the the thing you need to care about with open  telemetry when you want traces is you need to wrap

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

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

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

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

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

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

01:05:54like keep wrapping and wrapping and wrapping your  code until from like single beautiful functions

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

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

01:06:15you like you hate you hate this entire thing uh  either way and with effect you basically get it

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

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

01:06:31you have to use generator functions to compose  sequential effects anyway. So, all you have to

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

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

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

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

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

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

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

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

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

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

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

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

01:07:38which is this is like totally written in effect  in Typescript and is all local data. uh and

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

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

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

01:08:05like uh open toy uh open toy open ti open that  works yeah open whatever and then also connecting

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

01:09:56like looking at something that is like immediately  intuitive. Like we immediately understand where

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

01:10:11enriched data called span attributes that is  relevant for for this particular span if we

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

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

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

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

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

01:10:44which is interesting because it it shows off a  little bit of the effect concurrency primitives

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

01:10:51just me semantically blocking uh and and not and  taking a little while to resolve this uh deferred

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

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

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

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

01:11:19question.ask function which is annotated labeled  which is sort of trivially becoming that span

01:11:24which just works with any open telemetry provider  including my vibecoded semi vibecoded uh TUI

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

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

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

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

01:11:50state abstraction. This is probably one of the  more complicated bespoke abstractions used inside

01:11:55of the OpenCode codebase because OpenCode is  that server and there might be multiple parallel

01:12:00sessions going on uh in multiple projects in  multiple folders and we wouldn't for various

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

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

01:12:17session. So each session can store its own list  of pending questions basically and the pending

01:12:24entry is this. It's a particular request and  there's this deferred abstraction and a deferred

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

01:12:35it's something that you can create and it's  a value that you can manually either cause to

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

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

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

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

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

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

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

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

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

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

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

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

01:13:38user either responds or they reject they hit  escape and they cancel the question and they're

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

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

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

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

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

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

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

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

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

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

01:14:41block here whatever code is calling this will  semantically wait until this deferred is either

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

01:14:53question and then call fail with a rejected error.  And of course this is type safe like I cannot just

01:14:58fail with any error here because if I change this  I believe this will cause yeah an error because uh

01:15:05this deferred has to fail with rejected error not  with error. So it's it's all really damn nice. You

01:15:10can't like you can't get it wrong. Uh it's nice to  be constrained in these ways. I can come back and

01:15:14look at this after I think I did this three months  ago and sort of piece together what it does again

01:15:19uh live. And I think what is particularly nice  is how it's all scoped locally. Like this is not

01:15:29too large that uh we could still wrap our head  around now walking through this as most of us

01:15:36are not working on the OpenCode codebase and are  not familiar with it. Yet looking at this like we

01:15:42we can grasp it. It fits in our in into our head  and yet it's like a a non-trivial um complexity

01:15:49amount with like all those different cases but it  is all locally scoped and like we can just compose

01:15:57it like in the in the overall application and it  doesn't leak out that complexity throughout the

01:16:03entire codebase presumably but it's all contained  here in the same way as if I'm thinking on a on a

01:16:10high level building something like OpenCode  there's at some point there's a little thing

01:16:15that's responsible for for questions and then  that's resolved and it get that gets out of the

01:16:20way and I think that maps really nicely to to  the code where I like this distinction between

01:16:26existential complexity and exist existential  complexity where existential complexity is

01:16:33like all the things that you actually need to  build your app that's the good stuff accidental

01:16:38complexity is like that everything additionally  gets more complex without adding any benefits to

01:16:44your to your app and like that you want to have as  little as possible and I think effect allows us to

01:16:51to express that at the at like just the right uh  cut off point. I certainly think so. I would like

01:16:58to shift the topic slightly from like so far we've  been looking at code kind of like the the old way

01:17:05uh as we've been writing and reading code etc.  And I think that's still important like whatever

01:17:11um someone else or an agent etc is writing I think  us as engineers we should still be able to somehow

01:17:21load that in our head and make sense of it and  ideally even be able to judge it whether can it

01:17:27be improved is it good enough does it solve the  problem etc. Um and uh Kit is having fun over

01:17:35here with like uh with a vim mode in in Zed. Um  and I think it's certainly still worthwhile today

01:17:41to to learn vim as that as that's that little  uh anecdote. But um what I'm curious about is

01:17:48if we're now allowing ourselves to switch into  like a fully AI pilled perspective where truth

01:17:55be told I have written the last line of code uh  me personally in October last year 2025. So since

01:18:04then every line of code that uh I've shipped  um I have had done by an agent. So, uh, I've

01:18:11made the full hard switch and it's been great.  It doesn't mean that I don't read any lines of

01:18:18code anymore. Quite the opposite. Uh, and I'm more  thankful than ever for effect because it allows me

01:18:25to review in a much higher level whether whatever  was produced here is actually good or not. And I'm

01:18:32also very glad that I've had like years and years  of prior hard work by hand experience uh writing

01:18:41all of this by myself. So I know what uh good or  worse looks like at least judging based on my own

01:18:48standards. Um and uh I think that is just becoming  increasingly the the new reality. like not

01:18:56everyone has has to go like all the way over there  yet. But I do think it's the new reality that

01:19:02it's not just effect being an important thing for  humans to decide for like hey are we using this as

01:19:09a team or not but it also plays a big role where  the agents are uh successful with it or not. So I

01:19:16would like to hand back two questions to you like  how much code are you still writing by yourself by

01:19:21hand versus with coding agents working on a coding  agent? Um and what is your perspective on whether

01:19:29effect is an advantage or a disadvantage for  coding agents? Yeah. Yeah. Um yeah it's a tr it's

01:19:36a tricky question but I'll start by just answering  it honestly which is that uh yeah mostly dictating

01:19:43to the agent to write the code for me even in  such uh sort of um embarrassing circumstances

01:19:49as like you know rename that variable or add a  parenthesy to line you know column 18 on line

01:19:56149 or something like this. Uh so one thing I do  all the time is I I made my own open source uh

01:20:01hex.kitlangton.com. Uh what is this? Uh uh I type  that out though. Um it is sad to see my skills

01:20:10slightly slightly. It like I miss it especially in  these contexts. I I used to do these like weekly

01:20:14when I worked in the Zo world, these weekly videos  where I do a bunch of live coding and it was super

01:20:18fun and I knew all the tricks and JetBrains  and all the refactoring shortcuts uh and and

01:20:24took great pride in my Vim skills and and I I you  know have a Dvorak keyboard layout. I went fully

01:20:30uh you know keyboard lifestyle, but of course a  split keyboard these days. Yeah. I got my weird

01:20:36my weird uh double halved uh broken in half. Uh it  doesn't even have labels on the keys which is Oh

01:20:42yeah. Uh which uh impresses no one because no one  sees it except for my wife who's not impressed by.

01:20:48And also once in a while if I like need to figure  out how to do something uh with the keyboard like

01:20:54it doesn't pair with Bluetooth, I need to look at  the manual and it's like oh just hit command shift

01:20:58option P. I'm like okay but where's the where's  which one's the command key or which one's the

01:21:03meta key? So I have to pull up the the di anyway.  It's very embarrassing in those moments. Um what

01:21:08was I saying? Oh yeah. So I I'm very sad to admit  that most of the time I dictate. So I mean there's

01:21:13tons of apps that do this. There's another good  open source one called Handy. I made one called

01:21:17hex just to fulfill my own specific needs and  desires where I just like basically let's say

01:21:23hey can you delete all the comments I added in  this file please uh I want to restore this file

01:21:28and 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

01:21:34it's an Nvidia text to speech to text model and  there it goes it left some new lines in whatever

01:21:40you know I'll and and with this newfound ability  to know what line I'm selecting I could just sort

01:21:44of purely with Vim I don't know why I clicked I  can just navigate between these windows, go to

01:21:49line 135, select this, go back here, hit option  and say, "Hey, let's rename the bus variable to

01:21:54uh vehicle and it'll do that for me." And then  while it's doing that, I'll, you know, be able to

01:22:00look around at some other things, and it'll make  the change. Uh, so yeah, like, okay, maybe I could

01:22:07have actually sometimes for renames I will use my  let me make that back to bus using this trick. Uh

01:22:14but really if if sometimes there are consequences  of renaming things where you have to also update

01:22:20it in a comment that the renamer doesn't catch.  So yeah for efficiency sake I end up do just

01:22:26dictating everything. If if you do not yet dictate  I highly recommend dictating because there is some

01:22:31friction with typing like I did my I did my monkey  type. I have at my peak I had a pretty good words

01:22:36per minute. I'm sure that's atrophied somewhat  embarrassingly now and I have more typos. Luckily,

01:22:41agents don't really care about typos. So, you  can type like an idiot and it'll figure out

01:22:50what you're saying. Uh, what did I just say? Um,  and so like you can just degrade even more even by

01:22:57typing yourself. But there's there's a bit of  a friction there to just typing. Like it took

01:23:01me way slower to type that. I didn't actually  Oh, I did say it still understands I think. Um,

01:23:06I don't even how did it know that that I didn't  Anyway, I thought it was just devolved into just

01:23:11random letters at that point, but maybe it  just autocompleted the obvious intention of

01:23:14it. [laughter] Uh, and nonetheless, agents don't  really care about typos. They can so you can type

01:23:19like an idiot. It still understands. Uh, yes.  Um, and even there even some dictation typos,

01:23:26if you will, uh, misunderstandings, but it doesn't  matter. The agents get it. Even if you dictate one

01:23:30thing and it it doesn't understand how to say,  you know, two, okay, you know, two weeks. It's

01:23:35not two weeks instead of two, but if I say I'm  working on an agentic 2. What do you think? Um,

01:23:41okay. Agentic UI. Okay, fine. So, it'll figure  it out. And if you're in the right context,

01:23:46it doesn't even really matter. So, you can  just quickly brain dump so much more context

01:23:50verbally than you could u bottleneck through,  you know, your your digits. As fun as typing is,

01:23:55as much as I miss the experience and the time  where that was a sort of a differentiator, I I

01:24:00can just brain dump and and and it I tend to have  better results. I I will sort of secretly subtly

01:24:07uh 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

01:24:13lazy. So, it might be it'll it'll be misspelled  anyway because my typing is atrophied. So, highly

01:24:18recommend dictating. That's so that's kind of my  answer. I mostly dictating to an OpenCode agent

01:24:24or multiple OpenCode agents. I I like to use tabs  and have multiple in this project. Another thing

01:24:29I've been doing lately um is having it create work  trees for different uh right lines of work. Like

01:24:35if I have a refactoring that spans multiple files,  I'll just tell OpenCode to create a bunch of work

01:24:41trees. And it doesn't need any special feature  for that. It can just create a git work tree,

01:24:45CD into that directory, and then work there.  And then I have it open up a pull request and

01:24:49then I look at that in the browser. So you know  make a new work tree where you rename the const

01:24:54bus. Select this line here to vehicle and open  up a pull request. Yeah. And then open that pull

01:25:01request in my browser. So maybe I'll do something  like that except with an actual uh work task. And

01:25:06then we'll see that it is going to you know make  some to-dos. Okay. So do some [ __ ] So that

01:25:11that gives us a pretty good sense of your current  workflow. um as it relates to effect, how do you

01:25:18think using coding agents etc. um how does that  compare to working in a completely uneffectified

01:25:28codebase? Do you have any comparison there uh or  any intuition? I mean unfortunately or fortunately

01:25:36for myself I've been so thoroughly effectilled  for so long that I haven't really worked on a

01:25:41non-effect codebase in a while. But I I mean I was  already once again like horrified and recoiled and

01:25:46in terror to work on them before agents just for  my own productivity. Oh, something that I I that

01:25:52slipped my mind earlier which uh when talking  about the nice constraints of these things is

01:25:57that if you do not have the constraints of of a  type system just like sort of that sort of subtle

01:26:03uh pernitious tendency to when typing anytimes  there's friction like we're really lazy creatures

01:26:07right we're trying to preserve energy all the  time it takes a lot of effort to to to be less

01:26:12lazy um convenience sort of trumps everything we  we will express less now okay just open up the PR

01:26:18for the bus rename there it's very bus binding  is open. So I then would like open up the tab

01:26:23here and review it. Maybe I can leave comments and  then have the agent look at the comments. So I'll

01:26:27say in here I'll dictate what have you done? Why  did you rename this? I don't want you to do this

01:26:31at all. Actually close everything. Um so I'll add  that comment and then I will say read the comment

01:26:36I left and uh fulfill it. Anyway, it'll do that in  the background. So just as uh if by dictating I'm

01:26:42able to uh I just naturally end up being more  encompassing with all of my thoughts and I and

01:26:48I don't sort of drop them on the floor because  I'm bottlenecked by my typing speed. Similarly,

01:26:52if it is difficult to refactor a codebase, which  it is if it's dynamically typed, you will just

01:26:57simply refactor less. You might not think that  you're avoiding refactoring, but it's it's a pain

01:27:00in the butt and it's very scary. At least speaking  for me, maybe some people do love it. Obviously,

01:27:05DHH loves Ruby on Rails and I I get it. Like  there's some beauty there, but for me personally,

01:27:11that scares the big Jesus out of me. I just simply  wouldn't refactor it very much. I'd maybe like

01:27:15create a whole new codebase. And if you're not  refactoring, like why do I refactor? I refactor

01:27:20because I learned something about the code, about  the problem space while I'm working on it. And

01:27:25I want to encode that. I want to encode that  constraint in the type system and the structure

01:27:29of my code. I want to delete redundancies, sort of  collapse duplication into better abstractions. And

01:27:34I'm able to do that fearlessly with the backing  of a type system doubly triply so with a library

01:27:40like effect which allows me to encode even more in  the type system and have even more constraints. So

01:27:44I I end up refactoring more and I end up making  more beautiful codebases. So I think that just

01:27:49becomes easier to work on these codebases anyway  because they're better factored and they better

01:27:54express the domain and I can make them regular.  I can refactor so I can shape things similarly

01:27:59without fear. And the more things are consistent,  the easier it is for an agent to extrapolate on

01:28:04those patterns just as it was easier for me to  extrapolate on patterns or like a newcomer like

01:28:09because you can also think of a of an agent as a  fresh really smart fresh hire who already knows

01:28:14about you know every library in existence. But if  your codebase is a mishmash of different patterns,

01:28:19how would a new how would like a day one like  they're always sort of spawned into existence the

01:28:23second you have a fresh session. I mean whatever  module your agents.md files uh how well are they

01:28:30going to be able to perform the implicit  context of your entire codebase will guide

01:28:34them even more than the agents files. So yeah,  it's it's easier to in a library like effect,

01:28:39it's easier to refactor. Therefore, it's easier  to maintain a higher quality codebase that is sort

01:28:43of made consistent and then agents will sort of  extrapolate on that better. And because of this,

01:28:47the regularity, the self similarity, the fact that  each of these files look the same, I could open up

01:28:51five parallel PRs, something basic obviously,  and I could sort of scan over it and just the

01:28:58patterns if there is an aberration, an anomaly if  you will, that'll become that'll be immediately

01:29:03evident just by almost the structure of the  code itself. Like one thing I can do is let's

01:29:08say in here like I I can start from the interface  basically. I can have a uh I can make it sort of

01:29:14a to-do interface and and I can I can hand type  this if I feel like hand typing it. I could I'm

01:29:20at this point sometimes I actually do mistyping  because uh and I try to do a little bit to b make

01:29:26asy diagrams. You saw me do a little bit of that  during this this uh this this talk. I used to do

01:29:30this a lot when I was doing live coding. it it can  be even more compact sometimes to express things

01:29:36diagrammatically in in you know ASCII. So I might  just be able to say like okay what what do I want?

01:29:42I 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

01:29:49could describe it as the interface. Sorry. No, the  way how I think about it is like whatever is like

01:29:54the highest signal noise ratio that you can sort  of like give as intent to the agent like just use

01:30:01that. Sometimes it is like you copy pasting like  the old code and the new code you know exactly

01:30:07how you want the new code to be then just write  it out paste it in say like hey let's make this

01:30:12happen everywhere consistently. Uh, and sometimes  it's like a little uh like a little scribble on

01:30:19like a piece of paper and like I airdrop the the  picture into the coding agent and say like, "Hey,

01:30:25have this idea for this better architecture. What  do you think?" And like whatever is like the the

01:30:29best signal like I I think the the mental model  I like is what if you would uh show something to

01:30:37your like favorite colleague who's like very  experienced like immediately gets everything

01:30:41without you having to explain everything. and you  what is the thing you tell them and I think that

01:30:48works pretty well for for coding agents and uh  that I I love the the idea of like doing something

01:30:55at a speed of thought and I think now we now we  can yeah it's it's uh it's pretty fun obviously

01:31:02they can go off the rails and do all sorts of  crazy things so like I don't foresee myself being

01:31:07taken out of a job anytime soon but I can I can  definitely by using them often you get a sense of

01:31:12what their limits are and those bound boundaries  are always shifting. I mean, I've been using

01:31:15them maximally since they first came out and you  know, the first version of it was called Codeex,

01:31:19right? The autocomplete model and I ran it in  Jetbrains. I was doing some pretty complicated

01:31:24type level stuff in Scala and it it it was able  to extrapolate and like auto I could tab complete

01:31:30and it would do the next arity of the the method  or whatever or it would it would it would fulfill

01:31:34some pretty interesting patterns that weren't  just boilerplate. So I think I think there is

01:31:39something about the models where they are really  good at logic programming and and these kinds of

01:31:43sort of mathematical patterns and they deal well  with types right I mean because whatever the curry

01:31:47Howard isomeorphism types are logic etc. They seem  to be pretty good at this at this domain. Uh and

01:31:52my experience has borne that out. So so yeah what  I might do in this case is just yeah let me let me

01:31:59uh maybe I would have just dictated this to make a  new effect to do interface. But sometimes it could

01:32:03be fun if I do want to be very specific. I could  do this iteratively like now that I have this

01:32:07file I could say um just turn these into actual  functions on the interface please uh effectful

01:32:12functions and we'll see what it does. Uh it should  be able to do this pretty quickly and then once it

01:32:18does uh yeah maybe it'll look at other files. Oh  it's it's loading my whole effect skill because I

01:32:23do have an effect skill that tells it to look at  the effect. Speaking of that effect skill is that

01:32:27public? So this there is one in the codebase  that it found actually if I go to effect seal

01:32:32and it's very basic and it just basically says do  clone. So obviously I'm sure you've mentioned this

01:32:37trick before in this podcast but if not clone  the effect v4 I'm using effect v4 in here. So

01:32:43that's effect small uh under the effect-ts uh or  clone that somewhere and just tell the agent to

01:32:50look at it. Right. Yeah. I I [clears throat] think  that's one of the most reliable patterns not just

01:32:56for effect but for like any uh any technology that  the coding agents might not be like born with yet.

01:33:05And I I think that's that's a great uh a great  concept or a great method to embrace. However,

01:33:13I do think that it's still worthwhile pairing that  with a skill um particularly to show very specific

01:33:22usage oriented patterns and maybe your preferences  since like effect is uh such a wide ecosystem.

01:33:31Sometimes there's multiple ways to do the same  thing. So for example, if you want to build an

01:33:35HTTP API, you could do it over RP over effect RPC.  You could do it over the effect HTTP API module.

01:33:44You can also do it like more lowle. And maybe you  have certain preferences for your codebase. So I

01:33:51think being in the effect skill being it making  it more yours being more specific about like

01:33:57hey other people might be doing this but we we're  doing this here like writing this out concisely.

01:34:04I've had good success with in for for the for  my own effect skill. Yeah it's not it's not

01:34:09we don't do anything too complicated. It's mostly  like agents files. I think the skill was recently

01:34:13added. Um in the agents file I do have some  basic things like use Effect.gen use Effect.fn

01:34:21etc. Like use date time instead of new date.  There's some basic things, right? If if you see

01:34:27the agent making a mistake a bunch of times, just  throw it in your agents file or ask an agent to

01:34:31make that change. May maybe one other topic before  closing out. You've mentioned that you're using

01:34:36uh effect 4 or effect small as it started and  still called this way at least of as of today. Um,

01:34:43did you start the migration with effect 4 right  away or did you start with effect three and like

01:34:50upgrade it to effect 4 at some point? No, I I you  know laser less rule. I just I just went with it

01:34:57um the the beta version. I think I asked Dax, oh,  you know, it was it was still pretty early on, so

01:35:02I was afraid. I'm like, uh, there's a beta version  that just came out. Should uh I can use the old

01:35:06version. What what would make you feel the safest?  And Dax did not uh did not flinch. was like,

01:35:11"Yeah, just use the use the beta version." What's  your experience with Effect 4 at this point? Or

01:35:16do don't you really have like too many reference  points to to the old version? It's it's I mean,

01:35:21the agents do great. Um I think there were a  couple of naming flips that went back and forth.

01:35:25The like everything just works so well. I forget  what really ch it's pretty seamless. Obviously,

01:35:30the bundle size has been improved. Tree shaking  is improved. Uh schema is improved. But so so

01:35:38far pretty seamless. I like Context.Service.  I use that all the time. Uh it's better than

01:35:44what was it before? Context.key, I think, or  context. I think it was Context.Tag was before

01:35:49and effect. Yeah. Finally, we're we're we're  going to simplify things. Yeah. I think this

01:35:55is temporarily service map, but got shifted back  to context, which is great because that's that's

01:35:59a good metaphor from the React world for how these  things propagate. Um I wouldn't even mind somehow

01:36:04magically having it be service, but this is fine  or effect. Uh yeah. No, I mean it's barely noticed

01:36:10that it's a beta. There were a couple of those  naming changes, but I think those have mostly

01:36:13uh landed. It's great. I mean, it it's mostly  the same API as as V3, just better internals and

01:36:19uh yeah, a whole bunch of small breaking changes,  but for the those those methods that were being

01:36:24hit all the time or whatever, the paro principle  methods, it's not too different of an interface.

01:36:29I can't really recall anything off the top  of my head that's dramatically different.

01:36:33So you've been showing off uh a bit of OpenCode  here during this demo and I think it it really uh

01:36:40showed off like what an amazing workflow can look  like particularly when paired with an open editor

01:36:47that's integrated now with said and maybe also for  for other editors um also what you've shown with

01:36:53voice dictation which I also use heavily uh I'm  curious what is coming up for for OpenCode as it

01:37:00relates to effect or maybe as it doesn't relate to  effect. What are what are you most excited about?

01:37:06Yeah. Yeah. So, definitely a thousand different  things. Uh yeah, I've been mostly working on this

01:37:12effect migration. I did some other fancy uh  things like on the weekends. Now, if you hold

01:37:16click and hold on the OpenCode logo, [laughter]  boom. Uh make some different fun effects. Uh

01:37:23there's some other animations I snuck in there  on secret screens. Uh, we have the desktop app

01:37:28that I added some animations to, but that's kind  of being refactored at the moment as well. So, I'm

01:37:33excited to get back to some more product work. I  did just recently add this Zed integration uh and

01:37:39and my co colleague uh James Long, who is known  as the uh well, I don't know if he's known as it,

01:37:46but I'll tell you he's the he created prettier.  He's sort of working on some stuff right now with

01:37:50regards to work trees and workspaces. So, you can  I don't think I have this set up locally. It's

01:37:55still 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

01:38:03had him on my other local first podcast uh quite a  while back and I'm very excited for you all to to

01:38:10have a chance working with working with James. Oh  yeah, he's great. We just we just hung out for a

01:38:14week in in Miami uh the whole team or most of the  team which has been was just really fun. But yeah,

01:38:19he's great. You should definitely have him on  at some point. He's you could learn about his

01:38:22effect journey because he's kind of new to  it. But I think he's he the pills have taken

01:38:26hold after some time. So he's working on a bunch  of stuff with regard to syncing and workspaces

01:38:30that I think it'll make it really nice because  generally each OpenCode instance right now is

01:38:34while there is that server client architecture  if you just run it naively like this it's kind

01:38:38of all encapsulated. It's it's serving it's not  even exposed. It's internal to the process. So

01:38:43there is the server server client architecture  but it's not necessarily used in this case.

01:38:47You can start it as a you can do OC serve and just  start it as a server and then connect to this from

01:38:53other clients. Some companies like I think Ramp  famously has built a whole bunch of its internal

01:38:58uh agentic tooling off of OpenCode using this this  feature. Uh one thing that I really want to have

01:39:04that James' work is going to be a foundation for  is that like basically OpenCode server can be this

01:39:08control plane can be like a demon process in your  computer and all the clients just go into that and

01:39:13that'll help with things like memory usage because  instead of having multiple servers it'll just be

01:39:16one. Similarly whenever you run Claude Code like  each time it's starting a uh it's starting its own

01:39:21server process and you you see the screenshots  on Twitter whatever of like 27 different Claude

01:39:26Code or OpenCode processes. Um so that that'll be  really nice as a user experience and to be able

01:39:30to sort of switch to different uh sessions. Yeah,  I just want to get back to product work. I have a

01:39:34thousand ideas. I wanted to first get this effect  infrastructure like I don't like refactor as as

01:39:39I sort of I think I've expressed a few times I'm  terrified of refactoring uh non-effectful code or

01:39:45making dramatic changes to it. So once everything  is beautiful perfect self-similar fractal effect

01:39:51perfection then I can I'll probably make a second  pass sort of embracing uh pushing it even further

01:39:57really making the most out of typed error messages  etc. And then once I'm super happy I will add a

01:40:02bunch of features. So something I I really want  to add that I have a bit of a few spikes exploring

01:40:07is background sessions. Sorry, background agents  and background bash tools. Vision's pretty good

01:40:12at dealing with that anyway, but right now if I  have if I have it spawn multiple sub aents, it it

01:40:17blocks the main session. You can get around this  with plugins, but yeah, basically making the the

01:40:22SDK nicer and also uh some of those some of those  little uh paper cuts like a really nice experience

01:40:28for for that. There's there's a thousand other  things that everybody else is working on, but uh

01:40:32those were sort of my own um little pain points  that I want to address after the architecture is

01:40:38uh crystalline uh scintillating apogee of of  types. Yeah, I'm I'm particularly excited for

01:40:48OpenCode to be open like that other people can  learn from it like follow the journey. Now we

01:40:55probably OpenCode is probably like one of the  largest codebases that has migrated to effect

01:41:01or is in the process of migrating to effect and I  think that gives you a really great like reference

01:41:08how you can do the migration what a full fully  effectified codebase looks like and thank you

01:41:14definitely also for that. Yeah I know leaving  off here on a on a great cute demo. What are we

01:41:21looking at here? So, so [laughter] uh um my other  colleague uh Sebastian known as KMDR commander

01:41:29I call him because I call everyone by their uh  their I guess Twitter handles because that's what

01:41:33my brain sort of brings into my uh awareness uh  primarily is is he added this plug-in capability

01:41:40to OpenCode. I mean it's been there always but  TUI plugins that can also interoperate with server

01:41:45plugins. So uh when I when I now prompt it will  its eyes will glow. This is goblin mode. Sort of,

01:41:50you know, I decided to make a novelty plugin based  on the uh the trending meme of of GPT's goblin

01:41:56issue. So, this introduced obviously I said tell  us tell me a story. You know, it injects something

01:42:01into system prompt to to tell it to, you know, not  shy away from its uh innate love of goblins and

01:42:06raccoons and such. And then when you're typing,  it'll add this little beautiful it looks like a

01:42:10cat, but a goblin animation here. Uh so, pretty  stupid, but you know, it's it's easy. I prompted

01:42:17this with like three pro prompts and it made a 2  plugin for me. So I can I think there's a way to

01:42:22get um yeah plugins here and I can disable or  enable a lot of the APIs. The UI is actually

01:42:28built on top of uh plugins now. So we're trying  to make it even more pluggable which is a fun

01:42:32thing to have. But anyway, that was I just thought  I'd throw that up in the background for silliness

01:42:36as we as we leave. But yeah, it's an honor to  uh be able to contribute back to effect and to

01:42:41be part of this thing. I mean it's if I haven't  expressed it I want to express one last time like

01:42:45effect systems are [ __ ] perfect and and there  it fulfills the whatever the the the criterion of

01:42:52being 10 times more uh powerful and just better  than the competition. Like promises are junk.

01:42:58They're straight hot garbage. Programming is in  this sort of uh it's this this local maximum that

01:43:03it's been is hanging around in. And there have  been better ways of programming that have been

01:43:07sort of embraced in these niche languages which  were too weird to to sort of uh penetrate the

01:43:12mainstream. And bless uh the Italian uh vampire  Michael Arnaldi, the true creator of effect,

01:43:19I I'll say it uh for for bringing effect into  Typescript because it it has allowed it to be

01:43:24viable. Um and one thing I like to think a little  thought experiment is that every language where a

01:43:28type system an effect system was introduced in, it  did become the dominant uh way of writing in that

01:43:34language. Um, never before has it been introduced  into something as ginormous as as TypeScript,

01:43:38but I I I feel like we're on that hockey uh stick  growth curve. And it's it's just better. Like I

01:43:45don't we don't need to really pitch to anybody. We  need to like tantalize them with some ASMR [ __ ]

01:43:49But they'll realize uh either by the quality I  hope to make OpenCode so much better and so much

01:43:54more reliable and and memory efficient and fast  and delightful to iterate on as everybody else

01:43:59sort of just uses agents to write JavaScript slop.  they'll become uh they'll be weltering in their

01:44:03own slop and we will be uh you know iterating in  our golden crystalline palaces in the sky made of

01:44:08pure uh thought. Uh that's that's the idea that  we can like really show the proof in the pudding

01:44:13uh by covering ourselves in pudding and running  out into the streets naked and then all of us

01:44:18everyone will join in in the pudding party.  Beautifully said. Well, Kit, it's been a true

01:44:26pleasure uh having you on the show. We've spent  quite a bit of time together. So thank you so

01:44:30much for for giving that to to me and to all of  us here and sharing that journey how you came

01:44:37to effect how you're effectifying OpenCode and  can't see to to see where this goes. [music] I'm

01:44:44I'm super excited. Thanks for having me on. Thank  you so much. Take care. Bye. Peace. Thank you for

01:44:50listening to the cause and effect podcast. [music]  If you've enjoyed this episode, please subscribe,

01:44:55leave a review, and share it with your friends.  If you haven't done so already, you can join our

01:45:00Discord community. And if you have any questions,  feedback, or suggestions [music] about this

01:45:04episode or about effect in general, don't hesitate  to get in touch. See you in the next episode.

01:45:25[music]

01:45:25[music]