DEV Community

Harish Kotra (he/him)
Harish Kotra (he/him)

Posted on

Building Foundry: Autonomous Software Companies on Cardano

Introduction

Most AI coding tools give you a chat window and a diff. Foundry takes a different approach: you describe a product idea, and it spins up a virtual software company — a CEO agent scopes the work, specialist agents execute in a dependency graph, and the whole run is wallet-funded on Cardano Preprod.

We built this for India Codex '26. The live app is at https://foundry-gamma-three.vercel.app. The codebase lives in foundry/ inside the IndiaCodex-2026 submission repo.

This post walks through the architecture, execution model, Cardano integration, and the engineering decisions that make it work.


The core idea

Foundry treats software delivery as company orchestration, not single-shot code generation.

Traditional AI assistant Foundry
One model, one response Nine specialist agents + CEO
No dependency awareness Topological DAG with parallel waves
No payment model CIP-30 wallet → treasury → agent fees
Generic output Scoped roster per project brief
Static result Live NDJSON stream + React Flow canvas

A typical run produces research docs, architecture, Aiken contracts, a frontend scaffold, security audit, QA plan, documentation, and a deployment checklist — each attributed to the agent that produced it.


System architecture

System architecture

Layer breakdown

Frontend — Next.js 16 App Router, React 19, Tailwind CSS 4, React Flow for the live DAG, Zustand for persisted project/execution/agent state.

Backend — Two API routes. No separate server. Execution streams over HTTP using NDJSON.

Agents — Each role extends BaseAgent with its own system prompt, JSON output schema, Masumi metadata, and per-task fee.

Contracts — Separate Aiken project in contracts/ with four validators (main, lock, mint, vesting).


User journey

User journey


Scope analysis: picking the right team

Before execution, Foundry analyzes the project brief and decides which agents are needed. Research and Architecture always run. Specialists like Contract Engineer or Security Engineer are included only when the brief implies on-chain logic, UI, audits, etc.

The agent picker lets users override the AI selection with tooltips explaining each role — then reset to the AI pick if they change their mind.


The execution engine

The heart of Foundry is ExecutionController. It:

  1. Registers all agents on Masumi (non-fatal if mock mode)
  2. Runs the CEO to produce (or accept pre-analyzed) scope and a DAG
  3. Executes specialists in parallel topological waves
  4. Converts agent JSON outputs into downloadable ProjectOutput files

Parallel DAG execution

This is the key performance optimization. Instead of running agents sequentially, we find all nodes whose dependencies are satisfied and run them concurrently:

// src/services/execution-controller.ts
while (remaining.size > 0) {
  const ready = this.dag.filter(
    (node) =>
      remaining.has(node.id) &&
      node.dependencies.every((dep) => !remaining.has(dep)),
  );

  if (ready.length === 0) {
    this.emit({
      type: "execution:error",
      timestamp: Date.now(),
      data: { message: "Deadlock detected in execution DAG" },
    });
    break;
  }

  await Promise.all(
    ready.map((nodeDef) =>
      this.runSpecialistNode(nodeDef, agentMap, outputs, remaining),
    ),
  );
}
Enter fullscreen mode Exit fullscreen mode

After Architecture completes, Contract Engineer and Frontend Engineer run in the same wave. Security and QA follow once their prerequisites finish.

Tailored DAG construction

buildExecutionDag() only includes agents the project actually needs:

// src/services/execution-plan.ts
export function buildExecutionDag(requiredAgents: AgentRole[]): ExecutionDagNode[] {
  const roles = new Set(
    requiredAgents.filter((r) => ALL_SPECIALIST_ROLES.includes(r)),
  );

  add("research", []);
  add("architecture", ["research"]);
  add("contract-engineer", ["architecture"]);
  add("frontend-engineer", ["architecture"]);
  // security, qa, docs, deployment wired based on what's in `roles`
}
Enter fullscreen mode Exit fullscreen mode

If scope was already analyzed at project creation, the CEO takes a fast-path — it skips an extra LLM call and uses the pre-built DAG directly.


Streaming execution over HTTP

Execution doesn't poll. The API returns a live NDJSON stream — one JSON event per line:

// src/app/api/execution/route.ts
export async function POST(req: Request) {
  const controller = new ExecutionController(body.walletAddress);
  const encoder = new TextEncoder();
  const stream = new TransformStream();
  const writer = stream.writable.getWriter();

  const unsubscribe = controller.on((event) => {
    void writer.write(encoder.encode(`${JSON.stringify(event)}\n`));
  });

  controller.execute(body.projectContext).finally(async () => {
    unsubscribe();
    await writer.close();
  });

  return new Response(stream.readable, {
    headers: {
      "Content-Type": "application/x-ndjson; charset=utf-8",
      "Cache-Control": "no-cache, no-transform",
    },
  });
}
Enter fullscreen mode Exit fullscreen mode

Event types the client handles

Event Purpose
dag:generated CEO produced the task graph
agent:status waiting → working → completed
agent:log Live log line
agent:reasoning Chain-of-thought snippet
agent:output Structured JSON result
agent:confidence 0–1 quality score
agent:cost / agent:duration Per-agent metrics
outputs:generated Downloadable file bundle
execution:complete Company finished

