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)
Payload: The agent's analysis, the proposed alternative, and the reasoning for the substitution.
- Approve Deviations — accept the substitution; the implementer uses the alternative
- Reject — Follow Plan — keep the original technology; the implementer proceeds as planned
Missing Assets (missing_assets)
Payload: One card per declared need, each with a purpose line and a prose description of what the story or release expects.
- 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 shippedplaceholder.svg,picsum.photos, Lorem ipsum, etc. - Contacts (
skipCheckpointBusinessDetailsAudit/skipReleaseBusinessDetailsAudit) — catchesexample.comemails,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)
Payload: Which fields are missing + why the story needs them.
- 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)
Payload: Each missing key — the service it belongs to, the env var name it's injected as, and why the story needs it.
- 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)
Payload: The key_names with visible-but-undecryptable rows, and the workspace whose grant is pending.
- 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)
- Worker pre-flight — before the run's first phase, Trinity scans the project's stack for rows marked
needs_keysand checks whether each one has a secret bound. Any gap fires the gate with the full list of services to set up. - Agent signal — any pipeline phase can raise the gate mid-execution via the
signal_service_requiredtool 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.
- 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)
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.
- 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)
- Retry — once the backend is available again, retry the run; it re-resolves the environment and continues.
External Dependencies (external_deps)
Payload: List of external deps (name, description) and a human-readable explanation.
- 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)
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.
- 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)
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).
- 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)
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.
- 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)
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.
- 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)
Awaiting Host Review (forge_review_pending)
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)
- 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.
- 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)
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)
Payload: Audit findings, fixes applied, any remaining issues.
- Approve — marks the checkpoint passed
- Skip — acknowledges unresolved issues and continues
- Diagnose — open a chat to re-enter the feedback pipeline
Merge Conflict (merge_conflict)
Payload: Which repo, branch, and base branch are conflicting. Shown alongside a "resolve locally" hint.
- 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)
Payload: PR URL, branch, and repo — so you can see what was closed.
- 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)
Payload: Which repos succeeded vs. failed, with error details per failed repo.
- 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)
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).
- 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)
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.
- 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)
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.
- 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)
Waiting to Tag (version_pending)
Version Check Failed (version_check_failed)
- 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.1beside1.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.1after2.0.0-rc.2has 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.numbersuch as-rc.1.
The gate lists each problem and what every manifest declares.
Waiting to Forward-Port (forward_port)
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)
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.
- 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
latestpointer happens as part of that publish itself.
Waiting for a Quiet Release (rename_pending)
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.
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:
- Triage — the agent classifies what you're asking for
- Analyst — re-reads the codebase with your feedback as context
- Implementer — makes changes, committing as it goes
- Audit round — the Auditor's reviewers read the new changes and leave a review on each repo's PR
- 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