feat: Pack extension system — shareable bundles of skills, MCP servers, plugins, and instructions#568
feat: Pack extension system — shareable bundles of skills, MCP servers, plugins, and instructions#568anandgupta42 wants to merge 9 commits intomainfrom
Conversation
…instructions Introduces the Kit extension system that enables anyone — vendors, solution architects, team leads, individual engineers — to create and distribute shareable development setups. ## What's included **Core runtime** (`packages/opencode/src/kit/`): - `Kit` namespace with Zod schemas, state management, YAML loading - Trust tiers (`built-in`, `verified`, `community`) - Skill packs with activation modes (`always`, `detect`, `manual`) - Activate/deactivate lifecycle with full cleanup **11 CLI commands** (`packages/opencode/src/cli/cmd/kit.ts`): - `kit list`, `kit create`, `kit show`, `kit install`, `kit remove` - `kit activate` — one command: installs skills, configures MCP, enables - `kit deactivate` — clean removal (instructions + MCP config + active-kits) - `kit detect`, `kit search`, `kit status`, `kit validate` **TUI startup nudge** (`packages/opencode/src/cli/cmd/tui/thread.ts`): - Non-blocking detection on TUI startup - Shows one-line suggestion when matching kits found **JSONC-preserving config writes**: - Uses `jsonc-parser` `modify`/`applyEdits` to preserve user comments - MCP servers added on activate, removed on deactivate **Documentation** (`docs/`): - User guide: `docs/docs/configure/kits.md` (CLI reference, locations, tiers) - Author guide: `docs/docs/develop/kits.md` (full schema, tutorial, examples) - Ecosystem plan: `docs/PARTNER_ECOSYSTEM_PLAN.md` (strategy + simulation results) - Roadmap with planned features (`kit switch`, inheritance, `kit enforce`) ## Testing - 60/60 automated E2E tests passing (name validation, activate/deactivate lifecycle, MCP merge, JSONC preservation, detect, validate, install) - 10 stakeholder simulations across 5 scenarios (Snowflake, Dagster, dbt Labs, Airbyte, Healthcare, MSP consulting, OSS contributor, self-serve, enterprise) - 29 bugs found and fixed across 3 review rounds ## External - Kit content lives in `AltimateAI/data-engineering-skills` (merged PR #9) - Registry at `data-engineering-skills/registry.json` with 1 real entry - `dbt-snowflake` kit: 9 skills + dbt MCP server Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (16)
Disabled knowledge base sources:
📝 WalkthroughWalkthroughThis PR introduces a comprehensive "Pack" system for bundling and distributing skills, MCP servers, and instructions as reusable units. It adds CLI commands for pack lifecycle management (create, install, activate, deactivate, detect), implements integrity verification with tier-based trust levels and content hashing, tracks activation state via sidecars, and provides extensive documentation and tests. Changes
Sequence DiagramssequenceDiagram
actor User
participant CLI as pack activate
participant Pack as Pack Module
participant Manifest as Manifest/Hash
participant Config as Project Config
participant Skills as Skill System
participant MCP as MCP Config
User->>CLI: activate <pack-name>
CLI->>Pack: get(pack-name)
Pack->>Manifest: readManifest()
Pack-->>Pack: verify content hash
Pack-->>Pack: check tier allowlist
CLI-->>User: show integrity warnings
User-->>CLI: confirm activation
CLI->>Skills: install referenced skills
Skills-->>Skills: fetch & validate SKILL.md
CLI->>Config: write MCP entries
Config-->>Config: preserve JSONC comments
CLI->>Config: create instruction files
CLI->>Pack: writeActivationSidecar()
Pack-->>Pack: record applied changes
CLI-->>User: activation complete
sequenceDiagram
actor User
participant CLI as pack deactivate
participant Pack as Pack Module
participant Sidecar as Sidecar Record
participant Config as Project Config
participant MCP as MCP Cleanup
participant Plugins as Plugin Cleanup
User->>CLI: deactivate <pack-name>
CLI->>Sidecar: readActivationSidecar()
alt Sidecar found
Sidecar-->>CLI: activation metadata
CLI->>Config: read current config
CLI->>MCP: match & remove owned entries
MCP-->>MCP: preserve user modifications
CLI->>Plugins: refcount canonical names
Plugins-->>Plugins: keep if other packs use
CLI->>Config: delete pack instruction files
else Sidecar missing (legacy)
CLI->>Config: name-based cleanup attempt
Config-->>Config: best-effort removal
end
CLI->>Pack: deleteActivationSidecar()
CLI-->>User: deactivation complete
Estimated code review effort🎯 4 (Complex) | ⏱️ ~65 minutes Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…instructions Introduces the Kit extension system that enables anyone — vendors, solution architects, team leads, individual engineers — to create and distribute shareable development setups. ## What's included **Core runtime** (`packages/opencode/src/kit/`): - `Kit` namespace with Zod schemas, state management, YAML loading - Trust tiers (`built-in`, `verified`, `community`) - Skill packs with activation modes (`always`, `detect`, `manual`) - Activate/deactivate lifecycle with full cleanup **11 CLI commands** (`packages/opencode/src/cli/cmd/kit.ts`): - `kit list`, `kit create`, `kit show`, `kit install`, `kit remove` - `kit activate` — one command: installs skills, configures MCP, enables - `kit deactivate` — clean removal (instructions + MCP config + active-kits) - `kit detect`, `kit search`, `kit status`, `kit validate` **TUI startup nudge** (`packages/opencode/src/cli/cmd/tui/thread.ts`): - Non-blocking detection on TUI startup - Shows one-line suggestion when matching kits found **JSONC-preserving config writes**: - Uses `jsonc-parser` `modify`/`applyEdits` to preserve user comments - MCP servers added on activate, removed on deactivate **Documentation** (`docs/`): - User guide: `docs/docs/configure/kits.md` (CLI reference, locations, tiers) - Author guide: `docs/docs/develop/kits.md` (full schema, tutorial, examples) - Ecosystem plan: `docs/PARTNER_ECOSYSTEM_PLAN.md` (strategy + simulation results) - Roadmap with planned features (`kit switch`, inheritance, `kit enforce`) ## Testing - 60/60 automated E2E tests passing (name validation, activate/deactivate lifecycle, MCP merge, JSONC preservation, detect, validate, install) - 10 stakeholder simulations across 5 scenarios (Snowflake, Dagster, dbt Labs, Airbyte, Healthcare, MSP consulting, OSS contributor, self-serve, enterprise) - 29 bugs found and fixed across 3 review rounds ## External - Kit content lives in `AltimateAI/data-engineering-skills` (merged PR #9) - Registry at `data-engineering-skills/registry.json` with 1 real entry - `dbt-snowflake` kit: 9 skills + dbt MCP server Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
# Conflicts: # packages/opencode/src/altimate/telemetry/index.ts
…tics
Renames the extension-system primitive from "Kit" to "Pack" before any vendor
content has shipped publicly. "Pack" reads more naturally ("skill pack" is
already common language), differentiates from Claude Code's "plugin" noun,
and avoids the generic-SDK connotation of "kit".
Scope of rename:
- `Kit` namespace/types → `Pack` (runtime, CLI, config, telemetry)
- `KIT.yaml` → `PACK.yaml` file convention
- `.opencode/kits/` → `.opencode/packs/`; `active-kits` → `active-packs`
- Nested `SkillPack` type → `SkillGroup` / `skill_packs` field → `skill_groups`
to resolve the "pack contains packs" nesting collision
- Telemetry events `kit_*` → `pack_*`
- File moves: `src/kit/` → `src/pack/`; `cli/cmd/kit.ts` → `cli/cmd/pack.ts`;
`docs/{configure,develop}/kits.md` → `packs.md`
- CLI command group: `altimate-code kit ...` → `altimate-code pack ...`
No behavior change — pure rename + internal variable-shadow fix in
`allSkillsFromGroups` (inner loop variable `pack` → `group`).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ershoot) The bulk Kit→Pack rename in the previous commit incorrectly renamed the Drizzle Kit tool reference in `packages/opencode/AGENTS.md` because the regex did not exclude it. "Drizzle Kit" is the product name of Drizzle ORM's migration CLI (drizzle-kit on npm) and must not be renamed. Marker Guard surfaced this as an unmarked change to an upstream-shared file. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the remaining release gaps for the Pack extension system so it can ship to vendors (dlt-hub, Airbyte, DuckDB first-wave partners) with a credible trust story, offline-safe discovery, and a path for plugin-based extensibility — hooks, custom auth, and custom tools — through one bundle. ## Plugin bundling `PACK.yaml` already declared a `plugins: [npm-spec, ...]` field but only half the lifecycle was wired. This commit completes it: - `pack activate` preview now lists plugins alongside skills + MCP and warns that plugins run with full Node privileges. - `pack deactivate` removes plugin entries from `config.plugin[]` with **reference counting** — a plugin stays if another active pack still lists it, so co-activated packs can share dependencies safely. ## Manifest + integrity - New `Pack.Manifest` schema written to `manifest.json` alongside `PACK.yaml` at install time (`pack install` writes it; local `pack create` packs have no manifest and load as user-authored). - `Pack.computeContentHash(raw)` — SHA256 of content with CRLF→LF normalization for cross-platform stability. - `loadPack()` re-hashes on every load; mismatch surfaces as `pack.trust.tamper_detected = true` and produces an `INTEGRITY WARNING` banner during `pack activate`. - Not cryptographic signing — catches accidental corruption and naive tampering. Real PKI is explicitly out of scope (documented). ## Trust tier enforcement - Hardcoded `BUILTIN_ALLOWLIST` + `VERIFIED_ALLOWLIST` sets in `Pack`. - Packs claiming `built-in` / `verified` that are not on the allowlist are downgraded to `community` at load time and flagged via `pack.trust.tier_downgraded` + `trust.original_tier`. - Env-var overrides for local dev / internal distribution: `ALTIMATE_CODE_VERIFIED_PACKS` and `ALTIMATE_CODE_BUILTIN_PACKS`. - Activation preview shows `TIER DOWNGRADE` notice when it happens. ## Remote registry backend - `packs.registry` added to Config schema (new `Packs` zod type). Overridable via `ALTIMATE_CODE_PACK_REGISTRY` env var. - `pack search` now caches results at `~/.cache/altimate-code/pack-registry-cache.json` with 24h TTL. - `--refresh` flag bypasses cache. - Offline fallback: on fetch failure, falls back to stale cache if present and clearly labels results `(stale N hr ago — offline)`. ## Telemetry additions Three new event types for operators monitoring the installed base: - `pack_deactivated` — symmetric lifecycle event with clean-up counts (MCP entries, plugins, instructions) for measuring partial cleanups. - `pack_integrity_warning` — fired when `tamper_detected` or `tier_downgraded` triggers during activation. Includes `claimed_tier`. - `pack_applied` extended with `tier`, `tamper_detected`, `tier_downgraded` so we can chart trust-signal distribution. ## Tests 20 new bun tests in `test/pack/pack.test.ts` covering: schema discovery, slug-validator rejection, detect rules, activate/deactivate lifecycle, idempotency, multi-pack coexistence, hash determinism + CRLF/LF normalization, manifest roundtrip, tamper detection, tier downgrade, env-var allowlist override, and `allSkillsFromGroups` flattening. 224/224 pass across pack + config + plugin suites. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…count, atomic install Addresses CRITICAL + MAJOR findings from the 3-model consensus code review (GPT 5.4, Gemini 3.1 Pro, Kimi K2.5) before the Pack v1 release to partners. ## CRITICAL fixes - **MCP cleanup is ownership-aware (GPT, Kimi)** — `pack deactivate` no longer deletes MCP entries by name alone. An activation sidecar `.opencode/pack-state/<name>.json` records the exact MCP value each pack wrote; deactivate compares the current config value to the recorded one and only removes it on match. If the user edited the entry after activation, it's preserved and surfaced via `skippedMcpKeys`. - **Plugin refcount is canonical-name-based (Kimi)** — `@scope/plugin@^1.0` and `@scope/plugin@1.2.3` now correctly refcount as the same plugin via `Config.getPluginName()`. Deactivating pack A no longer removes a plugin that pack B still lists under a different version spec. - **`PackRemoveCommand` now runs the cleanup helper (Gemini)** — previously `pack remove` only deleted files + thinly deactivated, leaving orphaned MCP and plugin entries in config forever. Remove now runs the same ownership-aware cleanup as deactivate (before deleting the pack dir so the sidecar is still readable). ## MAJOR fixes - **`Pack.deactivate` uses `findActivePacksFile()` (Gemini)** — hardcoded `.opencode/active-packs` was silently no-op for users on the legacy `.altimate-code/` layout while still printing "✓ Deactivated pack". - **TOCTOU-hardened plugin writes in activate (GPT, Kimi)** — activate now reads the live plugin array via `readConfigField` directly from disk immediately before the JSONC `modify` edit, instead of relying on the parsed snapshot from `findConfigFile`. - **Manifest metadata verified against `PACK.yaml` (GPT, Claude)** — `loadPack` now compares `manifest.name`, `manifest.version`, and `manifest.tier` against the parsed YAML. Any mismatch sets `trust.tamper_detected = true`. Closes the hole where someone could edit YAML tier without re-computing the hash (allowlist still blocks elevation, but this makes the drift auditable). - **Registry cache Zod-validates before trust (Kimi)** — `readRegistryCache` now uses `CachedRegistry.safeParse()`; corrupted cache files degrade to "no cache" instead of crashing search. Also clamps negative age (clock skew) to 0 so a regressed clock can't mask stale cache as fresh. - **Install rolls back on manifest-write failure for remote sources (GPT, Kimi, Claude)** — remote installs now remove the partially-copied pack directory if `Pack.writeManifest` throws, instead of silently continuing and weakening integrity posture. Local-path installs still warn-and-continue (dev loop ergonomics). - **`PackActivateCommand` prints restart notice when plugins are added (Kimi)** — npm plugins in `config.plugin[]` only install on the plugin loader's lazy init. The activate command now tells the user that newly added plugins will finish installing on next start. ## Tests 12 new integration tests in `test/pack/pack-cli.test.ts` covering the cleanup helper directly: - MCP ownership: removes only entries matching the sidecar, preserves user-modified entries and reports them as skipped. - Plugin refcount: two packs sharing a canonical name → shared plugin survives; solo ownership → plugin removed. - Legacy fallback: sidecar missing → name-only cleanup with warning. - Empty config: no config file means no cleanup AND no scaffolded file. - Instructions: cleaned up when sidecar records one. - Sidecar roundtrip: write → read → delete (idempotent); malformed JSON safely returns undefined. - `Pack.deactivate` with legacy `.altimate-code/active-packs`. 1 new unit test in `test/pack/pack.test.ts`: - Manifest metadata mismatch (tier drift) triggers tamper detection even when content hash matches. 31/31 pack tests pass. Typecheck + Marker Guard clean. Intentionally deferred to follow-up issues (low ship risk): - Minor TOCTOU hardening in `findConfigFile` regex JSONC stripping → use `jsonc-parser.parse()` consistently. - Empty-pack activation skipping telemetry. - Env-var allowlist: quoted-value handling, BOM normalization in `computeContentHash`, registry cache stale-file GC on URL change, envAllowlist memoization for hot loop. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Root typecheck (`tsgo`) was stricter than bun test's runtime check and flagged the two fixture objects in `pack-cli.test.ts` for missing `instructions` — added as `undefined` so the fixtures match the Pack.Info schema shape exactly. No runtime behavior change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 29326785 | Triggered | Generic Password | abc632b | packages/opencode/test/altimate/connections.test.ts | View secret |
| 29327588 | Triggered | Generic Password | abc632b | packages/opencode/test/altimate/connections.test.ts | View secret |
| 30431051 | Triggered | Generic Database Assignment | abc632b | packages/opencode/test/altimate/connections.test.ts | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secrets safely. Learn here the best practices.
- Revoke and rotate these secrets.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
1 similar comment
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 29326785 | Triggered | Generic Password | abc632b | packages/opencode/test/altimate/connections.test.ts | View secret |
| 29327588 | Triggered | Generic Password | abc632b | packages/opencode/test/altimate/connections.test.ts | View secret |
| 30431051 | Triggered | Generic Database Assignment | abc632b | packages/opencode/test/altimate/connections.test.ts | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secrets safely. Learn here the best practices.
- Revoke and rotate these secrets.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
|
👋 This PR was automatically closed by our quality checks. Common reasons:
If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you. |
|
👋 This PR was automatically closed by our quality checks. Common reasons:
If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you. |
|
👋 This PR was automatically closed by our quality checks. Common reasons:
If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you. |
What does this PR do?
Introduces the Pack extension system — a shareable bundle format that packages skills, MCP servers, npm plugins, and instructions into one activatable unit. Vendors (dlt-hub, Airbyte, DuckDB lined up as first-wave partners) can ship a single repo with a PACK.yaml and users activate it in one command.
Why this, why now:
Every major data vendor shipped an MCP server in the last year. Snowflake, Databricks, BigQuery, MotherDuck, dbt, Atlan, Monte Carlo, Dagster, Airbyte — they all have one. But MCPs are raw surfaces: just tool lists. Nobody packages them into opinionated, dbt and lineage-aware workflows for coding agents. First-mover opportunity to become the bundler rather than another MCP consumer.
User pain is real and daily. Setting up altimate-code for a specific data stack today requires manually installing skills, configuring MCP servers, and writing instruction files. Every team member on the same project repeats this setup. Time-to-first-useful-agent is hours, not seconds.
Partner momentum. dlt-hub, Airbyte, and DuckDB partnerships are active and can ship the first vendor packs within weeks of this merging. Atlan, Monte Carlo, and Dagster are wave-2 targets. The go/no-go on the broader vendor program hinges on a clean extensibility primitive for partners to build against — this is it.
Defensible strategic position. Claude Code has plugins, Cursor has rules, Continue has blocks — but none are data-engineering-native. Packs give altimate-code a bundle format that ships opinionated dbt, lineage, and cost-aware experiences on top of raw MCPs. Vendors gain distribution; altimate-code gains the integration moat.
Usage: altimate-code pack install AltimateAI/data-engineering-skills, then altimate-code pack activate dbt-snowflake. That installs skills into the project skills directory, configures the MCP server in the project config (preserving JSONC comments), appends declared npm plugins to the plugin list, writes pack-scoped instructions, and prompts a restart so the plugin loader picks up the new specs.
Runtime additions under packages/opencode/src/pack/: Pack.Info Zod schema (skills, skill_groups, mcp, plugins, instructions, detect, trust metadata), Pack.Manifest schema plus SHA256 computeContentHash (CRLF/LF normalized), Pack.ActivationSidecar recording exactly what each pack wrote so deactivate cleans up ownership-aware, hardcoded VERIFIED and BUILTIN allowlists with env-var overrides (ALTIMATE_CODE_VERIFIED_PACKS and ALTIMATE_CODE_BUILTIN_PACKS), and integrity check comparing content hash plus name, version, and tier against the manifest.
CLI subcommands (11 total): list, create, show, install, activate, deactivate, remove, detect, search, status, validate. Ownership-aware cleanup via the sidecar means deactivate and remove leave user-modified MCP entries in place and report which were preserved.
Remote registry: pack search hits a configurable URL (packs.registry config field or ALTIMATE_CODE_PACK_REGISTRY env var), caches for 24 hours, supports --refresh to bypass cache, and falls back to stale cache when the registry is unreachable.
Telemetry: new event types pack_created, pack_installed, pack_applied (with tier, tamper_detected, tier_downgraded), pack_deactivated, pack_removed, pack_integrity_warning.
Docs: docs/docs/configure/packs.md (user), docs/docs/develop/packs.md (author), docs/PARTNER_ECOSYSTEM_PLAN.md (strategy).
Type of change
Issue for this PR
Closes #567
How did you verify your code works?
Checklist