Installs into .claude/skills of the current project.
Are you the author of Analytics?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/tandregbg-analytics)
---
name: analytics
description: Vault-level content analytics — file creation trends, skill adoption, contact engagement, content distribution, pipeline outcome metrics (insights/tasks/changelog per meeting), and unprocessed backlog detection. Outputs to .analytics/ folder.
user-invocable: true
argument-hint: [overview|skills|contacts|pipeline|backlog|help]
---
# /analytics -- Vault Content Analytics
Analyse the vault as a dataset — file metadata (names, dates, paths, counts), not file contents. Answers "how is my system performing?" rather than "what did I learn from this conversation?"
**Standalone skill** — no dependency on ops-base or ops-config.
**Key distinction from `/insights`:** The insights skill extracts *knowledge from conversations* (decisions, learnings, patterns about people and projects). This skill analyses *the vault itself* — creation velocity, skill adoption, engagement frequency, content distribution.
---
## Design Principles
- **Metadata and structured fields only.** Read filenames, paths, dates, and file sizes. Never read prose content — the only in-file reads allowed are lightweight classification (H1 heading, first line) and **structured-field scans** for the pipeline subcommand: regex-matching `date:`/`type:` lines in `_insights.yaml`, `created:` lines in `_tasks.yaml`, and `- **YYMMDD:` bullets in `CHANGELOG.md`. Field values only; summaries, rationale, and notes are never read.
- **Non-destructive.** Only writes to `.analytics/` — never modifies existing files.
- **Snapshot-based.** Each run produces a dated snapshot. Historical snapshots enable trend comparison.
- **Privacy-aware.** Contact names appear in analytics (they are folder names, not extracted content). Mark private contacts with `private: true` in `_meta.yaml` to exclude them from output.
---
## Output Location
All output goes to `{vault_root}/.analytics/` (CR-097). A dot surface: read on demand, never by a
folder walk -- the snapshots are named `YYMMDD-*.md`, the pattern skills use to find notes, and a dot
prefix keeps them out of every walk by rule rather than by exception.
**Before 1.83.0 this was `_analytics/`.** If `{vault_root}/_analytics/` exists and `.analytics/` does
not, offer to move it (the whole folder, its `.archive/` included) before writing, and write nothing
until the user answers. Never write to both. Readers fall back to `_analytics/` for one release.
```
.analytics/
├── YYMMDD-vault-overview.md <- /analytics overview
├── YYMMDD-skill-adoption.md <- /analytics skills
├── YYMMDD-contact-engagement.md <- /analytics contacts
├── YYMMDD-pipeline-report.md <- /analytics pipeline
├── YYMMDD-backlog-report.md <- /analytics backlog
└── .archive/ <- older snapshots (auto-archived)
```
**Archive policy:** When writing a new snapshot, move any existing file of the same type to `.archive/` with its date prefix preserved. Keep the latest of each type at the top level.
---
## Vault Detection
Determine vault root:
1. Walk up from cwd looking for `_contacts/` or `_projects/` markers
2. Fallback: `$OBSIDIAN_VAULT` environment variable
3. Fallback: cwd itself
---
## File Discovery
The core scanning step shared by all subcommands.
### YYMMDD File Detection
Scan vault recursively (max depth 8, skip `.archive/`, `.handoff/`, `.git/`, `node_modules/`, `clones/`). Match files where the basename starts with 6 digits followed by a separator:
```
Pattern: /^(\d{6})[-_ ]/
```
Validate the 6 digits as a plausible date:
- Year (positions 1-2): 22-29 (2022-2029)
- Month (positions 3-4): 01-12
- Day (positions 5-6): 01-31
### Metadata Collected Per File
| Field | Source |
|-------|--------|
| `date` | Filename prefix (YYMMDD) |
| `path` | Relative path from vault root |
| `directory` | Parent directory (2 levels from vault root) |
| `extension` | File extension (.md, .txt, .pptx, etc.) |
| `skill_type` | Classified by path and filename keywords (see below) |
| `contact` | Extracted from `_contacts/{name}/` path segment, if present |
### Skill Classification
Classify each file by **path first, keywords second**:
**Step 1 — Path-based classification** (highest confidence):
| Path contains | Classification |
|---------------|---------------|
| `_inbox/` | `inbox` |
| `.analytics/` (or legacy `_analytics/`) | skipped -- a dot surface is outside every walk; the legacy path is skipped explicitly until moved |
| `_outbox/` | `outbox` |
**Step 2 — Keyword-based classification** (filename, case-insensitive):
| Keywords | Classification |
|----------|---------------|
| `samtal`, `call`, `transcript` | `transcript` |
| `agenda`, `facilitator` | `agenda` (dual-mode docs, CR-018 — check before preparation) |
| `förberedelse`, `preparation`, `prep-` | `preparation` |
| `meeting`, `möte`, `standup`, `board`, `alignment`, `kickoff`, `weekly`, `sprint`, `retro`, `sync`, `sammanfattning`, `summary` | `ops/meeting` |
**Step 3 — Directory-context classification** (for files that didn't match keywords):
| Directory pattern | Classification |
|-------------------|---------------|
| `meetings/` or `moten/` or `möten/` anywhere in path | `ops/meeting` |
| `ops/` anywhere in path | `ops` |
| `_resor/` or `resor/` | `travel` |
| `ppc/` or `marketing/` or `marknads` | `marketing` |
| `.txt` extension | `raw-text` |
| `.pptx`, `.pdf`, `.docx`, `.xlsx` | `office-doc` |
| `.png`, `.jpg`, `.jpeg`, `.heic` | `image` |
**Step 4 — Fallback:** `uncategorized`
### Privacy Filtering (CR-009)
Before including a contact in named output:
1. **Resolve classification** for the contact folder:
- If `_meta.yaml` exists and has `classification` field: use it
- Else if `_meta.yaml` exists and has `private: true`: treat as `personal`
- Else check folder name against `privacy_defaults` in `base.yaml`:
- `_contacts/a1-*` or `_contacts/a2*` → `family`
- Else default: `professional`
2. **Apply filtering by subcommand:**
- `/analytics contacts`: Exclude `family` and `personal` contacts from output
- `/analytics overview`, `/analytics skills`: Include all files in aggregate counts without contact attribution
- `/analytics backlog`: Include all files (backlog is about content gaps, not people)
3. **Never expose family/personal contact names** in any output file. Aggregate their files into totals only.
---
## Subcommands
### `overview` -- Vault-wide metrics snapshot
**Trigger:** `/analytics overview` or `/analytics` (default subcommand)
**Steps:**
1. Run file discovery (scan vault)
2. Compute summary metrics:
- Total YYMMDD files, date range, unique active dates, active months
- Current pace (files/day for current quarter)
- **Active-day density** — active days / calendar days for the current quarter (e.g. `84/91`), plus files per *active* day. The gap between files/day and files/active-day shows whether growth comes from busier days or from fewer idle days.
- Trend direction (current quarter rate vs previous quarter rate)
3. Compute yearly totals with year-over-year growth multiplier
4. Compute **content type × quarter pivot** — the core analytical view showing how each skill type's volume evolves over time. Columns: transcript, ops/meeting, preparation, ops, travel, raw-text, uncategorized, other. Use `·` for zero cells.
5. Compute **content type × month pivot** (last 12 months) — same columns, monthly granularity for recent trends
6. Compute monthly activity bar chart (last 12 months)
7. Compute quarterly trend table with deltas
8. Compute distributions:
- **By skill type** — table with count and percentage
- **By top-level directory** — top 15 areas with count (private contacts aggregated as single anonymous row)
- **By file extension** — count per extension
- **By day of week** — weekday vs weekend pattern with bar chart
9. Compute **top 5 busiest dates** — date, day of week, count
10. Write to `.analytics/YYMMDD-vault-overview.md`
**Output format:**
```markdown
# Vault Analytics — Overview
Generated: YYYY-MM-DD
---
## Summary
| Metric | Value |
|--------|-------|
| Total files | N |
| Date range | YYYY-MM-DD → YYYY-MM-DD |
| Active months | N |
| Avg files/month | N.N |
| Unique dates | N |
| Current pace | N.N files/day (QN YYYY) |
| Active days (current quarter) | N/N |
| Files per active day | N.N |
| Trend | ↑ N% vs previous quarter |
---
## Yearly Growth
| Year | Files | Growth |
|------|------:|-------:|
| YYYY | N | — |
| YYYY | N | N.Nx |
---
## Content Type × Quarter
| Quarter | transcript | ops/meeting | preparation | ops | travel | raw-text | uncategorized | other | **Total** |
|---------|------:|------:|------:|------:|------:|------:|------:|------:|------:|
| YYYY-QN | N| N| ·| N| ·| N| N| ·| **N** |
| YYYY-QN * | N| N| N| ·| N| ·| N| N| **N** |
\* partial quarter
---
## Content Type × Month (Last 12)
| Month | transcript | ops/meeting | preparation | ops | travel | raw-text | uncategorized | other | **Total** |
|-------|------:|------:|------:|------:|------:|------:|------:|------:|------:|
| YYYY-MM | N| N| ·| N| ·| N| N| ·| **N** |
---
## Monthly Activity (Last 12 Months)
| Month | Files | |
|-------|------:|---|
| YYYY-MM | N | ████████████ |
---
## Quarterly Trend
| Quarter | Files | Delta |
|---------|------:|------:|
| YYYY-QN | N | — |
| YYYY-QN | N | +N |
| YYYY-QN (partial) | N | -N |
---
## Content Distribution
### By Skill Type
| Type | Files | % |
|------|------:|----:|
| ops/meeting | N | N% |
| transcript | N | N% |
| preparation | N | N% |
| ... | | |
### By Directory (Top 15)
| Directory | Files |
|-----------|------:|
| org/meetings | N |
| *(private contacts, N folders)* | *N* |
### By File Extension
| Extension | Files |
|-----------|------:|
| .md | N |
| .txt | N |
### By Day of Week
| Day | Files | |
|-----|------:|---|
| Monday | N | █████████████ |
---
## Busiest Dates
| Date | Day | Files |
|------|-----|------:|
| YYYY-MM-DD | Thu | N |
```
---
### `skills` -- Skill adoption analysis
**Trigger:** `/analytics skills`
**Steps:**
1. Run file discovery
2. Build **skill share pivot (absolute)** — same columns as the overview pivot (transcript, ops/meeting, preparation, ops, travel, raw-text, uncategorized, other), one row per quarter. Use `·` for zero cells.
3. Build **skill share pivot (percentage)** — same layout but percentages per quarter.
4. For each skill type, compute per-skill summary:
- **First appeared** — which quarter the skill type first produced files
- **Total files** across all time
- **Current share** — percentage in the most recent full quarter, with ↑/↓/→ arrow vs previous quarter
- **Peak quarter** — quarter with most files from this skill
5. Compute **structured vs unstructured ratio** by quarter. Structured = transcript + ops/meeting + preparation + ops. Unstructured = everything else. Show absolute counts, and a trend line from first to last full quarter.
6. Write to `.analytics/YYMMDD-skill-adoption.md`
**Output format:**
```markdown
# Vault Analytics — Skill Adoption
Generated: YYYY-MM-DD
---
## Skill Share Over Time (absolute)
| Quarter | transcript | ops/meeting | preparation | ops | travel | raw-text | uncategorized | other | Total |
|---------|------:|------:|------:|------:|------:|------:|------:|------:|------:|
| YYYY-QN | N| N| ·| N| ·| N| N| ·| N |
| YYYY-QN * | N| N| N| ·| N| ·| N| N| N |
## Skill Share Over Time (%)
| Quarter | transcript | ops/meeting | preparation | ops | travel | raw-text | uncategorized | other |
|---------|------:|------:|------:|------:|------:|------:|------:|------:|
| YYYY-QN | N%| N%| ·| N%| ·| N%| N%| · |
---
## Per-Skill Trends
### transcript
- First appeared: YYYY-QN
- Total files: N
- Current share: N% (↑ vs previous quarter N%)
- Peak quarter: YYYY-QN (N files)
### ops/meeting
[Same structure for each skill with >0 files]
---
## Structured vs Unstructured
| Quarter | Structured | Unstructured | Structured % |
|---------|----------:|-------------:|-------------:|
| YYYY-QN | N | N | N% |
Trend: Structured content share grew from **N%** (YYYY-QN) to **N%** (YYYY-QN).
```
---
### `contacts` -- Contact engagement analysis
**Trigger:** `/analytics contacts`
**Steps:**
1. Run file discovery, filtered to `_contacts/` paths
2. Apply privacy filter — resolve `classification` per contact (see Privacy Filtering section). Exclude `family` and `personal` contacts from named output. Report count and total files of excluded contacts as an anonymous summary line.
3. For each remaining (professional) contact, compute:
- Total file count
- First and last file dates (as YYYY-MM)
- Active months count
- Peak month (month with most files, with count)
- Average files per active month
- Quarterly activity map (for timeline visualisation)
4. Compute contact lifecycle metrics:
- **New contacts by year** — when contacts first appeared, with cumulative total
- **Active contacts per quarter** — contacts with at least 1 file in the quarter
5. Sort contacts by total file count descending
6. Generate **activity timelines** — a monospace block showing quarterly engagement density for top 20 contacts using heat notation: `·` = 0, `░` = 1-2, `▒` = 3-5, `▓` = 6-10, `█` = 11+
7. Write to `.analytics/YYMMDD-contact-engagement.md`
**Output format:**
```markdown
# Vault Analytics — Contact Engagement
Generated: YYYY-MM-DD
*N private contacts excluded (N files in aggregate totals only)*
---
## Top Contacts (by file count)
| Contact | Files | Span | Active mo | Peak month | Avg/mo |
|---------|------:|------|----------:|-----------|-------:|
| name | N | YYYY-MM → YYYY-MM | N | YYYY-MM (N) | N.N |
---
## Activity Timelines
```
Contact Q4 Q1 Q2 Q3 Q4 Q1 Q2
contact-name (N) · ░ ▒ ▓ █ ▒ ·
Legend: · = 0 ░ = 1-2 ▒ = 3-5 ▓ = 6-10 █ = 11+
```
---
## Network Growth
| Year | New contacts | Cumulative |
|------|------------:|----------:|
| YYYY | N | N |
## Active Contacts Per Quarter
| Quarter | Active contacts |
|---------|----------------:|
| YYYY-QN | N |
```
---
### `pipeline` -- Input → meeting docs → outcomes over time
**Trigger:** `/analytics pipeline`
The document counts alone are not the full picture — a meeting's *outcomes* live in structured files the other subcommands never touch. This subcommand traces the whole chain: what came in, what was documented, and what it produced.
**Data sources (structured fields only — never prose):**
| Layer | Source | Field scanned |
|-------|--------|---------------|
| Insights | `_insights.yaml` (all folders) | `date:` + preceding `type:` per entry |
| Tasks created | `_tasks.yaml` (v2, all folders) | `created:` per task. Folders declaring `workflows.task_ledger.mode` other than `local` are **excluded** and listed separately as *external ledger* (CR-041) |
| CHANGELOG entries | `CHANGELOG.md` (all folders) | `- **YYMMDD:` bullet dates |
| Outbox packages | `_outbox/**` file discovery | filename YYMMDD prefix |
| New contacts | `_contacts/<name>/` | earliest YYMMDD file per folder |
**Steps:**
1. Run file discovery (same scan as overview)
2. Scan the structured sources above
3. Build the **grouped chain table — quarters as columns** (metrics as row groups, so the whole chain aligns vertically). Collapse quarters before the first meaningful year into a single `≤YYYY` column to keep width manageable. Row groups:
- **INPUT:** transcripts, raw text (.txt)
- **MEETING DOCS:** summaries/notes, agenda/facilitator, preparations
- **OUTCOMES:** insights total + one row per insight type (largest types first, small ones aggregated as "other"), tasks created, CHANGELOG entries, outbox packages, new contact folders
4. Compute **derived ratios** for quarters where the systems are fully active: insights per meeting+transcript, tasks per meeting+transcript, CHANGELOG entries per meeting+transcript.
**Exclude folders whose task ledger is not `local` (CR-041)** from the tasks-per-meeting ratio, and name them under the table as *external ledger: work tracked in `<system>`*. Their zero is a correct pipeline, not a gap -- counting it drags the ratio down and reports a healthy project as failing. This skill does **not** read the external system: counting items in a repo registry or an issue tracker is a different and much larger job, and the ratio simply excludes what it cannot see.
5. Compute **per-day averages by quarter:** active days / calendar days, files/day, meetings+transcripts/day, insights/day, tasks/day, files per active day (partial quarters use elapsed days)
6. Write to `.analytics/YYMMDD-pipeline-report.md`
**Report structure — two parts, mandatory:**
- **Part 1 — Overview:** headline totals table, a numbered list of *interpreted* findings (adoption inflections, ratio shifts, what converged or diverged — written as conclusions, not table prose), and the **measurement notes**.
- **Part 2 — Deep dive:** the grouped chain table, derived ratios, per-day averages, and any monthly detail.
**Measurement notes (mandatory in every pipeline report):**
- Outcome systems have adoption dates: a `·` before a system existed means "not yet measured", not "nothing happened". State each source's start-of-record explicitly (e.g. insights backfilled with extraction dates, tasks v2 introduction).
- CHANGELOG entries carry the original meeting date and are therefore the best longitudinal outcome proxy.
- Action items inside summary tables are NOT counted (would require prose reads); the task count is the nearest proxy.
- Mark partial quarters/months and use elapsed days for their per-day rates.
**Output format (Part 2 core table):**
```markdown
| Group / metric | ≤YYYY | YY-Q1 | YY-Q2 | ... | **Total** |
|---|---:|---:|---:|---:|---:|
| **INPUT** | | | | | |
| Transcripts | N | N | N | ... | **N** |
| Raw text (.txt) | N | N | N | ... | **N** |
| **MEETING DOCS** | | | | | |
| Summaries / notes | N | N | N | ... | **N** |
| Agenda/facilitator | · | N | N | ... | **N** |
| Preparations | · | N | N | ... | **N** |
| **OUTCOMES** | | | | | |
| Insights (total) | · | · | N | ... | **N** |
| — learning | · | · | N | ... | **N** |
| — pattern | · | · | N | ... | **N** |
| Tasks created | · | · | N | ... | **N** |
| CHANGELOG entries | N | N | N | ... | **N** |
| Outbox packages | · | · | N | ... | **N** |
| New contact folders | N | N | N | ... | **N** |
```
Per-day averages table:
```markdown
| Metric | YY-Q1 | YY-Q2 | ... |
|---|---:|---:|---:|
| Active days (≥1 file) | N/N | N/N | ... |
| Files/day | N.N | N.N | ... |
| Meetings+transcripts/day | N.N | N.N | ... |
| Insights/day | · | N.N | ... |
| Tasks/day | · | N.N | ... |
| Files per active day | N.N | N.N | ... |
```
---
### `backlog` -- Unprocessed content detection
**Trigger:** `/analytics backlog`
Identifies content that may benefit from processing through existing skills.
**Steps:**
1. Run file discovery
2. **Detect unprocessed transcriptions (CR-099):**
- Find `.txt` files with YYMMDD prefix (classified as `raw-text`)
- **Exclude** a file when any of these holds, and count each cause:
- its directory contains a `_manifest.md` -- the folder's intent is declared
- an `.md` file sharing its date prefix sits in the same directory **or in a sibling
directory** (same parent) -- the summary exists. A project keeps raw material and summaries
in separate folders (`transcripts/` beside `meetings/`), so looking only in the same
directory flags every processed file there. Like step 3's ancestor rule this is a heuristic:
an `.md` of the same date in a sibling folder may belong to another meeting that day, which
costs a missed flag, not a false one
- its directory name marks it as archived (`arkiv`, `archive`, `raw`, `källmaterial`)
- the newest file in its directory is older than 12 months -- dormant, not queued
- The survivors are the queue: group by directory, sorted by count descending, with count and
date range. **Extension plus date alone cannot tell a transcript awaiting `/transcript` from
raw material kept deliberately after processing** -- on one vault a single archive of 124 old
`.txt` files was 36 % of the unfiltered total
3. **Detect orphaned content (CR-099):**
- Find directories with 2+ YYMMDD-prefixed files and no `CHANGELOG.md`
- **Exclude** a directory, counting each cause, when:
- an ancestor up to 4 levels holds a `CHANGELOG.md` -- a project indexes at its root, not per
subdirectory (`meetings/`, `audits/`)
- it holds a `_manifest.md`
- any path component is dot-prefixed -- raw-material surfaces by convention
- Show the survivors, top 15 by file count, with `*(+ N more)*` if truncated. Unfiltered, this step
was wrong nine times in ten on one vault: 241 flags, 19 real
- **The ancestor rule is a heuristic:** it assumes the ancestor's CHANGELOG covers the
subdirectory, which it usually does. Verifying that would mean parsing the CHANGELOG for links to
every file -- a separate concern. The tradeoff is a few misses for removing most false positives
4. **Detect stale inbox items:**
- Read `_inbox/_inbox.yaml` if it exists
- Count items with `status: pending`
- Report age of oldest pending item
5. **Detect insight gaps:**
- Find folders with `CHANGELOG.md` but no `_insights.yaml`
- Count YYMMDD-prefixed files in each (potential insight yield)
- **Exclude** a folder whose ancestor up to 4 levels holds an `_insights.yaml`, or that holds a
`_manifest.md` (CR-099)
- Only include folders with **2+** transcript files (CR-099; was 1+)
- Show top 15 by transcript count, with `*(+ N more)*` if truncated
6. Write summary table at top with all four categories and suggested actions. **Print flags raised and flags after exclusions side by side, and the exclusion counts by cause** (CR-099) -- a single number that has been silently filtered misleads as much as an unfiltered one
7. Write to `.analytics/YYMMDD-backlog-report.md`
**Output format:**
```markdown
# Vault Analytics — Backlog Report
Generated: YYYY-MM-DD
---
## Summary
| Category | Flags raised | After exclusions | Potential action |
|----------|-------------:|-----------------:|-----------------|
| Raw text files (.txt) | N | N | `/transcript` or `/inbox` |
| Folders without CHANGELOG | N dirs | N dirs, N files | Manual triage |
| Pending inbox items | N | N | `/inbox route` |
| Folders missing _insights.yaml | N dirs | N dirs, ~N transcripts | `/insights reprocess` |
Excluded by cause: ancestor CHANGELOG N · `_manifest.md` N · dot path N · summary exists N ·
archive folder N · dormant > 12 months N
---
## Raw Text Files (Likely Unprocessed Transcriptions)
| Directory | Count | Date range |
|-----------|------:|-----------|
| _contacts/name | N | YYMMDD → YYMMDD |
| _projects/name | N | YYMMDD → YYMMDD |
---
## Folders Without CHANGELOG
| Folder | YYMMDD files |
|--------|-------------:|
| org/meetings/area | N |
| _contacts/name/subfolder | N |
| *(+ N more)* | |
---
## Pending Inbox Items
N items pending. Oldest: YYYY-MM-DD
(or: No pending items.)
---
## Insight Reprocessing Opportunities
| Folder | Transcripts | Has _insights.yaml |
|--------|------------:|-------------------:|
| _contacts/name | N | No |
| org/_projects/name | N | No |
| *(+ N more)* | | |
```
---
### `help` -- Usage guide
**Trigger:** `/analytics help`
**Output:**
```
/analytics -- Vault Content Analytics
======================================
Analyse the vault as a dataset -- file metadata, not contents.
Usage:
/analytics Vault overview (default)
/analytics overview Same as above
/analytics skills Skill adoption over time
/analytics contacts Contact engagement timelines
/analytics pipeline Input -> meeting docs -> outcomes chain
/analytics backlog Unprocessed content detection
/analytics help This guide
Output: .analytics/ folder in vault root (one snapshot per run).
Data flow:
YYMMDD-*.* files ──> /analytics ──> .analytics/YYMMDD-*.md
(read filenames, (classify, (markdown snapshots,
paths, dates) aggregate) one per subcommand)
Related skills:
/insights Extract knowledge FROM file contents
/insights status Count _insights.yaml coverage
/analytics Longitudinal view (trends over time)
```
---
## Language
Output language follows the same resolution as other standalone skills:
1. If vault root `CLAUDE.md` specifies a language policy, follow it
2. Default: Swedish for section headers and labels, English for technical terms
3. Swedish text MUST use correct å, ä, ö characters
---
## Notes
- The `.analytics/` folder is created automatically on first run (after offering to move a legacy `_analytics/`)
- Old snapshots are archived to `.analytics/.archive/` — never deleted
- This skill reads `_insights.yaml`/`_tasks.yaml`/`CHANGELOG.md` at **field level only** (dates and type enums for the pipeline subcommand) — entry contents (summaries, rationale, notes) remain the visualisation app's domain
- This skill does NOT read file prose (except optional H1 heading for display)
- Contact privacy is respected via `_meta.yaml` `private: true`
- The skill classification algorithm uses **path first, keywords second** — this avoids the ~17% miscount that pure keyword matching produces (e.g., acme/meetings/ files with descriptive names)
- Quarterly comparisons handle partial quarters gracefully — the current quarter is annualised for trend comparison