# Specter - Supercharged AI App Development with Dev Agrawal

> Dev Agrawal demonstrates Specter, a TypeScript framework combining event sourcing, vertical slices, and executable specs for AI-friendly app development.

- **Collection:** Video
- **Published:** 2026-06-02
- **Author:** Anthony Campolo
- **Canonical URL:** https://ajcwebdev.com/videos/specter-supercharged-ai-app-development-with-dev-agrawal/
- **Markdown URL:** https://ajcwebdev.com/videos/specter-supercharged-ai-app-development-with-dev-agrawal/index.md
- **JSON URL:** https://ajcwebdev.com/videos/specter-supercharged-ai-app-development-with-dev-agrawal/index.json
- **Channel:** [Anthony Campolo](https://www.youtube.com/channel/UCpdzti0GURPfMjKzYK5FVSA)
- **Original URL:** https://www.youtube.com/watch?v=i5LGDnuHXOA
- **Original Label:** Watch original

---

## Episode Description

Dev Agrawal demonstrates Specter, a TypeScript framework combining event sourcing, vertical slices, and executable specs for AI-friendly app development.

## Episode Summary

Dev Agrawal introduces Specter, an early-stage TypeScript framework designed to make application behavior explicit, testable, and easier for AI coding agents to implement. Specter models domain facts as append-only events and organizes commands, queries, and reactions into independent vertical slices. Human-readable scenarios live beside each slice and become executable tests, providing deterministic checks without separate business-logic test files. A to-do application demonstrates event storage, slice-specific state, type-safe clients, database adapters, and rebuilding projections from the event log. Dev explains that Specter is not itself an AI tool; its constrained architecture, local context, and enforceable boundaries make generated code easier to create and review. The roadmap includes authentication context, external services and LLM reactions, automated evaluations, parallel slice implementation by multiple agents, visual diagrams, and generated documentation. Although not ready for production, Specter reflects Dev’s vision for faster consulting and application development with replaceable infrastructure and verifiable specifications.

## Speakers

- Anthony Campolo
- Dev Agrawal

## Chapters

### 00:00:00 - Introducing Specter and Its Origins

Anthony Campolo welcomes Dev Agrawal back and opens with the name Specter, connecting it to specifications, James Bond’s SPECTRE organization, ghosts, and comic-book mythology. Their playful discussion highlights how project names can acquire elaborate explanations after the fact, much like the changing story behind the Redwood framework’s earlier name.

Dev traces Specter’s development back to November and credits ideas explored by his former boss at Solvio. The framework grows from efforts to turn diagrams and higher-level behavioral descriptions into code or scaffolding. That goal intersects with the recent popularity of specification-driven development promoted by tools such as AWS Kiro and GitHub Spec Kit.

### 00:04:49 - Repository Links, Viewer Questions, and the README

While Dev reconnects after an initial network problem, Anthony shares the Specter GitHub repository and acknowledges viewers in the live chat. He also raises a comment asking about an unfamiliar project called Daima. Neither host can identify it confidently, so Dev promises to investigate it after the stream rather than speculate.

Once the connection stabilizes, they confirm the repository spelling and begin deciding how to present the project. Anthony suggests starting with the README as the natural entry point for a new user. The discussion quickly surfaces the importance of strong introductory documentation, clear commands, memorable visual branding, and a README structure that explains the tool before describing repository internals.

### 00:08:38 - Framework Scope and a Rough First Installation

Dev explains that Specter is now a TypeScript framework focused on stateful application logic rather than UI specification. It can support a frontend, backend, or type-safe client-server arrangement resembling tRPC, while also exposing REST APIs. The UI framework remains interchangeable because Specter’s main responsibility is defining and executing application behavior.

Anthony recommends placing installation and usage commands earlier in the README and notes that structured templates can improve AI-generated documentation. They try the starter, encountering an Effect Platform dependency problem under Node even though Bun works. Despite the early-stage setup issues, the generated Hono and SolidJS project launches successfully and displays the reference to-do application.

### 00:13:04 - The To-Do Demo and Event-Sourced Foundations

The reference application supports adding, removing, completing, and unchecking to-dos, with a celebratory banner appearing at completion milestones. Dev deliberately keeps the interface familiar so attention can remain on the architecture underneath it. Four domain events describe the entire example: a to-do was added, its completion changed, it was removed, or a milestone cheer was created.

Dev explains that Specter treats events as the source of truth. Its event log is append-only, so updates do not overwrite or delete prior facts. Other application state is derived as a projection of those events, preserving history and consistency. Event schemas follow the Standard Schema interface, allowing libraries such as Zod, Valibot, or Effect Schema to provide validation.

### 00:18:08 - From Event Storming to Vertical Slices

Dev relates Specter’s event definitions to event storming, a collaborative technique in which domain experts write business occurrences on sticky notes and arrange them into workflows. Once those facts are understood, they can be translated nearly one-for-one into typed event definitions. He eventually wants Specter to visualize those definitions automatically on a board.

The conversation then moves to slices, which contain the backend’s feature logic. A slice represents a command, query, or reaction and resembles an individual API interaction. Drawing on Jimmy Bogard’s vertical slice architecture, Dev contrasts this organization with conventional API, domain, and database layers. Keeping all code for one behavior together improves cohesion, reduces coupling, and gives AI agents a smaller, more relevant context.

### 00:23:25 - Isolation, Duplication, and Command Slices

Anthony asks whether slices import shared modules, and Dev explains that slices are prohibited from depending on one another. They may use framework code, events, database clients, or carefully chosen shared utilities, but feature behavior remains isolated. Vertical slice architecture also favors limited duplication over premature abstraction, with repeated patterns typically extracted only after they appear several times.

Dev introduces command slices as the equivalent of GraphQL mutations or other write endpoints. A command accepts input, validates it, and appends a new event rather than directly mutating the authoritative record. Shared modules can live elsewhere under the source directory, while Specter prescribes only the independent feature-slice structure. A brief audio failure leads Anthony to read background material explaining the historical move from layered architecture toward CQRS and vertical slices.

### 00:28:24 - Storage Adapters and Executable Scenarios

After reconnecting, Dev explains that the example stores events in SQLite, but Specter itself only defines an event-log adapter. Implementing query, append, and transaction operations allows applications to use SQLite, Postgres, EventStoreDB, or another persistence system. Storage therefore remains an application-level decision rather than a mandatory framework dependency.

The second major concept is the scenario: an inline specification describing how a slice should behave. A command scenario supplies an input, such as a title containing “Ship It,” and declares the event expected in response. Anthony connects this structure to the given-when-then exercises and red-green-refactor workflow he teaches. In Specter, however, these behavioral examples live directly in the slice definition and can be executed automatically.

### 00:32:19 - Generated Tests and Deterministic AI Review

The dedicated test file is only a few lines because Specter’s testing helper discovers the scenarios embedded in every slice. Running the suite produces 27 tests across the reference application. Dev removes a title-trimming operation to demonstrate a genuine failure, then shows how schema typing also catches malformed fields before execution.

This arrangement gives implementations a deterministic behavioral contract. Dev stresses that Specter is not an AI product by itself; it is a framework structured so agents are less likely to make uncontrolled changes. Reviewers can inspect scenarios and edge cases without reading every implementation detail, while nontechnical stakeholders may be able to propose or modify examples. Performance and code quality still merit review, but required behavior is directly verifiable.

### 00:37:07 - Stateful Commands, Queries, and Reactions

Asked what people should build, Dev says Specter is suitable for systems that can be represented as ordered events or state transitions. The remove-to-do command demonstrates preconditions: removing an existing item emits an event, while removing an unknown or previously removed item produces no result. Similar scenarios could enforce subscription limits or detect duplicates.

Query slices derive responses from prior events, such as returning only active to-dos after completion changes. Each slice contains metadata, scenarios, and implementation functions named apply and handle. Reaction slices automate workflows by responding to state changes; the example creates a cheer after five completed items while preventing users from repeatedly unchecking and rechecking one item to earn the same milestone again.

### 00:42:41 - Teaching Agents Specter’s Rules

The array-heavy definitions remind Anthony of XState, a resemblance Dev says David Khourshid also appreciated. Dev then opens the concise skill.md file bundled with projects created by the Specter CLI. It defines events, slices, scenarios, runtime responsibilities, and infrastructure boundaries so an agent receives focused instructions without an enormous documentation package.

Dev argues that a codebase embodying its intended patterns often guides agents better than extensive prose. Existing slices become examples from which models can infer the expected structure. Although models may recognize vertical slice architecture from training data, they still tend to introduce cross-slice imports or unnecessary abstractions. Specter supplements written guidance with deterministic checks, including a script that rejects imports from one slice into another.

### 00:48:38 - A Thin UI and Type-Safe Specter Client

The reference frontend uses the Solid 2.0 beta rather than SolidStart. Dev explains that missing testing-library support contributed to removing UI behavior from Specter’s core scope. More importantly, moving stateful logic into tested slices leaves components largely declarative, making many component tests little more than confirmation that JSX loops render their inputs.

The UI communicates through a type-safe Specter client modeled after tRPC. It imports the server definition’s type and directly exposes commands and queries such as adding or listing to-dos. Replacing Solid with React would not require changing Specter’s domain logic. Anthony also asks about Drizzle, and Dev clarifies that both the ORM and SQLite are application choices rather than framework requirements.

### 00:53:03 - Influences, Infrastructure Choices, and Server Integration

Dev identifies Auto, created by Solvio’s CEO, as Specter’s strongest inspiration. Both projects emphasize model-driven development in which specifications come first and AI writes implementations that must satisfy deterministic checks. Auto is more comprehensive and prescribes infrastructure, storage, and GraphQL exposure, while Specter aims to retain the behavioral conventions and let users bring their preferred stack.

Earlier Specter versions included Solid and Drizzle directly, but Dev has steadily removed those opinions. He may replace the split Hono API and Solid SPA starter with TanStack Start for a unified full-stack experience. The current Hono server translates HTTP requests into Specter command or query calls, after which the runtime selects a slice, executes it, persists emitted events, triggers reactions, and returns data.

### 00:58:00 - How Apply and Handle Execute a Slice

Dev examines the two functions that implement every slice. The apply function updates a slice’s private state as events are replayed, while handle processes the current command or query. Slices neither inspect one another’s state nor share feature data; they see only the event log and maintain the minimum projection needed for their own decisions.

The add-to-do slice needs no local state, so it only defines a handler. That pure function validates the submitted title, trims whitespace, rejects missing or oversized values, and returns a new event. If the product later limited free users to one hundred to-dos, the same slice could add state and apply logic to count prior additions before accepting another command.

### 01:02:00 - Authentication, External Effects, and LLM Evaluations

Looking ahead, Dev identifies authentication context as a major roadmap item. Handlers could receive user, role, organization, or session information supplied by application-level token decoding. Scenarios would then specify behavior for particular identities, such as rejecting a user’s 101st to-do while allowing another account to continue independently.

He also wants reactions to communicate with third-party APIs and language models, enabling agentic applications whose external behavior remains specified. A more experimental idea would transform scenarios into LLM evaluations. Exact assertions work for deterministic code, while generated text requires looser grading based on length, tone, quality, or instruction adherence. Anthony notes that some requirements can use ordinary checks, whereas subjective outputs may need another model as evaluator.

### 01:05:33 - Parallel Agents and Model Escalation

Dev outlines a workflow in which an agent first creates the application skeleton: domain events plus each slice’s name, description, and schema. Because slices are independent, separate subagents could then write scenarios, implementations, tests, and optimizations simultaneously. A twenty-slice application could potentially employ twenty parallel workers rather than one agent moving through the entire system sequentially.

The narrow responsibilities also support economical model routing. Less expensive models such as Haiku, Gemini Flash, or smaller GPT variants could attempt most slices first. If repeated tests fail, the system could escalate only that difficult slice to a stronger model. Multiple models might also implement the same contract, allowing developers to compare valid alternatives without changing externally specified behavior.

### 01:11:09 - Per-Slice Storage and Rebuildable Projections

Each slice acts as a sandbox whose implementation can be replaced without affecting its neighbors. Dev notes that imperfect generated code may be acceptable in a low-priority slice if it satisfies the contract, while performance-critical slices can receive careful optimization. Since behavior and interfaces remain stable, an implementation can later be discarded and rewritten safely.

Slices may also choose different storage technologies: SQLite for one, Postgres for another, JSON files for a simple case, or vector and graph databases for specialized queries. These stores hold projections rather than authoritative facts. A projection can be deleted and rebuilt by replaying the event log, which can reduce the need for conventional data migrations. Dev demonstrates changing a slice’s table shape while leaving unrelated slices untouched.

### 01:16:00 - Consulting Vision, Generated Docs, and Closing

Anthony praises Specter as a higher-level application architecture that codifies Dev’s preferences through useful constraints. Dev says the practical motivation is consulting and freelance work: agents could accelerate implementation while readable scenarios let nontechnical stakeholders inspect and correct expected behavior. Future visualizations may display events and slices on a canvas, making the system’s structure easier to understand collaboratively.

They also propose a CLI command that deterministically converts slice metadata, schemas, scenarios, inputs, and outputs into Markdown or API-style documentation. Anthony considers applying Specter’s slice model to AutoShow commands such as extraction, images, text-to-speech, and video generation. They close by warning that the create-specter command is not ready for prime time. The recording ends at 01:21:24, for a total duration of 01:21:24.

## Resources and Links

- [youtube.com/watch?v=rpU3z6ruMV8](https://www.youtube.com/watch?v=rpU3z6ruMV8)
- [github.com/devagrawal09/specter](https://github.com/devagrawal09/specter)
- [en.wikipedia.org/wiki/Event_storming](https://en.wikipedia.org/wiki/Event_storming)
- [jimmybogard.com/vertical-slice-architecture](https://www.jimmybogard.com/vertical-slice-architecture/)

## Transcript

[00:00:04] - Anthony Campolo
And we're live. Welcome back everyone to AJC and the Web Devs at Night, episode 3 or 4. I've lost count at this point, but, um, I guess it depends whether you count the one with Rizèl. But, uh, Dev, my man, you have a new project. What's up?

[00:00:22] - Dev Agrawal
I do, yeah, and I'm pretty sure it's been more than 4 at this point. Uh, we've had, we've just had a lot of like hiatuses in between.

[00:00:32] - Anthony Campolo
Yeah, I think this is probably the 4th with just you and I, and it'll be 5 with Rizèl, I think is how many it is. But yeah, so Specter, when I first, when you first created this project and I heard the name, it took me like a second to realize it has to do because of spec, and I felt really stupid, right? It took me like an hour of like hearing it over and over, like, wait a second, okay. Specter. Specter. I was gonna ask like, what's the name mean? And I was like, oh wait, duh. Right. Yeah, it made me think of, uh, the James Bond franchise. I don't know if you've seen much of James Bond films, but SPECTRE is the, um, international espionage network that is like the bad guy in a lot of the films. It stands for, um, A Special Executive for Counterintelligence, Terrorism, Revenge, and Extortion. So the R and the E are flipped. So that's also what I thought of when I heard Specter because that's another acronym. Okay, got it.

[00:01:35] - Dev Agrawal
And my exposure to the word Spectre mostly comes from like playing RPG games where it's like, it's like some sort of a ghost or, uh, and I think there's also a Spectre character in DC which is like a a god-level character.

[00:01:52] - Anthony Campolo
Uh, yes, yeah, Spectre is a spirit. Yeah, it's definitely another common use case. It's a versatile word.

[00:01:59] - Dev Agrawal
Yeah, I don't know, maybe I can concoct like a more— I, I should probably ask Codex to concoct like a more mythological story behind Specter the framework.

[00:02:08] - Anthony Campolo
This is like when, uh, Tom, he wrote this whole backstory about the name Redwood, and if you actually go back in the Git history, he had written almost the exact same thing for first name of it, which was Hammer, and then he just kind of took the vision and slightly reworded it because they had to change the name, and it sounded like, you know, it fit so perfectly. In both cases, it was basically the same justification.

[00:02:35] - Dev Agrawal
Nice. Yeah, but, uh, Specter, I feel, is like almost something I've been working on since like November. And it's inspired by something that, uh, my, like, my previous boss at Solvio, he was working— he has been working on, like, technically since, like, or late 2024. Um, but, like, it— yeah, I mean, I think I'm freezing up there. Are you—

[00:03:07] - Anthony Campolo
did you lose me at any point? Uh, no, you're coming in just fine. Yeah, no, you sound totally good. You may be getting lag on your end. This happened in the last episode also, but we can hear you just fine. Okay, carry on.

[00:03:22] - Dev Agrawal
Yeah, I can't wait to get out and get off of this like terrible Wi-Fi. Um, yeah, but like, yes, Specter was inspired by something that I mean a lot of other people have kind of been worked on for a while, uh, trying to turn like diagrams into code. Um, some are like at least some, some sort of scaffolding. Um, yeah, and it's essentially a way to, uh, like describe the kind— describe the kind of behavior you want out of applications at a higher level. Um, which, uh, which was pop— which was popular in some circles before spec-driven development kind of blew up thanks to AWS Kiro.

[00:04:08] - Anthony Campolo
Thanks to AWS.

[00:04:12] - Dev Agrawal
What? AWS Kiro, the IDE that they launched with that writes like massive, massive markdown documents.

[00:04:20] - Anthony Campolo
Okay.

[00:04:20] - Dev Agrawal
Kiro.

[00:04:21] - Anthony Campolo
Okay. Yeah. Kiro. I don't know how it's actually pronounced. You may be right.

[00:04:25] - Dev Agrawal
Or like GitHub Spec Kit. There's a bunch of these.

[00:04:28] - Anthony Campolo
Because this is what is superseding Q. Amazon Q, I think is what it is. Right. Yes.

[00:04:35] - Dev Agrawal
Yeah. Yeah.

[00:04:41] - Anthony Campolo
You are freezing a little bit now, actually, but you're, you're still good. Your, your video is just freezing a little bit.

[00:04:49] - Dev Agrawal
Give me, yeah, give me just one second. Let me reconnect.

[00:04:53] - Anthony Campolo
Okay. While you're doing that, I'm gonna grab some links. They're already in the YouTube show notes. I'll share them on screen while you're doing that. So we've got a GitHub repo and we've got a video that's already out of date. So, right, don't need to worry about that one too much, but I'll share the GitHub link for people. Hey, we got someone in the chat. Sorry, I wasn't seeing those. What's up, my man? Thank you for joining. Also, actually, before we get started, someone had a question, Dev, in the comments from last week. I think it's actually a person asking a real question. So it was for you. Let me pull that up real quick. We're asking about what your thoughts were on some project called Daima. D-A-I-M-A. Do you know what that is?

[00:05:58] - Dev Agrawal
D-I-A-M-A?

[00:06:01] - Anthony Campolo
D-A-I-M-A.

[00:06:05] - Dev Agrawal
I have— I do not know about this project.

[00:06:11] - Anthony Campolo
All that's coming up on Google searches I see one thing, it says a lightweight code editor, and another thing, it says a database proxy written in Java. Yeah, we got the comment said, inquiring minds want to know, how does Dev feel about Daima? D-A-I-M-A.

[00:06:32] - Dev Agrawal
I'll look into it after the stream. Cool.

[00:06:36] - Anthony Campolo
It may be just nonsense or a bot or something, but it's hard to tell. Someone else though commented, thank you for sharing your experiences. This video deserves more likes and comments. So I hope that's also a real person. We don't usually get many comments on the videos. Ryan comments sometimes, the Dash dude I know. But, you know. Okay, so is your connection all good now?

[00:07:02] - Dev Agrawal
Yeah, I think so.

[00:07:03] - Anthony Campolo
Sweet. So here's the link. DevAgrawal09/Specter with an E-R. Not an RE. The extortion comes before the revenge in this acronym.

[00:07:19] - Dev Agrawal
Yeah, I think Spectre with an RE is probably like, like there's probably more domains and packages available. Um, but yes, I think the TER is probably going to be more natural for an American audience.

[00:07:36] - Anthony Campolo
Yeah, totally.

[00:07:40] - Dev Agrawal
Cool. So how do we get started? Do we just jump into a demo or we talk through?

[00:07:45] - Anthony Campolo
Let's look at the README first.

[00:07:48] - Dev Agrawal
Okay.

[00:07:49] - Anthony Campolo
That's usually a good entry point. And if it's not a good entry point right now, that would be a good thing to think about at this point.

[00:07:57] - Dev Agrawal
Okay. Yeah. I think there's probably something in the README that we need to generate. I'll share my screen.

[00:08:04] - Anthony Campolo
Fat image that slaps for the home README. Right.

[00:08:11] - Dev Agrawal
Yeah. No, I want some really good images and logos for this. I think that's one benefit of using the names vector.

[00:08:21] - Anthony Campolo
Okay. Can you bump your font up a couple of times?

[00:08:24] - Dev Agrawal
Yes. Can I? At what point does it take over? Okay. The width. So, yeah, this is the part that's one of the obsolete things that I need to get rid of. Yeah, it's just a TypeScript framework now.

[00:08:38] - Anthony Campolo
Just TypeScript. So just, um, so is there a UI at all or it's just all scripts?

[00:08:45] - Dev Agrawal
So there is a UI, uh, like obviously the apps that you're going to build will have a UI, but I've, uh, I've kind of like cut the UI specification and UI behavior out of the scope. Um, Because at some point I realized that the— I think we're going to get into it. But basically now it's more of a— I guess it's closer to XState, honestly. Like, it's a way to describe stateful logic or— that you can put pretty much like anywhere.

[00:09:22] - Anthony Campolo
So, it's kind of a universal thing. It's logic. So, you can stick a UI on it. I'm sure. But at this point, that's not really the focus. You're just focusing on the functionality.

[00:09:35] - Dev Agrawal
Exactly.

[00:09:35] - Anthony Campolo
Yeah.

[00:09:36] - Dev Agrawal
And you can build a backend with it. And there's also a way to create a type-safe client for it so that you can have a server-side app written in Specter and then you can have a type-safe client that your UI uses to talk to your backend. So, kind of like tRPC-esque. But, but it can also like generate REST APIs. Yeah.

[00:10:02] - Anthony Campolo
For this README, before you get into the repository and how it's organized and stuff, you should have just the commands you would run to use this thing to like install it and actually use it. Because that's what I'm— yeah. So right there, the create repository, you should just flip those 2 sections. So you already, you already got that. That's, that'd be my one just kind of structural recommendation right there.

[00:10:22] - Dev Agrawal
Yeah. Yeah. This is like AI-generated READMEs. They don't really have a great understanding of how to write READMEs. It's just like they just dump whatever information is there.

[00:10:31] - Anthony Campolo
Yeah. It's actually one of the things that we do in my workshops is that we create a, like a structured README template that you can use to generate so that always gets like all the sections you want in the right order.

[00:10:42] - Dev Agrawal
Mm-hmm.

[00:10:42] - Anthony Campolo
So that's a, a useful, a useful prompt that I could share with you.

[00:10:46] - Dev Agrawal
Mm-hmm.

[00:10:48] - Anthony Campolo
Cool.

[00:10:48] - Dev Agrawal
Yeah, that's helpful. Thanks. So yeah, I mean, the way to get started with Specter is pretty straightforward. This will create— right now this is going to create like a Hono and SolidJS app. A single page app. I'm probably going to move this to something like TanStack Start right now. Now that Solid is not really a core thing. And you can use it with pretty much any framework that you want. The starter template just happens to be using Hono right now.

[00:11:22] - Anthony Campolo
I got an error. It said cannot find package effect/platform imported from thing.

[00:11:29] - Dev Agrawal
Yeah, there's things that I need to fix there.

[00:11:34] - Anthony Campolo
It works with Bun. Sweet.

[00:11:37] - Dev Agrawal
Yeah, I'm using Node. For everything. But yeah, it should, which means it should probably work with Bun. Uh, yeah, there's honestly not—

[00:11:47] - Anthony Campolo
it worked with Bun but not with Node. That's what I'm saying.

[00:11:54] - Dev Agrawal
Yeah, so super early, lots of fixes needed. And I don't think the README actually has much useful information here. Um, README kind of just describes what the, uh, what this repo is and not what Specter is, and I need to fix that.

[00:12:14] - Anthony Campolo
Yeah, if I were you, I would just rewrite the README to use Bun and have the CLI do bun install and bun dev because Bun's like super tight.

[00:12:25] - Dev Agrawal
I don't know if you know. Yeah, I honestly, I stopped using Bun a few weeks ago, I think. Yeah, I just don't want to contribute to anything Anthropic is doing. I mean, I like BUN as a thing, but I just don't like Anthropic.

[00:12:49] - Anthony Campolo
Fair enough. I'm just going to try. I got the project created and try to run it right now. Sweet. I got a to-do app.

[00:13:04] - Dev Agrawal
Yeah, so this is the app that you should see. It's like a pretty— in like not super interesting to-do app where you can add things, remove things, uh, mark them as checked. So I am very creative with demos, as you can see. And the only thing that, that additional— that's additional here is that If I check all 5 of them, I should see something here. Yeah. When you have 5 or 10 or 15 todos completed, it shows a little cheer. That's the only thing that's additional here from the todo app that you might be familiar with. But yeah, the demo itself is just a todo app. Um, and the— it's a simple to-do app so that we can focus on the more interesting part, which is how it's actually built. Okay, so I guess we can jump into like how it works unless you have other questions about this, or—

[00:14:13] - Anthony Campolo
yeah, go for it.

[00:14:14] - Dev Agrawal
I don't know where it came from. Um, so yeah, the basic idea of Specter is that Everything is an event. So this is Specter. It creates event-sourced apps, which means events are kind of the source of truth. And events are what we store in our main database. The event log is how we get like our consistency throughout the application. And it also means that we never lose any data. The event log itself is append-only. You just add events to it and everything else, like any other piece of state that you might need is basically like a projection of those events, which we'll get to in a second. But yeah, so everything in every interaction, every fact is recorded as an event. A todo was added with this ID and title. The completion of a todo was changed, and this is todo ID. This is the value that was changed to. Todo was removed. We created a cheer, the thing that the banner that we saw at the top, and it shows like how many todo how many todos did we complete for this like cheer milestone to be created, and what was the message shown? So. That's literally it. Like, these are the 4 events that kind of make up this entire app.

[00:15:44] - Anthony Campolo
Yeah, yeah, it's odd.

[00:15:46] - Dev Agrawal
Yes, that is odd. Um, but this accepts like a standard schema, so you can—

[00:15:51] - Anthony Campolo
this is pretty much whatever too, I would assume, because that's what crashed the first time I tried to download it.

[00:15:58] - Dev Agrawal
Yeah, uh, I still need to get rid of that. Like, it was using Effect for a while, then I kind of ripped it out of the internals. I'm probably gonna add it back in. Because the typed error handling is still helpful. But yeah, I was trying to figure out— I was trying to experiment with some patterns with Effect that didn't really go anywhere. So, I ended up ripping it out. But yeah, so, this was all— you can obviously also use Effect Schema here. Because this just accepts a standard schema thing.

[00:16:30] - Anthony Campolo
Yeah, most of my stuff is actually using Fallobot.

[00:16:35] - Dev Agrawal
Oh, I need to reload the window so that I have the LSP working. Uh, yeah, so when you create a new Specter app, um, you start by thinking in terms of events. And, uh, other than the fact that these events are what gets stored in the data, it's also like a good way to kind of, uh, think about your app at a very high level. Um, because in like you're not thinking in terms of like entity relation diagrams or like, like flowcharts. I mean, all of these, all of those are kind of like higher level things, but events are like a good way to represent things that have happened in your app. Um, so you can kind of like put together some sort of a, a user story or a workflow, like this happened and this happened. And this, there's a technique that a lot of people use to kind of map out complex domains before they build anything. It's called event storming, which is basically you get a bunch of people in the room that kind of basically like a bunch of domain experts and you hand them all orange sticky notes and you ask them to write something down, stick it on a board to kind of represent something that happens in their domain or in their business. And that's how we kind of map out— first map out everything that needs to happen, then you eventually like consolidate them, and then you go into building. Yeah, event storming.

[00:18:08] - Anthony Campolo
This is basically like, you know, Silicon Valley type stuff. I can imagine these types of, you know, companies do these types of activities a lot. It's a very techie kind of thing. They just love ways to put things in boxes in visual space.

[00:18:26] - Dev Agrawal
Exactly. Yeah, yeah, pretty much. And it's, it's a pretty helpful way to like get a high-level understanding of like very complicated things, um, because it kind of like reduce everything down to events. And then what you can do here is like once you have those events kind of mapped out, you just like write the— like you literally like have a one-to-one rewrite each event definition for each event that exists. And at some point, I want to take— like when the events are defined here, there's— like once there's a first-class concept of event definitions, we can take this and visualize it on a board. So, like it automatically kind of becomes that. Yeah, but this is like the main thing about Specter. Or not the— this is not the main thing, but this is like the kind of foundational thing that sets everything else up. So, after events, we have slices. So, the way that this codebase is organized, like we have our database, we have our empty folder, which I can delete. We have our UI. We have our server-side code. We have— yeah, this is our todo app. But all the actual logic for our backend lives inside these features. And each, each of these folders is a slice. So this is where the vertical sliced aspect comes from. So we saw the events here and we can look at this add todo slice. So each slice can be one of 3 things. It can be a command, a query, and a reaction. A command— so, commands and queries, you can think of it as API endpoints. Obviously, you're a GraphQL person. You're familiar with the—

[00:20:24] - Anthony Campolo
Yeah. I was thinking just based on how it's named. These look like API endpoints, essentially.

[00:20:30] - Dev Agrawal
Exactly, yeah. So, each slice is an API endpoint. Vertical slice architecture also has a pretty long history. Not as long as some other concepts, but I think it kind of— people started talking about it, I think, early 2010, 2011, '12. There was this guy, Jimmy Bogard, who goes to a lot of conferences to talk about this idea. Basically, the idea of vertical slice architecture is that the application itself should be built off independent slices instead of putting things in layers, like there's an API layer, your domain layer, and database layer. Instead of doing that layering, you can— yeah, Jimmy Bogart vertical slice architecture. You would write your code in vertical slices, and each slice is basically an API endpoint or something, some sort of interaction that the outside world can have with your system. And all the code that, that is needed for that slice to function lives in this one module instead of being spread across like, like 3 or 4 different layers or however, however many layers you might have. And the idea is that This creates high cohesion and low coupling, which basically means that all the related code lives together and these slices never depend on each other. One thing you'll notice is that each slice depends on our framework, our database layer, which is just our database connection, basically database client, and our events. So slices can never depend on each other, which makes it possible to build and test each slice independently. Now, the reason that vertical slice architecture was gaining popularity is because, I mean, yeah, because all the related code lives together. If you want to make a change to one feature, you have to just go to that one slice and make that change. Instead of going through 4 or 5 different files or different layers that describe different parts of it. But obviously with AI, you can probably see how that's even more helpful with AI because if all the code for a feature lives together, the agents only have to look at that one slice, and make changes to that one slice instead of having to understand the entire codebase and how things interact with each other. Yes, a slice cannot import another slice. That's a hard constraint almost.

[00:23:25] - Anthony Campolo
Interesting. There's not modules that would defeat the whole purpose that they're importing from. They're just completely self-contained within each directory.

[00:23:37] - Dev Agrawal
Yes. The module code is like Uh, like there's obviously going to be some kind of code you're importing from the library.

[00:23:44] - Anthony Campolo
Yeah, just that's how you're able to have this be still very compact and you're not, you know, duplicating lots and lots of code across, you know, similar types of slices.

[00:23:53] - Dev Agrawal
So the thing is, like, with vertical slice architecture, it's actually encouraged that you duplicate code rather than try to over-abstract. It's another one of those things where, like, instead of trying to, like, find— like, instead of trying to abstract everything prematurely The idea of vertical slice architecture is that you just duplicate the code as, like, whenever possible, and you only reach for, like, keeping, like, making shared modules when they're actually needed. So for, like, I think the kind of, like, the golden rule is that if you see the same pattern repeat 3 times or more, that's when you take that and abstract, like, make a shared module. But here, like, you'll see the same kind of a concept taken to a more extreme.

[00:24:43] - Anthony Campolo
Yeah.

[00:24:43] - Dev Agrawal
So, okay. So, let's talk about the command slice. The command slice is like— it's like a mutation in GraphQL or like in tRPC, whatever. It's like— it's— you give it some input, it does some validation, and it creates a new event. Again, we— the source of truth is the events. We just add events. We never like update or delete events. Um, so our— the mutation here in this case is like— or like changing the state of the system just means you add a new event to the system. Where would the shared module live? It can live anywhere, wherever you want in src. Um, the only kind of, uh, The, the only thing that Specter prescribes is that you keep all your feature code, um, like split in these slices, and then like the rest you can organize however you, you want. There's no, um, like built-in approach.

[00:25:43] - Anthony Campolo
Kind of like how you have the DB folder.

[00:25:44] - Dev Agrawal
And my earphones died, so I'm not going to be able to hear anything for a bit, so you can You can keep going.

[00:25:54] - Anthony Campolo
Yeah, I was just going off that because you were saying you could organize the other stuff anywhere in src, and now say you have like that DB folder. So that's the one example of something outside of the features folder, like there's some sort of shared logic happening in that DB that's being used. Dev, are you able to hear yet? Do do do do do do do do. Thanks for Sriharsh for joining, for asking questions. Appreciate it. All right, Jeff just dropped out. So vertical slice architecture. Look at this. So Jimmy Bogard wrote this in 2018. Many years back, we started on a new long-term project, and to start off with, we built the architecture around an onion architecture. Within a couple of months, the cracks started to show around this style. We moved away from that architecture towards CQRS before it had that name. Along with moving to CQRS, we started building our architectures around vertical slices instead of layers. Whether flat or concentric, it still layers. Since then, for the last 7, 8 years or so, building around vertical slice architectures for all manners of applications and systems has been our exclusive approach. It has a link to an image that is broken, which is not useful.

[00:27:34] - Dev Agrawal
It's not the website.

[00:27:39] - Anthony Campolo
All right, you're back.

[00:27:40] - Dev Agrawal
Okay, I think we're back. Yes, I'm sorry about the technical issues. I am very looking forward to never having these again very soon. Okay, so I guess you were reading the— I guess you were reading the vertical slice architecture article.

[00:27:58] - Anthony Campolo
Yeah, I read like the first opening paragraph to kind of like give us some context and fill some space. And then there is a Then there is a— he has a diagram where it says UI, application, domain, DB, and 4 vertical layers, and a slice goes through all of them. That's a useful, very simple diagram.

[00:28:24] - Dev Agrawal
Yes. We can keep talking about vertical slice architecture, but I think this is also where the second most important part of Specter comes in. Which is the specifications. So these— where are these events stored? They're stored in some database.

[00:28:43] - Anthony Campolo
You're using SQLite in this example?

[00:28:47] - Dev Agrawal
Yes, I'm using SQLite in this example. Specter itself doesn't actually ship like— Specter ships like an interface for an event database that you can implement. So if we go to Specter SQLite here— oh, not that one. Specter SQLite. Yeah. So this is the event log that we're actually using. This is— see, this is part of my application. This isn't a part of Specter. Specter just provides this event log adapter. And all you need to implement are these query, append, and transaction methods. And then you have your own way to store events. It's pretty straightforward. You can use SQLite, you can use Postgres, you can use Event Store DB, you can use pretty much whatever you want to store the actual events as long as they follow a certain adapter pattern. We talked about slices and command slices are responsible for creating new events into the system or into your event log as a way of like updating the state. Scenarios are how we specify how this command should behave. So we have like a scenario for creating a todo with the provided title. So, so the when here is like the input that the command receives. Um, so this command, like if, if you think of it as an API endpoint, you give it a title as a request body. So here we say that when, when you trigger this command with the title of Ship It, uh, we are expecting a todo added event to be created with this title of Ship It. So it's just like a, uh, like given-when-then, or like a simple behavior test of this is the input, this is the expected output.

[00:30:41] - Anthony Campolo
Um, so this is great because this is exactly what I teach in my workshop is we have given when then scenarios and the exercise we walk them through is we have them just write out in text, like clearly given when then as like a few-shot example with a scenario and then, you know, what to have for each of the things. So it would be something like, you know, resetting a password, like given someone, given a user includes their email and their, you know, correct password, then they can than this. And so, you start with that and then you can generate test scenarios off of that. And then we do, like, a TDD kind of— they call it red-green refactor. But this looks like it actually puts the test in the code itself. Yes.

[00:31:30] - Dev Agrawal
It's more like—

[00:31:31] - Anthony Campolo
the structure that are used in the test is actually the structure of the code itself, not, like, a separate test. That's how we use the given-when-then is we have that write then test cases where each of those are— it's structured the exact same way as this, but it's then like that's test code, it's not the actual code itself.

[00:31:52] - Dev Agrawal
Yes, correct. So for example, if I go here and run, um, cd apps/reference, and if I run pnpm test, then it's basically going to Like as it's basically going to go through all of these slices, look at all of these scenarios, and actually execute like a test at runtime that gives these inputs to the slice and checks if the output is as expected here.

[00:32:19] - Anthony Campolo
So I was asking here, which is what I'm curious about. So do you have, so what's, do you have test files and are they, would they be just very minimal? Is that kind of the idea?

[00:32:29] - Dev Agrawal
Yeah, so the test file looks like this. So you literally just need like a, 3 lines here to wire up everything into like this helper that you get from Specter Core Testing. Um, so you don't need— you don't need to like add any more tests for your business logic. Um, you literally just, uh, inline these scenarios in your definition. Now this is just like a JavaScript object, so when you— at runtime it's not going to do anything, but when you run pnpm test, it's going to look at all of these and, uh, uh, let's see scenario. Yeah, so 27 tests. So these are all the tests that, uh, that like that we had defined all the slices. Let me see if we can— if it shows all the actual scenario. Okay, it doesn't. Uh, it's supposed to like make a— show a list of all these descriptions. Like these are the description scenarios that it ran. I'm going to debug why that didn't happen. But for example, let's say that— so I have one here that trims surrounding whitespace before creating a todo. So I give it this extra, like ship it with extra space, and I'm expecting that the event that it created has that trimmed. Let's try to get rid of this. So if I remove .trim from here and if I run pnpm test again, I should see the scenario failing. Yes, there we go. Yeah, this was the expected, but this is the title that it actually got. So these scenarios automatically turn into executable tests as soon as you have them defined. And plus they are type safe. So obviously that will not work because the schema here had title in it, not title with 2 Ts. Yeah, so that's, yeah, that's, that's the idea of Specter is that you, you define or you specify the behavior right in here, uh, for each slice and each slice will have its own behaviors. You don't need a separate test file. This is part of the definition itself. So it's like, uh, very, very difficult for AI, like agents to get it wrong. And yeah, once you have these defined, you kind of have like a deterministic guarantee that whatever the implementation ends up being, it is going to follow this specification. So even like a non-technical person can come in, kind of like look at these, like even if they don't fully understand the— Did I drop for a second again?

[00:35:17] - Anthony Campolo
Yeah. No, just to make this explicit, the thing you're building here is not an AI tool at all. It's really just a framework. The idea is that it's going to be very easy for an AI agent to use it because of how this framework is structured.

[00:35:34] - Dev Agrawal
Exactly. Yeah. It's also going to be easy for like us and, uh, in, in a way to like review the AI code because we can— most of the time you can come in here, you can look at these scenarios and— nice, thanks. Uh, yeah, so like here, if the implementation, like I don't even need to look at it if I can look at these scenarios and I have a reasonable con— like Um, like if, if any edge cases that I can think of have been, uh, are like included in this specification, then I know that whatever the AI has implemented, it passes all the edge cases and I don't necessarily need to look at the implementation. I might want to look at it if I want to see how the AI actually implemented it. Maybe it can do something in a simpler way. Maybe, and maybe it's like not as performant, as efficient as it can be. So those are the things that you might want to check. But, um, even a non-technical person can look at these scenarios and maybe even add more scenarios or change something, and then the AI can just take care of implementing, like updating the implementation until all the tests pass.

[00:36:52] - Anthony Campolo
Great. So are you— do you have a, a projects you're using this for? Are you just currently kind of building the framework? Are you dogfooding it in any sense?

[00:37:07] - Dev Agrawal
Um, yeah, I was trying to dogfood it in a couple different proj— uh, a couple different projects. Uh, I think the main thing right now is like I don't have a lot of time, uh, outside of this and like my job search to actually build things with it. Um, but yeah, I'm almost certainly going to be dogfooding it in not just one, but I'm multiple apps, I'm sure.

[00:37:29] - Anthony Campolo
What would you tell someone to build with it, or, you know, suggest they could build with it?

[00:37:36] - Dev Agrawal
That's a good question. You can, you can build pretty much anything with this. Um, it's, uh, like it's not built for a specific kind of use case. Um, I think if there's anything that you, that you want to build that you can map out in your head as like Like certain things happening in an order or like it's like a state machine. Eventually everything is—

[00:38:00] - Anthony Campolo
Yeah, it does make sense. Yeah, think of it like a state machine because it's a sequence of steps that you're plotting out in as much of a deterministic way as you can.

[00:38:12] - Dev Agrawal
Exactly. Yeah. Let's look at another slice here, which is a remove todo slice. And what we are going to see here, again, this is another command. Like you send a command to remove a todo, you give it a todo ID. And here the scenarios have this given field, which is how we specifically give it some sort of precondition. Like if I have this todo already added and I try to delete that todo, I should see a todo removed event. If I don't have anything and I try to remove something, it shouldn't, it should just reject it. There shouldn't be any result. Or if it has already been removed and I try to remove it again, it shouldn't do anything. So now in this slice actually maintains some state of— or like it remembers what has happened in the past so that it can make its decision. And the addTodo, like at least the way that we have implemented it here, it doesn't really care about state. You just add something and it gets added. You can imagine that this is, so you might wanna keep track of like, okay, maybe a user can only add 100 todos before they have to pay, or maybe you wanna some sort of a duplicate check. And in that cases, you might want, you would want to add additional scenarios that have some like given fields. I just don't have any right now, but you can see them in the remove todo slice. And then we have the query. Uh, so query is replacing what, uh, what I had like as views or projections in my original video. Um, there's basically like a GET request where, uh, you give it some input, like I am querying for all or active or completed todos. And then I have the ordering wrong here, but yeah, so you can see that if there is nothing and the status, and I'm looking for all the todos, then I should get nothing. If I have created 2 of them, I should see 2 of them in the query response. Um, and if I have the latest state, uh, all events have, uh, have to be read to build the latest state, kind of. Um, We're going to get into the implementation in a bit. So each slice can— you can kind of think of it as like it has like its metadata, which is the name, the description, schema, the dependencies. Again, we'll get into this in a bit as well. And the second thing, each slice has its scenarios, which is how the behavior is specified. And the third thing is the implementation, which for each slice is split into like 2 functions. Every slice has an apply function and a handle function. This is basically how the slice implemented at runtime. All the events have to be read, yes, and we'll get to that in a bit. This is how a query works. If I have a todo added and I either completed it, then I added another one and I'm looking for only the active todos, it should only return todo 2. It shouldn't return 1 because we have already completed it. The same thing here. You can again specify how a query behaves by giving it some events and some input and then coming up with what should be the output of this query. You can imagine that most of your backend can be built in this way. Then the final thing is a reaction slice. Which is like how you would automate workflows. Um, yeah, so what this reaction does is that whenever you have, whenever you have 5 completed todos, it's going to create a cheer. Um, so we can see here that when there are only 4 completed todos, it's not going to do anything, but when there's 5 completed todos, it's going to create this todo cheer. It's basically like a side effect that the reaction can cause. And there's another one to say that if you have— like if you completed 5 todos, you uncheck a todo and then you check it again, then you shouldn't see anything because you've already received the cheer for 5 todos. So you cannot cheat the system.

[00:42:41] - Anthony Campolo
This does even— the code just reminds me of XState in a lot of ways too. You end up with lots of arrays of stuff. You know what I mean?

[00:42:52] - Dev Agrawal
Yeah, I know David was very happy to see this. Yeah.

[00:42:59] - Anthony Campolo
Cool. So is there something specific if you were to have an agent be building something with this that you would point it at any docs or any context for what it needs to do, or you would just point Codex or whatever and let it rip? Yeah, so I have a file.

[00:43:22] - Dev Agrawal
Yeah, the OpenCode file, that's like for, um, some configuration that I'm using like to build this. But, um, like really all you need is like this one skill.md. Okay, so that teaches— yeah, yeah. So this is the skill that gets cloned whenever, like when you run npm create Specter, um, the skill comes with the actual, uh, with like the reference app the starter app. And this basically teaches, uh, the agent how to use it. Um, I think that again, this is another thing that's—

[00:43:55] - Anthony Campolo
you actually scroll up to the top so I can just see like the first couple of lines of what it's defining. This is saying Specter Project is a TypeScript app built with vertical features. Events are domain facts emitted by accepted commands or reactions. A slice is one command query or reaction unit with private event-driven slice state. And a human-readable description. Yeah, this is great. This is actually— this itself is a good description for someone who just wants to get a high-level idea of what, what this is. Scenarios are executable examples for slices. Each scenario has a human-readable description. SQLite is app infrastructure. Inspector Core owns runtime contracts, not persistence tables or database setup. Yeah, so you, you're not really doing a backup or anything. Or you're not being the backend. Uh, really interesting. Great work. I have to head to bed now, but thank you both. Yeah. Thanks for watching.

[00:44:45] - Dev Agrawal
Have a good night.

[00:44:48] - Anthony Campolo
Thanks. Cool. No, this is sweet. Yeah. And having just like one kind of focused skill is like the perfect amount. Like, yeah, you don't need to go beyond that.

[00:44:59] - Dev Agrawal
Yeah. And honestly, I think the way that I've seen agents work best is that Um, the, the more your code base actually reflects the patterns that you want, the less additional documentation you need to provide it because the agents are going to do their research from previous streams. Yeah, exactly. Yeah. Um, so a lot of the like agent steer actually comes from just having this code in here that the agent can use as reference when it's building the app that you want. Oh my God, my earphone died again.

[00:45:37] - Anthony Campolo
And it's a type of architecture that has some sort of like online documentation so it can have some sort of context in terms of what this is, what would be some conventions kind of associated with it. So it probably has some just training data understanding of what a vertical slice is.

[00:46:00] - Dev Agrawal
Right.

[00:46:00] - Anthony Campolo
I don't know if you can hear me right now or not.

[00:46:06] - Dev Agrawal
Okay, I think I'm back.

[00:46:08] - Anthony Campolo
You're back. So I was asking— I was just asking if you think the vertical slices is something that also, because it is— there's— it's not, well, super duper well known, but it's not super obscure either. It would be in the training data and the models and just AIs have some sense of what it would mean to do vertical slices correctly already?

[00:46:32] - Dev Agrawal
Yeah, they have an idea of what vertical slices are, but because the training examples just don't— training examples are like most of the dataset is just like tangled codebases. They just cannot do vertical slices themselves. They will eventually end up importing things from slices into other slices or creating like a bunch of abstraction. Um, so again, like the amount of steering that you would need to give like a regular developer that doesn't understand these patterns pretty well, it— that's the same amount of steering that you need to do for agents. Um, the, the one difference is that you can add more deterministic things. So for example, uh, I have a script here That checks, that literally checks like if a slice— did I die again?

[00:47:26] - Anthony Campolo
I assume you're gonna say it checks to see if a slice is breaking the conventions, like importing something or doing whatever when it shouldn't be doing it. Kind of like a linter, essentially. We're having some storming happen where I am too.

[00:47:51] - Dev Agrawal
I should have just used my laptop for stream. So, oh no, this is definitely mine.

[00:47:57] - Anthony Campolo
Uh, operator? Operator? Yeah, now you're airing us.

[00:48:08] - Dev Agrawal
Yeah, it's been crappy for a few days. Like, imagine interviewing for jobs with this internet.

[00:48:15] - Anthony Campolo
Yeah, no, that sucks. Your screen is still coming in clearly though.

[00:48:19] - Dev Agrawal
Okay. Yeah. So, I was just gonna say that, yeah, I have like a script here that literally checks if a slice is importing another slice. So, things like these are helpful for the agent.

[00:48:29] - Anthony Campolo
Yeah.

[00:48:30] - Dev Agrawal
I don't even know how this works. It's been entirely white coded, but it works.

[00:48:34] - Anthony Campolo
Yeah. It works.

[00:48:38] - Dev Agrawal
Cool. I guess one other thing we— one final thing we could look at is like the actual to-do app. Um, and we can— so here, like, we have our Specter client.

[00:48:47] - Anthony Campolo
That's made with Solid?

[00:48:50] - Dev Agrawal
Yes, and this is using Solid 2, Solid 2.0, um, beta.

[00:48:53] - Anthony Campolo
SolidJS and not SolidStart, just Solid Client, I'm assuming?

[00:48:57] - Dev Agrawal
Yes. Um, it's one of the reasons why I decided to get rid of the UI aspect of Specter. Um, like, the, the first thing is that the Solid testing library, we don't have a version 2 of it yet. So I literally couldn't write tests for Solid 2.0. And then the second thing was that at some point I realized that the more of your logic moves into these slices, the more your UI components just become declarative. The less logic you have in your components, the less you need to test them.

[00:49:34] - Anthony Campolo
Because if it's just declarative, like render this one, one path, then as long as that's working correctly, then it just has to get to the very end in the UI and then let all that logic happen, not within the components.

[00:49:49] - Dev Agrawal
Exactly. Yeah. So for example, if here, uh, yeah, I have like a for, for each todo, I'm going to create this input. I'm going to show this todo title here. And if I then have a test somewhere that says that if I render this todo component with these 5 todos, I should see these 5 DOM elements, it's kind of like a pointless test because you're just testing if this for loop works, like if this JSX is as you expected. And you can just visually verify that. You don't need an executable test for that. What you might need tests for are your logic, your stateful logic. If you have stateful logic that you want tests for, you might as well just write that in Specter. Here what we see is that we have the Specter client. It's like a tRPC style API where we import this type from our server definition and then we create a client for it. That goes to /api. And then here we can just say that .todos.query, this is our query, .todos query. And then we have our .addToDo, this is our command. So you can call your commands and queries directly using the Specter client in your UI. So even if I change this from Solid to React, nothing about Specter will need to change. Cool. So I think we have covered events, slices and scenarios, the client here, and what we haven't yet covered is how these are actually— how the slices are actually implemented. Any questions before we get back into that, either from Either from you or from chat. I know there's one pending chat question.

[00:51:50] - Anthony Campolo
You said there's one pending chat question?

[00:51:53] - Dev Agrawal
The one about, like, do all the events have to be read to build the latest state? I think that's what we are going to answer. Yeah. Yeah.

[00:52:03] - Anthony Campolo
Go for it.

[00:52:06] - Dev Agrawal
No, I think that's going to be, like, as we talk about implementation, that's going to get answered. But you were saying something?

[00:52:12] - Anthony Campolo
No, no. Well, actually I was asking, you have Drizzle in this project. So that was one other part of the database implementation that is important to point out because you were— there was some sort of SQLite thing that you were importing. And this is also then Drizzle is kind of the ORM that goes along with that.

[00:52:30] - Dev Agrawal
Yeah. So again, so that's another thing that I'm using at the app level. Specter itself doesn't come with opinions of like what database layer, what ORM you should be using. Honestly, each slice could be storing its state in a JSON file for all Specter cares about.

[00:52:46] - Anthony Campolo
This is why you have this init command that builds you a project with Specter instead of having someone have to go through the process of building up a project around using the library. There's some kinks that go along at the app level.

[00:53:02] - Dev Agrawal
Makes sense.

[00:53:02] - Anthony Campolo
Yeah.

[00:53:03] - Dev Agrawal
So, the project that inspired Specter, it's called Auto, on.auto if you go to that website. It's like the same project, but like, yeah. Holy shit, my earphones died again. Talk. So, Otto is like a much more comprehensive framework. It actually prescribes its own infrastructure and data layer for how the events are stored, how the slices are stored. And each slice automatically turns into like a GraphQL endpoint. Um, so like the, again, like my, my previous company was like super heavy into GraphQL. Um, now they're like, they're pivoting kind of into like more of a product-focused rather than developer-focused. No, uh, Solvio.

[00:53:55] - Anthony Campolo
Oh, Solvio, right?

[00:53:56] - Dev Agrawal
Yeah, yeah, yeah. So Solvio is where I was working and The CEO of SolveView is building Auto. The point of Auto is the same thing, model-driven building. You write the specifications first and then the AI goes and implements it so that there's a deterministic step that verifies the specified behavior exists. Auto is a much more comprehensive framework underneath it. Um, but so what I'm trying to do is kind of like strip away as much of it as possible so that like you can bring your own opinions and make it just kind of—

[00:54:40] - Anthony Campolo
yeah, exactly, our conventions that you can build around.

[00:54:45] - Dev Agrawal
Yeah. Um, yeah, so yes, that's why I tweak a lot. I drizzle like already in my original version of Specter that I built maybe like a few weeks ago Solid, Drizzle, all of these things were included in Specter itself. But eventually, like, I found ways to shed them. And there's probably going to be more things. Yeah. I think that boundary is going to move a lot. I think I'm experimenting right now with ways to, like, make authentication a part of the framework as well. In a way that you can bring your own actual auth, like, infrastructure and you have some context. Right. But yeah. So, let's talk about how the slices are implemented. So, you can think of like any— the actual runtime app is like if you go here, like the UI calls Specter.todos.query. So, this will send an API request to the backend. The backend will parse the request and the object, and then it'll look for the todos query slice. And it's going to run that slice to figure out what data needs to be returned.

[00:56:03] - Anthony Campolo
You mentioned at one point potentially using TanStack. Is that where this would come into play with these todos query part?

[00:56:13] - Dev Agrawal
TanStack, I, I don't think that, yeah, I don't think that's, that would come into play here unless like, so the way that TanStack Start would come into play.

[00:56:24] - Anthony Campolo
You were mentioning TanStack, yeah. How would that come into play in terms of the—

[00:56:27] - Dev Agrawal
No, I, I was mentioning TanStack just like to replace the Hono and Solid setup that I have, to replace that with like TanStack Start. Because right now I have like a Hono API served at a different port and then the Solid like SPA served at a different port.

[00:56:41] - Anthony Campolo
Oh, okay. I see. So you have kind of a full stack thing happening here with a server and a client instead of like a full-stack framework running.

[00:56:49] - Dev Agrawal
Yeah. Yes. So here on this—

[00:56:51] - Anthony Campolo
yeah, I forgot, I forgot you had mentioned HANA was part of this. We hadn't looked at that, that part of the project, or maybe we did. Yeah.

[00:56:57] - Dev Agrawal
Oh no, we did not. So yeah, the server.ts, this is like the HANA app.

[00:57:02] - Anthony Campolo
Um, right.

[00:57:03] - Dev Agrawal
This is like—

[00:57:04] - Anthony Campolo
that's so funny, actually. This is— I went through a similar, um, kind of journey at one point where, uh, when I was building Auto Show, where it was like, right. It, no, it never was Hanno, but it was Fastify at one point. So it was like a similar setup to this. It was Fastify and Astro instead of Solid. And then I eventually got to SolidStart cuz, um, just having that kind of full stack framework made, made sense for me. But, um, exactly.

[00:57:31] - Dev Agrawal
Yeah.

[00:57:32] - Anthony Campolo
Uh, so yeah, so this is the part, the Hanno part is that what would be TanStack would replace.

[00:57:38] - Dev Agrawal
Exactly.

[00:57:39] - Anthony Campolo
Yeah.

[00:57:40] - Dev Agrawal
So, instead of calling that API, it would call maybe a TanStack server function or TanStack Start thing. And this is where we create our Specter app with all the slices that we have. And then—

[00:57:58] - Anthony Campolo
this is like that point.

[00:58:00] - Dev Agrawal
Yeah. Yeah. So, this is also some convoluted logic that I need to clean up. But this is basically how you integrate whatever your server-side infrastructure is with the Specter app that you've created. So this is also a part of the app, not Specter, because you can have whatever server framework that you are using and whatever database you're using. But so basically this is responsible for like converting your API endpoints into Specter commands or query calls. And then Specter takes care of like, okay, which slice handles this query or command? And then actually execute that slice, return the data or create the event, store that in your database and then run whatever reactions are needed. So that is the less interesting part. The more interesting part is how the query is actually implemented. So I mentioned that each slice has these 2 methods. The apply and the handle. This is the query slice, our changeTodoCompletion slice, which is command. It also has this apply and handle and our reactions here. If we collapse the scenarios, we have the same apply and handle here. Apply and handle are like the 2 implementation methods. For each slice. And the way it works is— let's go to todos query. Um, the apply— actually, let's just start with addTodo again because this doesn't have an apply. Uh, a .apply is basically how a slice's state gets updated with events. So each slice has its own state. Um, we talked about how slices don't depend on each other, they don't import code from each other. But the other important aspect is that at runtime, each slice has its own data and they don't look at the data of another slice. They only look at the event log and that's it. So each— for each slice, you can have the exact data structure that that slice needs, um, and you don't need to like store a bunch of data for each of the slice. You just need the minimum amount of data that any slice needs to make its decision or to respond to its queries. And we can see here that the addTodo, it doesn't even have any state because we don't need any state for adding a todo. We just add them into our event log. Now if we wanted to keep track, for example, a user can only add 100 todos before they have to pay. Now we need to keep track of state for this slice. But in this version there is no apply, there's just a handle. And the handle is what gets actually called at runtime. So this is your like API handler. So you receive a command, you trim it. If it doesn't exist, you throw an error. If it's more than the maximum length, you throw the error. So just validation here. And at the end, you just create an event. So each— the .handle functions are basically pure functions. You give them input and you return whatever they need to— whatever event they need to create. Questions so far?

[01:01:22] - Anthony Campolo
I mean, I think I get the kind of idea. It makes sense. It's like a— it's really an architectural kind of way of structuring your apps that gives you very specific kind of constraints. So, Yeah, no, it's cool. I guess my question would be, like, is there things you still are going to build in? Like you mentioned auth. So, it's like, what is the stuff that you're gonna add to this? Or, like, at what point do you consider this, like, quote unquote complete? Or is there, like, other parts of the vision in terms of what you're trying to do with this framework, you know?

[01:02:00] - Dev Agrawal
Yeah, there are a few things. I think auth is probably the big one. The way I'm imagining it is just that you get some context here in your command handler and you can, like, if context.userid, you can use that to make whatever decision you want. User ID, role, organization, whatever you want can be stored in this context. Then in your server.ts, you would actually define maybe you would have the logic for decoding a JSON Web Token and providing this context. Um, and then in scenarios you can say that, uh, I don't know, maybe, uh, maybe I would add like a separate context, uh, like in the scenarios of like user ID, uh, I don't know, 10. So auth is like definitely, uh, important on the roadmap. We want to be able to specify in these slices or in these scenarios how the slices should behave for specific users, for specific sessions. If I have 100 todo added events with the user ID of 10, and then I add another todo with the user ID of 10, it should throw an error instead of just adding it. So that kind of thing. Um, is, uh, and I think then the next most important thing would be, uh, reactions with, uh, basically external reactions or talking to the outside world, talking to third-party APIs. Um, that's another important part because we want to be able to specify how our apps communicate with the outside world. So like, for example, an LLM. And then kind of like make that part of the entire experience. Because I definitely want to be building kind of like agentic apps with this. And one kind of like more long-shot idea that I had was turning specs into evals automatically. I haven't like done too much exploration in that. But like if you think of it, like evals are essentially a bunch of examples that show how the LLM should behave, and then you try to tweak your prompts to get the expected results. So they follow a very similar shape where given some context, when the user sends you this prompt, you should have this sort of a response. The difference is that you're not going to be matching exact one-to-one. Like here, we're literally checking if the title is this string. But with an LLM, it's more fuzzy.

[01:04:48] - Anthony Campolo
Yeah, you'd be looking to test that. It just gives you some sort of response and then you need a way to kind of grade it in terms of how good or bad, how well it follows what you asked it to do. So you could look at basic things like if you asked it to give a response that was just within a certain character limit, you could check to see if it gave you that response in that character limit. If you want to, you know, do different types of summaries and test whether it gives you a short, medium, or long summary, you know? So that's one thing that you could test, just a basic.

[01:05:16] - Dev Agrawal
Yeah.

[01:05:16] - Anthony Campolo
But then you want really a higher level, you can have an LLM then grade the actual text outputs because there's usually more fuzzy things that you're looking for in terms of like what actually makes a good summary and things. What makes good tone, good voice, good grammar, things like that.

[01:05:33] - Dev Agrawal
Mm-hmm. Yeah. So those are a few things that could be done on like a framework level. Then there's like the workflow. So the way Specter is right now is it's just a framework with a skill.md. You go to your agent, you tell it to build something and it does it. But one of the superpowers of Specter that is not being leveraged right now is that each slice can be built and tested and optimized and refactored like completely independently. Once I have the events created and once I have— the workflow that I imagine is that you go to your agent, you describe an idea, and what the agent simply does is write all the events and just writes this much of your slices. The name, the description, and the schema. That's it. So it sets up the skeleton of your entire app first, um, and then once the skeleton is set up, each slice can be worked on in parallel, which means you can— if you have 20 slices, you can potentially launch 20 parallel subagents to write scenarios, build the implementation, uh, run, verify, refactor, simplify, optimize, whatever. Do all the work for each slice completely in parallel with all the other slices instead of having one agent go one by one, like let me implement this, let me implement this, and then this. Which means it doesn't matter how big your app gets, you can always do so much work in parallel, which is so much more efficient than having one agent go through every single thing. Which is even more helpful for super large codebases.

[01:07:29] - Anthony Campolo
Yeah. And I'm looking at— you have the 2 packages, the create-spector, which has like 3 Effect dependencies. Effect, Effect CLI, and Effect Platform Node. And then the actual core doesn't look like it has really any dependencies. Except standard schema spec. I think I know what that is. That's like the thing that Zod, Fallobot, and Effect call. Share, right?

[01:07:53] - Dev Agrawal
Yeah, yeah. And also it's like literally just, uh, it's just an import type. It's not like we're not even importing any code.

[01:08:01] - Anthony Campolo
Yeah, exactly.

[01:08:02] - Dev Agrawal
Yeah, yeah. I was wondering if this could just be like a— yeah, it's just import type. I was wondering if this could just be like a dev dependency, but for some reason Codex said that it does— it cannot be a dev dependency. I don't know why. Um, I'm gonna—

[01:08:17] - Anthony Campolo
it's doing something at runtime probably for validation. That's kind of like— that's what I've been led to believe is the point of these things, right?

[01:08:24] - Dev Agrawal
Yeah, I mean, the— it would be the validation library doing things at runtime, not standard schema. Standard schema is like literally just a spec and some type definitions. Um, so it really shouldn't need to exist at like a— as a dependency, but I think it exists so that any application that's using Specter, uh, it might have to import standard schema as a dependency for TypeScript to work. So it, uh, instead of like you having to import standard schema, Specter imports it, uh, imports standard schema so you don't have to. It's a weird TypeScript thing. I'm sure there's a way around it. I'm just not smart enough to find it right now.

[01:09:06] - Anthony Campolo
That's, that's all good.

[01:09:08] - Dev Agrawal
Yeah. Um, Yeah, so yeah, we were talking about like kind of the roadmap. So yeah, that, that kind of like building that sort of a workflow where you can have an agent like first set up your app, like the skeleton, and then have like parallel subagents actually like implement them. Um, maybe even like test with different variations. So you, once you have a single slice specified, you can have like 4 different models build 4 different implementations of them. You can test all of them, uh, see how they work, and, uh, right, and then compare them and maybe really easily. Exactly. Yeah. Um, another kind of workflow thing that I've thought of was that if you have the, like, specifications and everything defined, you can just have, like, cheaper models, uh, like a Claude Haiku or GPT Mini, Gemini Flash you can try implementing them, these slices, with those models. And if that doesn't work, if for, for some re— like maybe you, maybe you had Gemini Flash like give it 2 tries, like it tried to implement it, tested it, didn't work, made some changes, didn't work. Now you bring in like a smarter model like an Opus or a 5.5, um, like, okay, I tried a smaller model, it didn't work, now you go ahead and implement it. But most of the time what's going to happen is that because each slice has such like a small responsibility and everything is like very well tested, most of the time smaller models can do a pretty good job at implementing these. So once you have things set up, not only can you run things in parallel, you can also do use like— you don't have to use the, the frontier smartest model for all the implementation. You only have to bring them in when the smaller models are actually struggling to do something because this specific slice happens to have more complicated logic.

[01:11:05] - Anthony Campolo
Yeah. Makes sense.

[01:11:09] - Dev Agrawal
Yeah. And because each slice logic lives kind of in— it's almost like each slice is sandboxed.

[01:11:16] - Anthony Campolo
Yeah.

[01:11:16] - Dev Agrawal
Where you can even—

[01:11:18] - Anthony Campolo
away from all the other code.

[01:11:19] - Dev Agrawal
Yeah, exactly. So even if a slice is complete slop, that's fine because that slop is contained within a slice. Um, and at any point you can throw that implementation away and come up with a completely new implementation, and that's fine because the contracts are the same. Like, the behavior is the same, the contracts are the same, it's just the actual implementation that's different. And that's fine, you can have a slop implementation if you don't care about them. If you have certain slices that are the hot path that you actually need to fully optimize for, you pay attention to those slices and not the other ones. There's a lot of slice-specific thing that we can do here. One thing from a demo or an application level is that right now each slice stores its state in a SQLite table. So, we have the store here that kind of is— it's almost like a dependency declaration that, hey, this slice is going to store its data in SQLite. And then in our .apply here, we basically listen for events. And for each event, we do something to our database. So, when there's a todo added event, we're going to add a row into our specific table. But maybe you have a slice that requires like vector search, or maybe you have a slice that doesn't need like the whole Power SQL, it just needs some JSON data structure. That's fine. You can have each slice use a different database if you want. You can have a slice that only stores JSON files. You can have one slice that uses Postgres. You can have another slice that uses ChromaDB. You can have something that uses a graph database. And it doesn't matter because the actual source of truth are the events. And as long as your events— event log is like consistent and like that, the behavior there is fine, you can have each slice can choose its own data structures, its own database infrastructure, and all it has to do is to apply these. And another thing you can do is like this data doesn't really matter. You can completely throw away all the data of a slice. And when you run it again, it's going to start reading from the beginning of the event log and come back to its current state. So the actual— again, because the actual source of truth is the event log, the state of the slice is just like a snapshot of the event log. You can throw it away, you can rebuild it from scratch. You don't even need to do data migrations. Like if I, for example, if in the remove todo here we are tracking each todo and whether it was removed or not because we need to decide if, uh, or basically like, yeah, if we come down here we are checking if a todo has already been removed and if it has been removed we throw an error. If it hasn't been removed we create the remove, create, uh, todo removed event, right? Maybe if we want to change this, let's say that I just want to completely get rid of this field, and I'll come down here and instead of setting remove to true, I'm just going to say database dot, uh, is it dot delete? Yeah, uh, delete, uh, where this is the todo ID, and I'm just going to do this like, okay, now I have made a change to my database schema for the slice. I've made a change to my implementation, both the apply and the handle. Uh, now I can just like rerun this. I can just get rid of like the old table. The new table gets populated with data and that's it. I don't need to write any migrations. I don't need to worry about what happens to the existing data because that wasn't the source of the truth. The events are.

[01:15:22] - Anthony Campolo
So, you have 2 errors in addTodo. So, is that not related?

[01:15:30] - Dev Agrawal
This— oh, this is because I was trying to do this auth thing. Yeah. Again, slices don't depend on each other. So, there is literally no way that you can break some other slice.

[01:15:40] - Anthony Campolo
I see errors. I want to see if that was related or not. Cool.

[01:15:45] - Dev Agrawal
Yeah. There's literally no way to break another slice by making a change to one slice. Because it's not just the implementation, but also they have their own state.

[01:15:54] - Anthony Campolo
Yeah, that makes sense. The fact that this one wasn't broken and the other one was proves that.

[01:15:58] - Dev Agrawal
Yeah, exactly.

[01:16:00] - Anthony Campolo
Yeah, word.

[01:16:01] - Dev Agrawal
Now I don't need to like—

[01:16:03] - Anthony Campolo
I need to start wrapping it up in the next like 5 or so minutes.

[01:16:06] - Dev Agrawal
So, um, sure. Yeah, no, that was everything that I had to show or talk about.

[01:16:09] - Anthony Campolo
Yeah, this is great, man. Um, it's, it's very cool. Um, it's not what I was expecting. Um, but I can see why you would build something like this because, uh, You know, you get to kind of put some of your, um, you know, architectural tastes into practice in a way that kind of codifies it with just like some nice conventions, which, you know, that's what frameworks are for. So, um, it's cool. And it's, uh, it's not like a framework in like a JavaScript framework kind of way. It's like a higher level idea almost. Um, so yeah, it's very interesting.

[01:16:45] - Dev Agrawal
I see. Honestly, the biggest reason I built this is because I wanted to do a bunch of like consulting and freelancing. And I have my own like ideas on how to kind of accelerate this kind of work. And now with this, I can just like have agents build a bunch of things and I can even have like my non-technical stakeholders, like look at these scenarios and like tell me how, what I'm doing. Like, even eventually, maybe if I build a visualization— okay, another roadmap thing is that I want to be able to visualize all the slices and events on like a canvas, right?

[01:17:21] - Anthony Campolo
Yeah, yeah. No, you could have it— you just kind of point your agent at it and say, turn this into like— turn each slice into like an HTML file that gives, you know, these pieces and examples of the events and things like that and descriptions.

[01:17:43] - Dev Agrawal
Sorry, my earphone died again.

[01:17:47] - Anthony Campolo
Yeah, get your crap figured out, dude.

[01:17:50] - Dev Agrawal
Yeah, I'm just going to use my laptop next time. That was a dumb decision to not do that. Sorry. Yeah, you were saying?

[01:17:58] - Anthony Campolo
Yeah, I was saying you could point an agent at these and create reusable docs. If, because it has these conventions, so you just say, create a doc page for each slice that has these things, like example, like the inputs and the outputs, it'd be like, it's like an API documentation kind of thing.

[01:18:19] - Dev Agrawal
Yeah, it doesn't even have to be an agent. I can just write a script or I can, I can have an agent write a script that takes all these slices and gives me like a markdown version of these docs or these slices.

[01:18:29] - Anthony Campolo
Yeah, I'm saying if a person wanted to read docs is what I'm saying. Not, yeah, exactly.

[01:18:34] - Dev Agrawal
Yeah.

[01:18:34] - Anthony Campolo
So just wanted to understand their slices better. Yeah.

[01:18:38] - Dev Agrawal
Yeah. No, yeah, I think in my, in a version that I was building a couple months ago, I think one of the things I was, yeah, I think I should probably build this into Specter, which is like run a command, run a CLI command and all the slices get translated into Markdown so that you can read them.

[01:18:55] - Anthony Campolo
Yeah, exactly.

[01:18:56] - Dev Agrawal
I mean, it shouldn't need, it shouldn't even need an agent. Yeah, it shouldn't even need an agent to do that because like each slice has a name, a description, a schema.

[01:19:04] - Anthony Campolo
Yeah, you could just have a script do it. Yeah, totally.

[01:19:07] - Dev Agrawal
Exactly.

[01:19:10] - Anthony Campolo
Yeah, then that's probably less error-prone.

[01:19:16] - Dev Agrawal
Cool.

[01:19:18] - Anthony Campolo
Cool, man. Uh, well, I'll be curious to see where you go with this. Um, we won't stream next week I'm going to be busy the weekend. I won't necessarily be busy Monday, but I'll be recovering from a whole weekend trip. But 2 weeks from now, we could probably get back to it.

[01:19:38] - Dev Agrawal
Yeah, makes sense.

[01:19:40] - Anthony Campolo
Auto show stuff. See, so it would be the first.

[01:19:44] - Dev Agrawal
Yeah, excited to see where auto show is and maybe we can rebuild auto show inspector.

[01:19:50] - Anthony Campolo
Yeah, I mean, I would be interested to try out some of converting some of the CLI features because I'm thinking the way I now have the CLI going, each command can be thought of kind of like a slice because you'd have the extract slice, you'd have the image slice, the text-to-speech slice, the video slice, and then each of those are all kind of self-contained and don't have a whole lot of shared logic between them.

[01:20:12] - Dev Agrawal
Yeah, for sure.

[01:20:14] - Anthony Campolo
Cool, man. Uh, well, we'll call it here. Um, thank you to the people who are watching, especially to the person who's commenting. Uh, And whoever said hi at the beginning. Yeah, we got one person on Twitch, one person on YouTube. Sweet.

[01:20:30] - Dev Agrawal
Nice.

[01:20:30] - Anthony Campolo
Still worth deploying to multiple platforms. Yes. All right, well, thank you all for watching AJC and the Web Devs at night. Any parting words, Dev?

[01:20:45] - Dev Agrawal
Yeah, I mean, don't try npm create Specter right now. I'll let everyone know on Twitter once it's actually ready for primetime.

[01:20:56] - Anthony Campolo
Cool. Awesome, man. Yeah, well, let me know when you feel like it's in a good place and I'll tweet about it and tell all the, all, tell people that all the cool kids are using it. So if you're not, then you're not cool. So you're gonna use it, right? That's how you get people to use a tool.

[01:21:15] - Dev Agrawal
Yeah.

[01:21:15] - Anthony Campolo
Social pressure.

[01:21:19] - Dev Agrawal
Honestly, just say that this, this is, this fixed agentic coding and everyone's gonna jump on it.

[01:21:24] - Anthony Campolo
Yeah, that's all you need. All right, we'll catch you guys next time. See you later.
