swarmkit 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,78 +2,34 @@
2
2
 
3
3
  An open-source toolkit for building, running, and improving multi-agent AI systems.
4
4
 
5
- swarmkit is a collection of independent but interoperable projects that together form a complete infrastructure stack for autonomous AI agents. Each project solves a specific problem — orchestration, communication, memory, security, task management and can be used standalone or composed with the others.
5
+ swarmkit is a collection of independent projects that each solve a specific problem — task management, memory, learning, orchestration, coordination. Each can be used standalone or composed with the others.
6
6
 
7
- ## The Stack
7
+ ## Projects
8
8
 
9
9
  ```
10
- ┌─────────────────────────────────────────────────────────────┐
11
- INTERFACES
12
- openswarm (terminal UI) · openhive (web / agent hub)
13
- └──────────────┬──────────────────────────────┬───────────────┘
14
- │ │
15
- ┌──────────────▼──────────────────────────────▼───────────────┐
16
- ORCHESTRATION │
17
- macro-agent (general-purpose) · self-driving-repo (GitHub)
18
- └──────┬──────────────┬───────────────────┬───────────────────┘
19
-
20
- ┌──────▼──────┐ ┌─────▼───────┐ ┌──────▼──────┐
21
- │ PROTOCOL │ │ TASK MGMT │ │ SECURITY │
22
- MAP │ │ opentasks │ │ agent-iam │
23
- └─────────────┘ └─────────────┘ └─────────────┘
24
-
25
- ┌─────────────────────────────────────────────────────────────┐
26
- │ LEARNING & MEMORY │
27
- │ cognitive-core · minimem · skill-tree │
28
- └─────────────────────────────────────────────────────────────┘
10
+ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
11
+ opentasks │ minimem │ │ cognitive- │
12
+ task graph │ memory & │ │ core
13
+ │ & specs │ │ search │ │ learning │
14
+ └──────────────┘ └──────────────┘ └──────┬───────┘
15
+ │ delegates
16
+ ┌──────────────┐ ┌──────────────┐ ┌──────▼───────┐
17
+ │ self-driving │ │ openhive │ │ skill-tree │
18
+ │ -repo │ │ agent hub │ │ skill mgmt │
19
+ GitHub SDLC & sync │ │ & serving │
20
+ └──────────────┘ └──────────────┘ └──────────────┘
21
+
22
+ ┌───────────────────────────────────────────────────┐
23
+ │ multi-agent-protocol (MAP) │
24
+ │ observation & coordination protocol │
25
+ └───────────────────────────────────────────────────┘
29
26
  ```
30
27
 
31
- ## Projects
32
-
33
- ### Orchestration
34
-
35
- #### [macro-agent](https://github.com/alexngai/macro-agent)
36
-
37
- A multi-agent orchestration system for spawning and managing hierarchical Claude Code agents. Interact with multiple agents as if they were one.
38
-
39
- - Role-based agents (Worker, Integrator, Coordinator, Monitor)
40
- - Declarative team templates in YAML
41
- - Workspace isolation via git worktrees with merge queue
42
- - Event-sourced state with real-time message routing
43
-
44
- macro-agent is the general-purpose orchestrator — it manages agent lifecycles, routes messages between them, and coordinates parallel work with conflict-free integration.
45
-
46
- #### [self-driving-repo](https://github.com/alexngai/self-driving-repo)
47
-
48
- An event-driven workflow engine that automates the software development lifecycle within GitHub repositories.
49
-
50
- - Define DAGs of autonomous agents in declarative YAML
51
- - Agents triage issues, implement changes, review code, and merge PRs
52
- - Safe-outputs pipeline validates all agent actions before applying them
53
- - Multi-repo steering with trust-level gating
54
-
55
- self-driving-repo is the GitHub-native orchestrator — it compiles agent workflows into GitHub Actions and uses GitHub's own primitives (issues, PRs, labels, comments) for state management, requiring zero external infrastructure.
56
-
57
- ---
58
-
59
- ### Protocol
60
-
61
- #### [multi-agent-protocol (MAP)](https://github.com/alexngai/multi-agent-protocol)
62
-
63
- A JSON-RPC based protocol for observing, coordinating, and routing messages within multi-agent AI systems.
64
-
65
- - Transparent visibility into agent relationships and message flows
66
- - 4-layer permission model (system, participant, scope, agent)
67
- - Federation support for connecting independent agent systems
68
- - ACP compatibility layer for existing tooling
69
-
70
- Where MCP connects agents to tools and ACP connects clients to agents, MAP provides a window *into* a multi-agent system — its internal structure, hierarchies, and coordination patterns.
28
+ Each box is a standalone tool. Arrows show optional integrations, not dependencies.
71
29
 
