# Ops

> Operations Framework

- Skill: `tandregbg/ops` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tandregbg/ops`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tandregbg/ops/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tandregbg (https://skillmd.com/u/tandregbg)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/tandregbg/ops

---


# Operations Framework

Unified meeting and operations processing. Behaviour is driven by org config -- the same skill handles Bravo veckosynk, Acme management meetings, marketing standups, and project dev standups.

**Base framework:** Extends `ops-base` -- read `~/.claude/skills/ops-base/SKILL.md` for shared standards (meeting formats, task management, workflows, archive policy).

**IMPORTANT:** The project CLAUDE.md is the single source of truth for vault-specific details. This skill defines the processing workflow; CLAUDE.md defines file locations and naming conventions.

---

## SUBCOMMANDS

### `status` -- Show available configurations

**Trigger:** `/ops status`

Parse the user's input. If the first word is `status`, execute this subcommand instead of the normal processing flow (Steps 1-9).

**Steps:**

1. **Scan for org configs:**
   - Find vault root (walk up from CWD until `_inbox/`, `_outbox/`, or `.obsidian/`; or `VAULT_ROOT` env)
   - Glob `<vault>/*/_ops.yaml` for org-folder configs
   - Check `<vault>/_config/base.yaml` for vault-wide override
   - Read and parse each config
   - **Deprecated fallback:** also scan `~/.claude/skills/*-ops-config/` for legacy skill-based configs and emit a one-time deprecation warning per session if any are found (removed in v1.17.0)

2. **Detect active config:**
   - Check for project-level `.claude/ops-config.yaml` in current working directory
   - Walk up from CWD looking for the nearest `<folder>/_ops.yaml`
   - Determine org from CLAUDE.md `organization` field or folder name pattern
   - Report which config would be loaded for the current directory

3. **Present report** for each org config:
   - Organization name, language, swedish_chars
   - Team members (name + role, abbreviated if >4 members)
   - Workflows: update_files list, action_propagation status, agenda_management status, post_processing status
   - Rolling plans: count + axes (if `workflows.rolling_plans` configured)
   - Domain additions count
   - Summary sections (custom or default TWO-TIER)
   - Templates (if configured)
   - Strings (custom or default)

4. **Show base defaults** from `~/.claude/skills/ops-config/base.yaml`

5. **Vault health check** (CR-010 `rules.single_inbox_outbox`, `rules.yaml_naming`):
   - From the detected vault root, scan for stray inbox/outbox directories using the **CR-025 fuzzy matcher** (same as `/ops sweep` check 9): `_inbox`, `_outbox`, `.inbox`, `.outbox`, any `*inbox*`/`*outbox*` directory, and localized forms (`inkorg*`/`utkorg*`), case-insensitive, skipping `.archive/`/`.transcripts/`/`.handoff/`/`clones/`/`node_modules/`. Anything other than `<vault>/_inbox` and `<vault>/_outbox` is a stray; flag each unless listed in `workflows.sweep.structure_exemptions` (exempt paths get a one-line note with their reason). Exact-name matching is not enough -- real-world strays have appeared as `.inbox` and `_outbox-archive`.
   - For every `<vault>/<folder>/_ops.yaml` found in step 1, the folder is treated as ops-aligned. Confirm each parses as YAML; flag any that don't.
   - List ops-aligned folders that are *missing* an `_ops.yaml` only when CLAUDE.md or `_meta.yaml` in that folder declares `organization` -- otherwise the folder is intentionally not ops-aligned and should be silent.
   - If `~/.claude/skills/acme-ops-config/`, `~/.claude/skills/bravo-ops-config/`, or `~/.claude/skills/delta-ops-config/` still exists, emit the deprecation warning from step 1 here as a vault-health item too (one-line each, with the `unlink`/`mv` command to fix).
   - If everything is clean, print a single `Vault health: OK` line. Only expand into a warning list when something is non-conforming.

**Output format:** Structured markdown report:

```
## /ops Configuration Status

### Active Config (current directory)
Organization: Acme
Config source: ~/.claude/skills/acme-ops-config/acme.yaml
Project override: none

### Available Organizations

#### Acme
Language: per_claude_md | Swedish chars: strict
Team: Bob (CEO), Carol (COO), Alex (CAIO), +9 more
Workflows:
  update_files: summary, changelog, readme, task_matrix, meetings_index
  action_propagation: disabled
  agenda_management: disabled
  post_processing: task_import (enabled), dashboard_refresh (enabled, org: acme)
Domain additions: 8 sections configured
Summary sections: default (TWO-TIER)
Strings: default (per language)

#### Bravo
Language: swedish | Swedish chars: strict
Team: Alex (Affärsutveckling), Hank (CTO)
Workflows:
  update_files: summary, changelog
  action_propagation: enabled -> BRAVO.md, ALEX.md, HANK.md
  agenda_management: enabled -> BRAVO.md / "Nästa veckosynk"
  post_processing: disabled
Domain additions: 4 sections configured
Summary sections: default (TWO-TIER)
Templates: meeting_reflection

### Base Defaults
Language: input
Team: (none -- must be defined in org config)
Workflows: summary only

### Vault Health
Vault health: OK
```

When non-conforming, the Vault Health section expands. Examples:

```
### Vault Health
- Stray `_inbox/` at acme/_inbox -- contract requires exactly one at vault root. Move contents to <vault>/_inbox/ and remove.
- Missing `_ops.yaml` in <vault>/acme/ -- folder declares `organization: Acme` but has no _ops.yaml. Drop one in or remove the organization declaration.
- Legacy skill `~/.claude/skills/acme-ops-config/` still present (CR-011, removed in v1.17.0). Run `unlink ~/.claude/skills/acme-ops-config`.
```

---

### `help` -- Show usage guide

**Trigger:** `/ops help`

If the first word is `help`, present a usage guide instead of processing content.

**Include:**
1. One-line description of what /ops does
2. Available commands: `/ops [content]`, `/ops prepare [type]`, `/ops status`, `/ops normalize <path>`, `/ops lint <folder>`, `/ops sweep`, `/ops help`
3. Skill comparison table: when to use /ops vs /ops prepare vs /transcript, /preparation, /tasks, /daily-dashboard
4. Skill connection diagram: how /ops feeds into /tasks, /daily-dashboard, and how /ops prepare creates pre-meeting docs
5. Config loading summary (3-line version, point to `/ops status` for details)
6. Processing flow summary (9 steps, one line each)
7. Common usage patterns (examples including prepare)

**Output:** Markdown printed directly. No files created.

---

### `prepare` -- Create pre-meeting preparation

**Trigger:** `/ops prepare [type] [async-updates]`

Generate a structured preparation document for an upcoming team meeting. Pulls context from recent meetings, tasks, and optionally incorporates pre-submitted async updates from team members.

**Arguments:**
- `type` (optional): Meeting type hint (e.g., `standup`, `war-room`, `weekly`). Default: `standup`
- `async-updates` (optional): Pre-submitted text updates from team members to incorporate

**Examples:**
```
/ops prepare standup
/ops prepare war-room
/ops prepare standup [paste team updates here]
```

#### Preparation modes (single vs dual)

The skill supports two preparation modes, configured per meeting type in `_ops.yaml` under `meeting_types[<type>].preparation_mode`:

| Mode | When to use | Files produced | Filename pattern |
|------|-------------|---------------|------------------|
| `single` (default) | 1-on-1s, marketing meetings, anything where the facilitator and the participants are the same audience or there is no sensitive facilitator-only content | One file | `YYMMDD-preparation-[context]-[type].md` (or `förberedelse` for Swedish) |
| `dual` | Group meetings (standups, weeklies, war rooms) where the facilitator needs a private layer (deflection strategies, time-boxing cues, sensitive probes, policy reminders that should NOT be visible to attendees) on top of the normal team-facing prep | Two files | `YYMMDD-agenda-[context]-[type].md` (visible to team -- the standard prep) + `YYMMDD-facilitator-[context]-[type].md` (private add-on layer) |

**Default is `single`** -- only opt into `dual` when the org explicitly configures a meeting type to need it. If no `meeting_types` config exists, fall back to `single` regardless of `type` argument.

**Dual mode -- two-layer model:**

The agenda file is the team-facing prep document. It looks like the prior-day prep file in that folder -- same shape, same sections, same level of detail. The facilitator file is a *separate* private layer that contains only the additional content the facilitator needs and the team should not see.

**Agenda file** (visible to all attendees) -- mirror the prior-day single-mode prep in the same folder:
- Status overview (per-person yesterday/done/today)
- Key updates from async chat or prior meetings
- Async updates verbatim (if any)
- Agenda items with owners and time-boxes
- Blockers table, decisions pending, open action items carry-forward
- Reference links, build status, metrics
- Anything participants need to come prepared

**Facilitator file** (private, NOT shared with the team) -- contains only the additional layer:
- Facilitator's role clarification (e.g., "Alex runs the meeting only -- not driving test or fix work")
- The lead's expectations from prior handover or 1-on-1s
- Time-box discipline cues ("standup has run 25 min recently, target 30, hard stop 35")
- "Watch for" cues during the meeting (e.g., "Dana defaulting to 'I'll check after standup' on R2 blockers -- push for concrete commitment now")
- "Things NOT to surface in this forum" list (vertical/board topics, personnel matters, etc.)
- Decisions the facilitator owns and the framing for each (esp. when filling in for someone)
- Post-standup follow-ups the facilitator drives
- Pre-meeting backstory from 1-on-1s or lunches with subset of attendees

**Critical rule:** the agenda file does NOT mention or hint at the facilitator file. The visible document must not advertise that a private one exists. Cross-references go from facilitator → agenda only, not the other direction.

**Critical rule:** if the same content fits both files, it goes in the agenda file. The facilitator file should only contain content that would change behaviour or expose sensitive context if shared with the team.

---

#### Step P1: Gather Context

1. **Load org config** (same as normal /ops flow)
2. **Read recent meetings:**
   - Find last 1-3 meeting summaries in the target folder
   - Extract action items assigned to each team member
   - Note decisions made, blockers identified
3. **Read the task ledger** (resolve `workflows.task_ledger` first -- see ops-base, CR-040):
   - `local`: pull active tasks per person from `_tasks.yaml` (status: pending, in_progress, blocked)
   - `external`: read the declared `pointer` if it is reachable; otherwise state in the prep that open
     work lives in `system` and was not read. **Never fall back to an ancestor `_tasks.yaml`**
   - Identify blockers and their owners
4. **Read CHANGELOG.md:**
   - Scan recent entries for context
5. **Triage scan (CR-022):** if the vault has a registered triage doc (`_inbox/` working document, `type: working_doc` + tag `do-not-process`), pull open bullets whose bracket-tag second segment resolves to this meeting's participants (`[Möte · X]`, `[Uppföljning · X]`, ...) into the prep's agenda/open-actions, and stamp each pulled bullet `→ i prep YYMMDD` -- the only write allowed to the triage doc (same rule as `/preparation` Step 2.4). Skip silently when no doc or no matches.

---

#### Step P2: Parse Async Updates (if provided)

If the user provides pre-submitted team updates:

1. **Identify team members** using the name resolution algorithm:
   - Match against org config `team[]` (name, aliases)
   - Match against `_contacts/*/_meta.yaml` (display_name, aliases) for external contacts
   - Matching is case-insensitive with Swedish character folding
   - See [Contact Metadata Schema](../ops-config/contact-meta-schema.md)
2. **Extract per-person updates:**
   - What they report as done
   - What they're working on today
   - Issues/blockers mentioned
   - Decisions or announcements
3. **Correlate with yesterday's tasks:**
   - Match reported items against action items from previous meeting
   - Determine status: DONE, IN PROGRESS, NOT STARTED, NO UPDATE

---

#### Step P3: Generate Preparation Document

Create the file using the **Standup Preparation Template**:

```markdown
# [Organization/Project] [Meeting Type] -- [DD] [Month] [YYYY]

