chore: add Claude personas, skills, memory, and project docs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
121
.claude/skills/discuss/SKILL.md
Normal file
121
.claude/skills/discuss/SKILL.md
Normal 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
|
||||
189
.claude/skills/implement/SKILL.md
Normal file
189
.claude/skills/implement/SKILL.md
Normal 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
|
||||
75
.claude/skills/review-issue/SKILL.md
Normal file
75
.claude/skills/review-issue/SKILL.md
Normal 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)
|
||||
74
.claude/skills/review-pr/SKILL.md
Normal file
74
.claude/skills/review-pr/SKILL.md
Normal 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)
|
||||
65
.claude/skills/svelte-code-writer
Normal file
65
.claude/skills/svelte-code-writer
Normal 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
|
||||
121
.claude/skills/transcribe/SKILL.md
Normal file
121
.claude/skills/transcribe/SKILL.md
Normal 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.
|
||||
Reference in New Issue
Block a user