Documents and enforces rules for closed-not-merged PR reconciliation, direct-master-push prevention, and issue label cleanup. Rules added: - Explicit definitions for Merged, Landed, Closed-not-merged, and Reconciled. - A PR is done only when Gitea reports it merged or reconciliation proves content is present on master. - Direct push to master is forbidden except as a documented recovery exception. - PRs closed but not merged trigger the reconciliation process. - Branch and worktree cleanup is forbidden until merge or reconciliation is confirmed. - Final reports require PR metadata and Git content verification. Closes #51.
13 KiB
name, description
| name | description |
|---|---|
| llm-project-workflow | Portable, safe operating workflow for LLMs working on any Git/forge project: issue-first, isolated branch worktrees, no self-review/self-merge, distinct author/reviewer profiles, cleanup after merge, and fail-closed behavior. Use at the start of any implementation, review, or merge task on a repo. |
LLM Project Workflow
A reusable workflow any LLM can follow to work on any repository safely. Copy
this skills/llm-project-workflow/ directory into another project unchanged;
adapt only the forge-specific names in Adapting to a project.
The core promise: an LLM never does unsafe or untracked work. Every change is tracked by an issue, isolated in its own worktree, reviewed by a different identity, and cleaned up only after a real merge.
Definitions
- Merged: Gitea PR metadata says
merged=true. - Landed: Equivalent content is present on remote
master, but PR metadata may not say merged. - Closed-not-merged: PR state is closed and
merged=false. - Reconciled: A human/LLM verified whether closed-not-merged content landed, partially landed, or was lost, and repaired issue/label/tracker state.
A. Issue-first rule
No repository change without a tracking issue. This includes creating,
editing, deleting, or chmod-ing files; docs; scripts; commits; pushes; and PRs.
- Before any change, confirm a tracking issue exists.
- If none exists, create one first (title + problem + scope + acceptance).
- Claim it (assign yourself or apply the
status:in-progresslabel) and comment that work is starting, including the planned branch name. - If the issue cannot be created or claimed, stop. Do not touch files.
Reading the repo, running read-only status/git log, and creating/claiming the
issue itself are allowed from the orchestration checkout without a prior issue.
B. Isolated worktree rule
Never implement or review in the main checkout. The main checkout is for
orchestration and status only (issue creation, git status, creating worktrees).
- Each issue gets its own branch worktree under an ignored
branches/directory. - Review work uses a separate review worktree, never the author's folder.
- Dirty work in one branch folder must not block starting another issue.
- No LLM may edit another issue's worktree unless explicitly assigned to it.
- Branch folders are removed only after the PR is merged/closed and cleanup is explicitly part of the task.
Every implementation branch must include its issue number so it is traceable end to end: issue → branch → worktree folder → PR → cleanup.
Allowed implementation patterns:
fix/issue-123-short-descriptionfeat/issue-123-short-descriptiondocs/issue-123-short-descriptionchore/issue-123-short-description
Review-only branches:
review/pr-456-short-description
Use a filesystem-safe folder under branches/ by replacing slashes with
hyphens, for example branches/fix-issue-123-short-description.
scripts/worktree-start enforces this: it rejects an implementation branch
that does not match (fix|feat|docs|chore)/issue-<number>-… (or a
review/pr-<number>-… branch), unless --allow-unlinked is passed. Traceability
is maintained by:
- the branch name (contains the issue number),
- a claim comment on the issue, e.g.
Claimed. Branch: fix/issue-123-short-description. Worktree: branches/fix-issue-123-short-description., - the PR body —
Closes #123when the PR should close the issue,Refs #123when related but not closing, - cleanup after merge — remove the remote branch, local branch, and the issue
worktree folder, and drop
status:in-progress.
For projects using Gitea-Tools helpers:
scripts/worktree-start fix/issue-123-example # → branches/fix-issue-123-example
scripts/worktree-review fix/issue-123-example # → branches/review-fix-issue-123-example (detached)
scripts/worktree-clean --delete-branch fix/issue-123-example
Manual equivalent:
git fetch <remote> --prune
git worktree add -b fix/issue-123-example branches/fix-issue-123-example <remote>/master
cd branches/fix-issue-123-example
venv/ and similar are not copied into new worktrees — run checks with a known
interpreter path, or create a venv inside the branch folder.
C. Identity and profile safety
- Use canonical execution profiles where available; the profile is the role, not the LLM. A task selects a profile; a profile is not permanently assigned.
- Author and reviewer identities must be distinct.
- Never place raw tokens/passwords in an LLM/MCP client config. Reference secrets
by keychain id or environment variable name only. Prefer a single canonical
config file selected by two env vars, e.g.:
GITEA_MCP_CONFIG— path to the canonical profiles fileGITEA_MCP_PROFILE— the profile to activate
- If the authenticated user equals the PR author, stop — no self-review, no self-merge.
D. Branch naming
fix/issue-123-short-description
feat/issue-123-short-description
docs/issue-123-short-description
review/pr-456-scope-check
Worktree folder = branch with / replaced by -
(branches/fix-issue-123-short-description).
E. Start-work workflow
- Verify the orchestration checkout (right repo, clean tree).
- Fetch/prune:
git fetch <remote> --prune. - Confirm local
masterequals remotemaster(git rev-list --left-right --count <remote>/master...master→0 0). - Create/claim the issue (§A).
- Create the isolated worktree (§B) from latest remote
master. - Implement the narrow scope only — no unrelated refactors or formatting churn.
- Add/update focused tests when behavior changes.
- Run the checks (tests, compile/lint,
git diff --check, secret scan). - Commit with an issue-linked message.
- Push the branch.
- Open a PR to
master. - If you are the author, stop before review/merge.
- Normal issue work must not directly push to
master. PR content should be merged through the forge PR merge mechanism. - Direct push to
masteris allowed only as a documented recovery exception. If used, the final report must include:- why the PR merge path could not be used
- exact commits pushed
- PR metadata state
- issue labels/state repaired
- whether the PR is closed-not-merged
F. Review workflow
- Use a separate review worktree (
scripts/worktree-review <branch>), detached. - Verify your authenticated identity.
- Verify the PR author — you must not be the author.
- Verify the worktree is clean.
- Inspect the full diff; confirm scope matches the linked issue; flag unrelated files.
- Run the tests.
- Do not merge if checks fail. Do not merge if the reviewer is the author.
G. Merge / cleanup workflow
Only an eligible (non-author) reviewer merges. After a real merge:
- Confirm remote
masteractually contains the merge commit (A PR is not done just becausemastermoved. A PR is done only when: Gitea reports the PR merged or reconciliation documents equivalent content onmaster; remotemastercontains the expected content; linked issues are closed;status:in-progressis removed). - Close/release the issue.
- Whenever an issue is closed, check for
status:in-progress: remove it, or report why it could not be removed. - Do not delete the remote source branch until: PR
merged=true, or reconciliation confirms content is safely landed, or the issue owner explicitly abandons the work. - Remove the local branch.
- Remove the branch worktree folder (
scripts/worktree-clean --delete-branch <branch>). Branches/worktrees are cleaned only after the above is verified. - Fetch/prune.
- Confirm the main checkout is clean and current (
0 0vs remote). - Final merge/reconciliation reports must include both: PR metadata (state, merged flag, merge commit/hash) and Git content (remote master hash, expected content present or not).
Never run cleanup before the merge is confirmed on remote master.
H. Fail-closed cases
Stop and report — take no mutating action — if:
- No issue exists and one cannot be created.
- Worktree state is unclear or unexpected.
- Branch/PR state conflicts with the prompt (e.g. prompt says "merged" but it is not).
- A PR is closed but not merged (closed with
merged=false). In this case:- stop normal review/merge
- do not delete branches/worktrees
- do not start dependent work
- run reconciliation
- Local
masteris ahead of remote unexpectedly. - The authenticated user is the PR author (for review/merge).
- Secrets/tokens appear in the diff.
- Tests fail.
- A cleanup step would delete unmerged work.
When in doubt, stop and surface the discrepancy; do not guess or work around a gate.
I. Recovery patterns
- Dirty worktree from another issue: do not touch it. Start your issue in its own new worktree; unrelated dirty work must not block you.
- Local
masterahead of remote unexpectedly: do not pushmaster. Confirm the commits are preserved on a feature branch (local + remote) first, thengit reset --hard <remote>/masterto realign. Never discard commits that are not safely pushed elsewhere. - PR closed but not merged (
merged=false): do not merge. Run reconciliation: compare PR content to remotemasterand decide:- fully landed: comment that content is present on
master, removestatus:in-progress, keep/close issue as appropriate, clean up only after content equivalence is confirmed. - partially landed: do not clean up, reopen issue if needed, create corrective issue/PR for missing pieces.
- not landed: reopen issue if needed, reopen PR or create replacement PR, do not clean up source branch/worktree.
- fully landed: comment that content is present on
- Branch deleted before merge: if the commits still exist locally (a branch or
reflog), re-push them and reopen the PR; otherwise recover via
git fsck --lost-found. Preserve first, then proceed. - Unauthorized/untracked file created: do not commit it. Leave pre-existing
untracked artifacts (e.g. editor/agent dirs, reports) alone; stage only the
files your issue names (
git add <files>, never blindgit add -A). - Preserve commits before a reset: confirm the target commits are reachable
from a branch that is pushed to the remote, then reset. Verify with
git branch --contains <sha>andgit log <remote>/<branch>.
J. Prompt snippets
Ready-to-copy templates live in templates/:
start-issue.md— start a new issue.review-pr.md— review a PR.merge-pr.md— merge a PR (eligible reviewer only).recover-bad-state.md— recover from bad state.reconcile-closed-not-merged-pr.md— reconcile a closed-not-merged PR.worktree-cleanup.md— clean up after merge.release-tag.md— create a release tag.
Adapting to a project
Replace these project-specific names when copying the skill elsewhere:
| Placeholder | Meaning | Example here |
|---|---|---|
<remote> |
Git remote for the forge | prgs |
| default branch | Integration branch | master |
| profile env vars | Canonical config + profile selectors | GITEA_MCP_CONFIG, GITEA_MCP_PROFILE |
branches/ |
Ignored worktree directory | branches/ |
| helper scripts | Worktree helpers | scripts/worktree-start / -review / -clean |
The rules in §A–§I are project-agnostic and should not change.
Versioning And Tagging
Releases follow SemVer: vMAJOR.MINOR.PATCH (use v0.x.y while
unstable). Choose the bump by the largest change since the last tag:
- PATCH — bug fixes, docs, tests, wrappers, non-breaking workflow polish.
- MINOR — new tools/helpers/config features; backward-compatible behavior.
- MAJOR — breaking config/schema/API behavior or a changed MCP contract.
Tags must:
- be created only from
master(the exact commit on remotemaster), - be created only after the full test suite passes,
- be annotated tags (
git tag -a), never lightweight, - include release notes / a changelog summary referencing the merged PRs/issues.
Never tag feature branches, dirty worktrees, unreviewed or self-authored
work, or commits not present on remote master.
Release process (see templates/release-tag.md):
git fetch <remote> --prune.- Verify local
masterequals remotemaster(0 0) and the tree is clean. - Run the full test suite; stop on any failure.
- Inspect merged issues/PRs since the last tag
(
git log --oneline <last-tag>..<remote>/master). - Choose the version bump.
- Create the annotated tag on remote
masterwith release notes. - Push the tag.
- Create/update release notes if the forge supports it.