**[Next event note if relevant, e.g., "War room tomorrow: Wednesday March 12, 10:00-12:00 CET"]**

---

## Status Overview

| Person | Yesterday | Done | Today |
|--------|-----------|------|-------|
| **[Name]** | [Tasks assigned] | [What's done] | [Today's plan] |
| ... | ... | ... | ... |

**[Key metric if relevant, e.g., "Test results: 4 PASS / 4 FAIL (50%)"]**

---

## Key Updates

| Update | Source |
|--------|--------|
| [Important update or decision] | [Person] |
| ... | ... |

---

## Agenda

- [ ] 1. **[Person]** -- [Key questions]
- [ ] 2. **[Person]** -- [Key questions]
- [ ] ...
- [ ] N. **[Topic]** -- [Confirm/discuss]

---

## Reported Updates

**[Person]:**
> "[Their exact update text]"

**[Person]:**
> "[Their exact update text]"

...

---

## Blockers

| Issue | Status | Owner |
|-------|--------|-------|
| [Blocker description] | [Status] | [Owner] |
| ... | ... | ... |

---

## Decisions

**Made:**
- [Decision] -- [brief rationale]

**Pending:**
- [Decision needed]

---

# Reference

## [Relevant reference section, e.g., Test Results]

[Tables or details as needed]

