A progress update on the AI-driven DAG project, and a few things I’ve been thinking about while building it.

This one is less of an essay than the last few. It’s a status post: what I’ve actually started, what I deliberately haven’t, and the question that keeps coming back while I write the code.

Finally getting started

A few weeks ago I wrote up a spike on programmable harness infrastructure — agents authoring durable pipelines, with execution, triage and orchestration kept as separate responsibilities. That post ended honestly: the mechanics worked on a toy, and the economics were unproven.

I’ve now started building it for real. This is my own project, done outside work.

It is still very early, and I want to be precise about how early. I have not touched the core DAG functionality at all. Nothing in the repository schedules a node, resolves a dependency, or persists a run. What exists is a shell around the existing Pi Core runtime, plus the beginnings of session-level features: session lifecycle, persistence, history, and the surrounding controls.

That is a long way from the thing I described in September. I’m fine with that. The part I’m building now is the part everything else will sit on.

Why I’m building my own shell

The honest first reaction to this plan was that it’s a lot of work. Building scaffolding from scratch — a server, a UI, session plumbing, all the unglamorous parts — is exactly the kind of work that makes you wonder whether you should just use something that already exists.

Two things pushed me the other way.

The first is the canvas. Eventually this project needs a DAG canvas that is genuinely customizable: node-level interaction, inspection of a running step, editing a definition while instances are in flight. That’s not a view I can bolt onto a generic chat shell later. If the canvas is going to be the primary interface, the thing underneath it has to be shaped for the canvas from the start.

The second is more mundane. The environments I work in have strict compliance requirements around AI tooling — which is reasonable, and increasingly normal. The practical effect is that the set of off-the-shelf shells I could realistically standardize on is smaller than the set that exists, and it changes. A shell where the capability boundaries, the data paths and the approval points are mine to define is simply easier to live with under that kind of constraint.

Neither reason is exciting. Together they were enough.

Faster implementation, more design decisions

The thing I keep noticing is how much less time the implementation takes.

Turning an idea into working code is genuinely easier now. Scaffolding, wiring, a first pass at persistence, the twentieth variation of a form — all of it moves faster than it used to. Some evenings I get further than I used to get in a weekend.

What has not changed at all is that the software still needs layers with clear responsibilities. There are four here, and they do not collapse into each other just because the code arrived quickly:

  • Session management — lifecycle, persistence, history.
  • Agent execution — the Pi Core loop, tools, model calls.
  • DAG orchestration — definitions, scheduling, run state.
  • UI and canvas interactions — rendering, editing, inspection.

Today I own three of them in some form. DAG orchestration is an empty slot.

Right now session management calls agent execution directly. That’s the correct thing to do while there is no DAG — adding an orchestration layer that does nothing but forward calls would be pure ceremony.

But the seam I choose today decides what it costs to insert that layer later. If session management knows too much about how a single agent run works, the DAG will have to be threaded through it rather than placed above it. If the UI reaches past session management into execution, every canvas feature becomes a cross-layer change. These are not problems I’d notice this week. They’re problems I’d notice the week I finally write the orchestrator.

So the uninteresting work — deciding what a session owns, what a run context contains, where the capability envelope is assembled — is the work that actually matters at this stage.

Where human judgment actually matters

Here’s the part I’m still sitting with.

With AI assistance, developers at a wide range of experience levels can produce working software. How far that goes, I genuinely don’t know. I don’t think the honest answer is “it changes nothing,” and I don’t think it’s “experience no longer matters” either. I’d rather leave the question open than pretend I’ve resolved it.

What I’m more confident about is narrower: even when the visible functionality looks the same, the design and the implementation underneath can differ considerably. Two versions of this project could expose an identical UI and behave identically for a user, and still be completely different pieces of software.

The difference shows up at the next change.

Three questions I find myself asking about my own code:

  • How many places have to change for one new feature?
  • How much effort does it take to locate a bug — can I narrow it to a layer before I narrow it to a file?
  • How difficult is it to accommodate a new compliance requirement?

That last one is not hypothetical for me. A rule about which tools may be used, under what conditions, is cheap if there’s one place that decides and expensive if every call site decides for itself. The functionality looks identical either way, right up until the rule changes.

This is where I think human judgment still earns its place: deciding what to separate, what to keep simple, and what to postpone. Not “design everything carefully” — that’s a slogan, not a decision.

And I want to be fair to the other side of the trade. More upfront design is not free. You pay for abstractions that turn out to serve requirements that never arrive. You pay in indirection every time you read the code or explain it to someone. I’ve built plenty of seams I later deleted. Choosing where the design effort pays off, and where it’s just anxiety with a UML diagram attached, is part of the work — and I don’t always get it right.

The harness keeps evolving

The controls I’ve already built around Pi Core — capability injection instead of prompt-level restriction, an approval boundary that the runtime enforces, tool adapters, lifecycle behavior owned by the harness rather than the model, logging designed for triage — are a starting point, not a finished layer.

Real use keeps finding the gaps. Most of my previous post on hardening the harness was a list of assumptions that only broke once the system met actual work, and I don’t expect that to stop.

Session-level features are already raising new questions. What does a session mean when work spans several agent executions? What survives a restart, and what shouldn’t? Where does the capability envelope get assembled when the caller is a session rather than a user?

DAG execution will raise harder ones. Approval is reasonably well understood when a human is watching a single run; I don’t yet know what it should mean for a step that runs unattended, three nodes deep, at two in the morning. I’m not going to pretend I’ve designed that. I’d rather get the layers right first and let the shape of the problem show up.

What I’m trying to hold onto is the same thing as before: the harness can keep growing, as long as each piece still has an obvious owner.

What I’m actually optimizing for

The clearest effect AI has had on me is not speed. It’s willingness.

Ideas that used to stay on the drawing board — because the implementation cost was too high relative to how curious I was — now get built. This project is one of them. I would probably not have started it two years ago.

But the faster implementation gets, the more my attention moves to the other end. Not “how long will this take to build” but “how much will it cost to change once it exists.” Producing the first version is no longer the constraint. Being able to produce the fifth version without rewriting the first is.

That’s a strange place to end a progress update, given how little of the thing actually works.

The DAG isn’t running yet. For now, I’m trying to make the next change a little easier.