The client (useExecutionStream) fans these events into three stores: agentStore (sidebar detail), executionStore (React Flow nodes), and projectStore (persisted outputs).


Live UI: React Flow + agent nodes

The execution page renders the DAG with React Flow. Each node is a custom AgentNode showing:

  • Status icon (waiting, working, completed, failed)
  • Confidence bar (synced to executionStore, not just the sidebar)
  • Clickable output chips per agent (files appear as each agent completes)

Outputs are derived live from agent results before the final outputs:generated batch lands in the project store:

const allOutputs = useMemo(() => {
  if (projectOutputs.length > 0) return projectOutputs;
  return agents.flatMap((agent) =>
    agent.output
      ? deriveOutputsForAgent(projectId, name, agent.config.role, agent.output)
      : [],
  );
}, [projectOutputs, agents, projectId, project?.name]);
Enter fullscreen mode Exit fullscreen mode

Cardano integration

Foundry is Cardano-native, not Cardano-bolted-on.

flowchart LR
  User[User Wallet] -->|CIP-30 sign| Mesh[Mesh SDK]
  Mesh -->|lovelace tx| Treasury[Treasury Address]
  Treasury -->|85%| Agents[Agent Fee Pool]
  Treasury -->|15%| Protocol[Protocol Fee]
  Agents --> Execution[Agent Run Unlocked]
  Contracts[Aiken Validators] --> Preprod[Cardano Preprod]
Enter fullscreen mode Exit fullscreen mode
  • Wallet — Mesh SDK, CIP-30, Preprod only. MetaMask and non-Cardano wallets filtered out.
  • Funding — User must fund the treasury before execution. Mock mode skips on-chain tx when treasury isn't configured.
  • Fees — Budget = sum of active agent fees + CEO fee + 15% treasury cut.
  • Deploy — Six-step UI: compile → keys → faucet → build → submit → verify on Preprod explorer.

Smart contracts (Aiken)

Contracts live in a separate contracts/ project — not embedded in the Next.js app.

Validator Purpose
main.ak Owner-signed spending validator
lock.ak Timelock — lock ADA until deadline
mint.ak Owner-signed mint, open burn
vesting.ak Linear vesting with cliff

Example — the lock validator signature:

// contracts/validators/lock.ak
validator {
  owner: VerificationKeyHash,
  deadline: Int,
  beneficiaries: List<VerificationKeyHash>,
}

fn owner_signed(tx: Transaction) -> Bool {
  tx.extra_signatories
    |> list.member(owner)
}
Enter fullscreen mode Exit fullscreen mode

The Contract Engineer agent generates project-specific Aiken from the architecture blueprint. Reference validators in contracts/ serve as the canonical on-chain codebase for the submission.


Masumi agent economy

Each agent carries Masumi marketplace metadata — capability name, pricing in lovelace, tags, request limits. At execution start, ExecutionController registers agents on the Masumi registry. The /marketplace page surfaces them for discovery.

MASUMI_MOCK=true lets you demo the full flow locally without Masumi infrastructure.


Agent roster

Agent Role Always runs? Key outputs
CEO Orchestration Yes (pre-DAG) Project summary, dynamic DAG
Researcher Research Yes (core) Requirements, risks, tech stack
Architect Architecture Yes (core) Components, data flow, folder structure
Contract Engineer Contracts Scope-dependent .ak files, validation rules
Frontend Engineer Frontend Scope-dependent React/Next.js scaffold
Security Engineer Security When contracts exist Audit report, vulnerability score
QA Engineer Testing Scope-dependent Test plan, coverage targets
Documentation Engineer Docs Scope-dependent README, API docs, Catalyst proposal
Deployment Engineer Deploy Scope-dependent Checklist, shell commands

Each agent has a dedicated system prompt in src/prompts/, a Zod-validated JSON output schema, and structured streaming via the OpenAI SDK (OpenRouter-compatible).


Frontend engineering note: surviving Tailwind v4

One painful lesson: Tailwind v4 doesn't reliably emit utilities from cva() strings in dev, and Mesh SDK preflight resets button { background: transparent }. Buttons and landing typography looked broken — classes in the DOM, no CSS behind them.

Fix: standalone CSS files imported directly in layout.tsx (buttons.css, landing.css), bypassing Tailwind's purge pipeline. The Button component maps to explicit .btn--primary classes instead of bg-primary utilities.


Running it locally

cd foundry
pnpm install
cp .env.example .env.local
pnpm dev
Enter fullscreen mode Exit fullscreen mode

Open http://localhost:3000. Mock mode works without API keys — agents return realistic structured placeholders. For real LLM calls, set OPENAI_API_KEY and optionally OPENAI_BASE_URL=https://openrouter.ai/api/v1.

For contracts:

cd contracts
aiken check && aiken build
Enter fullscreen mode Exit fullscreen mode

What we'd build next

  • Persistent execution history across sessions (agent store currently resets on refresh)
  • Real Masumi payment settlement per agent task
  • Mainnet deployment path with audited contract templates
  • Agent memory sharing across projects via a vector store
  • Public marketplace where third-party agents can register and bid on tasks

Links

Top comments (0)