LaufwerkLaufwerk
Examples

Documentation repair

Repair a small command’s README, then verify both its behavior and the allowed change boundary.

Repair a small command’s README, then verify both its behavior and the allowed change boundary.

Set up the example

Start in a project created with bunx laufwerk@0.0.1-alpha.6 init --example coding. Complete host setup first. Run these commands from the consumer project root. The download contains synthetic fixtures and complete workflow source.

curl -fsSLo workflow-recipes.tar.gz https://www.laufwerk.dev/downloads/alpha6/workflow-recipes.tar.gz
tar -xzf workflow-recipes.tar.gz
mkdir -p laufwerk/workflows
cp workflow-recipes/agents.ts laufwerk/recipe-agents.ts
mkdir -p laufwerk/workflows/docs-repair
sed 's|../../agents|../../recipe-agents|' workflow-recipes/workflows/docs-repair/workflow.ts > laufwerk/workflows/docs-repair/workflow.ts
cp -R workflow-recipes/fixtures/cli ./cli-trial
git -C cli-trial init
git -C cli-trial add .
git -C cli-trial -c user.name="Laufwerk trial" -c user.email="trial@example.invalid" commit -m "Initial fixture"
bun run --cwd laufwerk check

Run it

bunx laufwerk@0.0.1-alpha.6 run docs-repair --input '{"executionKey":"docs-repair-1","source":"cli-trial"}'

Expect completed (healthy). Read cli-trial/README.md, then run sh verify.sh inside cli-trial. Only the README should differ: inspect git -C cli-trial diff.

The workflow records the original Git revision before the model starts. Verification compares against that revision, so staging an implementation change cannot hide it. It also rejects untracked files. The behavior checks are intentionally specific to this tiny fixture; adapt them to your repository.

This is a check against accidental changes, not a hostile-code security boundary: the agent and verification run in the same writable sandbox. For untrusted candidates, run trusted verification outside the candidate’s write permissions before publication.

How it works

This is the complete workflow. The download provides a Codex agent using the same subscription setup as the starter.

laufwerk/workflows/docs-repair/workflow.ts
import { Workflow } from "@effect/workflow";
import { Session, Workspace } from "@laufwerk/sdk";
import { Cause, Effect, Exit, Schema } from "effect";
import { analyst } from "../../recipe-agents";

// Compare with the immutable pre-turn revision, never the mutable Git index.
export const documentationCheck = (revision: string) => {
  if (!/^[a-f0-9]{40}$/.test(revision)) throw new Error("Invalid baseline revision");
  return `git diff --exit-code ${revision} -- . ':!README.md' && test -z "$(git ls-files --others --exclude-standard)" && sh verify.sh`;
};

export const workflow = Workflow.make({
  name: "docs-repair",
  payload: { executionKey: Schema.String, source: Schema.String },
  success: Schema.String, error: Schema.String,
  idempotencyKey: input => input.executionKey,
});
export const layer = workflow.toLayer(input => Effect.gen(function* () {
  const workspace = yield* Workspace.open({ source: input.source });
  const session = yield* Session.open({ key: "docs", agent: analyst, workspace, access: "read-write" });
  const result = yield* Effect.exit(Effect.gen(function* () {
    const baseline = yield* session.exec({ key: "baseline", command: "test -z \"$(git status --porcelain)\" && git rev-parse HEAD" });
    if (baseline.exitCode !== 0) return yield* Effect.fail("Documentation repair requires a clean committed source tree");
    const revision = baseline.stdout.trim();
    if (!/^[a-f0-9]{40}$/.test(revision)) return yield* Effect.fail("Invalid source revision");
    const summary = yield* session.ask({
      key: "repair",
      prompt: "Check bin/task-summary and its actual --help behavior against README.md. Correct only README.md to accurately document supported flags, invocation, output and exit behavior. Keep it concise, with working examples. Do not change implementation or tests.",
    });
    const check = yield* session.exec({ key: "check", command: documentationCheck(revision) });
    if (check.exitCode !== 0) return yield* Effect.fail(`Documentation verification failed: ${check.stderr}`);
    return summary;
  }));
  yield* session.close();
  if (Exit.isFailure(result)) return yield* Effect.fail(Cause.pretty(result.cause));
  yield* Workspace.writeBack({ workspace });
  return result.value;
}).pipe(Effect.mapError(String)));

Use a new execution key for each new attempt. Inspect failed or waiting runs →

On this page