Skip to content
Back to skills

Inbox

ASecurity

Universal entry point for unstructured content. Classifies, stores in _inbox/, and hands off to the appropriate downstream skill.

  • 4 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added August 31, 2026
documentationgogitapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned October 1, 2026

npx -y skills add tandregbg/core-claude-skills --skill inbox --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Inbox?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Inbox
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tandregbg-inbox/badge)](https://www.skillsdirectory.com/skills/tandregbg-inbox)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: inbox
description: Universal entry point for unstructured content. Classifies, stores in _inbox/, and hands off to the appropriate downstream skill.
user-invocable: true
argument-hint: [content, file path, or subcommand: status|process [id|all]|triage [refresh|status]|help]
---

# Inbox Skill

Universal capture and classification for unstructured content. Accepts voice memos, quick notes, raw text, forwarded emails -- classifies and routes to the appropriate downstream skill.

## Vault Location

```
vault/_inbox/
  _inbox.yaml           # Derived index (rebuilt from frontmatter)
  YYMMDD-HHMMSS[-slug].md   # Active items (frontmatter is canonical)
  .audio/               # Raw audio captured by Trillian, paired by basename
    YYMMDD-HHMMSS[-slug].m4a
  .files/               # File drops: input files with a vault destiny (CR-024)
    YYMMDD-HHMMSS[-slug].<ext>
  .archive/             # Processed items (moved here after downstream skill runs)
    .audio/             # Audio archived alongside transcript
    .files/             # Source files that don't accompany their output
```

**Schema**: see [`docs/schemas/inbox.md`](../../docs/schemas/inbox.md) for
the canonical `<id>.md` frontmatter shape, `.audio/` convention, and
lifecycle states. The schema is the source of truth; this SKILL.md
documents skill behaviour. Other tools (Trillian, Deep Thought, Marvin,
external skills) write directly to `_inbox/` against the schema; `/inbox`
is one of several producers.

## Subcommands

**Renamed in v1.79.0 (CR-089); `/inbox process` was removed in v1.81.0.** An old name is not recognised: say that it is now `/inbox route`, and do not run it.

### `/inbox [content]` -- Default: Capture + Classify

Accept raw content (pasted text, file path, or inline text), classify it, store in `_inbox/`, and suggest the downstream skill.

**Processing flow:**

1. **Parse input** -- detect content type:
   - Multiple speakers, timestamps, speaker labels -> `voice_memo`
   - "From:", "Subject:", email headers -> `email`
   - File path provided -> read the file, detect type from content
   - **Binary or non-markdown file path** (PDF, CSV/xlsx, image, media, archive) -> `file_drop` (CR-024): move/copy the file into `_inbox/.files/<id>.<ext>` and create the paired stub with `source.file_path` and a type-based classification guess (PDF/document → summarize into a folder; CSV/xlsx → project data; image/media → attachment). Files >~25 MB: flag the size and offer process-in-place + reference-stub archiving instead of moving the blob. Full convention in [`docs/schemas/inbox.md`](../../docs/schemas/inbox.md) "File drops".
   - Short text, no structure -> `quick_note`
   - Everything else -> `raw_text`

2. **Auto-classify** -- determine which downstream skill should process this:

   | Signal | Classification | Target Skill |
   |--------|---------------|-------------|
   | Speaker labels, timestamps, dialogue format | `transcript` | `/transcript` |
   | Org team member names (from ops-config), meeting context | `ops` | `/ops` |
   | **Sender header, no dialogue: a report, newsletter, automated digest, or any mail whose value is its content rather than an exchange** | `content` | `/ops process` (writes a `content` file, **not** a summary — CR-105) |
   | **A thread: someone wrote, you replied, they replied again** | `correspondence` | `/ops process` (writes a `correspondence` file — CR-080) |
   | "TODO", "remind me", imperative sentences, action items | `task` | `/tasks add` |
   | Short observation, no action context | `note` | None (already saved) |
   | Idea, brainstorm, "what if" | `idea` | Appended to an `_ideas.md` -- see step 6 |

   Assign confidence: `high` (clear signals), `medium` (some signals), `low` (ambiguous).

   **`content` vs `transcript` (CR-105).** Step 1 detects `email` as a content *type*; this is
   where it goes. The distinction is not the channel but the shape: a transcript lost its
   structure and the pipeline recovers it (who spoke, how names are spelled), while incoming
   material arrives structured — it has a **sender, not participants**, and no facilitator.
   Routing it as a meeting invents an event that never happened. A mail that *is* an exchange
   between people about a decision is **correspondence**, the row below (CR-080, revived
   2026-10-01). The test between them is simply whether anyone replied.

3. **Determine routing** -- consult CLAUDE.md MEETING ROUTING for folder suggestions:
   - Match participant names using the name resolution algorithm:
     - Check `_contacts/*/_meta.yaml` for `display_name` or `aliases` match
     - Check config `team[]` for internal team members
     - Matching is case-insensitive with Swedish character folding
   - Identify org context from ops-config team lists
   - Suggest target folder (e.g., `_contacts/david-ekberg/`, `acme/meetings/management/`)
   - See [Contact Metadata Schema](../ops-config/contact-meta-schema.md) for name resolution details

4. **Confirm with user** -- present classification + routing summary:
   ```
   Classification: transcript (high confidence)
   Target skill: /transcript
   Target folder: _contacts/david-ekberg/

   OK to proceed? (or override)
   ```
   Wait for user confirmation or override. Keep it brief -- one question, then go.

5. **Store in `_inbox/`**:
   - Write content to `_inbox/YYMMDD-HHMMSS[-slug].md` with frontmatter per [`docs/schemas/inbox.md`](../../docs/schemas/inbox.md)
   - Set `id`, `created`, `classification`, `confidence`, `status: pending`, and routing fields in frontmatter
   - Rebuild `_inbox.yaml` index from the new frontmatter
   - If the input was paired audio, set `source.audio_path` and ensure the audio is at `_inbox/.audio/<id>.m4a`

6. **Execute the downstream skill automatically:**
   - `transcript` -> Run `/transcript` with the content, passing the target folder
   - `ops` -> Run `/ops` with the content, passing the config
   - `task` -> Run `/tasks add [extracted description]`
   - `note` -> Already saved, no downstream skill needed
   - `idea` -> **Append one line to an `_ideas.md`** (see "Ideas" below) instead of leaving an orphan item in `_inbox/`
   - **Do NOT just print instructions** -- actually invoke the skill and let it run
   - The downstream skill handles all its own processing (summary, changelog, task import, insights, history)

7. **Archive the inbox item** after the downstream skill completes:
   - Set frontmatter `status: processed`, `processed_at` to now (ISO 8601), `processed_by` to the downstream skill name, `output_file` to its output path
   - Move the .md file to `_inbox/.archive/<id>.md` and set `archived_to`
   - If paired audio exists, also move `_inbox/.audio/<id>.m4a` to `_inbox/.archive/.audio/<id>.m4a`
   - Rebuild `_inbox.yaml` to reflect the new state

### Ideas

An `idea` is the owner's own thinking, not someone else's input. It gets **one line appended
to an `_ideas.md`** -- no inbox item, no frontmatter, no archive cycle, no task.

**Which file:**

| The idea names | Append to |
|---|---|
| A project with its own `_ideas.md` | that project's file |
| An organisation with one at its root | that org's file (e.g. `<org>/_ideas.md`) |
| Nothing placeable | **`_inbox/_ideas.md`** -- the default |

**Rules:**
- **Append verbatim, one line.** Do not reword, expand, classify or add a date unless the
  owner wrote one. The value of the surface is that writing costs nothing.
- **Never create an `_ideas.md` that does not exist** -- fall back to `_inbox/_ideas.md`.
  New files are the owner's decision, not the skill's.
- **Never route an idea into a project's task ledger, an issue tracker or a changelog.**
  These files exist precisely because they have no automatic input into project work; an
  idea becomes a task only when the owner writes it into `_capture.md` themselves.
- **Do not ask which file** when the content places itself. One line, done -- a confirmation
  prompt costs more than the filing saves.

**When unsure, use the default.** `_inbox` is a door, not a home: an idea can be routed out
later, and a wrong guess is worse than an unsorted one.

### `/inbox status` -- Show Inbox State

Display counts by status (per [schema](../../docs/schemas/inbox.md)):
```
Inbox Status:
  pending:    3 items
  processing: 1 item
  processed:  5 items (will archive on next process run)
  skipped:    1 item
  archived:   12 items (in .archive/)
  ---
  Active:     4 items (pending + processing + skipped)
  Orphan audio: 1 file (audio in .audio/ with no matching .md yet)
```

Also show classification breakdown of active items, flag any orphan
audio waiting in `.audio/` for a matching transcript, and flag orphan
**file drops** in `.files/` with no paired stub (offer to register them,
CR-024).

### `/inbox route [id|all]` -- Route stored items to their skill (was `process`)

Process one item by ID, or all unprocessed items (status `new` or `classified`) with `all`.

**Single item (`/inbox route <id>`):**

1. Read the item's frontmatter and body from `_inbox/<id>.md`
2. If `classification` is missing or `confidence: low`, run classification (Step 2 from default flow); update frontmatter
3. Show classification and target, ask user to confirm or override
4. Set frontmatter `status: processing`
5. **Execute the downstream skill** -- actually run `/transcript`, `/ops`, or `/tasks add` as appropriate
6. After the downstream skill completes, update frontmatter:
   - `status: processed`, `processed_at`, `processed_by`, `output_file`
7. Move `<id>.md` to `_inbox/.archive/<id>.md` (and paired audio to `.archive/.audio/<id>.m4a` if present); set `archived_to`
   - **File drops (CR-024):** the source file in `.files/` moves WITH the output -- to the target folder's `.attachments/` when it should accompany the content (ask if unclear), else to `_inbox/.archive/.files/<id>.<ext>`. Record the final path in the stub before archiving it.
8. Rebuild `_inbox.yaml` from current frontmatter

**All items (`/inbox route all`):**

1. Glob `_inbox/*.md`, read each frontmatter, filter to `status: pending` or `processing`. **Skip working documents** (registered `type: working_doc` / tag `do-not-process` per the [schema](../../docs/schemas/inbox.md) CR-022 section) -- they are surfaces, not captures
2. If no items to process, report "Inbox is empty" and stop
3. Read and classify all items, then present a single confirmation table:
   ```
   | ID                       | Title          | Classification | Target      | Folder              |
   |--------------------------|----------------|----------------|-------------|---------------------|
   | 250428-091803-bob        | samtal med bob | transcript     | /transcript | _contacts/bob/      |
   | 250428-103044-sara       | samtal med sara| transcript     | /transcript | _contacts/sara/     |
   ```
   Ask: "Process all? (or list IDs to skip/override)"
4. **Execute each item sequentially** -- for each confirmed item:
   a. Set frontmatter `status: processing`
   b. Run the downstream skill with the body content and target folder
   c. Let the skill complete its full processing (summary, changelog, tasks, insights)
   d. Update frontmatter: `status: processed`, `processed_at`, `processed_by`, `output_file`, `archived_to`
   e. Move `<id>.md` to `.archive/`; move paired audio (if any) to `.archive/.audio/`
   f. Brief status line: "Item 250428-091803-bob done -- processed as transcript -> _contacts/bob/"
5. Rebuild `_inbox.yaml` once at the end
6. Print final summary: "Processed N items, M archived, K orphan audio still pending"

**Key principle:** `/inbox route` is an automation pipeline, not a suggestion engine. It actually runs the downstream skills. Human-in-the-loop is limited to:
- Confirming the classification table before execution begins
- Any validation questions the downstream skill itself needs (e.g., `/transcript` may ask about participants, `/ops` may ask about config) -- pass these through to the user as they come up

### `/inbox triage [refresh|status]` -- Triage working-surface upkeep (CR-022)

Operates on the vault's registered **triage doc** (see the
[schema](../../docs/schemas/inbox.md) CR-022 section: an `_inbox/` working
document with `type: working_doc`, `status: keep`, tag `do-not-process`).
If no triage doc is registered, say so and stop -- this subcommand never
creates one uninvited (offer to register an existing file if the user asks).

