Skip to main content

Operating model

Current mode: direct pushes to main. The owner has authorized direct pushes to main as the standard workflow. Work happens on main in the canonical checkout; commits are pushed directly without pull-request ceremony, and the staging/Vercel QA lane is skipped unless the owner requests it for a specific change. The Builder/Integration model below remains the reference for any change the owner flags for staged QA, and becomes the default again if this mode is revoked. Direct-to-main does not relax the safety rules; they become local-verification requirements:
  • Run checks proportional to the change before pushing (same evidence table as below).
  • Keep CHANGELOG.md and the applicable living docs current in the same commit series.
  • Push only fast-forward updates. The history-integrity ruleset still blocks force-pushes, resets, and branch deletion on main and staging for every actor including DevelopedByDev.
  • Root vercel.json must keep git.deploymentEnabled.main set to false. After each push, verify that no production Vercel deployment was created.
  • Keep commits to one coherent change each; the absence of a PR boundary is not license to mix unrelated work.
Overlay uses two agent roles. A Builder works in one isolated worktree and normally submits a pull request to staging. The Integration agent reviews and merges the owner-selected candidate base, tests the required revision, and promotes or deploys it according to the explicit release choice. The canonical checkout stays clean and remains the trusted source for production operations. GitHub pull requests, checks, and commit history are the authoritative integration record. Do not maintain a second hand-written queue of open pull requests: it will drift. CHANGELOG.md is the concise record of changes that actually reached main.

Reusable role prompts

When assigning work, tag BUILDER_AGENT_PROMPT.md for implementation and PR submission, or INTEGRATION_AGENT_PROMPT.md for review, staging QA, promotion, and production verification. These prompts restate the role boundaries below so an agent can execute the workflow without relying on a shortened task description.

Roles

Do not require separate Reviewer or Release Authority agents. The Integration agent owns those responsibilities so each change normally consumes only one Builder and one Integration agent. Before Integration acts, it asks the owner: “Should this use a pull request or the owner-only direct-push fast path?”, “Should it target staging or main?”, and “Should Vercel deploy after integration; if so, staging or production?” If the current request already answers a question, the agent records that choice instead of asking again. The default remains a pull request to staging for hosted QA and no production Vercel deployment unless explicitly authorized.

Owner-only direct pushes

Repository rules require pull requests and status checks on main and staging for every actor except the specific DevelopedByDev user. This exception is a release-velocity option for the owner, not the default agent workflow. An agent authenticated as DevelopedByDev may use it only when the owner explicitly requests a direct push for the current task; full access, account identity, or an earlier instruction is not authorization. Two stacked rulesets keep the exception narrow:
  • Pull requests and checks requires a pull request, conversation resolution, and the configured CI/security checks. Only DevelopedByDev has an always-bypass for direct pushes; repository administrators retain a PR-only bypass for stuck checks.
  • History integrity blocks branch deletion and non-fast-forward updates to main and staging with no bypass actors. The owner exception therefore cannot be used to force-push, reset, or delete either branch.
Before an authorized direct push, fetch the target, verify the local target matches its remote, review the complete outgoing commit range and diff, run checks proportional to the change, and confirm the update is fast-forward. Push from the dedicated target worktree without force, then verify the remote SHA and post-push Actions. A direct push to main still requires the CHANGELOG.md and living-doc updates that a PR would carry, plus confirmation that no unauthorized production Vercel deployment was created. A direct push to staging normally starts its branch-gated Vercel build. If the owner declines a staging deployment, do not push staging until the deployment trigger is deliberately suppressed or the owner chooses a different target.

Worktree ownership

Worktrees are scoped to active work, not to every pull request:
  • Each active Builder task gets one isolated codex/<slug> feature worktree. That worktree belongs to the Builder until the pull request is handed off.
  • The Integration agent reuses one long-lived sibling worktree, ../overlay-landing-staging, checked out on staging, for every sequential Builder pull request. After a merge, fetch and fast-forward that same worktree to origin/staging; do not create or retain a new Integration worktree for each PR, and do not check out feature branches in the staging worktree.
  • Keep the canonical main worktree separate and clean for production operations. It is not an Integration scratch area.
  • A short-lived temporary worktree is justified only for an exceptional conflict reproduction or side-by-side investigation. Remove it after the investigation and confirm its branch is no longer needed.
This keeps the working set small while preserving isolation: GitHub pull requests and the staging branch remain the integration record, and the dedicated staging worktree is the single local checkout used for staged QA.

Start every task from origin/main

Fetch before creating the worktree. Never assume the local main branch is current.
Use a short, descriptive slug such as agent-memory-retrieval or project-navigation. One worktree belongs to one branch and one task. Agents must not share a feature branch or edit the canonical main checkout. If a task depends on an unmerged pull request, branch from that pull request’s reviewed head and declare the dependency in both pull requests. Otherwise, branch from origin/main.

Make reviewable commits

Commits should describe reversible units of behavior. Keep tests and the documentation for a behavior change in the same commit when practical. Do not mix formatting, generated files, refactors, and unrelated product behavior merely to make the worktree clean. Before opening a pull request:
  1. Fetch origin/main and inspect the divergence.
  2. Rebase or merge the latest origin/main into the feature branch before review when the base has moved materially.
  3. Resolve conflicts by understanding both changes; never choose an entire side mechanically.
  4. Run checks proportional to the changed surface.
  5. Update the applicable living documentation and CHANGELOG.md.
  6. Push the branch and open a focused pull request with staging as its base.
The Builder’s handoff ends when the pull request is complete and ready for integration. Rewriting unpublished local commits is fine. Once integration review or staging QA has started, force-pushing or rewriting commits invalidates the recorded evidence and requires a fresh review.

