Files
everyinc__compound-engineer…/docs/guides/ce-commit-push-pr.md
2026-09-09 18:38:12 -05:00

13 KiB

ce-commit-push-pr

Commit, push, and open a PR. Or rewrite an existing PR description. Or print a description and leave git alone.

ce-commit-push-pr is the shipping skill. It is a git-workflow tool, not a core-loop step. Reach for it when the code is written and you want a PR, or when you only want the description.

It runs in one of three modes: the full ship, a description rewrite on an existing PR, or a printed description with no git side effects. Descriptions always cover the full PR commit range, not just whatever is uncommitted when you invoke it. After a new PR or new commits on an open one, it hands off to /ce-babysit-pr unless you opt out.

/ce-commit is the local-only sibling. Same commit pass, no push, no PR.


TL;DR

Question Answer
What does it do? Commits, pushes, and opens a PR; or rewrites an existing description; or prints a description without touching git
When to use it You want a PR, a refreshed description, or a draft body for a branch
What it produces An open PR URL, an updated description, or a printed body
What's next Hands off to /ce-babysit-pr by default (babysit:off or auto_babysit: false to skip). You merge when babysit reports ready. A clear stack request submits via gh stack and babysits the bottom open non-draft PR.

Example invocations

An empty invoke is the full ship. Your phrasing picks description-only vs rewrite. A PR URL or number alone is description-only. Stacks are opt-in.

# Commit, push, open a PR, then start /ce-babysit-pr
/ce-commit-push-pr

# Same ship, but do not start babysit
/ce-commit-push-pr babysit:off

# Print a description. No commit, no push, no gh pr edit.
/ce-commit-push-pr draft a PR description for this branch

# Rewrite the open PR on this branch. Preview first, then confirm.
/ce-commit-push-pr update the PR description to include benchmark results

# Description-only for that PR's complete commit range
/ce-commit-push-pr https://github.com/acme/widgets/pull/1234

# Force babysit mode on the PR this run just opened or updated
/ce-commit-push-pr babysit:checkpoint

# Opt-in stack rooted on that PR, then babysit the bottom open non-draft PR
/ce-commit-push-pr stack this on top of PR #123

# Same stack path, and tell babysit to land when green
/ce-commit-push-pr stack this and land when green

/ce-commit if you only want the local commit.


The Problem

"Code is done, open a PR" fails in a few repeatable ways:

  • A one-line fix and a large refactor get the same Summary / Test Plan / Notes template
  • git add -A picks up .env files, build artifacts, and generated files
  • The description only covers the working-tree diff and misses commits already on the branch
  • Issue references get dropped, or a magic word closes work the PR does not resolve
  • --body via stdin can return a URL while the body is empty (gh still exits 0)
  • The commit lands on the default branch, on detached HEAD, or against a stale base

The Solution

The skill picks a mode, then runs only that path:

  • Full workflow (default): commit pending work, push, and open a PR, or push onto the one that already exists
  • Description update: rewrite an existing PR body without a commit or push
  • Description-only: print a body. Apply only if you ask.

