Skip to content

vt-c-inbox-qualify

Pre-qualify inbox items and show pending proposals dashboard. Scans intake/pending/ for active proposals, then analyzes inbox articles, categorizes them, and routes to knowledge library, intake proposals, or archive.

Plugin: core-standards
Category: Other
Command: /vt-c-inbox-qualify


/vt-c-inbox-qualify — Knowledge Inbox Pre-Qualification

Pre-qualify raw external knowledge (articles, blog posts, community patterns) dropped into intake/inbox/ for routing into the toolkit's intake pipeline.

When to Use

  • You saved a markdown article and dropped it into intake/inbox/
  • You want to triage accumulated inbox items into the knowledge library or intake proposals
  • You need to qualify external content before it enters the structured intake pipeline
  • You want a quick overview of all pending proposals across intake/pending/ subdirectories

Invocation

/vt-c-inbox-qualify              # Process up to 10 inbox items (default)
/vt-c-inbox-qualify --batch 5    # Process only 5 items

Prerequisites

  • intake/inbox/ directory exists in the toolkit root
  • intake/knowledge/ directory exists with category subdirectories
  • intake/pending/from-research/ directory exists for toolkit proposals
  • intake/pending/from-projects/ directory exists for project proposals
  • intake/pending/from-rca/ directory exists for RCA proposals
  • intake/pending/bugs/ directory exists for bug reports
  • intake/archive/ directory exists for rejected items

Execution Instructions

Step 0: Pending Proposals Dashboard

Scan intake/pending/ subdirectories for active proposals to give the user a complete picture of all actionable items before processing the inbox. This step is read-only — it does not modify, route, or process any files.

  1. Use Bash to list each pending subdirectory:
    ls "intake/pending/from-projects/"
    ls "intake/pending/from-research/"
    ls "intake/pending/from-rca/"
    ls "intake/pending/bugs/"
    
    Filter each to .md files only. Exclude .gitkeep and hidden entries (.backups/).

If a subdirectory does not exist or is inaccessible, skip it silently (EC-010).

  1. For each .md file found, read only the YAML frontmatter (up to the closing ---). Extract: date, severity, target_skill, toolkit_proposal_status, and the first # Heading as title.

  2. Filter out terminal statuses — skip files where toolkit_proposal_status is any of: applied, rejected, rejected-at-gate, qualified, completed, resolved, spec-created, reviewed.

Keep files with proposed, pending, needs-modification, deferred-to-spec, or no status field.

Note: This status filter matches toolkit-review Step 1c (lines 95-105). If new statuses are added to the proposal lifecycle, both locations need updating.

If no active proposals found in any subdirectory:

No pending proposals across intake/pending/.
Proceed to Step 1.

If active proposals found, display:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Pending Proposals: N active across intake/pending/
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

from-projects/ (X)
  YYYY-MM-DD  severity  target_skill  Title from first heading

from-research/ (X)
  YYYY-MM-DD  severity  target_skill  Title from first heading

from-rca/ (X)
  YYYY-MM-DD  severity  target_skill  Title from first heading

bugs/ (X)
  YYYY-MM-DD  severity  target_skill  Title from first heading

→ Process proposals: /vt-c-toolkit-review
→ Triage bugs: /vt-c-triage-bugs
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Omit the item lines for subdirectories with 0 active proposals — show only the header with (0).

  1. Proceed to Step 1 regardless of what was found.

Step 1: Scan Inbox

  1. Use Bash to list the inbox directory:
    ls "intake/inbox/"
    
    Filter results to .md files, excluding .gitkeep.

Do NOT use the Glob tool for this scan — Glob silently excludes filenames containing spaces, causing items to be missed without error.

  1. Count discovered items

If no .md files found:

Inbox empty — nothing to qualify.
Exit cleanly.

If items found, display:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Inbox Scan: N items found
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  1. If --batch N argument provided, limit to first N items
  2. If more than 10 items and no --batch argument, process first 10 and note remainder:
    Processing 10 of N items. Run again to process the rest.
    

Non-markdown files (EC-002): If non-.md files are found in intake/inbox/, warn:

Skipping non-markdown files: [filename.pdf], [filename.txt]
Only .md files are supported.

Step 2: Analyze Each Item

For each inbox item, read and classify:

2a: Read Content

  • Files under 1000 lines: Read the full file
  • Files over 1000 lines (EC-005): Read first 100 lines + last 20 lines

2a-bis: Input Validation

