Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 32 additions & 20 deletions docs/plans/2026-02-14-ccpkg-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ nav_order: 3

# ccpkg Design Document

| Field | Value |
| Field | Value |
|---------|--------------|
| Date | 2026-02-14 |
| Status | Draft |
| Authors | Allen R. |
| Date | 2026-02-14 |
| Status | Draft |
| Authors | Allen R. |

---

Expand Down Expand Up @@ -161,11 +161,11 @@ Plugins frequently need configuration: API keys, file paths, feature flags, serv

```json
{
"config": {
"API_KEY": { "type": "secret", "required": true, "description": "Service API key" },
"MAX_RESULTS": { "type": "number", "default": 10 },
"OUTPUT_FORMAT": { "type": "enum", "values": ["json", "text"], "default": "json" }
}
"config": {
"API_KEY": { "type": "secret", "required": true, "description": "Service API key" },
"MAX_RESULTS": { "type": "number", "default": 10 },
"OUTPUT_FORMAT": { "type": "enum", "values": ["json", "text"], "default": "json" }
}
}
```

Expand Down Expand Up @@ -258,14 +258,14 @@ ccpkg packages install as Claude Code plugins. This is the fundamental integrati

```json
{
"extraKnownMarketplaces": {
"ccpkg": {
"source": {
"source": "directory",
"path": "~/.ccpkg/plugins"
}
}
}
"extraKnownMarketplaces": {
"ccpkg": {
"source": {
"source": "directory",
"path": "~/.ccpkg/plugins"
}
}
}
}
```

Expand Down Expand Up @@ -362,7 +362,7 @@ The ccpkg format targets multiple AI coding assistant hosts, but each host has f

---

### 15. Instructions Assembly Base + Per-Host Overlays
### 15. Instructions Assembly. Base + Per-Host Overlays

**Decision**: The `components.instructions` field supports both a simple string form (single file) and a structured form declaring a base file with optional per-host overlay files. Overlays declare their assembly position (`append`, `prepend`, or `insert` at a named marker) via YAML frontmatter. The installer assembles the final instructions output per host at install time.

Expand All @@ -372,7 +372,19 @@ The ccpkg format targets multiple AI coding assistant hosts, but each host has f

1. **Separate instruction files per host** -- Each host gets its own complete file (`claude-instructions.md`, `copilot-instructions.md`). Simple to implement but leads to content duplication. When shared content changes, authors must update N files. Rejected because it undermines the DRY principle and scales poorly with host count.
2. **Template language with conditionals** -- Use a templating syntax (e.g., Handlebars, Jinja) with `{{#if host == "claude"}}` blocks. Powerful but introduces a template engine dependency, makes the raw files hard to read, and is overkill for what is typically "shared base + small per-host additions." Rejected for complexity.
3. **mappings.json only (previous design)** -- Map a single canonical file to host-specific filenames without any content variation. Already proven insufficient — the filename mapping exists via `targets.*.instructions_file`, but the content is identical everywhere. Superseded by the assembly model which adds content variation on top of filename mapping.
3. **mappings.json only (previous design)** -- Map a single canonical file to host-specific filenames without any content variation. Already proven insufficient. the filename mapping exists via `targets.*.instructions_file`, but the content is identical everywhere. Superseded by the assembly model which adds content variation on top of filename mapping.

### 16. MCP server deduplication at install time

When multiple packages bundle the same MCP server, the installer deduplicates at install time rather than requiring packages to declare shared dependencies or a shared MCP directory.

**Why install-time dedup?** Packages stay self-contained. Authors do not need to change anything. The dedup is transparent -- the installer is smarter about what it writes to the host config. This preserves Principle #1 (self-contained) and Principle #8 (no inter-package deps).

**Why not shared directory with refcounting?** Reference counting introduces a new complexity vector. Crashes mid-uninstall corrupt counts. It breaks the "each plugin is self-contained in its directory" model hosts expect.