**Design principle (blocking): mechanical upkeep only.** Never reorder,
reword, re-bucket, or classify items. Sorting INKORG is the human's
thinking step, not the skill's.

**`refresh`** (default):

1. **Week anchor:** update the `Veckoankare:` line's date and week number to
   today. Preserve the standing-context text after them verbatim -- only the
   date/week tokens change. If bucket headings carry week numbers
   (e.g. `DENNA VECKA (v.26)`), update those tokens too.
2. **Archive done items:** move every `[x]` bullet (with its sub-bullets) to
   `_inbox/.archive/YYMMDD-triage-klart.md` -- create with a `# KLART-arkiv`
   header if missing, append under a `## YYMMDD` heading, keep the bullet
   text verbatim plus a `(arkiverad YYMMDD)` suffix.
3. **Report INKORG age:** list INKORG items that have sat unsorted >7 days
   (report only -- sorting is the human's job).
4. **Flag plaintext credentials:** scan for password/API-key-looking lines
   (per the schema's no-secrets rule) and report them with the
   recommendation to replace with a password-manager reference. Never
   auto-remove. **Skip lines ending in `<!-- secret-ok -->`** — that marker
   is the owner's recorded decision to keep the credential inline; offer to
   stamp it when the user says a flagged line should stay.
5. **Report:** one summary line per action class (anchor updated, N items
   archived, M INKORG items aging, K credential flags). Show the diff of
   what moved.

**`status`:** read-only -- items per section, INKORG count + oldest item
age, `[x]` items awaiting archive, week-anchor date vs today, link to the
KLART archive.

**Optional external mirror (CR-017).** A vault MAY point the triage doc at an
external actions surface (e.g. a task app) for a focused *today/tomorrow* view.
This is a **local, per-vault integration** -- its script, credentials, and
target IDs live outside this repo (a local script dir + a gitignored secret;
a config pointer under the vault's own config layer). Two directions, both
**human-gated**, mirroring the mechanical-upkeep principle above:

- **push** -- mirror the current actionable *today/tomorrow* items outward,
  after showing a preview. One-way, additive, deduped against what's already
  there. It never invents dates: an item ships only if the line itself marks
  it today/tomorrow.
- **reconcile** -- read the external surface back and, for items completed
  there, **propose** marking the matching triage line `[x]`; the human
  approves before anything is written. Never an automatic merge -- the triage
  doc stays the system of record, consistent with "sorting is the human's
  step, not the skill's."

This skill documents the *contract* (gated push + gated reconcile, secret-free,
triage-path read from the registered `file:`); it ships **no** provider code.

### `/inbox help` -- Usage Guide

Print this usage guide:

```
/inbox [content]        Capture, classify, and route content
/inbox status           Show inbox counts by status
/inbox route [id|all] Process one or all stored items
/inbox triage [refresh|status]  Triage working-surface upkeep (CR-022)
/inbox help             This help text

Content types detected: voice_memo, email, quick_note, raw_text, clipboard
Classifications: transcript, ops, task, note, idea

Items are stored in vault/_inbox/ and tracked in _inbox.yaml.
After processing with the downstream skill, items are archived.
```

## `_inbox.yaml` -- derived index

`_inbox.yaml` is a derived index, rebuilt from the frontmatter of every
`_inbox/*.md`. It exists for fast batch listing (Marvin, `/inbox status`)
without parsing every markdown file.

The canonical metadata for any single item lives in that item's
frontmatter, not here. If frontmatter and index disagree, frontmatter wins.

`/inbox` rebuilds the index on every `status` or `process` invocation.
External tools writing items directly into `_inbox/<id>.md` MAY also append
to the index, but they are not required to -- the next `/inbox` call picks
up new files from frontmatter automatically.

See [`docs/schemas/inbox.md`](../../docs/schemas/inbox.md) for the index
schema (`version: 2`, post-CR-012). v1 files are detected and rewritten
lazily on first run.

## Content File Format

Markdown with **YAML frontmatter** (canonical metadata) and a body. See
[`docs/schemas/inbox.md`](../../docs/schemas/inbox.md) for the full
frontmatter spec.

Filename: `YYMMDD-HHMMSS[-slug].md` where:
- `YYMMDD-HHMMSS` is creation timestamp (vault-local)
- `slug` is optional, kebab-case, derived from a short title

Minimal valid frontmatter:

```yaml
---
id: 250428-091803
created: 2026-04-28T09:18:03+02:00
status: pending
---
```

`/inbox` populates additional fields (classification, target_skill,
target_folder, confidence) when the item is classified.

## Integration

- **Reads** ops-config for team member recognition and org routing
- **Reads** CLAUDE.md MEETING ROUTING for folder suggestions
- **Reads** `_contacts/` folder structure for participant matching
- **Executes** downstream skills (`/transcript`, `/ops`, `/tasks`) -- not just suggestions
- **Marvin** (formerly core-skills-visualisation) provides a web UI for the same data (create, view, classify, archive)
- **Trillian** (vault-pulse) writes raw audio to `_inbox/.audio/` and frontmatter-only stub markdown to `_inbox/<id>.md`; the matching transcript arrives later from Deep Thought
- **Deep Thought** writes transcript markdown back to `_inbox/<id>.md` with `source.external_id` set to the DT job id

## Archive Policy

Follows the core-skills archive pattern: never delete, always archive.
- Processed markdown moves to `_inbox/.archive/<id>.md`
- Paired audio (if any) moves to `_inbox/.archive/.audio/<id>.m4a`
- The pairing-by-basename rule is preserved across the move
- `_inbox.yaml` retains the item entry with `status: processed` and `archived_to` set
- Archive is browsable but not shown in active views
- Retention for archived audio is user-configurable (default: keep indefinitely; future `/inbox prune --older-than Nd` will reclaim space)

## Rules

- Confirm classification with user before executing -- one brief confirmation, then go
- **Execute downstream skills automatically** after confirmation -- do not just print instructions
- Minimize questions -- classify, confirm, execute, archive. No back-and-forth.
- **Frontmatter is canonical**; `_inbox.yaml` is a derived index. If they disagree, frontmatter wins.
- Use the `YYMMDD-HHMMSS[-slug]` identifier format (per [schema](../../docs/schemas/inbox.md))
- One content file per inbox item; pair with `.audio/<id>.m4a` if audio captured
- Items created via Marvin web UI, Trillian, or Deep Thought follow the same schema
- After downstream skill completes, archive the inbox item automatically (and its paired audio)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.