Workflows as code
Keep workflow code in your repository. Version, test, and review your process in TypeScript, with business rules your team controls.
Turn your domain expertise into a process you can run. Compose agents, tasks, and human decisions in TypeScript. Laufwerk keeps track of the execution.
Bun ≥1.4.2 · Node ≥22 · Gitbunx laufwerk init
Run in your project directory to set up Laufwerk and its configuration.
Keep your engineering effort close to the work: domain rules, useful integrations, and results your experts can trust. Build on a maintained execution layer.
The process and the definition of a good result.
Durable workflows · Agent sessions · Human decisions · Evidence
The access and operating boundaries you choose.
The building blocks to turn a working idea into a system you can run, inspect, and improve. Your team controls the process, access, and human approvals.
Keep workflow code in your repository. Version, test, and review your process in TypeScript, with business rules your team controls.
Keep completed work when a run is interrupted. Inspect the failure and resume from persisted state.
Follow agent traces, recorded operations, and human decisions. Keep results and reviewed cases to evaluate changes and inform a future migration.
Ask for approval, collect feedback, or request input. Human interaction is part of the workflow.
See the state of your runs, inspect execution, and respond to human requests in one place.
Run Codex and Claude through their native harnesses, using your existing subscriptions. We’re exploring lightweight harnesses like Pi and Vercel’s fx for more control over agent behavior.
Choose where agents run and what they can access. Review storage, provider traffic, isolation, and operational ownership before deployment.
Keep context across turns in a session. Give each agent the workspace, instructions, and information it needs.
Curate reviewed cases and compare workflow versions with dataset and benchmark APIs. Automatic workflow improvement remains product direction.
One example of a workflow built on Laufwerk: follow an issue through planning, implementation, and human review. Then explore the same workflow in TypeScript.
A planner and reviewer shape the change. An implementer works through feedback, checks gate publication, and a human decides whether to merge.
Draft → review → revise once, even if the reviewer approved the draft.
Up to 3 implementation passes initially; 2 after human feedback. Review approval exits early. The final allowed pass skips agent review and reports that limitation.
Requested changes return to Implement & review. Empty feedback prompts again; it does not start another coding cycle.
Failed checks or commit export stop the run before publication.
import { Workflow } from "@effect/workflow";
import { Human, Session, Workspace } from "@laufwerk/sdk";
import { Effect, Schema } from "effect";
import {
execution,
implementer,
planner,
reviewer,
} from "../../agents/factory";
import {
branchFor,
merge,
prepareIssue,
publish,
} from "../../tasks/factory";
export const Review = Schema.Struct({
approved: Schema.Boolean,
feedback: Schema.String,
});
export const workflow = ({
name: "issue-to-pr",
payload: { issueNumber: Schema.Int.pipe(Schema.positive()) },
success: Schema.String,
error: Schema.String,
idempotencyKey: ({ issueNumber }) => `laufwerk-issue-${issueNumber}`,
});
export const layer = ((input) =>
(function* () {
const issue = yield* (input.issueNumber);
const workspace = yield* ({
source: issue.source,
execution,
});
const request = `${issue.url}\n${issue.title}\n\n${issue.body}`;
const planning = yield* ({
key: "planner",
agent: planner,
workspace,
access: "read-only",
});
let plan = yield* ({
key: "draft",
prompt: `Inspect the repository and plan this issue. Give concrete acceptance criteria, minimal implementation steps and verification.\n${request}`,
});
const planReview = yield* ({
key: "plan-review",
agent: reviewer,
workspace,
access: "read-only",
output: Review,
prompt: `Review this plan against the actual source and issue. Identify missing requirements, duplicated mechanisms, unnecessary complexity and verification gaps.\nIssue: ${request}\nPlan: ${plan}`,
});
plan = yield* ({
key: "revise",
prompt: `Revise the plan once using this feedback (even if approved). Return the complete final plan and explicitly name unresolved disagreements.\n${planReview.feedback}`,
});
yield* ();
// Keep the implementer's context within a coding cycle; close it before human
// suspension so idle approvals do not retain running containers indefinitely.
let humanFeedback = "";
for (let cycle = 0; ; cycle++) {
const coding = yield* ({
key: `implementer-${cycle}`,
agent: implementer,
workspace,
access: "read-write",
});
let feedback = humanFeedback || planReview.feedback;
let summary = "";
let reviewStatus = "";
const passes = cycle === 0 ? 3 : 2;
for (let pass = 1; pass <= passes; pass++) {
summary = yield* ({
key: `implement-${pass}`,
prompt: `Implement this issue and plan. ${cycle > 0 ? "This revises the existing PR in response to the human." : ""}
Issue: ${request}\nPlan: ${plan}\nFeedback: ${feedback}
Inspect the current source, implement minimal changes and run relevant tests. Report what changed, evidence and limitations.`,
});
if (pass === passes) {
reviewStatus = `The last implementation pass (${pass}) was not reviewed, as specified by the iteration limit. Previous review feedback: ${feedback}`;
break;
}
const review = yield* ({
key: `code-review-${cycle}-${pass}`,
agent: reviewer,
workspace,
access: "read-only",
output: Review,
prompt: `Independently inspect all changes against base ${issue.base} (including untracked files). Check the issue and final plan are fully implemented. Reject defects, unnecessary complexity, duplicate code, unrelated edits, weak tests or unsupported verification claims.
Issue: ${request}\nPlan: ${plan}\nHuman feedback: ${humanFeedback}\nImplementation report: ${summary}`,
});
reviewStatus = review.approved
? `Code review approved: ${review.feedback}`
: `Code review rejected: ${review.feedback}`;
if (review.approved) break;
feedback = review.feedback;
}
// Required checks run in Docker and cannot execute repository code on the host.
const check = yield* ({
key: "verify",
command:
"bun install --frozen-lockfile && bun run check && bun run test:ci",
});
if (check.exitCode !== 0) {
yield* ();
return yield* (
`Required verification failed; nothing published.\n${check.stdout}\n${check.stderr}`,
);
}
const branch = (issue.number);
const exported = yield* ({
key: "commit-and-export",
command: `set -eu
[ "$(git branch --show-current)" = '${branch}' ]
git merge-base --is-ancestor '${issue.base}' HEAD
git -c core.hooksPath=/dev/null add -A
if ! git diff --cached --quiet; then
git -c core.hooksPath=/dev/null -c user.name='Laufwerk Factory' -c user.email='factory@laufwerk.local' commit -m 'Implement issue #${issue.number} (revision ${cycle})' >&2
fi
[ "$(git rev-parse HEAD)" != '${issue.base}' ]
git bundle create /tmp/factory.bundle 'refs/heads/${branch}' '^${issue.base}' >&2
base64 -w0 /tmp/factory.bundle`,
});
yield* ();
if (exported.exitCode !== 0)
return yield* (
`Commit/export failed: ${exported.stderr}`,
);
const report = `${summary}\n\n${reviewStatus}\n\nRequired verification passed: bun run check; bun run test:ci.\n\n${cycle > 0 ? `Human feedback addressed:\n${humanFeedback}` : ""}`;
const pr = yield* (
issue,
cycle,
exported.stdout.trim(),
report,
);
const approved = yield* ({
key: `approve-${cycle}`,
title: `Review PR #${pr.number}`,
description: `${pr.url}\nCommit: ${pr.sha}\n\n${report}\n\nApprove to squash-merge this exact commit. Reject to supply requested changes.`,
});
if (approved) return yield* (pr);
humanFeedback = yield* ({
key: `feedback-${cycle}`,
title: `Requested changes for PR #${pr.number}`,
description: `${pr.url}\nDescribe what the implementer should change.`,
});
// Blank rejection must not start another paid coding cycle.
for (let attempt = 1; !humanFeedback.trim(); attempt++) {
humanFeedback = yield* ({
key: `feedback-${cycle}-required-${attempt}`,
title: "Please describe the requested changes",
description: pr.url,
});
}
}
}).pipe(((error) => String(error))),
);
An archived issue-to-PR reference from Laufwerk’s development project, with simplified agent and task excerpts. GitHub helpers are omitted. The software factory is not a product we sell: Laufwerk is the foundation for your own systems. This example is separate from the starter workflow.
Opt into evidence capture and curate reviewed cases. Use the dataset and benchmark APIs to compare workflow versions before changing how the work runs.
Curate cases and review labels that represent the work you need to get right.
Your team proposes changes to steps, instructions, or checks. Automatic proposal generation remains product direction.
| Measure | Current | New |
|---|---|---|
| Time | 1m 50s | 1m 20s |
| Cost | $0.42 | $0.24 |
| Quality | Pass | Pass |
Quality = passes the case’s checks and review criteria.
| Across 100 cases | Current | New |
|---|---|---|
| Quality pass rate | 82% | 93% |
| Mean time / run | 3m 04s | 2m 14s |
| Mean cost / run | $0.62 | $0.39 |
11 more cases pass. 27% less time and 37% lower cost per run on average.
Compare quality, time, and cost on the same cases. Adopt the version that improves your objective.
Dataset and benchmark APIs are available from alpha.14. The comparison above uses synthetic cases to illustrate the method; it is not a product performance result. Fully automatic workflow improvement remains product direction.
The strongest fits are repetitive processes where domain expertise is applied to specific cases. These examples show how Laufwerk extends across industries; they are illustrative workflows, not prebuilt products.
Turn a tracked issue into an isolated patch, verified changes and a pull request for human review.
In order
Check or review feedback → Plan again. Maximum 3 passes; then maintainer review.
Exactly one outcome
Assemble the evidence, check the policy and calculate supported amounts. An adjuster owns the decision.
Independent analyses. Wait for all three results; missing data stays explicit.
Exactly one outcome
Research supply for each component, compare landed costs and turn an approved purchasing plan into orders.
Independent components; at most 4 active. Keep an outcome for every BOM line.
Both analyses required for this component
Every item needs an outcome · A–D illustrate the repeated work
Exactly one outcome
Check a carrier invoice against delivery evidence and contracted rates before posting an approved payable.
Wait for both analyses
While waiting: deadline → broker escalation. Hold posting until resolved.
One route. Only matched or resolved, re-audited invoices continue to approval.
Confirmed is different from unknown
Collect source evidence once, evaluate each control and prepare an evidence package for human sign-off.
All required sources must respond or be explicitly marked unavailable
Reuse evidence IDs; all scoped controls need a disposition.
Every item needs an outcome · A–D illustrate the repeated work
A licence to Laufwerk, ongoing development, and hands-on support. We work with your implementation owner, examine the actual workflow, and help get your first system running.
Discuss your use case Working with LaufwerkCurrently in alpha. Enterprise adoption starts with a scoped evaluation of your workflow and environment.