## Builds / Versions

- [Current build info]

---

*Created: [YYYY-MM-DD]*
```

---

#### Step P4: Template Variations

**For standup:**
- Focus on Status Overview (Yesterday → Done → Today)
- Keep agenda person-by-person
- Include reported updates if async input provided

**For war-room:**
- Add "Focus Areas" section after agenda
- Include test matrix reference
- Add "Participants" confirmation

**For weekly/planning:**
- Add "Sprint Goals" or "Week Priorities" section
- Include metrics summary
- Add "Carry-over Items" from previous week

---

#### Step P5: Save and Report

1. **Resolve preparation mode:**
   - Look up `meeting_types[<type>].preparation_mode` in the merged org config
   - If absent, default to `single`

2. **Determine filename(s):**

   **Single mode** -- one file:
   - Format: `YYMMDD-preparation-[org/project]-[type].md` (English) or `YYMMDD-förberedelse-[org/project]-[type].md` (Swedish)
   - Include the organization or project name to distinguish preparations created the same day for different orgs/projects
   - Examples: `260311-preparation-acme-mobile-daily-standup.md`, `260311-förberedelse-delta-veckosynk.md`

   **Dual mode** -- two files (always English -- dual mode is not yet localized for Swedish):
   - Agenda file (team-facing): `YYMMDD-agenda-[org/project]-[type].md`
   - Facilitator file (private add-on layer): `YYMMDD-facilitator-[org/project]-[type].md`
   - Examples: `260505-agenda-coreteam-weekly-w19.md` + `260505-facilitator-coreteam-weekly-w19.md`

   **Order of generation:** write the agenda file first using the same template the same folder's prior-day single-mode prep used (status overview, blockers, action items, agenda, references). Then derive the facilitator file as a slim private layer on top -- only the content from the "Facilitator file" list above. If a section is present in both, keep it in the agenda and remove it from the facilitator file.

3. **Save to meetings folder** (per CLAUDE.md MEETING ROUTING). For dual mode, both files go in the same folder.

4. **For dual mode, ensure the cross-references are one-directional:**
   - The facilitator file MUST link to the agenda file at the top with a notice such as: `> **Private facilitator file.** The team-facing version is [YYMMDD-agenda-...md](YYMMDD-agenda-...md). Do not share this file with the team.`
   - The agenda file MUST NOT mention or link to the facilitator file. The visible document must not advertise that a private one exists.

5. **Report what was created:**

   **Single mode:**
   ```
   Created: meetings/260311-preparation-acme-mobile-daily-standup.md

   Status Overview:
   - Dev1: 1 done, 4 in progress
   - ...

   Blockers: 4 items
   Agenda: 7 items
   ```

   **Dual mode:**
   ```
   Created (dual mode):
   - meetings/coreteam/260505-agenda-coreteam-weekly-w19.md (team-facing -- full prep)
   - meetings/coreteam/260505-facilitator-coreteam-weekly-w19.md (private add-on layer)

   Agenda file: status overview (8 people), 10 agenda items, 6 P0 blockers, 13 carry-forward actions
   Facilitator-only layer: 5 items (role clarification, time-box cues, "watch for" list, "do not surface" list, post-meeting follow-ups)
   ```

---

#### Step P6: Lifecycle

After the meeting, when `/ops [transcript]` is run:
- Single mode: the `preparation`/`förberedelse` file is automatically marked as superseded (per Step 9 of normal flow)
- Dual mode: BOTH the `facilitator` and `agenda` files are marked as superseded
- No manual action needed

---

#### Notes

- **No CHANGELOG update** for preparation files (they're pre-meeting)
- **Language:** Follow same rules as normal /ops (per_claude_md, etc.)
- **If no async updates provided:** Generate preparation from historical context only, with empty "Reported Updates" section or skip it
- **If team member missing from updates:** Show "No update" in Status Overview

---

### `normalize` -- Restore Swedish characters in hand-written docs (CR-007)

**Trigger:** `/ops normalize <path> [--dry-run] [--strict-no-ambiguous]`

Lint pass that scans markdown and YAML files for known Swedish character drift (`ar` → `är`, `for` → `för`, `pa` → `på`, `mote` → `möte`, etc.) and restores the correct characters. Use it on hand-written ops documents that bypassed the `/transcript` and `/ops` pipelines and accumulated character errors.

**Use cases:**
- A folder of pasted notes (e.g., `_projects/<client>/ops/*.md`) was created without going through `/ops` and never got a Swedish-character pass
- A legacy file from before CR-007 inheritance was added still contains old drift
- Bulk remediation across a sub-tree

**Arguments:**

| Argument | Meaning |
|---|---|
| `<path>` | A single file OR a folder. If a folder, scans all `.md` and `.yaml` files recursively. |
| `--dry-run` | Show the diff without writing. Use to preview before applying. |
| `--strict-no-ambiguous` | Skip substitutions marked `ambiguous: true` in `swedish_substitutions.yaml` (e.g., `ar` → `är`, `bor` → `bör`, `Andre` → `André`). Recommended for first-pass scans. |
| `--names` | (CR-017) Instead of Swedish characters, normalize person names: apply the org `people[]` roster (aliases → canonical) across the target's `.md` files and CHANGELOG. Reports each substitution for confirmation before writing; never runs implicitly. |
| `--filenames` | (CR-021) Instead of file content, normalize filenames against the slug contract (restore å/ä/ö, fix digit-transliterations like `m0te`, unify date prefix to YYMMDD). Dry-run lists `old → new`; on apply, renames AND updates inbound references found in the same tree (CHANGELOG.md, README.md, supersede stamps, wikilinks). |

**Examples:**

```
/ops normalize _projects/bravo-project/ops/annonsering.md
/ops normalize _projects/bravo-project/ --dry-run
/ops normalize _projects/bravo-project/_insights.yaml --strict-no-ambiguous
```

#### Step N1: Load substitution map

Read `~/.claude/skills/ops-config/swedish_substitutions.yaml`. This file contains the seed substitution list (from MEMORY.md) and is the single source of truth for the linter.

#### Step N2: Scan target file(s)

For each file:

1. **Detect language.** Treat the file as Swedish-context if any of:
   - The file already contains å, ä, or ö characters
   - The file is in a folder configured for Swedish (per CLAUDE.md or `language_inheritance` in base.yaml)
   - The user explicitly passed `--lang sv`
2. **Skip if not Swedish-context** -- this is a Swedish-character normaliser, nothing else
3. **Tokenize the file** while preserving:
   - Code blocks (```...```) -- skip
   - Inline code (`...`) -- skip
   - URLs and file paths -- skip
   - YAML keys (only `value:` parts are scanned, not keys) -- skip keys
   - Lines containing `<!-- no-normalize -->` -- skip the entire line
4. **For each token**, look up against the substitution map. Use word-boundary matching (`\bword\b`).
5. **Skip ambiguous substitutions** if `--strict-no-ambiguous` is set.

#### Step N3: Apply or report

**If `--dry-run`:**
- Print a unified diff to stdout showing all proposed substitutions
- Print a summary: total substitutions, ambiguous skipped, files affected
- Do not write anything

**If not dry-run:**
- Apply substitutions to each file
- Write the file back atomically (write to temp, rename)
- Update or create a `CHANGELOG.md` entry in the file's parent folder (if a CHANGELOG exists):

  ```markdown
  - **YYMMDD: Normalize** [filename] -- restored Swedish characters (N substitutions). -> [file]
  ```

#### Step N4: Report

```
Normalized 4 files, 23 substitutions applied:
  _projects/bravo-project/_insights.yaml         8 substitutions
  _projects/bravo-project/ops/annonsering.md     7 substitutions
  _projects/bravo-project/ops/byrasamarbete.md   5 substitutions
  _projects/bravo-project/ops/c56-krav.md        3 substitutions

Ambiguous substitutions skipped (use without --strict-no-ambiguous to apply):
  ar -> är: 14 occurrences
  bor -> bör: 2 occurrences

Backup: none (use git to revert if needed)
```

#### Notes

- **No backup files written.** Rely on git for revert. If the target is not a git repo, the user is warned and asked to confirm.
- **The substitution list is data, not code.** New common drifts can be added to `swedish_substitutions.yaml` without changing skill code.
- **Defence in depth:** the same substitution map is used by `/insights` pre-write validation (see insights/SKILL.md). The normaliser is the after-the-fact remediation; the validator is the at-write-time gate.

---

### `lint` -- Check existing files against template contracts (CR-018)

**Trigger:** `/ops lint <folder>`

Read-only version of the CR-018 pre-save template-contract check, run across a folder's existing files. Use it to detect **template forking in a recurring series** -- the drift class where each file is internally consistent but the series silently changed shape at some point.

**Steps:**

1. Resolve the contract registry (`workflows.meeting_templates` from the merged config; `default` = CR-006 canonical).
2. For each `YYMMDD-*.md` meeting summary in the folder (skip preps, agendas, emails, `.archive/`): resolve its contract by `match` glob and run the three checks (heading sequence, action-table header row, empty-Beslut marker).
3. **Group findings by series and by first-deviating date** -- the output should read "this series forked at YYMMDD", not a flat per-file list:

```
/ops lint meetings/management

weekly-management (14 files checked):
  OK through 260519. Forked at 260526:
  - action_table: missing column "Prio" (260526, 260605, 260702 -- 3 files)
  - heading "Sammanfattning" (banished) prepended (same 3 files)
  1-on-1 files (22 checked): all OK.

To accept the new shape: declare it in workflows.meeting_templates.
To fix the files: edit manually or re-run /ops on the source transcripts.
```

4. **Never rewrites files.** Lint reports; the user decides between amending the contract (accept the fork as deliberate) and fixing the files.

---

### `sweep` -- Closure/staleness audit (CR-019)

**Trigger:** `/ops sweep [scope]` (default scope: vault root; depth 6; skip `.archive/`, `.transcripts/`, `.handoff/`, `clones/`, `node_modules/`, `.ephemeral/`)

Skills append reliably but never reconcile: indexes lag, ledgers rot, migrations leave live-looking corpses, sent outbox items never get archived. Bookkeeping follows attention, not structure -- so nothing catches the abandoned lane until a human stumbles on it. `/ops sweep` is the missing sweeper: one read-only pass that detects the closure-debt classes and **offers** fixes (report-only by default; every fix is confirmed, never automatic).

**The nine checks:**

1. **Index lag** -- README.md / meetings/README.md whose newest referenced date lags the folder's newest `YYMMDD-*` file or CHANGELOG head entry by >14 days. CHANGELOGs are the heartbeat; READMEs are the lag indicator -- compare them per folder.
2. **Ledger rot** -- `_tasks.yaml` with open tasks whose `last_updated` lags folder activity by >30 days; `_insights.yaml` whose `last_compiled` stamp is absent or >30 days older than its newest entry (compile never ran / is stale).
   **Resolve the ledger mode first (CR-041).** Read `workflows.task_ledger.mode` before judging a missing `_tasks.yaml`:
   - `local` (default): as above, unchanged.
   - `external`: the rot check is **skipped and replaced by two others** -- (a) **incoherent declaration**: `system` or `pointer` absent, or the pointer unresolvable; that is the real failure mode for this shape, and it is silent otherwise. (b) **The duplicate the declaration exists to prevent**: a folder declaring `external` that nonetheless contains a `_tasks.yaml`. Report both as findings with the same weight as rot.
   - `none`: skip.
   `_insights.yaml` staleness is checked in **every** mode -- the knowledge layer is local regardless of where the work is tracked.
   Rationale worth keeping in the report: a *declared* absence is deliberate, an *undeclared* one is indistinguishable from neglect. Reporting a correctly-configured folder as broken every week is worse than not checking it -- the first time the sweep is right and nobody believes it, the check has stopped working.
3. **Migration corpses** -- artifacts that look live but were superseded by a move: root symlinks/files whose same-purpose counterpart elsewhere is fresher (dashboards, `_TODAY-*`); folders inactive >60 days whose participant/topic stream demonstrably continues in a sibling folder. Offered fix: a **tombstone** (see ops-base Retirement Convention).
4. **Outbox aging** -- run the `/outbox list` logic: sent-but-unarchived items, manifest-less items, **manifests missing `Kanonisk källa` (CR-032)**, and items pending >30 days. Offered fix: `/outbox archive --all-sent`. The `Kanonisk källa` finding matters because without it nobody can tell whether a folder is a disposable rendering or the only copy of the material -- which is what made a bulk clean-up unsafe in the 260828 audit (86 items, 3 of 71 manifests named a source).
5. **Sync duplicates** -- `* 2.*` / `* 3.*` files whose base file exists. Report size+mtime comparison side by side; **never auto-delete** (the larger "duplicate" is sometimes the newer content).
6. **Unrouted residue** -- `unsorted/` folders with files >30 days old; `.ephemeral/` content >14 days old; root-level files matching paste conventions (`__*`, `xxx -*`, `Namnlös*`, untitled).
7. **Triage hygiene (CR-022)** -- if a triage doc is registered: INKORG items unsorted >7 days, `[x]` items not yet moved to the KLART archive, week anchor >7 days stale, plaintext-credential-looking lines (no-secrets rule; lines marked `<!-- secret-ok -->` are a recorded owner decision and are skipped). Offered fix: `/inbox triage refresh` (which handles all but the sorting -- that stays human).
8. **Contract alignment & repo privacy (CR-023/CR-029)** -- if `workflows.sweep.alignment_check.command` and/or `workflows.sweep.privacy_scan.command` are configured (maintainer machines only; **absent → skip silently**): run each command (read-only by construction) and parse its `[OK]`/`[DRIFT]`/`[FINDING]`/`[SKIP]` verdict lines. The privacy scan watches the whole public-repo tree continuously — denylist identifiers, secret patterns, and name-like tokens missing from the invented-examples allowlist — so a leak that somehow lands is caught within a week, not at the next audit. Report each `[DRIFT]` component with expected-vs-actual version and a pointer to the update runbook (documented in the alignment script's header). **`[SKIP]` is reported as *unverified*, not clean** -- an unreachable component (e.g. a stale mount) is itself a finding, and has previously hidden six releases of drift. Never auto-applies fixes: cross-repo version references and live deploys are human-confirmed changes. The alignment command stays the single source of truth for the component list; the sweep is the scheduled reader that guarantees its output is actually seen.
9. **Structure conformance (CR-025)** -- enforce the CR-010 single-inbox/outbox rule with a **fuzzy matcher**, because reality drifts through variants that exact-name checks miss: scan for directories matching `_inbox`, `_outbox`, `.inbox`, `.outbox`, any `*inbox*`/`*outbox*`, and localized forms (`inkorg*`/`utkorg*`), case-insensitive. Everything except the vault-root `_inbox/` + `_outbox/` pair is a finding -- **including empty scaffolds** (they re-seed the habit). Paths in `workflows.sweep.structure_exemptions` are skipped with a one-line `(exempt: <path> -- <reason>)` note: deliberate exceptions are recorded once and respected. Offered fixes (never auto-applied): merge pending items into the central folder *via the normal `/inbox`/`/outbox` flows* so manifests and indexes stay true; archive already-resolved material to its destination folder; delete empty scaffolds; or add a `structure_exemptions` entry if the exception is deliberate. Rationale worth repeating in the report: a second outbox means the central pending list lies.

**Output:** one report grouped by class, each finding with its offered fix as a command or concrete action. End with a one-line scoreboard (`9 classes: 5 clean, 3 with findings (14 items), 1 skipped`) so repeat runs are comparable. Young folders are exempt via the age thresholds -- a fresh project reports nothing.

**Wiring:** suitable for a weekly scheduled run that drops its report into `_inbox/` as a triage item (closing the loop through the existing daily-triage habit). The sweep itself never mutates content.

---

## WHEN TO USE /OPS vs /OPS PREPARE vs /TRANSCRIPT

- **`/ops prepare`**: Use **before** a team meeting to create a structured preparation with status tracking. Pulls context from recent meetings and tasks. Optionally incorporates pre-submitted async updates from team members. Outputs one file (`preparation`/`förberedelse`) by default, or two files (`facilitator` + `agenda`) when the meeting type is configured `preparation_mode: dual`.
- **`/ops`**: Use **after** a meeting to process content into structured documentation (summary, changelog, README, task matrix, meetings index, task import, dashboard). Recommended default for all org meetings. Automatically marks any preparation file as superseded.
- **`/transcript`**: Use for ad-hoc recordings, personal calls, or contexts without an ops config. Produces summary + changelog + optional task import only.

**Flow:**
```
/ops prepare standup     → creates preparation (before meeting)
[meeting happens]
/ops [transcript]        → creates summary, marks prep as superseded (after meeting)
```

When `/ops` and `/transcript` both apply, prefer `/ops` -- it is a superset of `/transcript` functionality.

---

## CONFIGURATION

### Config Loading

1. **Determine organization** from:
   - Explicit `organization` field in project CLAUDE.md
   - Project folder name pattern (e.g., `bravo-*` -> bravo, `acme-*` -> acme)
   - Participant names matching team members in configs
2. **Load config** following resolution order:
   - Project-level: `.claude/ops-config.yaml`
   - Folder-local (CR-011): nearest `<folder>/_ops.yaml` walking up from CWD until vault root
   - Vault-wide (CR-011, optional): `<vault-root>/_config/base.yaml`
   - Skill defaults: `~/.claude/skills/ops-config/base.yaml`
   - Deprecated fallback (removed v1.17.0): `~/.claude/skills/{org}-ops-config/{org}.yaml`
3. **Merge layers** -- project overrides folder-local, folder-local overrides vault-wide, vault-wide overrides skill defaults

### What Config Controls

| Setting | Effect |
|---------|--------|
| `language` | Output language (english/swedish/input/per_claude_md) |
| `swedish_chars` | Swedish character enforcement (strict) |
| `team` | Participant recognition and attribution |
| `responsibility_matrix` | Owner assignments |
| `terminology` | Domain-specific terms |
| `summary_sections` | Custom summary structure (overrides TWO-TIER) |
| `status_terminology` | Domain-specific status terms |
| `issue_id_format` | Issue ID pattern |
| `workflows.update_files` | Which files to update |
| `workflows.action_propagation` | Propagate actions to external files |
| `workflows.agenda_management` | Post-meeting agenda updates |
| `meeting_types[<type>].preparation_mode` | `single` (default) or `dual` -- whether `/ops prepare` produces one file or a facilitator/agenda pair |
| `workflows.meeting_templates` | Per-meeting-type shape contracts + lint mode (`warn`/`strict`) -- see ops-base Template Contracts (CR-018) |
| `workflows.post_processing` | Task import, dashboard refresh, and optional priorities artifact (`priorities_artifact.enabled`) after meeting |
| `workflows.rolling_plans` | Participant-triggered per-axis living planning docs (update after a matching 1-on-1) |
| `domain_additions` | Extra sections to add to summaries |
| `templates` | Custom template paths |
| `strings` | i18n string overrides |

---

## PROCESSING FLOW

### Step 0.5: Load Applicable Rules (CR-013)

Before parsing the input, load any promoted **rules** from the `_insights.yaml` chain in scope:

1. **Walk up from CWD** collecting `_insights.yaml` files at each level (max depth 6, skip `.archive/`, `.handoff/`, `clones/`).
2. **Filter to rules:** entries where `confidence: rule` AND `status: active`.
3. **Cap to 20 entries** — if more, prefer highest `confirmation_count`, ties broken by most recent confirmation date.
4. **Build a one-line-per-rule preamble** in the form `[type] summary` and treat it as additional standing instructions for this run. For example:
   - `[preference] Bob prefers concise weekly summaries`
   - `[pattern] Bob raises customer-success topics last in 1-on-1s`
   - `[decision] Board updates use English for India team`
5. **Apply the rules during Step 3 (Create Meeting Summary)** and Step 4 (Apply Domain Additions). Do not echo the preamble in the output; rules influence content, not chrome.

**Scoping:** Only rules in the CWD's parent chain apply. A rule in `meetings/marketing/_insights.yaml` is not loaded when running `/ops` from `meetings/management/`.

**No rules found:** Skip silently. The skill works without rules; this is purely additive context.

### Step 1: Parse Input

Extract from the input (transcript, notes, standup content):
- Participants and their roles -- use name resolution algorithm:
  - Match against org config `people[]` roster (canonical, aliases) for recurring non-contact persons (CR-017)
  - Match against org config `team[]` (name, aliases) for internal team
  - Match against `_contacts/*/_meta.yaml` (display_name, aliases) for external contacts
  - Use resolved canonical names in output (correct spelling, Swedish characters)
  - **Committed-spelling consistency (CR-017):** before saving the summary AND before writing CHANGELOG/README entries, run the folder-precedent near-miss check from `/transcript` ("Committed-spelling consistency" section) -- compare draft names and anomalous proper nouns against the target folder's recent files and CHANGELOG; use the established spelling when it resolves, flag both forms when it doesn't, never silently introduce a spelling variant. CHANGELOGs are how misspellings propagate; this check gates them too.
- Completed work items (who did what)
- In-progress work (current status)
- Decisions made (with rationale)
- Action items (with owners and deadlines)
- Issues/blockers discovered
- Technical updates
- Version/build information (if mentioned)
- Metrics and KPIs (if mentioned)

### Step 2: Determine Summary Format

**If `summary_sections` is defined in config** (non-empty list):
Use the configured section structure. Each section becomes a numbered heading with the specified type (table/subsections/freeform). Only include sections whose trigger condition is met.

**If `summary_sections` is empty or not defined:**
Use the TWO-TIER SUMMARY FORMAT from CLAUDE.md:
- **Concise Operational** for weekly syncs, quick calls, standups
- **Detailed Strategic** for quarterly reviews, major decisions, milestones

### Step 3: Create Meeting Summary

1. Determine date from transcript/content or use today
2. Determine filename and location from CLAUDE.md MEETING ROUTING
3. Build summary using the format from Step 2
4. Include metadata header (date, time, participants, format)
5. Write executive summary (2-3 sentences)
6. Populate all applicable sections
7. Attribute actions to correct people using `responsibility_matrix`

### Step 4: Apply Domain Additions

For each entry in `domain_additions` from config:
- `trigger: always` -- always include the section
- `trigger: if_mentioned` -- include if the topic appears in the input
- `trigger: if_relevant` -- include if contextually appropriate

Append domain-specific sections after the standard summary structure.

### Step 5: Update Files

Update files per `workflows.update_files` from config:

| File key | Target | Action |
|----------|--------|--------|
| `summary` | Meeting summary | Always created (Step 3) |
| `changelog` | CHANGELOG.md | Add dated entry at top |
| `readme` | README.md | Update Current Status, Active Tasks, Recent Meetings |
| `task_yaml` | _tasks.yaml | Update/create per-folder task file (v2 schema). **Skipped entirely when `workflows.task_ledger.mode` is not `local` (CR-040)** |
| `meetings_index` | meetings/README.md | Add entry to meeting index |

For `changelog`, follow the format in ops-base. Always reference the meeting summary file.

### Step 5.5: Knowledge Extraction (silent)

After updating files, scan the meeting summary for durable insights worth accumulating. This step writes to `_insights.yaml` in the same folder as the CHANGELOG -- it is a silent accumulation layer that never surfaces in any skill output.

**Same extraction logic as `/transcript` Step 3.5** (insight types, threshold, format, dedup). See the transcript skill for the full `_insights.yaml` schema and extraction criteria.

**Reusability (CR-020):** Names are allowed in insight entries (the former no-names privacy rule is retired). Prefer name-free phrasing in `summary`/`tags` when the insight generalizes -- `context` and `source.file` carry the who/what; names in `rationale` are always fine. Apply the write-time vocabulary guard from `/transcript` Step 3.5 (canonical types only, `confidence` = `hypothesis|rule`, YYMMDD dates, integer ids, max 5 tags).

**Swedish characters:** When writing Swedish content in `_insights.yaml`, ALL words MUST use correct å, ä, ö. YAML files are equally prone to missing characters.

**Additional ops-specific sources:**
- Strategic decisions from `domain_additions` -> `decision` type
- Cleared agenda items with resolution -> `learning` or `decision` type
- Configuration or workflow changes discussed -> `decision` type

**Process:**
1. Scan the meeting summary (including domain addition sections) for qualifying insights
2. Write to `_insights.yaml` in the same folder as the CHANGELOG
3. Dedup by `source.file` -- if insights from this meeting file already exist, skip

**Skip conditions:**
- No CHANGELOG.md in the target folder
- Pure standup (short status updates without decisions)
- User explicitly said "skip insights"

**Output:** Same brief format as transcript Step 3.5:
```
Extracted [N] insights to _insights.yaml:
- [type] summary sentence
```

### Step 6: Propagate Actions

If `workflows.action_propagation.enabled` is true:
- Decisions -> `targets.decisions` file
- Per-person actions -> `targets.actions_by_person.{name}` file

### Step 7: Manage Agenda

If `workflows.agenda_management.enabled` is true:
- Open the file at `agenda_management.fi

…(truncated)
