Skip to content

Raklet Engineering Workflow

This is the canonical end-to-end workflow for shipping a change at Raklet.

Operating model

AI is the implementer. Humans are the gatekeepers.

The engineer takes a task from the tracker, hands the link to an AI agent (Claude or Codex), and the AI drives the work — planning, worktree creation, implementation, QA, PR — pausing at named gates for human approval. The engineer's job is no longer to write the code; it's to pick the work, approve the plan, approve the QA, and review the final PR. Humans give feedback when the AI gets it wrong; the AI iterates.

This shifts the engineer's leverage: instead of one task at a time, an engineer can supervise multiple AI-driven tasks in parallel, moving between them as gates open.

Tracker

We are transitioning from Trello (8+ years of use) to Linear. Linear is canonical for all new work going forward. During the transition both boards have active tickets:

  • New tasks — features, bugs, ops, hotfixes — open as Linear issues.
  • In-flight Trello cards stay on Trello until they ship; do not re-create them in Linear partway through.
  • Pickup is fine from either board while the transition is in progress. When the AI receives a Trello card, it links the card URL in the PR; when it receives a Linear issue, it links RAK-*.
  • If a customer report arrives without a ticket, the engineer who picks it up opens the Linear issue before handing the link to the AI.

The nine phases

Each phase has one required action and one artifact. Two human-approval gates sit inside the loop: the Plan Gate (after phase 3) and the QA Gate (after phase 5). Nothing past those gates happens without human signoff.

1. Pickup — engineer claims the task

Who: Engineer. Action: Move the Linear issue to In Progress (or the equivalent Trello column) and confirm your understanding of the task in a comment. Artifact: Ticket status moved, ticket link copied.

  • If the task is ambiguous, get the author's confirmation in writing on the ticket before handing it to the AI. Ambiguous prompts produce ambiguous plans.
  • Don't pick up ad-hoc work that isn't on a board. Open a Linear issue first, even for yourself.

2. Hand-off — engineer → AI

Who: Engineer. Action: Open Claude Code (or Codex CLI) and paste the ticket link with a short prompt: "Take this task: . Plan it, then check in with me before coding." Artifact: AI session started, AI has the ticket context.

  • The engineer does not write the code. The engineer's role from here on is to approve at the two gates and to review the PR.
  • One ticket = one AI session = one branch = one PR. Don't bundle multiple tickets into one AI session.

3. Plan — AI plans, human approves (Plan Gate)

Who: AI proposes, human approves. Action: AI runs /autoplan (always). For non-trivial scope, AI also runs /plan-eng-review and/or /plan-ceo-review. AI surfaces the plan to the engineer. The engineer reviews, asks questions, and approves the plan. Artifact: A plan document the engineer has explicitly approved.

  • /autoplan is the auto-decision pipeline — it surfaces only the genuine taste-decisions (close approaches, borderline scope, codex disagreements) for human input. It is mandatory for every issue.
  • /plan-eng-review is the engineering-manager-mode review. Run it when the task touches architecture, data flow, edge cases, performance, or test coverage. Engineer's judgment.
  • /plan-ceo-review is the founder/CEO-mode review (rethink the problem, challenge premises, find the 10-star product). Run it when the task is meaningful product scope and the AI should sanity-check ambition vs the smallest-version-that-works. Engineer's judgment, escalate to CEO/CTO when the call isn't yours to make.
  • No code is written before the plan is approved. This is the first hard gate. AI must wait.
  • Acceptable to iterate: engineer pushes back, AI revises the plan, re-surfaces. Loop until the engineer types "approved" (or equivalent).
  • For obvious tiny work (typo, copy fix, single-config bump), the AI can surface a one-line plan; the engineer can approve in one line.

4. Implement — AI does the work

