In Effect, there are two distinct error channels: expected errors (tracked by the type system) and defects (untyped, not tracked by the type system). Expected errors are recoverable failures that are part of your domain and can be handled by your application, such as HTTP API errors where you want to provide users with contextual information. Defects are unexpected failures that your application cannot recover from and should crash the program, such as internal server errors where you want to preserve failure details for debugging without exposing sensitive information to users. When defining service shapes, if you find errors related to implementation details leaking out, you should either wrap them in service-specific errors to hide implementation details or use effect.orDie to eliminate them entirely.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
Effect Office Hours 28 🔥Added:
We are and YouTube as well. Nice, nice, nice, nice. [sighs] Hello effect enjoyers. Do welcome back.
Welcome back to another episode of effect office hours. We took a break last week, but we're back.
What is good everyone? [snorts] So everyone is good it seems. Um we let me open up the office hours chat. And I also say that I just written that right before starting. But as always um if you have some question you want to ask or if you have some code snippets some G or some repo you want us to have a look at as always this is the best time to do that. So, I encourage you to grab your GS and your repo links and post them in our office hours channel over our effect discord and we'll have a look at the at that today.
Um, in the office hours channel, Edgar Boon asks, uh, I saw a tweet by Michael that was about two error channels in effect. I mostly use effect.fail fail. But when is effect die more appropriate? For example, when when there's a required config value missing, I bubble it up to be handled as an HTTP API error internal server error. This should probably use effect.d die, right? Or am I or for missing column during a DB query? Um, that's a good question. So, uh, for people who don't know, um, there are two error channels in effect. There's one that's tracked by the type system, which is the, um, error channel in the effect type, and we call that it's got a couple of names, but I think probably the most common way we refer to it are like the expected errors from your program, like the things that your program can actually handle and recover from.
Um, and that's why they're tracked by the type system because they're part of your domain.
They're things that your application can actually react to, uh, recover from or things that you might want to like Yeah, exactly. Like information you may actually want to provide to your user.
So for the situation that Gerbun mentioned about like an HTTP API error, um most of the time your API errors are probably going to be typed errors, things that you track as part of your domain because that you know you want to be able to give your user contextual information about the failure that occurred. Um, but there's also another error channel in the in the effect runtime which is untyped, not tracked by the type system. Um, and we call that kind of like the the most common way we refer to it as a defect or an unexpected error. Um, and that particular error channel is really designed for failures that your application cannot recover from or that were unexpected, things that should crash your program. So again, going back to the example that Gerboon posted, usually, you know, the the defect, I'll call it the defect channel. There's probably a better name uh that we could use for this, but for now I'll just call it the defect channel. Um, you know, for defects that occur in your program, um, you really want to reserve electing things to defects in your program if your application can't recover for them because you really you you lose a lot of like some contextual information that you could be providing to the end user of your of your code.
So going back to Garbun's example, if you have like a defect that occurs in your HTTP API, probably the most appropriate thing to do at that point is to just raise some internal server error to the user. Uh and then maybe you know have a tracking ID or something like that that you can give to the user related to the error that you also have on your end. And on your end you you preserve all of the failure details like the stack trace and like all of the other things the cause of the failure etc. Um telemetry information things like that. Yeah exactly because you don't know what caused that failure and you probably don't want to let that information leak out into you know user land because it could there could be sensitive information there could be things about your application you don't want to leak out. So um I'm using that particular example from Gerboon, but usually expected errors, the error channel in effect, those are reserved for things that are part of your domain that you want to actually be able to handle in your code.
Whereas the defect channel is for things that your application cannot recover from, things that should um really actually cause like a runtime exception like in your program.
I would also say in summary in summary only use effect.or or die because there's a hat for that. [laughter] Exactly. Very very limited edition hat but there is the G1 this is the first I think it was the first merch that we created. I think so as well. Yeah.
[snorts] So um but that was a good question. Yeah. I would also add that um you could also one should also considering lifting typed failures to defect also when you reach a point where either you expected that specific kind of failure to be handled previously and if that kind of failure reach that point for example due to retries failing or something like that that's a good point where you can use effect or die mentioned to basically get away of that uh typed channel error because at that point you basically say yeah I would have expected the retry to like keep care of that end typed error and if that didn't happened uh okay well uh that's something really odd and that's why we call that a defect and also one other thing that I would just add which is not strictly strictly related to the question uh but it's kind of the in the same like um argument I would say is also that we always speak about services leaking requirements leaking like um dependencies in the methods um that are dependencies of how a service is actually implemented behind the scene. But the same also applies to errors when you define the shape of one of your services. If you find out that you are basically leaking out errors that are related to the implementation of the service, you need to ask yourself two question is one is probably I need to wrap that error inside of specific error for these services because that way I can hide away that specific implementation. And the other thing again is if I don't care about that error happening in here and for this specific service behavior probably it's just better to just say or die and get rid of that specific kind of error.
Hang on one second. I'm getting a phone call that is blocking my ability to hear anything.
Okay. Yeah. Hope um yeah, I I agree with uh the additional points that Matia made. Those are good points. Um there's another question in the office hours channel. Um maybe I can put the code up on the screen. Hang on, let me get Zoom in.
Yes.
Okay. Uh maybe before we go over this code, it looks like garbon had clarification. An issue I have that I'm an issue I an issue I have is that I'm nesting errors and their causes which don't print print pretty to the logs. How can I track the error better? Uh when you log the error um with effect if instead of logging the error directly like doing a tap error and logging the error if you tap the cause and effect.log or effect.log error is probably more appropriate here. The the cause you'll get a a pretty printed version of the cause which should traverse the like cause properties on the error. So you'll get like a better stack.
What type of log would that be? Because I think Matia, maybe this is relevant to you.
That would have say on the format.
What type of log would that be? Because I think that would have a say on the format. Trace versus war info logs. Oh, probably it's related to what you have just mentioned about logging the error that yeah it depends. Yeah, probably if you want to log more deeply probably you can use like trace logs and if you want to log just the error that happened probably you can just log error that one but again depends on how visible are your logs I would say.
Yeah, I think personally I would be leaning into log error if I have a cause that I'm trying to print. All of the effect.log methods will attempt to pretty pretty print a cause if they see one.
I'm pretty sure. Mhm. Uh at least with the default implementation of the logger, we always attempt to pretty print a cause. Um, if you have a custom logger, you'll need to probably do a little bit of extra work, but you can look at any of the loggers we've implemented to to see. And in V4, like building your own logger and adding loggers to your program is much easier than it was in V3.
Uh, are there some resources on logging or traces in effect other than in the docs? Cloning the repository and asking your agent [clears throat] for for now. That has become the go-to. [laughter] I'll be honest, there are times where, you know, keeping the entire FI code base in your brain at the same time when you're like even as a maintainer is not possible. No. Uh unless you're maybe Tim. Uh and so I frequently have just like pop open a a session with the clanker and we'll ask it questions. Uh or we have a special like command that the maintainers can use in Discord that basically does the same thing like allows us to run a user's question through AI to help give us context and we can like spit out the answer. So you may have like seen every once in a while the effect bot answer a question. Um and that's one of us triggering the AI to do that.
Um because if we're not at our desk and can't like pop open a session or whatever, like sometimes that's a little easier. But anyway, so there are two questions about this code. One is I was surprised to learn that Random.nextUUIDv4 doesn't use crypto, but rather a custom implementation. How secure is it to use on a production environment?
Well, uh the random implementation in B4 actually let me do uh this so I can split terminals.
Uh small scratchpad.
It's not what I wanted. Random.nextUUID. So this is what Spitty's talking about here.
Um we have a custom UUIDv4 implementation in the V4 codebase. Um so asking how secure is it to use in production. Um I think we have a pretty robust implementation of uh random number generation in V4. We used um a cryptographically secure random number generator.
Um it's a it's a new implementation from V3 to V4. So, there's a uh a CSPRNG cryptographically secure random number generator um called Isaac uh maybe I can pull it up even hang on. Um that we used that I based the V4 random on. Let me Oh my god, I have like too many windows. Uh Isaac, I'll open I'll I know I'm not showing it. Give me one sec. PS pseudo random number generator JavaScript.
Meanwhile, a new word has been baked. Wed effects day. W effects day. Wed effects day. Wed effects day. Love it. Uh, give me one second. Stop sharing screen. Entire screen. Share. [snorts] Um so Isaac is a cryptographically secure pseudo random number generator meant to be used as a stream cipher.
Um and the effect v4 random pseudo random number generator is based on the Isaac uh implementation from this repository actually. Um and so I think the random number generation is as robust as it probably could be. We could I mean could probably be like it could always be more robust but you know the question of like using crypto versus um our custom implementation um I don't really know how to answer like I think it's robust I think it's robust enough to use in prod but um obviously like if folks find issues or anything like that please let us know open up um issues in the codebase and we'll address them uh but this is the pseudo random number generator implementation uh that I used for the V4 random implementation or at least the default random number generator uh that you get in V4. Um and it's it's because it's a tiny bit more flexible than what we had in V3. And um yeah, why didn't we use crypto? Uh there were a couple of reasons but mostly to avoid depending on a platform specific thing that may not exist on certain platforms. So crypto is available in the browser. It's available in node but I think does node crypto have a UUID generator? I can't remember. It does. And I know the browser does too, but um I think React Native doesn't have one if I recall correctly. Yeah, the the whole point was to avoid us relying on a global that may not exist in certain platforms. I mean, you see like if you look at the V3 codebase, like there are tons of issues open for like platform specific things. Even on V4 now, we've already got issues being opened about, hey, you're using something that's not present on this particular platform. So, it's like very hard to design a library that is uh especially one as big as effect that's that's designed to kind of like be [snorts] totally platform agnostic. So, um to avoid uh us shooting ourselves in the foot, that's why we built our own. Um, and then I guess there's another question about the actual code here. Let me see. Um, calling yield workflow.execute in a program doesn't register the workflow in any way in the effects requirements. This means you have to remember to always register your workflows and there's no type safety around that. So you'll only learn that you forgot to register a workflow when it is first executed. That's quite bad for production environments. Is that a bug or is it something not yet implemented in workflows? Maybe I'll let Matia answer. But the the I remember that I remember that. Yeah, that's that's the cool part. I remember that the initial implementation that also team did had that feature of adding into the requirements the workflow uh that you execute being basically provided. Um, but I also recall that meanwhile that sounds great in uh theory, I remember that there are issues. For example, if you have workflow that trigger and require one another or things like having to always manually like propagate them wasn't like awesome. Uh I don't recall the exact reason why it was dropped that feature but I recall that that was exactly the way it was designed initially and then it was removed as a feature because it was more in the way than it was actually useful. But again, if you care about that, um, you can always like wrap your own execute function around that if you care about that and provide your own type typed dependency if you if you want that. But I am almost sure that that was mostly due to the ergonomics not being like awesome with the fact that you always had um an handler for uh the workflow.execute execute and also that doesn't mean for example if you have a workflow engine that invokes some like um you can have you can basically trigger workflow.execute execute with the workflow engine as a dependency. But maybe the actual implementation of the workflow lives on another server and that would have mean that um if you add that as requirement that means that you would have needed also to provide fake implementations for um the yielded execute. So it's kind of like splitting the idea of having a workflow engine that just knows how to trigger workflow and another thing instead is the actual workflow engine where the workflows lives. I think that this gives you more insight of why that wasn't the case.
Yeah, I mean if [clears throat] it's something that you feel strongly about, if folks are using workflow and they think this is non-intuitive, uh feel free to open the issue.
And I mean Tim did a lot of the work on this and could probably like shed more light on it. Um, but I think I I sort of remember what Matia remembers that like this was more of an ergonomics thing and like a practicality thing where again like this workflow is not necessarily executing on the same machine that this code's running on. So like having to provide all those requirements is just like unnecessary. But anyway, feel free to open an issue to discuss like and we can get Tim in there and sort of like talk more about uh the pros and cons of having this propagate to the requirements so [snorts] that this layer becomes required. Um and like I said, maybe Tim can shed more light on it. Um people are still talking about random number generation. Oh my god. Um, if you're curious about how entropy works with Isaac, please read the read me from this project and then you can tell me if you have horrible uh, and it does link to the um, like paper from I think it was like 2006, the original Isaac paper. Um, so anyway, uh, yeah, read this and then if you still have problems, let me know and we can talk about it. But I believe, um, the entropy source for Isaac uh, you seed your own entropy source. Um so like the I'm trying to remember the details with the particular implementation that we have you have to provide like a strong entropy source and I can't remember exactly what we do um for the default random service. Give me a second. Mhm. Uh [groaning] random current random. No. Uh context.
So this is the default random number generator which does not rely on Isaac the UUID one.
Right. Right. I remember now. Okay. Sorry. I forgot about like this whole discussion that Tim and I had. I'm sorry everybody.
Okay, backing up. So, uh, backing up the original when I first designed the random module for V4, I built it on top of Isaac as a random number generation framework and I had like a default seed value that you you provide. And then Tim and I were discussing it and there were two problems.
One is obviously with the default seed like that's not secure and two um the Isaac code was making the bundle like larger than we wanted it to be. So the default random number generation defaults to using math.random random and then you can actually provide a seed and basically switch internally to the Isaac version with with seed.
Yes. So um because if you look somewhere in here Isaac it generates 32-bit random numbers cycles are extremely long guaranteed to be at least two to the 40 values long. Yes, speaking of which, it is the responsibility of the user to seed Isaac with a strong entropy source. So, this was like part of the reason why we [snorts] didn't make it the default at the end of the day. Like this whole dis this this whole discussion we had just like left me until this moment. Um anyway, you can opt in to Isaac as the implementation of random that you use in your program if you wrap the program with random.with seed. So the seed that you provide, the user provided seed has to be a strong entropy source. It has to be like a a long string that's like random enough uh to be like a strong entropy source. And they talk a little bit more about that elsewhere in here. here somewhere uh I don't remember somewhere in here they talk about it but the default random implementation uses a combination of math.random random with rounding. And it was primarily to [snorts] one make sure that seeds could come from the user since it's the user's responsibility to provide a strong seed and two um to make sure the bundle was as small as it could be. And then the whole reason we're not using crypto is to avoid relying on a platform specific implementation that may not exist in some platforms. I saw somewhere somebody asked what if crypto was a service you could opt into in the platform solutions. Yeah, I mean we've talked about adding a crypto service to some of the platform implementations. [snorts] The trick is always finding like what the least common denominator is for a service interface. So like uh you know with file system and path and some of the other platform services you have a a a least common denominator that we can implement across a variety of different platforms. Um so the trick is always figuring that out for a service. We're not opposed to having a a a crypto service I don't think but we just [snorts] haven't done it yet.
Uh spirit going back to the workflow question. So basically for now it's recommended to register all workflows just in case. Uh I don't know. I'll let Matia answer that.
I would say that worst case that works. worst case. Um, and probably that's better. Uh, but that's not good because that basically like would leak into the the list of um dependencies that work those workflows use as well. So I would say that probably the best thing you could do is to keep aside the workflow implementation layers and also like the execution ones. So you at least try to merge them all together and be sure that whenever you require like parts of your domain that require specific workflows, you provide the actual implementation of the workflows as well.
Or again, if you want to, you can wrap the test workflow.execute execute method to create your own that taints the requirements channel with the depend the required um workflow that needs to be implemented as well but again we're open to discuss that um yeah it's an interesting topic it has I would say a lot of like different areas and way could be handled because again not all of the workflow engines behave the same and again the purpose of the effect workflow is to try to define um a shared common denominator style interface that you could potentially like bake behind the scene with different implementations of workflows. Um again you can implement thirdparty providers behind the scene just satisfying the workflow engine service but again I would say that if you maybe open an issue describing more specifically what's um it's basically like um what you would look for what have you tried and what why doesn't it work we could like open a more detailed discussion with team that has more uh insight about the choices behind that I do think it's worth uh discussing again the lack of registration of the workflow type and the requirements. Mhm.
Um I think it's worth discussing it again. So please do open an issue and we can like talk about it with Tim who's kind of like the primary architect behind workflows at the moment.
Um but yeah, I think that the current design was um I think the current design uh wait, why is the current default UUID insecure FIWS? I don't I don't quite understand that. Um but yeah, I would say like open an issue related to the workflow question and we'll talk with Tim about it.
Um, Lloyd would like a review slashroast of some code. Before I do that though, there was a question in the office hours channel about I've been using Drizzle OM which as of RC1 supports effect v4. But can you all briefly go over the difference between using an OM like Drizzle and using bear effect SQL and in particular how migrations differ and what path the effect team takes is what path the effect team recommends moving forward in terms of DX. Well, uh, effect SQL is not, uh, an OM. It is just a way to write SQL queries and, um, get schema validated results out out the other end if you use the particular modules that do that and also to get like batching and request resolveresque behavior. Um, so yeah, effect SQL is definitely not an OM and that was never the intention. So if you need an OM, I would use the Drizzle like implementation. And if you need if you don't need an OM, if you just want to write SQL, then you use effect SQL. Um, and that kind of goes handinhand with the question about migrations. And effect SQL migrations are written using SQL. And with Drizzle, I I I don't know cuz I haven't tried out their V4 uh their V4 uh implementation yet, but I assume migrations are written using Drizzle.
Drizzle RM effect v4. [clears throat] Also the migration of FXS SQL are forward only whereas probably other RMS can also provide you back and forth or like snapshotting the ideal structure of your database and then defing that about what you actually have. So that's also like a difference that you have because again FXSQL is not an OM. It's just like a way to running SQL queries.
Yeah, I don't know how uh migrations work with Drizzle, but I assume it leans into the OM. So that's the difference. Migrations are written using SQL exactly like the previous Drizzle versions, just the structures changed a bit. Yeah. So I guess the decision on whether to use effect SQL or Drizzle, it comes down to whether or not you want to use an OM. Personally, if I'm writing a large application, I think I would probably use the Drizzle. Um, because I kind of like the OM style, but some people might prefer just to write plain SQL, especially now that Drizzle's OM is is so speedy. Um, but anyway, yeah, sorry. Go ahead, Matia. It also depends if you want like to take particular advantage of particular features of the backend database that you have behind the scene because usually like OMS trade off that uh for like an unified interface and instead if you have maybe a use case where you want to leverage 100% of the optimization that a specific uh SQL engine could provide you by choosing some particular trade-off or SQL instruction that you need to inject into the query. for opting into those. Well, obviously an RM does doesn't give you that. So, it's more like a domain choice rather than an actual like a domain technical choice rather than something. It's good to use that and not that one, I would say. Yeah, depends on use case. Again, as always, let me crack open. Where did my browser go?
Hold on. You probably went that way.
So, this is the two things that Lloyd wanted us to look at. Okay. Get the chats back up. Um, so what did Lloyd say? Lloyd says, "I've been doing a decent amount of work with prompt.custom custom in the V4 beta to build out a bunch of custom prompts based on my exploration of effect small. But if you would like to roast my implementation and give any pointers you see on how to improve the render cycle, uh that would be good. This I guess is this file is the first couple of experiments. There's a scratch pad on this repository you can use. This repository has the production versions with six different form components here. So, you got the text area, the text input, the select, the multi select, horizontal select, and confirm. Would also love to know what prompt.custom was intended for, and if I'm using it correctly. Uh, okay. Um, before anyone roast you, please increase the font size. I will. I will. In fact, I'm just going to clone the project. Clone repository. Okay, that's good. Uh, new window office. No, office hours.
Uh, get clone.
Okay.
Uh there's a question in chat while this is loading. Is there a way in effect SQL to declare tables from effect schemas? No. Again, that's not an RM. So that's more like an ORM would do that.
As Maxwell mentioned before, there are just ways to perform a query and then take out the output of the query and use a schema to decode the output of the of that query into what the schema does. But that's not an describes table as objects. Again, has anybody ever seen the original Santa Claus movie like with Tim Allen, whatever? Uh there's this scene in the Santa Claus where Tim Allen uh when he first is doing like the Christmas deliveries, he goes down the chimney and uh there's this little girl sleeping on the couch and uh I forget I forget what he what happens the first time, but he tells the little girl that he's lactose intolerant. And then the next year when he comes back, he drinks the milk and he's like and the little girl goes, "What's wrong?" when she said you were lac or you said you were lactose intolerant and I don't know why but I just got like that scene flashback for when Lloyd was like I added a NYX flake for you this time [laughter] cuz there's a flake in the project this time. Thank you very much Lloyd. I appreciate it. Uh makes my life easier. Um let's take a look. So um packages where was it? scaffold. Uh, it was into the scratch. It was into the scratch pad. There was 07 text prompts. Oh, it's a different project.
Hang on a minute. Got to clone this one too, Lloyd. Oops. Monos. [laughter] Uh, good. Hold on.
See the effect just blindly during allowing installing malware on my machine. Yeah. What could go wrong? I don't know what could go wrong. Actually, uh, speaking of what could go wrong, I'm going to run a PMPM install in a second after I scan.
I'm like so paranoid now about installing any project on my machine. It is so scary.
This looks fine.
Here we go. This is the moment that Max installed the worm onto his machine. [snorts] That's And that was the last time they saw Maxwell online. Stream stream immediately cuts [laughter] out. Exactly. [sighs] H It's not funny, but it is. Um Okay.
So, [snorts and laughter] um Lloyd wants us to look at uh Why is it why are we getting Oh. Um, so one of the questions I think Void has was would also love to know what prompt.custom was intended for and if I'm using it correctly. Absolutely. Hang on.
Uh, [snorts] let's look at your implementation. So, uh, this is a box input using prompt.custom. Prompt.custom. It takes two for those who are not aware prompt. Custom takes two arguments. The state uh which can either be like the actual state pure like a the pure initial state or an effect that resolves to the initial state and then a set of handlers for the different states of a prompt. Um and so what is the state? Oh, also before people start asking, we are speaking about prompts for CLIs, not prompts for agents. Just to give some context. [laughter] Good call. I'm uh anyway, so let's take a quick peek through here. We've got the process method, we've got the clear method, and we've got so on a prompt. Again for those who are unawares uh there are three handlers you have to implement. There's the render method which gets called um when the current state has been processed. So you get like the state and you get the action that you're now trying to render. Um, so the action could be like a beep, which is our way of saying like the to do like a it semantically maps like in your brain to a the terminal beep sound, but you can do whatever you want here. So this is like kind of like you've done something invalid.
You've clicked an invalid button. Um, and and to be clear, prompt.custom Custom is designed sort of like as a state machine where you're you have your initial state. [snorts] You process that state to return an action which then gets rendered by the terminal. So this is the render method. But if we scroll down again, here's the process method. And then clear is a special case for um like when you want to actually clear all the terminal output. But if we just focus on process.
So you get the initial render based on the initial state that you've provided and then you capture user input. So every single time the user inputs something process will run and then you'll end up rendering the next like state, right? So you get the user input and the current state and then you do something with it. So in this case, uh, we've got like handlers for backspace, left, right, enter. Maybe we can even look at this. T-Max new effect boxes.
Oops. Text. Uh, this is effect. Can I just run it with node? Is this ESM only? Yeah, I think that it's uh Nope. Okay. Okay.
TSX notbound. Lloyd, how am I supposed to run this? Uh, PNPM scratch- run equals 7. PNPM scratch d-run equals 7. Run equals 7. That what Lloyd said. Thanks. That's how that's how you install the malware. So that's how [laughter] that is how the malware makes it onto your system. [gasps] Lloyd Lloyd, the attack is complete. You you now have root access to my MacBook. Um so uh to be clear what's happening right now, we've rendered the initial state. So this initial state behind the scenes by prompt.custom, there's a few things that happen.
And then we enter this render function [snorts] which has the state and the action we want to take. So uh the initial state is what we're doing now. [sighs] Um and most likely the action is next frame. I can't remember. Uh but anyway we we're we're rendering we're doing the initial render.
And now when I type something process would get invoked. So if we type I don't know let's type a character uh here if we have input and the input length is one then we do some stuff and then in this case Lloyd is rendering the next frame so let's do max is my name um and so again every single time I type something we get we render the next frame which comes back up to render we have the current state and the action. So, we're rendering the next frame. And so, basically, you have this like it's almost like a game loop where you have this like action and render like loop going on. Um, so it's not super complex. Um, back to end curses. Lol. Indeed. Um, and then I guess you know you can move around. Enter to submit. What is my favorite food? Pizza. No, pasta.
Hello, Max. Your favorite food is pasta. Indeed. Indeed. We were just in Italy. So, in fact, we can we can do uh there's a type of pasta. Yeah, there's a there's a actually is that the correct way to spell it, Matia? I'm pretty sure it is. Uh oh, that's that's a good question. I think it was Yeah, it should be one. Yeah, it is one one C. Yeah, in Sienna where Mike is and Migella are from, there's a particular type of pasta that's like and native to that area of Italy called pichi. Uh, and it's like very thick noodles and it's so delicious and there's a bunch of different ways you can make it. Anyway, every time I go there, I just eat peichi the whole time. Um, so I guess getting back to Lloyd's original question, is this the way the prompt custom is intended to be used? Yes, definitely. Uh this is absolutely the way that this is meant to be used. Building your own prompts on top of like the internal render loop that effect gives that the um effect CLI prompt type gives you. Um so Lloyd has definitely look it looks like you've done quite a bit of work. Um I really like the box output and everything. [snorts] It's very nice. Um let's do something else. Let's look. I want to look at the log viewer.
Oo.
Can I like Can I like trigger logs, Lloyd? Can I like uh How do I How do I fake the log stream? Don't call them noodles. Don't call them noodles in Italy. I'm trying to like cater to the, you know, international audience we have here. Okay, I'm you may not believe it, but I am Italian as well. So, I know that noodles is absolutely not the correct term, but I need We're speaking to an international audience here. Press a key. Press Press a key that's not enter. Got it. [laughter] Yeah. Oh, okay. This is cool. That's nice. I like this.
Very cool. Um, yeah, prompt.custom is definitely meant for this kind of thing. Uh, building your own prompt like render loops. Um, so this is very nice. I like it. Very nice. Lloyd, what is this? Pearl and flow field. Okay, we got to do that one now. [snorts] Okay, this is sick.
[laughter] Little bit of parallel noise. Yeah, maybe we should Yeah, exactly. Maybe we should restart we start that with a wider screen. I just want to make it a big mess and then let it keep going. [laughter] All right, fine. I'll I'll restart it with a bigger screen.
Very nice colors.
Why is it glitching? Are you talking about the uh the flicker?
Like that flicker? Is that what you're asking for about [sighs and gasps] anyway? Yeah, they're not noodles. It's like, you know, spaghetti or pot.
It literally is peichy. Like the type of pasta is peachy. I don't know what [snorts] you That's the name. Yeah. So, how am I supposed to describe that in a way that makes sense? I don't know. Yeah, the flicker. Uh, that is um I think just like a somebody can correct me if I'm wrong, but I'm pretty sure that's just like a limitation of the terminal. I'm pretty sure that open code and clawed code have recently solved this problem, but I didn't want to spend many engineering hours trying to figure this out. Uh, so you get what you get for now, but but uh open to PRs. So, um, cool. No, this is great, Lloyd. Um, I think the the custom prompts are really nice. What was the code that you wanted me to roast the components repository in the other project? Uh, let's see. I think the flicker is from the clear line command. I've tried before to just move the cursor and keep typing. It's a UI hint, so you know the app is still running. [laughter] It's not a bug, it's a feature. If you were if it was too smooth, you wouldn't know. Yeah. No, I mean, there's definitely ways that it could be optimized. Uh, so if anybody wants to open PRs to help us make it better, feel free. Stack effect main apps CLI source components. Okay.
Absoli source components. Uh maybe we start with confirm. This seems simple enough. I have to install things. Oh god.
Okay, I'm not I'm just not going to install. I I'm too scared.
Components confirm.
Okay. I mean, I'm not I'm probably not going to have a tremendous amount to say here because I think that a lot of this looks like it's your own boxes uh code, which seems pretty like seems fine. [snorts] It seems like very good models. Yeah, I like that it has a similar model to the old um unseen. Now, what was the what was the effect printer Yeah. I I don't think I've ported that to V4 yet. I don't know if I'm going to port that to V4, but um I like that it I like the uh programming model of like building up a box this way.
Let's see. [sighs and gasps] Uh, if you wanted to, this could be an effect. FN, I think.
Also, I don't know if box has like a effectful render methods, but you could then just do that.
What is everybody saying? Effect printers blocking adoption of V4. 99% of [laughter] people 99% of people are blocked upgrading to V4 because of printer. Did you guys know, [laughter] man, that really got me the last time we did office hours? Then when I saw Drizzle release their V4, uh, the first thing I thought about, I forget the name of the user who said 99%. But, uh, the first thing I thought about was that user and I was like, I got to find that person and message them, be like, we've unblocked 99% of users. It's unbelievable. [laughter] So it's it's unbelievable. Uh yeah, Lloyd. So if you want you could just do this now. So this way these just become effectful functions. That's one. It's not there's really not a major difference here, but um could do it this way if you want. Um yeah, I'm I'm I'm probably not going to have a ton to say about this stuff. Oh. Uh, okay. I'll eat my words right now. Get rid of these these gens in the return statement. Also, also what uh go back please. Also, uh if you have a gen that returns Oh, sync. Okay. Okay. So, so here uh why not just do literally this? Yeah. I mean, yeah, I would expect something like that. Yeah. But render pretty of an effect, right? That's what Lloyd told me. Yeah.
Yeah. First time caller, longtime listener. Welcome, Fold Kit. Welcome.
[laughter] Feel like we should start doing this like it's a like it's a I guess a call radio show. Yeah. Yeah. 90s call-in radio. We need to bring back the the call-ins that we used that that we did when when Kit was uh doing this with us. Yeah, definitely.
Welcome. First time first time caller, longtime listener. Um finally catching one of these live an hour late though. That's okay. That's okay. We won't hold it against you.
We've got 99% of users blocked by [laughter] by effect printer. Yep. Yeah, I would say this could be like substantially cleaned up with just a bit of like effect.
Fn onraced because then you could delete all these like effect.ucceeds seeds that are like littering the code and the intent becomes a lot clearer now like what's going on in my opinion. Also, what is this? What is this? Oh my god. This is terrible.
I think um I think that the terminal service in effect now has a rose property.
Uh probably I I recall not having that but eventually I think somebody made some improvements to the terminal recently. No, I guess maybe I'm maybe I made it up in my head. Yeah, there are columns but not rows. Yeah, regardless uh regardless this is this is a uh this is no good.
Um because because teaching moment um because this is being evaluated eagerly on process not within an effect because because you're returning effect.ucceed for every action. Um this is being evaluated like eagerly as part of process instead of as part of the effect. Whereas if you did this uh then it's fine. mean [clears throat] because internally every effectg generator effect generator uh is wrapped by a suspend which helps which basically allows you to do um this um you can like do sideffecting things inside a generator and it's okay and you don't have to do like this um otherwise you would have to do this uh if you were not in a generator. So like accessing the process global. Uh yeah, no good. Bad Lloyd. Bad.
No, but this looks great. Um this looks very cool. Um the boxes uh stuff that you've been working on, I'm I'm I think looks great. I think you can build some really nice uh UIs with it. Um, yeah, for folks who have not checked out Lloyd's effect boxes project, definitely go take a look. And I think Lloyd, you can uh correct me if I'm wrong, but I'm pretty sure this effect stack thing is for scaffolding TypeScript apps with effect. Uh, maybe we can go to the read me here. Can I make this bigger?
Nice. Uh, no, this is boxes. Whoops.
Stack effect. There you go. So, I think this effect stack or stack effect. By the way, why why stack effect and not effect stack? Anyway, um I think this is like uh for scaffolding effect projects. So, you folks should check this out too. Give Lloyd some feedback.
Clanker question. Is it enough to put my effect preferences in some markdown files or should I go a step above and make them ox plugins? What's your experience recommendations? It is not enough to have them in markdown files. In my experience, I would have custom lint rules built. You can literally just tell your clanker to build the rule for you. But in my experience, like yeah, it helps to have your like custom preferences in somewhere. But like in my experience, you'll still get deviations unless you set up more back pressure. And uh yeah, linting rules are a great way to have that back pressure as long as you like force it to do that, right?
I like to give them both because you need to first give a preemptive hint how what they should and shouldn't do and then like as Maxwell said the back the linting rule is mostly for back off and ensuring that the rule does not get deviated and not processed.
Um man I love these UIs you could build with boxes Lloyd looks looks really good. really good because stack effect is for stacking effect and it makes the stack.json look cool. [laughter] Okay, for me it was more I don't know just my brain but effect stack was like the the more intuitive thing for me. But I think this looks great. Yep. The LSP is really dope, but sometimes it's not enough. I agree. That's why you need your own custom lint rules. Yeah. Also, because a lot of rules are very domain specific to what you're building and that's why you need them. I mean, we've talked about it like like endlessly on office hours, but the if you want your your agent to behave the way that you want it to behave, you have to spend time giving it the back pressure to do what you want.
So setting up like pre-commit rules to run linting every time it tries to commit something and like telling it that it has to run formatterers and blah blah blah every time it changes code.
And and you know the more you can do to force the agent to run checks and get get feedback, the closer you'll like you'll end up to the code that you want at the end of the day.
Anyway, Lloyd, nice work on boxes. Looks great.
Um, anybody else have other questions? I feel like that hour went by very fast, so I'm open to answering some more questions if folks have them.
It's always nice when we have things like those to see and discuss. I really love looking to the things that you are building. And by me, I mean you, everyone are building. Matia's talking specifically about me. Oh, yeah. Obviously. [laughter] Um, yeah. If you folks I I I like uh doing this type of thing as well. If you folks are building something and you want feedback, um, you can do it like this. You could, you know, maybe we could have more people come on and talk about their projects. Um, so always like hit us up ahead of time if that's something you're interested in. We'll talk about that. Um, but if nobody has any other questions, uh, I don't really want to like just sit here and wait. Um, but if if there are any other last minute questions, drop them in like Discord or in the chat. We can try to answer them before we close out. One day I'll bring something to roast. [laughter] Sunday roast. Why not? Uh, why not next week? Yeah.
Sephi undercover. Hello. Hello everyone. Hello.
All right. Well, okay. If nobody has any other questions, uh we'll probably close up office hours for today, but um definitely. Oh, actually, wait. What? What? I spoke too soon. Oh my god. Everybody's like the questions. [laughter] They're about to close. Pass your question now. What do you recommend for timestamps in databases?
It seems like the test clock cannot override the Postgrql default timestamp. Uh oh wow.
Um they are two different languages. Yeah. So how does cluster work? Um, [laughter] at some point I'm going to have like Tim come on and do a and actually do a cluster stream so that so that FIWS has nothing to troll me with. Um, so for time getting back to the question for timestamps, uh, you should model timestamps in your domain the way that you want to and you should model timestamps in your database the way that your database accepts them. Um so like in SQLite I think usually integers are the best in Postgress your mileage may vary but using their time stamp type or time stamp with time zone like it it dep I don't I can't answer that question very generally but then like it's kind of up to you to map those types to your own domain. Um, I'm not really sure what you mean about the test clock overriding the Postgress default timestamp.
I I probably imagine I hope I one way I could read that question is that you cannot override the database clock time and so a default like current time stamp of of the database will still be the actual real time stamp and if you are doing that I think that's a bad thing happening because either you get your application controlling the time and relying on injecting the time in there and that means like baking the time creation and snapshotting in your domain model. Yeah, if that's if that's the way the question is asked. Yeah, I'm not sure that's the intention. I think you're right. I think you're right. I think you're right. That's the question. No, sorry. No, go ahead. Go ahead. I would say that um there is no way to control time over a database unless like you use things like test containers and then you adjust the time but probably that's an overkill for tests. Uh it depends on the kind of the test you have. Um but if you really want to use the uh current time stamp provided by the DB engine um and if that's not the case what I would recommend is probably to use um effect has um an unstable um schema model uh which u is basically something that's baked on top of effect schemas and allow you to define models where you can have fields s uh that can be generated by your app and then fed into the database and can be omitted when you construct your domain model and will be automatically fed in with things like for example the current time stamp or generating a UU ID v7 or things like that. Uh that is something you could look into again. uh spin up a clanker session and ask your clanker how do I use the unstable uh schema model uh together with um the effects SQL module and it will point you to examples where um the both of them cooperate so that you have basically kind of a model uh it's called model but probably uh again it's not an OM it's just like defining a shape of a data and it has utilities for having fields like for example a time stamp being generated by your app and then injected into the database. So that way if you inject a test block it will resolve the test time of your test instead of using the current time sum of the database if that's the question. You could also you could also I guess uh if you're using test containers or something like that you could issue a query against the database to get the current time stamp and then seed your test clock with it.
Uh right like you could do something like that or you can adjust the time in the test container SQL that's also another thing if you want like the save the deterministic like again it won't be deterministic because then it's another system that has its own clock so the test won't be deterministic so that's something probably I would avoid uh because usually you want tests to be as most deterministic they could be I would Okay. Whenever I see uh I'm sorry, somebody mentioned effect and RxJS in the same sentence. You need to post the link for the FAQ. Yeah. Yeah. That's my response to the RXJS. It is complex. Uh I won't I won't disregard the the intent of the comment.
Effect is complicated. Um and and it takes some time to learn, but I think the payoff is there.
obviously or I wouldn't be working with the fact um and I don't think it's really I don't think the barrier to entry is too too high like to get started obviously to become like advanced with the fact it is but uh it takes time but um how does so there's a lot of comments about like cluster um if we do an office hours that is cluster specific Um, I think having Tim on would be really useful, but that does mean that office hours would be in the evening, East Coast time. Like it would be in usually on the East Coast, we do it office hours resolves to about like 10:00 a.m. here of the East Coast of the United States, Eastern Standard Time. Um, if we did if we had an office hours where we got Tim on on and like did it with Tim, um, it would probably have to be like like 5:00 p.m. Eastern Standard Time. So, like seven hours later than we usually do office hours. So, but if that's something that's of interest to people, um, we can figure that out. It needs to be 24 hours so there there is no issues about time zones. Eventually, it will catch anyone, right? [laughter] Everybody will be present eventually. Exactly. The longest eventual attendency of of the stream. Yeah. The whole team would would attend eventually. Um, and there was somebody who asked if we could do a Adam focused office hours at some point. I don't know if we'll do like a full office hours on Adam, but if you have questions about Atom or want us to like demonstrate some of the capabilities of Atom, like sure, we can definitely do that. Um, one question. So, Sephi, I know you have a bunch of like questions about using effect and things like that. How is effect supposed to be used full usage with HTTP server? Can it live next to an existing server like Express? The answer is it can be both.
You can do both. If you have an existing server and you want to incrementally adopt effect, you can do that. If you have a green field project and you want to build an HTTP server with effect, you can do that. Um, so it's very flexible. Obviously, like sometimes the flexibility means that it's um more difficult for folks to get into uh from the beginning. But we are working on a bunch of things that will help with like your AI agent teaching you how to use effect. for example. Um, so we have some things in the pipeline related to that that I think folks will enjoy definitely. Um, let me see. As I understand current prototype of the state machine PR is non- serializable. Is a serial is serialization unrealistic? I have no context on the state machine PR that Mike is working on.
I'm sure that at some point serialization will become a thing if it's not already a thing.
I think it was serializable. I think I mean if it's modeled with schema then it's serializable.
Um just like scrolling through scrolling. Yeah, do scrolling the comments and see there is some good videos by Kit uh that talk about effect. There's also some really great websites. Um maybe folks can link Sephi to um all of Kit's websites, the effect.institute, institute the effect visualizations which I forget the name of that site. Um but maybe you you folks can link Sephi to those sites. Um and also way back when but Ethan Naiser did some great videos on on effect which are one of which is on our homepage right now. Um [clears throat] there is also the just [ __ ] use effect.dev dev website which is [laughter] just [ __ ] use effect. [clears throat] But again, if you want to get B in effect that has a lot of like uh things pointed as a joke, but that they are actual reality on why effect makes sense and why it's great. Plus one for Adam also. And also how does Adam compare to BackboneJS? [laughter] Okay. Okay. Um, yeah, I'm more familiar with prototypeJS, but we can find something else. I just write like raw script tags. [laughter] Who needs a framework? Yeah. Documents in inner html equals. That's right. Who needs Who needs a virtual DOM? Who needs Who needs any framework really? Who needs effect? Everybody needs effect. Um, Is there any other questions that I missed? Matia, there is one regarding effect schema versus zod. It's a bit painful to switch from zod because schema is a bit more than zod uh does. But re it really works well with effect.
Oh, sorry. It was a reply. Sorry, not a question. Sorry. Didn't see the tag at the beginning. Also, if APIs accept uh standard schema, you can take an effect like if you want to migrate incrementally, um you could take the API that you're feeding your Zod schema into and use standard schema instead and then like convert your ZOD schema to standard schema and then slowly replace your ZOD schemas with effect schemas if that's what you want to do. Um because you your effect schema can also be converted to standard schema. Um, I use on click equals code here. Yes, [laughter] indeed. Yes, indeed. The good old times. Yeah, Sephy, if you're not in Discord yet, uh, that's also a wonderful place to go to ask questions. I'll I'll I'll link the Discord uh invite link in chat here. Uh, but there's a ton of folks on Discord who are always willing to like help answer questions.
There's a beginner's channel and I also agree with uh Spid Spiritzu Spiritzu uh and on starting from V4 and not V3 cuz I think we're like getting closer and closer to a more stable V4. Uh there's still a few like question marks we're working out um like um like uh removing yieldability in favor of very selective subtyping again but I mean yeah it yeah but V4 has no printer [laughter] 99% of 99% of users are blocked 99%. My biggest pain point with effect schema is that I overuse transformations with Zod and I have to always specify both decode and encode even though I only need to do an actual transformation. Uh if you want to only specify a one-way transform, that is possible. Um and I think the V4 schema docs even show you how. Hang on. M and also it does not mean that you have to provide a valid implementation. You can always start implementing only new one of that and let always the other one fail. So you will see if you actually need only one side of that.
[sighs] Hold on a minute. Hold on a minute. Packages V4 was stable enough since since December. Yeah, I mean yeah one way percent of the user are running V4 in production omitting values when transforming actually I should look at the index the outline here tupils arrays blah blah blah validation I will share my screen when I find what I'm looking for when I find the screen emitting values encoded side defaults isn't like is it like decode only and I got Julio's document on schema is like so Uh comprehensive types extracts.
Can you say more about yieldable versus subtyping discussion?
I intentionally omitted that from office hours this today, but then I accidentally said it and then I tried to ignore that I said it but they heard me. Yeah.
Uh hang on folks. I'm trying to find this this oneway transform example. [snorts] It's like it's like you do a transformer fail and then on the encode side you just effect fail or something like that. Yeah. Yeah. Yeah. That's was we were saying before that yeah you can just say transform fail and just implement one of those and then leave the other for when eventually you need it. Yeah. Because unfortunately usually you always need both of them. Flipping a schema. Yeah. I I I can't find it right now, but it's basically like a one-way transform. Actually, there's a good example of this source. Hang on, I'll share my screen so you guys don't share screen.
Um, somewhere in here. Schema schema schema schema. It's like uh XML.
Maybe this isn't a good example. [snorts] [laughter] Uh but we even in the library we have some like one-way transforms. So you can like anyway encode effect um even within the library we have some one-way transformers. So like uh this like XML encoder is a one-way transformer. Um but anyway somewhere in the docs that Julio put together there is a example of oneway transform where you just fail on the encode side.
Do you plan to support the Vest V4 with effect plugin in effect V4? Uh uh yes, I think so. [cough] [clears throat] Is that not Wait, are we on B3 right now? B test V3. No, we're on B4.
This is M. Yeah, the effect v test plugin is maintained. I think there's an issue with it, but there is um you guys wanted me to talk about Yeah. So, this is what Mike is working on to fix effect test. There's a issue with layer memoization uh and like nested layers and sibling layers. So, he's working on a fix which I'm supposed to look at but I haven't. Um, where? Oh, did Tim already merge it? Yep. It's already there, folks. Can't go back now. Beta beta 66. Okay, here we here it is. Uh basically, um we killed the yieldable type or interface because uh long story short, we hated always calling as effect everywhere. Like this was really annoying. Um and you could like get around this with like effect.service service or whatever, but like doing this was really annoying. Uh, and it it especially became annoying when we were working with um [snorts] when we're when we were working with like effect cluster and workflow like in an activity like having to always call as effect to to turn the activity into an effect so that you could pipe it to other things. It was just like a this this this the idea was sound with yieldable like the the general what we were trying to achieve which was removing the foot gun of of of subtyping was uh noble and it was like the right idea but yieldable yield built wow the yieldable interface uh turned out to be the wrong abstraction for for doing that. So what we did instead is we reintroduced subtyping. So let's find an example in here. Let's look at context is a good example. View file.
So um where are you context?
The type is defined on top the type uh we pass that through after the type ID. There you go.
Here we go. Extends effects. Yeah. So, uh when I say subtyping, I mean a a a given type that also is an effect. We had removed this um from the library moving into V4 because if you don't do this carefully, you can end up with situations where you introduce foot guns for users and we actually had a unintentional in V3 we unintentionally introduced a breaking change at some point um with with the migration to like subtyping more and more of the library types.
Um, so in V4 when we first started like building V4, we introduced this like yieldable um interface where if you wanted a type to be like to to if you wanted to be able to like yield star a given type in a generator, you would make it extend yieldable and you would implement the as effect method. So that outside of generators to to convert a type into an effect you would call as effect explicitly. Um instead of just having it happen automatically. Um and similarly in a generator you could just yield the type directly without calling as effect.
But like the that as effect method became really annoying to work with um like especially like I mentioned in cluster and and workflow. Um, so we reintroduced subtyping, but we did it much more carefully and intentionally this time where there are only like a select few types that implement uh sub our subtypes of effect. Um, like for example context and whatnot. [sighs] Um, but for example, I think fiber is not an effect subtype anymore. for example. Yeah. Like in in [clears throat] V3, um fiber was like the the fiber type itself was was a subt type of effect. So like you could directly yield um a fiber and I think it would but but again like that becomes confusing because you don't know like okay if fiber is a subt type of effect technically there are two ways to convert a fiber to effect. you can join the fiber or you can await the fiber and they're both different but you don't know like exactly which method we're calling behind the scenes. So we tried to be much more intentional with subtyping now. Um so fiber is not a subt type of effect and like uh option and result are not subtypes of effect. They need to be explicitly lifted into like an effect now.
Um, so again, the the the goal was to try to make this more um uh retain the ability to yield stuff, most stuff. Uh, with option and result, you have to like do an effect from option effect. Um, we still want to be able to yield certain things like context values, right? Like you want to be able to yield your service to get the implementation back. Um but we did not make types that were problematic in V3 uh subtypes of effect in V4 like fiber and ref and etc. Basically all of those cases where it was more like a utility than or something like fun to have rather than rather than being actual useful. Any plans to support the V+ ecosystem? Uh, I don't really know how we would support the V+ ecosystem. We use the V+ ecosystem for different things internally. I'm not sure like how we would support it. How is the new docs page doing? Where how can I ban [snorts and laughter] the ban the ban score is going higher and higher. Can I can I time people out in YouTube chat? No, I can only report or block. All right, let me report FIWS for for harassment. [laughter] [gasps] Um, anyway, hopefully that uh clarifies the whole removing of the yieldable interface for folks. Um, so yeah, that was the whole reason behind this this PR. Yep. Um, this was a discussion we had ongoing for probably the last like two months trying to figure out if like this made sense or not. Um, and while we were together last week, we decided this made sense. Uh, so, okay.
Anything else? I think that we're now at an hour and a half, so we'll probably close. Yep. office hours now. But um if anybody has any questions that we didn't get to or wants us to talk about something next week, um feel free to drop that into the office hours discord channel. We'll pick it up next week. But until then, thank you everybody very much for attending office hours. Hopefully you all enjoyed yourselves and yeah, keep writing effect. Show us what you're building. We're waiting for your guests and your repos. Gotta love Tim's commits and PRs. Whip whip whip whip whip whip whip. [laughter] Keep I told Tim the same thing.
He's got the best commit messages. He learned it from Mike. [laughter] Mike's commit messages. Fix fix try try fix fix try try. [laughter] Anyway, cheers everybody. Have a good rest of your day.
Related Videos
Agentforce NOW AMA: Build with React and Salesforce Multi-Framework
SalesforceDevs
490 views•2026-05-28
How agent o11y differs from traditional o11y — Phil Hetzel, Braintrust
aiDotEngineer
450 views•2026-05-28
WEB TECHNOLOGIES UNIT-2 | Degree 4th sem BCOM Computers web technologies unit-2 full explanation💯✅
LearnwithSahera
1K views•2026-05-29
More tests are always better? How to use AI to identify tests that bring little value
Alliance4Qualification
335 views•2026-05-29
Search Algorithms Explained in 60 Seconds! 🤖💨
samarthtuliofficial
218 views•2026-06-01
People of Game of Thrones using JavaScript DOM
AltCampus
296 views•2026-05-30
Introduction to Problem Solving Part - 1 | Lecture 1 | Intermediate DSA
ascensionix
107 views•2026-05-29
🚀 BCS613C Compiler Design | Module 1 to 5 Schema Evaluation 🔥 | VTU 6th Sem 💯 #VTU #bcs613c #exam
Pranavaa-y4y
104 views•2026-06-02











