返回资讯中心
外部精选
软件工程
#开发者实时流

A software factory is just a durable workflow

In the first post in our software factory series we built up a framework for how to think about software factories and how organizations should responsibly adopt them.

Hacker News 最新nikhilunni2026/10/22 · 23 天前21 分钟阅读

以下正文同步自 Hacker News 最新,版权归原站所有,已转换为易读排版。

In the first post in our software factory series we built up a framework for how to think about software factories and how organizations should responsibly adopt them.

TL;DR: The software factory is just your existing SDLC, with as many steps automated as responsibly possible.

new work reprioritize Strategicbets Product spec Tech spec Ticketbreakdown Build + PRs Review +merge Deploy Monitoring Incidents +learnings Customers Customerfeedback Triage The factory is the entire workflow, with or without AI

Yeah, yeah — pretty diagram, what does that actually mean in practice?

Let’s dig into the technical details: how exactly Cortex’s open source factory, engrams, implements this idea.

First let’s focus on a subgraph of the above diagram: we start with a bug ticket in Jira and we want to ship a fix to production:

Jira ticket Write somecode Create PR PR isapproved PR is merged Code isdeployed Let’s pretend we’ve never heard of AI — what would this look like for a human?

Abstract away the details, and this is just a workflow! A well-defined sequence of steps with an indeterminate time inbetween, moved along through a series of handoffs and triggers.

This idea is not a new one; businesses have been systematizing processes going back to Henry Ford’s Model T assembly line. This idea evolved into the discipline of Business Process Management (BPM) by the early aughts, and some of the earliest workflow execution engines were built with this use case in mind.

The difference now is that we have AI to participate in or fully take over each of those steps.

Going back to our tiniest factory: look where the time goes! A human or agent works on the code and puts up a pull request… then what?

Wait hours for a review, or bother reviewers for reviews after a socially acceptable amount of time. Change requests are raised on the PR, and then we work on it… then more reviews. Even when the code makes it to production, if there’s a process for rolling it out via feature flags, we must participate in that, and so on.

This shape of work breaks the usual ways of running code:

A durable workflow is exactly the primitive built to solve this issue. Where modern workflow engines differ from BPM execution engines is that you can model your processes as ordinary code: a function that calls steps in order. The runtime checkpoints each step’s result to a database as it completes. If the process crashes or a deploy restarts it, the workflow resumes from its last completed step, and finished steps return their recorded result instead of running again. Waiting is a first-class operation: a workflow can park until a message arrives, holding nothing open while it waits.

That gives a factory the two guarantees it needs: every run resumes where it was, and every side effect happens once.

engrams is our software factory. It runs Claude Code, Codex, or your own harness in a Firecracker microVM in your own cloud; idle agents are snapshotted to blob storage and cost almost nothing, and credentials never enter the VM. We spent a lot of time nailing down security, reliability, and cost effectiveness of that platform primitive, so that we could build the actual software factory product around it, where agentic sessions are “just another step” in a workflow you design.

But we didn’t launch an open workflow platform on day one. A blank canvas of workflow blocks makes a poor first impression, so we started with two experiences people would use every day, built to be good on their own:

Now the software factory is just piecing together some of those same building blocks, with a handful more, to automate just about anything within your SDLC.

Picking apart just the PR reviewer: there are a series of steps that it does that are broadly applicable to other automations we may want to do:

We chose DBOS as our durable workflow engine because it is a simple, lightweight, and reliable engine that is easy to run in your own cloud. It is very important to us that engrams have as simple of a deployment model as possible, and the appeal of “all you need is Postgres” without the operational burden that its open source competitors suffer from was very attractive.

Plus, we had recent organizational experience dabbling with DBOS for our newly launched OpEx Review product.

DBOS runs embedded in our TypeScript product plane (on Bun), its system tables live in a dbos schema next to our Drizzle tables, and the engine launches before the HTTP server starts serving:

DBOS.setConfig({ name: "engrams-orchestrator", systemDatabaseUrl: config.databaseUrl, systemDatabaseSchemaName: "dbos", executorID: dbosExecutorId(), // the pod name runAdminServer: false, logger: dbosLogger, }); await DBOS.launch();

How an Automation Becomes a DBOS Workflow

To make blocks composable, we replaced both hand-written workflows with a single registered workflow, AutomationRunWorkflow, that interprets a block graph stored as data. Every automation, built-in or custom, runs through it.

export async function automationRunWorkflowImpl(input, deps = {}) { // Bump on ANY change to step naming, step order, recv semantics, // or finalize position. Lives in the registered body so a bump // rotates the DBOS application version. const ENGINE_STEP_CONTRACT = 4; const engine = deps.engine ?? productionEngineDeps(); // DBOS.runStep, DBOS.recv, ... return interpretAutomation({ ...input, contract: ENGINE_STEP_CONTRACT }, engine); }

export const automationRunWorkflow = DBOS.registerWorkflow( automationRunWorkflowImpl, { name: "AutomationRunWorkflow" });

The body is intentionally small, because DBOS versions an application by the source of its registered workflow functions. The graph changes every time someone edits an automation, but the registered body almost never does. A few rules keep replay deterministic:

A snapshot test asserts the exact ordered step names for linear, branch, loop, retry, deadline, stop, and supersede graphs. Any accidental change to the step sequence breaks CI, and an intentional one bumps ENGINE_STEP_CONTRACT.

Every automation run has exactly one mailbox, and the run id is the DBOS workflow id: autorun:<automationId>:<deliveryKey>. When a block needs to wait (for a session to go idle, for a Slack reply, for a signal from the agent), the interpreter parks in DBOS.recv. Nothing else is held: no socket, no lock — and notably — no VMs.

Compute nodes are the dominant cost for engrams deployments so we built our control plane so that it could efficiently tear down and rehydrate idle sessions.

This primitive fits very naturally with the DBOS model: a parked workflow is just a row in the system tables, just like a parked VM is just a row in Postgres, along with some files in blob storage, so that the next time a message arrives for that run, the engine wakes it up and resumes from its last completed step:

SESSION_IDLEThe agent finished its turn. The VM can be snapshotted; the run only needed to hear that it went idle.

Anything that wants to wake a run sends to it:

Early on, we discovered that the hardest side effects to get a handle on were commands running inside an agent’s microVM: a git clone, a build, or a message to Claude Code. They take minutes, they aren’t idempotent, and the VM underneath them can be snapshotted, evicted, and restored on another host while they run.

A race condition we ran into: a PR review ran git clone inside a DBOS step. Mid-clone, a routine VM snapshot reset the guest’s connections! The command finished, but its result had nowhere to go.

The fix was to make VM operations behave like DBOS steps:

Now a DBOS step that runs a command can safely re-run as a whole after any restart: the replay attaches to the original exec and gets the original result.

We used this same pattern for every side effect — because we can lean on DBOS for at-least-once delivery, with idempotency for every operation, we can guarantee effectively-once delivery for every automation:

engrams is a software factory that “just works” only because of the durable workflow model that DBOS gives us. A block graph someone drew in an editor gets the same guarantees as code we wrote ourselves: it survives restarts and deploys, it can wait days for a reply, and every side effect, down to a command inside a VM, happens once. And it runs in the Postgres every engrams install already has.

If you’re building agents that act over hours or days, try engrams, or start with DBOS in your own Postgres!

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →