Initial session-notes skill: convention enforcer for coding sessions

Skill that triggers at the end of every coding session where files changed.
Enforces structured session notes with label, narrative, and four fields
(What, Why, How, Touches) at one-entry-per-logical-change granularity.

Includes reference examples from the Loom project and review-ready CLAUDE.md
with key patterns documented.
This commit is contained in:
Travis Herbranson 2026-04-27 20:17:06 -04:00
commit 1f7a85b7d1
5 changed files with 285 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.skill
__pycache__/
.DS_Store

53
CLAUDE.md Normal file
View File

@ -0,0 +1,53 @@
# Session Notes Skill
Claude Code skill that enforces structured session note documentation
at the end of every coding session.
## Architecture
```
session-notes-skill/
session-notes/
SKILL.md — Skill definition (triggers, format, rules)
references/
example-session.md — Reference examples at correct granularity
```
## Key Patterns
**Skill-as-convention enforcer.** This skill doesn't generate code or
transform files — it enforces a documentation convention. The SKILL.md
teaches the agent what to write, when, and at what granularity. The
reference file provides concrete examples to calibrate quality.
**Granularity rule.** The core constraint is one entry per logical change.
This is the hardest thing to get right — agents naturally want to
summarize. The skill explicitly calls out the anti-pattern (rolling
multiple changes into one entry) and provides a "too coarse" vs "right
granularity" comparison.
**Progressive disclosure.** SKILL.md body is always loaded when triggered
(~100 lines). The reference examples in `references/` are loaded on
demand when the agent needs to calibrate its output quality.
**Session notes live in the project, not the skill.** The skill tells
the agent to write to `sessions/<slug>.md` in whatever project it's
working on. The skill itself doesn't store any session data.
## Development
```bash
# Package as .skill file
cd session-notes && zip -r ../session-notes.skill SKILL.md references/
```
## Session Notes
After each coding session, append a session entry to
`sessions/session-notes-skill.md` in this project folder.
See that file for the format convention and existing entries.
Granularity: one entry per logical change. A new function, a new route,
a new template, a new config setting, or a bug fix each get their own
entry. Don't combine multiple changes into one entry. If it would be a
separate item in a code review, it's a separate entry here.

121
session-notes/SKILL.md Normal file
View File

