Ensemble — Library, CLI, TUI, and desktop app for centrally managing Claude Code extension artifacts across 17 AI clients (21 planned in v2.0.1 spec). Today the library manages MCP servers, skills, plugins, hooks, settings, and rollback snapshots; subagents (agents.ts), slash commands (commands.ts), and the TUI browse engine (browse.ts) remain v2.0.1 targets. Library-first: designed to be consumed by apps (like Chorus) as a dependency. The Electron desktop app provides visual management with full CLI parity; ensemble browse provides a TUI-grade discovery experience.
- TypeScript, Node 24+, npm (workspaces monorepo)
- CLI: Commander.js (
ensemble/ens) - Desktop: Electron + React + Tailwind CSS v4 (packages/desktop/), scaffold-compliant (sandboxed, tRPC bridge, minimal preload)
- Desktop IPC:
electron-trpc0.7 +@trpc/server/@trpc/client/@trpc/react-querypinned to ^10.45 and@tanstack/react-querypinned to ^4.36. Do not bump any of these independently — electron-trpc 0.7 is not compatible with tRPC v11, and tRPC v10 requires react-query v4. Bumping any one of the four breaks the stack until electron-trpc ships a v11 release. - Desktop wire format: superjson transformer on both router and client (rich types across IPC)
- Validation: Zod (schemas exported for consumers)
- Build: tsup (library), electron-vite (desktop, main + preload emit CJS so they can
require()native deps under sandbox) - Test: Vitest (library/CLI), Playwright (desktop E2E)
- Lint: Biome
- Config:
~/.config/ensemble/config.json - Skills:
~/.config/ensemble/skills/
Library-first with four layers: schemas/config → operations → sync/I/O → presentation (CLI + desktop app). Monorepo: library/CLI at root, desktop at packages/desktop/.
| Module | Role |
|---|---|
schemas.ts |
Zod schemas and inferred TypeScript types for the entire data model |
config.ts |
Config I/O (loadConfig/saveConfig), query helpers, resolution helpers |
operations.ts |
Pure functions for all mutations: (config, params) → { config, result } |
clients.ts |
17 client definitions, detection, format adapters, CC settings helpers |
sync.ts |
Sync engine — resolve + write configs, non-destructive hook/settings merge, pre-sync snapshot creation, drift detection, symlink fan-out |
skills.ts |
SKILL.md frontmatter parser, canonical store CRUD |
search.ts |
BM25-style local capability search across servers and skills |
registry.ts |
Registry adapters (Official + Glama), caching, security summary |
doctor.ts |
Deterministic health audit, structured scoring, 6 categories (adds capability) |
hooks.ts |
Hook store — non-destructive settings.json merge under the hooks key, seven lifecycle events |
settings.ts |
Declarative settings.json key management — non-destructive key-level merge preserving unmanaged keys |
snapshots.ts |
Safe apply / rollback snapshots — pre-sync capture, forward-restore, retention |
agents.ts |
Subagent store — .claude/agents/*.md frontmatter parser, canonical store CRUD, fan-out to client agents directories; dual-field contract (description from frontmatter, userNotes library-side only) |
commands.ts |
Slash command store — .claude/commands/*.md frontmatter parser (description + optional allowed-tools, argument-hint), canonical store CRUD, fan-out to client commands directories |
projects.ts |
Project registry reader (optional better-sqlite3) |
secrets.ts |
Secret scanning — regex detection in env values and skill content |
usage.ts |
Usage tracking for self-learning search scoring |
setlist.ts |
Setlist capability integration (read-only, optional @setlist/core) |
init.ts |
Guided onboarding (ensemble init / --auto) |
export.ts |
Profile-as-plugin group export |
discover.ts |
Filesystem scan for existing installed skills and plugins; feeds addToLibrary during ensemble init |
lifecycle.ts |
Noun-first verb dispatcher — routes pull/install/uninstall/remove/library across the existing operations layer |
managed-settings.ts |
Canonical managed-settings store at ~/.config/ensemble/managed-settings.json, backing the ensemble settings verbs |
browse.ts |
Library-side browse engine — pure-function fuzzy search over library + discoverable resources with @marketplace/ filter parsing. Powers ensemble browse and the desktop Registry view. |
cli/index.ts |
Thin Commander.js wrapper over operations and lifecycle |
Desktop IPC (chunk 10) now exposes agents, commands, hooks, and settings sub-routers alongside the existing browse and snapshots routers — the Electron renderer can drive every v2.0.1 resource type.
| index.ts | Public API barrel export |
| packages/desktop/ | Electron desktop app — React + Tailwind over library via IPC |
v2.0.1 targets: See .fctry/spec.md §Architecture → Modules (v2.0.1 targets) for remaining unbuilt modules (browse.ts, import-legacy.ts).
import { loadConfig, saveConfig, addServer } from 'ensemble';
import { ServerSchema } from 'ensemble/schemas';
import { syncClient } from 'ensemble/sync';- Operations are pure.
(config, params) → { config, result }. No I/O in operations.ts. - Run tests before committing. All tests must pass:
npm test - Additive sync only. Never delete servers, plugins, skills, agents, commands, hooks, or managed settings keys the user didn't create via Ensemble. The
__ensemblemarker (orensemble: managedfrontmatter on markdown resources) identifies managed entries. - Secrets stay in 1Password. Env values may contain
op://references — store them as-is, never resolve. - Always update docs with functionality changes. Update
COMMANDS.mdand.fctry/changelog.md. - Type check.
npx tsc --noEmitmust pass.