**Why not a server_id manifest field?** Requires schema change and author adoption. Existing packages would not benefit. The key_name + origin tuple provides sufficient identity without opt-in.

**Identity model:** (key_name, origin) tuple. Origin is derived from server mode: command string for Mode 1, bundle path for Mode 2, source URL for Mode 3. Version resolution: highest wins. User override: per-server or global.

---

Expand Down Expand Up @@ -429,7 +441,7 @@ Dev mode uses a symmetric pair of operations that mirror the install/uninstall l
1. Validate the directory contains a valid `manifest.json`
2. Prompt for required config values (same as install)
3. Generate `.claude-plugin/plugin.json` inside the source directory (from manifest metadata)
4. Create symlink: `~/.ccpkg/plugins/{name}` source directory
4. Create symlink: `~/.ccpkg/plugins/{name}` -> source directory
5. Add `{name}@ccpkg` to `enabledPlugins` in `settings.json`
6. Render MCP/LSP templates with config substitution
7. Write lockfile entry with `"source": "link:/absolute/path"`, `"linked": true`, and `"generated_plugin_json": true` (if plugin.json was created by ccpkg, not pre-existing)
Expand Down
108 changes: 54 additions & 54 deletions docs/plans/2026-02-14-spec-grounding-revision.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ccpkg Spec Grounding Revision Implementation Plan
# ccpkg Spec Grounding Revision. Implementation Plan

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Expand All @@ -21,35 +21,35 @@ Claude Code's plugin system provides automatic namespacing via `.claude-plugin/p
- Plugin with `{"name": "my-package"}` + skill in `skills/my-skill/SKILL.md` = `/my-package:my-skill`
- Namespace prefix: driven by `plugin.json` `name` field (NOT directory name, NOT SKILL.md frontmatter)
- Component name within namespace: driven by skill **directory name** (NOT frontmatter `name`)
- User-level skills (`~/.claude/skills/`) CANNOT be namespaced subdirectories flatten
- User-level commands (`~/.claude/commands/`) CANNOT be namespaced subdirectories flatten
- User-level skills (`~/.claude/skills/`) CANNOT be namespaced. subdirectories flatten
- User-level commands (`~/.claude/commands/`) CANNOT be namespaced. subdirectories flatten
- There is NO programmatic API to register namespaced components outside the plugin system

**Implication:** ccpkg packages MUST be installed as Claude Code plugins to get namespacing.

### Finding 2: extraKnownMarketplaces Is the Official Registration Entry Point

Claude Code supports third-party plugin sources via `extraKnownMarketplaces` in `settings.json`. This is the documented, supported API NOT `known_marketplaces.json` (which is internal).
Claude Code supports third-party plugin sources via `extraKnownMarketplaces` in `settings.json`. This is the documented, supported API. NOT `known_marketplaces.json` (which is internal).

Seven source types are supported:
1. `github` GitHub repositories
2. `git` any Git URL
3. `url` hosted marketplace.json
4. `npm` npm packages
5. `file` local marketplace.json file
6. `directory` local directory of plugins
7. `hostPattern` regex host matching
1. `github`. GitHub repositories
2. `git`. any Git URL
3. `url`. hosted marketplace.json
4. `npm`. npm packages
5. `file`. local marketplace.json file
6. `directory`. local directory of plugins
7. `hostPattern`. regex host matching

**Implication:** ccpkg registers as a marketplace using the `directory` source type, pointing at `~/.ccpkg/plugins/`. Claude Code auto-discovers plugins in that directory.

### Finding 3: Six Plugin Loading Mechanisms Exist

1. **Marketplace installation** via `/plugin` UI or `claude plugin install`
2. **`--plugin-dir` CLI flag** session-only, no persistence, for quick testing
3. **CLI commands** `claude plugin install/uninstall/enable/disable`
4. **Interactive `/plugin` UI** 4-tab manager (Discover, Installed, Marketplaces, Errors)
5. **Project-level `.claude/settings.json`** team-shared, committed to git
6. **Managed settings** enterprise/org level, highest precedence, read-only
1. **Marketplace installation**. via `/plugin` UI or `claude plugin install`
2. **`--plugin-dir` CLI flag**. session-only, no persistence, for quick testing
3. **CLI commands**. `claude plugin install/uninstall/enable/disable`
4. **Interactive `/plugin` UI**. 4-tab manager (Discover, Installed, Marketplaces, Errors)
5. **Project-level `.claude/settings.json`**. team-shared, committed to git
6. **Managed settings**. enterprise/org level, highest precedence, read-only

Scope precedence: Managed > Local > Project > User

Expand All @@ -74,9 +74,9 @@ Confirmed: no hot-reload mid-session. Changes to plugin registration take effect
- Pack/verify commands via ZIP + manifest validation

**Aspirational (requires Claude Code application changes):**
- Hot-reload after install (no session restart) no API to notify Claude Code of new plugins mid-session
- Host-aware lockfile loading Claude Code does not read `ccpkg-lock.json` at startup
- Runtime component state machine (Idle Active Idle) no host-managed state tracking
- Hot-reload after install (no session restart). no API to notify Claude Code of new plugins mid-session
- Host-aware lockfile loading. Claude Code does not read `ccpkg-lock.json` at startup
- Runtime component state machine (Idle -> Active -> Idle). no host-managed state tracking

### Finding 6: Install Architecture

Expand Down Expand Up @@ -105,13 +105,13 @@ Confirmed: no hot-reload mid-session. Changes to plugin registration take effect
6. Remove lockfile entry
7. Inform user: session restart to deactivate

### Finding 7: Dev Mode Symmetric Link/Unlink
### Finding 7: Dev Mode. Symmetric Link/Unlink

**`/ccpkg:link ~/Projects/my-plugin`:**
1. Validate directory has valid `manifest.json`
2. Prompt for required config values
3. Generate `.claude-plugin/plugin.json` inside source directory (from manifest)
4. Create symlink `~/.ccpkg/plugins/{name}` source directory
4. Create symlink `~/.ccpkg/plugins/{name}` -> source directory
5. Add to `enabledPlugins`, render templates, write lockfile with `"source": "link:/absolute/path"`
6. Record `generated_plugin_json: true` in lockfile if plugin.json was created (not pre-existing)

Expand All @@ -128,24 +128,24 @@ Confirmed: no hot-reload mid-session. Changes to plugin registration take effect
The lockfile serves dual purpose: reproducibility record AND uninstall manifest.

Expanded fields per package entry:
- `installed_files` list of all files written during install
- `merged_mcp_servers` MCP server names merged into `.mcp.json`
- `merged_hooks` hook entries merged into settings
- `config_keys` config variable names stored in settings
- `generated_plugin_json` boolean, whether `.claude-plugin/plugin.json` was generated
- `linked` boolean, whether this is a dev-linked package
- `source` URL, file path, or `link:/path` for dev mode
- `installed_files`. list of all files written during install
- `merged_mcp_servers`. MCP server names merged into `.mcp.json`
- `merged_hooks`. hook entries merged into settings
- `config_keys`. config variable names stored in settings
- `generated_plugin_json`. boolean, whether `.claude-plugin/plugin.json` was generated
- `linked`. boolean, whether this is a dev-linked package
- `source`. URL, file path, or `link:/path` for dev mode

### Finding 9: Two Lockfiles, Two Audiences

- `installed_plugins.json` Claude Code's internal plugin registry (for host discovery)
- `ccpkg-lock.json` ccpkg's lifecycle manifest (source URLs, checksums, config hashes, provenance)
- `installed_plugins.json`. Claude Code's internal plugin registry (for host discovery)
- `ccpkg-lock.json`. ccpkg's lifecycle manifest (source URLs, checksums, config hashes, provenance)