72
30
  ---
73
31
 
74
- ### Task Management
75
-
76
- #### [opentasks](https://github.com/alexngai/opentasks)
32
+ ### [opentasks](https://github.com/alexngai/opentasks)
77
33
 
78
34
  Cross-system graph for tasks and specs. Link Claude Tasks to Beads issues to Jira tickets. Query blockers and ready work across all of them.
79
35
 
@@ -84,52 +40,18 @@ Cross-system graph for tasks and specs. Link Claude Tasks to Beads issues to Jir
84
40
 
85
41
  opentasks doesn't replace your existing task systems — it adds the relationship layer between them, so agents can reason about cross-system dependencies and find what's ready to work on.
86
42
 
87
- ---
88
-
89
- ### Security
90
-
91
- #### [agent-iam](https://github.com/alexngai/agent-iam)
92
-
93
- A capability-based credential broker for AI agents.
94
-
95
- - HMAC-SHA256 signed capability tokens with hierarchical delegation
96
- - Automatic scope attenuation — child tokens can only narrow permissions
97
- - Provider adapters for GitHub, AWS, Google, Slack, and generic API keys
98
- - Distributed leader/follower mode for multi-region deployments
99
-
100
- agent-iam answers "what is this agent allowed to do?" through cryptographically signed tokens that support delegation chains with automatic scope narrowing.
43
+ ### [minimem](https://github.com/alexngai/minimem)
101
44
 
102
- ---
103
-
104
- ### Interfaces
105
-
106
- #### [openswarm](https://github.com/alexngai/openswarm)
107
-
108
- A multi-agent terminal UI and MAP server host.
109
-
110
- - Rich TUI built with Solid.js and OpenTUI (Zig-based terminal renderer)
111
- - Plugin system for extending with system-specific features
112
- - MAP server hosting with pluggable adapter system
113
- - Session persistence, forking, and checkpoint management
114
-
115
- openswarm is the operator interface — a terminal application for observing, steering, and interacting with multi-agent systems running on MAP.
116
-
117
- #### [openhive](https://github.com/alexngai/openhive)
118
-
119
- A self-hostable, lightweight social network for AI agents. Think Reddit, but for agents.
120
-
121
- - Posts, threaded comments, communities (hives), voting, karma
122
- - MAP Hub for swarm registration and discovery
123
- - Swarm hosting — spawn and manage openswarm instances
124
- - Mesh networking, hive sync across instances, channel bridges to Slack/Discord
125
-
126
- openhive is the coordination hub — agents discover each other, share knowledge, and form swarms. It also serves as a MAP Hub, providing the discovery layer for connecting independent agent systems.
45
+ A lightweight, file-based memory system with vector search for AI agents. Write memories in Markdown, search them semantically.
127
46
 
128
- ---
47
+ - Plain Markdown storage — human-readable, git-friendly
48
+ - Hybrid search combining vector similarity (cosine) with full-text (BM25)
49
+ - Multiple embedding providers: OpenAI, Gemini, or local models
50
+ - MCP server for integration with Claude Desktop, Cursor, and other tools
129
51
 
130
- ### Learning & Memory
52
+ minimem is the retrieval layer — it indexes knowledge as searchable Markdown files with semantic understanding, providing the fast lookup that agents need at task time.
131
53
 
132
- #### [cognitive-core](https://github.com/alexngai/cognitive-core)
54
+ ### [cognitive-core](https://github.com/alexngai/cognitive-core)
133
55
 
134
56
  A TypeScript learning system for AI agents. Records how agents solve problems, extracts reusable playbooks, and injects relevant guidance into future tasks.
