Summary: Smalltalk taught a generation of programmers what it felt like to build by conversing with a live system, and Alan Kay hoped it would turn users into builders. Version 1.8 of the pico engine takes both ideas seriously: a better developer UI for people, an MCP surface for agents, and a schema underneath that makes both possible. This post describes the release and why the builders it serves don't all have to be developers.
When I was in grad school, Smalltalk was all the rage. Commercial Smalltalk systems were expensive, so we didn't get much time with them, but the experience of sitting at the console and building something by interacting with a live system has always stuck with me. You didn't write a program and then run it. You worked inside a running world of objects, poked at them, changed them, and watched what happened.
In time, the software industry settled on the C model of edit, compile, and run because it produced reproducible, reasonably portable code on standard operating systems. Java arrived in the 1990s and stole the object-oriented limelight with C-style syntax and a familiar build model. Smalltalk slowly faded into relative obscurity. Still, I never forgot the joy of working with a live system or the convenience of debugging from a console against a real image. So when we built the pico engine, Bruce Conrad built a developer UI that lets you see a pico mesh, send events and queries to any pico in it, and examine the results.
The latest release of the pico engine, version 1.8, doubles down on that idea and makes the developer experience better than it has ever been. And since developers now often include AI agents, we've made it better for them as well. An accompanying Manifold 1.8 release brings the Manifold rulesets along. This post describes the changes and why I think they matter beyond the people who write KRL for a living.
A Smalltalk system wasn't a program you compiled. It was an image: a saved snapshot of a whole world of live objects, including the classes, the windows, the compiler, and the development tools themselves. You started the image and picked up where you left off, with every object still holding its state. Everything in that world was an object, and objects talked by sending messages. Alan Kay later said that calling it "object-oriented" was a mistake because the big idea was messaging; what mattered was what happened between objects, not what was inside them. That idea runs through actors and, eventually, to picos, as I described in Closures, Objects, Actors, and Picos.
The tools were where Smalltalk put developers first. Each was a live view into running objects:
Together these collapsed the edit, compile, run, and debug cycle into one continuous conversation with a running system. You didn't reproduce a bug; you were already standing in it. And Kay had a bigger goal than developer convenience. His Dynabook work at Xerox PARC imagined a world where children and other non-specialists would use Smalltalk to build their own tools. Users would be builders, not just consumers of software. Both of those ideas, the continuous conversation and users as builders, sit at the center of this release.
The Testing tab in the pico engine UI has always been the closest thing we had to a Smalltalk workspace. You pick a pico, choose an event or query, fill in some attributes, and send it. Until now, though, the forms came from a hidden __testing structure that the compiler guessed at and that rulesets like wrangler maintained by hand. It drifted from the code, and it told you nothing about what happened after you pressed the button.
In 1.8, the Testing tab is built from the ruleset's schema, which I'll describe in a moment. That brings several changes:
@example in the ruleset becomes a pre-filled form.
The console is the piece that feels most like Smalltalk. Want to know how many relationships a pico has? Evaluate ent:established.length() in the subscription ruleset and see the answer from the running pico rather than reasoning about what it ought to be. The console is read-only by construction; it compiles your input as an expression and runs it the way a query runs, so it can't assign entity variables or take actions. It's also owner-only, available on the UI channel and to the local developer tools, never on discovery or app channels. The Rulesets tab gets a companion Docs view that renders each ruleset's documentation from the same schema, with a "Try it" button next to every example.
Coding agents like Claude Code and Cursor work best in exactly the loop Smalltalk made famous: try something, observe the result, and adjust. A person can stare at code for a long time before running it. An agent learns by running it, many times, and anything that makes the loop slow or silent hurts an agent more than it hurts a person. The pico engine had a notorious silent failure: a stray character after a ruleset's meta block would keep the ruleset from registering, with no visible error. It bit us more than once while building Manifold, and an agent that can't see an error can't fix it.
Version 1.8 attacks the loop from both ends. On the checking side, krl-check parses and compiles a ruleset, lints its annotations, and reports errors with line and column. Installing or flushing a ruleset now validates it first, and a failure raises wrangler:ruleset_install_failed or wrangler:ruleset_flush_failed with the errors instead of quietly doing nothing. On the live side, rule outcomes and the console give an agent the same answers they give a person in the Testing tab. Each of the repositories now carries a CLAUDE.md and AGENTS.md explaining layering, conventions, and commands, and the engine serves its documentation as llms.txt along with an OpenAPI description of its HTTP API.
The engine also has a built-in MCP server with two faces. The first is for agents acting as developers. Running pico-engine mcp --stdio connects an agent to a local engine with tools to validate and install rulesets, create and delete picos, raise events, run queries, evaluate expressions in the console, and tail the event log. Our bar for the release was simple: a fresh Claude Code session with only CLAUDE.md and the MCP server should be able to start an engine, write a ruleset that passes krl-check, install it, raise an event, and query the result without ever opening the wiki. That's the Smalltalk loop, carried out by an agent.
The second face is for agents acting as operators of a running mesh. Every channel can be reached over Streamable HTTP at /mcp/:eci with an OAuth bearer token scoped to that channel. The tools aren't written by hand; they're generated from what the channel allows, one tool for each event and query the channel's policy permits. When I wrote about building a conversational interface for Manifold, my students hand-wrote MCP wrappers for Manifold's events and queries. The mesh MCP server generalizes that work to any pico, and it can do so because of the schema.
The change that makes everything above possible is that a pico can now describe itself. Ruleset authors add structured doc comments, /** ... */, directly before the rules and shared functions they want callers to see.
We considered declaring events and queries in a block inside the ruleset's meta section and rejected it for three reasons:
meta is a second copy of every event and function, far from the code, and it will drift.select when already says.shares, forcing every existing ruleset to change.
Comments on the rules themselves avoid all three problems. Here's an annotated rule from Manifold:
/**
* Create a thing pico as a child of Manifold and subscribe it as a manifold_thing.
* Only fires while Manifold has fewer than max_picos children. When the thing is
* fully initialized, community:thing_created is sent to callback_eci with the
* caller's rcn.
* @attr name String "display name of the new thing"
* @attr callback_eci String optional "channel to receive community:thing_created"
* @attr rcn String optional "caller's correlation id, echoed in the callback"
*/
rule create_thing {
select when manifold create_thing
...
}
The author writes only what the code can't say: a description, the attributes the rule cares about, and their types. Everything else is derived by the compiler: the entry event from select when, any constraints in its where clause, the rule's condition, the shared functions a caller can check in advance, and the events the rule may raise or send. Annotations are opt-in. A rule without one still runs; it just isn't advertised. Annotations also decide only what is advertised, never what is permitted; shares still decides what is queryable and channel policy still decides who may do what.
From those annotations the engine builds two schemas. The ruleset schema describes what one ruleset offers, rule by rule, with all the derived detail a developer wants. That's what the Testing tab and the Docs view use. The pico schema merges the ruleset schemas of every ruleset installed on a pico into one aggregate, grouped by event, because a caller doesn't care which ruleset handles an event, only what it can send and query. Filter the pico schema by a channel's policy and you get a channel schema: what this particular caller can do here.
That chain, from ruleset schemas to pico schema to channel schema, is what the rest of the release consumes. The Testing tab, the Docs view, discovery bindings for integrators, and the generated mesh MCP tools all read from it, so they can't disagree with each other or with the code. The surface that a developer sees in the UI is the same surface an agent sees through MCP.
The schema also turns reference documentation into a build step rather than a writing task. The engine repository includes a krl-schema tool that reads a ruleset's annotations and derived data and writes a reference page in Markdown: each operation with its entry event, attributes, condition, and the events it may emit, and each query with its arguments and return type. Because the page is generated from the same schema the engine uses, it can't fall out of date the way hand-written ruleset documentation always has. A project can feed the same output into its llms.txt, so the reference an agent reads matches the one a person reads.
If live systems were so good, why did edit, lint, and compile win? Mostly because of the image. Code lived inside it alongside the objects, which made Smalltalk hard to version, diff, and merge in a world that standardized on text files and, eventually, git. Images accumulated state, so "it works in my image" was a harder problem than "it works on my machine." And Smalltalk was a world of its own that didn't integrate well with the operating system or other languages.
Liveness didn't die, though. It survived as a layer on top of files: REPLs, Jupyter notebooks, the browser's developer console, hot reload, Erlang's hot code . Files won as the source of truth. Liveness stayed as the way you explore. But several things have changed since Smalltalk lost that argument:
| Then | Now |
|---|---|
| Programs were things you ran, then stopped | Always-on systems such as cloud services, actors, and IoT, where the running system is the reality |
| The builder was a human at a screen | Agents are builders too, and they live on tight try, observe, adjust loops |
| Reflection was for humans (Browser, Inspector) | Systems need surfaces that machines can read: schemas and MCP |
| Building required learning a formal language | An agent can carry the formal part; a builder needs intent and judgment |
| The image trusted everything inside it | Authority boundaries are expected: capabilities, policies, scoped tokens |
Many of today's systems are long-lived and stateful. A pico or a cloud service runs for months, accumulating state, and new code changes what that running thing does rather than starting a fresh program. That's the world Smalltalk assumed, and it's the world picos live in.
But picos don't have to choose between Smalltalk's model and the file-based one. Smalltalk merged code and state in one image, and that's what made it hard to version and reproduce. Picos separate the two. Code lives in rulesets, which are text files at URLs, versioned in git and checked by krl-check. State lives in picos, which are persistent, always on, and live; you talk to them through the Testing tab, the console, events, and queries.
Version 1.8 strengthens both sides at once. krl-check, validation on install, and install-failure events make the file side better. The console, rule outcomes, and schemas make the live side better. The developer MCP server gives an agent both in one loop: write a file, check it, install it, and then have a conversation with the running pico. Smalltalk was right about the live conversation, and the industry was right about files. Now that builders include agents, you need both.
Two other changes deserve mention. The first is a fix to channel policy. In 1.8, deny overrides permit, so a narrow deny can't be widened by a broader permit. Parents can set a policy ceiling when they create a child so that the child can't create channels more permissive than its parent allows, operators can configure engine-wide deny lists, and wildcard channels can optionally require a validated caller identity. This might look like an operator concern in a release for builders, but it's what makes the mesh MCP server safe to use. Tools generated from a channel's schema are only as safe as the channel that scopes them, and a leaked ECI shouldn't be a key to more than it was meant to open. We published an audit of the engine's channel policies alongside the release.
The second is an engine configuration file. Engine settings can now live in ~/.config/pico-engine/config.json, or in another file named with pico-engine -c or PICO_ENGINE_CONFIG, which makes running several engines on one machine much less fiddly. Environment variables still work, but the config file wins when both are set.
Annotations are only useful if people know how to write them, so we annotated the rulesets that every pico engine developer already depends on. Wrangler, the subscription ruleset, PDS, OAuth, and the other rulesets bundled with the engine now carry annotations in place of the hand-maintained __testing maps they used before. That makes them the first place you'll see the new Testing tab and Docs view at work, and the place to look when you want to see how a rule with forwarded attributes or several @example presets is described. If you're annotating your own rulesets, start by reading wrangler's.
The Manifold 1.8 release does the same for a framework built on top of the engine. Manifold's rulesets are annotated throughout, including the delegation rules, like create_thing above, that take a callback_eci and correlation ID and finish their work asynchronously. Its ruleset reference pages and llms.txt are generated with krl-schema, which makes Manifold the first full example of documentation built from annotations. SafeAndMine and the Journal ruleset build their discovery bindings with wrangler:schemaBindings rather than hand-written maps. The release also adds a Home Assistant notification channel and retires the old skills registry in favor of the engine's MCP server.
In Smalltalk, the conversation with a running system was a metaphor. You typed an expression, chose do it, and the system answered. With an agent on the developer MCP server, the conversation is literal. Imagine telling an agent, "make a pico that watches my freezer sensor and tells me when it gets warm." The agent writes the KRL, validates it, installs it, raises a test event, reads the rule outcome, and reports back. That's the same live loop, carried out in plain language, and the 1.8 features are what make it work: errors the agent can act on, outcomes that say why a rule didn't fire, and a console that shows real state instead of a guess.
Kay's second idea, users as builders, is the one I find most interesting, partly because it mostly didn't happen. Smalltalk became a tool for professionals. The real successes in end-user building were spreadsheets and HyperCard, and both succeeded by narrowing what you could build. The barrier was never just the tools; building required learning a formal language. Agents lower that barrier in a way Smalltalk couldn't. A builder now needs to know what they want and be able to judge whether they got it, not how to write KRL. That changes who gets to shape the software that acts on their behalf. A builder who isn't a developer, working through an agent, needs a few things from the system, and the MCP surface is where 1.8 provides them:
| What a builder needs | What 1.8 provides |
|---|---|
| To know what a pico can do | Schemas from annotations, readable by people in the Docs view and by agents as MCP tools |
| To act without breaking things | The channel schema: an agent holding a channel sees only the events and queries that channel's policy permits, and the engine refuses anything else |
| Limits they don't have to understand | Channel policy: deny overridespermit , policy ceilings, scoped OAuth tokens |
| To understand what happened | Rule outcomes and install-failure events, which an agent can explain in plain language |
Smalltalk trusted everyone inside the image, and that was fine when the image belonged to one programmer at one workstation. A world where people build through agents can't make that assumption. Picos have always had channel policies; what 1.8 adds is tightening them and tying the schema to them, so what a builder's agent can see is exactly what it's allowed to do. None of this finishes Kay's project; plenty of hard problems remain between "tell an agent what you want" and software you can rely on. But it moves the line. Version 1.8 gives the people who build with picos a live conversation with the running system, and it opens that conversation to builders who don't have to be programmers. That's who this release is for.
Photo Credit: Building in conversation with a pico from ChatGPT (public domain)
Tags: picos pico+engine krl manifold programming smalltalk ai mcp