On the full path it stages named files, splits distinct concerns at file level (2-3 commits max), and routes detached HEAD, default-branch, and missing-upstream cases before it pushes. Every body goes through a temp file and --body-file <path>. Descriptions read the full PR range. A related-work preflight classifies each tracker ID as closing, non-closing, or uncertain. If it guesses the wrong mode, say so in the next prompt (just write the description, don't apply it).


How it behaves

Descriptions sized to the change

There is no fixed template. A typo fix can be one or two sentences. A large refactor gets motivation, decisions, a test plan, evidence, and risks. The composition pass reads every commit in the PR, not just the uncommitted diff. A project PR template still sets the structural floor.

Named-file commits, then a branch decision tree

Same commit rules as /ce-commit: never git add -A, splits at file level only, convention from context, then recent history, then conventional commits (fix: wins when fix: and feat: both fit). A plan unit ID already in hand gets appended to the subject in parentheses ((U3) for unit 3).

Branch routing is explicit:

  • Detached HEAD -> create a feature branch from current HEAD
  • Default branch with work -> create a feature branch. If local default has unpushed commits, it asks whether to carry them forward
  • Default branch, everything pushed, no PR -> stop (no feature branch work)
  • Feature branch, no upstream -> push -u and continue
  • Feature branch, all pushed, no open PR -> skip commit/push, open the PR
  • Feature branch, all pushed, open PR -> report up to date, then ask about a rewrite

Bodies go through a quoted heredoc into a temp file. The skill does not use --body-file -, stdin pipes, or --body "$(cat ...)", because those can hand gh an empty body that still returns a URL.

Before composing, it scans the prompt, branch name, full commit messages, existing body, PR template, plan notes, and visible IDs. A GitHub issue gets Fixes #123 only when the PR targets the default branch and actually resolves the issue. Linear gets Fixes ENG-123 or Related to ENG-123 in the description, not a comment. An unknown tracker gets a neutral link.

A rewrite previews the new title, the first two sentences of the Summary, and the body line count, then asks before gh pr edit. Decline and you can send focus text for another draft.

Concept teaching, branding, and the babysit handoff

When the change introduces a concept new to this repo (checked against the base ref, not the working tree), the body can gain a ## New concepts section. Most PRs should not have one. Turn it off with pr_teaching_section: false. pr_teaching_archive: true (or archive:on) writes the explainer under the CE artifact root and links it.

New PRs get the Compound Engineering badge only with branding:on or an explicit ask. Rewrites keep whatever branding is already there.

After a newly created PR, a successful stack submit, or new commits on an open PR, the run hands monitoring to /ce-babysit-pr. That skill selects the monitoring mode. When the same agent runs both skills, it continues until babysit reaches its stop condition. Declining an existing PR's description rewrite still proceeds to this handoff gate. babysit:off skips it; babysit:continuous and babysit:checkpoint force that mode. auto_babysit: false in CE config (config.local.yaml then config.yaml) is the standing opt-out. Description-only, description-update, mode:pipeline (except after a stack submit), non-GitHub remotes, a draft this run created, and a head you cannot push all skip the handoff. Fork PRs are fine when you can push the head.

Opt-in stacks

Stacks are never the default and never get suggested for a one-line fix. An explicit request is required intent, so it is not rewritten as a single PR with a custom --base. The skill probes for gh stack, classifies a named parent PR by number, reuses a confirmed topology, or (for completed work) builds the smallest useful linear layers, then submits with gh stack submit --auto --open and babysits the bottom open non-draft PR. Default posture is stack-ready; stack-land only when you asked to land or merge when green. Ambiguous review boundaries ask first. mode:pipeline returns the proposed topology as a residual instead of guessing.


Quick Example

You finish a notification-mute feature on a named feature branch with no upstream. Four uncommitted files span a migration, a model, a controller, and a UI component.

/ce-commit-push-pr matches recent conventional-commits-with-scope history, splits into two file-level commits (data layer; UI), and pushes -u. It reads the full range, not just the leftover working tree. You pass a GIF URL from the harness capture flow; that becomes ## Demo.

It writes a title (feat(notifications): add per-type mute with TTL) and a body (summary, decisions, test plan, the GIF) to a temp file, then gh pr create --title ... --body-file .... It returns the URL and starts /ce-babysit-pr.


When to Reach For It

Use ce-commit-push-pr when:

  • The code is written and you want commits plus a PR
  • An existing PR description is stale and you want it rewritten
  • You want a printed description without committing or pushing
  • You explicitly want a PR stack and gh stack is available

Skip it when:

  • You want commits only -> /ce-commit
  • You want to commit on the default branch and stay there. This skill will not push the default; it creates a feature branch
  • You need an interactive rebase or a history rewrite. Do that by hand
  • A PR is already open and you want it watched -> /ce-babysit-pr
  • Review comments are already in and you want them fixed now -> /ce-resolve-pr-feedback

Chain Position

On-demand shipping. Not a required ideation-chain stage.

/ce-work   ->  /ce-commit-push-pr  ->  /ce-babysit-pr
/ce-debug  ->  /ce-commit-push-pr  ->  /ce-babysit-pr
/ce-commit ->  /ce-commit-push-pr     (if you committed first, then decide to ship)

/lfg and /ce-work call this with branding:on when they own the ship. If the project's instructions name their own shipping process, that process runs instead. You can also invoke it on a branch you already finished by hand.


Reference

Argument Effect
(empty) Full workflow on the current branch, then babysit
"draft a PR description" / "describe this PR" Description-only. Printed, not applied.
"update the PR description" / "refresh the PR description" Description update on the existing PR
<PR URL or number> alone Description-only for that PR's full range
"...<focus text>" Steers composition (include the benchmarking results)
stack language Opt-in gh stack path. Parent PR/branch roots the layers.
babysit:off Skip the /ce-babysit-pr handoff
babysit:continuous / babysit:checkpoint Force that babysit mode (also watches a draft this run created)
mode:pipeline Non-interactive. Existing-PR rewrite defaults to no, except in description-update mode, which applies.
archive:on|off Per-run override of pr_teaching_archive
branding:on|off Add or omit Compound Engineering branding on a new PR. Off unless asked. Rewrites keep current branding.

See the configuration reference for pr_teaching_section, pr_teaching_archive, and auto_babysit.


FAQ

Why not a fixed PR template? A one-line fix does not need a test-plan heading. A large refactor does. The description matches the change; a project PR template still sets the structural floor.

Why --body-file instead of --body? Stdin wrappers can produce an empty body while gh exits 0 and returns a URL. A quoted temp file keeps $VAR, backticks, and literal EOF from expanding.

Description-only vs description update? Description-only prints and stops. No gh pr edit, no commit, no push. Description update finds the open PR, previews, asks, then applies with gh pr edit. A URL or number alone is description-only.

Does it follow a non-conventional commit style? Yes. Project conventions in context, then recent history, then conventional commits. Ambiguous fix: vs feat: defaults to fix:.

Does it skip hooks or signing? No. The commit command does not pass --no-verify or --no-gpg-sign. Your git config and hooks run as usual.

Can I open a draft PR? Not as a flag on the full workflow. Use description-only, then gh pr create --draft --title "..." --body-file "...". Stack submit uses --auto --open so layers are ready for babysit, not drafts.

When does it open a stack? Only when you (or a standing preference) clearly want one. "Stack this on top of PR #123" builds a managed stack rooted on that PR. With no topology, it can split completed work into linear layers when whole-file groups or existing commits make one plan clear. It asks before an ambiguous split or a published-history rewrite.

Why is there no ## New concepts section? Most PRs should not have one. It fires only when the change introduces a concept that is new to this codebase and transferable. Refactors, renames, and dependency bumps never qualify. Set pr_teaching_section: false to turn it off.


See Also