Human-in-the-loop workflows in StudioExplore

The framework to turn repetitive knowledge work into enterprise-ready agentic systems.

Start with one workflow.

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 · Git

bunx laufwerk init

Run in your project directory to set up Laufwerk and its configuration.

Read the guide

Build your first workflow

Help me build my first workflow with Laufwerk in this project.

Read the project instructions and current Laufwerk documentation at https://www.laufwerk.dev/docs/build. Check the setup requirements at https://www.laufwerk.dev/docs/setup. If Laufwerk is not initialized here, use bunx laufwerk init. Read the installed authoring instructions before writing workflow code.

Ask me which repetitive process I want to automate, what information each case starts with, and what a successful result looks like. Identify where my domain expertise is needed and which decisions should come back to a human.

Propose the smallest useful workflow. Implement it in TypeScript using the documented Laufwerk APIs, keeping agent work, deterministic tasks, and human decisions clear. Reuse the existing project structure and avoid unnecessary abstractions.

Check the workflow and explain how to run it in Studio, inspect its output, and respond to any human requests.

Build what makes your
business different.

Keep your engineering effort close to the work: domain rules, useful integrations, and results your experts can trust. Build on a maintained execution layer.

Your teamBusiness workflows, expert rules, integrations

The process and the definition of a good result.

LaufwerkExecute. Inspect. Review. Improve.

Durable workflows · Agent sessions · Human decisions · Evidence

Your environmentInfrastructure, model providers, business systems

The access and operating boundaries you choose.

Explore the platform

Built for the whole workflow.

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.

Workflows as code

Keep workflow code in your repository. Version, test, and review your process in TypeScript, with business rules your team controls.

Define / Review / Ship

Durable by design

Keep completed work when a run is interrupted. Inspect the failure and resume from persisted state.

Run / Persist / Resume

Observable. Auditable.

Follow agent traces, recorded operations, and human decisions. Keep results and reviewed cases to evaluate changes and inform a future migration.

Humans in the loop

Ask for approval, collect feedback, or request input. Human interaction is part of the workflow.

Approve / Respond / Continue

A Studio for your systems

See the state of your runs, inspect execution, and respond to human requests in one place.

Runs / Traces / Inbox

Built around frontier harnesses

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.

Codex + Claude today · More harnesses ahead

Self-hostable

Choose where agents run and what they can access. Review storage, provider traffic, isolation, and operational ownership before deployment.

Context management

Keep context across turns in a session. Give each agent the workspace, instructions, and information it needs.

Workspace + Instructions + Session

Build toward better workflows

Curate reviewed cases and compare workflow versions with dataset and benchmark APIs. Automatic workflow improvement remains product direction.

What does a workflow look like?

One example of a workflow built on Laufwerk: follow an issue through planning, implementation, and human review. Then explore the same workflow in TypeScript.

Example workflow

issue-to-pr

A planner and reviewer shape the change. An implementer works through feedback, checks gate publication, and a human decides whether to merge.

Starts with
A GitHub issue number and its repository
Produces
The exact approved commit merged, or a stopped run with failure evidence
taskagenthuman
Shape the changeIn order

Draft → review → revise once, even if the reviewer approved the draft.

Implement & reviewLoop

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.

Human decisionChoose one

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.

The same workflow, in TypeScript.

issue-to-pr / workflow.ts
issue-to-prWorkflow source
workflows/issue-to-pr/workflow.tsTypeScript
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))),
);
TypeScript · Durable executionHover or tap underlined calls to explore

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.

Benchmarking & workflow improvement

Improve the workflow. Keep the evidence.

Opt into evidence capture and curate reviewed cases. Use the dataset and benchmark APIs to compare workflow versions before changing how the work runs.

Build the dataset

Real cases from your workflows
A growing dataset
Choose the cases to retain
  • Trigger payload
  • Workflow version
  • Result and human-in-the-loop feedback

Curate cases and review labels that represent the work you need to get right.

Propose an improvement

Current workflowHow the work runs today
Proposed workflowRevised steps, instructions, or checks, ready to evaluate.

Your team proposes changes to steps, instructions, or checks. Automatic proposal generation remains product direction.

Same cases. Two workflows.

Illustrative benchmark · synthetic results
One dataset · 100 casesIdentical inputs for both versions
A

Current workflow

100 results82 pass · 18 need review
B

New workflow

100 results93 pass · 7 need review
PassNeeds review
Case 1 · illustrative results
MeasureCurrentNew
Time1m 50s1m 20s
Cost$0.42$0.24
QualityPassPass

Quality = passes the case’s checks and review criteria.

New workflow leads in this example
Summary of all 100 synthetic cases
Across 100 casesCurrentNew
Quality pass rate82%93%
Mean time / run3m 04s2m 14s
Mean cost / run$0.62$0.39

11 more cases pass. 27% less time and 37% lower cost per run on average.

Illustrative evaluation

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.

Industry use cases

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.

Example workflow

Issue to a verified pull request

Turn a tracked issue into an isolated patch, verified changes and a pull request for human review.

Starts with
A tracked issue and a pinned repository revision
Produces
A reviewed PR, or an explicit stop with evidence
taskagenthuman
Establish the changeIn order

In order

Build and reviewLoop

Check or review feedback → Plan again. Maximum 3 passes; then maintainer review.

Publication decisionChoose one
Gates pass + approvedIn order

Exactly one outcome

Make one useful
thing repeatable.

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 Laufwerk

Currently in alpha. Enterprise adoption starts with a scoped evaluation of your workflow and environment.