Execution Gates

Gates are checkpoints where Trinity pauses the pipeline and asks for your input. They keep you in control of decisions that the agent can't (or shouldn't) make on its own.

How Gates Work

When an agent or the coordinator detects a situation that needs human judgment, it raises a gate. The job transitions to waiting_gate, a notification appears on the Run page and in the sidebar task indicator, and the pipeline won't advance until you respond.

Gates are tied to an entity (either a story or a release). Each gate carries a typed payload describing what triggered it — the same structure powers both the UI and the feedback pipeline.

Gates that pause a run before it starts. Five of the gates below are a pre-flight: Trinity checks them once, before the first agent spawns, so a run whose prerequisites are missing pauses instead of dying part-way through with half its work on disk. Those five are Waiting for Key Grant, Service Setup Required, Secrets Backend Unreachable, Provider Key Missing, and Tool Not Installed for the case where git, or a configured step's CLI, isn't installed. They run on both kinds of story run — a standard story and a quality checkpoint — so a checkpoint on a device without git, or pinned to a provider you haven't keyed or a harness whose CLI is missing, pauses up front rather than failing mid-audit. Answering one re-runs the whole set, so a run blocked on two prerequisites pauses again on the second until both are cleared.

Gate Types

The gate types you'll encounter (from the JobGateType enum):

Deviation Approval (deviation_approval)

When The analyst detects that a technology specified in the roadmap has a genuine blocker — security vulnerability, end-of-life status, or incompatibility with other stack choices.

Payload: The agent's analysis, the proposed alternative, and the reasoning for the substitution.

Actions
  • Approve Deviations — accept the substitution; the implementer uses the alternative
  • Reject — Follow Plan — keep the original technology; the implementer proceeds as planned
Important
Deviations are only raised for concrete blockers (security, EOL, incompatibility). Personal preference or "this is better" are **not** valid grounds — the prompt explicitly filters those out.
Auto-approve Turn on **Auto-approve technology deviations** (in the run modal or project/global automation settings) to skip this gate — the deviation is accepted automatically and still surfaces in the PR for review.

Missing Assets (missing_assets)

When Raised two ways. **Plan-time** — the analyst declares one or more specific asset needs it can't ship with placeholders (hero imagery, logos, product photos, brand icons); this is a declared need, not a heuristic regex count. **Mid-build** — the implementer, or (for a release's SEO/content fix pass) the release-side fix agent, hits a content slot whose asset was deleted or never uploaded after the plan assumed it would land. Either way the gate is scoped to whichever entity raised it — a story or a release.

Payload: One card per declared need, each with a purpose line and a prose description of what the story or release expects.

Actions
  • Save & Continue — upload real assets to those cards, then the story replans with the new assets in hand
  • Use Placeholders — explicit opt-in. Trinity threads this choice back into the analyst as a feedback directive so it doesn't redeclare the same need on replan. The post-checkpoint placeholder audit remains the safety net.

Skip globally: toggle skipAssetCheck in project settings or globally. The flag is resolved up front and threaded into the analyst prompt so the analyst never declares when you've opted out.

Checkpoint + Release Placeholder Audits

Quality checkpoints run a full-worktree placeholder scan in addition to the analyst-plan pre-flight. Two regex families are independent:

  • Images (skipCheckpointAssetAudit / skipReleaseAssetAudit) — catches shipped placeholder.svg, picsum.photos, Lorem ipsum, etc.
  • Contacts (skipCheckpointBusinessDetailsAudit / skipReleaseBusinessDetailsAudit) — catches example.com emails, 555-* phones, John Doe, Your Company, stale copyright years.

Findings surface as entries on the quality checkpoint gate — each with file:line refs.

Agent triage: when the scan finds anything, an agent classifies each match as leak (blocks), fixture / docs (info, non-blocking), or false_positive (dropped). For leaks, the agent also suggests a replacement using the project's uploaded assets + business details. If the agent itself fails, raw scan warnings surface unchanged.

