Foundry

Foundry is an event-driven workflow engine for engineering automation. It replaces imperative shell scripts with composable task blocks connected by events, with throttle controlling how far each event ripples through the system.

Foundry runs as a daemon (foundryd) with a CLI controller (foundry) communicating over gRPC. Any emitter — a scheduled job, a webhook, a manual command — can fire an event and trigger the same downstream workflow.

For day-to-day engineering work, the main entry points are:

  • foundry task for one concrete objective in an isolated, reviewed worktree;
  • foundry campaign for a durable mission that derives one task at a time from live evidence;
  • foundry validate, iterate, and scout for project health and intent;
  • foundry run and sentinels for maintenance and scheduled operations.

Start with Getting Started, then read Tasks and Campaigns before authorizing autonomous coding work. The remaining chapters explain the event engine, workflow formations, operations, and wire-level reference.

How We Got Here

Foundry has been evolving for roughly four months. It started as a patchwork of shell scripts and launchd jobs — nightly maintenance automation that grew into a linear pipeline: iterate projects, audit for vulnerabilities, cut releases, install locally. Each step waited for all previous steps to complete. Projects couldn't run in parallel. An audit couldn't start until every project finished updating. A vulnerability discovered at 2pm had to wait for the 2am maintenance window.

As the scripts accumulated, the concepts started to clarify. Events, task blocks, throttle control, self-filtering — these patterns kept emerging from the scripts, so we started extracting them into something more intentional. Foundry is the result: a strongly typed Rust framework for building event-driven engineering workflows, replacing the fragile shell glue with compiler-checked event flows and composable task blocks.

Foundry decouples the work from the scheduling. The same task blocks that run during nightly maintenance can be triggered individually, at any time, with throttle controlling how deep the ripple goes.

Where We Are Today

Foundry has two layers, both defined in Rust:

  • Event library — the vocabulary of immutable facts that flow through the system. Each event type is a variant of the EventType enum with a well-defined payload structure.
  • Block library — the catalogue of reusable task blocks. Each block implements the TaskBlock trait, declaring which events it sinks on, what work it performs, and what events it emits.

All blocks are registered into a single engine at startup. Workflows are not declared anywhere — they emerge from the sink/emit relationships between blocks. The engine routes by event type; blocks self-filter by inspecting payload fields. This means a different entry event (or a different payload) activates a different subset of blocks, producing a different workflow — all from the same block library.

See Workflow Formations for the formations that exist today and the possibilities the current block library opens up.

Where We're Headed

Events and blocks will remain Rust-defined — they benefit from strong type safety and compile-time guarantees. The composition layer is what we intend to extract: allowing teams to declare which blocks participate in a formation and how events flow between them through configuration rather than code, enabling situational customisation without recompilation.

Key Ideas

  • Events are immutable facts — something happened. They carry a payload but have no opinion about what should happen next.
  • Task blocks are reusable units of work. Each block sinks on specific event types, does work, and emits new events.
  • Tasks isolate one coding objective, verify mechanical gates, obtain a skeptical typed review, and either land or preserve the result.
  • Campaigns hold a mission, evidence, context, owner policy, and a bounded cycle budget. They derive the next objective only after observing current repository state and the previous task result.
  • Throttle sits on a task block's output side. It controls whether Mutators execute: full (everything runs and propagates) or dry_run (Mutators are simulated, no side effects).
  • Workflows are compositions of task blocks wired together by events. They emerge from the emitter/sink relationships — not from a central orchestrator.