Skip to content
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "claudius",
"version": "5.13.0",
"version": "5.14.0",
"description": "Collection of specialized development agents and skills for Claude Code",
"author": {
"name": "lklimek",
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ Format follows [Keep a Changelog](https://keepachangelog.com/). This project use

## [Unreleased]

## [5.14.0] - 2026-07-21

### Changed

- **PR-body template** (`skills/git-and-github/SKILL.md` §Creating a PR): replaced the "Why this PR exists" skeleton with a plain-language-first structure — `TL;DR` (one sentence) -> `## User story` ("As a **\<role\>**, I want to \<what-to-do\>, to achieve \<user-goal\>.") -> `## Scenario` (`### Base flow` / `### Actual behavior` / `### Expected behavior`) -> `## Detailed discussion` (nests the former `What was done`/`Testing`/`Breaking changes`/`Checklist`/`Attribution` sub-sections, plus problem statement and blocking relationship). The first three sections must stay free of specialized terms and code identifiers — aimed at a technical product manager or external reviewer; `Detailed discussion` is the technical section for implementors and AI agents.
- **Issue-body template** (`skills/git-and-github/SKILL.md` §Issues): unified onto the same `TL;DR` -> `User story` -> `Scenario` -> `Detailed discussion` shape as PRs, replacing the old "feature/enhancement issues need a `### User Story`" bullet. For bug reports, `Scenario` doubles as the reproduction; feature requests with nothing to reproduce may drop it.
- **Both templates externalized**: the literal skeletons moved out of `SKILL.md` prose into `skills/git-and-github/references/pr-body-template.md` and `references/issue-body-template.md`; `SKILL.md` and `references/gh-cli-fallback.md` now link to them instead of inlining a copy (the `gh` CLI fallback now fills in the template file and passes it via `--body-file`); `push/SKILL.md` continues to delegate to `git-and-github` without inlining its own copy. Pinned by `tests/test_pr_body_template.py` and the new `tests/test_issue_body_template.py`.
- Both templates gained a `### Prior work` section (links to possibly related/similar PRs or issues, each with a one-sentence summary of how it relates to the one being filed), placed between `Checklist`/`Detailed discussion` and `Attribution` so the mandatory attribution footer stays the true last section, per Copilot review on #76. Same review flagged the template pointer sentences (`SKILL.md`, `gh-cli-fallback.md`) as ambiguous about copying the whole template file vs. just its fenced skeleton — both templates and all four pointer sentences now say explicitly to copy only the fenced block.

## [5.13.0] - 2026-07-20

### Added
Expand Down
25 changes: 8 additions & 17 deletions skills/git-and-github/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,17 @@ Always ask explicit confirmation before every push, even if the user agreed earl

### Creating a PR

Check for a PR template first. If a template exists, read and fill it in. When applicable, include an informal user story (what the user can achieve, no technical details -- start with "Imagine you are...").
Check for a PR template first. If a template exists, read and fill it in, folding its required content into the skeleton linked below rather than replacing it.

The PR body **must lead with a `## Why this PR exists` section** — reviewers read motivation before mechanics. Use this skeleton (drop empty sections):
The PR body **must lead with a plain-language summary before any implementation detail** — a technical product manager or an external reviewer with no code context must understand everything before `Detailed discussion` at a glance. Copy the skeleton from [pr-body-template.md](references/pr-body-template.md) (the fenced block only, not the page's title or explanatory text) and fill it in.

```markdown
## Why this PR exists
- **Problem**: 1-2 plain-language sentences on what's broken or missing.
- **What breaks without it**: a concrete reproduction or threat scenario — numbered steps or a short narrative showing the actual failure/misbehaviour, not an abstract claim.
- **Blocking relationship**: prerequisite for / depends on / stacked atop PR #N, if any.
**`TL;DR` / `User story` / `Scenario` are user-facing** — plain language only, no specialized terms, no internal implementation details, no code identifiers. Describe strictly user-observable behavior (for an API/CLI, the calling developer *is* the user). `User story` follows the same "As a `<role>`..." shape as the Issues `User story` below, phrased for a change already made. `Scenario` isn't only for bugs: for a new feature, `Actual behavior` is what's missing/impossible today and `Expected behavior` is what becomes possible after this PR — no failure or "actual" bug is required. For a pure internal change with no user-observable effect, drop `User story` and `Scenario` entirely and say so in `Detailed discussion`. Note any blocking relationship (prerequisite for / depends on / stacked atop PR #N) in `Detailed discussion`.

## What was done
## Testing
## Breaking changes
## Checklist
## Attribution
```
**`Detailed discussion` is for implementors and AI agents** — it may get as technical as needed: problem/rationale, code-level specifics, and the sub-sections above.

`Why this PR exists` comes first; the remaining sections follow in that order. Always create PRs as drafts.
`TL;DR` → `User story` → `Scenario` → `Detailed discussion`, in that order. Always create PRs as drafts.

**PR descriptions describe net final state only** — no development history, changelog, or step-by-step iteration/debugging narrative; that belongs in commit messages. Concise final testing/verification results (the `## Testing` section) describe the final state, not history, and are expected.
**PR descriptions describe net final state only** — no development history, changelog, or step-by-step iteration/debugging narrative; that belongs in commit messages. This doesn't conflict with `### Actual behavior`, which describes the pre-existing problem being solved, not the PR's own iteration history. Concise final testing/verification results (the `### Testing` sub-section) describe the final state, not history, and are expected.

### Reviewing a PR

Expand All @@ -86,9 +77,9 @@ See [pr-review.md](references/pr-review.md) for the full procedure: fetching PR

### Issues

Before creating, search existing issues (open + closed) and PRs for duplicates. If found, show to user and ask before proceeding. Check for issue templates. Always append attribution footer.
Before creating, search existing issues (open + closed) and PRs for duplicates. If found, show to user and ask before proceeding. Check for issue templates first; if one exists, fold its required content into the skeleton linked below rather than replacing it.

**Feature/enhancement issues must include a `### User Story` section** -- an informal story describing what the user can achieve (no technical details). Start with "As a **\<persona\>**, I want to ... so that ...". Multiple personas are fine. Place user stories before technical details.
Issue bodies use the same plain-language-first skeleton as PRs (see §Creating a PR for the full rationale). Copy the skeleton from [issue-body-template.md](references/issue-body-template.md) (the fenced block only, not the page's title or explanatory text) and fill it in: `TL;DR` → `User story` → `Scenario` → `Detailed discussion`. `User story` uses the same "As a **\<role\>**, I want to ..., to achieve ..." shape as PRs — multiple personas are fine, repeat the line. Always append the attribution footer last.

## Safety Rules

Expand Down
41 changes: 9 additions & 32 deletions skills/git-and-github/references/gh-cli-fallback.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,12 @@ Check for a PR template first:
git ls-tree HEAD --name-only -r .github/ | grep -i pull_request_template
```

If a template exists, read and fill it in. When applicable, include an informal user story (what the user can achieve, no technical details -- start with "Imagine you are...").
If a template exists, read and fill it in, folding its required content into the linked skeleton below. See the main skill's §Creating a PR for the full rationale (plain language up top, technical detail in `Detailed discussion`).

Always create PRs as drafts:
Fill in the skeleton from [pr-body-template.md](pr-body-template.md) (the fenced block only, not the page's title or explanatory text), save the completed body to a file, then create the PR as a draft, passing the body via `--body-file` (not `--body` — avoids shell-escaping the whole skeleton inline):

```bash
gh pr create --draft --title "<type>: <description>" --body "$(cat <<'EOF'
## Issue being fixed or feature implemented

### User Story

### Details

Closes #<issue-number>

## What was done?

<description of changes>

## How has this been tested?

<testing details>

## Breaking Changes

None

## Checklist

- [x] I have performed a self-review of my own code
- [x] I have added or updated relevant tests
- [x] I have made corresponding changes to the documentation if needed

<sub>🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent</sub>
EOF
)"
gh pr create --draft --title "<type>: <description>" --body-file /path/to/filled-in-pr-body.md
```

## Reviewing a PR
Expand All @@ -69,6 +40,12 @@ Check for issue templates before creating:
git ls-tree HEAD --name-only -r .github/ | grep -i issue_template
```

If none exists, fill in the skeleton from [issue-body-template.md](issue-body-template.md) (the fenced block only, not the page's title or explanatory text; see the main skill's §Issues), save the completed body to a file, then:

```bash
gh issue create --title "<title>" --body-file /path/to/filled-in-issue-body.md
```

## Elevated Permissions (ghsudo) -- Optional Fallback

If you use a **read-only default token** with `gh`, install [ghsudo](https://github.com/lklimek/ghsudo) (`pip install ghsudo`) for write operations. When a `gh` or `git` command fails with HTTP 403 (Forbidden), 404 (Not Found), or "Resource not accessible", re-run it through ghsudo. **Never fork the repository** — forking creates a separate repo and breaks push/PR workflows. GitHub may return 404 instead of 403 for private resources when the token lacks sufficient permissions.
Expand Down
38 changes: 38 additions & 0 deletions skills/git-and-github/references/issue-body-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Issue Body Template

Canonical issue-body skeleton for `git-and-github` §Issues — same plain-language-first
shape as [`pr-body-template.md`](pr-body-template.md). Copy only the contents of the fenced
block below into the issue body — not this page's title or explanatory text. Drop whole
sections or sub-sections that don't apply, keep the section order. `TL;DR` / `User story` /
`Scenario` are plain-language and user-facing; `Detailed discussion` is technical, for
implementors and AI agents.

For a bug report, `Scenario` is the reproduction: `Base flow` gets there, `Actual behavior`
is the bug, `Expected behavior` is the fix target. For a feature request with nothing to
reproduce, drop `Scenario` and describe the gap in `User story` / `Detailed discussion`
instead.

```markdown
**TL;DR:** <one plain-language sentence describing the problem or request>

## User story
As a **<role>**, I want to <what-to-do>, to achieve <user-goal>.

## Scenario
### Base flow
<the ordinary steps that lead to this situation — plain narrative>

### Actual behavior
<what happens today — the bug, gap, or missing capability>

### Expected behavior
<what should happen, or become possible, once this is addressed>

## Detailed discussion
<technical notes, proposed approach, logs, links>

### Prior work
<links to possibly related or similar PRs/issues, each with a one-sentence summary of how it relates to this one; omit if none>

### Attribution
```
37 changes: 37 additions & 0 deletions skills/git-and-github/references/pr-body-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# PR Body Template

Canonical PR-body skeleton for `git-and-github` §Creating a PR. Copy only the contents of
the fenced block below into the PR body — not this page's title or explanatory text. Drop
whole sections or sub-sections that don't apply, keep the section order. `TL;DR` /
`User story` / `Scenario` are plain-language and user-facing; `Detailed discussion` is
technical, for implementors and AI agents.

```markdown
**TL;DR:** <one plain-language sentence describing what this PR does>

## User story
As a **<role>**, I want to <what-to-do>, to achieve <user-goal>.

## Scenario
### Base flow
<the ordinary steps that lead to this situation — plain narrative>

### Actual behavior
<what happens today — the bug, gap, or missing capability>

### Expected behavior
<what should happen, or become possible, after this PR>

## Detailed discussion
### What was done
<description of changes; add `Closes #<issue-number>` here if applicable>

### Testing
### Breaking changes
### Checklist

### Prior work
<links to possibly related or similar PRs/issues, each with a one-sentence summary of how it relates to this one; omit if none>
Comment thread
lklimek marked this conversation as resolved.

### Attribution
```
2 changes: 1 addition & 1 deletion skills/push/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Load `claudius:git-and-github` skill first — all commit, push, PR, and attribu
4. **Push** to remote

5. **PR**
- PR body MUST lead with a "Why this PR exists" section per `git-and-github` §Creating a PR
- PR body MUST follow the TL;DR → User story → Scenario → Detailed discussion skeleton per `git-and-github` §Creating a PR
- If PR exists for this branch: update its title and description to reflect current changes
- If no PR: create a draft PR with summary + test plan per `git-and-github`

Expand Down
86 changes: 86 additions & 0 deletions tests/test_issue_body_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""Regression guard: the canonical issue-body template lives in one external file.

Mirrors `test_pr_body_template.py`: the literal skeleton lives ONLY in
`skills/git-and-github/references/issue-body-template.md`; `git-and-github/SKILL.md`
must reference it (§Issues), not inline a duplicate. Pins the template's heading
set/ordering — same plain-language-first shape as the PR-body template.
"""

from __future__ import annotations

import re
from pathlib import Path

REPO_ROOT = Path(__file__).resolve().parent.parent
GIT_GITHUB = REPO_ROOT / "skills" / "git-and-github" / "SKILL.md"
TEMPLATE = (
REPO_ROOT / "skills" / "git-and-github" / "references" / "issue-body-template.md"
)

USER_STORY = "## User story"
SCENARIO = "## Scenario"
DETAILED = "## Detailed discussion"

SKELETON_HEADINGS = (
"**TL;DR:**",
USER_STORY,
SCENARIO,
"### Base flow",
"### Actual behavior",
"### Expected behavior",
DETAILED,
"### Attribution",
"### Prior work",
)


def test_template_has_required_headings() -> None:
text = TEMPLATE.read_text(encoding="utf-8")
for heading in SKELETON_HEADINGS:
assert heading in text, f"{TEMPLATE}: missing '{heading}'"


def test_template_sections_are_ordered() -> None:
text = TEMPLATE.read_text(encoding="utf-8")
tldr = text.index("**TL;DR:**")
user_story = text.index(USER_STORY)
scenario = text.index(SCENARIO)
base_flow = text.index("### Base flow")
actual = text.index("### Actual behavior")
expected = text.index("### Expected behavior")
detailed = text.index(DETAILED)
attribution = text.index("### Attribution")
prior_work = text.index("### Prior work")
assert tldr < user_story < scenario < detailed, (
f"{TEMPLATE}: sections must appear in order TL;DR -> User story -> Scenario -> Detailed discussion"
)
assert scenario < base_flow < actual < expected < detailed, (
f"{TEMPLATE}: 'Scenario' sub-sections must appear in order "
"Base flow -> Actual behavior -> Expected behavior, before 'Detailed discussion'"
)
assert detailed < prior_work < attribution, (
f"{TEMPLATE}: 'Prior work' must sit between 'Detailed discussion' and 'Attribution'"
)
assert attribution == max(text.index(h) for h in SKELETON_HEADINGS), (
f"{TEMPLATE}: 'Attribution' (the mandatory footer) must be the last section in the skeleton"
)


def test_skill_references_template_without_inlining_it() -> None:
text = GIT_GITHUB.read_text(encoding="utf-8")
assert "references/issue-body-template.md" in text, (
f"{GIT_GITHUB}: §Issues must link to references/issue-body-template.md"
)


def test_skill_issues_section_scoped_to_shared_template() -> None:
"""§Issues should point at the shared skeleton, not restate a bespoke one."""
text = GIT_GITHUB.read_text(encoding="utf-8")
issues_heading = text.index("### Issues")
issues_section = text[issues_heading:]
for heading in SKELETON_HEADINGS:
assert (
re.search(r"^" + re.escape(heading), issues_section, re.MULTILINE) is None
), (
f"{GIT_GITHUB}: §Issues must not inline a duplicate '{heading}' heading — delegate to issue-body-template.md"
)
Loading
Loading