brainctl 0.1.4 β†’ 0.1.6

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
@@ -1,121 +1,120 @@
1
1
  # 🧠 brainctl
2
2
 
3
- > Stop reconfiguring your AI tools.
3
+ > One AI setup. Multiple agents. Zero reconfiguration.
4
4
 
5
- `brainctl` is a CLI for managing a portable AI environment across tools like Claude Code and Codex.
5
+ **brainctl** is a cross-agent AI workflow manager that unifies your environment across Claude Code, Codex, and Gemini CLI β€” with a web dashboard, MCP server, and portable profiles.
6
6
 
7
- Define your memory, skills, and execution flow once, then reuse them across different AI agents.
7
+ [![npm version](https://img.shields.io/npm/v/brainctl)](https://www.npmjs.com/package/brainctl)
8
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)
9
+ [![Build](https://img.shields.io/github/actions/workflow/status/Rorogogogo/brainctl/deploy.yml?branch=main)](https://github.com/Rorogogogo/brainctl/actions)
8
10
 
9
11
  ---
10
12
 
11
- ## ✨ Why brainctl?
13
+ ## ✨ Features
12
14
 
13
- If you're using multiple AI tools, you've probably already hit the same problems:
14
-
15
- - Rewriting the same prompt for different agents
16
- - Losing context between tools
17
- - Rebuilding your environment every time you switch
18
-
19
- `brainctl` solves that with one core idea:
20
-
21
- > **One AI setup. Multiple agents.**
22
-
23
- ---
24
-
25
- ## πŸš€ Features
26
-
27
- - 🧠 File-based memory from Markdown files
28
- - 🧩 Reusable skills stored in `ai-stack.yaml`
29
- - πŸ”Œ Multi-agent execution with Claude and Codex
30
- - βš™οΈ Unified context builder
31
- - πŸ›  CLI-first workflow
32
- - πŸ” `status` and `doctor` for visibility
33
- - πŸ” Optional fallback agent support with `--fallback`
15
+ - πŸ”€ **Multi-agent support** β€” Claude Code, Codex, and Gemini CLI from one config
16
+ - πŸ–₯️ **Web dashboard** β€” Visual drag-and-drop MCP management across agents
17
+ - πŸ”Œ **MCP server** β€” 20 tools exposable to any MCP-compatible agent
18
+ - πŸ“¦ **Portable profiles** β€” Export/import skill + MCP bundles as tarballs
19
+ - 🧠 **Shared memory** β€” Markdown-based context files shared across agents
20
+ - 🧩 **Reusable skills** β€” Prompt templates stored in `ai-stack.yaml`
21
+ - πŸ”„ **Profile sync** β€” Push configs to all agents in one command
22
+ - 🩺 **Health checks** β€” `status` and `doctor` commands for visibility
23
+ - πŸ” **Fallback agents** β€” Automatic failover if primary agent is unavailable
34
24
 
35
25
  ---
36
26
 
37
- ## πŸ“¦ Installation
27
+ ## πŸ“Έ Demo
38
28
 
39
- ### Option 1: Install from npm
29
+ ### Web Dashboard β€” Drag MCPs between agents
40
30
 
41
- ```bash
42
- npm install -g brainctl
43
31
  ```
44
-
45
- Then:
46
-
47
- ```bash
48
- brainctl --help
32
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
33
+ β”‚ Claude β”‚ β”‚ Codex β”‚ β”‚ Gemini β”‚
34
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚
35
+ β”‚ β”‚ github β”‚β—„β”œβ”€β”€β”€β–Ίβ”‚ github β”‚ β”‚ β”‚ Drop here β”‚
36
+ β”‚ β”‚ brainctl β”‚ β”‚ β”‚ β”‚ brainctl β”‚ β”‚ β”‚ to copy β”‚
37
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚
38
+ β”‚ Skills: 11 β”‚ β”‚ Skills: 3 β”‚ β”‚ Skills: 0 β”‚
39
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
49
40
  ```
50
41
 
51
- ### Option 2: Local CLI install from source
42
+ The dashboard reads **live config files** from each agent (`~/.claude.json`, `~/.codex/config.toml`, `~/.gemini/settings.json`) and lets you drag MCPs between them. Changes are staged and only applied on confirm.
52
43
 
53
- ```bash
54
- npm install
55
- npm run build
56
- npm link
57
- ```
44
+ ---
58
45
 
59
- Then:
46
+ ## πŸ“¦ Installation
60
47
 
61
48
  ```bash
62
- brainctl --help
49
+ npm install -g brainctl
63
50
  ```
64
51
 
65
- ### Option 3: Run without linking
52
+ Or from source:
66
53
 
67
54
  ```bash
68
- npm install
69
- npm run build
70
- node dist/cli.js --help
55
+ git clone https://github.com/Rorogogogo/brainctl.git
56
+ cd brainctl
57
+ npm install && npm run build && npm link
71
58
  ```
72
59
 
73
- `brainctl` does not bundle agent CLIs. You still need at least one supported agent installed separately and available on `PATH`, such as `claude` or `codex`.
60
+ > **Prerequisite:** At least one supported agent CLI must be installed and on your `PATH` (`claude`, `codex`, or `gemini`).
74
61
 
75
62
  ---
76
63
 
77
- ## ⚑ Quick Start
78
-
79
- ### 1. Initialize a project
64
+ ## πŸš€ Quick Start
80
65
 
81
66
  ```bash
67
+ # 1. Initialize a project
82
68
  brainctl init
83
- ```
84
-
85
- This creates:
86
-
87
- - `ai-stack.yaml`
88
- - `memory/`
89
- - `memory/notes.md`
90
69
 
91
- ### 2. Inspect the setup
92
-
93
- ```bash
70
+ # 2. Check your setup
94
71
  brainctl status
95
72
  brainctl doctor
96
- ```
97
-
98
- ### 3. Run a task
99
73
 
100
- ```bash
74
+ # 3. Run a skill
101
75
  brainctl run summarize ./memory/notes.md --with claude
76
+
77
+ # 4. Launch the web dashboard
78
+ brainctl ui
79
+ # β†’ http://127.0.0.1:3333
102
80
  ```
103
81
 
104
- Or:
82
+ ---
83
+
84
+ ## πŸ“– Usage
105
85
 
106
- ```bash
107
- brainctl run summarize ./memory/notes.md --with codex
108
- ```
86
+ ### CLI Commands
87
+
88
+ | Command | Description |
89
+ |---------|-------------|
90
+ | `brainctl init` | Scaffold `ai-stack.yaml` and `memory/` directory |
91
+ | `brainctl status` | Show memory, skills, MCPs, and agent availability |
92
+ | `brainctl doctor` | Validate config, paths, and installed agents |
93
+ | `brainctl run <skill> <file> --with <agent>` | Execute a skill through an agent |
94
+ | `brainctl profile list` | List available profiles |
95
+ | `brainctl profile create <name>` | Create a new profile |
96
+ | `brainctl profile use <name>` | Switch active profile |
97
+ | `brainctl profile export <name>` | Export profile as portable tarball |
98
+ | `brainctl profile import <archive>` | Import profile from tarball |
99
+ | `brainctl sync` | Sync active profile to all agent configs |
100
+ | `brainctl ui` | Start the web dashboard |
109
101
 
110
- With fallback:
102
+ ### Run Examples
111
103
 
112
104
  ```bash
113
- brainctl run summarize ./memory/notes.md --with claude --fallback codex
105
+ # Basic execution
106
+ brainctl run summarize ./notes.md --with claude
107
+
108
+ # With fallback agent
109
+ brainctl run analyze ./report.md --with codex --fallback claude
110
+
111
+ # Using Gemini
112
+ brainctl run review ./code.md --with gemini
114
113
  ```
115
114
 
116
115
  ---
117
116
 
118
- ## 🧠 Example `ai-stack.yaml`
117
+ ## 🧠 Config: `ai-stack.yaml`
119
118
 
120
119
  ```yaml
121
120
  memory:
@@ -124,119 +123,144 @@ memory:
124
123
 
125
124
  skills:
126
125
  summarize:
127
- description: Summarize content
126
+ description: Summarize content into bullet points
128
127
  prompt: |
129
128
  Summarize the following content into concise bullet points.
130
129
 
131
- analyze:
132
- description: Analyze content deeply
130
+ review:
131
+ description: Code review with actionable feedback
133
132
  prompt: |
134
- Analyze the following content and extract key insights.
133
+ Review the following code and provide actionable feedback.
135
134
 
136
135
  mcps: {}
137
136
  ```
138
137
 
139
- ---
138
+ ### How Context Assembly Works
140
139
 
141
- ## 🧩 How It Works
140
+ ```
141
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
142
+ β”‚ MEMORY β”‚ ← Markdown files from configured paths
143
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
144
+ β”‚ SKILL β”‚ ← Prompt template from ai-stack.yaml
145
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
146
+ β”‚ INPUT β”‚ ← Your file
147
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
148
+ ↓
149
+ Agent CLI (claude / codex / gemini)
150
+ ```
142
151
 
143
- `brainctl` builds a unified context before calling an agent:
152
+ ---
144
153
 
145
- ```text
146
- --- MEMORY ---
147
- [your markdown files]
154
+ ## πŸ”Œ MCP Server
148
155
 
149
- --- SKILL ---
150
- [prompt template]
156
+ brainctl exposes **20 MCP tools** that any compatible agent can call:
151
157
 
152
- --- INPUT ---
153
- [your file]
158
+ ```bash
159
+ # Add brainctl as an MCP server in your agent config
160
+ # Claude (~/.claude.json):
161
+ {
162
+ "mcpServers": {
163
+ "brainctl": {
164
+ "type": "stdio",
165
+ "command": "npx",
166
+ "args": ["-y", "brainctl", "mcp"]
167
+ }
168
+ }
169
+ }
154
170
  ```
155
171
 
156
- That context is then sent to the selected agent over stdin.
157
-
158
- ---
159
-
160
- ## πŸ›  Usage
172
+ **Available tools:**
161
173
 
162
- ### Commands
174
+ | Category | Tools |
175
+ |----------|-------|
176
+ | **Skills** | `list_skills`, `get_skill`, `run` |
177
+ | **Memory** | `read_memory`, `write_memory` |
178
+ | **Profiles** | `list_profiles`, `get_profile`, `create_profile`, `update_profile`, `delete_profile`, `switch_profile`, `copy_profile_items`, `export_profile`, `import_profile` |
179
+ | **Agent Configs** | `read_agent_configs`, `add_agent_mcp`, `remove_agent_mcp` |
180
+ | **System** | `status`, `doctor`, `sync` |
163
181
 
164
- | Command | Purpose |
165
- | --- | --- |
166
- | `brainctl init` | Initialize `ai-stack.yaml` and memory files |
167
- | `brainctl status` | Show memory, skills, MCP count, and agent availability |
168
- | `brainctl doctor` | Validate config, memory paths, skills, and installed agents |
169
- | `brainctl run <skill> <file> --with <agent>` | Build context and execute with an agent |
182
+ ---
170
183
 
171
- ### Examples
184
+ ## πŸ–₯️ Web Dashboard
172
185
 
173
186
  ```bash
174
- brainctl run summarize ./memory/notes.md --with claude
175
- brainctl run analyze ./memory/notes.md --with codex
176
- brainctl run summarize ./memory/notes.md --with claude --fallback codex
187
+ brainctl ui
177
188
  ```
178
189
 
190
+ Opens a local dashboard at `http://127.0.0.1:3333` with:
191
+
192
+ - **Agent Profiles** β€” See live MCPs and skills for Claude, Codex, and Gemini side-by-side
193
+ - **Drag & Drop** β€” Copy MCPs between agents by dragging cards
194
+ - **Staged Changes** β€” Preview adds/removes before applying, with undo support
195
+ - **Skills Editor** β€” Edit skill prompts with live preview
196
+ - **MCP Manager** β€” View and edit MCP configurations
197
+ - **Memory Viewer** β€” Browse shared markdown memory files
198
+ - **Run Console** β€” Execute skills with real-time streaming output
199
+
179
200
  ---
180
201
 
181
- ## πŸ“‚ Project Structure
202
+ ## πŸ—οΈ Architecture
182
203
 
183
- ```text
204
+ ```
184
205
  brainctl/
185
206
  β”œβ”€β”€ src/
186
- β”‚ β”œβ”€β”€ cli.ts
187
- β”‚ β”œβ”€β”€ config.ts
188
- β”‚ β”œβ”€β”€ context/
189
- β”‚ β”œβ”€β”€ commands/
190
- β”‚ β”œβ”€β”€ executor/
191
- β”‚ └── services/
192
- β”œβ”€β”€ tests/
193
- β”œβ”€β”€ ai-stack.yaml
194
- β”œβ”€β”€ memory/
195
- β”œβ”€β”€ package.json
196
- └── tsconfig.json
207
+ β”‚ β”œβ”€β”€ cli.ts # CLI entry point (Commander)
208
+ β”‚ β”œβ”€β”€ commands/ # 8 command handlers
209
+ β”‚ β”œβ”€β”€ services/ # 11 business logic services
210
+ β”‚ β”‚ └── sync/ # Agent config readers/writers
211
+ β”‚ β”œβ”€β”€ context/ # Memory loader, skill resolver, context builder
212
+ β”‚ β”œβ”€β”€ executor/ # Agent spawning (Claude, Codex, Gemini)
213
+ β”‚ β”œβ”€β”€ mcp/ # FastMCP server (20 tools)
214
+ β”‚ └── ui/ # HTTP server with SSE streaming
215
+ β”œβ”€β”€ web/src/ # React dashboard (Vite + dnd-kit)
216
+ β”œβ”€β”€ tests/ # Vitest test suite
217
+ └── ai-stack.yaml # Project config
197
218
  ```
198
219
 
220
+ ### Agent Config Locations
221
+
222
+ | Agent | Config Path | MCP Location |
223
+ |-------|-------------|-------------|
224
+ | Claude | `~/.claude.json` | `projects[cwd].mcpServers` |
225
+ | Codex | `~/.codex/config.toml` | `[mcp_servers.*]` |
226
+ | Gemini | `~/.gemini/settings.json` | `mcpServers` |
227
+
199
228
  ---
200
229
 
201
230
  ## πŸ§ͺ Development
202
231
 
203
232
  ```bash
204
233
  npm install
205
- npm test
206
- npm run build
234
+ npm test # Run all tests (Vitest)
235
+ npm run build # Build server (tsc) + web (Vite)
236
+ npm run dev -- <args> # Run CLI via tsx
207
237
  ```
208
238
 
209
239
  ---
210
240
 
211
- ## 🧠 Philosophy
212
-
213
- `brainctl` does not replace your AI tools.
214
-
215
- It sits between you and them as a thin orchestration layer:
241
+ ## 🀝 Contributing
216
242
 
217
- - You keep using Claude, Codex, and other agent CLIs
218
- - `brainctl` keeps the environment consistent
243
+ Contributions are welcome! Please open an issue or submit a pull request.
219
244
 
220
- ---
221
-
222
- ## πŸ—Ί Roadmap
223
-
224
- - [ ] JSON output mode
225
- - [ ] Multi-agent pipelines
226
- - [ ] MCP runtime integration
227
- - [ ] Better execution tracing and logs
228
- - [ ] UI / dashboard
245
+ ```bash
246
+ git clone https://github.com/Rorogogogo/brainctl.git
247
+ cd brainctl
248
+ npm install
249
+ npm test
250
+ ```
229
251
 
230
252
  ---
231
253
 
232
- ## πŸ’‘ Inspiration
254
+ ## πŸ’‘ Philosophy
233
255
 
234
- AI tools are getting more powerful, but also more fragmented.
256
+ brainctl doesn't replace your AI tools. It sits between you and them as a thin orchestration layer:
235
257
 
236
- `brainctl` is an attempt to bring state, structure, and consistency to that workflow.
258
+ - **You keep using** Claude Code, Codex, and Gemini CLI directly
259
+ - **brainctl keeps** the environment consistent across all of them
260
+ - **Profiles make it portable** β€” share your setup with your team
237
261
 
238
262
  ---
239
263
 
240
264
  ## πŸ“„ License
241
265
 
242
- MIT
266
+ [MIT](https://opensource.org/licenses/MIT) β€” use it however you want.
package/dist/cli.d.ts CHANGED
@@ -2,6 +2,8 @@
2
2
  import { Command } from 'commander';
3
3
  import { type DoctorService } from './services/doctor-service.js';
4
4
  import { type InitService } from './services/init-service.js';
5
+ import { type ProfileExportService } from './services/profile-export-service.js';
6
+ import { type ProfileImportService } from './services/profile-import-service.js';
5
7
  import { type ProfileService } from './services/profile-service.js';
6
8
  import { type RunService } from './services/run-service.js';
7
9
  import { type StatusService } from './services/status-service.js';
@@ -12,6 +14,8 @@ export interface CliServices {
12
14
  statusService: StatusService;
13
15
  doctorService: DoctorService;
14
16
  profileService: ProfileService;
17
+ profileExportService: ProfileExportService;
18
+ profileImportService: ProfileImportService;
15
19
  syncService: SyncService;
16
20
  }
17
21
  export declare function createProgram(overrides?: Partial<CliServices>): Command;
package/dist/cli.js CHANGED
@@ -14,6 +14,8 @@ import { registerUiCommand } from './commands/ui.js';
14
14
  import { printError } from './output.js';
15
15
  import { createDoctorService } from './services/doctor-service.js';
16
16
  import { createInitService } from './services/init-service.js';
17
+ import { createProfileExportService } from './services/profile-export-service.js';
18
+ import { createProfileImportService } from './services/profile-import-service.js';
17
19
  import { createProfileService } from './services/profile-service.js';
18
20
  import { createRunService } from './services/run-service.js';
19
21
  import { createStatusService } from './services/status-service.js';
@@ -31,7 +33,11 @@ export function createProgram(overrides = {}) {
31
33
  registerStatusCommand(program, services.statusService);
32
34
  registerRunCommand(program, services.runService);
33
35
  registerDoctorCommand(program, services.doctorService);
34
- registerProfileCommand(program, services.profileService);
36
+ registerProfileCommand(program, {
37
+ profileService: services.profileService,
38
+ profileExportService: services.profileExportService,
39
+ profileImportService: services.profileImportService,
40
+ });
35
41
  registerSyncCommand(program, services.syncService);
36
42
  registerUiCommand(program);
37
43
  registerMcpCommand(program);
@@ -62,6 +68,8 @@ function createDefaultServices(overrides) {
62
68
  statusService: createStatusService({ resolver }),
63
69
  doctorService: createDoctorService({ resolver }),
64
70
  profileService,
71
+ profileExportService: createProfileExportService({ profileService }),
72
+ profileImportService: createProfileImportService(),
65
73
  syncService: createSyncService({ profileService }),
66
74
  ...overrides
67
75
  };
@@ -1,3 +1,10 @@
1
1
  import type { Command } from 'commander';
2
+ import type { ProfileExportService } from '../services/profile-export-service.js';
3
+ import type { ProfileImportService } from '../services/profile-import-service.js';
2
4
  import type { ProfileService } from '../services/profile-service.js';
3
- export declare function registerProfileCommand(program: Command, profileService: ProfileService): void;
5
+ export interface ProfileCommandServices {
6
+ profileService: ProfileService;
7
+ profileExportService: ProfileExportService;
8
+ profileImportService: ProfileImportService;
9
+ }
10
+ export declare function registerProfileCommand(program: Command, services: ProfileCommandServices): void;
@@ -1,5 +1,6 @@
1
1
  import pc from 'picocolors';
2
- export function registerProfileCommand(program, profileService) {
2
+ export function registerProfileCommand(program, services) {
3
+ const { profileService, profileExportService, profileImportService } = services;
3
4
  const profileCmd = program
4
5
  .command('profile')
5
6
  .description('Manage brainctl profiles');
@@ -40,4 +41,33 @@ export function registerProfileCommand(program, profileService) {
40
41
  const prev = result.previousProfile ? ` (was "${result.previousProfile}")` : '';
41
42
  console.log(`Switched to profile "${name}"${prev}`);
42
43
  });
44
+ profileCmd
45
+ .command('export')
46
+ .argument('<name>', 'Profile name to export')
47
+ .option('-o, --output <path>', 'Output file path')
48
+ .description('Export a profile as a portable tarball')
49
+ .action(async (name, options) => {
50
+ const result = await profileExportService.execute({
51
+ cwd: process.cwd(),
52
+ name,
53
+ outputPath: options.output,
54
+ });
55
+ console.log(`Exported profile to ${result.archivePath}`);
56
+ });
57
+ profileCmd
58
+ .command('import')
59
+ .argument('<archive>', 'Path to profile tarball')
60
+ .option('--force', 'Overwrite existing profile', false)
61
+ .description('Import a profile from a tarball')
62
+ .action(async (archive, options) => {
63
+ const result = await profileImportService.execute({
64
+ cwd: process.cwd(),
65
+ archivePath: archive,
66
+ force: options.force,
67
+ });
68
+ console.log(`Imported profile "${result.profileName}"`);
69
+ if (result.installedMcps.length > 0) {
70
+ console.log(`Installed bundled MCPs: ${result.installedMcps.join(', ')}`);
71
+ }
72
+ });
43
73
  }