Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion web/app/flows/onboarding/AgentStepEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { defaultAgentPrompt, resolveAgentSettings, type AgentRole, type FlowAgen
import type { FlowTrack } from '../../../lib/flow-analytics';
import s from './onboarding.module.css';

const roleLabels: Record<AgentRole, string> = { planner: 'Plan', 'plan-reviewer': 'Review plan', 'prototype-1': 'Implementation 1', 'prototype-2': 'Implementation 2', 'prototype-3': 'Implementation 3', comparator: 'Compare', implementer: 'Implement', adversary: 'Review', fixer: 'Fix review findings' };
const roleLabels: Record<AgentRole, string> = { planner: 'Plan', 'plan-reviewer': 'Review plan', 'prototype-1': 'Implementation 1', 'prototype-2': 'Implementation 2', 'prototype-3': 'Implementation 3', comparator: 'Compare', implementer: 'Implement', adversary: 'Review', fixer: 'Fix review findings', 'check-discovery': 'Find how to run checks', 'check-repair': 'Repair failing checks' };

export function AgentStepEditor({ draft, roles, onChange, onClose, onTrack }: { draft: FactoryDraft; roles: AgentRole[]; onChange: (draft: FactoryDraft) => void; onClose: () => void; onTrack: FlowTrack }) {
const dialog = useRef<HTMLDialogElement>(null);
Expand Down
4 changes: 2 additions & 2 deletions web/app/flows/onboarding/RunOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ export function RunOptions({ draft, chosen, setDestination, onTrack, getJourneyI
<li><strong>Check and run on a new branch</strong>{command(LOCAL_RUN, 'run commands')}</li>
</ol>
<details className={s.localRequirements} onToggle={event => onTrack('help_toggled', { section: 'local_requirements', open: event.currentTarget.open })}><summary>Requirements and local behavior</summary>
<p>Node.js 22.18+, macOS (Apple silicon) or Linux (x64), your selected coding agents installed and signed in, and GitHub CLI authenticated. Start with a clean Git repository and a working <code>npm test</code> command.</p>
<p>The local version uses a one-hour runtime limit, not a dollar cap. Your coding agent’s usage charges still apply. Every preset stops at “needs_human” for you to review and merge the PR in GitHub.</p>
<p>Node.js 22.18+, macOS (Apple silicon) or Linux (x64), your selected coding agents installed and signed in, and GitHub CLI authenticated. Start with a clean Git repository whose tests run the way its CI runs them; the flow reads your CI configuration to find the command, or you can set <code>checkCommand</code> in the flow.</p>
<p>The local version uses a two-hour runtime limit, not a dollar cap. Your coding agent’s usage charges still apply. Every preset stops at “needs_human” for you to review and merge the PR in GitHub.</p>
<p>In GitHub, require approving reviews and passing CI checks in your target branch’s rules. A repository administrator needs to configure these protections.</p>
<p>This runs one ticket. Automatic triggers from your issue tracker require a separate connection.</p>
</details>
Expand Down
8 changes: 6 additions & 2 deletions web/lib/flow-agent-settings.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { isCodingAgent, type CodingAgent } from './flow-agents';
import type { WorkflowId, WorkflowStep } from './flow-workflows';

export const AGENT_ROLES = ['planner', 'plan-reviewer', 'prototype-1', 'prototype-2', 'prototype-3', 'comparator', 'implementer', 'adversary', 'fixer'] as const;
export const AGENT_ROLES = ['planner', 'plan-reviewer', 'prototype-1', 'prototype-2', 'prototype-3', 'comparator', 'implementer', 'adversary', 'fixer', 'check-discovery', 'check-repair'] as const;
export type AgentRole = typeof AGENT_ROLES[number];
export type AgentSettings = { agent?: CodingAgent; model?: string; prompt?: string };
export type FlowAgentSettings = Partial<Record<`${WorkflowId}:${AgentRole}`, AgentSettings>>;
Expand All @@ -20,7 +20,11 @@ export function defaultAgentPrompt(workflow: WorkflowId, role: AgentRole): strin
case 'comparator': return 'Compare the implementations and test results in the provided worktrees. Read their code and prototype-notes.md. Write comparison.md with each prototype path, strengths, weaknesses, and which ideas to combine. Do not modify the prototypes or implement yet.';
case 'implementer': return (workflow === 'traditional' ? 'Follow reviewed-plan.md. ' : workflow === 'prototype' ? 'Read comparison.md and inspect the prototype implementations it references. Combine the strongest ideas into the final implementation on the current branch, not in the prototype worktrees. ' : '') + 'Implement on the current branch. Add regression tests. Commit changes. Write a PR summary to summary.md.';
case 'adversary': return 'Review the PR diff, tests, and all PR comments. ' + (workflow === 'prototype' ? 'Read comparison.md to check that the final implementation combines the strongest ideas. ' : '') + 'Find bugs and edge cases. Write review.md. Create review.clean only if no issues remain.';
case 'fixer': return 'Read review.md and gh pr view --comments. Address every issue. Commit fixes without pushing. The workflow runs tests and pushes only after they pass.';
case 'fixer': return 'Read review.md and gh pr view --comments. Address every issue. Commit fixes without pushing. The workflow runs the checks and pushes the revision.';
// Setup, not the ticket: the ticket text arrives with every task, so the
// prompt says plainly not to start on it.
case 'check-discovery': return 'This is a setup step: do not start on the ticket. Work out how this repository checks itself on a fresh machine, the way its CI does. Read the CI configuration (.github/workflows, .gitlab-ci.yml, .circleci and similar), any Makefile, justfile or Taskfile, and AGENTS.md, CLAUDE.md, CONTRIBUTING and README. Write .relayflow/check.sh: a POSIX sh script starting with set -e that installs dependencies, runs whatever CI runs before its tests (builds, code generation), then runs the tests. Leave out steps that need secrets, deployments or services this machine does not have, with a comment saying why. Do not run the full test suite, do not change any other file, and do not commit. If the repository has no tests, do not create the file.';
case 'check-repair': return 'The repository\'s checks failed on this branch. The command that ran is .relayflow/check.sh and its full output is in .relayflow/check.log. For each failure, work out whether it comes from missing setup (a build, code generation or install step the tests expect, often named in the error) or from a bug in the change on this branch. Fix missing setup by adding the step to .relayflow/check.sh the way the repository\'s CI does it; do not commit that file. Fix bugs in the change and commit the fix. Never skip, delete or weaken a test, and never change a test only to make it pass. If a failure is outside your control, such as a tool that is not installed, no network, or missing credentials, leave it and write what you found to .relayflow/repair-notes.md.';
default: return '';
}
}
Expand Down
7 changes: 4 additions & 3 deletions web/lib/flow-local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ const RUN = ${JSON.stringify(LOCAL_RUN)};
const KIT_FILES = new Set([
"START-HERE.txt", "flow-input.json", ${JSON.stringify(LOCAL_PREFLIGHT)},
"software-factory.flow.mts", "package.json", "package-lock.json",
"node_modules/", ".relayflowd/", "summary.md",
"node_modules/", ".relayflowd/", ".relayflow/", "summary.md",
]);

// KIT_FILES exempts names from the dirty-tree check; it is not a description of
Expand Down Expand Up @@ -427,7 +427,7 @@ Requirements
- macOS on Apple silicon or Linux x64 (bundled runtime platforms).
- ${names}, installed and signed in.
- GitHub CLI (gh), signed in, and a repository with push access to origin.
- The flow installs your repository's dependencies with its package manager (pnpm, Yarn, Bun, or npm, chosen by lockfile) and runs its test script. Without a package.json or a test script it reports that it skipped the tests and carries on. If your project uses another test command, change testCommand in software-factory.flow.mts before running.
- The flow runs your repository's own checks. Before changing any code, an agent reads your CI configuration, Makefile and README and writes .relayflow/check.sh; failing that it uses your ecosystem's default (a make or just test target, npm/pnpm/Yarn/Bun, cargo, go, pytest, bundle, Maven, Gradle, dotnet or mix). To use your own command instead, set checkCommand in software-factory.flow.mts, or commit a .relayflow/check.sh. The tools your checks need must be installed.

1. Extract this kit into your repository root. Keep any existing files before replacing them. Open a terminal in that directory.

Expand All @@ -443,9 +443,10 @@ ${LOCAL_PREFLIGHT} runs first and stops before any model usage if this is not a

The flows command then starts the local runtime and attaches the local worker. Coding agents use their existing local sign-in; no Agent Relay Cloud account is needed. This flow edits code, runs tests, pushes the branch, and opens a pull request.
If the agents commit nothing — a ticket with nothing to do in this repository — the run stops before pushing: no branch, no pull request, and a line saying why.
If the checks fail, a repair agent reads the output and fixes missing setup or its own bugs, never by weakening tests. Whatever still fails is compared with the commit the branch started from, and the pull request opens as a draft with both outputs in its body: the work is never thrown away. A change that breaks checks which pass on the starting commit ends as step_failed (exit code 1). Working files (summary.md, plans, reviews, .relayflow/) are kept out of the commits through .git/info/exclude, and removed from the branch before pushing if an agent committed them anyway.

Local runtime behavior
This local version uses a one-hour wall-clock budget. Model usage is billed by your coding-agent provider; this is not a dollar cap.
This local version uses a two-hour wall-clock budget. Model usage is billed by your coding-agent provider; this is not a dollar cap.
Every preset reports needs_human (exit code 3) after its checks and any agent reviews pass. This is the intended manual approval stop, not a failed run. Review and merge the PR in GitHub; the flow never merges automatically and does not resume automatically after approval.
A run whose adversarial review does not pass ends as step_failed (exit code 1) instead. Its findings are written to review-blocked.md and posted to the pull request, and the pull request is left as a draft so it cannot be merged by accident.
${draft.workflow === 'prototype' ? 'Prototype worktrees remain available under the generated temporary directory for inspection.' : ''}
Expand Down
2 changes: 1 addition & 1 deletion web/lib/flow-onboarding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export function factoryCodeSections(draft: FactoryDraft, target: 'cloud' | 'loca
// such a step runs unmetered, so a dollar cap cannot bound it. Wall-clock is
// enforced on every step regardless of pricing, which is why it stays the
// default here; `{ dollars, wallclock }` together is also valid.
const budget = '{ wallclock: "1h" }';
const budget = '{ wallclock: "2h" }';
if (!draft.sources.length) return [{ id: 'empty', code: `import { flow } from "@relayflows/surface";

export default flow("software-factory",
Expand Down
Loading
Loading