Merge remote-tracking branch 'prgs/master' into feat/issue-434-gated-actions
# Conflicts: # docs/webui-local-dev.md # tests/test_webui_skeleton.py # webui/app.py
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
# Canonical State Comments
|
||||
|
||||
Gitea is the durable system of record for workflow continuation. When a
|
||||
comment changes issue, PR, or discussion state, it should leave enough
|
||||
information for the next role to continue without private chat history.
|
||||
|
||||
Canonical comments answer:
|
||||
|
||||
- what state the object is in
|
||||
- who acts next
|
||||
- what the next actor should do
|
||||
- the exact prompt the next actor should run
|
||||
- which proof, blocker, or dependency matters
|
||||
|
||||
Non-workflow discussion comments do not need this template.
|
||||
|
||||
## Issue State
|
||||
|
||||
Use this when an issue becomes ready, blocked, in progress, PR-open,
|
||||
superseded, merged, or otherwise changes workflow direction.
|
||||
|
||||
```text
|
||||
## Canonical Issue State
|
||||
|
||||
STATE:
|
||||
<ready-for-author | in-progress | blocked | PR-open | needs-review | ready-to-merge | merged | closed | superseded>
|
||||
|
||||
WHO_IS_NEXT:
|
||||
<controller | author | reviewer | merger | reconciler | user>
|
||||
|
||||
NEXT_ACTION:
|
||||
<specific one-sentence action>
|
||||
|
||||
NEXT_PROMPT:
|
||||
<paste-ready prompt for the next role>
|
||||
|
||||
WHAT_HAPPENED:
|
||||
<latest meaningful event>
|
||||
|
||||
WHY:
|
||||
<decision rationale>
|
||||
|
||||
RELATED_DISCUSSION:
|
||||
<link/reference or none>
|
||||
|
||||
RELATED_PRS:
|
||||
- #...
|
||||
|
||||
BRANCH:
|
||||
<branch or none>
|
||||
|
||||
HEAD_SHA:
|
||||
<40-character SHA or none>
|
||||
|
||||
VALIDATION:
|
||||
<tests/proofs or none>
|
||||
|
||||
BLOCKERS:
|
||||
<blocker and unblock condition, or none>
|
||||
|
||||
LAST_UPDATED_BY:
|
||||
<identity/profile/date>
|
||||
```
|
||||
|
||||
## PR State
|
||||
|
||||
Use this when a PR needs review, receives changes requested, is approved,
|
||||
is stale, is superseded, or becomes ready for merge.
|
||||
|
||||
```text
|
||||
## Canonical PR State
|
||||
|
||||
STATE:
|
||||
<needs-review | changes-requested | approved | stale-approval | ready-to-merge | merged | blocked | superseded>
|
||||
|
||||
WHO_IS_NEXT:
|
||||
<controller | author | reviewer | merger | reconciler | user>
|
||||
|
||||
NEXT_ACTION:
|
||||
<specific one-sentence action>
|
||||
|
||||
NEXT_PROMPT:
|
||||
<paste-ready prompt for the next role>
|
||||
|
||||
WHAT_HAPPENED:
|
||||
<latest meaningful event>
|
||||
|
||||
WHY:
|
||||
<decision rationale>
|
||||
|
||||
ISSUE:
|
||||
#...
|
||||
|
||||
BASE:
|
||||
<branch>
|
||||
|
||||
HEAD:
|
||||
<branch>
|
||||
|
||||
HEAD_SHA:
|
||||
<40-character SHA>
|
||||
|
||||
REVIEW_STATUS:
|
||||
<none | approved | changes-requested | stale | contaminated>
|
||||
|
||||
VALIDATION:
|
||||
<tests/proofs>
|
||||
|
||||
BLOCKERS:
|
||||
<blockers or none>
|
||||
|
||||
SUPERSEDES:
|
||||
<PRs or none>
|
||||
|
||||
SUPERSEDED_BY:
|
||||
<PR or none>
|
||||
|
||||
MERGE_READY:
|
||||
<yes/no and why>
|
||||
|
||||
LAST_UPDATED_BY:
|
||||
<identity/profile/date>
|
||||
```
|
||||
|
||||
## Discussion Summary
|
||||
|
||||
Discussions should normally have at least five substantive comments before
|
||||
conversion into issues. A controller may waive that only for tiny mechanical,
|
||||
urgent, or explicitly trivial work.
|
||||
|
||||
```text
|
||||
## Canonical Discussion Summary
|
||||
|
||||
STATE:
|
||||
<needs-more-discussion | ready-for-issues | issues-created | closed>
|
||||
|
||||
WHO_IS_NEXT:
|
||||
<controller | author | reviewer | user>
|
||||
|
||||
DECISION:
|
||||
<what was decided>
|
||||
|
||||
WHY:
|
||||
<reasoning and tradeoffs>
|
||||
|
||||
SUBSTANTIVE_COMMENTS:
|
||||
<count and summary>
|
||||
|
||||
ISSUES_TO_CREATE_OR_CREATED:
|
||||
- #...
|
||||
|
||||
DEPENDENCY_ORDER:
|
||||
<order or none>
|
||||
|
||||
NON_GOALS:
|
||||
<non-goals>
|
||||
|
||||
OPEN_QUESTIONS:
|
||||
<questions or none>
|
||||
|
||||
NEXT_ACTION:
|
||||
<specific one-sentence action>
|
||||
|
||||
NEXT_PROMPT:
|
||||
<paste-ready prompt for the next role>
|
||||
|
||||
LAST_UPDATED_BY:
|
||||
<identity/profile/date>
|
||||
```
|
||||
|
||||
## Validation Rules
|
||||
|
||||
The final-report validator rejects canonical state update claims when the
|
||||
report omits the canonical block or when the block lacks:
|
||||
|
||||
- `STATE`
|
||||
- `WHO_IS_NEXT`
|
||||
- `NEXT_ACTION`
|
||||
- `NEXT_PROMPT`
|
||||
|
||||
It also rejects vague next actions such as `continue`, ready-to-merge states
|
||||
without approval/head-SHA proof, superseded states without canonical item
|
||||
proof, and blocked states without an unblock condition.
|
||||
@@ -0,0 +1,142 @@
|
||||
# Canonical Thread Handoff (CTH)
|
||||
|
||||
**CTH** = **Canonical Thread Handoff**
|
||||
|
||||
A CTH comment is the authoritative workflow handoff in a Gitea issue or PR
|
||||
thread. It records current state, decisions, blockers, proof, and the exact
|
||||
next prompt/action for the next LLM or person.
|
||||
|
||||
CTH comments complement — but do not replace — formal Gitea review state.
|
||||
A CTH may summarize an APPROVE or REQUEST_CHANGES decision, yet merge gates
|
||||
still require the live Gitea review verdict.
|
||||
|
||||
## CTH comment types
|
||||
|
||||
- `CTH: State Handoff`
|
||||
- `CTH: Controller Decision`
|
||||
- `CTH: Author Handoff`
|
||||
- `CTH: Reviewer Handoff`
|
||||
- `CTH: Merger Handoff`
|
||||
- `CTH: Supersession Notice`
|
||||
- `CTH: Blocker`
|
||||
|
||||
## Required base template
|
||||
|
||||
```md
|
||||
## CTH: <Type>
|
||||
|
||||
Status:
|
||||
Next owner:
|
||||
Current blocker:
|
||||
Decision:
|
||||
Proof:
|
||||
Next action:
|
||||
Ready-to-paste prompt:
|
||||
```
|
||||
|
||||
Extended fields may map to canonical issue/PR state templates from #495 when
|
||||
that layer is available. Until then, keep the base fields complete.
|
||||
|
||||
## Discovery and posting rules
|
||||
|
||||
Before acting in an issue or PR thread:
|
||||
|
||||
1. **Find the latest CTH comment** before doing work.
|
||||
2. Treat the **latest valid CTH** as the current handoff state.
|
||||
3. **Post a new CTH** when you finish, block, skip, supersede, request
|
||||
changes, approve, or hand off.
|
||||
4. Do **not** rely on stale non-CTH comments when a newer CTH exists.
|
||||
5. Casual discussion comments do not need to be CTH comments.
|
||||
|
||||
## Examples
|
||||
|
||||
### PR approved and ready for merger
|
||||
|
||||
```md
|
||||
## CTH: Reviewer Handoff
|
||||
|
||||
Status: approved_at_current_head
|
||||
Next owner: merger
|
||||
Current blocker: none
|
||||
Decision: APPROVE recorded at head abc123...
|
||||
Proof: gitea_submit_pr_review performed; visible verdict APPROVE
|
||||
Next action: eligible merger merges PR #N with pinned expected_head_sha
|
||||
Ready-to-paste prompt: Merge PR #N for issue #M if live head still abc123... and merge gates pass.
|
||||
```
|
||||
|
||||
### PR request-changes back to author
|
||||
|
||||
```md
|
||||
## CTH: Reviewer Handoff
|
||||
|
||||
Status: request_changes_at_current_head
|
||||
Next owner: author
|
||||
Current blocker: unresolved findings in validation report
|
||||
Decision: REQUEST_CHANGES at head def456...
|
||||
Proof: gitea_submit_pr_review performed; blocking review visible
|
||||
Next action: author fixes findings and pushes; reviewer re-validates fresh head
|
||||
Ready-to-paste prompt: Fix PR #N review findings, push to feat/issue-M-..., post Author Handoff CTH.
|
||||
```
|
||||
|
||||
### Duplicate / superseded PR closure
|
||||
|
||||
```md
|
||||
## CTH: Supersession Notice
|
||||
|
||||
Status: superseded
|
||||
Next owner: controller
|
||||
Current blocker: duplicate branch/PR work
|
||||
Decision: close PR #N; continue on PR #M
|
||||
Proof: duplicate gate linked open PR #M for issue #K
|
||||
Next action: controller closes superseded PR and records canonical state
|
||||
Ready-to-paste prompt: Close superseded PR #N; confirm PR #M remains canonical for issue #K.
|
||||
```
|
||||
|
||||
### Blocked workflow due to dirty root/worktree
|
||||
|
||||
```md
|
||||
## CTH: Blocker
|
||||
|
||||
Status: blocked_preflight
|
||||
Next owner: operator
|
||||
Current blocker: dirty control checkout / branches worktree mismatch
|
||||
Decision: stop before mutation
|
||||
Proof: verify_preflight_purity failed; workspace diagnostics attached
|
||||
Next action: repair worktree or relaunch MCP from branches/ worktree
|
||||
Ready-to-paste prompt: Repair dirty workspace, relaunch MCP from branches/review-prN, retry review.
|
||||
```
|
||||
|
||||
### Stale head requiring fresh review
|
||||
|
||||
```md
|
||||
## CTH: Reviewer Handoff
|
||||
|
||||
Status: stale_head
|
||||
Next owner: reviewer
|
||||
Current blocker: live head differs from pinned review head
|
||||
Decision: prior approval not valid for current head
|
||||
Proof: expected_head_sha mismatch at merge gate
|
||||
Next action: re-run validation and post fresh review decision
|
||||
Ready-to-paste prompt: Re-validate PR #N at live head, dry-run review gates, submit fresh verdict.
|
||||
```
|
||||
|
||||
### Issue implementation handoff
|
||||
|
||||
```md
|
||||
## CTH: Author Handoff
|
||||
|
||||
Status: implementation_complete_pending_review
|
||||
Next owner: reviewer
|
||||
Current blocker: none
|
||||
Decision: PR #N ready for review at head fedcba...
|
||||
Proof: tests passed in branches/issue-M-...; PR opened with Closes #M
|
||||
Next action: reviewer acquires lease and validates PR #N
|
||||
Ready-to-paste prompt: Review PR #N for issue #M; pin head fedcba... before mutations.
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [`llm-workflow-runbooks.md`](llm-workflow-runbooks.md)
|
||||
- [`../skills/llm-project-workflow/templates/canonical-thread-handoff.md`](../skills/llm-project-workflow/templates/canonical-thread-handoff.md)
|
||||
- #495 — canonical next-action comment fields
|
||||
- #496 — fail-closed validation for workflow-changing comments
|
||||
@@ -0,0 +1,43 @@
|
||||
# Two-comment workflow examples (#507)
|
||||
|
||||
Paired `[CONTROLLER HANDOFF]` + `[THREAD STATE LEDGER]` comments for Gitea threads.
|
||||
See `thread_state_ledger_examples.py` for machine-checked fixtures.
|
||||
|
||||
## Approved review posted
|
||||
|
||||
**Handoff** (detailed): identity, worktree, validation commands, mutation ledger with
|
||||
`gitea_submit_pr_review → APPROVED review posted to Gitea`.
|
||||
|
||||
**Ledger** (concise):
|
||||
|
||||
```markdown
|
||||
[THREAD STATE LEDGER] PR #487 — APPROVED review posted to Gitea
|
||||
|
||||
What is true now:
|
||||
- PR state: open
|
||||
- Server-side decision state: APPROVED review posted to Gitea
|
||||
- Local verdict/state: APPROVE verdict prepared locally
|
||||
|
||||
What is blocked:
|
||||
- Blocker classification: no blocker
|
||||
|
||||
Who/what acts next:
|
||||
- Next actor: merger
|
||||
- Required action: merge on explicit operator command
|
||||
- Do not do: re-post APPROVE
|
||||
```
|
||||
|
||||
## Approve validated locally but blocked before posting
|
||||
|
||||
Ledger must show `no server-side state changed` under server-side decision state and
|
||||
`APPROVE verdict prepared locally` under local verdict/state.
|
||||
|
||||
## Environment / tooling blocker
|
||||
|
||||
Ledger blocker classification: `environment/tooling blocker`. Mutation ledger:
|
||||
`none — no server-side state changed`.
|
||||
|
||||
## Stale head blocker
|
||||
|
||||
Ledger: `approval_at_current_head is false`; classification `stale head`.
|
||||
Do not do: merge with stale approval.
|
||||
@@ -22,9 +22,12 @@ launched with exactly one static execution profile:
|
||||
| Namespace (MCP server name) | Profile (role) | Typical use |
|
||||
|-----------------------------|----------------|-------------|
|
||||
| `gitea-author` | an author profile | implement issues, push branches, open PRs, comment |
|
||||
| `gitea-reviewer` | a reviewer profile | review, approve/request changes, merge |
|
||||
| `gitea-reviewer` | a reviewer profile | review, approve/request changes |
|
||||
| `gitea-merger` | a merger profile | merge PRs after approval and verification |
|
||||
| `gitea-reconciler` | a reconciler profile | close already-landed open PRs after ancestry proof (#304 profile; #310 close tool) |
|
||||
|
||||
Review and merge are separate workflow roles. A reviewer approval is not merge authorization.
|
||||
|
||||
Properties:
|
||||
|
||||
- **One process, one credential.** Each namespace authenticates as exactly
|
||||
@@ -106,6 +109,14 @@ syntax to the client):
|
||||
"GITEA_MCP_CONFIG": "<path-to-profiles.json>",
|
||||
"GITEA_MCP_PROFILE": "<reviewer-profile-name>"
|
||||
}
|
||||
},
|
||||
"gitea-merger": {
|
||||
"command": "<path-to>/venv/bin/python3",
|
||||
"args": ["<path-to>/mcp_server.py"],
|
||||
"env": {
|
||||
"GITEA_MCP_CONFIG": "<path-to-profiles.json>",
|
||||
"GITEA_MCP_PROFILE": "<merger-profile-name>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,7 +311,8 @@ To make Gitea MCP profile activation and runtime identity state explicit, the fo
|
||||
### 2. Dual MCP Namespaces Recommendation
|
||||
For security-sensitive or high-risk tasks, the preferred safety model uses separate, isolated MCP server instances (namespaces/sessions) launched with static profiles:
|
||||
- `gitea-author`: Exposes tools configured with author permissions; cannot perform approvals or merges.
|
||||
- `gitea-reviewer`: Exposes tools configured with reviewer permissions; used for PR reviews and merges.
|
||||
- `gitea-reviewer`: Exposes tools configured with reviewer permissions; used for PR reviews. Review and merge are separate workflow roles. A reviewer approval is not merge authorization.
|
||||
- `gitea-merger`: Exposes tools configured with merger permissions; used for PR merges.
|
||||
This layout maintains physical separation of credentials and prevents privilege escalation within a single session.
|
||||
This is the model accepted in #139; deployment details, rationale, and client
|
||||
setup live in
|
||||
|
||||
+88
-24
@@ -1,34 +1,98 @@
|
||||
# Label Taxonomy
|
||||
|
||||
This document catalogs the issue labels used for MCP workflows, including Jenkins and GlitchTip (observability).
|
||||
This document defines the canonical issue labels used by MCP workflows.
|
||||
|
||||
> **Approval Required:** Do not create or apply new labels in `manage_labels.py` without explicit owner approval of this document.
|
||||
Every issue should carry:
|
||||
|
||||
## Existing Labels
|
||||
- one `type:*` label
|
||||
- one `status:*` label
|
||||
|
||||
* **`jenkins`**
|
||||
* Description: Jenkins integration
|
||||
* Color: `d93f0b`
|
||||
* Use: Used to mark issues, PRs, or tasks that involve the `jenkins-mcp` boundaries, CI/CD designs, or build failures.
|
||||
Discussion-only issues must carry `type:discussion`.
|
||||
|
||||
* **`glitchtip`**
|
||||
* Description: GlitchTip integration
|
||||
* Color: `b60205`
|
||||
* Use: Used to mark issues related to the `glitchtip-mcp` boundary and observability integration.
|
||||
## Issue Type Labels
|
||||
|
||||
## Proposed / Missing Labels
|
||||
| Label | Use |
|
||||
| --- | --- |
|
||||
| `type:bug` | Bug or defect |
|
||||
| `type:feature` | Feature or enhancement |
|
||||
| `type:process` | Process or policy work |
|
||||
| `type:workflow` | Workflow automation or guidance |
|
||||
| `type:guardrail` | Safety gate or guardrail |
|
||||
| `type:docs` | Documentation work |
|
||||
| `type:test` | Tests or test infrastructure |
|
||||
| `type:discussion` | Discussion-only issue |
|
||||
| `type:umbrella` | Umbrella or tracker issue |
|
||||
| `type:cleanup` | Cleanup or hygiene work |
|
||||
|
||||
* **`observability`**
|
||||
* Proposed Description: Observability, metrics, and monitoring tasks
|
||||
* Proposed Color: `5319e7`
|
||||
* Use: Broader than GlitchTip alone; covers logging, metrics, traces, and general observability pipeline improvements.
|
||||
## Workflow Status Labels
|
||||
|
||||
* **`source:glitchtip`**
|
||||
* Proposed Description: Issue filed automatically by GlitchTip orchestration
|
||||
* Proposed Color: `b60205`
|
||||
* Use: Applied automatically by the orchestrator when a GlitchTip error event is converted into a Gitea issue.
|
||||
Only one `status:*` label should be active on an issue at a time. When an issue
|
||||
moves forward, tooling must remove the old `status:*` label and apply the new
|
||||
one.
|
||||
|
||||
* **`status:triage`**
|
||||
* Proposed Description: Issue needs human or orchestrator triage
|
||||
* Proposed Color: `fbca04`
|
||||
* Use: Used for incoming issues (especially automated ones like `source:glitchtip`) that have not yet been evaluated for priority or resolution.
|
||||
| Label | Use |
|
||||
| --- | --- |
|
||||
| `status:triage` | Issue needs triage |
|
||||
| `status:ready` | Issue is ready for work |
|
||||
| `status:claimed` | Issue is claimed |
|
||||
| `status:in-progress` | Issue is being worked on |
|
||||
| `status:blocked` | Issue is blocked |
|
||||
| `status:needs-review` | Issue work needs review |
|
||||
| `status:pr-open` | A linked PR is open |
|
||||
| `status:approved` | Linked PR is approved |
|
||||
| `status:merged` | Linked PR is merged |
|
||||
| `status:reconcile` | Issue needs reconciliation |
|
||||
| `status:done` | Issue workflow is complete |
|
||||
| `status:duplicate` | Issue is a duplicate |
|
||||
| `status:wontfix` | Issue will not be fixed |
|
||||
|
||||
## Transition Rules
|
||||
|
||||
Suggested lifecycle:
|
||||
|
||||
1. New issue created: `status:triage` or `status:ready`
|
||||
2. Issue selected by an author: `status:claimed`
|
||||
3. Author starts work: `status:in-progress`
|
||||
4. Work is blocked: `status:blocked`
|
||||
5. PR opened: `status:pr-open`
|
||||
6. PR approved: `status:approved`
|
||||
7. PR merged but issue still needs closure/reconciliation: `status:reconcile`
|
||||
8. Issue fully complete: `status:done`
|
||||
9. Duplicate issue: `status:duplicate`
|
||||
10. Won't-fix issue: `status:wontfix`
|
||||
|
||||
The helper module `issue_workflow_labels.py` is the source of truth for the
|
||||
canonical label specs and status transition replacement behavior.
|
||||
|
||||
## Discussion Issues
|
||||
|
||||
Discussion issues must be labeled `type:discussion`.
|
||||
|
||||
A discussion issue should not be treated as implementation-ready unless it also
|
||||
has a clear implementation status and next action.
|
||||
|
||||
If a discussion produces implementation work, either:
|
||||
|
||||
1. convert the discussion issue into an implementation issue by changing labels
|
||||
and adding acceptance criteria, or
|
||||
2. create child implementation issues and leave the discussion issue as
|
||||
`type:discussion`.
|
||||
|
||||
## Tooling
|
||||
|
||||
- `manage_labels.py --create-labels` creates the canonical `type:*` and
|
||||
`status:*` labels.
|
||||
- `gitea_create_issue` recommends `type:*` and `status:*` labels when missing
|
||||
and can apply supplied label names.
|
||||
- `gitea_mark_issue(..., action="start")` replaces old `status:*` labels with
|
||||
`status:in-progress`.
|
||||
- `gitea_create_pr` fails closed before PR creation if `status:pr-open` cannot
|
||||
be applied to the locked issue, then applies it after the PR is created.
|
||||
- `gitea_set_issue_labels` accepts an explicit `worktree_path` so author
|
||||
sessions can satisfy the branches-only mutation guard while changing labels.
|
||||
|
||||
## Existing Non-Workflow Labels
|
||||
|
||||
Existing non-workflow labels such as `mcp`, `workflow`, `labels`, `tracker`,
|
||||
`jenkins`, `glitchtip`, `documentation`, and `testing` remain valid topical
|
||||
labels. They do not replace the required `type:*` and `status:*` labels.
|
||||
|
||||
+158
-10
@@ -7,6 +7,11 @@ package of the MCP Control Plane: creating issues, implementing them, opening
|
||||
and reviewing pull requests, merging, and closing out — safely and
|
||||
reproducibly.
|
||||
|
||||
Canonical state comments for durable issue/PR/discussion continuation are
|
||||
documented in [`canonical-state-comments.md`](canonical-state-comments.md).
|
||||
Use them when a workflow-changing comment needs to leave the next actor, next
|
||||
action, and paste-ready prompt in Gitea.
|
||||
|
||||
> 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
|
||||
@@ -28,6 +33,8 @@ audit logging). See [Related documents](#related-documents).
|
||||
> to discover the available project workflows and `mcp_get_skill_guide(<name>)`
|
||||
> for step-by-step instructions. This replaces long pasted operator prompts for
|
||||
> the standard rules; operator prompts still control task-specific scope.
|
||||
>
|
||||
> **BLOCKED + DIAGNOSE (default for any missing required step):** If a required workflow skill, guide, tool, capability, preflight, terminal, worktree binding, profile, or instruction is unavailable or fails, STOP. State BLOCKED. Use the canonical blocker report template (see skills/llm-project-workflow/templates/blocked-diagnose-report.md and the llm-project-workflow/SKILL.md universal rules). Only non-mutating recovery. Report fully. No unsafe fallbacks (temp scripts, direct API, MCP internals, direct imports, in-memory restoration, manual bypasses) unless controller authorizes in the handoff for this case. Missing required steps must fail closed *before* any git or Gitea mutation. Controller prompts and all workflows must reinforce: BLOCKED + DIAGNOSE, then stop.
|
||||
> See issue #129 for the skill registry design.
|
||||
|
||||
Jenkins and GlitchTip workflows use separate MCP servers, not this Gitea MCP
|
||||
@@ -408,6 +415,31 @@ The guard blocks when the **control checkout** (repository root) is:
|
||||
`branches/...` directories are disposable role worktrees; the root checkout is
|
||||
the stable orchestration surface only.
|
||||
|
||||
## Canonical workflow skill names (#551)
|
||||
|
||||
Controller prompts and sessions must load the **same** workflow skill wall
|
||||
regardless of runtime (Claude, Codex, Gemini):
|
||||
|
||||
| Name | Role |
|
||||
|------|------|
|
||||
| `gitea-workflow` | Primary controller / Codex skill name |
|
||||
| `llm-project-workflow` | Portable in-repo package |
|
||||
| `git-pr-workflows` | Legacy alias |
|
||||
|
||||
- Inventory: `mcp_list_project_skills` lists all three.
|
||||
- Preflight: `mcp_check_workflow_skill_preflight` before mutations.
|
||||
- Codex install: `scripts/install-codex-workflow-skill.sh`
|
||||
- Full doc: [`docs/workflow-skill-mount.md`](workflow-skill-mount.md)
|
||||
|
||||
If the skill is missing, stop with BLOCKED + DIAGNOSE — do not mutate.
|
||||
|
||||
## No direct-import mutation path (#558)
|
||||
|
||||
Never `import gitea_mcp_server` or call `gitea_auth.get_auth_header` /
|
||||
keychain fill from a raw shell to bypass MCP preflight.
|
||||
|
||||
Use the official MCP daemon only. See [`docs/mcp-daemon-import-guard.md`](mcp-daemon-import-guard.md).
|
||||
|
||||
## Bootstrap Review Path for self-hosted MCP fixes (#557)
|
||||
|
||||
When a PR fixes Gitea-Tools MCP workflow code that the **live daemon** still
|
||||
@@ -634,19 +666,24 @@ loop and do **not** substitute WebFetch/Playwright/manual base64.
|
||||
- **Profile:** issue-manager or author (any profile allowed to create issues).
|
||||
- **Steps:** create the parent/roadmap issue; create child issues; apply the
|
||||
minimal label set; link children to the parent.
|
||||
- **Labels:** new issues should carry one `type:*` label and one `status:*`
|
||||
label. Discussion-only issues must carry `type:discussion`. See
|
||||
[`label-taxonomy.md`](label-taxonomy.md).
|
||||
- **Prompt:** `Using the issue-manager profile, create issue "<title>" with body
|
||||
<body>, then create child issues for <list> and link them to the parent.`
|
||||
|
||||
### Implement an issue and open a PR
|
||||
|
||||
- **Profile:** author.
|
||||
- **Steps:** claim the issue (`status:in-progress`); create an isolated branch
|
||||
worktree from latest `master` under `branches/` (`feat/issue-<n>-...` /
|
||||
- **Steps:** claim the issue (`status:in-progress`, replacing any old
|
||||
`status:*` label); create an isolated branch worktree from latest `master`
|
||||
under `branches/` (`feat/issue-<n>-...` /
|
||||
`fix/...` / `docs/...`); `cd` into that worktree; implement narrowly; add or
|
||||
update tests if behavior changes; run the full suite; commit with an
|
||||
issue-linked message; open a PR to `master`. **Do not** review or merge your
|
||||
own PR. Include an `LLM Handoff Metadata` block (with `LLM-Agent-SHA`) in
|
||||
the PR body — see [`llm-agent-sha.md`](llm-agent-sha.md).
|
||||
issue-linked message; open a PR to `master`; move the issue to
|
||||
`status:pr-open`. **Do not** review or merge your own PR. Include an
|
||||
`LLM Handoff Metadata` block (with `LLM-Agent-SHA`) in the PR body — see
|
||||
[`llm-agent-sha.md`](llm-agent-sha.md).
|
||||
- **Prompt:** `Use an author profile to implement issue #N and open a PR to
|
||||
master. Do not self-review or self-merge.`
|
||||
|
||||
@@ -687,10 +724,10 @@ loop and do **not** substitute WebFetch/Playwright/manual base64.
|
||||
### Merge a PR
|
||||
|
||||
- **Profile:** merger (allowed to merge; must **not** be the PR author).
|
||||
- **Steps:** confirm eligibility; require explicit confirmation
|
||||
(`MERGE PR <n>`); optionally pin head SHA / changed-file set; merge only when
|
||||
Gitea reports the PR mergeable (branch-protection checks satisfied). No force,
|
||||
no ignore-checks. Verify that remote master contains the merge commit or the expected squashed changes (do not assume a "closed" PR succeeded without verifying the actual landed changes).
|
||||
- **Steps:**
|
||||
- Merger workflow starts only after formal approval at current head. Reviewer workflow ends with review decision and separate merger handoff.
|
||||
- Confirm eligibility; require explicit confirmation (`MERGE PR <n>`); optionally pin head SHA / changed-file set; merge only when Gitea reports the PR mergeable (branch-protection checks satisfied). No force, no ignore-checks. Verify that remote master contains the merge commit or the expected squashed changes (do not assume a "closed" PR succeeded without verifying the actual landed changes).
|
||||
- Review and merge are separate workflow roles. A reviewer approval is not merge authorization.
|
||||
- **Prompt:** `Use any eligible merger profile to merge PR #N if checks pass and
|
||||
it is mergeable. Confirm with "MERGE PR N". Do not force-merge.`
|
||||
|
||||
@@ -779,7 +816,7 @@ an author.
|
||||
|---|---|---|---|---|
|
||||
| Review PR (`review_pr`) | reviewer (e.g. `sysadmin` / `prgs-reviewer`) | read, gated review verdicts | commits, pushes, file edits, author comments, merge without eligibility | active profile is an author profile — stop immediately; do **not** switch to author-side fixes unless the operator explicitly re-tasks |
|
||||
| Address PR change requests (`address_pr_change_requests`) | author (e.g. `jcwalker3` / `prgs-author`) | commit/push fixes to the PR branch, PR comment summarizing fixes | review verdicts, approve, request-changes, merge | active profile lacks branch push |
|
||||
| Merge PR (`merge_pr`) | reviewer/merger | gated merge after eligibility + approval | merging own PR, merging without pinned head match | active profile is an author profile, or any merge gate fails |
|
||||
| Merge PR (`merge_pr`) | merger (e.g. `sysadmin` / `prgs-merger`) | gated merge after eligibility + approval | merging own PR, merging without pinned head match, reviewing PRs | active profile is an author or reviewer-only profile, or any merge gate fails |
|
||||
| Comment on issue discussion (`comment_issue`) | any profile with `gitea.issue.comment` | issue thread comments | review verdicts, closing via comment | permission missing (`gitea.pr.comment` does **not** imply it) |
|
||||
| Comment on PR (`comment_pr`) | any profile with `gitea.pr.comment` | PR thread comments | review verdicts | permission missing |
|
||||
| Author implementation (`create_branch`/`push_branch`/`create_pr`) | author | branch, commit, push, open PR | self-review, self-merge | profile lacks the author permissions |
|
||||
@@ -829,6 +866,27 @@ Never imply full-suite success unless the full-suite command itself passed
|
||||
(`full_suite_passed: true`). A report that hides a failed or skipped check
|
||||
is worse than a failing report.
|
||||
|
||||
## Canonical Thread Handoff (CTH)
|
||||
|
||||
**CTH** = **Canonical Thread Handoff** — the authoritative workflow handoff
|
||||
comment in a Gitea issue or PR thread. See
|
||||
[`canonical-thread-handoff.md`](canonical-thread-handoff.md) for types,
|
||||
templates, and examples.
|
||||
|
||||
Before acting in an issue or PR thread:
|
||||
|
||||
1. **Find the latest CTH comment** before doing work.
|
||||
2. Treat the **latest valid CTH** as the current handoff state.
|
||||
3. **Post a new CTH** when you finish, block, skip, supersede, request
|
||||
changes, approve, or hand off.
|
||||
4. Do **not** rely on stale non-CTH comments when a newer CTH exists.
|
||||
|
||||
A CTH summarizes workflow state for the next session. Formal Gitea review
|
||||
verdicts remain authoritative for merge gates — a CTH is not merge approval
|
||||
by itself.
|
||||
|
||||
Template: [`../skills/llm-project-workflow/templates/canonical-thread-handoff.md`](../skills/llm-project-workflow/templates/canonical-thread-handoff.md)
|
||||
|
||||
## Controller Handoff (required, every task)
|
||||
|
||||
Every task — implementation, review, merge, triage, documentation,
|
||||
@@ -861,6 +919,95 @@ touched release state names the exact tag/commit and why. Design debates
|
||||
belong in **discussion/RFC issues** (e.g. #100 `profiles.json v2`) — comment
|
||||
on the issue, create no branches/PRs, and end the comment with this handoff.
|
||||
|
||||
## Two-comment workflow reporting (#507)
|
||||
|
||||
After meaningful controller/workflow work, post **two separate Gitea comments**
|
||||
(not one combined blob):
|
||||
|
||||
1. **`[CONTROLLER HANDOFF]`** — detailed operational continuation for the
|
||||
next LLM/controller (proof-heavy; may be long).
|
||||
2. **`[THREAD STATE LEDGER]`** — short canonical truth readable in ~30 seconds.
|
||||
|
||||
The ledger must answer: what is true now, what changed, what is blocked,
|
||||
who/what acts next — and must **separate**:
|
||||
|
||||
- local verdict/state
|
||||
- server-side Gitea state
|
||||
- attempted-but-blocked mutations
|
||||
- completed mutations
|
||||
|
||||
Use precise state phrases (`APPROVED review posted to Gitea`,
|
||||
`APPROVE verdict prepared locally`, `merge performed`, `merge not performed`,
|
||||
`no server-side state changed`, `lease attempt blocked`) instead of ambiguous
|
||||
standalone words (`approved`, `merged`, `ready`, `blocked`, `done`).
|
||||
|
||||
The ledger must include a **blocker classification** from:
|
||||
`code blocker`, `test blocker`, `merge conflict`, `stale head`,
|
||||
`permission/capability blocker`, `environment/tooling blocker`,
|
||||
`process/rule blocker`, `queue/lease blocker`,
|
||||
`duplicate/canonicalization blocker`, `no blocker`.
|
||||
|
||||
Templates: [`two-comment-workflow.md`](two-comment-workflow.md).
|
||||
Worked examples: [`examples/two-comment-workflow-examples.md`](examples/two-comment-workflow-examples.md).
|
||||
|
||||
Validation: `thread_state_ledger_validator.py` checks tagged comments at post
|
||||
time (`gitea_create_issue_comment`) and tagged final reports via
|
||||
`assess_final_report_validator`. Legacy `## Controller Handoff` final reports
|
||||
remain valid during transition; the tagged pair is required for new workflow
|
||||
comments.
|
||||
|
||||
Related (do not duplicate): #494/#495 lifecycle state, #501 mutation-ledger
|
||||
consistency, #505 CTH umbrella, #496 workflow comment gate when merged.
|
||||
|
||||
## Canonical comment validation (#496)
|
||||
|
||||
Workflow-changing issue/PR/review comments must carry durable next-action
|
||||
state. Casual discussion is still allowed.
|
||||
|
||||
The MCP server runs `canonical_comment_validator.assess_canonical_comment`
|
||||
**before** posting through:
|
||||
|
||||
- `gitea_create_issue_comment`
|
||||
- `gitea_submit_pr_review` / `gitea_dry_run_pr_review` (non-empty review bodies)
|
||||
- `gitea_reconcile_already_landed_pr` when `post_comment=True`
|
||||
- internal structured comment helpers (machine lease/heartbeat markers stay exempt)
|
||||
|
||||
Detection examples:
|
||||
|
||||
- **Allowed:** `Thanks, I will check this.`
|
||||
- **Rejected:** `Blocked, author should fix.` (workflow trigger without canonical fields)
|
||||
|
||||
When validation fails, the tool returns `canonical_comment_validation` with
|
||||
`allowed: false`, `missing_fields`, `vague_fields`, `correction_message`, and
|
||||
`suggested_template`. **No Gitea API call is made.**
|
||||
|
||||
Minimum workflow comment fields:
|
||||
|
||||
```text
|
||||
STATE:
|
||||
WHO_IS_NEXT:
|
||||
NEXT_ACTION:
|
||||
NEXT_PROMPT:
|
||||
WHY:
|
||||
```
|
||||
|
||||
`WHO_IS_NEXT` must be one of: `controller`, `author`, `reviewer`, `merger`,
|
||||
`reconciler`, `user`.
|
||||
|
||||
Issue comments also require `RELATED_PRS`, `BLOCKERS`, and `VALIDATION` when
|
||||
they mention PR work. PR comments/reviews also require `ISSUE`, `HEAD_SHA`,
|
||||
`REVIEW_STATUS`, `MERGE_READY`, `BLOCKERS`, and `VALIDATION`.
|
||||
|
||||
Special states:
|
||||
|
||||
- `STATE: blocked` — `BLOCKERS` must name an explicit unblock condition.
|
||||
- `STATE: superseded` — requires `CANONICAL_ITEM` and `SUPERSEDED_ITEM`.
|
||||
- `STATE: ready-to-merge` — requires approval proof and head SHA in
|
||||
`HEAD_SHA`, `REVIEW_STATUS`, `MERGE_READY`, or `VALIDATION`.
|
||||
|
||||
Final reports must not claim a comment was posted when
|
||||
`canonical_comment_validation.allowed` is false (#496 AC14).
|
||||
|
||||
## Fail-closed behavior
|
||||
|
||||
Before any mutating action the workflow verifies identity, active profile,
|
||||
@@ -972,6 +1119,7 @@ When posting a Canonical Thread Handoff after a binding blocker:
|
||||
|
||||
## Related documents
|
||||
|
||||
- [`reviewer-handoff-consistency.md`](reviewer-handoff-consistency.md) — reject contradictory reviewer handoffs (#501).
|
||||
- [`issue-acceptance-gate.md`](issue-acceptance-gate.md) — controller issue-acceptance audit after PR merge (#500).
|
||||
- [`../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.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# MCP daemon import and keychain guard (#558)
|
||||
|
||||
## Problem
|
||||
|
||||
During deadlock debugging, agents imported `gitea_mcp_server` / ran credential
|
||||
helpers from a raw shell, bypassing preflight purity and role gates.
|
||||
|
||||
## Rule
|
||||
|
||||
Mutation auth and keychain fill require a **sanctioned MCP daemon** process.
|
||||
|
||||
| Context | Allowed |
|
||||
|---------|---------|
|
||||
| Official MCP entrypoint (`mcp_server.py` / `gitea_mcp_server` `__main__`) sets `GITEA_MCP_SANCTIONED_DAEMON=1` | yes |
|
||||
| pytest | yes |
|
||||
| `GITEA_ALLOW_DIRECT_MCP_IMPORT=1` (operator/tests only) | yes |
|
||||
| bare `python -c 'import gitea_auth; get_auth_header(...)'` | **no** |
|
||||
| keychain fill without daemon | **no** unless `GITEA_ALLOW_KEYCHAIN_CLI=1` |
|
||||
|
||||
## Operator note
|
||||
|
||||
LLM sessions must never set the allow-direct-import or allow-keychain-cli
|
||||
overrides. Those are human-only escape hatches.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Reviewer Handoff Consistency
|
||||
|
||||
Reviewer and final-review controller handoffs must not contradict themselves.
|
||||
A narrative that says a merge happened, a review was blocked, or a terminal
|
||||
mutation budget was consumed must match the mutation ledger fields in the same
|
||||
handoff.
|
||||
|
||||
## What gets validated
|
||||
|
||||
`reviewer_handoff_consistency.assess_reviewer_handoff_consistency()` checks:
|
||||
|
||||
- merge claims appear under `Merge mutations` or `MCP/Gitea mutations`
|
||||
- terminal-mutation-budget claims name the exact prior mutation in the ledger
|
||||
- blocked review submission is not paired with "final decision marked"
|
||||
- reviewer lease acquisition includes a `Review decision`
|
||||
- blocked/rejected mutations include proof fields:
|
||||
- tool called
|
||||
- mutation attempted
|
||||
- mutation rejected
|
||||
- no server-side state changed
|
||||
|
||||
`final_report_validator` applies this as `reviewer.handoff_consistency` on
|
||||
`review_pr` reports and fails closed.
|
||||
|
||||
## Blocked review template
|
||||
|
||||
When `gitea_submit_pr_review` fails closed, use
|
||||
`reviewer_handoff_consistency.render_blocked_review_handoff_template()` or the
|
||||
copy in
|
||||
[`skills/llm-project-workflow/templates/blocked-review-handoff.md`](../skills/llm-project-workflow/templates/blocked-review-handoff.md).
|
||||
|
||||
## Related
|
||||
|
||||
- #331 — file-mutation ledger alignment
|
||||
- #501 — contradictory narrative vs ledger detection
|
||||
@@ -0,0 +1,123 @@
|
||||
# Two-comment workflow: Controller Handoff + Thread State Ledger
|
||||
|
||||
After meaningful controller/workflow work, post **two separate Gitea comments**:
|
||||
|
||||
1. **`[CONTROLLER HANDOFF]`** — detailed operational handoff for the next
|
||||
LLM/controller session (proof-heavy; may be long).
|
||||
2. **`[THREAD STATE LEDGER]`** — short canonical truth readable in ~30 seconds.
|
||||
|
||||
The ledger is the concise source of truth. The handoff is the detailed
|
||||
continuation artifact. This complements CTH (#505) and lifecycle state
|
||||
comments (#494/#495) without replacing them.
|
||||
|
||||
## Controller Handoff template
|
||||
|
||||
```markdown
|
||||
[CONTROLLER HANDOFF] PR #___ / Issue #___ — <short title>
|
||||
|
||||
Purpose:
|
||||
This comment is the operational handoff for the next controller/LLM session.
|
||||
|
||||
Identity/profile:
|
||||
- Active profile:
|
||||
- Authenticated identity:
|
||||
- Role:
|
||||
- Self-review / role-conflict proof:
|
||||
|
||||
Target:
|
||||
- Repo:
|
||||
- Issue:
|
||||
- PR:
|
||||
- Branch:
|
||||
- Pinned head SHA:
|
||||
- Worktree:
|
||||
|
||||
Work performed:
|
||||
- <step 1>
|
||||
- <step 2>
|
||||
|
||||
Files touched or reviewed:
|
||||
- `<file>` — <why it matters>
|
||||
|
||||
Validation:
|
||||
- `<command>` → <result>
|
||||
- Full suite: <result or not run + reason>
|
||||
|
||||
Server-side mutation ledger:
|
||||
- <mutation 1, including tool/action/comment id if available>
|
||||
- Or: none — no server-side state changed
|
||||
|
||||
Local-only changes:
|
||||
- <worktree created, files edited locally, etc.>
|
||||
- Or: none
|
||||
|
||||
Blockers:
|
||||
- <none>
|
||||
- Or: <exact blocker, exact gate, exact reason>
|
||||
|
||||
Controller prompt for next session:
|
||||
```markdown
|
||||
<ready-to-paste prompt>
|
||||
```
|
||||
```
|
||||
|
||||
## Thread State Ledger template
|
||||
|
||||
```markdown
|
||||
[THREAD STATE LEDGER] PR #___ / Issue #___ — <current state in one line>
|
||||
|
||||
What is true now:
|
||||
- PR state:
|
||||
- Issue state:
|
||||
- Current head SHA:
|
||||
- Server-side decision state:
|
||||
- Local verdict/state:
|
||||
- Latest known validation:
|
||||
|
||||
What changed:
|
||||
- <short summary since prior ledger>
|
||||
|
||||
What is blocked:
|
||||
- Blocker classification: <see list below>
|
||||
|
||||
Who/what acts next:
|
||||
- Next actor:
|
||||
- Required action:
|
||||
- Do not do:
|
||||
- Resume from:
|
||||
```
|
||||
|
||||
### Blocker classifications
|
||||
|
||||
- code blocker
|
||||
- test blocker
|
||||
- merge conflict
|
||||
- stale head
|
||||
- permission/capability blocker
|
||||
- environment/tooling blocker
|
||||
- process/rule blocker
|
||||
- queue/lease blocker
|
||||
- duplicate/canonicalization blocker
|
||||
- no blocker
|
||||
|
||||
### Precise state language
|
||||
|
||||
Prefer:
|
||||
|
||||
- `APPROVE verdict prepared locally`
|
||||
- `APPROVED review posted to Gitea`
|
||||
- `REQUEST_CHANGES posted to Gitea`
|
||||
- `merge performed` / `merge not performed`
|
||||
- `lease acquired` / `lease attempt blocked`
|
||||
- `server-side state changed` / `no server-side state changed`
|
||||
|
||||
Avoid ambiguous standalone claims (`approved`, `ready`, `merged`, `blocked`,
|
||||
`done`) without proof and server-side state separation.
|
||||
|
||||
## Validation
|
||||
|
||||
- `thread_state_ledger_validator.py` — comment and final-report checks
|
||||
- `gitea_create_issue_comment` — fail-closed gate on tagged comments
|
||||
- `assess_final_report_validator` — `shared.two_comment_workflow` rule
|
||||
|
||||
Examples: [`examples/two-comment-workflow-examples.md`](examples/two-comment-workflow-examples.md)
|
||||
+27
-5
@@ -45,17 +45,27 @@ Optional environment variables:
|
||||
| `/api/prompts` | JSON prompt export with workflow hashes |
|
||||
| `/runtime` | MCP runtime health and stale detection (#430) |
|
||||
| `/api/runtime` | JSON runtime health export |
|
||||
| `/audit` | Stub — report audit paste (#431) |
|
||||
| `/worktrees` | Stub — hygiene dashboard (#432) |
|
||||
| `/leases` | Stub — lease visibility (#433) |
|
||||
| `/audit` | Report audit paste + validator preview (#431) |
|
||||
| `/api/audit` | JSON validator preview (POST `report_text`, optional `task_kind`) |
|
||||
| `/worktrees` | Worktree hygiene dashboard (#432) |
|
||||
| `/api/worktrees` | JSON worktree scan with classifications and anomalies |
|
||||
| `/actions` | Gated write-action registry — all disabled in MVP (#434) |
|
||||
| `/api/actions` | JSON action registry with capability metadata |
|
||||
| `/api/actions/{id}/preview` | Mutation ledger preview (GET, read-only) |
|
||||
| `/leases` | Lease and collision visibility (#433) |
|
||||
| `/api/leases` | JSON lease/collision export |
|
||||
|
||||
All routes are GET-only except registered POST handlers, which still return
|
||||
`405` with `read-only-mvp` until write paths ship.
|
||||
Most routes are GET-only. POST/PUT/PATCH/DELETE return `405` with
|
||||
`read-only-mvp`, except `/audit` and `/api/audit` which accept POST for
|
||||
local validator preview only (no Gitea mutations, no server-side storage).
|
||||
|
||||
## Report audit (#431)
|
||||
|
||||
Paste an LLM final report at `/audit` or POST JSON to `/api/audit`. The UI
|
||||
reuses `final_report_validator` and review schema checks to surface missing
|
||||
proof fields, wrong validation vocabulary, mutation contradictions, and a
|
||||
suggested next prompt or issue-comment draft. Task kind can be auto-detected
|
||||
or selected explicitly.
|
||||
|
||||
## Project registry (#427)
|
||||
|
||||
@@ -96,6 +106,17 @@ permission, and profile role from `task_capability_map.py` — aligned with
|
||||
`gitea_resolve_task_capability`. Buttons are disabled; previews always render
|
||||
a mutation ledger. Direct `attempt_action` calls fail closed without invoking
|
||||
MCP tools.
|
||||
|
||||
## Worktree hygiene (#432)
|
||||
|
||||
`/worktrees` scans local `branches/` directories and registered git worktrees.
|
||||
Each entry is classified (`active-pr`, `active-issue`, `dirty`, `stale-clean`,
|
||||
`detached-review`, `unsafe-unknown`, `orphan`). Missing preserved worktrees
|
||||
referenced by the issue lock file are flagged as anomalies (#404). The page
|
||||
includes a copy/paste canonical cleanup prompt only — no deletion actions.
|
||||
|
||||
Override scan root with `WEBUI_REPO_ROOT` (defaults to repository root).
|
||||
|
||||
## Lease visibility (#433)
|
||||
|
||||
`/leases` surfaces read-only lease and collision state: local issue lock file,
|
||||
@@ -117,5 +138,6 @@ no tokens or MCP restart actions are exposed.
|
||||
|
||||
```bash
|
||||
pytest tests/test_webui_skeleton.py tests/test_webui_project_registry.py tests/test_webui_prompt_library.py tests/test_webui_queue_dashboard.py tests/test_webui_gated_actions.py -q
|
||||
pytest tests/test_webui_skeleton.py tests/test_webui_project_registry.py tests/test_webui_prompt_library.py tests/test_webui_queue_dashboard.py tests/test_webui_audit.py tests/test_webui_worktree_hygiene.py -q
|
||||
pytest tests/test_webui_skeleton.py tests/test_webui_project_registry.py tests/test_webui_prompt_library.py tests/test_webui_queue_dashboard.py tests/test_webui_lease_visibility.py tests/test_webui_runtime_health.py -q
|
||||
```
|
||||
@@ -16,12 +16,21 @@ bind an authenticated Gitea identity to an allowed operation set.
|
||||
- **Allowed:** branch create/push, PR create, issue comment/create/close, repo commit, read.
|
||||
- **Forbidden:** PR approve, merge, request_changes.
|
||||
|
||||
### Reviewer / merger
|
||||
### Reviewer
|
||||
|
||||
- **Profile:** `prgs-reviewer`
|
||||
- **Typical identity:** `sysadmin`
|
||||
- **Allowed:** PR review/approve/merge/request_changes, issue comment, read.
|
||||
- **Forbidden:** branch push, PR create, repo commit.
|
||||
- **Allowed:** PR review/approve/request_changes, issue comment, read.
|
||||
- **Forbidden:** branch push, PR create, repo commit, PR merge.
|
||||
|
||||
Review and merge are separate workflow roles. A reviewer approval is not merge authorization.
|
||||
|
||||
### Merger
|
||||
|
||||
- **Profile:** `prgs-merger`
|
||||
- **Typical identity:** `sysadmin`
|
||||
- **Allowed:** PR merge, issue comment, read.
|
||||
- **Forbidden:** branch push, PR create, repo commit, PR approve, PR review, PR request_changes.
|
||||
|
||||
## Configuration
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# Workflow skill mount across runtimes (#551)
|
||||
|
||||
## Problem
|
||||
|
||||
Controller prompts require **`gitea-workflow`**, but:
|
||||
|
||||
- Claude may load `~/.claude/skills/gitea-workflow`
|
||||
- Codex often has **no** `~/.codex/skills/gitea-workflow`
|
||||
- The portable package in-repo is `skills/llm-project-workflow`
|
||||
- `mcp_list_project_skills` historically listed operational guides only, not
|
||||
the workflow router
|
||||
|
||||
Sessions then either **block** incorrectly or **proceed without** the workflow
|
||||
wall.
|
||||
|
||||
## Canonical names (must resolve to the same skill)
|
||||
|
||||
| Name | Use |
|
||||
|------|-----|
|
||||
| `gitea-workflow` | **Primary** controller / Codex skill name |
|
||||
| `llm-project-workflow` | Portable in-repo package name |
|
||||
| `git-pr-workflows` | Legacy alias |
|
||||
|
||||
Source of truth: `skills/llm-project-workflow/SKILL.md`
|
||||
In-repo alias stub: `skills/gitea-workflow/SKILL.md`
|
||||
|
||||
## Codex install
|
||||
|
||||
From a `branches/` worktree (or any clone of the repo):
|
||||
|
||||
```bash
|
||||
./scripts/install-codex-workflow-skill.sh
|
||||
# optional:
|
||||
./scripts/install-codex-workflow-skill.sh --dry-run
|
||||
./scripts/install-codex-workflow-skill.sh --skills-dir "$HOME/.codex/skills"
|
||||
```
|
||||
|
||||
This symlinks the portable package under all three names. **Restart Codex**
|
||||
after install.
|
||||
|
||||
## MCP discovery
|
||||
|
||||
- `mcp_list_project_skills` includes `gitea-workflow`, `llm-project-workflow`,
|
||||
and `git-pr-workflows`.
|
||||
- `mcp_get_skill_guide("<name>")` returns the same router steps for each.
|
||||
- `mcp_check_workflow_skill_preflight` proves the in-repo skill file exists and
|
||||
reports Codex mount status.
|
||||
|
||||
## Preflight rule
|
||||
|
||||
Before any git or Gitea mutation:
|
||||
|
||||
1. Call `mcp_check_workflow_skill_preflight`.
|
||||
2. If `blocked` / `workflow_skill_ready` is false → **BLOCKED + DIAGNOSE**; do
|
||||
not mutate.
|
||||
3. Load the skill by **any** canonical name and follow the router.
|
||||
|
||||
Missing Codex mount alone does not block if the in-repo skill is present and
|
||||
loaded via MCP/docs; operators should still install the Codex symlink so
|
||||
prompt names resolve natively.
|
||||
|
||||
## Controller prompts
|
||||
|
||||
Prefer:
|
||||
|
||||
> Invoke skill `gitea-workflow` (alias of `llm-project-workflow`).
|
||||
|
||||
Do not require a name that is only available on one runtime.
|
||||
Reference in New Issue
Block a user