ccpkg writes to BOTH during install. They serve different systems.

---

## Task 1: Revise Specification Install Lifecycle Section
## Task 1: Revise Specification. Install Lifecycle Section

**Files:**
- Modify: `spec/specification.md` (lines ~730-830, Install Lifecycle section)
Expand All @@ -154,7 +154,7 @@ ccpkg writes to BOTH during install. They serve different systems.

Replace the current Mermaid sequence diagram. The new diagram must:
- Remove the `Host->>User: Components available (no restart required)` step
- Add explicit `Installer->>Installer: Generate .claude-plugin/plugin.json`
- Add explicit `Installer->>Installer: Generate.claude-plugin/plugin.json`
- Add explicit `Installer->>Host: Add to enabledPlugins in settings.json`
- End with `Installer->>User: Installation complete. Restart session to activate.`

Expand Down Expand Up @@ -191,7 +191,7 @@ Replace the current 5-step process with the symmetric link/unlink design:

---

## Task 2: Revise Specification Add Host Integration Section
## Task 2: Revise Specification. Add Host Integration Section

**Files:**
- Modify: `spec/specification.md` (new section after Install Lifecycle, before Lockfile Format)
Expand Down Expand Up @@ -219,15 +219,15 @@ Document:
Document:
- User scope: `extraKnownMarketplaces` in `~/.claude/settings.json`
- Project scope: `extraKnownMarketplaces` in `{project}/.claude/settings.json`
- Project settings are committed to git team members get prompted to install
- Project settings are committed to git. team members get prompted to install
- Managed scope: enterprise admins can allowlist ccpkg via `strictKnownMarketplaces`
- Scope precedence: Managed > Local > Project > User

**Step 4: Commit**

---

## Task 3: Revise Specification Rewrite Lazy Loading Section
## Task 3: Revise Specification. Rewrite Lazy Loading Section

**Files:**
- Modify: `spec/specification.md` (lines ~896-923, Lazy Loading section)
Expand All @@ -238,7 +238,7 @@ Replace the current 5-step host-reads-lockfile description with:
- State that Claude Code already implements lazy loading for skills: frontmatter (name + description) is loaded at startup, full SKILL.md body is loaded on invocation via the Skill tool
- ccpkg leverages this existing behavior by placing well-formed SKILL.md files in standard plugin directories
- No custom host-level lockfile reader is required
- The host discovers ccpkg plugins via `extraKnownMarketplaces` directory source standard plugin component discovery
- The host discovers ccpkg plugins via `extraKnownMarketplaces` -> directory source -> standard plugin component discovery

**Step 2: Keep "On-Demand Loading" table**

Expand All @@ -256,7 +256,7 @@ Add a note: "These behaviors are provided by the host application's existing plu

---

## Task 4: Revise Specification Expand Lockfile Schema
## Task 4: Revise Specification. Expand Lockfile Schema

**Files:**
- Modify: `spec/specification.md` (lines ~831-895, Lockfile Format section)
Expand Down Expand Up @@ -285,7 +285,7 @@ Show a complete example with all new fields, including one installed package and

---

## Task 5: Revise Specification Add Aspirational Appendix
## Task 5: Revise Specification. Add Aspirational Appendix

**Files:**
- Modify: `spec/specification.md` (new Appendix D after Appendix C)
Expand All @@ -294,26 +294,26 @@ Show a complete example with all new fields, including one installed package and

Move all aspirational content here with clear framing:

Section D.1 Hot-Reload After Install:
Section D.1. Hot-Reload After Install:
- Description: Components become available immediately after install without session restart
- Requires: A host API or file-watch mechanism to detect new plugins mid-session
- Current behavior: Session restart required

Section D.2 Host-Aware Lockfile Loading:
Section D.2. Host-Aware Lockfile Loading:
- Description: Host reads `ccpkg-lock.json` at startup for optimized package discovery
- Requires: Host application to understand ccpkg lockfile format
- Current behavior: Host discovers packages via `extraKnownMarketplaces` and standard plugin directories

