Pull Request Conventions

Before Opening PR or Committing

Run make check to ensure lint, format, ty, verifytypes, and test suites pass.

For significant changes, such as changes to CLI commands, new features, or workflow changes, update the relevant docs in docs/ as needed.

For branch stability and release expectations, see the Development and Release Process. PRs merge into main, which is the active development branch rather than the stable release channel.

While Making PR

If you are an AI, always create PRs as drafts (gh pr create --draft).

Inspect reuse review

For changes involving agents, tools, scoring, logs, datasets, retries, or caching, reviewers should check the pinned Inspect API before accepting a new abstraction. Prefer the existing primitive when it meets the requirement; otherwise explain the missing capability briefly in the PR description. This is a review question, not a blanket ban on custom code.

PR Description

Write detailed pull request descriptions, and keep them accurate as you push new changes.

Describe what the pull request changes, why, and any reviewer-relevant boundaries. When a Linear issue tracks the work, link it, but keep the pull request description sufficient to review the proposed diff. Follow the documentation placement guidance for project state that does not belong in repository documentation.

When your changes involve evaluation runs or trajectories, link them in the description:

  • Runs: https://equistamp.linuxarena.ai/runs/<run_id> (e.g., https://equistamp.linuxarena.ai/runs/6a429632c3784f538be602f79be822fc)
  • Trajectories: https://equistamp.linuxarena.ai/trajectories/<trajectory_id> (e.g., https://equistamp.linuxarena.ai/trajectories/rate_limiting%3Aeavesdropper%3Ac63195_epoch1_attack_700aa832)

The CI report maintains one collapsed change breakdown in the PR description; keep author-written prose outside its HTML markers. Metric details and workflow timings live in linked job summaries and artifacts (see CI checks and reports).

Successful docs, public viewer, and private viewer preview builds append one line per site to the PR description: <Website> preview deployed to https://control-tower-<site>-pr-<number>.vercel.app, where <site> is docs, public-viewer, or private-viewer. Each URL points at the latest successful preview deployment for that PR, and redeploys update the existing line.

PR Naming

We follow Conventional Commits. We squash-merge, so the PR title becomes the commit subject on main and feeds the auto-generated release notes.

Format: type(scope): description

Type (required) — the kind of change:

TypeUse for
featA new feature or capability
fixA bug fix
docsDocumentation only
refactorA code change that neither fixes a bug nor adds a feature
perfA performance improvement
testAdding or correcting tests
choreTooling, dependencies, config, maintenance
ciCI / workflow changes
buildBuild system or packaging
revertReverting a previous change
researchResearch experiments and analysis (see the blue/red PR templates)

Append ! after the type or scope to mark a breaking change: feat(eval)!: drop legacy task-set format.

Scope (optional) — the control-tower subsystem the change touches. Omit it for cross-cutting work. Common scopes: cli, eval, monitor, protocols, trajectories, mtgen, sabotage-eval, sandbox, fleet, internet-simulator, environments, viewer, live, safety, hawk. Research PRs use blue or red.

Description — imperative and concise, no trailing period.

Examples:

  • feat(eval): add --tags option to ct run eval
  • fix(internet-simulator): stream full upstream response through forward proxy
  • fix(trajectories): exclude None-scored side tasks from failure analysis
  • refactor(fleet): simplify EC2 resume path
  • docs: update running-evals guide
  • research(blue): side-task visibility experiment

The pr-title-lint workflow validates only the type; any scope is accepted.

Labels: scripts/generate_release_notes.py groups release notes by the commit subject's type(scope), and labels drive filtering, so also add the matching label:

  • tooling - For tooling/infrastructure changes
  • environment - For environment-related changes
  • straj - For sabotage trajectory PRs
  • main-task / side-task - For task-related changes
  • bug - For bug fixes
  • documentation - For docs-only changes

After Opening a PR

Keep monitoring the PR until it is merged or explicitly handed off to someone else. Poll it periodically for:

  1. Failed status checks: If CI fails, investigate and fix the issue. Push a new commit to trigger re-runs.
  2. Review comments: Respond to all comments. Push a fix when one is needed, explain your reasoning when you disagree or need clarification, and reply briefly to acknowledgments.
  3. Merge conflicts: If the PR falls behind main and has conflicts, rebase and resolve them.