odoo-timesheets/.claude/skills/monthly-review/SKILL.md

298 lines
15 KiB
Markdown

---
name: monthly-review
description: >-
Generate a higher-level monthly timesheet review from the weekly review
sections of one calendar month's Joplin week notes, and write it as a note in
Work / Self-Reviews. Produces a month-level narrative of the work done plus an
inspections section (time allocation, stuck/recurring threads, long weeks).
Use when the user asks for a monthly review, a month recap, to "review my
month", to summarize a month of work, or to prep for a monthly/checkin
overview. Optionally takes a month (e.g. "April", "2026-04", "last month") to
target a month other than the current one.
---
# Monthly timesheet review
Build a month-level review by synthesizing the **weekly review sections** that
already exist in that month's week notes, and write it into a note in
`Work / Self-Reviews`. The weekly reviews are granular (one week each); this
zooms out: collapse the week-by-week detail into month-level arcs, say where the
big threads landed, and surface patterns that are only visible across the whole
month.
This is the bigger sibling of the `weekly-review` skill. The reference for the
target output is the existing `2026 - Year Review (W01-W22)` note in
`Work / Self-Reviews`: it is synthesized from weekly review sections at year
scale. A monthly review is the same idea, one month wide, plus an explicit
inspections section.
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. The `weekly-review` skill describes the weekly review format
this one consumes.
## Inputs
- Optional target month. Accept a month name (`April`), `YYYY-MM` (`2026-04`),
`last month`, `this month`, or any date (the month containing it). Default to
the **current** calendar month relative to today.
- If today is in the first days of a month and the request is ambiguous, the
user most likely means the month that just ended. Confirm which month before
doing the work.
- A review run for an incomplete (current, still-running) month is fine, but say
in the note that it is partial.
- The CLI reads timesheets from Joplin with `--joplin`. Config (token, project
map) is already set up; do not ask for it.
## What a month is here
A calendar month, **strict day filter**: only days that actually fall in the
month count. ISO weeks do not align with months, so a week that straddles the
boundary (e.g. the week of Apr 27 with days in both April and May) is included
**only for its in-month days**. The out-of-month days of a straddling week
belong to the other month's review.
Consequence: a straddling week whose in-month days have no logged entries (e.g.
for May, the week of Apr 27 only reaches into May 1-3, a Friday-to-Sunday with a
public holiday and no entries) contributes nothing and drops out entirely. Do
not pull its review in.
## Steps
### 1. Resolve the month and find its week notes
- Resolve the target month to its first and last calendar day, relative to
today. Convert any relative expression to an absolute month (e.g. with today
2026-05-30, "last month" = April 2026, "this month" = May 2026).
- Week notes live in `Work / Timesheets / <year>`, titled `YYYY - WNN`. List
them:
```
find_notes_in_notebook("Work/Timesheets/<year>")
```
A month near a year boundary (January, December) can pull weeks from **two**
year notebooks; list both when relevant.
- For each candidate week note, read its first heading
`# Week of <Monday> - Review` to get the week's Monday. The week spans
Monday..Monday+6. **Include the week if that span intersects the target
month** (week-Monday <= month-last-day AND week-Sunday >= month-first-day).
- For a **straddling week** (Monday before the 1st, or Sunday after the last
day), only the in-month days count (see "What a month is here"). Check whether
those in-month days actually have logged entries:
- If they do, include the week but treat only the in-month days as this
month's work. Read the day tables for those days to see what was worked, and
use the weekly Summary for context; do not attribute the out-of-month days'
work to this month.
- If the in-month days have no entries, drop the week entirely.
- Record the list of weeks that contribute days to this month (e.g. W19-W22) for
the title and caveats.
### 2. Read the weekly review sections (primary source)
For each included week note, read the **review block**: everything from the
`# Week of YYYY-MM-DD - Review` heading down to (not including) the first day
heading (`# <weekday> - ...`). Use `get_note(note_id, force_full=true)` and take
that top block. It holds the three subsections the weekly skill writes:
- `## Summary` — the narrative of own work, grouped by theme, with rough
per-theme times and a meetings line. This is the spine of the month narrative.
- `## Reviews` — work that was only reviewing other people's MRs, with a rough
total. Sum these across the month for the review-load figure.
- `## Loose ends` — open checklist items, recurring unclosed stories, carry-over.
This is the spine of the stuck/recurring-threads inspection.
The weekly reviews already carry the substance and the user's voice. Draw the
narrative from them; do **not** re-derive everything from the raw day tables.
The weekly review section is the source of truth for what the week was about.
Carry over the Joplin note links (`[label](:/<id>)`) from the weekly sections
when you reference the same ticket; do not invent new ids.
### 3. Get per-week totals (cross-check, long-week detection)
Run, once per included week, using that week's Monday date:
```sh
uv run timesheets summary -w -ss --joplin <monday-date> # per-day + week total
```
Use this to compute the month total and to spot long weeks. The `-ss` output
gives a per-day breakdown, so for a **straddling week** sum only the in-month
days rather than the whole-week total. **Cross-check against the total stated in
the week's `## Summary`.** The CLI total is occasionally garbage from data-entry
typos in the raw tables (a week can show a nonsense 100h+). When the CLI total
and the week note's stated total diverge wildly, trust the week note and flag
the week in Caveats. Never sum hours by hand from the raw tables.
### 4. Write the month narrative
Higher altitude than a weekly review. The reader should come away knowing what
the month was about and where the big threads landed, not the day-to-day.
- **Lead with the shape of the month**: one short paragraph. What were the one
or two centers of gravity? Was it focused on a flagship effort, or fragmented
across many small things? Did a release, a customer, or an interruption
dominate a stretch?
- **Group own work by major project/theme**, most time first. For each, give a
few plain sentences: what it was, how it progressed across the month's weeks,
and where it ended the month (landed / merged / still in flight / handed off).
Merge a theme that appears in several weekly summaries into one month-level
thread rather than repeating it per week. To state where a thread ended with
confidence, check the backing story note's location in Joplin: a note in the
top-level `Work / Story Logs` is still active, one in
`Work / Story Logs / Archive / <year>` is finished (the user archives a story
log once its work is done). This confirms landed/closed vs still in flight
rather than guessing from the weekly prose alone.
- **Recurring / continuous work** in a tighter list: bug-fixing load, the areas
that came up repeatedly (specific subsystems), customer/incoming work, MCP/AI,
security/ISMS, etc. Mirror the "Recurring areas" / "Continuous work" split in
the year-review note when there is enough material.
- **Meetings**: name the noteworthy ones (brainstorms, retros, growth-path,
customer/technical meetings, trade fairs). Fold dailies and Factry Flow into a
one-line catch-all. Pull these from the weekly summaries' meetings lines.
- Reference tickets by **paraphrase + id in brackets**, same convention as the
weekly skill, and only link ids that a weekly section already linked. At month
scale, reference fewer tickets than a weekly review would; lead with threads,
not ticket numbers.
### 5. Write the inspections section
This is the point of the monthly view: patterns visible only across the whole
month. Cover these three lenses (and only these unless the user asks for more):
1. **Time allocation.**
- Own work vs reviewing other people's MRs: sum the weekly `## Reviews`
totals and express the review load as a rough share of the month. A heavy
review month is worth calling out (it is real, valuable work, but it is a
large time sink and the user tracks it separately from own work).
- The split across major projects/themes for the month.
- How fragmented the month was: many small bugs and heavy context-switching
vs sustained focus on one or two threads. The weekly summaries say this
directly ("fragmented week", "no single theme", "one theme dominated");
aggregate that judgement.
2. **Stuck / recurring threads.**
- Tickets and loose ends that appear in **multiple** weeks' `## Loose ends`
or recurring-story lists and never closed within the month.
- Repeated rework: rebases of the same big branch, repeated rounds of fixing
the same failing tests or de-flaking the same suite (e.g. Cypress).
- Threads that opened early in the month and were still open at month end. A
thread is genuinely still open if its backing story note is still in the
top-level `Work / Story Logs`; if the note has moved to an archive
subnotebook it closed within the month, so do not list it as stuck.
- These are candidates the user may want to push to close or escalate.
3. **Long weeks (only).**
- Flag weeks that clearly ran over 40h and say what drove them (evening trade
fairs, late stress-test or customer work, a release crunch).
- **Do not flag short or low-hour weeks as reduced output or a concern.** The
user always works full weeks. A week that logs under 40h almost always
means vacation or time off that was simply not entered in the timesheet,
not less work done. At most mention a low-logged week once, in Caveats, as
a data-entry gap, never in the workload inspection as a productivity
signal.
Keep inspections concrete and tied to the data. If a lens has nothing real for
this month, say so in a line rather than padding.
### 6. Voice
Write it the way the user writes, not the way an assistant writes. The reference
is the user's **`Express Guide`** OpenTelemetry note (in `Knowledge /
OpenTelemetry`): read it before drafting and match its register.
How the user actually writes:
- **Plain and matter-of-fact.** States what a thing is and what happened, e.g.
"ArgoCD is gitops CD for Kubernetes, it reconciles the live cluster against
the git repo". Defines with "X is Y", gives concrete examples in parentheses
with "e.g.". No drama.
- **Full sentences, normal capitalization, English.** No Dutch, no
lowercase-everything, no `gwn`/`da`/`ge` (that is only how the rough
free-text is drafted, not how finished notes read).
- **Light first person where natural** ("I changed the GC to be less
aggressive", "I'm explaining them here").
- **Bold for the key term** that starts a thread or definition, the way the
Express Guide bolds **Counter**, **resource**, etc.
- `->` for results/consequences is fine. **No em dashes**; use commas,
parentheses, colons, `->`, or new sentences.
Avoid the AI tells the user does not use:
- No journalistic punch verbs or set-piece phrasing: not "blew up", "the spine
of the month", "rides with it", "pivoted hard", "exploded".
- No editorializing flourishes: not "worth keeping visible", "risks drifting",
"bit-rot risk". State the fact and, if needed, the plain consequence.
- No balanced "not X, but Y" rhythm or rule-of-three lists for effect.
- Keep the altitude high (what the thread was and where it landed), but the
prose flat and concrete. Exact config values and internal symbol names stay
out (the story logs hold those); `centre of gravity` is the user's own phrase
and is fine.
### 7. Confirm, then write 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 as a note in the `Work / Self-Reviews` notebook. Title convention,
mirroring the year-review note: `YYYY - <Month> Review (Wxx-Wyy)`, e.g.
`2026 - May Review (W18-W22)`.
- **Before creating, search for an existing note for this month**
(`find_notes_in_notebook("Work/Self-Reviews")`). If one exists, update it with
`edit_note` rather than creating a duplicate. The Joplin tools cannot delete
notes, so a wrongly-created duplicate can only be blanked, not removed; check
first. Only create a new note with `create_note` when none exists.
- After writing, re-fetch the note (or report the diff) so the user can verify.
## Output structure
```markdown
# <Month> <Year> Review (Wxx-Wyy)
Synthesized from the weekly review sections of the Wxx-Wyy timesheet notes.
## Shape of the month
<one short paragraph: the one or two centers of gravity, overall character>
## Major threads
<own work grouped by project/theme, most time first; where each landed>
## Recurring & continuous work
<bug-fixing load, repeated subsystems, customer/incoming work, meetings line>
## Inspections
**Time allocation** — <own vs review share, project split, fragmentation>
**Stuck / recurring threads** — <multi-week carry-overs, repeated rework, still-open>
**Long weeks** — <weeks over 40h and what drove them; none -> say so>
## Caveats
<missing week notes, unreliable CLI totals, low-logged weeks as data gaps>
```
Adapt the headings to the material; this is a shape, not a rigid template. Match
the depth of the year-review note: enough to be useful, not a per-ticket ledger.
## Edge cases
- **Missing or empty week note.** If an included week has no review section
(e.g. it was never reviewed, or is a near-empty stub), note it in Caveats and
work from what is there. Do not fabricate a week's content. If most of the
month's weeks lack review sections, tell the user the monthly review will be
thin and suggest running the weekly reviews first.
- **Straddling weeks** count only for their in-month days (see "What a month is
here"). If the in-month days have no entries, drop the week. Use the per-day
CLI breakdown to attribute hours.
- **Unreliable CLI totals.** Prefer the week note's stated total over a wildly
divergent CLI total; flag it in Caveats.
- **Low-logged weeks are not short weeks.** See step 5, lens 3: treat them as
unlogged-vacation data gaps, never as reduced output.
- **Never touch the week notes or the checkin notes.** This skill only reads the
weekly review sections and writes a new note in `Work / Self-Reviews`. Checkin
notes in `Work / Meetings / Checkins` are the user's own and are off-limits.
- Do not modify the day tables in any week note.