chore: add Claude personas, skills, memory, and project docs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-14 20:22:39 +02:00
parent e4719b9487
commit 3d3d4b8616
26 changed files with 12123 additions and 0 deletions

View File

@@ -0,0 +1,121 @@
---
name: discuss
description: Single-persona interactive discussion of a Gitea issue. The persona reads the issue and all comments, lists open items in their scope, and walks through each with the user. When done, posts the discussion result as a Gitea comment.
---
# Single-Persona Issue Discussion
You will adopt a single persona, read a Gitea issue in full, and have an interactive discussion with the user — working through every open item in that persona's scope. At the end you post the agreed outcomes as a comment on the issue.
## Arguments
The user provides an issue URL and a persona shorthand, e.g.:
`http://heim-nas:3005/marcel/familienarchiv/issues/162 ui`
Parse the URL to extract:
- `owner` — e.g. `marcel`
- `repo` — e.g. `familienarchiv`
- `issue_number` — e.g. `162`
Map the persona shorthand to a file in `.claude/personas/`:
| Shorthand | File |
|---|---|
| `dev` | `developer.md` |
| `arch` | `architect.md` |
| `ui` | `ui_expert.md` |
| `ops` | `devops.md` |
| `qa` or `tester` | `tester.md` |
| `sec` or `security` | `security_expert.md` |
If the shorthand doesn't match any of the above, tell the user the valid options and stop.
---
## Step 1 — Gather Issue Context
Use the Gitea MCP tools in parallel:
1. Full issue (title, body, labels) via `issue_read` with method `get`
2. All existing comments via `issue_read` with method `get_comments`
Read both before proceeding.
---
## Step 2 — Read the Persona
Read the persona file from `.claude/personas/`. Fully internalize their identity, priorities, domain focus, and blind spots as described.
---
## Step 3 — Identify Open Items
As the persona, read the entire issue body and all existing comments. From your domain perspective, build a numbered list of **open items** — questions, risks, gaps, decisions, or ambiguities that you would want to resolve before or during implementation.
An open item is anything the persona would genuinely care about that is either:
- Not answered in the issue or its comments, or
- Answered but in a way that raises follow-up questions from this persona's perspective
Be specific and reference the issue text. Do not repeat observations that are already fully resolved in the comments. Do not produce generic items — each must be grounded in the actual issue content.
**Present this list to the user** in the persona's voice, with a short intro in character. Format:
```
## [Persona emoji + Name] — [Role]
I've read through the issue and comments. Here are the open items I want to work through with you:
1. **[Short title]** — [One-sentence description of the concern or question]
2. **[Short title]** — ...
...
Let's go through them one by one. Ready to start with item 1?
```
Then **stop and wait for the user to respond** before proceeding.
---
## Step 4 — Interactive Discussion
Work through the open items **one at a time**:
1. Present the item in full from the persona's perspective — their concern, why it matters to them, what they want to understand or decide
2. Ask a focused, specific question (not multiple questions at once)
3. Wait for the user's response
4. React as the persona — accept, push back, propose alternatives, or note follow-up implications
5. When the item feels resolved (the user has answered and you've responded), mark it as done and move to the next item
Stay in character throughout. The persona's tone, priorities, and blind spots should be evident in every message.
If the user says "skip", "next", or similar — acknowledge it briefly and move on. Mark the item as skipped (unresolved).
When all items are done, show a brief summary:
- Resolved items (what was agreed or decided)
- Skipped / unresolved items (noted for the comment)
Ask: **"Ready to post the discussion summary to the issue?"**
Wait for explicit confirmation before posting.
---
## Step 5 — Post the Comment
After user confirmation, post a single comment to the issue using the Gitea MCP `issue_write` tool with method `add_comment`.
The comment should:
- Open with the persona header: `## [emoji] [Name] — [Role]` and a one-liner about what this comment captures
- List resolved items with the agreed outcome or decision
- List unresolved / skipped items briefly, noting they were raised but not settled
- Close with a short sentence from the persona about their overall read of the issue
Keep it scannable — bullet points per item, no walls of text.
---
## Step 6 — Report Back
After posting, tell the user:
- The comment was posted (with the Gitea URL if available)
- A one-line summary of the most important thing that came out of the discussion

View File

@@ -0,0 +1,189 @@
---
name: implement
description: Felix Brandt reads a Gitea issue or Pull Request, clarifies ambiguities with the user, presents an implementation plan for approval, then works autonomously using red/green TDD until every task is done and committed.
---
# Implement — Felix Brandt's Issue/PR-Driven TDD Workflow
You are Felix Brandt. Read your full persona from `.claude/personas/developer.md` before doing anything else.
## Argument
The user provides a Gitea issue **or** pull request URL, e.g.:
- Issue: `http://heim-nas:3005/marcel/familienarchiv/issues/162`
- PR: `http://heim-nas:3005/marcel/familienarchiv/pulls/174`
Parse the URL to determine the type (`issues`**issue mode**, `pulls`**PR mode**) and extract:
- `owner` — e.g. `marcel`
- `repo` — e.g. `familienarchiv`
- `number` — e.g. `162` / `174`
---
## Phase 1 — Read Everything
### Issue mode
Use the Gitea MCP tools to collect:
1. The full issue (title, body, labels, milestone, assignees) via `issue_read`
2. Every comment on the issue in order — read them all, do not skip any
### PR mode
Use the Gitea MCP tools to collect:
1. PR metadata (title, description, base branch, head branch) via `pull_request_read`
2. Every review comment and inline code comment on the PR — read them all, do not skip any
3. The full content of every changed file (read each file at the head branch using `get_file_contents`)
**In PR mode your job is to address the team's open concerns, not to invent new work.**
Build a complete list of every reviewer concern that has not yet been resolved:
- Blockers (reviewer requested changes)
- Suggestions the author acknowledged or agreed to
- Unanswered questions in the review thread
Mark each concern with its source: reviewer name + comment excerpt.
### Both modes
Also read:
- `CLAUDE.md` for project conventions
- Any relevant existing source files mentioned in the issue/comments
- The current branch state (`git status`, `git log --oneline -10`)
Do not start Phase 2 until you have read everything.
---
## Phase 2 — Clarification
### Issue mode
After reading, identify every point that is genuinely ambiguous or underspecified — things you cannot safely decide unilaterally:
- Scope questions (is X in or out of this issue?)
- Design decisions with multiple valid approaches where the choice affects architecture
- Missing acceptance criteria (how do we know when this is done?)
- Conflicting statements between the issue body and the comments
- Dependencies on external things (backend changes needed? migration required?)
### PR mode
For each open reviewer concern where **no clear fix path exists**, present it to the user and ask how to resolve it. Be specific — quote the reviewer comment and explain why the fix isn't obvious. Do **not** ask about concerns that have a clear, unambiguous fix.
---
Present all your clarifying questions to the user as a numbered list in a single message. Reference the exact passage you're asking about.
**Do not ask about things you can decide yourself** using the project conventions, existing code patterns, or common sense. Only ask when the answer genuinely changes what you build.
Wait for the user to answer before continuing.
---
## Phase 3 — Implementation Plan
Once clarifications are resolved, present a numbered implementation plan as a task list. Each item must be:
- A single atomic unit of work (one behavior, one file change, one migration)
- Written as a sentence that implies the test name: "Tag detail page returns 404 when tag does not exist"
- Ordered so each item builds on the previous ones
- Prefixed with the layer: `[backend]`, `[frontend]`, `[migration]`, `[test]`, `[refactor]`
**In PR mode**, each task must reference the reviewer concern it addresses, e.g.:
```
3. [frontend] Extract magic number 42 into named constant MAX_RESULTS — fixes @anna: "avoid magic numbers"
```
Format:
```
## Implementation Plan
1. [backend] PersonController returns 404 when person id does not exist
2. [migration] Add index on documents.sender_id for performance
3. [frontend] PersonCard renders full name from firstName + lastName props
4. [frontend] PersonCard shows placeholder when both names are null
...
```
End with:
```
Does this plan look right? Reply **approved** to start, or tell me what to change.
```
**Do not write a single line of code until the user approves the plan.**
---
## Phase 4 — Autonomous Implementation
Once the user approves (any message clearly indicating agreement — "approved", "yes", "go ahead", "looks good", etc.), work through every item in the plan **without stopping to ask for permission**.
### Branch setup
Check the current branch.
- **Issue mode**: If already on a feature branch for this issue, stay there. Otherwise create:
```
git checkout -b feat/issue-{number}-{short-slug}
```
- **PR mode**: Check out the PR's head branch and stay on it. All fixes go on that same branch.
### For each task — red/green/refactor
**Red:**
1. Write a failing test for exactly this one behavior
2. Run the test suite
3. Confirm the new test fails with a clear assertion failure (not a compile error or NPE)
4. If the failure message is unclear, fix the test first before proceeding
**Green:**
1. Write the minimum code to make the failing test pass — nothing more
2. Run the full test suite (not just the new test)
3. All tests must be green before committing
**Refactor:**
1. Check for naming, duplication, function size violations
2. Apply any needed clean-up — no new behavior
3. Run the full suite again to confirm still green
**Commit:**
Commit atomically after each task using the project's commit conventions:
```
feat(scope): short imperative description
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
```
Move to the next task immediately.
### Test commands
- Frontend unit tests: `cd frontend && npm run test`
- Frontend type check: `cd frontend && npm run check`
- Backend tests: `cd backend && ./mvnw test`
- Single backend test class: `cd backend && ./mvnw test -Dtest=ClassName`
### Rules during autonomous implementation
- Never skip the red step — if you cannot write a failing test for a task, stop and explain why to the user before writing any implementation code
- Never add behavior beyond what the current task requires
- Never bundle two tasks into one commit
- If a test that was passing starts failing during a later task, fix it before continuing — do not leave broken tests
- If you hit a genuine blocker (missing API, infrastructure not available, etc.) that prevents completing a task, stop and report it to the user rather than working around it silently
---
## Phase 5 — Completion Report
After all tasks are done:
1. Run the full test suite one final time and confirm all green
2. Run `npm run check` (frontend) and `./mvnw clean package -DskipTests` (backend) to confirm no type or build errors
### Issue mode
3. Post a completion comment on the Gitea issue summarising what was implemented, listing all commits made
4. Report back to the user: every task ✅, any skipped/deferred tasks (with reason), the branch name, next suggested action (open PR, run `/review-pr`, etc.)
### PR mode
3. Push the updated branch
4. Post a comment on the PR summarising every concern that was addressed, referencing the relevant commits
5. Report back to the user: every concern resolved ✅, any concerns deferred (with reason), and the push status

View File

@@ -0,0 +1,75 @@
---
name: review-issue
description: Multi-persona feature issue review. Each persona from .claude/personas/ reads the issue and posts constructive feedback as a separate Gitea comment.
---
# Multi-Persona Feature Issue Review
You will perform a thorough multi-persona review of the given Gitea issue URL and post each persona's constructive feedback as a **separate comment** on the issue.
Personas give **advisory input only** — no blocking, no verdicts. The goal is to surface blind spots, risks, and improvement ideas before implementation starts.
## Argument
The user provides a Gitea issue URL, e.g.:
`http://heim-nas:3005/marcel/familienarchiv/issues/161`
Parse it to extract:
- `owner` — e.g. `marcel`
- `repo` — e.g. `familienarchiv`
- `issue_number` — e.g. `161`
## Step 1 — Gather Issue Context
Use the Gitea MCP tools to collect:
1. The full issue (title, body, labels, milestone, assignees) via `issue_read`
2. All existing comments on the issue via `issue_read` — read them so personas don't repeat what's already been said
Read everything before starting any review.
## Step 2 — Read Every Persona
Read all six persona files from `.claude/personas/`:
- `developer.md` → Felix Brandt
- `architect.md` → architect persona
- `tester.md` → tester persona
- `security_expert.md` → security persona
- `ui_expert.md` → UI/UX persona
- `devops.md` → DevOps persona
## Step 3 — Write Each Review
For each persona, fully adopt their identity, priorities, and thinking style as described in their persona file. Write feedback that:
- Is **constructive and forward-looking** — no blockers, no verdicts, no approval stamps
- Asks clarifying questions the persona would genuinely want answered before or during implementation
- Points out risks, edge cases, or gaps the persona sees from their domain
- Offers concrete suggestions or alternative approaches where relevant
- References the issue text specifically — don't write generic advice
- Stays focused on what the persona would actually care about (e.g. Felix asks about test strategy and naming; the architect asks about layer boundaries and coupling; the security expert asks about auth, input validation, and data exposure; the tester asks about acceptance criteria and edge cases; the UI expert asks about interaction patterns and accessibility; DevOps asks about deployment, config, and observability)
Format each comment in Markdown with a persona header, e.g.:
```
## 👨‍💻 Felix Brandt — Senior Fullstack Developer
### Questions & Observations
...
### Suggestions
...
```
Keep each comment focused and scannable. Use bullet points. Avoid walls of text.
## Step 4 — Post Comments
Post each persona's feedback as a **separate comment** on the issue using the Gitea MCP `issue_write` tool.
Post all six comments. If a persona genuinely has nothing to add (rare), write a short "No concerns from my angle" with one sentence explaining what they checked — so the team knows that perspective was considered.
## Step 5 — Report Back
After all comments are posted, tell the user:
- Which personas posted feedback
- A brief summary of the most important cross-cutting themes (questions or risks that multiple personas flagged)

View File

@@ -0,0 +1,74 @@
---
name: review-pr
description: Multi-persona PR review. Each persona from .claude/personas/ reviews the PR and posts their findings as a separate Gitea comment.
---
# Multi-Persona PR Review
You will perform a thorough multi-persona code review of the given PR URL and post each persona's findings as a **separate comment** on the PR.
## Argument
The user provides a Gitea PR URL, e.g.:
`http://heim-nas:3005/marcel/familienarchiv/pulls/160`
Parse it to extract:
- `owner` — e.g. `marcel`
- `repo` — e.g. `familienarchiv`
- `pull_number` — e.g. `160`
## Step 1 — Gather PR Context
Use the Gitea MCP tools to collect:
1. PR metadata (title, description, base branch, head branch) via `pull_request_read`
2. The list of changed files via `get_dir_contents` or the PR files endpoint
3. The full diff / file contents of every changed file — read each file at the head commit using `get_file_contents`
Read ALL changed files completely before starting any review. Do not skip files.
## Step 2 — Read Every Persona
Read all six persona files from `.claude/personas/`:
- `developer.md` → Felix Brandt
- `architect.md` → architect persona
- `tester.md` → tester persona
- `security_expert.md` → security persona
- `ui_expert.md` → UI/UX persona
- `devops.md` → DevOps persona
## Step 3 — Write Each Review
For each persona, fully adopt their identity, priorities, and review lens as described in their persona file. Write a review that:
- Opens with a one-line verdict: **✅ Approved**, **⚠️ Approved with concerns**, or **🚫 Changes requested**
- Lists concrete findings with file paths and line references where relevant
- Distinguishes blockers (must fix) from suggestions (nice to have)
- Uses the persona's voice and priorities (e.g. Felix cares about TDD and clean code; the security expert checks for injection, auth, and data exposure; the architect checks layer boundaries and coupling)
- Stays focused — only comment on what the persona would actually care about
Format each comment in Markdown with a persona header, e.g.:
```
## 👨‍💻 Felix Brandt — Senior Fullstack Developer
**Verdict: ⚠️ Approved with concerns**
### Blockers
...
### Suggestions
...
```
## Step 4 — Post Comments
Post each persona's review as a **separate comment** on the PR using the Gitea MCP `issue_write` tool (issues and PRs share the comment API in Gitea).
Post all six comments. Do not skip any persona even if their domain has nothing to flag — in that case write a brief "LGTM" with a short explanation of what they checked.
## Step 5 — Report Back
After all comments are posted, summarize to the user:
- Which personas posted comments
- The overall verdict across all personas (worst-case wins: if any said "Changes requested", the overall is "Changes requested")
- A bullet list of the top blockers found (if any)

View File

@@ -0,0 +1,65 @@
---
name: svelte-code-writer
description: Write svelte code using best practices and common good patterns. Avoid anti patterns.
---
# Svelte 5 Code Writer
## CLI Tools
You have access to `@sveltejs/mcp` CLI for Svelte-specific assistance. Use these commands via `npx`:
### List Documentation Sections
```bash
npx @sveltejs/mcp list-sections
```
Lists all available Svelte 5 and SvelteKit documentation sections with titles and paths.
### Get Documentation
```bash
npx @sveltejs/mcp get-documentation "<section1>,<section2>,..."
```
Retrieves full documentation for specified sections. Use after `list-sections` to fetch relevant docs.
**Example:**
```bash
npx @sveltejs/mcp get-documentation "$state,$derived,$effect"
```
### Svelte Autofixer
```bash
npx @sveltejs/mcp svelte-autofixer "<code_or_path>" [options]
```
Analyzes Svelte code and suggests fixes for common issues.
**Options:**
- `--async` - Enable async Svelte mode (default: false)
- `--svelte-version` - Target version: 4 or 5 (default: 5)
**Examples:**
```bash
# Analyze inline code (escape $ as \$)
npx @sveltejs/mcp svelte-autofixer '<script>let count = \$state(0);</script>'
# Analyze a file
npx @sveltejs/mcp svelte-autofixer ./src/lib/Component.svelte
# Target Svelte 4
npx @sveltejs/mcp svelte-autofixer ./Component.svelte --svelte-version 4
```
**Important:** When passing code with runes (`$state`, `$derived`, etc.) via the terminal, escape the `$` character as `\$` to prevent shell variable substitution.
## Workflow
1. **Uncertain about syntax?** Run `list-sections` then `get-documentation` for relevant topics
2. **Reviewing/debugging?** Run `svelte-autofixer` on the code to detect issues
3. **Always validate** - Run `svelte-autofixer` before finalizing any Svelte component

View File

@@ -0,0 +1,121 @@
---
name: transcribe
description: Transcribe a document's PDF by visually analyzing each page, creating annotation-backed transcription blocks via the API with paragraph-level bounding boxes and OCR text.
---
# Transcribe — PDF-to-Transcription-Blocks Workflow
## Argument
The user provides:
1. A **document URL**, e.g. `http://localhost:5173/documents/{id}` — extract the document UUID from the path.
2. A **PDF file path**, e.g. `@import/C-1654.pdf` — the source file to read and transcribe.
---
## Phase 1 — Gather Context
1. **Read the PDF** using the Read tool to get the visual content of every page.
2. **Check the API** — the transcription blocks endpoint is:
```
POST /api/documents/{documentId}/transcription-blocks
```
with Basic Auth (`admin:admin123`) and JSON body:
```json
{
"pageNumber": <1-based>,
"x": <0-1 normalized>,
"y": <0-1 normalized>,
"width": <0-1 normalized>,
"height": <0-1 normalized>,
"text": "transcribed text",
"label": "optional label or null"
}
```
3. **Check for existing blocks** — `GET /api/documents/{documentId}/transcription-blocks`. If blocks already exist, ask the user whether to delete them first or abort. Do not silently overwrite.
### Coordinate system
- All coordinates are **normalized 0-1 fractions** of page width and height.
- `x`, `y` is the **top-left corner** of the annotation rectangle.
- Page numbers are **1-based** (page 1 = 1, page 2 = 2).
---
## Phase 2 — Visual Analysis & Segmentation
For each page of the PDF:
1. **Identify the script type**: typewritten, Kurrent/Sutterlin, Latin handwriting, mixed, printed, etc.
2. **Segment into logical blocks** — each block is one visual paragraph or logical section:
- Header / letterhead / date line
- Salutation / greeting
- Body paragraphs (split at natural paragraph breaks)
- Closing / signature
- Address fields (postcards)
- Margin notes, annotations, stamps
- Rotated text sections (note the rotation in the label)
3. **Estimate bounding boxes** for each block as normalized 0-1 coordinates. The rectangle should tightly enclose all the text in that block with a small margin.
4. **Assign labels** to structural blocks:
- `Briefkopf` — letterhead / header with date and location
- `Anrede` — salutation line
- `Gruss` — closing and signature
- `Adresse` — address field (postcards)
- `Fortsetzung (gedreht)` — rotated continuation text
- `null` — regular body paragraphs (no label needed)
---
## Phase 3 — Transcription
For each identified block, transcribe the text:
### Rules
- **Never guess**. If a word or passage is not clearly readable, use `[unleserlich]` as a placeholder.
- Preserve the original spelling, punctuation, and line breaks where they indicate structure (e.g. address lines, signature blocks). Do not "correct" old German spelling.
- For typewritten text with handwritten corrections/additions above or below the line, note them inline, e.g. `statt [unleserlich]` or describe in brackets: `[handschriftliche Erganzung: ...]`.
- For Kurrent/Sutterlin script: be especially conservative. It is better to mark something `[unleserlich]` than to guess incorrectly. If an entire block is unreadable, use: `[unleserlich - Kurrentschrift, kurze Beschreibung des Inhaltsbereichs]`.
- For rotated text, note the rotation in the label field.
- Use `\n` for line breaks within a block (e.g. multi-line addresses, signature blocks).
### Script-specific guidance
| Script | Confidence threshold | Notes |
|--------|---------------------|-------|
| Typewritten (Schreibmaschine) | High — most words should be readable | Watch for corrections, strikethroughs, carbon copy artifacts |
| Latin handwriting | Medium — depends on hand | Easier than Kurrent but still variable |
| Kurrent / Sutterlin | Low — expect heavy `[unleserlich]` usage | Angular strokes, long-s, distinctive letter forms. Context helps (dates, place names, salutations are easier) |
| Mixed | Per-section | Common on postcards: Latin address + Kurrent message |
---
## Phase 4 — Create Blocks via API
1. **Delete existing blocks** if user approved it in Phase 1.
2. **Create blocks in reading order** using `curl` with Basic Auth:
```bash
curl -s -u admin:admin123 -X POST \
"http://localhost:8080/api/documents/${DOC_ID}/transcription-blocks" \
-H "Content-Type: application/json" \
-d '{ "pageNumber": 1, "x": 0.03, "y": 0.02, "width": 0.94, "height": 0.07, "text": "...", "label": "Briefkopf" }'
```
3. Create blocks **page by page, top to bottom**. The API auto-assigns `sortOrder` incrementally.
4. Verify each response returns a valid block ID.
---
## Phase 5 — Summary
After all blocks are created, present a table:
| # | Page | Label | Readability | Content (truncated) |
|---|------|-------|-------------|---------------------|
Where readability is one of:
- **Klar** — fully readable, no `[unleserlich]` markers
- **Teilweise** — some `[unleserlich]` markers, majority readable
- **Schwer** — heavy `[unleserlich]` usage, only fragments readable
- **Unleserlich** — entire block could not be transcribed
End with a note about the overall script type and any sections that would benefit from expert review.