Add weekly-review skill and project guide
Add .claude/skills/weekly-review: a Claude Code skill that builds the weekly timesheet review (narrative summary, reviews split out, loose ends) and writes it into the Joplin week note, plus a distill/refine pass over the status/distill and status/refine knowledge queue. Also track CLAUDE.md, the project/agent guide. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8f5232d1fe
commit
c50bd49b4a
2 changed files with 353 additions and 0 deletions
352
.claude/skills/weekly-review/SKILL.md
Normal file
352
.claude/skills/weekly-review/SKILL.md
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
---
|
||||
name: weekly-review
|
||||
description: >-
|
||||
Generate a weekly timesheet review (narrative summary + loose ends) from the
|
||||
Joplin week note and write it into that note's Review section, and process the
|
||||
knowledge queue (notes tagged status/distill and status/refine). Use when the
|
||||
user asks for a weekly review, a week recap, to "review my week", to fill in
|
||||
the Review section of a timesheet week note, or to "process distill/refine
|
||||
tags", "distill my notes", or "clear the knowledge queue". Optionally takes a
|
||||
date or week to target a week other than the current one.
|
||||
---
|
||||
|
||||
# Weekly timesheet review
|
||||
|
||||
Build a review of one week of timesheets and write it into the Review section
|
||||
of the corresponding Joplin week note. The point is that reading it tells you
|
||||
what the week was about. The review has these parts: a narrative **Summary** of
|
||||
the work done, a short **Reviews** section for work that was only reviewed (not
|
||||
the user's own tickets), and a **Loose ends** section for carry-over.
|
||||
|
||||
Altitude matters: explain what happened and the conclusions, not the precise
|
||||
technical detail. The user has explicitly trimmed hard metrics, config values,
|
||||
and internal symbol names out of the summary (the story-log notes already hold
|
||||
those). Aim for "I can read this and immediately know what the week was about",
|
||||
not a technical report. See the Voice section.
|
||||
|
||||
The full weekly ritual has **two parts**:
|
||||
|
||||
1. **Part 1 — Week review**: build the Summary / Reviews / Loose ends and write
|
||||
it into the week note (steps below).
|
||||
2. **Part 2 — Distill & refine**: process the knowledge queue, i.e. notes tagged
|
||||
`status/distill` and `status/refine` (at the end of this file).
|
||||
|
||||
Part 2 is **independent of the week** chosen in Part 1: the tags are a standing
|
||||
queue, not week-scoped. It can be run on its own. Do both parts when running a
|
||||
full weekly review unless the user only asked for one.
|
||||
|
||||
Read `README.md` and `CLAUDE.md` first if you are not already familiar with the
|
||||
project. The timesheet structure, table format, and Joplin notebook layout are
|
||||
described there.
|
||||
|
||||
## Inputs
|
||||
|
||||
- Optional target week. Accept a date (`2026-05-29`, `yesterday`, `last week`)
|
||||
or an ISO week. Default to the current week (today's date).
|
||||
- The CLI reads timesheets from Joplin with `--joplin`. Config (token, project
|
||||
map) is already set up; do not ask for it.
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Resolve the target week and locate the note
|
||||
|
||||
- Determine the target date. Default to today.
|
||||
- Get the structured data straight from the CLI (it resolves the week itself):
|
||||
|
||||
```sh
|
||||
uv run timesheets stories -w --joplin <date> # themes + per-story time
|
||||
uv run timesheets summary -w -ss --joplin <date> # per-day totals + week total
|
||||
```
|
||||
|
||||
`<date>` is optional; omit it for the current week. The `stories` output is
|
||||
the **source of truth** for the `## Stories` block; do not re-derive it by
|
||||
hand.
|
||||
- Find the Joplin note to write into. Week notes are titled `YYYY - WNN` in
|
||||
`Work / Timesheets / YYYY`. Compute the ISO year and week from the target
|
||||
date, then:
|
||||
|
||||
```
|
||||
find_notes_in_notebook("Work/Timesheets/<year>")
|
||||
```
|
||||
|
||||
Match the title `YYYY - WNN` and keep its `note_id`.
|
||||
|
||||
### 2. Read context
|
||||
|
||||
- `get_note(note_id, force_full=true)` for the target week. From it, collect:
|
||||
- Free-text notes under each day (often Dutch; that is fine).
|
||||
- Checklist items: `- [ ]` (open) and `- [x]` (done).
|
||||
- The `Note` column of each table row. This is NOT a personal scratchpad: it
|
||||
is part of the timesheet and gets pushed to the timesheet system (Odoo) as
|
||||
the entry description. The user uses it to section off parts of a longer
|
||||
ticket ("fix tests", "respond to comments", "rebase", "review"). Read it for
|
||||
the *what/why* of each entry, but never suggest the user put extra detail
|
||||
there. Richer per-ticket detail belongs in the story-log notes, not here.
|
||||
- **`review` as the note marks reviewed work, not the user's own work.** An
|
||||
entry whose note is "review" means the user was reviewing someone else's MR
|
||||
on that ticket, not building the ticket themselves. These are handled
|
||||
separately (see step 3, Reviews). Treat the literal note "review" as the
|
||||
signal.
|
||||
- **Read the linked story notes.** The week note contains Joplin links of the
|
||||
form `[label](:/<note_id>)` in the Story column, the Note column, and the
|
||||
free text. Extract every `(:/<32-hex-id>)` link, dedupe the ids, and
|
||||
`get_note(id, force_full=true)` each one **before** writing the Summary.
|
||||
- **Find story notes that are not linked in the timesheet.** Not every ticket is
|
||||
linked inline, but a note may still exist. For each PBI/Bug worked on this
|
||||
week, look for its backing note in `Work / Story Logs` (and
|
||||
`Work / Story Logs / Archive / <year>`): list the notebook and/or
|
||||
`find_notes("<ticket-number> <few title words>")`, and match by ticket number.
|
||||
Build a map of `ticket -> note_id` for every story that has a note. Read the
|
||||
ones with real content. Note titles follow `PBI <num>: <title>` /
|
||||
`Bug <num>: <title>`, or a descriptive title for research notes
|
||||
(e.g. "Recticel profiling research"). Many notes are near-empty section
|
||||
templates; link them but do not mine them for narrative.
|
||||
|
||||
Story-log notes carry the substance (Context / Investigation / Decision /
|
||||
Solution / Learnings, or research findings). The narrative should draw on
|
||||
that, not just the one-line story titles.
|
||||
- Read the **previous one or two** week notes the same way (the next-lower
|
||||
`WNN`). You need them only to detect carry-over in step 4.
|
||||
|
||||
### 3. Write the narrative Summary (and split out Reviews)
|
||||
|
||||
**First, separate reviewed work from own work.** Go through the raw rows and
|
||||
classify each story:
|
||||
|
||||
- A story is **reviewed work** if all its entries that week have the note
|
||||
"review" (the user only checked someone else's MR, did not build it).
|
||||
- Everything else is **own work**.
|
||||
|
||||
Own work goes in the Summary. Reviewed-only work goes in a separate, short
|
||||
`## Reviews` section (see step 5). Do not mix the two: the user does not count
|
||||
reviewing someone else's MR as part of their own work done. A story with a mix
|
||||
of real work and review entries stays own work.
|
||||
|
||||
Then write the Summary:
|
||||
|
||||
- Group own work by the project/task labels that `stories` produced (these are
|
||||
the themes). Lead with the themes that took the most time.
|
||||
- For each significant theme, write a few plain sentences on what happened that
|
||||
week and where it landed. Convey the gist, not the precise detail (no exact
|
||||
percentages, config values, or internal symbol names; the story-log note holds
|
||||
those). Someone reading it should know what the week was about.
|
||||
- Call out the shape of the week where it is real: a dominant feature, a heavy
|
||||
bug-fixing stretch, lots of context switching, an interruption (incoming
|
||||
requests, customer work like Recticel), or a spike/research day.
|
||||
- **Mention noteworthy meetings explicitly.** The daily standup and Factry Flow
|
||||
are routine, fold them into a brief catch-all line at most. Every *other*
|
||||
meeting is often noteworthy and should be named: brainstorms (e.g. Historian
|
||||
BrAInStorm, AI-usecases), sprint retros, growth-path sessions, customer or
|
||||
technical meetings (e.g. the Recticel stress-test meeting). Identify these
|
||||
from `internal`, `product`, `incoming`, customer projects, and the `Note`
|
||||
column ("brainstorm", "meeting", "retro", "Growth Path", etc.). Say what the
|
||||
meeting was about if the notes make it clear.
|
||||
- Mention the week total and anything notable about it (e.g. leave days, a short
|
||||
or long week) using the `summary` output.
|
||||
|
||||
#### Voice — write it in the user's polished English
|
||||
|
||||
The review is the user's own log, written for themselves, so it can sit a notch
|
||||
looser than a doc meant for others. But it must be **clean English in the user's
|
||||
polished voice**, not the rough Dutch/English mix they use while drafting
|
||||
timesheet free-text. The reference for the target voice is their knowledge notes
|
||||
(e.g. the "Express Guide" OpenTelemetry note); the self-notes (e.g. the looser
|
||||
"OpenTelemetry" note) show the acceptable looser end.
|
||||
|
||||
Their polished style:
|
||||
|
||||
- **English, full sentences, normal capitalization.** No Dutch. No
|
||||
lowercase-everything. No `gwn`/`da`/`ge`/`et`.
|
||||
- **Direct, at the right altitude.** Active voice. Explain plainly what
|
||||
happened and the conclusion ("ArgoCD is gitops CICD for Kubernetes, it
|
||||
reconciles the cluster against the git repo; got it running, plenty still to
|
||||
do"). A short conceptual explanation is welcome. Hard numbers, exact config
|
||||
values, and internal symbol names are not: the user trims those out (e.g. they
|
||||
cut `GOGC=200` / `~50%` / `buildRange` down to "changed GC to be less
|
||||
aggressive with `GOGC`"). When in doubt, go one level more abstract.
|
||||
- **Terse, no throat-clearing.** Skip "This week was dominated by...". Lead with
|
||||
the substance. Bullets are fine where they read better than prose.
|
||||
- **`->` for results/consequences** is fine and matches their notes.
|
||||
- **No em dashes.** Use commas, parentheses, `->`, or new sentences.
|
||||
- Light first person is fine ("I got ArgoCD running via port-forward"), matching
|
||||
how they write in their own logs.
|
||||
- Do not over-polish. The user's own prose has the odd typo and loose phrasing;
|
||||
clean readable English is the target, not editorial perfection.
|
||||
|
||||
Pull the substance and phrasing from the linked story notes, but render it in
|
||||
this clean English voice. Accurate before polished.
|
||||
|
||||
#### Referencing tickets — paraphrase, then ticket in brackets
|
||||
|
||||
Never drop a literal story title into the prose; many are too long. Paraphrase
|
||||
what the ticket was about in your own short words, then put the ticket id in
|
||||
round brackets after it. Put the note link on the bracketed id when a note
|
||||
exists.
|
||||
|
||||
- With a note: `setting up ArgoCD for the Hatchry demos ([PBI 34839](:/<note_id>))`
|
||||
- Without a note: `the homepage audit logs not checking privileges (Bug 34960)`
|
||||
|
||||
Only link tickets you actually found a note for (the `ticket -> note_id` map from
|
||||
step 2). Never invent note ids. Reference each ticket this way the first time it
|
||||
appears; afterwards a short phrase is fine.
|
||||
|
||||
### 4. Build the Loose ends section
|
||||
|
||||
Carry-over is the point of this section. Include:
|
||||
|
||||
- **Open checklist items** (`- [ ]`) still present in the target week note.
|
||||
- **Recurring unclosed stories**: stories worked on this week that also appear
|
||||
in the previous week(s) and are clearly still in flight (still being reviewed,
|
||||
rebased, "respond to comments", failing tests, etc.). Use judgement from the
|
||||
`Note` column; do not flag a story as carry-over just because the number
|
||||
recurs.
|
||||
- **Still-open todos** from the previous week note that were never checked off
|
||||
and are still relevant.
|
||||
|
||||
If there is genuinely nothing to carry over, write a single line saying so
|
||||
rather than padding.
|
||||
|
||||
### 5. Assemble the review block
|
||||
|
||||
Produce this structure:
|
||||
|
||||
```markdown
|
||||
## Summary
|
||||
|
||||
<narrative of own work, grouped by theme, most time first; meetings line near the end>
|
||||
|
||||
## Reviews
|
||||
|
||||
<short list of stories that were only reviewed (note = "review"), with rough total time>
|
||||
|
||||
## Loose ends
|
||||
|
||||
<open checklist items, recurring unclosed stories, carry-over todos>
|
||||
```
|
||||
|
||||
- The **Reviews** section is a short bullet list, not prose. Paraphrase each
|
||||
reviewed ticket and put the id in brackets, same format as the Summary. If
|
||||
nothing was only-reviewed that week, drop the section.
|
||||
- Theme times in the Summary should reflect **own work only**; a story that
|
||||
moved to Reviews takes its time with it (its per-story total from `stories`
|
||||
is its review time, since it is review-only).
|
||||
- The older notes (W20, W21) carried a verbatim `## Stories` block (the raw CLI
|
||||
output with full ticket titles). The user prefers paraphrased references and
|
||||
does not want literal story names dumped in, so do **not** add that block by
|
||||
default. Only include it if the user asks for the raw ticket/time ledger.
|
||||
|
||||
### 6. Confirm, then write into the note
|
||||
|
||||
- **Show the full draft to the user first and ask for confirmation.** This is
|
||||
LLM-generated prose going into a durable note; do not write blindly. Apply any
|
||||
edits the user asks for.
|
||||
- Write it into the Review section with `edit_note` in Replace mode, anchored on
|
||||
the review heading so the day tables below are untouched. The review heading is
|
||||
the first heading of the note, of the form `# Week of YYYY-MM-DD - Review` (or
|
||||
just `# Review` in older notes). Replace from that heading down to (but not
|
||||
including) the first day heading (`# <weekday> - ...`).
|
||||
|
||||
Concretely: read the current text between the review heading and the first day
|
||||
heading, pass it as `old_string`, and pass the heading plus the new block as
|
||||
`new_string`. If the Review section is an empty placeholder (heading
|
||||
immediately followed by the first day heading), anchor on the heading line
|
||||
alone and insert the block after it.
|
||||
- After writing, re-fetch the note (or report the diff) so the user can verify.
|
||||
|
||||
## Notes and edge cases
|
||||
|
||||
- Tables have no `Duration` column; the CLI computes duration from Start/End.
|
||||
Trust the CLI's times, not a hand count.
|
||||
- A leave day shows as `~verlof` / a `VERLOF:` heading prefix and counts toward
|
||||
totals but has no stories. Mention leave in the Summary when it shortened the
|
||||
week.
|
||||
- Overlapping entries exist in the raw tables; the CLI already resolves them.
|
||||
Never sum durations by hand from the raw note.
|
||||
- Do not modify the day tables or their `Note` columns. Only the Review section.
|
||||
|
||||
---
|
||||
|
||||
# Part 2 — Distill and refine the knowledge queue
|
||||
|
||||
Clearing the knowledge queue: notes the user flagged during the week for
|
||||
knowledge work. This is **week-independent** (it processes whatever is currently
|
||||
tagged, a standing queue) and can be run on its own.
|
||||
|
||||
## What the tags mean
|
||||
|
||||
- **`status/distill`**: the note holds general, reusable knowledge (a gotcha, a
|
||||
fact, how something works) that should be promoted into a proper Knowledge
|
||||
page. Example: OpenAPI gotchas written down while doing a REST-migration ticket
|
||||
were distilled into the `OpenAPI Cheat Sheet`. Ticket-specific debugging detail
|
||||
stays in the story log; only the generalizable knowledge gets distilled.
|
||||
- **`status/refine`**: the note itself needs rewriting/cleanup. The content
|
||||
stays in the same note, it just gets cleaned up. This applies mainly to
|
||||
story-log and similar notes. Important exclusions:
|
||||
- **Checkin notes** (in `Work / Meetings / Checkins`) are never refined by the
|
||||
skill. The user does those themselves. Skip them entirely.
|
||||
- For any **meeting note**, never touch the `## Topics` section. Those are the
|
||||
user's own words and stay as-is. Refine only the other sections if they hold
|
||||
rough content that needs cleanup.
|
||||
- Refine in the note's **original language**. If the note mixes languages, use
|
||||
English.
|
||||
|
||||
Note: `status/read` is unrelated to this queue. It means the note contains a
|
||||
link to something that still needs to be read, NOT "already processed". Do not
|
||||
treat it as a done-state and do not touch it here.
|
||||
|
||||
A note can carry both tags.
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Collect the queue.** `find_notes_with_tag("status/distill")` and
|
||||
`find_notes_with_tag("status/refine")`. Read each note in full.
|
||||
2. **Know the knowledge base.** Read `Knowledge/_Index` for the existing pages
|
||||
(cheat sheets, concept pages, infra, Factry-internal, etc.). Distilled content
|
||||
should land in an existing page; only propose a new page when nothing fits,
|
||||
and mark it clearly as new.
|
||||
3. **For each `distill` note, propose:**
|
||||
- the target Knowledge page: an existing page when one fits, or a new page
|
||||
when the topic deserves its own (e.g. ArgoCD got its own page because the
|
||||
user will keep researching it). Mark new pages as new and place a link under
|
||||
the right `Knowledge/_Index` heading. **Before proposing a new page, search
|
||||
(`find_notes`) for an existing one on the topic and check `Knowledge/_Index`
|
||||
— merge into it rather than creating a duplicate.** Note that the available
|
||||
Joplin tools cannot delete notes, so a wrongly-created duplicate can only be
|
||||
blanked, not removed; check first.
|
||||
- the actual distilled content, written in the user's knowledge-note voice.
|
||||
The reference for knowledge pages is the "Express Guide" OpenTelemetry note:
|
||||
fuller and more explanatory than the weekly summary, well-structured, clean
|
||||
English, no em dashes.
|
||||
- Quote the source lines you are distilling so the user can verify nothing was
|
||||
invented or distorted.
|
||||
4. **For each `refine` note, propose** the rewritten note (or rewritten
|
||||
sections), preserving the user's stances, opinions, and meaning exactly. Do
|
||||
not soften or invent content. Honor the exclusions above (skip checkin notes,
|
||||
never touch a meeting note's `## Topics`, keep the original language / English
|
||||
if mixed). If a note's only content is in an off-limits section, there is
|
||||
nothing to refine: leave it for the user and do not remove its tag.
|
||||
5. **List everything and get approval before writing anything.** Present one
|
||||
list: per note, what would be written and where (knowledge page edit, or note
|
||||
rewrite). The user approves or rejects each item individually. This mirrors
|
||||
Part 1's confirm-before-write rule and is a hard requirement here.
|
||||
6. **After approval**, for each approved item:
|
||||
- distill: merge the content into the target Knowledge page with `edit_note`
|
||||
(and add a link in `Knowledge/_Index` if a new page was created). Leave the
|
||||
source note's content intact.
|
||||
- refine: rewrite the note in place with `edit_note`.
|
||||
- **Tag handling:** once a note has actually been processed, remove the
|
||||
processed tag with `untag_note` (drop `status/distill` and/or
|
||||
`status/refine`). Only remove a tag for work that was actually done and
|
||||
approved. Never move it to `status/read` (that tag means something else).
|
||||
|
||||
## Edge cases
|
||||
|
||||
- **`Inbox` is intentionally tagged `distill`** so the user does not lose track
|
||||
of it; it is a triage list, not knowledge. Ignore it: do not distill it and do
|
||||
not remove its tag.
|
||||
- More generally, **not everything tagged `distill` is promotable knowledge.** If
|
||||
a tagged note holds none, say so and leave it (and its tag) alone rather than
|
||||
forcing a Knowledge edit.
|
||||
- If the queue is empty (or everything in it is excluded), say so. Do not invent
|
||||
work.
|
||||
- Never write to a Knowledge page or rewrite a note without explicit approval.
|
||||
1
CLAUDE.md
Symbolic link
1
CLAUDE.md
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
AGENTS.md
|
||||
Loading…
Add table
Add a link
Reference in a new issue