8bff54d5ac
Formalize the branch↔issue relationship and add a release/version-tagging policy. Branch/issue linkage: - scripts/worktree-start now validates branch names: implementation branches must match (fix|feat|docs|chore)/issue-<number>-<slug>; review branches review/pr-<number>-<slug>. Untraceable names are rejected with a clear error (exit 2). New --allow-unlinked override for genuine exceptions. --dry-run preserved. - Documented issue → branch → worktree → PR → cleanup traceability in the runbook and the portable SKILL, including the claim-comment convention and Closes #n / Refs #n PR-body usage. - Noted that Gitea exposes no native issue→branch API field (only a PR head branch), so linkage is enforced via branch name + claim comment + PR body + cleanup. Versioning / tagging policy (docs only; no release automation yet): - SemVer vMAJOR.MINOR.PATCH (v0.x.y while unstable) with PATCH/MINOR/MAJOR bump rules. - Annotated tags only, from the exact commit on remote master, only after the full suite passes, with release notes referencing merged PRs/issues. Never tag feature branches, dirty worktrees, unreviewed/self-authored work, or commits not on remote master. - Release runbook in the runbook + SKILL, plus a new skills/llm-project-workflow/templates/release-tag.md prompt template. Tests: worktree-start branch validation — accepts fix/feat/docs/chore/issue-* and review/pr-*, rejects fix/random-name / my-branch / non-numeric issue, honors --allow-unlinked, preserves --dry-run. Full suite 291 passed / 0 failures; bash -n clean; git diff --check clean; no secrets. Release-tag automation (a scripts/release-tag helper) intentionally deferred to a later issue to keep this diff narrow and testable. Closes #48. Refs #38, #39, #46. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
282 lines
10 KiB
Markdown
282 lines
10 KiB
Markdown
# LLM Project Workflow
|
|
|
|
Use this skill when an LLM is asked to create issues, implement repository
|
|
changes, review pull requests, merge pull requests, or recover from unsafe git
|
|
state in any project.
|
|
|
|
This skill is intentionally portable. Replace the remote name, default branch,
|
|
profile names, and repository URL conventions with the target project's local
|
|
standards, but keep the safety rules intact.
|
|
|
|
## Core Rule
|
|
|
|
No repository change happens without a tracking issue first.
|
|
|
|
Repository changes include creating files, editing files, deleting files,
|
|
changing executable bits, changing documentation, adding scripts, changing
|
|
config, committing, pushing, and opening pull requests.
|
|
|
|
If no issue exists, create one before touching the repository. If issue creation
|
|
or issue claiming fails, stop immediately and report the blocker.
|
|
|
|
## Worktree Isolation
|
|
|
|
Never implement or review directly in the main checkout.
|
|
|
|
The main checkout is for orchestration only: status checks, issue creation,
|
|
issue claiming, fetching, and creating branch worktrees. Each issue gets a
|
|
separate branch worktree under an ignored `branches/` directory. Review work
|
|
gets its own separate review worktree.
|
|
|
|
Dirty work in one branch folder must not block unrelated work in another branch
|
|
folder. No LLM may edit or clean another issue's worktree unless explicitly
|
|
assigned to that issue and cleanup is part of the task.
|
|
|
|
## Branch Naming
|
|
|
|
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-description`
|
|
- `feat/issue-123-short-description`
|
|
- `docs/issue-123-short-description`
|
|
- `chore/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 #123` when the PR should close the issue, `Refs #123`
|
|
when related but not closing,
|
|
- cleanup after merge — remove the remote branch, local branch, and the issue
|
|
worktree folder, and drop `status:in-progress`.
|
|
|
|
Forges like Gitea do not expose a native issue→branch association through the
|
|
API (only a PR's head branch), so linkage is enforced by the branch name, claim
|
|
comment, PR body, and cleanup process above — not a dedicated API field.
|
|
|
|
## Worktree Creation
|
|
|
|
Generic pattern:
|
|
|
|
```bash
|
|
git fetch <remote> --prune
|
|
git worktree add -b <branch> branches/<safe-branch-folder> <remote>/master
|
|
cd branches/<safe-branch-folder>
|
|
```
|
|
|
|
For Gitea-Tools specifically:
|
|
|
|
```bash
|
|
./scripts/worktree-start fix/issue-123-example
|
|
cd branches/fix-issue-123-example
|
|
```
|
|
|
|
If the default branch is not `master`, use the target project's default branch.
|
|
If `local master` is ahead of the remote unexpectedly, stop before creating the
|
|
worktree and ask for explicit recovery instructions.
|
|
|
|
## Identity And Profile Safety
|
|
|
|
Use canonical execution profiles where available. The profile is the role; the
|
|
LLM is not permanently an author, reviewer, or merger.
|
|
|
|
Author and reviewer identities must be distinct. Before review, approval, merge,
|
|
or branch cleanup, verify both the authenticated user and the PR author. If the
|
|
authenticated user is the PR author, stop immediately.
|
|
|
|
Never place raw tokens or passwords in LLM configs, prompts, commits, PR
|
|
comments, logs, or tool outputs. Prefer profile references such as:
|
|
|
|
- `GITEA_MCP_CONFIG`
|
|
- `GITEA_MCP_PROFILE`
|
|
|
|
If identity cannot be determined, fail closed. Do not approve, merge, close, or
|
|
clean up with an unknown identity.
|
|
|
|
## Implementation Workflow
|
|
|
|
1. Verify the request has a tracking issue. If not, create one.
|
|
2. Claim the issue using the project's in-progress convention, such as
|
|
`status:in-progress`.
|
|
3. Fetch/prune and confirm the local default branch matches the remote default
|
|
branch.
|
|
4. Create an issue-specific branch worktree from the latest remote default
|
|
branch.
|
|
5. Implement only the issue scope inside that worktree.
|
|
6. Run focused checks and the project's required full checks.
|
|
7. Inspect the diff for scope, secrets, and unrelated files.
|
|
8. Commit.
|
|
9. Push.
|
|
10. Open a PR to the default branch.
|
|
11. Stop before review or merge if you authored the PR.
|
|
|
|
## Review Workflow
|
|
|
|
1. Use a separate review worktree.
|
|
2. Verify authenticated identity.
|
|
3. Verify PR author.
|
|
4. Stop if authenticated identity matches the PR author.
|
|
5. Verify the PR is open and targets the expected base branch.
|
|
6. Verify the PR head matches the reviewed commit or includes it.
|
|
7. Verify the review worktree is clean.
|
|
8. Inspect changed files and diff against the linked issue scope.
|
|
9. Run required tests and checks.
|
|
10. Inspect for secrets, credential paths, raw environment dumps, unrelated work,
|
|
and disallowed behavior.
|
|
11. If checks fail, leave exact blockers and do not approve or merge.
|
|
12. If checks pass and the reviewer is eligible, approve or leave the requested
|
|
review comment according to the task.
|
|
|
|
## Merge And Cleanup Workflow
|
|
|
|
Only merge when assigned merge duty and reviewer-eligible.
|
|
|
|
After an eligible merge:
|
|
|
|
1. Confirm the PR is still open and targets the expected base branch.
|
|
2. Confirm the PR head is still the reviewed commit or includes it.
|
|
3. Confirm the authenticated user is not the PR author.
|
|
4. Merge through the project's gated merge workflow.
|
|
5. Confirm remote `master` or the target default branch contains the merge.
|
|
6. Close or release the linked issue according to project workflow.
|
|
7. Remove `status:in-progress` or the equivalent in-progress label when
|
|
applicable.
|
|
8. Delete the merged remote branch when policy allows.
|
|
9. Remove the local PR branch.
|
|
10. Remove the local branch worktree folder only after confirming it is merged
|
|
or no longer needed.
|
|
11. Fetch/prune.
|
|
12. Confirm the main checkout is clean and current.
|
|
|
|
Do not delete branches or worktrees containing unmerged work.
|
|
|
|
## Fail-Closed Cases
|
|
|
|
Stop immediately if any of these are true:
|
|
|
|
- no issue exists and one cannot be created
|
|
- the issue cannot be claimed
|
|
- a worktree is dirty and belongs to the current task, but its state is unclear
|
|
- dirty work belongs to another issue or another LLM
|
|
- branch or PR state conflicts with the prompt
|
|
- the PR is closed but not merged
|
|
- local `master` is ahead of the remote unexpectedly
|
|
- authenticated identity cannot be verified
|
|
- authenticated user is the PR author for review, approval, or merge
|
|
- the active profile is unknown or not allowed for the requested operation
|
|
- secrets, tokens, passwords, auth headers, or credential paths are found in the
|
|
diff
|
|
- tests or required checks fail
|
|
- branch cleanup would delete unmerged work
|
|
- production, deploy, rollback, migration, restart, CI trigger, or unrelated
|
|
service behavior appears outside the issue scope
|
|
|
|
Fail closed means no mutation, no approval, no merge, and no cleanup that could
|
|
destroy work.
|
|
|
|
## Recovery Patterns
|
|
|
|
Dirty worktree from another issue:
|
|
|
|
- Do not edit, reset, delete, or clean it.
|
|
- Create or use a separate branch worktree for the assigned issue.
|
|
- Report the unrelated dirty files only if they affect the task.
|
|
|
|
Dirty worktree from the current issue:
|
|
|
|
- Inspect status and diff.
|
|
- Preserve useful work in a commit, patch, or explicit handoff only when asked.
|
|
- Do not reset or delete ambiguous work without explicit approval.
|
|
|
|
Local default branch ahead of remote:
|
|
|
|
- Stop.
|
|
- Report the local and remote commit hashes.
|
|
- Ask whether to push, preserve, or reset. Do not choose destructively.
|
|
|
|
PR closed but not merged:
|
|
|
|
- Do not merge.
|
|
- Release the issue from in-progress only if the task explicitly asks and the
|
|
project workflow allows it.
|
|
- Leave a clear comment explaining the PR is closed without merge.
|
|
|
|
Branch deleted before merge:
|
|
|
|
- Verify whether the PR was merged.
|
|
- If merged, cleanup can continue.
|
|
- If not merged, stop and report that the source branch is missing.
|
|
|
|
Unauthorized untracked file created:
|
|
|
|
- Stop immediately.
|
|
- Report the exact file path.
|
|
- Do not commit it.
|
|
- Remove it only when explicitly instructed or when the recovery request asks for
|
|
removal.
|
|
- Recreate the change only after an issue exists and is claimed.
|
|
|
|
Need to preserve commits before reset:
|
|
|
|
- Prefer non-destructive preservation: tag, branch, patch file, or pushed backup
|
|
branch.
|
|
- Do not use destructive reset or checkout commands unless the user explicitly
|
|
requests that operation.
|
|
|
|
## Prompt Templates
|
|
|
|
Ready-to-copy templates live in `templates/`:
|
|
|
|
- `start-issue.md`
|
|
- `review-pr.md`
|
|
- `merge-pr.md`
|
|
- `recover-dirty-worktree.md`
|
|
- `release-tag.md`
|
|
|
|
Adapt the placeholders to the project before use.
|
|
|
|
## 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 remote `master`),
|
|
- 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`](templates/release-tag.md)):
|
|
|
|
1. `git fetch <remote> --prune`.
|
|
2. Verify local `master` equals remote `master` (`0 0`) and the tree is clean.
|
|
3. Run the full test suite; stop on any failure.
|
|
4. Inspect merged issues/PRs since the last tag
|
|
(`git log --oneline <last-tag>..<remote>/master`).
|
|
5. Choose the version bump.
|
|
6. Create the annotated tag on remote `master` with release notes.
|
|
7. Push the tag.
|
|
8. Create/update release notes if the forge supports it.
|