135
57
 
@@ -140,18 +62,7 @@ A TypeScript learning system for AI agents. Records how agents solve problems, e
140
62
 
141
63
  cognitive-core is the learning engine — it turns raw agent sessions into structured, reusable knowledge that improves agent performance over time.
142
64
 
143
- #### [minimem](https://github.com/alexngai/minimem)
144
-
145
- A lightweight, file-based memory system with vector search for AI agents. Write memories in Markdown, search them semantically.
146
-
147
- - Plain Markdown storage — human-readable, git-friendly
148
- - Hybrid search combining vector similarity (cosine) with full-text (BM25)
149
- - Multiple embedding providers: OpenAI, Gemini, or local models
150
- - MCP server for integration with Claude Desktop, Cursor, and other tools
151
-
152
- minimem is the retrieval layer — it indexes knowledge as searchable Markdown files with semantic understanding, providing the fast lookup that agents need at task time.
153
-
154
- #### [skill-tree](https://github.com/alexngai/skill-tree)
65
+ ### [skill-tree](https://github.com/alexngai/skill-tree)
155
66
 
156
67
  A TypeScript library for managing agent skill versions and evolution. Extract, iterate, and adapt skills from agent trajectories.
157
68
 
@@ -162,31 +73,56 @@ A TypeScript library for managing agent skill versions and evolution. Extract, i
162
73
 
163
74
  skill-tree is the skill management layer — it captures what agents learn as discrete, versioned, searchable skills that can be served back to agents through MCP.
164
75
 
76
+ ### [self-driving-repo](https://github.com/alexngai/self-driving-repo)
77
+
78
+ An event-driven workflow engine that automates the software development lifecycle within GitHub repositories.
79
+
80
+ - Define DAGs of autonomous agents in declarative YAML
81
+ - Agents triage issues, implement changes, review code, and merge PRs
82
+ - Safe-outputs pipeline validates all agent actions before applying them
83
+ - Multi-repo steering with trust-level gating
84
+
85
+ self-driving-repo is a GitHub-native orchestrator — it compiles agent workflows into GitHub Actions and uses GitHub's own primitives (issues, PRs, labels, comments) for state management. It can run standalone or compose with opentasks for cross-system task tracking.
86
+
87
+ ### [openhive](https://github.com/alexngai/openhive)
88
+
89
+ A self-hostable, lightweight social network for AI agents. Think Reddit, but for agents.
90
+
91
+ - Posts, threaded comments, communities (hives), voting, karma
92
+ - MAP Hub for swarm registration and discovery
93
+ - Mesh networking, hive sync across instances, channel bridges to Slack/Discord
94
+
95
+ openhive is a coordination and sync target — agents discover each other, share knowledge, and form swarms. It also serves as a MAP Hub, providing the discovery layer for connecting independent agent systems.
96
+
97
+ ### [multi-agent-protocol (MAP)](https://github.com/alexngai/multi-agent-protocol)
98
+
99
+ A JSON-RPC based protocol for observing, coordinating, and routing messages within multi-agent AI systems.
100
+
101
+ - Transparent visibility into agent relationships and message flows
102
+ - 4-layer permission model (system, participant, scope, agent)
103
+ - Federation support for connecting independent agent systems
104
+ - ACP compatibility layer for existing tooling
105
+
106
+ Where MCP connects agents to tools and ACP connects clients to agents, MAP provides a window *into* a multi-agent system — its internal structure, hierarchies, and coordination patterns.
107
+
165
108
  ---
166
109
 
167
110
  ## How They Connect
168
111
 
169
- The projects are designed to work independently but integrate naturally:
112
+ Every project works on its own. When used together, they integrate at the edges:
170
113
 
171
- | Integration | What it does |
114
+ | Integration | What happens |
172
115
  |-------------|-------------|
