Skip to content

Add active/ hygiene guardrail — flag completed-not-archived notes + ungrouped multi-file topics #98

@breferrari

Description

@breferrari

Summary

Add a lightweight, no-LLM guardrail that keeps work/active/ honest by surfacing two drift modes automatically: (1) notes marked done but never archived, and (2) related notes piling up loose in the active/ root that should be grouped into a folder. Wired into the SessionStart and Stop hooks (nudge-only) and the weekly review (where you act on it).

Motivation

active/ is meant to hold only current work, but it rots predictably:

  • Completed notes stay because "archive later" never comes. A status: completed note in active/ pollutes the SessionStart task aggregation and any status-filtered Base view.
  • A workstream spawns meetings/reports that scatter as loose files in the root instead of grouping, until the folder feels disorganized.

Both are invisible until someone notices. This makes them visible on a cadence, with zero enforcement.

Design

New shared lib .claude/scripts/lib/active-hygiene.ts, consumed by both hooks. Two detectors, both conservative (false negatives preferred over nagging — same philosophy as the existing org-change detector in stop-checklist.ts):

  1. completed-not-archived — recursively scan work/active/**.md; flag any whose frontmatter status ∈ {completed, archived, done}. Reuses extractFrontmatterField from lib/session-start.ts.

  2. ungrouped multi-file topic — among notes directly in the active/ root (subfoldered = already grouped), tokenise titles (strip a leading YYYY-MM-DD prefix, lowercase, drop tokens <4 chars, numerics, and a small generic-process stopword list: report/sync/plan/notes/draft/meeting/review/…). Flag a token shared by ≥2 root notes. Guards against noise:

    • Document-frequency cap: a token in >50% of root notes is treated as a generic vault-wide term (e.g. a team/element name), not a topic → dropped. This is what makes it safe without a vault-specific stopword list.
    • Min-root threshold: stay silent until the root has ≥4 loose notes — folders are for taming size, not ceremony.

formatActiveHygiene(report) returns [] when clean, so callers emit nothing.

Wiring

  • SessionStart hook: conditional ### Vault Hygiene (active/ drift) section, appended only when there are findings (silent when clean).
  • Stop hook: append findings under the existing wrap-up checklist.
  • /om-weekly: a new "active/ Hygiene Sweep" step — the hooks flag, the weekly is where you act (archive / group / mark stale).
  • CLAUDE.md: codify the two conventions this enforces —
    • Date naming: YYYY-MM-DD prefix for point-in-time notes (meetings, syncs, retros, prep); bare title for living project/concept notes.
    • Folder grouping: a workstream with >1 note gets active/<Topic>/ holding the project note + its sub-notes; mirror in archive/YYYY/.

Files

  • lib/active-hygiene.ts (new), tests/active-hygiene.test.ts (new)
  • session-start.ts, stop-checklist.ts (wire-in, ~6 lines each)
  • commands/om-weekly.md, CLAUDE.md (docs/conventions)

Testing

10 unit tests over fixtures (mkdtemp): status detection incl. recursion, cluster detection, stopword + DF guard + min-root behaviour, date-prefix stripping, and the renderer. Full suite stays green.

Out of scope / config

  • Never moves files — nudge only.
  • Thresholds (DF cap 50%, min 4 root files, stopword list) are constants; could be vault-manifest.json-configurable in a follow-up if desired.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions