Compare commits

...

2 Commits

Author SHA1 Message Date
sysadmin 00ec883014 docs: add portable llm-project-workflow skill + templates (#46)
Extract the project's operating rules into a reusable, project-agnostic skill
so any repo can adopt the same safe LLM workflow.

- skills/llm-project-workflow/SKILL.md: issue-first; isolated branch worktrees
  (main checkout = orchestration only); distinct author/reviewer identities and
  profile safety (secrets by reference only; stop if authenticated user == PR
  author); branch naming; start/review/merge/cleanup workflows; fail-closed
  cases; recovery patterns; and an "Adapting to a project" table for the
  forge-specific names.
- templates/: copy/paste prompts for start-issue, review-pr, merge-pr,
  recover-bad-state, worktree-cleanup.
- Link the skill from README.md and docs/llm-workflow-runbooks.md (the runbook
  is framed as the Gitea-specific application of the portable skill).

Docs-only; no code, no secrets, safe placeholder examples only. No change to
MCP runtime, Gitea API, credential storage, or worktree helpers.

Checks: full suite 287 passed / 0 failures; git diff --check clean; secret scan
of skills/ clean.

Closes #46. Refs #38, #39.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 04:07:14 -04:00
sysadmin 92b449f080 docs: add portable LLM workflow skill 2026-07-02 03:17:02 -04:00
9 changed files with 390 additions and 0 deletions
+13
View File
@@ -186,6 +186,10 @@ Notes:
[`docs/llm-workflow-runbooks.md`](docs/llm-workflow-runbooks.md) for the [`docs/llm-workflow-runbooks.md`](docs/llm-workflow-runbooks.md) for the
task-scoped, profile-based runbooks (create/review/merge/close, thin task-scoped, profile-based runbooks (create/review/merge/close, thin
launchers, migration, fail-closed rules). launchers, migration, fail-closed rules).
- For the **portable** version of this workflow (issue-first, isolated
worktrees, no self-review/merge, profile safety, cleanup, fail-closed) that
can be copied into any project, see the reusable skill
[`skills/llm-project-workflow/SKILL.md`](skills/llm-project-workflow/SKILL.md).
- **Audit logging (#18):** mutating actions emit a durable, redacted JSON audit - **Audit logging (#18):** mutating actions emit a durable, redacted JSON audit
record — timestamp, action, result (`allowed`/`blocked`/`failed`/`succeeded`), record — timestamp, action, result (`allowed`/`blocked`/`failed`/`succeeded`),
profile name + audit label, authenticated username, target repo/issue/PR, profile name + audit label, authenticated username, target repo/issue/PR,
@@ -270,6 +274,15 @@ The generated launcher snippets contain only `command`, `args`,
`GITEA_MCP_CONFIG`, and `GITEA_MCP_PROFILE` — never a token or password. `GITEA_MCP_CONFIG`, and `GITEA_MCP_PROFILE` — never a token or password.
</details> </details>
### Portable LLM workflow skill
Reusable LLM operating rules are packaged as a portable skill at
[`skills/llm-project-workflow/SKILL.md`](skills/llm-project-workflow/SKILL.md).
It documents issue-first work, isolated branch worktrees, no self-review or
self-merge, profile safety, fail-closed behavior, merge cleanup, and recovery
patterns. Copy the `skills/llm-project-workflow/` directory into other projects
that should use the same workflow.
<details> <details>
<summary><strong>Codex / non-MCP tools</strong></summary> <summary><strong>Codex / non-MCP tools</strong></summary>
+13
View File
@@ -7,11 +7,23 @@ package of the MCP Control Plane: creating issues, implementing them, opening
and reviewing pull requests, merging, and closing out — safely and and reviewing pull requests, merging, and closing out — safely and
reproducibly. reproducibly.
> For the **project-agnostic** version of these operating rules (issue-first,
> isolated worktrees, no self-review/merge, profile safety, cleanup, fail-closed)
> that can be copied into any repository, see the reusable skill
> [`skills/llm-project-workflow/SKILL.md`](../skills/llm-project-workflow/SKILL.md)
> and its `templates/`. This runbook is the Gitea-specific application of it.
These runbooks are **operational guidance only**. They add no tooling; the These runbooks are **operational guidance only**. They add no tooling; the
behavior they rely on already exists (canonical runtime profiles, the behavior they rely on already exists (canonical runtime profiles, the
interactive setup menu, identity/eligibility checks, gated review/merge, and interactive setup menu, identity/eligibility checks, gated review/merge, and
audit logging). See [Related documents](#related-documents). audit logging). See [Related documents](#related-documents).
For cross-project use, copy the portable workflow skill at
[`../skills/llm-project-workflow/SKILL.md`](../skills/llm-project-workflow/SKILL.md).
It extracts the issue-first, isolated-worktree, no-self-review, profile-safety,
merge-cleanup, fail-closed, and recovery rules into a reusable package that can
be adapted to other repositories.
## Principle: the profile is the role, not the LLM ## Principle: the profile is the role, not the LLM
```text ```text
@@ -316,6 +328,7 @@ with the profile and authenticated user when `GITEA_AUDIT_LOG` is set (see
## Related documents ## Related documents
- [`../skills/llm-project-workflow/SKILL.md`](../skills/llm-project-workflow/SKILL.md) — portable cross-project LLM workflow skill.
- [`gitea-execution-profiles.md`](gitea-execution-profiles.md) — the profile model. - [`gitea-execution-profiles.md`](gitea-execution-profiles.md) — the profile model.
- [`safety-model.md`](safety-model.md) — trust boundaries and audit logging. - [`safety-model.md`](safety-model.md) — trust boundaries and audit logging.
- [`tool-boundaries.md`](tool-boundaries.md) — per-tool allowed operations. - [`tool-boundaries.md`](tool-boundaries.md) — per-tool allowed operations.
+190
View File
@@ -0,0 +1,190 @@
---
name: llm-project-workflow
description: >-
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](#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.
---
## 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.
1. Before any change, confirm a tracking issue exists.
2. If none exists, create one first (title + problem + scope + acceptance).
3. Claim it (assign yourself or apply the `status:in-progress` label) and comment
that work is starting, including the planned branch name.
4. **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.
Preferred helpers (if present in the project):
```bash
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:
```bash
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 file
- `GITEA_MCP_PROFILE` — the profile to activate
- **If the authenticated user equals the PR author, stop** — no self-review, no
self-merge.
## D. Branch naming
```text
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
1. Verify the orchestration checkout (right repo, clean tree).
2. Fetch/prune: `git fetch <remote> --prune`.
3. Confirm local `master` equals remote `master` (`git rev-list --left-right --count <remote>/master...master``0 0`).
4. Create/claim the issue (§A).
5. Create the isolated worktree (§B) from latest remote `master`.
6. Implement the narrow scope only — no unrelated refactors or formatting churn.
7. Add/update focused tests when behavior changes.
8. Run the checks (tests, compile/lint, `git diff --check`, secret scan).
9. Commit with an issue-linked message.
10. Push the branch.
11. Open a PR to `master`.
12. **If you are the author, stop before review/merge.**
## F. Review workflow
1. Use a separate review worktree (`scripts/worktree-review <branch>`), detached.
2. Verify your authenticated identity.
3. Verify the PR author — **you must not be the author.**
4. Verify the worktree is clean.
5. Inspect the full diff; confirm scope matches the linked issue; flag unrelated files.
6. Run the tests.
7. **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:
1. Confirm remote `master` actually contains the merge commit.
2. Close/release the issue; remove `status:in-progress` if used.
3. Delete the remote branch.
4. Remove the local branch.
5. Remove the branch worktree folder (`scripts/worktree-clean --delete-branch <branch>`).
6. Fetch/prune.
7. Confirm the main checkout is clean and current (`0 0` vs remote).
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.
- Local `master` is 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 `master` ahead of remote unexpectedly:** do not push `master`. Confirm
the commits are preserved on a feature branch (local + remote) first, then
`git reset --hard <remote>/master` to realign. Never discard commits that are
not safely pushed elsewhere.
- **PR closed but not merged:** the work is not in mainline. Re-push the branch,
reopen (or open a replacement) PR, and let an eligible reviewer merge. Do not
assume "closed" means "merged" — verify remote `master` contains the commits.
- **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 blind `git 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>` and `git log <remote>/<branch>`.
## J. Prompt snippets
Ready-to-copy templates live in [`templates/`](templates/):
- [`start-issue.md`](templates/start-issue.md) — start a new issue.
- [`review-pr.md`](templates/review-pr.md) — review a PR.
- [`merge-pr.md`](templates/merge-pr.md) — merge a PR (eligible reviewer only).
- [`recover-bad-state.md`](templates/recover-bad-state.md) — recover from bad state.
- [`worktree-cleanup.md`](templates/worktree-cleanup.md) — clean up after merge.
## 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.
@@ -0,0 +1,28 @@
# Template: merge a PR (eligible reviewer only)
Copy, fill the `<...>` fields, and paste as the task prompt.
```text
Task: merge PR #<pr> for issue #<n> if it is eligible and checks pass.
Rules (llm-project-workflow):
- Only an eligible, NON-author reviewer merges. If authenticated user == PR
author → STOP.
- Do not merge unless the PR is open, mergeable, and its checks/review pass.
- No force-merge, no bypassing branch protections.
Steps:
1. Verify authenticated identity + active profile.
2. Confirm PR #<pr>: author (not you), state open, mergeable, review approved.
3. If any gate fails → STOP and report.
4. Merge with explicit confirmation (e.g. confirmation="MERGE PR <pr>"),
optionally pinning the reviewed head SHA / changed-file set.
5. Confirm remote master now contains the merge commit.
Then run the cleanup template (worktree-cleanup.md):
- close/release issue #<n>, remove status:in-progress
- delete remote branch, remove local branch + worktree folder
- fetch/prune; confirm main checkout is clean and current (0 0).
Handoff: reviewer identity, merge result + commit, cleanup done, issue closed.
```
@@ -0,0 +1,32 @@
# Template: recover from bad state
Copy, fill the `<...>` fields, paste as the task prompt. Recovery is read-then-
act: gather facts first, never discard unmerged work.
```text
Task: recover repo state for <situation>. Do not lose unmerged work.
Rules (llm-project-workflow):
- Fail closed: if state is unclear or a step would delete unmerged work, STOP.
- Never push master. Never discard commits not safely pushed to <remote>.
Diagnose first:
1. git fetch <remote> --prune
2. git status --short; git worktree list
3. git rev-list --left-right --count <remote>/master...master # ahead/behind
4. For any PR involved: confirm state (open/closed/merged) AND whether
<remote>/master actually contains its commits ("closed" != "merged").
Act per case:
- Dirty worktree from another issue: leave it; start yours in a new worktree.
- Local master ahead of remote: confirm the extra commits live on a branch
pushed to <remote>, THEN git reset --hard <remote>/master. Verify with
`git branch --contains <sha>` first.
- PR closed but not merged: re-push the branch, reopen/replace the PR, let an
eligible reviewer merge. Do not merge your own.
- Branch deleted before merge: recover commits from a local branch/reflog (or
git fsck --lost-found), re-push, reopen the PR.
- Unauthorized untracked file: do not commit it; leave pre-existing artifacts.
Handoff: what was wrong, evidence, action taken, current state, what remains.
```
@@ -0,0 +1,31 @@
# Recover Dirty Worktree Prompt
You are recovering repository state in `<repo-name>`.
Rules:
- Do not reset, delete, clean, or overwrite work unless explicitly instructed.
- Do not edit another issue's worktree unless assigned to that issue.
- Preserve ambiguous work before any destructive operation.
Workflow:
1. Run `git status --short --branch`.
2. Identify whether dirty files belong to the current issue, another issue, or
unknown work.
3. If dirty work belongs to another issue, leave it alone and use a separate
worktree for the current task.
4. If an unauthorized untracked file was created, stop and report its exact path.
5. Remove unauthorized files only when explicitly instructed.
6. If local `<default-branch>` is ahead of `<remote>/<default-branch>`, stop and
report both commit hashes.
7. If cleanup is requested, verify the branch is merged or explicitly abandoned
before deleting any branch or worktree.
Report:
- current branch
- dirty files
- ownership assessment
- actions taken
- remaining blockers
@@ -0,0 +1,26 @@
# Template: review a PR
Copy, fill the `<...>` fields, and paste as the task prompt.
```text
Task: review PR #<pr> for issue #<n>.
Rules (llm-project-workflow):
- Review in a SEPARATE detached review worktree, never the author's folder.
- You must NOT be the PR author. If the authenticated user == PR author, stop.
- Do not merge if any check fails.
Steps:
1. Verify your authenticated identity (whoami) and the active profile.
2. Fetch the PR facts: PR author, head SHA, state (must be open), base branch.
3. If authenticated user == PR author → STOP (no self-review).
4. scripts/worktree-review <pr-head-branch> # detached, branches/review-*
cd branches/review-<pr-head-branch-slug>
5. Confirm the worktree is clean. Inspect the FULL diff; confirm scope matches
issue #<n>; flag any unrelated files, secrets, or formatting churn.
6. Run the test suite; note results.
7. Post the review verdict: approve only if scope is clean and checks pass;
otherwise request changes with specifics. Never merge from this review step.
Handoff: reviewer identity, PR author, scope verdict, checks + results, decision.
```
@@ -0,0 +1,29 @@
# Template: start a new issue
Copy, fill the `<...>` fields, and paste as the task prompt.
```text
Task: implement <issue title / one-line goal>.
Rules (llm-project-workflow):
- No repo changes without a tracking issue. If none exists, create one first;
if it can't be created, stop.
- Work only in an isolated branch worktree under branches/. The main checkout
is orchestration/status only.
- Do not self-review or self-merge.
Steps:
1. Verify the orchestration checkout is the right repo and clean.
2. git fetch <remote> --prune; confirm local master == <remote>/master (0 0).
3. Create the issue "<title>" (problem, scope, acceptance) and claim it
(status:in-progress + a "starting work" comment naming the branch).
4. scripts/worktree-start <type>/issue-<n>-<slug> # type = fix|feat|docs
cd branches/<type>-issue-<n>-<slug>
5. Implement the narrow scope only; add/update focused tests if behavior changes.
6. Checks: run the test suite, compile/lint changed files, git diff --check,
and scan the diff for secrets.
7. Commit (issue-linked message), push the branch, open a PR to master.
8. Stop before review/merge — you are the author.
Handoff: issue #, branch, worktree path, files changed, checks + results, PR URL.
```
@@ -0,0 +1,28 @@
# Template: clean up after merge
Copy, fill the `<...>` fields, and paste as the task prompt. Only run AFTER a
real merge is confirmed on remote master.
```text
Task: clean up branch/worktree for PR #<pr> / issue #<n> after merge.
Rules (llm-project-workflow):
- Do NOT clean up until the merge is confirmed on <remote>/master.
- Cleanup would-delete-unmerged-work → STOP. Never --force-remove a dirty tree.
Steps:
1. git fetch <remote> --prune
2. Confirm <remote>/master contains the merge of PR #<pr>
(git log <remote>/master | grep the merge, or git branch -r --contains <sha>).
If not merged → STOP; run the recovery template instead.
3. Close issue #<n> if not auto-closed; remove the status:in-progress label.
4. scripts/worktree-clean --delete-branch <type>/issue-<n>-<slug>
(removes branches/<type>-issue-<n>-<slug>; refuses if dirty; git branch -d is
safe-delete only — fails on unmerged.)
5. Delete the remote branch if the merge did not already remove it.
6. From the main checkout: git fetch <remote> --prune; git checkout master;
git reset --hard <remote>/master ONLY if local master safely matches remote.
7. Confirm main checkout clean and current (git status; 0 0 vs <remote>/master).
Handoff: merge confirmed, issue closed, branch+worktree removed, checkout clean.
```