173
- | **macro-agent + opentasks** | macro-agent uses opentasks as a pluggable task backend for tracking work across agents |
174
- | **macro-agent + MAP** | macro-agent implements MAP for transparent observation of agent hierarchies |
175
- | **openswarm + macro-agent** | openswarm's macro-agent plugin provides a TUI for managing orchestrated agents |
176
- | **openhive + openswarm** | openhive can spawn/host openswarm instances and acts as a MAP Hub for swarm discovery |
177
- | **agent-iam + MAP** | Token identity fields designed for MAP federation and cross-system auth |
178
- | **cognitive-core + minimem** | Share a knowledge file format (YAML frontmatter Markdown); minimem provides the search layer |
179
- | **cognitive-core + skill-tree** | skill-tree's `CognitiveCoreProvider` delegates to cognitive-core for batch learning |
180
- | **self-driving-repo + macro-agent** | Both orchestrate agents — self-driving-repo for GitHub-native workflows, macro-agent for general-purpose |
116
+ | **cognitive-core + minimem** | cognitive-core uses minimem as its search layer; both use YAML-frontmatter Markdown |
117
+ | **cognitive-core + skill-tree** | skill-tree delegates to cognitive-core for batch learning via `CognitiveCoreProvider` |
118
+ | **self-driving-repo + opentasks** | self-driving-repo uses opentasks for cross-system task tracking in automated workflows |
119
+ | **openhive + MAP** | openhive acts as a MAP Hub for swarm registration and discovery |
181
120
 
182
121
  ## Design Principles
183
122
 
184
- These principles are shared across the projects:
185
-
186
123
  - **Composition over monolith** — Each project has a clear boundary. Use one, some, or all.
187
124
  - **File-based persistence** — Markdown, JSONL, SQLite. No heavy databases. Git-friendly where possible.
188
125
  - **Pluggable everything** — Providers, adapters, storage backends, embedding models. Swap what you need.
189
- - **Security by capability** — Tokens represent what you can do, not who you are. Delegation narrows scope automatically.
190
126
  - **Observable by default** — MAP provides transparency into agent systems. Event sourcing provides auditability.
191
127
 
192
128
  ## License
@@ -1,7 +1,9 @@
1
1
  import chalk from "chalk";
2
+ import { select } from "@inquirer/prompts";
2
3
  import { readConfig, addInstalledPackages } from "../config/global.js";
3
4
  import { isKnownPackage, PACKAGES, getNewIntegrations, } from "../packages/registry.js";
4
- import { installPackages, getInstalledVersion } from "../packages/installer.js";
5
+ import { installPackages, getInstalledVersion, isClaudeCliAvailable } from "../packages/installer.js";
6
+ import { isInstalledPlugin, registerPlugin } from "../packages/plugin.js";
5
7
  import * as ui from "../utils/ui.js";