@ -0,0 +1,121 @@
---
name: session-notes
description: >
Write structured session notes at the end of every coding session. Triggers
automatically when a session involves code changes — new files, bug fixes,
refactors, features, config changes, or any modification to project files.
Also triggers when the user says "write session notes", "log this session",
"document what we did", "wrap up", or "end of session". If you made code
changes during this session, use this skill before the conversation ends.
Do not wait to be asked.
---
# Session Notes
At the end of every coding session where code was changed, write a structured
session note capturing each individual change. This is how future sessions,
reviewers, and the Loom dashboard understand what happened.
## When to Write
Write session notes when any of these are true:
- You created, modified, or deleted project files during this session
- The user asks you to log, document, or wrap up the session
- The conversation is ending and you made changes
Do not write session notes for conversations that were purely discussion,
planning, or Q&A with no file changes.
## Where to Write
Session notes live in the project directory at `sessions/<project-slug>.md`.
If the file doesn't exist, create it with the header template. If it exists,
append a new dated session entry at the bottom.
The project slug is the kebab-case project name — usually matches the
directory name (e.g., `work-index-dashboard`, `cli-standardization`).
## Format
Each session entry is a dated heading followed by one or more change entries.
Each change has a label, a narrative, and four structured fields.
```markdown
## Session — YYYY-MM-DD
### <Change Label>
<Narrative what was done and why, in plain English. 2-4 sentences
that explain the change to someone who hasn't seen the code.>
- **What:** <one-line summary of the change>
- **Why:** <the motivation what problem or need drove this>
- **How:** <implementation approach key functions, patterns, libraries used>
- **Touches:** <files modified, with (new) for new files>
```
## Granularity
This is the most important rule: **one entry per logical change.**
A logical change is a new function, a new route, a new template, a config
addition, a bug fix, or a refactor. If you'd explain it as a separate thing
in a code review, it's a separate entry.
The test: could someone read this single entry and understand what was
changed without looking at the diff? If yes, the granularity is right.
If they'd need to mentally decompose it into sub-changes, it's too coarse.
**Too coarse** (don't do this):
```markdown
### Built the data layer
Created vault reader, Trello client, and join layer.
```
**Right granularity** (do this):
```markdown
### Vault Frontmatter Reader
Scans all .md files in the vault and extracts YAML frontmatter into
VaultProject dataclasses...
### Trello REST Client
Wraps the Trello board API with httpx...
### Join Layer
Merges vault projects and Trello cards into a unified ProjectView...
```
## Writing Quality
The narrative is the most important part — it's what a human reads first.
Write it as if you're explaining the change to a colleague who knows the
project but wasn't in this session. Be specific about what was built,
not just that something was built.
For the structured fields:
- **What** should be a single line, specific enough to be useful in a list
- **Why** should state the actual motivation, not just "it was needed"
- **How** should name the key functions, patterns, or libraries — enough
that someone could find the relevant code without grepping
- **Touches** should list every file that was created or modified, with
`(new)` for new files
## File Header
If creating the session notes file for the first time, use this header:
```markdown
# <Project Name> — Session Notes
Session log for the <project-slug> project. Each session is a dated
heading with a list of changes. Each change has a label, narrative, and
four structured fields (What, Why, How, Touches).
---
```
Then append the first session entry below the `---`.
## Reference
See `references/example-session.md` for a complete example of a
well-written session entry at the right granularity level.

View File

@ -0,0 +1,60 @@
# Example Session Entry
This is a reference example showing the right granularity and writing
style for session notes. Each change is its own entry with specific
detail about what, why, how, and what files were touched.
---
## Session — 2026-04-27
### Trello REST Client
Wraps the Trello board API with httpx. Fetches lists and cards, groups
cards by label name (which is the project slug). Includes in-memory cache
with configurable TTL so the dashboard doesn't hit Trello on every page
load.
- **What:** `TrelloClient` class with card grouping and TTL cache
- **Why:** Dashboard needs live Trello card state joined to vault data
- **How:** httpx.Client with 15s timeout. `_fetch_all()` populates cache
dict with lists and cards. `get_cards_by_project()` groups cards by
label name. `get_list_for_project()` returns highest-priority list
name using a priority map (Active=0, On Deck=1, etc). `refresh()`
invalidates cache.
- **Touches:** data/trello.py (new)
### Loose Thread Scanner
Scans all vault .md files for unchecked `- [ ]` checkbox items. Returns
them as LooseThread objects with the text, project slug, and source file.
Found 862 items across the real vault.
- **What:** `find_loose_threads()` returns list of LooseThread
- **Why:** "What loose threads have I left" — unfiled commitments
- **How:** Regex `^(\s*)-\s+\[\s\]\s+(.+)$` with MULTILINE flag. Scans
all .md files regardless of type. Uses project slug from frontmatter
if available, falls back to filename stem.
- **Touches:** data/sessions.py
### Path Traversal Fix
Gemini CLI review caught that _log_session accepted arbitrary slugs that
could write outside the vault directory via `../../` paths. Added slug
validation regex and resolved-path containment check.
- **What:** Slug validation + path containment for MCP write tools
- **Why:** Security — prevent path traversal via malicious slug input
- **How:** _SLUG_RE regex `^[a-z][a-z0-9-]*$` rejects anything with dots,
slashes, or uppercase. _validate_slug() returns error message or None.
Additional check: `filepath.resolve().is_relative_to(vault_path.resolve())`.
Applied to both _log_session and _update_project_status.
- **Touches:** mcp/server.py
### Pydantic Settings
App configuration using pydantic-settings with LOOM_ env prefix. Covers
host, port, vault path, Trello credentials, and cache TTL. Reads from
.env file.
- **What:** `Settings` class with LOOM_ prefix and vault_dir property
- **Why:** Centralized config with env-file support
- **How:** pydantic-settings BaseSettings with env_prefix="LOOM_". vault_dir
is a @property that returns Path(vault_path).
- **Touches:** core/config.py

View File

@ -0,0 +1,48 @@
# Session Notes Skill — Session Notes
Session log for the session-notes-skill project. Each session is a dated
heading with a list of changes. Each change has a label, narrative, and
four structured fields (What, Why, How, Touches).
---
## Session — 2026-04-27
### SKILL.md Definition
Wrote the core skill definition with trigger description, format template,
granularity rule, and writing quality guidance. The trigger is set to fire
automatically at the end of any coding session where files changed, and
also responds to manual invocations like "write session notes" or "wrap up."
- **What:** SKILL.md with session notes convention and auto-trigger
- **Why:** Need a reusable skill that enforces consistent session documentation
across all projects and all Claude Code sessions
- **How:** YAML frontmatter with pushy description for reliable triggering.
Body covers when/where/format/granularity. Includes good-vs-bad granularity
comparison and file header template for new projects.
- **Touches:** session-notes/SKILL.md (new)
### Reference Examples
Created a reference file with four real session entries from the Loom
project (work-index-dashboard) showing the correct granularity and style.
Covers different change types: new function, scanner utility, security fix,
and config setup.
- **What:** Example session entries for agent calibration
- **Why:** The granularity rule needs concrete examples to be effective —
abstract rules alone lead to over-summarization
- **How:** Extracted and lightly edited four entries from the Loom session
notes that were validated as "right granularity" by Travis.
- **Touches:** session-notes/references/example-session.md (new)
### Project Documentation
Added CLAUDE.md with key patterns section documenting the skill-as-convention
approach, granularity rule importance, progressive disclosure pattern, and
the separation between skill (convention) and session data (in each project).
- **What:** CLAUDE.md with architecture and key patterns
- **Why:** Future sessions working on this skill need to understand the
design decisions, not just the file tree
- **How:** Follows the review-ready CLAUDE.md convention established in the
Loom project — file tree plus key patterns plus session notes pointer.
- **Touches:** CLAUDE.md (new)