Who: AI. Action: AI creates a worktree from latest origin/master, branches in type/short-kebab-summary form, and implements the approved plan with logically grouped commits. Artifact: A worktree under .claude/worktrees/<short-name>/ with commits on a feature branch.

  • AI uses .agents/skills/worktree-workflow/SKILL.md for worktree commands. If packages/ references break, junction it to the main checkout's packages/.
  • New task, release-fix, and promotion-unblocker branches always start from origin/master. Do not branch from test or prod, and do not target them with manual fix PRs; fix on master and let Dev->Test / Test->Prod promotions carry the change forward. Emergency integration-branch work needs explicit approval in the current thread.
  • AI builds with scripts/dev/build-fast.ps1 — never raw msbuild.
  • New .cs files MUST be registered in the matching old-style .csproj as <Compile Include="..." />. The build silently skips them otherwise.
  • Frontend asset changes under Raklet.Backend/Content/ need scripts/dev/invoke-backend-grunt.ps1 to actually serve.
  • EF migrations go in their own branch and PR, released before the logic that depends on them — see Migration-first rule.
  • AI does not deviate from the approved plan. If implementation reveals the plan was wrong, AI pauses and re-surfaces a revised plan to the engineer (back to phase 3) — does not just silently change direction.

5. QA — AI runs, engineer approves (QA Gate)