Custom excludes: placeholderAuditExcludes (project / workspace / Trinity default) is a list of glob patterns added to the hard-coded base list (node_modules/, **/__tests__/**, etc.). A .trinityignore file at the worktree root is also honoured (gitignore syntax).

On-demand scrub: Project Settings → Audit Codebase runs the same scan at any time — informational, nothing blocks.

Missing Business Details (missing_business_details)

When The analyst flags the story needs business info (company name, contact email, branding) but the project's business details aren't populated.

Payload: Which fields are missing + why the story needs them.

Actions
  • Save & Resume — fill in the missing fields directly in the gate's inline form, then resume the run
  • Skip — Use Placeholders — proceed without business details

Skip globally: toggle skipBusinessDetailsCheck in project settings or globally.

Missing Secret (missing_secret)

When The analyst determines the plan needs an API key or credential that isn't registered yet — raised _before_ the plan is written, so the story is planned against the real service instead of around an unconfigured one.

Payload: Each missing key — the service it belongs to, the env var name it's injected as, and why the story needs it.

Actions
  • Save & Resume — enter the values directly in the gate dialog, one masked field per key. Trinity saves them encrypted to your secrets, then resumes the run with the keys injected into the agent's environment.

This is a blocking gate with no skip: the analyst pauses at the tool call and the run waits right here until you provide the keys (or the hold window elapses, after which the gate resumes through the normal flow). You provide the secrets inline — there's no "go to Project Settings and come back."

Waiting for Key Grant (waiting_key_grant)

When Execution-critical secrets exist in the cascade, but none of their rows decrypts on this device — the workspace's shared key grant hasn't reached this account yet. There's nothing to type in: the value exists, this device just can't read it. Nothing has to be approved either — a device holding the workspace key delivers the grant on its own, within seconds if one is open and at its next start otherwise.

Payload: The key_names with visible-but-undecryptable rows, and the workspace whose grant is pending.

Actions
  • Check again — the only action. Once the key has been delivered, click this; the run re-runs its decryptability check and clears when the key has landed (or re-arms the same gate if it hasn't). Someone on a key-holding device can skip the wait with Grant key in Workspace Settings → Access Control → Encryption Keys.

Service Setup Required (service_setup_required)

When A third-party service the run needs hasn't been configured yet — env var undefined, expected config file absent, CLI auth needed. Two paths trigger this gate:
  1. Worker pre-flight — before the run's first phase, Trinity scans the project's stack for rows marked needs_keys and checks whether each one has a secret bound. Any gap fires the gate with the full list of services to set up.
  2. Agent signal — any pipeline phase can raise the gate mid-execution via the signal_service_required tool when it discovers a service the worker pre-flight didn't catch (e.g. an internal SDK that needs a project ID).

Payload: List of missing_services[] — each with the service name, target binding, and (for agent signals) the agent's goal and blockingReason.

Actions
  • Configure & resume — run the inline setup runner. Trinity launches the relevant playbook (e.g. gh auth login, paste-from-dashboard) pre-bound to the right target. Captured values flow into the secrets store and any config files materialize to disk before the story resumes.
  • Skip and run anyway — proceed without configuring (the agent owns the failure mode from here)

The setup runner is the same UI you've seen in Project Settings → Stack → Setup — pty-driven CLI, capture forms for tokens, paste prompts for values the CLI prints at the end.

Provider Key Missing (provider_key_missing)

When A run needs the API key for a provider (Anthropic, DeepSeek, Moonshot, and so on) that no key is configured for yet. Trinity checks **every step the run can reach** before it starts — the analyst, implementer, auditor and documenter phases of a story, or the audit, fix, docs and consolidate phases of a quality checkpoint — so a single step you pointed at a different provider raises the gate even when the rest of the run is fully keyed. The reverse holds too: a tier whose provider has no key doesn't pause anything if no step in the run actually uses it.

Two things this deliberately doesn't do. A step the story proves it will skip — the auditor, when the story's reviewers are set to 0 — is left out, so a model you picked for a phase that never runs can't block the story. And steps that are only sometimes skipped are still checked, because whether they run is decided later, during the run.

Payload: The step (operation) and the model it resolved to, the provider whose key is missing and the keyName it's stored under, and whether that model is pinned — the story's own per-step pick was honored — or is the account tier default. A step that names a per-step model doesn't always come back pinned: a pick has to sit on its provider's rung for the step's tier to be honored, and an off-rung pick is dropped in favor of the tier default even if that default happens to land on the same model the pick named. The gate dialog names the step and model directly, so you know exactly what to change.

Actions
  • Save & Resume — type the provider's API key directly in the gate dialog (a single masked field). Trinity saves it encrypted and resumes the run.
  • Change Model — switch to a provider you already have configured, instead of supplying a new key. When the named step's model is pinned, the dialog points you at that story's Execution Settings, since that per-step pick is what's driving the resolved model; when it's riding the tier default — including when a per-step pick was dropped — the dialog points you at Settings → AI Models instead.

Secrets Backend Unreachable (env_resolve_failed)

When A run can't resolve the secrets or environment it needs because the secrets backend is briefly unreachable — the values exist, Trinity just couldn't reach them this time. The run pauses here instead of failing the story outright.
Actions
  • Retry — once the backend is available again, retry the run; it re-resolves the environment and continues.

External Dependencies (external_deps)

When The story requires something outside Trinity's control — a third-party service to be provisioned, manual configuration, or setup an agent cannot automate.

Payload: List of external deps (name, description) and a human-readable explanation.

Actions
  • Diagnose — complete the external action, then open the chat to describe what you provisioned or configured. Your report threads back to the agent and the story resumes.

Story Blocked (story_blocked)

When An agent raised its hand. Any pipeline phase (Analyst, Implementer, Documenter, Checkpoint Fix) can call the `signal_blocked` MCP tool when it genuinely cannot make progress — intractable build error, missing context the plan doesn't cover, ambiguous requirements, a corrupted worktree. The pipeline pauses at a gate so you can diagnose and unblock.

Payload: Which agent phase escalated, a prose explanation of what's stuck, and (optionally) the list of approaches the agent already tried — so you know what not to suggest.

Actions
  • Diagnose — open a diagnostic chat to investigate the blocker; submitting your guidance re-enters the story through the feedback pipeline.
  • Mark failed — give up and mark the story Failed. The recorded cause reflects which agent was stuck: an audit-phase escalation records audit criticals; any other phase records retries exhausted.

There is no skip — diagnose the blocker or mark the story failed.

Story Failed (story_failed)

When A story hit a **hard failure** — the implementer hung or crashed without producing its final report, an agent timed out, or the automatic retry budget ran out. Instead of dead-ending at terminal **Failed**, the story parks here so you can investigate and recover interactively.

A structural failure (a report-missing run or an agent timeout) parks here after a single attempt rather than burning the full retry budget — re-running the same prompt just re-hangs, so there's no point exhausting retries first. The gate's header says so ("This story failed on its first attempt").

Payload: The coarse failure cause phrased for humans (e.g. "ran out of retries", "produced no implementation"), a short reason, and — when present — the verbatim implement-phase diagnostic (the actual hang/crash message).

Actions
  • Diagnose — open a diagnostic chat to co-investigate the failure; submitting your guidance re-runs the story through the feedback pipeline. This is the recovery path.
  • Mark failed — give up and mark the story Failed, carrying through the recorded cause so the failure reads the same as why it originally failed.

There is no skip — recover via Diagnose or mark the story failed. The full blast-radius failure dossier is already filed for the architect when the story parks here, so a resolution proposal is usually waiting either way.

Repository Access (git_write_access)

When The member running the story can't push to one or more of the project's managed repos, so no story can start. Raised right after a story is claimed, this gate is per-project and binary — any blocking repo blocks every story. A confirmed denial (a live token without the grant) reads differently from a "couldn't verify" (the host was unreachable); Trinity never calls the latter a denial.

Payload: Every managed repo you can't push to, each with its host and whether the block was confirmed. The repos the story's packages live in are called out to sharpen the message, but they never loosen the gate.

Actions
  • Check again — runs a fresh read-only re-probe. It resolves to access confirmed, still blocked, or "couldn't verify — the host didn't answer."
  • Request access — notifies the project owner that you need write access to the listed repos (an entry in their activity inbox).
  • Start story / Start anyway — always available, because it's the appeal: starting runs the story through to its push, which is the real test — a successful push overturns a stale negative, a genuine block re-confirms it. After a clearing re-check the button reads Start story; otherwise Start anyway.

PR Review (pr_review)

When A story's PR is open, its checks have passed, and it's waiting for your review before the merge chain continues. This gate appears only when **Auto-merge** is off. Trinity waits for the checks first — a PR whose checks are still running, failing, or missing never reaches review; it goes through the [checks gates](#checks-gates) below instead.

Payload: one section per repo (multi-repo projects get one per repo), each with a link to its PR and three parts that read like a code review:

  • Summary — the Documenter's latest close-out for the repo, rendered as markdown: what the story built there, and whether its acceptance criteria were met. The same close-out is on the repo's story issue.
  • Review rounds — a timeline, oldest first. Each round shows how many reviewers read it, its findings counted by severity (blocker, major, minor, nit) and by what became of them (fixed, declined, open), and the review's summary. Show findings expands the round's findings, each with its file, line, severity, review angle and what the Auditor did about it. When you asked for changes earlier, Your request heads the round it fed.
  • Diff — the branch-vs-base diff rendered inline, in a bounded pane, so you can review the actual changes without opening the PR. A file tree sits beside it: search by path, filter by file type, or show only files with findings; lockfiles and generated files sit in one collapsed group. Each file opens collapsed, showing its name, its added/removed line counts and how many findings it carries; click a file, or its entry in the tree, to expand it. The latest round's findings appear inline: a finding with a line sits at that line, and one about a whole file sits at the file's header. Findings are shown at the lines the review read, so a finding the Auditor fixed can sit on a line that has since moved; its fixed, declined or open badge says what became of it.

The expand button in the dialog header takes the gate fullscreen, which gives the diff more room; closing the dialog resets it. The actions stay pinned at the bottom of the dialog in both sizes, so a large change never pushes them out of reach.

Actions
  • Merge — continue the merge chain
  • Diagnose — open a chat to review the changes; your comments are sent back as a request for changes, which re-runs the feedback pipeline against the PR. Your text is also posted, as you wrote it, as a comment on every repo's PR and shows in the gate's timeline as Your request
  • Skip — cancel this leg of the merge

Checks gates

Trinity merges a pull request only once the checks your repository host runs on it — CI workflows, status checks — have passed and the host itself will accept the merge. That holds for every merge Trinity makes: a story's PR, a batch branch merging on to the release branch once its last story lands (at an epic, phase or prd Merge Level), a quality checkpoint's fix branch, a release's staging placement and promotion, a walk-up, and a backport. A merge that isn't green yet pauses at one of the four gates below, and each one names the pull requests it's holding, with every check, where it stands, and a link to its output.

A batch branch's merge pauses on the story whose merge completed the batch. That story has already merged, so the pause holds only the batch branch: once the checks allow it, Trinity merges the batch branch and nothing of the story runs again.

What a paused merge was doing decides what stopping it means: a story or a quality checkpoint is marked Failed; a batch branch's or a release's merge is left undone, with its pull request still open.

Awaiting Checks (checks_pending)

When The checks on a pull request are still running.
Actions None needed — Trinity keeps re-reading the checks and carries on once they finish, whatever they say. If they're still running two hours after the pause, Trinity stops waiting on its own and asks you instead, at [Checks Unverified](#checks-unverified-checks_unverified). **Stop waiting** gives up early.

Awaiting Host Review (forge_review_pending)

When The checks passed, but your repository host still won't allow the merge — usually a required review from a teammate, or another branch-protection rule.
Actions Give the review (or satisfy the rule) on your repository host. Trinity notices and carries on by itself. **Stop waiting** gives up. A story's review step never pauses here: when **Auto-merge** is off, you are the review the host is waiting for, so the story goes straight to [PR Review](#pr-review-pr_review).

GitHub and GitLab report these rules to Trinity. Bitbucket and Forgejo don't, so on those hosts a merge the host refuses fails at the merge itself instead of waiting here.

Checks Unverified (checks_unverified)

When Nothing tells Trinity whether the pull request is good:
  • No checks ran on it at all — the repository has no CI, or none that runs on this branch.
  • The checks finished without passing — at least one was skipped, cancelled, or finished neutral, and none failed. A CI workflow limited to certain paths does this whenever a change falls outside them, so it's the usual reason you'll see this gate.
  • The checks were still running after two hours at Awaiting Checks.
  • Trinity couldn't read the pull request — your account can't see it, or the host's answer made no sense. Merge without checks tries the merge anyway, and it fails if the host still refuses.
Actions
  • Merge without checks (or Review without checks, when the story was about to go to review) — go ahead this once.
  • Always go ahead in this project — go ahead, and answer this question for the whole project: every later pull request with no checks, or with checks that finished without passing, merges without asking. It changes the project's Pull requests without verified checks setting to Merge without them, so it needs permission to change the project's settings, and it isn't offered when the checks simply ran out of time. Change the setting back to Ask me under Project Settings → General → Automation whenever you like; the next merge follows it.
  • Check again — read the checks again and carry on with what they say now.
  • Mark failed / Stop — give up on this merge.

A failing check is never covered by any of these: a failing check always stops the merge.

Checks Failed (checks_failed)

When A check failed on a pull request that no agent is working on — a batch branch's merge, a quality checkpoint's fix branch, or one of a release's merges.
Actions Fix the cause on the branch, or re-run the check on your repository host, then **Check again**. **Mark failed** / **Stop** gives up.

A story's own pull request never pauses here. When its checks fail, Trinity sends the story back to its implementer with the failing checks and their output as feedback, and the fixed story goes through the checks again. After three rounds that still fail, the story pauses at Story Failed instead.

Quality Checkpoint Approval (quality_checkpoint_approval)

When A `quality_checkpoint` story has finished its intensive audit pipeline and needs sign-off before downstream stories continue.

Payload: Audit findings, fixes applied, any remaining issues.

Actions
  • Approve — marks the checkpoint passed
  • Skip — acknowledges unresolved issues and continues
  • Diagnose — open a chat to re-enter the feedback pipeline
Auto-approve toggle `autoApproveQualityCheckpoints` (workspace, member, project, entity, or job level) to auto-approve the gate. The gate row is still created for the audit trail but resolves immediately.

Merge Conflict (merge_conflict)

When A story's PR can't merge cleanly — git reports conflicts Trinity can't resolve automatically.

Payload: Which repo, branch, and base branch are conflicting. Shown alongside a "resolve locally" hint.

Actions
  • I resolved it — retry — re-run the merge after you pushed a manual conflict resolution
  • Diagnose — open a chat to investigate the conflict; submitting your fix plan retries the merge with that plan threaded into the conflict-resolver agent's prompt as authoritative guidance
  • Mark failed — give up on the story and mark it Failed

External PR Closed (external_pr_closed)

When A PR Trinity opened was closed on GitHub outside Trinity (manually or by another tool) while Trinity was still waiting on it.

Payload: PR URL, branch, and repo — so you can see what was closed.

Actions
  • Recreate PR — re-open a fresh PR with the same branch and keep going
  • Diagnose — open a chat to investigate before deciding; submitting from the chat recreates the PR
  • Mark failed — give up on the story and mark it Failed

Partial Merge Failed (partial_merge_failed)

When A multi-repo story merged some of its repos but others failed (e.g., a branch protection rule rejected the push, or a conflict couldn't be resolved alongside other failures).

Payload: Which repos succeeded vs. failed, with error details per failed repo.

Actions
  • Retry Failed — re-attempt the merge for just the failed repos; already-merged repos are untouched
  • Mark failed — give up and mark the whole story Failed. Repos that already merged keep their code on the branch, but the story blocks dependents until you fix it or mark it failed — it never reads "merged" with a repo's work missing.

This gate is specific to polyrepo projects — a single unresolved conflict (with nothing merged yet) raises merge_conflict instead.

Re-auth Required (reauth_required)

When A mid-run git operation (push, PR open, or merge-push) hit an authentication failure — the credential is dead, expired, or revoked. Rather than aborting the run, Trinity parks the job here: all completed work stays safe on disk. So does a merge whose pull request Trinity couldn't read before merging it because the credential is dead — it pauses here rather than waiting out the checks. Only a true authentication failure raises this gate; a permissions problem (valid credentials without access) or a transient network error takes a different path.

A release publishing a package to its registry pauses here too when the package has no registry token, or the registry rejects it. The gate names the package and the key to set (NPM_TOKEN or CARGO_REGISTRY_TOKEN); set it on that package in Project Settings → Secrets as a registry publish token, then choose I've set the token — resume, and Trinity picks the publish up at that package — nothing already published goes out again. If pointers are still waiting to move, the Pointer Move gate asks for your approval again first. If the token is already set but this device can't decrypt it yet, the gate says so; resume once the device has the workspace key. Its give-up action is Stop this step, which ends the release's publish there: what already landed on the registry stays, and nothing else publishes.

Payload: The account and host that need re-authentication, which op failed and on which repo, and a fix hint. A registry publish names the package and the registry instead of an account. The gate is tied to either a story (a story job's git op) or a release (a release-finalize push).

Actions
  • I've re-authenticated — resume — confirms you re-authenticated the credential out-of-band; Trinity re-runs only the failed op (re-push, re-open the PR, or re-merge), never the whole story or release
  • The give-up action depends on the entity:
    • Mark failed (story jobs) — marks the story Failed. A story that can't push didn't land — it isn't skipped, and it blocks dependents until you fix it or mark it failed.
    • Skip this step (release runs) — records the release as partially_shipped; repos that were already tagged persist.
    • Stop this step (a release merge paused before it read its pull request) — stops that merge, leaving its pull request open, the way stopping a checks gate does.

Commit Email Needed (commit_email_required)

When A commit is about to land under your identity, but the resolved git identity has no real verified author email and the host can't derive one — this happens on providers without a public commit email, namely **Bitbucket** and self-hosted **Forgejo/Gitea**. Rather than stamping the commit as an unknown user, Trinity parks _before_ the commit; all completed work stays safe on disk. The author-side sibling of Re-auth Required.

Payload: The host the author email is missing for, which op was blocked (push, PR open, or merge) and on which repo, and a fix hint. Tied to either a story or a release-finalize commit/tag.

Actions
  • Set commit email & resume — set a verified commit email for the host directly in the gate. The field prefills a suggestion from your account, validates against your verified addresses on that host (only verified emails are accepted), and offers one-tap chips. Once set, Trinity re-runs only the parked op.
  • The give-up action depends on the entity:
    • Mark failed (story jobs) — marks the story Failed.
    • Skip this step (release runs) — ships as partially_shipped.

You can also set this ahead of time: each connected account carries a commit email you can set in the connect flow or override per account in Settings — see Signing In → Commit email per account.

Tool Not Installed (tool_missing)

When A command-line tool — **git**, **Claude Code**, or **Codex** — isn't installed on this device. Most often this is caught before the run's first step even starts: pre-flight checks probe git, then resolve which CLI each step will spawn, and park here right away if one is missing, so no worktree or agent work happens on a story that can't run. git is checked first, because a run needs it whatever else it is configured with. The same gate is also the backstop for a tool that goes missing mid-story (a spawn that dies partway through), with completed work safe on disk either way.

Git that's installed but has no user.name / user.email set does not pause a run here — Trinity resolves commit authorship from the account you connected, and asks separately via Commit Email Needed when it can't.

Payload: Which binary is missing and its install recipe, plus the underlying error for diagnostics.

Actions
  • I've installed it — resume — confirm you installed the tool (via the inline recipe or on your own); Trinity re-runs the pipeline.
  • Mark failed — give up and mark the story Failed.

Workspace Not Ready (topology_not_ready)

When A run starts before the release's repositories and targets are fully provisioned on disk (for example, right after committing a plan whose repos are still being created and cloned).
Actions None needed — the run parks and resumes on its own once the workspace is whole. This gate auto-heals; it exists so a run never fails just because provisioning hadn't finished yet.

Waiting to Tag (version_pending)

When A release whose [fixed release group](/user-guide/releases#the-release-policy) spans several repositories is ready to tag one repository while a sibling repository hasn't landed where the tag goes yet — production for a release that ships, your integration branch for a [release candidate](/user-guide/releases#release-candidates). Tagging a fixed group is all-or-nothing, so the run parks here rather than tagging one repo on a version the others don't carry.
Actions None needed — Trinity re-checks the barrier and resumes on its own once every repository has landed, then tags the whole set on one matching version. Like Workspace Not Ready, this gate auto-heals and never waits on a decision from you. A release whose versions each stay inside one repository never hits it; each repository tags off its own latest tag.

Version Check Failed (version_check_failed)

When A release is about to ship, and the version its packages declare can't be tagged. Trinity reads the version from each package's own manifest (`package.json`, `Cargo.toml`, `pyproject.toml`) and checks it before anything is tagged or written to a changelog. It stops here when:
  • the members of a fixed release group declare different versions,
  • the packages declare versions with different labels, or a label on some and none on others (2.0.0-rc.1 beside 1.4.0) — a label covers the whole release,
  • the release carries a label and is being shipped — a release candidate is integrated and tagged, never shipped,
  • the version is already tagged on this release's line, including a candidate tagged on your integration branch,
  • a package this release changed still declares the version it last shipped,
  • the version sorts below one already tagged for the same release (a 2.0.0-rc.1 after 2.0.0-rc.2 has shipped),
  • the release changes how packages version and the version isn't a new major above every affected package's current one — the gate names the major to declare, or
  • the manifest's version isn't major.minor.patch, optionally followed by a -label.number such as -rc.1.

The gate lists each problem and what every manifest declares.

Actions Fix the version in the manifests on the branch the gate names, then **Check again** — Trinity reads the manifests again and carries on. **Stop** ends the release run with nothing tagged.

Waiting to Forward-Port (forward_port)

When A [hotfix release](/user-guide/releases#hotfix-releases) has landed on production but your dev branch hasn't absorbed it yet. A hotfix writes production directly, so until dev catches up, every later release's promote to production would refuse to run — shipping the hotfix first would hand the next release a broken promote. The run parks here instead of tagging.
Actions None needed — Trinity merges production back onto dev and re-checks on its own, then tags and ships. Unlike Waiting to Tag, this gate applies to hotfixes whatever your release policy says: it's a property of how the release was routed, not of how versions are numbered.

A patch release never parks here. A maintenance line doesn't merge into anything, so a line that hasn't sent its fix to trunk breaks nothing — the patch ships straight away, and what waits instead is the next release on that line.

If Trinity's own merge-back can't land (a conflict it can't resolve, or a repository it can't push), open the back-merge PR yourself and merge it — the gate clears as soon as your dev branch contains production, whichever merge got it there. The fix itself is already live on production the whole time; only the tag and the Shipped status are waiting.

Pointer Move (pointer_move)

When A release has tagged a package a **Library** or **CLI** target ships, and is about to move the npm dist-tag its consumers resolve — `latest` for a release on trunk, your prerelease pointer for a labelled release, or `latest-` for a maintenance patch. Trinity first publishes each package under a holding tag no consumer resolves, dependencies first, then stops here for your approval, whatever your automation settings say for the rest of the release. The release's status has already moved on by then; only the publish waits. A package the registry has never seen, and any package depending on one, waits here unpublished.

Payload: A dry run of every package about to publish, in publish order — its version, its pointer, what that pointer names right now, and what it will name once this publish lands. A package with no pointer to move (Cargo, Go, or a Python package) shows as publishing with nothing to move. A package the registry has never published before is called out separately: the registry sets latest on a first publish whatever tag you configured, so Trinity raises this gate for it before the publish rather than after. If Trinity couldn't read a package's current pointer from the registry for a reason other than a dead credential, that shows too, so you know its "current" value is unverified rather than genuinely unset.

Actions
  • Approve — publish the packages that waited, dependencies first, then move every pointer the dry run showed
  • Stop — end the release here. A package already published stays published, with nothing about its pointer changed. A package flagged as a first publish is held back from publishing at all, since setting its latest pointer happens as part of that publish itself.
Important
This gate never auto-heals and is never skipped by an automation setting — it is the last step of a registry publish that can't be taken back, so a person always decides.

Waiting for a Quiet Release (rename_pending)

When You queued a [branch rename](/user-guide/releases#renaming-the-branch) on a release that still has work in flight. A branch name is what open pull requests target and what queued merges are aimed at, so the rename waits rather than moving the name out from under them.

Payload: Exactly what it's still waiting on — open pull requests into the branch, unsettled merges into your dev branch, live staging placements, and any run still going.

Actions None needed — the rename holds new work back, waits for what's already running to finish on its own, then moves the branch and lifts the hold. Like Workspace Not Ready and Waiting to Tag, this gate auto-heals.

It will never cancel or interrupt a run to get there. If something is stuck rather than slow, resolve it the way you normally would — the rename picks itself back up as soon as the release goes quiet.

Marking a Story Failed

The failure gates (merge_conflict, partial_merge_failed, external_pr_closed, reauth_required, commit_email_required, tool_missing, story_blocked, story_failed) share Mark failed as their give-up action (on release runs, reauth_required and commit_email_required offer Skip this step instead):

  • The story is marked Failed with a cause that records the obstacle — see the cause table in Stories → Failed Stories. Branches, PRs, and repos that already merged keep their code; nothing is deleted.
  • A failed story blocks its dependents until it's resolved, so the plan never builds on work that silently went missing.
  • Marking a story failed files a failure dossier for the architect — the cause and reason, the attempt count, the gate's details, the latest conflict-resolution findings, and which stories are now stuck — and the architect immediately drafts a resolution proposal from it (retry, reshape, or delete). By the time you open the failed story, a reviewable way forward is usually waiting.

The same dossier is filed when a story fails without a gate (retry exhaustion, an implement run that produced no changes), so every failure — from the gate or automatic — carries the same paths to resolution. How loudly a failure surfaces depends on what it blocks — see Running → Failed Stories on the Run Page.

Gate Feedback

Instead of a binary approve/skip, every gate supports a feedback response that re-enters the story (or release) through the feedback pipeline:

  1. Triage — the agent classifies what you're asking for
  2. Analyst — re-reads the codebase with your feedback as context
  3. Implementer — makes changes, committing as it goes
  4. Audit round — the Auditor's reviewers read the new changes and leave a review on each repo's PR
  5. Documenter — documents the round in each touched package's documentation, checks it, commits it, and closes the round out on each repo's PR; Trinity then walks the merge chain

This is the sanctioned way to iterate on agent output without editing code yourself. It's the same shape for story gates and release gates.

Attachments

When you provide feedback, you can attach files:

  • Screenshots of desired behavior
  • Updated wireframes or specs
  • API contracts or documentation
  • Anything the agent might need to reason about

Attached files are saved with your feedback so the agent can open them wherever it runs, and they're cleared after a week. They show up in the project's asset list under the surface they came from until then.

Gate Reentry

Every gate tracks how many times it's been re-entered via gate_reentry_count. Visible on the gate card — useful for spotting stories that keep bouncing back through feedback without converging. If a story hits a high reentry count, that's usually a sign the problem needs manual intervention or a restructured plan.

Best Practices

  • Respond promptly — gates block the pipeline, and dependent stories stall behind them
  • Prefer feedback over skip — the feedback pipeline can fix most issues without you editing code
  • Be specific — "Make the button blue" beats "This doesn't look right"; include screenshots when layout matters
  • Use skip judiciously — bypassing a gate (skipping a checkpoint, a merge leg, or release notes) can leave downstream work brittle; the gate exists for a reason
  • Audit skipped gates — check the activity feed to see which gates you skipped and why