Section D.3 Runtime Component State Machine:
- Description: Components track Idle Active Idle lifecycle states
Section D.3. Runtime Component State Machine:
- Description: Components track Idle -> Active -> Idle lifecycle states
- Requires: Host-managed activation tracking per component
- Current behavior: Components are either installed (files exist in plugin directory) or not

**Step 2: Commit**

---

## Task 6: Revise Specification Update Archive Directory Structure
## Task 6: Revise Specification. Update Archive Directory Structure

**Files:**
- Modify: `spec/specification.md` (lines ~136-169, Directory Structure)
Expand All @@ -322,14 +322,14 @@ Section D.3 — Runtime Component State Machine:

The archive structure itself does not change. But add a note after the diagram explaining:
- At install time, the installer generates `.claude-plugin/plugin.json` from `manifest.json` metadata
- This generated file is NOT part of the archive it is a host-specific artifact created during installation
- The mapping: manifest `name` plugin.json `name`, manifest `version` plugin.json `version`, manifest `description` plugin.json `description`, manifest `author` plugin.json `author`
- This generated file is NOT part of the archive. it is a host-specific artifact created during installation
- The mapping: manifest `name` -> plugin.json `name`, manifest `version` -> plugin.json `version`, manifest `description` -> plugin.json `description`, manifest `author` -> plugin.json `author`

**Step 2: Commit**

---

## Task 7: Revise Design Document Add Plugin System Integration
## Task 7: Revise Design Document. Add Plugin System Integration

**Files:**
- Modify: `docs/plans/2026-02-14-ccpkg-design.md`
Expand Down Expand Up @@ -378,10 +378,10 @@ Replace with the symmetric link/unlink design:

**Step 1: Review schema for any required changes**

The manifest schema itself should NOT change significantly the manifest is the package author's contract. The `.claude-plugin/plugin.json` generation is an installer concern, not a manifest concern.
The manifest schema itself should NOT change significantly. the manifest is the package author's contract. The `.claude-plugin/plugin.json` generation is an installer concern, not a manifest concern.

However, verify:
- The `scope` enum still makes sense (it does `user`, `project`, `any`)
- The `scope` enum still makes sense (it does. `user`, `project`, `any`)
- The `targets` object can accommodate plugin.json generation hints if needed
- No fields reference the old `~/.claude/packages/` path

Expand Down Expand Up @@ -424,7 +424,7 @@ Capture the following to mnemonic:
- `_semantic/decisions`: ccpkg installs as Claude Code plugins via extraKnownMarketplaces directory source
- `_semantic/decisions`: Namespacing handled by plugin system, not file editing
- `_semantic/knowledge`: installed_plugins.json is read-only at startup, no hot-reload
- `_procedural/patterns`: Symmetric link/unlink manages .claude-plugin/plugin.json lifecycle
- `_procedural/patterns`: Symmetric link/unlink manages.claude-plugin/plugin.json lifecycle
- `_semantic/knowledge`: Six plugin loading mechanisms in Claude Code (marketplace, --plugin-dir, CLI, /plugin UI, project settings, managed settings)

---
Expand Down Expand Up @@ -461,7 +461,7 @@ Each task ends with a commit. Commit messages follow:

### What This Plan Does NOT Cover

- Implementation of ccpkg CLI/skills (pack, install, verify, etc.) that is a separate plan
- Implementation of the registry protocol that is a separate plan
- Testing no tests exist yet for the spec itself
- GitHub Pages deployment the deploy.yml workflow already exists
- Implementation of ccpkg CLI/skills (pack, install, verify, etc.). that is a separate plan
- Implementation of the registry protocol. that is a separate plan
- Testing. no tests exist yet for the spec itself
- GitHub Pages deployment. the deploy.yml workflow already exists
Loading