Skip to content
Back to skills

Start

ASecurity

Run red-green on one ticket or spec of this project, from worktree to fast-forward.

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
ai-agentsgobashnodegit

Security analysis

A100/100

Scanned November 7, 2026

npx -y skills add futorio/red-green --skill start --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Start?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Start
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/futorio-start/badge)](https://www.skillsdirectory.com/skills/futorio-start)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: start
description: Run red-green on one ticket or spec of this project, from worktree to fast-forward.
disable-model-invocation: true
---

# Start a red-green run

You are the main thread: you prepare the run, launch it, accept it and report. The user names only the ticket.

`<tools>` is `${CLAUDE_PLUGIN_ROOT}`, the core's checkout.

## 1. Inputs

- `target`: the ticket or spec path the user named. No path given: ask for it.
- `<name>`: a short slug of the ticket's file name.
- `<branch>`: the branch the user is on; `base`: its HEAD.
- `run`: a fresh scratchpad directory.
- `profile`: the contents of the project's profile file `.claude/red-green/profile.json`, else `{}`
  ([`args-and-profile.md`](../../docs/red-green/args-and-profile.md)).

With a profile file, check it: `node <tools>/.claude/workflows/red-green/template/render.mjs --check
.claude/red-green/profile.json`. Exit 1: stop here and give the user the check's stderr and the file's path; the
worktree and the run wait for a profile that passes.

With no declared gates (`profile.blocks.gates.gates` absent or empty), find them here; a run refuses to start without:

1. Find candidates: the repo's agent instructions, then CI config, then the task runner; the first source that names
   gates wins. A gate: a command CI or those instructions require before a commit; runs with no human, network or
   secrets; pass/fail by exit code; writes nothing to the tree.
2. Ask the user to pick and name them, proposing a tier per pick: `fast` a static check that reads the source without
   building it (lint, format check, typecheck); `round` a build, a test suite, or a gate you are unsure of; `acceptance`
   one too heavy to run each iteration. A run needs at least one `fast` or `round` gate.
3. Put the picks in `profile.blocks.gates.gates` as `{name, command, tier}`, for this run only: nothing is written to the
   project unless the user asks.
4. No candidate, or none picked: stop here and offer `/red-green:setup`.

Done when the check exits 0 (or there is no profile file), `profile` declares a `fast` or `round` gate, and every arg in
`args-and-profile.md`'s required rows has a value or a step below that gives it.

## 2. Worktree

`git worktree add ../wt-<name> -b wf/<name> <branch>`. `repo` is its absolute path, `branch` is `wf/<name>`. Copy or
symlink into it any gitignored file the project's gates need.

Done when `repo` has `wf/<name>` checked out at `base` and every gitignored file the gates read is in it.

## 3. Baseline

Measure the `fast` and `round` gates with the runner on the worktree, with a Bash timeout of 10 minutes:

`node <tools>/.claude/workflows/red-green/skills/run_gates.mjs --gates '<gates as JSON>' --dir <run> --repo <repo> --tier round --no-cache`

`<gates as JSON>` is `profile.blocks.gates.gates`, its commands' placeholders filled from the args
([`args-and-profile.md`](../../docs/red-green/args-and-profile.md)). Exit 3: run it again. Exit 2 or a `not_run` row: stop
here and give the user the reason. Each printed row's `status` and `line` become `args.baseline[<gate name>]`. Write
`<run>/gates.json` as `{<gate name>: {seconds, line}}` and give the user a line per gate: name, status, seconds, line.
`acceptance` gates are not measured at base.

Done when `baseline` and `gates.json` have an entry per `fast` and `round` gate, each with its seconds in the report.

## 4. Run

Pick the launch before calling. Only the session's working directory counts for a `scriptPath` launch, not `repo` or an
added directory:

- `<tools>` inside the session's working directory: `Workflow({scriptPath: '<tools>/.claude/workflows/red-green.js', args})`,
  which reads the scripts from disk.
- Any other case, a `<tools>` added with `/add-dir` included: `Workflow({name: 'red-green:red-green-workflow', args})`,
  and tell the user the run uses the scripts as they were at session start.

`args` is `{target, repo, branch, tools: '<tools>', run, base, baseline, profile}` in both.

A refused launch is not retried unchanged.

`<wf dir>` is the transcript directory the Workflow launch result prints; it holds the run's `journal.jsonl`.

The run goes on in the background and never waits for the user. Watch its journal with the Monitor tool, `timeout_ms`
1800000:

```
tail -n +1 -F <wf dir>/journal.jsonl | jq -cn --unbuffered 'foreach (inputs | select(.key)) as $r ({};
  if $r.type == "started" then .[$r.key] = $r.label else . end; .[$r.key] as $l
  | if $r.type == "started" and $l == "implement" then ({done: true}, halt)
    elif $r.type == "result" and ($l | IN("research", "plan", "replan")) then
      (($r.result | objects | .questions) // []) as $q | ($q[] | {stage: $l, requirement, question, reading, cases}), {stage: $l, questions: ($q | length)}
    else empty end)'
```

Give the user each question as it lands: stage, requirement, question, and the plan's reading and cases. Tell them a
reply settles it and that, unanswered, the run keeps the reading. Implement starts after plan and any replan, so the
watch command exits there, after a `{done: true}` line, and the watch ends with it, even when that line is lost. A run
that fails before implement ends the watch with its result: stop the monitor then (TaskStop). Re-arm it on an earlier
expiry.

A reply, or any detail the user adds meanwhile, goes to the run's mailbox
([`mailbox.md`](../../docs/red-green/mailbox.md)), and the run keeps going. A reply to a question is an entry `to: all`
whose text names the requirement.

Done when the run's result is in.

## 5. Accept

1. Save the spans: `node <tools>/.claude/workflows/red-green/trace.mjs <wf dir> > <run>/trace.jsonl`, `<wf dir>` as in § 4
   ([`tracing.md`](../../docs/red-green/tracing.md)).
2. Read the result ([`result.md`](../../docs/red-green/result.md)) and every commit on `wf/<name>`.
3. Delete from the worktree each `path` in `stray_proofs`: an uncommitted proof left by the run. Its `stray proof` entry
   in `failures` then no longer counts against the fast-forward; every other entry does. Then `git status --porcelain`
   in the worktree: acceptance measures the commit that lands, so anything left skips step 4 and stops the fast-forward;
   show it to the user at step 6.
4. Run the acceptance gates on the worktree, from scratch, with a Bash timeout of 10 minutes:

   `node <tools>/.claude/workflows/red-green/skills/run_gates.mjs --gates '<gates as JSON>' --dir <run> --repo <repo> --tier acceptance --no-cache --baseline '<baseline as JSON>'`

   Exit 3: run it again. Blocking: a row with status `red` or `not_run`, or exit 2. A `known_red` row is reported and not
   blocking.
5. Fast-forward `<branch>` to `wf/<name>` when all of these hold and the user did not ask to hold:
   - `failures` holds nothing but the `stray proof` entries of step 3;
   - `verdicts` holds no `DIED` or `SILENT`;
   - `leftover_findings` holds no blocking finding: `severity: major` or `status: unmet`. A leftover minor or `unverified`
     row goes in the report and does not stop it;
   - step 3 left the worktree clean and step 4 found nothing blocking.
6. Otherwise both branches stay. A red `acceptance` gate may first be run on base: in a temporary worktree at `base`,
   given the gitignored files the gates read, with `--gates` holding that gate, `--tier acceptance` and `--dir <run>/base`, then removed. Red
   there too is an old breakage, and you report it as one. Show the user the findings and wait for the choice:
   - accept: fast-forward as in step 5;
   - fix: make the fixes on `wf/<name>` in the worktree, then repeat from the status check of step 3;
   - new run: it takes a `<name>` of its own, since `wf/<name>` stays.
7. After the fast-forward or the user's decision, and only then: remove the worktree (`git worktree remove <repo>`),
   delete every directory under `run` (keeping its top-level files, `trace.jsonl` and `gates.json` among them), then
   `git worktree prune`.

Done when `trace.jsonl` and `gates.json` are in `run`, the branch is fast-forwarded or the user has decided with the
reason in the report, `run` holds no directory, and the worktree is removed.

## 6. Report

To the user: `status`, the commits, the acceptance rows, the strays deleted, `leftover_findings`, `advisory`, `verify_launch` (checks only a person can make), the open
questions per stage, and the tokens per block from `trace.mjs --table`.

Done when the report names each of them, `none` where one is empty.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.