Before processing, validate the file: 1. If YAML frontmatter exists: parse it. If parsing fails (malformed YAML) → classify as archive with note "Malformed YAML frontmatter — skipping to prevent injection" 2. Sanitize any extracted title for slug generation: - Strip path traversal sequences: .., /, \ - Strip shell-dangerous characters: <, >, |, *, ?, ", ', `, $, ;, & - Truncate to 50 characters - Replace spaces with hyphens, lowercase 3. If target_skill is extracted from content: validate it exists in the toolkit's skill manifest (plugins/core-standards/.claude-plugin/skill-symlinks.manifest). If not found → set to tbd with note "target_skill not in manifest" 4. Check for path traversal in any extracted file paths: reject values containing .. or absolute paths outside the toolkit root

2b: Extract Metadata

From the content, extract: - Title: From the first H1 heading (# Title), or from the filename if no H1 found - Source URL: From any URL in the first 10 lines, or empty if not found - Tags: 3-5 keywords extracted from content topics - Summary: One-line AI-generated summary of the article's main point

2c: Classify Relevance

Classify each item into one of three categories based on content analysis:

Classification Criteria Destination
toolkit-proposal Directly actionable for improving the toolkit: new skill patterns, agent improvements, workflow enhancements, security patterns intake/pending/from-research/ + intake/knowledge/{category}/
reference Useful knowledge but not immediately actionable: general AI articles, background reading, techniques that may be useful later intake/knowledge/{category}/
archive Not relevant to the toolkit: unrelated topics, outdated content, duplicates, empty files intake/archive/

2d: Assign Category

For items classified as toolkit-proposal or reference, assign a category:

Category When to Use
patterns Coding patterns, skill patterns, agent patterns, workflow patterns
tools Tool configurations, CLI techniques, IDE integrations, MCP servers
workflows Process improvements, methodology articles, development workflows

If the content doesn't fit these categories (EC-007), note the suggested custom category. The user can approve or override during interactive approval.

2e: Generate AI & Tooling Update Entry

For items classified as reference or toolkit-proposal, check whether the content describes an AI or tooling update relevant to the VisiTrans team. Indicators include:

  • Claude Code features, hooks, permissions, IDE integrations
  • MCP server developments, new tools, protocol changes
  • Claude API changes, Anthropic SDK updates, model releases
  • General AI development tools, SDKs, frameworks
  • Development workflow tooling, CI/CD innovations, automation

If indicators found, use AskUserQuestion: - Yes — Generate update entry → proceed with entry generation below - No — Skip → continue to Step 2f (normal routing)

Entry generation (when confirmed):

  1. Generate slug: YYYY-MM-DD-kebab-title (max 60 chars, lowercase). If a file with that slug already exists in docs/ai-updates/, append -2, -3 etc.

  2. Assign AI update category (one of):

Category When to Use
claude-code Claude Code CLI features, hooks, permissions, IDE integrations
ai-tooling General AI development tools, SDKs, frameworks
mcp Model Context Protocol servers, tools, resources
api Claude API, Anthropic SDK, model releases
workflow Development workflow changes, CI/CD tooling, automation
  1. Commentary prompt — use AskUserQuestion:
  2. Add commentary now → use AskUserQuestion with free-text input to capture the commentary
  3. Edit later in IDE → insert <!-- Add your commentary here --> placeholder

  4. Write entry file to docs/ai-updates/YYYY-MM-DD-slug.md using this template:

---
title: "[Entry Title]"
date: "YYYY-MM-DD"
tags: [tag1, tag2]
category: claude-code
source_url: "https://..."
source_title: "Original Article Title"
---

## Summary

[AI-drafted 2-3 sentence summary of the update from the source content]

## Key Details

- [Key detail 1]
- [Key detail 2]
- [Key detail 3]

## Why Rolf Thinks This Matters

[User's commentary or <!-- Add your commentary here -->]

## Further Reading

- [Source Title](source_url)
  1. Update .index.json: Read docs/ai-updates/.index.json, parse as JSON array, append a new entry object, write back:
{ "slug": "YYYY-MM-DD-slug", "title": "Entry Title", "date": "YYYY-MM-DD", "tags": ["tag1", "tag2"], "category": "claude-code", "summary": "AI-drafted summary", "source_url": "https://..." }

Edge cases for entry generation: - No source URL (EC-1): Use null for source_url in JSON; omit the Further Reading section link but keep source_title if available - .index.json missing (EC-3): Create it with a single-entry array - .index.json malformed (EC-4): Log warning, backup existing file to .index.json.bak, create fresh with the new entry - Long article >1000 lines (EC-6): Generate summary from first 100 + last 20 lines (consistent with Step 2a behavior) - Multiple categories applicable (EC-7): Use the most specific category; capture secondary topics in the tags field

After writing the entry and updating the index, continue with the normal classification routing (Step 2f onward). The item is still routed to intake/knowledge/ or intake/archive/ as usual — the AI update entry is an additional output.

2f: Detect Empty Content (EC-008)

If the file has no substantive content (empty, only whitespace, or only a YAML frontmatter block with no body): - Auto-classify as archive - Note: "No substantive content"

2g: Detect Duplicates (EC-004)

Check if an item with a very similar title already exists in intake/knowledge/:

Grep: pattern="title: [similar-title]" path=intake/knowledge/
If a likely duplicate is found, flag it for user attention in the summary table.

Step 3: Present Summary Table

Display the analysis results for all items:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Qualification Results
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

| # | File | Classification | Category | Summary |
|---|------|---------------|----------|---------|
| 1 | claude-code-patterns.md | toolkit-proposal | patterns | New fork-safe skill pattern for ... |
| 2 | ai-industry-overview.md | archive | — | General AI industry report, no toolkit relevance |
| 3 | mcp-server-guide.md | reference | tools | Guide to building MCP servers with ... |

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

If any duplicates were detected (EC-004), append a warning:

⚠ Possible duplicate: "claude-code-patterns.md" is similar to existing
  intake/knowledge/patterns/2026-02-15-claude-patterns.md

Step 4: Interactive Approval

Process each item one at a time using AskUserQuestion:

Item 1 of N: claude-code-patterns.md
Classification: toolkit-proposal → intake/pending/from-research/ + intake/knowledge/patterns/
Summary: New fork-safe skill pattern for handling permission denials

Use AskUserQuestion: - Approve — Route as proposed - Change category — Keep classification but change category (e.g., patterns → workflows) - Reclassify — Change classification entirely (e.g., toolkit-proposal → reference) - Skip — Leave in inbox for later

If user selects "Change category": Use AskUserQuestion to pick the new category: - patterns - tools - workflows

If user selects "Reclassify": Use AskUserQuestion to pick the new classification: - toolkit-proposal — Will create intake proposal + move to knowledge - reference — Move to knowledge library only - archive — Move to archive

Step 5: Route Approved Items

For each approved item, execute the routing:

5a: Add Qualification Frontmatter

For items WITHOUT existing YAML frontmatter:

Prepend frontmatter to the file content:

---
title: "[extracted title]"
date_saved: "YYYY-MM-DD"
qualified_date: "YYYY-MM-DD"
source_url: "[extracted URL or empty]"
category: [assigned category]
relevance: [toolkit-proposal | reference | archive]
tags: [extracted, keyword, tags]
summary: "[AI-generated one-line summary]"
---

[original content unchanged]

For items WITH existing YAML frontmatter (EC-001):

Preserve all existing fields. Add only the missing qualification fields: - qualified_date - category - relevance - summary - tags (merge with existing tags if present)

Never overwrite existing values.

5b: Route the File

Use git mv to move the file to its destination (NF-002 — preserves git history):

toolkit-proposal:

git mv intake/inbox/[filename] intake/knowledge/[category]/[filename]

reference:

git mv intake/inbox/[filename] intake/knowledge/[category]/[filename]

archive:

git mv intake/inbox/[filename] intake/archive/[filename]

CRITICAL: Before running git mv, check for uncommitted changes to the target file. If the file was just modified (frontmatter added), stage the changes first:

git add intake/inbox/[filename]
git mv intake/inbox/[filename] [destination]

5d: Update Knowledge Index (SPEC-071)

After routing to intake/knowledge/{category}/, update the knowledge index so the new document is immediately discoverable:

  1. Create .summaries/ directory if it doesn't exist:

    mkdir -p intake/knowledge/{category}/.summaries
    

  2. Read the newly routed document and parse its frontmatter (added in Step 5a)

  3. Generate summary JSON per SPEC-070 schema:

  4. Extract key topics from H2 headings (up to 8)
  5. Detect document type (transcript if 3+ **[MM:SS] speaker patterns found)
  6. Build summary with: version, generated_at, source_file, document_type, title, author, date_saved, category, relevance, tags, summary, key_topics, word_count, deep_evaluated (false), frontmatter_present
  7. Write to intake/knowledge/{category}/.summaries/{filename_without_ext}.json

  8. Update category index:

  9. Read existing {category}/index.json (or create new if first document)
  10. Add entry for the new document
  11. Sort documents by date_saved descending
  12. Regenerate {category}/index.md from index.json

  13. Update top-level index:

  14. Read existing intake/knowledge/index.json
  15. Update the category's count, top_tags (top 3 by frequency), and recent (most recent filename)
  16. Regenerate intake/knowledge/index.md

  17. Stage generated files:

    git add intake/knowledge/{category}/.summaries/ intake/knowledge/{category}/index.json intake/knowledge/{category}/index.md intake/knowledge/index.json intake/knowledge/index.md
    

Skip this step for items routed to intake/archive/.

5c: Create Intake Proposal (toolkit-proposal only)

When an item is classified as toolkit-proposal, also create a proposal file:

intake/pending/from-research/YYYY-MM-DD-inbox-[slug].md

Where [slug] is a kebab-case version of the article title (max 50 chars).

Use the standard intake proposal frontmatter format:

---
type: research-finding
date: YYYY-MM-DD
source: inbox-qualify
source_path: intake/knowledge/[category]/[filename]
target_skill: "[identified from content analysis, or tbd]"
severity: medium
category: new-pattern
toolkit_proposal_status: proposed
tags: [from, qualification, analysis]
---

# Proposal: [Title from article]

**Source**: intake/knowledge/[category]/[filename]
**Type**: research-finding
**Priority**: [HIGH | MEDIUM | LOW based on analysis]

## Finding

[Summary of what the article describes and why it's relevant to the toolkit]

## Suggestion

- [Specific action 1]
- [Specific action 2]

## Action

- [ ] Review
- [ ] Implement

Step 6: Summary Report

After all items are processed, display:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Inbox Qualification Complete
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Processed: N items
• Toolkit proposals: X → intake/pending/from-research/
• Reference: Y → intake/knowledge/
• Archived: Z → intake/archive/
• Skipped: W (remaining in inbox)

Remaining in inbox: M items

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
NEXT STEPS:
• Deep evaluate: /vt-c-content-evaluate --scan-knowledge
• Review proposals: /vt-c-toolkit-review --status
• Implement approved proposals: /vt-c-research-implement
• Process remaining inbox: /vt-c-inbox-qualify
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Edge Cases Reference

ID Scenario Handling
EC-001 Item already has YAML frontmatter Preserve existing, merge qualification fields (Step 5a)
EC-002 Non-markdown file in inbox Skip with warning (Step 1)
EC-003 Inbox is empty Display "Inbox empty" and exit (Step 1)
EC-004 Duplicate content detected Flag in summary table, let user decide (Step 2g, Step 3)
EC-005 File exceeds 1000 lines Read first 100 + last 20 lines (Step 2a)
EC-006 Processing interrupted mid-run Already-routed items stay routed; unprocessed remain in inbox
EC-007 Category doesn't match predefined set Allow custom category via AskUserQuestion (Step 4)
EC-008 Empty or template-only file Auto-classify as archive: "No substantive content" (Step 2f)
EC-009 Filenames with spaces Use Bash ls instead of Glob tool — Glob silently excludes these files (Step 1)
EC-010 Pending subdirectory missing or inaccessible Skip that subdirectory silently in Step 0

Integration Points

Skill Relationship
/vt-c-content-evaluate Deep evaluation of classified items for actionable patterns
/vt-c-research-ingest Also scans intake/inbox/ as a fourth source (FR-008)
/vt-c-toolkit-review Reviews proposals generated by this skill
/vt-c-research-implement Implements approved proposals
docs/ai-updates/ AI update entries generated during qualification (Step 2e)
/vt-c-triage-bugs Processes bugs shown in Step 0 dashboard

Troubleshooting

"git mv" fails

If git mv fails with "not under version control": 1. Run git add intake/inbox/[filename] first 2. Then retry git mv

If git mv fails with "destination exists": 1. The target file already exists in the destination 2. This may indicate a duplicate — ask the user whether to overwrite or skip

Context limits with many large files

If processing many items causes context issues: 1. Use --batch 3 to reduce the number of items processed 2. Process large files individually 3. Run multiple times to clear the backlog

Open Brain Capture (Optional)

After qualifying inbox items, if the capture_thought MCP tool is available, capture the qualification summary.

When to capture: After every completed qualification batch.

How: 1. Check if capture_thought tool is available. If not: skip silently. 2. If no items were processed: skip capture. 3. Call capture_thought with:

thought: "Inbox qualification: {N} items processed. Routed: {N} to knowledge, {N} to intake proposals, {N} archived. Key item: {most relevant article title and category}."
4. On timeout or error: log debug message and continue. Never fail the skill.