# Context Manifest

> Lines 904-911 in NamespaceReferenceValidator contain unreachable nested skill reference resolution after early return line 903. Verify with coverage before removal.

- Skill: `tools-only/context-manifest` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add tools-only/context-manifest`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/context-manifest/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-29
- Page: https://skillmd.com/skills/tools-only/context-manifest

---


## Context Manifest

_Generated by context-gathering agent on 2026-02-13_

### How This Currently Works: Plugin Validation Architecture

The plugin_validator.py (3045 lines) implements a protocol-based validation framework with 9 existing validators that check skills, agents, commands, and plugin structure. When a file is validated:

1. **File Type Detection** (lines 147-165): `FileType.detect_file_type()` classifies files into 5 types (SKILL, AGENT, COMMAND, PLUGIN, UNKNOWN) based on filename and path patterns
2. **Validator Selection** (lines 2896-2913): Hard-coded dispatch selects validators per file type - skills get 7 validators, agents get 4, commands get 4, plugins get 1
3. **Single-File Read** (optimization needed): Currently multiple validators may re-read same file - architecture spec requires reading once and passing content to all validators (lines 814-836 of architecture spec)
4. **Validation Execution**: Each validator implements the Validator protocol (lines 249-286) with `validate(path: Path) -> ValidationResult`, `can_fix() -> bool`, `fix(path: Path) -> list[str]`
5. **Result Aggregation** (lines 2865-2951): Collects ValidationResult objects from all validators
6. **Report Generation** (lines 2599-2858): Three reporter implementations (Console, CI, Summary) format and display results

**Data Models** (lines 168-242):

- `ValidationIssue` (frozen dataclass): field, severity, message, code, line, suggestion, docs_url
- `ValidationResult` (frozen dataclass): passed, errors, warnings, info
- `ComplexityMetrics` (frozen dataclass): total_tokens, frontmatter_tokens, body_tokens, encoding

**Token-Based Complexity** (lines 1939-2122): ComplexityValidator uses tiktoken library (cl100k_base encoding) to count tokens instead of lines. Thresholds: 4000 tokens warning (SK006), 10000 tokens error (SK007). Architecture at lines 44-45 defines these constants.

**Pydantic Schema Validation** (lines 1030-1236): Three frontmatter models:

- `SkillFrontmatter` (10 fields, all optional, normalizes CSV fields)
- `CommandFrontmatter` (7 fields, description required, normalizes CSV)
- `AgentFrontmatter` (9+ fields, name+description required, uses camelCase per official schema)

**Validation Flow per Validator:**

1. **FrontmatterValidator** (lines 1243-1600): Extracts YAML frontmatter, validates with Pydantic model, converts Pydantic errors to ValidationIssues, auto-fixes YAML arrays→CSV, multiline→single-line, removes name field from plugin skills (Claude Code bug workaround lines 1541-1560)
2. **NameFormatValidator** (lines 1603-1787): Checks name pattern `^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$`, no auto-fix
3. **DescriptionValidator** (lines 1790-1936): Checks min 20 chars (SK004), requires trigger phrases (SK005) from REQUIRED_TRIGGER_PHRASES constant (lines 56-64), no auto-fix
4. **ComplexityValidator** (lines 1939-2122): Uses tiktoken to count tokens, splits frontmatter vs body, no auto-fix
5. **InternalLinkValidator** (lines 448-631): Regex extracts markdown links, checks file existence, ignores code blocks (lines 468-490), no auto-fix
6. **ProgressiveDisclosureValidator** (lines 334-441): Checks for references/, examples/, scripts/ directories, INFO severity only, no auto-fix
7. **NamespaceReferenceValidator** (lines 638-1023): Parses namespace-qualified references (Skill(), Task(), @agent, /command), resolves from settings.json, checks target file exists, no auto-fix
8. **PluginStructureValidator** (lines 2125-2414): Validates plugin.json schema, runs `claude plugin validate` CLI if available (lines 2421-2500), no auto-fix

**Known UX Bugs:**

- Lines 2681-2709: ConsoleReporter counts ValidationResult objects not unique files (shows "7 files" for 1 file with 7 validators)
- Lines 904-911: Dead code in NamespaceReferenceValidator after early return (need coverage verification before removal)
- Line 1802: DescriptionValidator fires SK005 on commands (commands don't need trigger phrases since explicitly invoked)

**Error Code Registry** (lines 71-109): 23 existing codes across 6 categories:

- FM001-FM010: Frontmatter errors (10 codes)
- SK001-SK007: Skill errors (7 codes)
- LK001-LK002: Link errors (2 codes)
- PD001-PD003: Progressive disclosure (3 codes)
- PL001-PL005: Plugin errors (5 codes)
- NR001-NR002: Namespace reference errors (2 codes)

### For New Feature Implementation: Hook/MCP/LSP Configuration Validation

**Architecture Requirements** (architect-plugin-linter.md):

Need to add 4 new FileType variants (lines 85-130 of architecture):

- `HOOK_CONFIG` - Detects `hooks.json` exact filename
- `MCP_CONFIG` - Detects `.mcp.json` exact filename
- `LSP_CONFIG` - Detects `.lsp.json` exact filename
- `HOOK_SCRIPT` - Detects `hooks/*.{js,py,sh}` directory pattern

**Detection Priority** (architecture lines 105-130):

1. Exact filename matches (hooks.json, .mcp.json, .lsp.json)
2. Special filenames (SKILL.md, plugin.json)
3. Directory-based (agents/, commands/, hooks/)
4. UNKNOWN fallback

**New Pydantic Models Required** (architecture lines 135-312):

**HookConfig Schema** (architecture lines 135-194, official source: <https://docs.anthropic.com/en/docs/claude-code/hooks.md>):

- 15 valid event types: SessionStart, UserPromptSubmit, PreToolUse, PermissionRequest, PostToolUse, PostToolUseFailure, Notification, SubagentStart, SubagentStop, Stop, TeammateIdle, TaskCompleted, PreCompact, SessionEnd, ToolUseFailure
- 3 hook types: COMMAND (shell execution), PROMPT (LLM injection), AGENT (sub-agent invocation)
- Discriminated union on type field - command/prompt/agent fields required based on type
- Matcher field contains regex pattern (must validate compilation without execution)
- Timeout field must be positive integer if present

**MCPConfig Schema** (architecture lines 196-222, official source: <https://modelcontextprotocol.io/docs/server>):

- Required: command (non-empty string)
- Optional: args (list of strings NOT single string), env (dict[str, str]), cwd (directory path)
- Validation: command existence check with shutil.which() as WARNING only (may not exist at validation time)

**LSPConfig Schema** (architecture lines 224-265, official source: <https://docs.anthropic.com/en/docs/claude-code/plugins.md#lsp-servers>):

- Required: command (non-empty string), extensionToLanguage (non-empty dict)
- Extension keys must start with dot (.py not py or *.py)
- Language values must be lowercase identifiers
- Transport: stdio or socket only
- Timeouts must be positive integers
- maxRestarts must be positive

**AgentFrontmatter Enum Enhancement** (architecture lines 267-312):

Existing AgentFrontmatter model (lines 1167-1235) needs 3 new enum validations:

- `model` field: Add AgentModel enum (sonnet, opus, haiku, inherit)
- `permissionMode` field: Add AgentPermissionMode enum (6 values including default, acceptEdits, dontAsk, etc.)
- `memory` field: Add AgentMemory enum (user, project, local)

**New Validators Required** (architecture lines 360-580):

**HookConfigValidator** (architecture lines 360-420):

- No auto-fix (JSON too complex)
- Validates 15 event types with fuzzy matching suggestions for unknown types
- Validates hook type discriminators
- Compiles regex patterns without execution (security)
- Error codes: HK001-HK010

**MCPConfigValidator** (architecture lines 422-473):

- No auto-fix
- Command existence check via shutil.which() produces WARNING not error
- Args must be list[str] not single string
- Env must be dict[str, str]
- Error codes: MC001-MC010

**LSPConfigValidator** (architecture lines 475-528):

- No auto-fix
- Strict extension format validation (.py not py)
- Lowercase language identifier enforcement
- Transport enum validation
- Error codes: LS001-LS010

**AgentEnumValidator** (architecture lines 530-580):

- No auto-fix (would guess user intent)
- Validates enum fields against official schema
- Provides suggestions for invalid enum values
- Only runs on FileType.AGENT files
- Error codes: AG001-AG010

**DescriptionValidator Modification** (architecture lines 582-629):

Current signature: `validate(self, path: Path, content: str) -> ValidationResult`
New signature: `validate(self, path: Path, content: str, file_type: FileType) -> ValidationResult`

Behavior change:

- Skip SK005 (trigger phrase check) when `file_type == FileType.COMMAND`
- Continue SK005 for SKILL and AGENT types
- Preserve SK004 (length check) for all types

**Validator Registration** (architecture lines 637-697):

Need to create VALIDATORS_BY_TYPE dispatch table:

```python
VALIDATORS_BY_TYPE: dict[FileType, list[type[Validator]]] = {
    FileType.SKILL: [FrontmatterValidator, NameFormatValidator, DescriptionValidator, ComplexityValidator, InternalLinkValidator, ProgressiveDisclosureValidator, NamespaceReferenceValidator],
    FileType.AGENT: [FrontmatterValidator, NameFormatValidator, DescriptionValidator, AgentEnumValidator, NamespaceReferenceValidator],
    FileType.COMMAND: [FrontmatterValidator, DescriptionValidator, NamespaceReferenceValidator],  # SK005 skipped
    FileType.HOOK_CONFIG: [HookConfigValidator],
    FileType.MCP_CONFIG: [MCPConfigValidator],
    FileType.LSP_CONFIG: [LSPConfigValidator],
    FileType.PLUGIN: [PluginStructureValidator],
}
```

**Error Code Registry Expansion** (architecture lines 700-763):

Need 40 new error code constants (lines 71-109 pattern):

- HK001-HK010: Hook configuration errors (10 codes)
- MC001-MC010: MCP configuration errors (10 codes)
- LS001-LS010: LSP configuration errors (10 codes)
- AG001-AG010: Agent enum errors (10 codes)

**Report Generation Fix** (architecture lines 836-893):

Change from counting validators to counting files:

- Current: `len(results)` counts ValidationResult objects
- Required: Count unique file paths `len(set(path for path, _ in results))`
- Message change: "X validators passed" → "X files validated"
- Group issues by file path, then by error code within file

**Dead Code Removal** (architecture lines 1149-1165):

Lines 904-911 in NamespaceReferenceValidator contain unreachable nested skill reference resolution after early return line 903. Verify with coverage before removal.

**Testing Strategy** (architecture lines 900-1027):

Minimum coverage: 80% overall, 90% for new validators
Test files needed:

- test_hook_config_validator.py - parametrize 15 event types, test all HK error codes
- test_mcp_config_validator.py - mock shutil.which(), test warning vs error severity
- test_lsp_config_validator.py - parametrize extension formats, test language identifier validation
- test_agent_enum_validator.py - parametrize valid enum combinations, test suggestion quality
- test_file_type_detection.py - test all 9 FileType values, edge cases (nested paths)
- test_report_generation.py - verify file counts not validator counts
- test_description_validator.py - add file_type parameter tests

**Performance Requirements** (architecture lines 1060-1097):

- Single file: <1 second
- Plugin with 10 components: <5 seconds
- Full repository scan: <30 seconds
- Optimization: Read each file once, pass content to all validators (no redundant I/O)

**Pre-Commit Integration** (architecture lines 1129-1143):

Current .pre-commit-config.yaml pattern (line 1136):

```yaml
files: '^plugins/.*(SKILL\.md|agents/.*\.md|commands/.*\.md|plugin\.json)$'
```

Required enhancement:

```yaml
files: '^plugins/.*(SKILL\.md|agents/.*\.md|commands/.*\.md|plugin\.json|hooks\.json|\.mcp\.json|\.lsp\.json)$'
```

### Technical Reference Details

#### Component Interfaces & Signatures

**FileType Enum Extension** (plugin_validator.py lines 138-166, architecture lines 85-130):

```python
class FileType(StrEnum):
    SKILL = "skill"
    AGENT = "agent"
    COMMAND = "command"
    PLUGIN = "plugin"
    HOOK_CONFIG = "hook_config"      # NEW
    MCP_CONFIG = "mcp_config"        # NEW
    LSP_CONFIG = "lsp_config"        # NEW
    HOOK_SCRIPT = "hook_script"      # NEW
    UNKNOWN = "unknown"

    @staticmethod
    def detect_file_type(path: Path) -> FileType:
        """Detect file type from path structure and filename.

        Detection priority order:
        1. Exact filename matches (hooks.json, .mcp.json, .lsp.json)
        2. Special filenames (SKILL.md, plugin.json)
        3. Directory-based (agents/, commands/, hooks/)
        4. UNKNOWN fallback
        """
```

**Validator Protocol** (plugin_validator.py lines 249-286, unchanged):

```python
class Validator(Protocol):
    def validate(self, path: Path, content: str) -> ValidationResult: ...
    def can_fix(self, issue: ValidationIssue) -> bool: ...
    def fix(self, path: Path, content: str) -> str: ...
```

**DescriptionValidator Signature Change** (architecture lines 596-629):

```python
class DescriptionValidator:
    def validate(
        self,
        path: Path,
        content: str,
        file_type: FileType  # NEW PARAMETER
    ) -> ValidationResult:
        """Validate description field with file-type awareness.

        Checks:
        - Minimum length (SK004) - ALL file types
        - Trigger phrases (SK005) - ONLY skills and agents, skip commands

        Args:
            path: Path to file
            content: File content
            file_type: FileType enum (determines SK005 behavior)

        Returns:
            ValidationResult with SK errors (SK005 skipped for commands)
        """
```

#### Data Structures

**HookConfig Pydantic Models** (architecture lines 135-194):

```python
from pydantic import BaseModel, Field

class HookType(StrEnum):
    COMMAND = "command"
    PROMPT = "prompt"
    AGENT = "agent"

class HookEventType(StrEnum):
    SESSION_START = "SessionStart"
    USER_PROMPT_SUBMIT = "UserPromptSubmit"
    PRE_TOOL_USE = "PreToolUse"
    PERMISSION_REQUEST = "PermissionRequest"
    POST_TOOL_USE = "PostToolUse"
    POST_TOOL_USE_FAILURE = "PostToolUseFailure"
    NOTIFICATION = "Notification"
    SUBAGENT_START = "SubagentStart"
    SUBAGENT_STOP = "SubagentStop"
    STOP = "Stop"
    TEAMMATE_IDLE = "TeammateIdle"
    TASK_COMPLETED = "TaskCompleted"
    PRE_COMPACT = "PreCompact"
    SESSION_END = "SessionEnd"

class HookDefinition(BaseModel):
    type: HookType
    command: str | None = None      # Required if type=command
    prompt: str | None = None       # Required if type=prompt
    agent: str | None = None        # Required if type=agent
    timeout: int | None = None
    model: str | None = None

class EventMatcher(BaseModel):
    matcher: str | None = None      # Optional regex pattern
    hooks: list[HookDefinition]

class HookConfig(BaseModel):
    hooks: dict[str, list[EventMatcher]]  # Event name → matchers
```

**MCPConfig Pydantic Models** (architecture lines 196-222):

```python
class MCPServer(BaseModel):
    command: str
    args: list[str] = Field(default_factory=list)
    env: dict[str, str] = Field(default_factory=dict)
    cwd: str | None = None

class MCPConfig(BaseModel):
    mcpServers: dict[str, MCPServer]
```

**LSPConfig Pydantic Models** (architecture lines 224-265):

```python
class LSPTransport(StrEnum):
    STDIO = "stdio"
    SOCKET = "socket"

class LSPServer(BaseModel):
    command: str
    extensionToLanguage: dict[str, str]
    args: list[str] = Field(default_factory=list)
    transport: LSPTransport = LSPTransport.STDIO
    env: dict[str, str] = Field(default_factory=dict)
    initializationOptions: dict[str, Any] = Field(default_factory=dict)
    settings: dict[str, Any] = Field(default_factory=dict)
    workspaceFolder: str | None = None
    startupTimeout: int | None = None
    shutdownTimeout: int | None = None
    restartOnCrash: bool = False
    maxRestarts: int | None = None

class LSPConfig(BaseModel):
    lspServers: dict[str, LSPServer]
```

**AgentFrontmatter Enum Models** (architecture lines 267-312):

```python
class AgentModel(StrEnum):
    SONNET = "sonnet"
    OPUS = "opus"
    HAIKU = "haiku"
    INHERIT = "inherit"

class AgentPermissionMode(StrEnum):
    DEFAULT = "default"
    ACCEPT_EDITS = "acceptEdits"
    DELEGATE = "delegate"
    DONT_ASK = "dontAsk"
    BYPASS_PERMISSIONS = "bypassPermissions"
    PLAN = "plan"

class AgentMemory(StrEnum):
    USER = "user"
    PROJECT = "project"
    LOCAL = "local"

class AgentFrontmatter(BaseModel):
    name: str  # Required
    description: str  # Required
    model: AgentModel | None = None  # Enhanced with enum
    permissionMode: AgentPermissionMode | None = None  # Enhanced with enum
    memory: AgentMemory | None = None  # NEW with enum
    # ... other existing fields (existing validators unchanged)
```

#### Configuration Requirements

**Official Schema Sources** (architecture lines 1487-1493):

- Hooks: <https://docs.anthropic.com/en/docs/claude-code/hooks.md>
- Agents: <https://docs.anthropic.com/en/docs/claude-code/sub-agents.md>
- MCP: <https://modelcontextprotocol.io/docs/server>
- LSP: <https://docs.anthropic.com/en/docs/claude-code/plugins.md#lsp-servers>
- Plugins: <https://docs.anthropic.com/en/docs/claude-code/plugins.md>

**Token Counting** (plugin_validator.py lines 44-45):

- Library: tiktoken 0.8.0+
- Encoding: cl100k_base
- Warning threshold: 4000 tokens
- Error threshold: 10000 tokens

**Dependencies** (plugin_validator.py lines 1-11):

```python
# /// script
# requires-python = ">=3.11"
# dependencies = [
#     "typer>=0.21.0",
#     "rich>=13.0.0",
#     "tiktoken>=0.8.0",
#     "pyyaml>=6.0",
#     "pydantic>=2.0.0",
# ]
# ///
```

#### File Locations

**Implementation Target**: `plugins/plugin-creator/scripts/plugin_validator.py`

**Key Line Regions**:

- Lines 71-109: Error code constants (add 40 new constants)
- Lines 138-166: FileType enum (add 4 new variants)
- Lines 147-165: detect_file_type() method (enhance detection logic)
- Lines 1030-1236: Pydantic models (add HookConfig, MCPConfig, LSPConfig, agent enums)
- Lines 1790-1936: DescriptionValidator (add file_type parameter)
- Lines 2896-2913: Validator registration (create VALIDATORS_BY_TYPE dispatch)
- Lines 2681-2709: ConsoleReporter.summarize() (fix file counting)
- Lines 904-911: Dead code removal (verify with coverage first)

**Test Files to Create**:

- `plugins/plugin-creator/tests/test_hook_config_validator.py`
- `plugins/plugin-creator/tests/test_mcp_config_validator.py`
- `plugins/plugin-creator/tests/test_lsp_config_validator.py`
- `plugins/plugin-creator/tests/test_agent_enum_validator.py`
- `plugins/plugin-creator/tests/test_file_type_detection.py`
- `plugins/plugin-creator/tests/test_report_generation.py`

**Test Files to Modify**:

- `plugins/plugin-creator/tests/test_description_validator.py` (add file_type parameter tests)

**Documentation to Update**:

- `plugins/plugin-creator/scripts/ERROR_CODES.md` (add 40 new error code entries)

**Pre-Commit Config**:

- `.pre-commit-config.yaml` (update file pattern around line 1136)

#### References

**Primary Sources** (Read Before Implementation):

1. **Task decomposition**: `./plan/tasks-1-plugin-linter.md` - Complete task breakdown with dependencies
2. **Architecture specification**: `./plan/architect-plugin-linter.md` - WHAT to build (interfaces, contracts, schemas)
3. **Feature context**: `./plan/feature-context-plugin-linter.md` - WHY this feature exists, gaps identified
4. **Codebase analysis**: `./plan/codebase/plugin-validator-architecture.md` - HOW current system works
5. **Main implementation**: `./plugins/plugin-creator/scripts/plugin_validator.py` - Complete 3045-line validator
6. **Existing tests**: `./plugins/plugin-creator/tests/` - Test patterns to follow (11 test files)
7. **Pre-commit config**: `./.pre-commit-config.yaml` - Hook integration patterns

**Official Documentation** (Cite in Model Docstrings):

- Hooks schema: <https://docs.anthropic.com/en/docs/claude-code/hooks.md>
- Agent schema: <https://docs.anthropic.com/en/docs/claude-code/sub-agents.md>
- MCP schema: <https://modelcontextprotocol.io/docs/server>
- LSP schema: <https://docs.anthropic.com/en/docs/claude-code/plugins.md#lsp-servers>

**Testing Standards** (architecture lines 1030-1051):

- Fixture type hints required: `Generator[YieldType, None, None]`
- Test function signatures: All parameters typed, `-> None` return type
- Mocking: pytest-mock only, NEVER unittest.mock
- AAA pattern: Arrange-Act-Assert with comments
- Property-based: Use hypothesis for validation functions, minimum 500 examples

**Verification Checklist Before Starting**:

- [ ] Read complete architecture specification (architect-plugin-linter.md)
- [ ] Read complete task decomposition (tasks-1-plugin-linter.md)
- [ ] Read current plugin_validator.py implementation (all 3045 lines)
- [ ] Read all official schema documentation URLs above
- [ ] Understand FileType detection priority order
- [ ] Understand Validator protocol contract
- [ ] Understand validation pipeline flow (detect → select → validate → aggregate → report)
- [ ] Understand token-based complexity measurement (tiktoken usage)
- [ ] Understand Pydantic field validator patterns from existing models
- [ ] Understand existing test file structure (conftest.py fixtures, test class patterns)