Pull request contract

Every pull request must state:
  • the user or operational outcome;
  • the important implementation decisions;
  • touched systems and known dependencies;
  • risk and rollback approach;
  • exact checks run and their results;
  • staging or browser evidence when the behavior needs it;
  • migration, environment, Convex, or deployment steps;
  • the base and tested head commit when release provenance matters.
The pull request is the detailed change record. CHANGELOG.md stays user-focused and concise.

Checks should match risk

Overlay does not require the maximum possible gate for every change. It requires enough evidence for the actual risk: Required GitHub checks remain mandatory. Zero approving reviews is intentional for the current sole-maintainer setup; do not add a gate that the pull-request author cannot satisfy. The Integration agent performs the substantive review and may request Builder changes when evidence or implementation is incomplete.

Preserve meaningful history

The default merge method is a merge commit when the pull request contains meaningful, reviewed commits. This preserves the exact branch commits, the pull-request boundary, and the ability to revert one independent commit without undoing the whole change. Use a squash merge when the branch history is disposable—for example, a trivial one-commit change or a branch full of fixups that do not represent independently valid states. Rebase merging is disabled because it rewrites commit identities and loses the explicit integration boundary. History preservation does not make a broken commit safe. Every commit retained through staging and main should build or be an intentionally inseparable part of the pull request. The Integration agent may ask the Builder to clean up a noisy history before merging. To undo a retained commit, use git revert <commit>. To undo an entire merge-commit pull request, use git revert -m 1 <merge-commit>. Never reset or force-push main to perform a production rollback.

Integration procedure

The Integration agent owns the change from PR review through production verification:
  1. Before accepting a candidate, confirm staging contains the current origin/main. If it does not, synchronize main into staging without rewriting either branch, then verify the resulting tree.
  2. Confirm the Builder PR targets staging and records its head SHA, scope, dependencies, risk, validation, and changelog entry.
  3. Read the diff and relevant surrounding implementation. Test evidence is not a substitute for review.
  4. Confirm which PRs are already present in staging. Prefer one release candidate at a time; if several PRs are intentionally batched, list and test the complete batch.
  5. Verify the required checks, resolve conflicts deliberately, and merge the Builder PR into staging. Prefer a merge commit for meaningful commits; squash only disposable fixup history.
  6. Test the exact resulting origin/staging SHA using the staging web and matching development Convex deployment. Record the SHA and evidence.
  7. If staging or main changes after QA begins, incorporate the new state into staging and repeat the affected QA. Never promote a revision different from the one tested.
  8. Open or update a release pull request from staging to main. Include every Builder PR in the candidate, the tested staging SHA, checks, rollback notes, and deployment steps.
  9. Confirm root vercel.json still sets git.deploymentEnabled.main to false. After the release PR checks pass, merge it with a merge commit, verify the resulting commit on origin/main, and verify that Vercel created no production deployment for that SHA. The merge leaves that SHA merged but not deployed.
  10. Fast-forward staging to the accepted origin/main merge commit before the next Builder PR. This keeps the two long-lived branches aligned without force-pushing and prevents the next review from containing old release-history differences.
  11. Stop unless the user explicitly authorizes production deployment. When authorized, deploy the accepted origin/main revision from the clean canonical main worktree, verify the production web deployment, deploy production Convex when applicable and only after the web deployment is live, then run the production smoke test.
An administrator’s pull-request-only ruleset bypass is for a demonstrably stuck or broken gate, not for skipping relevant validation. The DevelopedByDev direct-push bypass is available only through the explicit owner fast path above. Force-pushing and deleting main or staging remain prohibited by the separate history-integrity ruleset.

Staging and production QA

The shared staging branch and staging Vercel project are the only hosted pre-production lane. Builder pull requests target staging; feature branches do not produce hosted previews. The Integration agent tests after the Builder PR reaches staging, then promotes staging through a separate pull request to main. Root vercel.json disables Git-triggered deployments for main while leaving staging available for hosted QA, so promotion and production deployment are separate, explicitly reported states. Do not rely on an account-level deployment-source policy alone; verify the source-controlled rule and the absence of a production deployment after every release merge. The staging project is explicitly branch-gated to staging to prevent PR and other branch builds from consuming Vercel build minutes. Its Ignored Build Step runs scripts/vercel-ignore-build.sh with DEPLOY_BRANCH=staging in both Vercel environments. For that staging target the guard fails closed: only an exact staging Git ref runs a build; missing refs (including manual or hook-triggered deploys), unset targets, and every other branch are skipped. The shared script preserves no-ref manual releases for any separate, explicitly configured target. Preview deployment sources stay disabled. Verify these project settings when rotating Vercel projects or credentials. Follow Worktree Staging QA for staging integration, Convex deployment boundaries, smoke tests, and production promotion. A successful pull-request check does not prove the staging or production UI, and an HTTP response does not prove an authenticated browser flow.

Maintain the changelog

Every pull request that changes user-visible behavior, developer workflow, deployment behavior, data, security posture, or operations adds a concise item under Unreleased in root CHANGELOG.md. Pure maintenance may omit an entry only when the pull request explains why it has no meaningful release impact. At release time, the integration agent moves the shipped Unreleased entries into a dated section and leaves a fresh Unreleased heading. Link pull requests where that improves traceability; do not copy implementation detail already preserved in the pull request and Git history.

Clean up completed work

After merge and verification:
The ancestry check works directly for merge commits because the feature head is retained. For squash merges, verify the pull request’s merged state and resulting commit instead; the original feature head will not be an ancestor of main.