Who: AI runs the suites, engineer approves the result. Action: AI runs /qa against the local environment. The skill captures screenshots of the changed flows, uploads them to Azure Blob via the pr-evidence skill, and posts a QA report (test results + screenshot links) back to the engineer. The engineer reviews the QA report and approves it. Artifact: A QA report with screenshot URLs and pass/fail per scenario, approved by the engineer.

  • The engineer who handed the task to the AI is the same person who approves the QA. Self-approval is fine here — the second pair of eyes is the PR reviewer in phase 8, not this gate.
  • If QA fails or the screenshots show something off, engineer gives feedback, AI iterates: fix → re-run QA → re-surface. Loop until QA passes.
  • Screenshots are mandatory for any user-facing change (controllers, views, services reached from controllers, JS/CSS bundles). They live in Azure Blob (rakletlocalfiles/customcodes/pr-evidence/<num>/), never in the repo.
  • Acceptable QA-skip cases (state in the PR): docs-only, infra-only (CI/scripts/.agents//.github/), build/csproj-only.

6. Open PR — AI, draft

Who: AI. Action: AI pushes the branch and opens a draft pull request with the full template body, the screenshot links from phase 5, and the ticket link. Artifact: Draft PR on GitHub linked to the Linear issue or Trello card.

  • PR opens as draft. Phase 7 is what flips it to ready.
  • Title: short, imperative, conventional-commit style: fix(crm): denylist stale Stripe refs. Under 70 characters.
  • Body uses .github/pull_request_template.md sections (Problem / Root Cause / Solution / Scope of Change / Risk / Test Notes). Skip sections that don't apply, but state why.
  • Body must include:
  • Ticket link (Linear: RAK-273 or Trello: <card url>)
  • Screenshot links from the QA run (Azure Blob URLs)
  • Plan approval reference (one line: who approved, when)
  • Re-check the description matches the actual diff after creation. PR text drifts during writing; catch it on first read.

7. Mark Ready — engineer flips draft to ready, CI runs

Who: Engineer. Action: After QA was approved (phase 5), engineer flips the PR from draft to ready. This triggers the full CI pipeline. Artifact: PR in Open state with CI checks running.

  • Refresh the description checklist before flipping to ready. The "How to test" boxes and "Remaining todos for production" section are not write-once — they drift as the work evolves. Right before marking ready, the author re-reads every checkbox against the final diff and makes each one true and current:
  • Delete boxes that no longer apply (a step you dropped, a template placeholder you never filled in, a check another PR now covers).
  • Tick anything already verified — including steps CI//qa proved in phases 5–7. An unchecked box means "not yet done", so don't leave verified work unchecked.
  • Add any verification or production step the change introduced that isn't listed yet.
  • Move real follow-up work that won't be done in this PR out of the checklist and into a Linear issue — don't leave it as a box.

This matters because the promotion gate later blocks Dev→Test / Test→Prod on these exact boxes. A stale unchecked box becomes a phantom blocker on every future promotion; a missing box lets unverified work ship. Curating the list at ready-time is what keeps the promotion gate meaningful instead of noise. The same review applies to any later push that changes scope — keep the checklist matching the diff. - The local QA in phase 5 is the smoke gate. The CI in phase 7 is the broader net (unit tests, integration tests, linters, build matrix). - Today: CI runs on GitHub Actions hosted runners on push, including while the PR is still draft. - Target state (in progress): CI for ready PRs runs on a Raklet-owned VM separate from developer machines. The dev machine is freed up the moment the engineer flips to ready; PR progress is tracked on GitHub. - After flip, the engineer can move on to the next task (handed to a new AI session). Watch the GitHub PR for CI status and reviewer feedback.

8. Review & Merge — peer reviewer approves, author squash-merges

Who: A different engineer (peer review), then the PR author merges. Action: Peer reviewer reads the diff, the PR body, the screenshots. One approval is required. Author squash-merges. Artifact: A squash commit on master with the PR's title and body, and a deleted feature branch.

  • One approval is the standard. CODEOWNERS may add owners automatically for high-risk areas (payments, auth, migrations, prod infra) — wait for those if they appear.
  • AI agents do not approve PRs. Copilot reviews are signal, not approval. When Copilot or bot comments arrive, AI triages them with .agents/skills/pr-comment-triage/SKILL.md before the human reviewer sees them.
  • Author merges. Use gh pr merge <num> --squash --delete-branch. No merge commits on master.
  • mergeStateStatus: BLOCKED on a PR with green CI usually means "review required" — master no longer requires CI checks to merge as of 2026-05-15.

9. Post-deploy — verify and close

Who: Engineer (the one who handed the task off, supervising the AI). Action: Verify the deploy landed and the live behavior matches expectations. Move the Linear issue to Done. Artifact: Linear issue moved to Done with a deploy timestamp and a brief "verified by …" note. (Trello cards still in flight: move to the Done column and link the merge commit.)

  • Master deploys automatically through the Azure pipeline (master → test → prod). Watch the pipeline; deploy is not done until prod is green.
  • For user-facing changes, run the post-deploy browse smoke against the deployed environment:
    gh workflow run browse-ui-tests.yml --ref master `
      -f suite=smoke `
      -f test_domain=.raklet.net `
      -f admin_url=https://admin.raklet.net/ng/
    gh run watch
    
    This is the deployed-environment version of the same suite that ran in phase 5 against local. The hosted-runner workflow is workflow_dispatch only by design — it validates the deployed environment, not the PR branch.
  • Watch GlitchTip (monitor.raklet.net) for new exceptions tied to the change for the first hour after deploy.

Migration-first rule

EF migrations are released in their own PR, merged and deployed before the logic that depends on them. Two PRs, in order:

  1. Migration PR: the Add-Migration output and only that. Merged, deployed, verified on test.
  2. Logic PR: the code that reads/writes the new schema. Merged after the migration is live in prod.

This protects against rollback scenarios where logic referencing a not-yet- shipped column starts throwing in prod. The AI must surface this split during the Plan phase — it is a planning decision, not an implementation detail.

Promotion gate: Dev→Test and Test→Prod

Master deploys roll out through two branch promotions — master → test and test → prod — each opened automatically as a "Dev to Test" / "Test to Prod" PR by dev-to-test.yml and test-to-prod.yml.

A promotion PR must not be merged while any feature PR rolled up in it still has an outstanding description todo. This is a hard rule, not a suggestion. The "How to test" checkboxes and the "Remaining todos for production" section of a feature PR are the author's record of what must be verified or finished before the change is safe in test/prod — promoting with them open ships unverified or known-incomplete work to a shared environment.

To make this enforceable instead of trusting memory, every promotion PR carries an auto-generated checklist:

  • scripts/ci/promotion-checklist.mjs runs inside the promotion workflow each time the PR is opened or updated.
  • It enumerates every feature PR in the promotion (squash subjects ending in (#N)), pulls each PR's outstanding todos, and posts one sticky comment on the promotion PR — a per-PR checklist with links straight back to each source PR, so the deployer knows exactly what to look at.
  • It sets a promotion-todo-gate commit status on the promotion PR: red while any todo is open, green when all are clear.

Before merging a Dev→Test or Test→Prod PR:

  1. Open the promotion-todo-gate checklist comment.
  2. For each PR listed under Outstanding, complete the work and tick the box on that source PR (or, if a box is stale/not-applicable, edit it out and say why in the PR). The checklist refreshes on the next push.
  3. Merge only once promotion-todo-gate is green.

A todo that genuinely does not gate the promotion (e.g. a follow-up tracked separately) should be removed from the source PR's description and captured as a Linear issue instead — don't leave it as an unchecked box that blocks every future rollout.

The gate is only as good as the boxes. It assumes each source PR's checklist was curated to be true and current when the PR was marked ready (phase 7). If you hit the gate and find a box is outdated — stale, a leftover template placeholder, or already satisfied — fix it at the source: edit the source PR's description (tick it if done, delete it if no longer applicable and note why), don't work around it on the promotion PR. The promotion gate enforces completion; keeping the items accurate is the author's job upstream, not the deployer's at promotion time.

What happens when you merge a promotion PR

Merging a promotion PR automatically starts the build on Azure DevOps. The merge commit on test / prod triggers the corresponding AzDO build pipeline — there is no manual "queue build" step. For Test→Prod, the build runs automatically on merge, but the prod deploy stage then waits at a manual approval gate before it goes live, so the new build serves at an unknown time (minutes to days) after merge — see prod-deploy-sentry-canary.md. The merge is not the deploy: watch the AzDO pipeline through to the prod stage going green.

Two mechanics to know when clearing the gate to merge:

  • The promotion-todo-gate check only recomputes on a push to the destination branch. Ticking todo boxes on the rolled-up source PRs does not refresh the check, and re-running its workflow run is a no-op (the promotion PR already exists, so the gate step is skipped). It next recomputes on the following merge into master / test. So the check can read stale-red even when every blocking box is genuinely ticked — verify the boxes at the source (gh pr view <n> --json body) rather than trusting a stale status.
  • test and prod have no required status checks (only master carries a ruleset). A stale-red promotion-todo-gate — or an environmental red like the ci-vm-1 browse smoke leg — therefore does not mechanically block gh pr merge. That makes verifying the actual todo state (above) the real gate, not the check colour.

Tiny PR exception

For trivial changes — typo fix, formatting, single-config bump, doc-only — the workflow shortens but does not skip phases:

  • Plan: AI surfaces a one-line plan; engineer approves in one line.
  • QA: Skipped only when the change is genuinely docs-only, infra-only (CI/scripts/.agents//.github/), or build/csproj-only. State the skip reason in the PR.
  • Review & Merge: A single peer approval is still required. No self-merge for AI-authored PRs, even tiny ones — the human review is the audit trail for AI-generated code.

Rules of thumb

  • AI implements, humans gate. No code without an approved plan. No PR ready without an approved QA. No merge without a peer review.
  • Plan-first, code-second. If the AI starts coding before the plan is approved, stop the session and restart at phase 3.
  • No promotion with open todos. Never merge a Dev→Test or Test→Prod PR while promotion-todo-gate is red — every rolled-up PR's description todos must be complete first. See Promotion gate.
  • One ticket = one session = one PR. No multi-ticket bundles.
  • No master commits. Worktree + branch + PR every time.
  • Build with build-fast.ps1. Never raw msbuild.
  • English in all agent-facing files (commits, branches, PR text).
  • No AI co-author trailers on commits, branches, or PRs unless explicitly requested.
  • No screenshots or binaries in the repo. Always Azure Blob via .agents/skills/pr-evidence/SKILL.md.

When things go wrong

  • AI disagrees with the engineer at the Plan Gate: AI explains why, engineer either accepts the AI's reasoning or overrides explicitly. AI defers to human override but logs the disagreement in the plan.
  • QA fails repeatedly: if the AI cannot get QA green after 2-3 iterations, pause and re-plan (back to phase 3). Don't keep grinding.
  • Merge conflicts on the branch: AI rebases onto origin/master, resolves in the worktree, force-pushes with --force-with-lease. Never --force.
  • CI failing on something the PR didn't change: engineer or AI checks git log origin/master for recent infra changes. May be flaky or a real rebase need.
  • You shipped something that broke prod: revert first, investigate after. Use the GitHub UI's Revert button on the merged PR (creates a revert PR you fast-merge), or locally:
    git revert <squash-commit-sha>
    gh pr create --title "Revert: <original title>" --fill
    gh pr merge --squash --delete-branch --admin
    
    Page the on-call channel immediately. Post-mortem comes later, rollback comes now.
  • Local DB drift after a migration shuffle: see the resolved memory note on Models-context drift, or ask #engineering. Do not run Update-Database against a context that may have abandoned migrations.

Reference

Gstack skills referenced in this workflow: - /autoplan — mandatory in phase 3 for every issue. - /plan-eng-review — phase 3, judgment. - /plan-ceo-review — phase 3, judgment, escalate to CEO/CTO when needed. - /plan-design-review — phase 3, when the task has UI/UX components. - /qa — phase 5, mandatory for user-facing changes. - /pr-evidence — phases 5 and 6, for Azure Blob screenshot uploads.