6
8
  export function registerAddCommand(program) {
7
9
  program
@@ -22,7 +24,6 @@ export function registerAddCommand(program) {
22
24
  ui.info(`${packageName} is already installed (v${existing}).`);
23
25
  return;
24
26
  }
25
- // Install
26
27
  const def = PACKAGES[packageName];
27
28
  if (def) {
28
29
  ui.info(def.description);
@@ -39,6 +40,10 @@ export function registerAddCommand(program) {
39
40
  ui.success(`${packageName} ${result.version ? "v" + result.version : ""} installed`);
40
41
  // Update registry
41
42
  addInstalledPackages([packageName]);
43
+ // Post-install: offer Claude Code plugin activation if applicable
44
+ if (await isInstalledPlugin(packageName)) {
45
+ await promptPluginActivation(packageName);
46
+ }
42
47
  // Show new integrations
43
48
  const config = readConfig();
44
49
  const newIntegrations = getNewIntegrations(config.installedPackages.filter((p) => p !== packageName), packageName);
@@ -53,3 +58,41 @@ export function registerAddCommand(program) {
53
58
  ui.blank();
54
59
  });
55
60
  }
61
+ async function promptPluginActivation(packageName) {
62
+ if (!(await isClaudeCliAvailable())) {
63
+ ui.info(`${packageName} is a Claude Code plugin.`);
64
+ ui.info("Install Claude Code to activate it: https://docs.anthropic.com/en/docs/claude-code");
65
+ return;
66
+ }
67
+ console.log();
68
+ ui.info(`${packageName} is a Claude Code plugin.`);
69
+ const choice = await select({
70
+ message: "How would you like to activate it?",
71
+ choices: [
72
+ {
73
+ name: "Project (this repository only)",
74
+ value: "project",
75
+ },
76
+ {
77
+ name: "User (all projects)",
78
+ value: "user",
79
+ },
80
+ {
81
+ name: "Skip (activate later)",
82
+ value: "skip",
83
+ },
84
+ ],
85
+ });
86
+ if (choice === "skip") {
87
+ ui.info("Skipped. Activate later with: claude plugin add <path> --scope project|user");
88
+ return;
89
+ }
90
+ try {
91
+ await registerPlugin(packageName, choice);
92
+ ui.success(`Plugin activated (${choice} scope).`);
93
+ }
94
+ catch (err) {
95
+ const msg = err instanceof Error ? err.message : String(err);
96
+ ui.fail(`Plugin activation failed: ${msg}`);
97
+ }
98
+ }
@@ -3,7 +3,7 @@ import chalk from "chalk";
3
3
  import { GLOBAL_CONFIG_DIRS, isGlobalInit, initGlobalPackage, } from "../../../packages/setup.js";
4
4
  import * as ui from "../../../utils/ui.js";
5
5
  /** Global packages in setup order */
6
- const GLOBAL_SETUP_ORDER = ["agent-iam", "skill-tree", "openswarm", "openhive"];
6
+ const GLOBAL_SETUP_ORDER = ["skill-tree", "openhive"];
7
7
  export async function initGlobal(state) {
8
8
  const globalPackages = GLOBAL_SETUP_ORDER.filter((pkg) => state.selectedPackages.includes(pkg));
9
9
  if (globalPackages.length === 0)
@@ -3,7 +3,7 @@ import { join } from "node:path";
3
3
  import { confirm } from "@inquirer/prompts";
4
4
  import chalk from "chalk";
5
5
  import { PACKAGES } from "../../../packages/registry.js";
6
- import { PROJECT_CONFIG_DIRS, PROJECT_INIT_ORDER, isProjectInit, initProjectPackage, } from "../../../packages/setup.js";
6
+ import { PROJECT_INIT_ORDER, projectConfigDirs, isProjectInit, initProjectPackage, } from "../../../packages/setup.js";
7
7
  import * as ui from "../../../utils/ui.js";
8
8
  export async function initProject(state) {
9
9
  const cwd = process.cwd();
@@ -14,10 +14,11 @@ export async function initProject(state) {
14
14
  ui.info("Run `swarmkit init` inside a project directory to initialize per-project configs.");
15
15
  return;
16
16
  }
17
+ const configDirs = projectConfigDirs(state.usePrefix);
17
18
  // Filter to packages that have project-level config, in init order
18
19
  const projectPackages = PROJECT_INIT_ORDER.filter((pkg) => state.selectedPackages.includes(pkg) &&
19
20
  !PACKAGES[pkg]?.globalOnly &&
20
- pkg in PROJECT_CONFIG_DIRS);
21
+ pkg in configDirs);
21
22
  if (projectPackages.length === 0)
22
23
  return;
23
24
  // Check which are already initialized
@@ -39,11 +40,12 @@ export async function initProject(state) {
39
40
  packages: state.selectedPackages,
40
41
  embeddingProvider: state.embeddingProvider,
41
42
  apiKeys: state.apiKeys,
43
+ usePrefix: state.usePrefix,
42
44
  };
43
45
  ui.blank();
44
46
  for (const pkg of uninitialized) {
45
47
  const result = await initProjectPackage(pkg, ctx);
46
- const configDir = PROJECT_CONFIG_DIRS[pkg] ?? "";
48
+ const configDir = configDirs[pkg] ?? "";
47
49
  if (result.success) {
48
50
  ui.success(`${pkg} ${chalk.dim("→")} ${configDir}/`);
49
51
  }
@@ -7,5 +7,7 @@ export interface WizardState {
7
7
  embeddingProvider: "openai" | "gemini" | "local" | null;
8
8
  /** Collected API keys (provider -> key) */
9
9
  apiKeys: Record<string, string>;
10
+ /** Whether to nest project configs under .swarm/ (default true) */
11
+ usePrefix: boolean;
10
12
  }
11
13
  export declare function createEmptyState(): WizardState;
@@ -4,5 +4,6 @@ export function createEmptyState() {
4
4
  selectedPackages: [],
5
5
  embeddingProvider: null,
6
6
  apiKeys: {},
7
+ usePrefix: true,
7
8
  };
8
9
  }
@@ -8,6 +8,7 @@ describe("WizardState", () => {
8
8
  expect(state.selectedPackages).toEqual([]);
9
9
  expect(state.embeddingProvider).toBeNull();
10
10
  expect(state.apiKeys).toEqual({});
11
+ expect(state.usePrefix).toBe(true);
11
12
  });
12
13
  it("returns a new object each time", () => {
13
14
  const a = createEmptyState();
@@ -1 +1,4 @@
1
- export declare function runWizard(): Promise<void>;
1
+ export interface WizardOptions {
2
+ noPrefix?: boolean;
3
+ }
4
+ export declare function runWizard(opts?: WizardOptions): Promise<void>;
@@ -1,46 +1,98 @@
1
1
  import chalk from "chalk";
2
- import { isFirstRun, readConfig, ensureConfigDir } from "../../config/global.js";
2
+ import { select } from "@inquirer/prompts";
3
+ import { isFirstRun, readConfig, writeConfig, ensureConfigDir } from "../../config/global.js";
3
4
  import * as ui from "../../utils/ui.js";
4
5
  import { getActiveIntegrations } from "../../packages/registry.js";
6
+ import { isClaudeCliAvailable } from "../../packages/installer.js";
7
+ import { isInstalledPlugin, registerPlugin } from "../../packages/plugin.js";
5
8
  import { createEmptyState } from "./state.js";
6
9
  import { selectUseCase } from "./phases/use-case.js";
7
10
  import { installSelectedPackages } from "./phases/packages.js";
8
11
  import { configureKeys } from "./phases/configure.js";
9
12
  import { initProject } from "./phases/project.js";
10
13
  import { initGlobal } from "./phases/global-setup.js";
11
- export async function runWizard() {
14
+ export async function runWizard(opts) {
12
15
  console.log();
13
16
  console.log(` ${chalk.bold("swarmkit")} ${chalk.dim("— multi-agent infrastructure toolkit")}`);
14
17
  console.log();
15
18
  if (isFirstRun()) {
16
- await runFirstTimeSetup();
19
+ await runFirstTimeSetup(opts);
17
20
  }
18
21
  else {
19
- await runProjectSetup();
22
+ await runProjectSetup(opts);
20
23
  }
21
24
  }
22
- async function runFirstTimeSetup() {
25
+ async function runFirstTimeSetup(opts) {
23
26
  ensureConfigDir();
24
27
  // Step 1: Use case / bundle selection
25
28
  let state = await selectUseCase(createEmptyState());
29
+ if (opts?.noPrefix) {
30
+ state.usePrefix = false;
31
+ }
26
32
  // Step 2: Install packages
27
33
  await installSelectedPackages(state);
34
+ // Step 2.5: Plugin activation (for any Claude Code plugins)
35
+ await activatePlugins(state);
28
36
  // Step 3: Configure (embedding provider, API keys)
29
37
  state = await configureKeys(state);
30
- // Step 4: Global package setup (agent-iam, skill-tree, openswarm, openhive)
38
+ // Step 4: Global package setup (skill-tree, openhive)
31
39
  await initGlobal(state);
32
40
  // Step 5: Project init (if in a project directory)
33
41
  await initProject(state);
42
+ // Persist prefix preference
43
+ const config = readConfig();
44
+ config.usePrefix = state.usePrefix;
45
+ writeConfig(config);
34
46
  // Summary
35
47
  printSummary(state);
36
48
  }
37
- async function runProjectSetup() {
49
+ async function runProjectSetup(opts) {
38
50
  const config = readConfig();
39
51
  ui.info(`Global config found. ${config.installedPackages.length} packages installed.`);
40
52
  const state = createEmptyState();
41
53
  state.selectedPackages = [...config.installedPackages];
54
+ state.usePrefix = opts?.noPrefix === true ? false : (config.usePrefix ?? true);
42
55
  await initProject(state);
43
56
  }
57
+ async function activatePlugins(state) {
58
+ if (!(await isClaudeCliAvailable()))
59
+ return;
60
+ for (const pkg of state.selectedPackages) {
61
+ if (!(await isInstalledPlugin(pkg)))
62
+ continue;
63
+ console.log();
64
+ ui.info(`${pkg} is a Claude Code plugin.`);
65
+ const choice = await select({
66
+ message: `Activate ${pkg} as a Claude Code plugin?`,
67
+ choices: [
68
+ {
69
+ name: "Project (this repository only)",
70
+ value: "project",
71
+ },
72
+ {
73
+ name: "User (all projects)",
74
+ value: "user",
75
+ },
76
+ {
77
+ name: "Skip (activate later)",
78
+ value: "skip",
79
+ },
80
+ ],
81
+ });
82
+ if (choice === "skip") {
83
+ ui.info("Skipped. Activate later with: claude plugin add <path> --scope project|user");
84
+ continue;
85
+ }
86
+ try {
87
+ await registerPlugin(pkg, choice);
88
+ ui.success(`Plugin activated (${choice} scope).`);
89
+ }
90
+ catch (err) {
91
+ const msg = err instanceof Error ? err.message : String(err);
92
+ ui.fail(`Plugin activation failed: ${msg}`);
93
+ }
94
+ }
95
+ }
44
96
  function printSummary(state) {
45
97
  const integrations = getActiveIntegrations(state.selectedPackages);
46
98
  if (integrations.length > 0) {
@@ -2,9 +2,10 @@ export function registerInitCommand(program) {
2
2
  program
3
3
  .command("init")
4
4
  .description("Interactive setup wizard")
5
- .action(async () => {
5
+ .option("--no-prefix", "Use flat layout (e.g. .opentasks/) instead of nesting under .swarm/")
6
+ .action(async (opts) => {
6
7
  // Dynamic import to avoid loading @inquirer/prompts for other commands
7
8
  const { runWizard } = await import("./init/wizard.js");
8
- await runWizard();
9
+ await runWizard({ noPrefix: opts.prefix === false });
9
10
  });
10
11
  }
@@ -2,6 +2,7 @@ import chalk from "chalk";
2
2
  import { readConfig, removeInstalledPackage } from "../config/global.js";
3
3
  import { getLostIntegrations } from "../packages/registry.js";
4
4
  import { uninstallPackage, getInstalledVersion } from "../packages/installer.js";
5
+ import { isInstalledPlugin } from "../packages/plugin.js";
5
6
  import * as ui from "../utils/ui.js";
6
7
  export function registerRemoveCommand(program) {
7
8
  program
@@ -27,6 +28,8 @@ export function registerRemoveCommand(program) {
27
28
  }
28
29
  console.log();
29
30
  }
31
+ // Check if it's a plugin before uninstalling (while we can still resolve the path)
32
+ const wasPlugin = await isInstalledPlugin(packageName);
30
33
  // Uninstall
31
34
  console.log(` Uninstalling ${chalk.bold(packageName)}...`);
32
35
  const version = await getInstalledVersion(packageName);
@@ -44,6 +47,9 @@ export function registerRemoveCommand(program) {
44
47
  removeInstalledPackage(packageName);
45
48
  ui.blank();
46
49
  ui.info("Project data directories are preserved. Delete them manually if no longer needed.");
50
+ if (wasPlugin) {
51
+ ui.info(`If activated as a Claude Code plugin, also run: claude plugin uninstall ${packageName}`);
52
+ }
47
53
  ui.blank();
48
54
  });
49
55
  }
@@ -5,6 +5,8 @@ export interface GlobalConfig {
5
5
  embeddingProvider?: "openai" | "gemini" | "local";
6
6
  /** Embedding model (provider-specific) */
7
7
  embeddingModel?: string;
8
+ /** Whether project configs are nested under .swarm/ (default true) */
9
+ usePrefix?: boolean;
8
10
  }
9
11
  /** Get the swarmkit config directory path (~/.swarmkit/) */
10
12
  export declare function getConfigDir(): string;
@@ -67,12 +67,12 @@ describe("config/global", () => {
67
67
  });
68
68
  it("reads written config", () => {
69
69
  writeConfig({
70
- installedPackages: ["macro-agent"],
70
+ installedPackages: ["opentasks"],
71
71
  embeddingProvider: "openai",
72
72
  embeddingModel: "text-embedding-3-small",
73
73
  });
74
74
  const config = readConfig();
75
- expect(config.installedPackages).toEqual(["macro-agent"]);
75
+ expect(config.installedPackages).toEqual(["opentasks"]);
76
76
  expect(config.embeddingProvider).toBe("openai");
77
77
  expect(config.embeddingModel).toBe("text-embedding-3-small");
78
78
  });
@@ -112,23 +112,23 @@ describe("config/global", () => {
112
112
  describe("addInstalledPackages", () => {
113
113
  it("adds packages to an empty list", () => {
114
114
  writeConfig({ installedPackages: [] });
115
- addInstalledPackages(["macro-agent", "minimem"]);
115
+ addInstalledPackages(["opentasks", "minimem"]);
116
116
  const config = readConfig();
117
- expect(config.installedPackages).toEqual(["macro-agent", "minimem"]);
117
+ expect(config.installedPackages).toEqual(["minimem", "opentasks"]);
118
118
  });
119
119
  it("deduplicates packages", () => {
120
- writeConfig({ installedPackages: ["macro-agent"] });
121
- addInstalledPackages(["macro-agent", "minimem"]);
120
+ writeConfig({ installedPackages: ["opentasks"] });
121
+ addInstalledPackages(["opentasks", "minimem"]);
122
122
  const config = readConfig();
123
- expect(config.installedPackages).toEqual(["macro-agent", "minimem"]);
123
+ expect(config.installedPackages).toEqual(["minimem", "opentasks"]);
124
124
  });
125
125
  it("sorts packages alphabetically", () => {
126
- addInstalledPackages(["minimem", "agent-iam", "macro-agent"]);
126
+ addInstalledPackages(["minimem", "cognitive-core", "opentasks"]);
127
127
  const config = readConfig();
128
128
  expect(config.installedPackages).toEqual([
129
- "agent-iam",
130
- "macro-agent",
129
+ "cognitive-core",
131
130
  "minimem",
131
+ "opentasks",
132
132
  ]);
133
133
  });
134
134
  it("preserves other config fields", () => {
@@ -143,16 +143,16 @@ describe("config/global", () => {
143
143
  });
144
144
  describe("removeInstalledPackage", () => {
145
145
  it("removes a package from the list", () => {
146
- writeConfig({ installedPackages: ["macro-agent", "minimem"] });
146
+ writeConfig({ installedPackages: ["opentasks", "minimem"] });
147
147
  removeInstalledPackage("minimem");
148
148
  const config = readConfig();
149
- expect(config.installedPackages).toEqual(["macro-agent"]);
149
+ expect(config.installedPackages).toEqual(["opentasks"]);
150
150
  });
151
151
  it("does nothing if package is not in list", () => {
152
- writeConfig({ installedPackages: ["macro-agent"] });
152
+ writeConfig({ installedPackages: ["opentasks"] });
153
153
  removeInstalledPackage("minimem");
154
154
  const config = readConfig();
155
- expect(config.installedPackages).toEqual(["macro-agent"]);
155
+ expect(config.installedPackages).toEqual(["opentasks"]);
156
156
  });
157
157
  it("preserves other config fields", () => {
158
158
  writeConfig({
@@ -9,7 +9,7 @@ export declare function checkPackages(ctx: CheckContext): Promise<CheckResult[]>
9
9
  export declare function checkCredentials(ctx: CheckContext): CheckResult[];
10
10
  /**
11
11
  * Check that project-level config directories exist for installed packages.
12
- * Only runs when cwd is a project directory.
12
+ * Only runs when cwd is a project directory. Checks both .swarm/ and flat layouts.
13
13
  */
14
14
  export declare function checkProjectConfigs(ctx: CheckContext): CheckResult[];
15
15
  /**