Step 3 — Commit, push, and open the pull request (author path only)
This step applies only when you authored a fix in Step 2B — it's about
opening a PR. (The review path 2A adopts the existing PR instead of opening one,
then goes straight to Step 4 to land it.) Once the set is genuinely green:
Check again before publishing. Once the fix and PR body are ready, repeat
Step 1's search immediately before creating a new PR, or before the final
handoff to a CI publisher. Inspect only new or changed candidates, using Step 2A
if one may cover the bug; preserve your work while evaluating it. Recheck the
state of earlier candidates too: if one merged, use the shared repro audit on
updated main before deciding whether your fix is still needed. Record the check
and decision in fix_summary. Skip this refresh for skip_push and updates to
an existing PR.
Choose the publication mode before proceeding
- Local-only (
skip_push: true) — commit the fix and stop at Step 3.2. No PR
will be published automatically, so do not prepare a PR body or run Step 4.
This takes precedence even when CI appended a generic publisher contract.
- Workflow-owned publication (
skip_push: false plus an explicit CI publisher
contract) — do not push or make any gh write. Prepare and validate
.omnigent/pr-body.md using the body-writing instructions in Step 3.4, but do
not run its gh pr create command. Complete the deferred live-validation
preparation described in Step 4.4, then write the final handoff and stop. The
publisher performs the GitHub writes; do not run the PR-facing
CI/preview/review loop in the rest of Step 4.
- Direct publication (no publisher contract) — perform all of Step 3, then
drive the published PR through Step 4, except for the draft proposal below.
Unresolved design choice: after completing the investigation and available
validation in resolve-investigate, publish a direct author proposal with
gh pr create --draft. Explain the choice, evidence, alternatives, and remaining
checks in the body. Emit a partially_fixed handoff with the decision in
remaining_work. Skip preview, readiness checks, and the Step 4 review loop that
requires a ready PR; do not mark it ready merely to trigger automation. This is
a reviewable proposal, not proof the bug is fixed. For workflow-owned publication,
prepare the same body and incomplete handoff and obey the supplied publisher
contract; do not assume it supports drafts. skip_push still means local only.
In workflow-owned mode, .omnigent/ is intentionally gitignored, so body
transport does not rely on the file being committed. The workflow captures
pr-body.md separately in the resolve artifact bundle alongside the committed
checkpoint, then restores it into the publication worktree before running the PR
finalizer. The finalizer validates and uses that restored file as the PR
description; without it, the publisher can only construct a less readable
fallback from machine-oriented handoff fields.
Checked publication provided by CI
When .omnigent/pr-gate.json exists, use the pr.py helper supplied in the
resolve-drive-pr skill directory. This mode replaces the direct GitHub write
and token-recovery recipes below. Keep Git pushes on the supplied credential;
never decode another token or change credential configuration.
| Action | Helper arguments |
|---|
| Open a PR after the required checks | create --title TITLE --body-file FILE --base main |
| Update its description | edit --number N --body-file FILE |
| Reply to findings | comment --number N --body-file FILE |
| Submit a review without approval | review --number N --head SHA --event COMMENT --body-file FILE |
| Mark a draft ready | ready --number N |
Run the helper from the fix checkout. Use review_cycle.py request for review
requests; CI routes it through the host. Follow CI's review budget and warning
policy. Actions the helper does not support remain maintainer actions; never
recover a broader credential, approve, or merge to work around that boundary.
Legacy direct publication: GitHub write token
The following token setup applies only when CI has not supplied the checked
publication helper and has explicitly authorized direct publication.
Any write to GitHub — git push, gh pr create, gh pr edit --add-reviewer,
gh pr comment, gh pr close — needs the resolve-agent App installation token
(omni-resolve-agent[bot], Contents and Pull requests: write;
Actions: read and write on omnigent-ai/omnigent). Actions access is needed to
read review runs and completion artifacts and dispatch both review workflows.
Your shell does not inherit it in a usable env var:
you run inside the session's runner process (a different process, often a
different machine when hosted on --server), so $GH_TOKEN in your shell is
empty and a bare git push fails with a 403 / permission error. This is not
a missing/expired/read-only token — the write credential IS on this machine, in
the git config of your checkout. Recover it before any GitHub write.
The reliable source is the checkout's persisted http.extraheader.
actions/checkout bakes the App installation token into your repo's git config
as an AUTHORIZATION: basic <base64> header (git worktrees share it via the
common config, so it's readable from your fix worktree too). Decode it and export
it as GH_TOKEN:
# Run from anywhere inside your checkout / fix worktree. The extraheader value is
# base64("x-access-token:<token>"), so strip the prefix, base64 -d, take the part
# after the colon.
export GH_TOKEN="$(git config --get http.https://github.com/.extraheader \
| sed 's/^AUTHORIZATION: basic //' | base64 -d | cut -d: -f2-)"
[ -n "$GH_TOKEN" ] || echo "no extraheader token found in git config"
gh auth setup-git # route git pushes through gh's credential helper with this token
- Do this once at the start of Step 3 (and again in Step 4 if a later
gh/git push call reports it lost auth). Then push, open the PR, request the
reviewer, and comment normally — all of them use this token. Confirm it works
and is write-scoped with gh auth status / a cheap gh api /repos/omnigent-ai/omnigent
before relying on it.
- Do not go hunting elsewhere first. The token is not reachable via
/proc/*/environ (that is denied in the session sandbox), and the ambient
github-actions[bot] credential is read-only on omnigent-ai/omnigent (it's
scoped to omnigent-internal) — both are dead ends that waste the turn. The
extraheader above is the one that works.
- If the extraheader is genuinely absent (rare — e.g. a
skip_push run, or the
checkout didn't persist it), report that exact fact in maintainer_review with
the command output. Never substitute a guess like "token expired" or "PAT
is read-only" — those are false and drop the hand-off silently. Only a real,
quoted failure goes in maintainer_review.
- CI may also configure
omnigent.forkPushTokenFile. That is a separate
maintainer credential for one purpose only: pushing a fix to an existing fork
PR whose author enabled maintainer edits. Never export it as GH_TOKEN and
never pass it to gh; PR creation, comments, reviews, labels, and every other
visible action must continue using the App token so GitHub attributes them to
omni-resolve-agent[bot].
Once the set is genuinely green:
-
Commit the fix and selected permanent regression tests on the working
branch. Reused unchanged tests need no new commit. Follow the repo's commit
conventions. Before omitting an investigative test introduced for this task,
retain its original paths, command, tested revision, result, and source under
.omnigent/repro-evidence/, or cite the intact CI repro baseline/bundle.
Follow the evidence retention rules in 2B.4:
identify the CI run/artifact/path or verified persistent local copy, and
distinguish pending workflow upload from confirmed storage. A worktree-local
path alone is not durable; preserve that worktree if retention is unresolved.
Put selected committed tests in tests and the selection/evidence location in
test_audit; no reproduction-only source is required in the PR. This does not
authorize deleting existing repository tests solely to reduce LOC.
Never commit workspace artifacts. In particular, never stage or commit
the recordings/ clips or any .omnigent/ handoff files (e.g.
.omnigent/repro-handoff.json): recordings are workspace artifacts that ride
in the PR's Demo section / CI artifact bundle, not in the diff (see
dev/recording-lanes.md). Do not use a blanket
git add -A / git add . that sweeps them in — stage the fix and test paths
explicitly, and run git status / git diff --cached --stat before committing
to confirm the staged set is only the fix + test. If a recording or handoff
file already landed in an earlier commit on this branch, remove it (e.g.
git rm --cached) so it never reaches the PR.
Read the staged diff for redundant comments and docstrings, including tests
carried over from repro. Keep only short explanations of non-obvious
constraints; move investigation history to the handoff. If a safety
explanation runs long, consider clearer code or a focused docstring first.
Refresh the shared impact assessment against the committed deliverable. If a
hook changed tested files, rerun their affected checks before the handoff.
After committing, if the target checkout has the advisory checker, run
python .github/scripts/pr-template/hygiene.py --base origin/main (using the
target's default branch). Review any long added comment blocks and trim only
redundant text. If the checker is unavailable, inspect the diff manually;
the workflow-owned publisher runs its own copy before creating a PR.
-
If the input has skip_push: true, stop here — the fix is committed
locally; do not push and do not open a PR. Report the branch name in
your output (pushed_branch) so a human can inspect, push, and PR it. The
focused local validation in 2B.5 still runs before the handoff is written.
This local-only input also suppresses workflow-owned publication; never treat
the presence of the generic CI publisher overlay as permission to continue.
-
Otherwise push the branch. First make sure git push / gh have the
write token — see "Get the GitHub write token" below. Your shell does not
inherit GH_TOKEN (you run in the session's runner, not the CI wrapper's
process), so echo $GH_TOKEN is normally empty and a bare git push / gh pr create fails with a permission error. Recover the token first; do not
conclude the token is "expired" or "read-only" from an empty env var — it is
present on the machine, just not exported to your shell.
-
Open a ready-for-review PR with gh pr create, unless the draft proposal
exception above applies. Automated review runs on ready PRs. Create
.omnigent/ if needed. If the target repository provides
.github/pull_request_template.md, copy it to
.omnigent/pr-body.md and edit that file. Otherwise create
.omnigent/pr-body.md with concise Related issue, Summary, and Test
Plan sections. Pass the finished file to gh pr create --body-file .omnigent/pr-body.md. The
workflow-owned publisher also restores this file from the resolve artifact
bundle if it has to finish publication after your session ends, so write it
before the GitHub call or final handoff. Link the bug in the template's
Related issue section.
Write the description for a reviewer, not for the handoff parser:
- Keep the template's required headings and every checkbox row. Follow its
instructions for optional sections such as Changelog. Do not replace the
standard structure with custom
Root Cause, Validation, or Issues
sections.
- In Summary, start non-trivial changes with a 1–2 sentence ELI5 of the
user-visible problem and result, inline rather than in a separate section.
Then explain the cause and implementation in 1–3 short bullets or
paragraphs. Use complete sentences and plain language. Add a small diagram
when a relationship or sequence is hard to follow in prose. Never include
placeholder diagrams or empty sections.
State any intentional policy change, its historical rationale, and the
remaining decision from
resolve-investigate; a passing test alone does
not justify the policy.
- In Test Plan, group the proof into short, scannable bullets. Name the
command or test, what failed before the fix, and what passes now. Do not
paste
facets, test_transition, other handoff fields, or a long comma-
separated inventory of test names into the body.
- Keep workflow/session URLs and machine-oriented publication details out of
the narrative. The internal workflow links those separately. Never paste
the JSON handoff into the PR description.
- Aim for fewer than 600 visible words, including the template. This is a
review prompt, not a hard cap: retain necessary safety or migration details,
but leave investigation history and repeated proof in the handoff.
- Read the finished Markdown once as rendered prose. Split run-on sentences,
expand unexplained internal shorthand, and remove repeated evidence before
opening the PR. Compare Test Plan and Demo claims with the diff, test output,
and available footage.
If the target repository provides the template validator, validate the body
locally before publishing it:
PR_BODY="$(cat .omnigent/pr-body.md)" \
python .github/scripts/pr-template/validate.py
Fix every validation error before gh pr create. In Related issue, use a
GitHub closing keyword only against a GitHub issue number —
Resolve #<closing_issue_number> (equivalently Closes #<n>), using the
closing_issue_number you determined in Step 1 (the bug_url issue, or the
mirrored GitHub issue for a Linear ticket). Never point a closing keyword
at a raw Linear URL — GitHub can't close it, and it clutters the body. When
there is no closing_issue_number (Linear-only bug with no mirror), don't use
a closing keyword at all: reference the ticket in prose
(e.g. "Resolves OMNI-1234 (Linear)"). Then summarize the root cause and the
fix, and in the Test Plan give the concrete fail→pass proof (test paths,
the pre-fix fail reason, the post-fix pass). Check
"Bug fix" and the test-coverage boxes that apply. Generate the body from the
actual diff and this reproduction — do not skip template sections. Put the
before/after recordings in the Demo section: upload the files when your
environment can attach media to the PR; otherwise link where they live (the
CI run's artifact bundle, or the repro session) so reviewers can watch the
failure and the fix. For internal/API-only results with no visible user
interaction, put the written before/after evidence in Demo. If recording
was blocked, explain why and include the available evidence. When the bug
is a Linear ticket and a Linear key is available, also attach both recordings
to the ticket (GraphQL fileUpload + attachmentCreate).
If the target checkout has .github/scripts/pr-template/hygiene.py, run it
on the committed diff and finished body before publication:
python .github/scripts/pr-template/hygiene.py \
--base origin/main --body-file .omnigent/pr-body.md
Use the target's default branch when it is not main. Review warnings about
long comments, body length, or repeated prose; trim redundant text while
keeping necessary safety explanations. Warnings are advisory and do not
replace template validation. If the checker is unavailable, review the body
manually; the workflow-owned publisher runs its own copy before PR creation.
-
Emit an interim handoff now — the moment the PR is open. As soon as
gh pr create succeeds, print the full handoff json block (the Output schema)
with pr_url set and outcome at its current best assessment, before you
start Step 4. This is what lets the workflow post the PR link to the Linear
ticket promptly, rather than waiting the ~hour Step 4 can take. Leave the
not-yet-known Step-4 fields empty (ci_status, polly_review, ocr_review,
maintainer_review, with review_cycle: {}) — refill them in the final
handoff. Emit it as a normal intermediate message (json block last in that message), then carry on.
For a draft proposal, emit the incomplete handoff and finish without the
outward actions below or Step 4. Otherwise, before this handoff, do the two
outward actions a mid-turn drop would otherwise strand:
- Label your PR
ui-preview (author path) — gh pr edit <pr> --add-label ui-preview. Your own PR is same-repo, already-pipelined code, so it needs no
CI-green gate (see 4.1); label it now so the preview builds while you drive
Step 4. (Review-path fork PRs still wait for green — 4.1.)
- If you opened this PR to supersede another (fork take-over, or the
"approach is wrong" escape hatch), you already commented on that PR but left
it open. Ensure the replacement body contains
Supersedes #<old> on its own
line, and set reviewed_pr_url so workflow reconciliation can preserve and
inform the original PR until the replacement merges.
-
You do not merge. For a ready PR, go to Step 4 and drive it to a green,
reviewed, ready-for-a-human state. Draft proposals use the exception above.