clementine-agent 1.5.0 → 1.6.0

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
@@ -20,43 +20,15 @@ Connects to Discord, Slack, Telegram, WhatsApp, and webhooks. Remembers everythi
20
20
 
21
21
  ## How it works
22
22
 
23
- Clementine is three layers stacked on a shared memory store:
24
-
25
- ```
26
- ┌─────────────────────────────────────────┐
27
- │ Channel Layer │
28
- Discord · Slack · Telegram · WhatsApp │
29
- Webhook API · Discord Guild Channels │
30
- └────────────────┬────────────────────────┘
31
-
32
- ┌────────────────▼────────────────────────┐
33
- │ Gateway Layer │
34
- │ Router · Session Manager · Heartbeat │
35
- │ Cron Scheduler · Unleashed Engine │
36
- │ Notification Dispatch │
37
- └────────────────┬────────────────────────┘
38
-
39
- ┌────────────────▼────────────────────────┐
40
- │ Agent Layer │
41
- │ Claude Code SDK · Security Hooks │
42
- │ Auto-Memory · Session Rotation │
43
- │ Agent Profiles · Sub-Agent Teams │
44
- │ Self-Improvement Loop │
45
- └────────────────┬────────────────────────┘
46
-
47
- ┌────────────────▼────────────────────────┐
48
- │ MCP Tool Server │
49
- │ 30+ tools over stdio transport │
50
- │ Memory · Tasks · Vault · Workspace │
51
- └────────────────┬────────────────────────┘
52
-
53
- ┌──────────────────────▼──────────────────────┐
54
- │ Memory Store │
55
- │ SQLite FTS5 · Salience Scoring · Decay │
56
- │ Episodic Memory · Wikilink Graph │
57
- │ FalkorDB Knowledge Graph · Procedural Skills│
58
- │ Obsidian Vault (source of truth) │
59
- └─────────────────────────────────────────────┘
23
+ Clementine is four layers over a shared memory store:
24
+
25
+ ```
26
+ Channels → Gateway → Agent → MCP tools → Memory
27
+ Discord Router Claude SDK 100+ tools SQLite FTS5
28
+ Slack Sessions Security hooks stdio + vectors
29
+ Telegram Heartbeats Auto-memory Knowledge graph
30
+ WhatsApp Cron + queues Sub-agents Obsidian vault
31
+ Webhook Delivery Self-improve (source of truth)
60
32
  ```
61
33
 
62
34
  ### The memory loop
@@ -86,7 +58,7 @@ clementine dashboard # open the web command center
86
58
 
87
59
  Already installed? Update in place with `clementine update`.
88
60
 
89
- ### Troubleshooting
61
+ ### Install issues
90
62
 
91
63
  **`EACCES: permission denied` on `npm install -g`.** Your Node was installed system-wide (`/usr/local/lib/...`) and npm can't write there without sudo. Fix it once, permanently:
92
64
 
@@ -127,72 +99,34 @@ Handles system dependencies (redis, libomp, build tools), npm packages, TypeScri
127
99
  ~/.clementine/ ← Data home (created on first run)
128
100
  ├── .env ← Configuration (created by setup wizard)
129
101
  ├── .sessions.json ← Session persistence
130
- ├── .memory.db ← (legacy, unused — real DB is vault/.memory.db)
131
102
  ├── .clementine.pid ← Daemon PID lock
132
- ├── logs/
133
- │ ├── clementine.log ← Daemon stdout/stderr
134
- │ └── audit.log ← Security audit trail
103
+ ├── logs/ ← Daemon log + security audit log
135
104
  ├── cron/runs/ ← Per-job JSONL run logs
136
- ├── unleashed/ Unleashed task progress & checkpoints
137
- │ └── <task>/
138
- ├── status.json Current status, phase, timing
139
- └── progress.jsonl Phase-by-phase event log
140
- ├── self-improve/ Self-improvement state
141
- │ ├── experiment-log.jsonl ← Append-only experiment history
142
- │ ├── state.json Loop status, baseline metrics
143
- │ └── pending-changes/ Proposed diffs awaiting approval
144
- └── {experiment-id}.json
145
- └── vault/ ← Obsidian-compatible vault
146
- ├── 00-System/ SOUL.md, MEMORY.md, HEARTBEAT.md, CRON.md
147
- └── skills/ ← Procedural memory (auto-extracted from successful tasks)
148
- ├── 01-Daily-Notes/ Auto-generated daily logs (YYYY-MM-DD.md)
149
- ├── 02-People/ ← Person notes (auto-created from conversations)
150
- ├── 03-Projects/ Project notes
151
- ├── 04-Topics/ ← Knowledge topics
152
- ├── 05-Tasks/ TASKS.md master list ({T-NNN} IDs)
153
- ├── 06-Templates/ Note templates
154
- └── 07-Inbox/ Quick captures
155
-
156
- src/ Package code (wherever npm installed it)
157
- ├── agent/
158
- ├── assistant.ts PersonalAssistant the brain
159
- ├── hooks.ts Security enforcement (3-tier model)
160
- │ ├── profiles.ts Agent profile switching
161
- │ └── self-improve.ts ← Nightly self-improvement loop engine
162
- ├── channels/
163
- │ ├── discord.ts ← Discord.js adapter
164
- │ ├── slack.ts ← Slack Socket Mode adapter
165
- │ ├── telegram.ts ← grammY adapter
166
- │ ├── whatsapp.ts ← Twilio WhatsApp bridge
167
- │ └── webhook.ts ← HTTP webhook API
168
- ├── gateway/
169
- │ ├── router.ts ← Message routing + session management
170
- │ ├── heartbeat.ts ← HeartbeatScheduler + CronScheduler
171
- │ └── notifications.ts ← Channel-agnostic notification fan-out
172
- ├── memory/
173
- │ ├── store.ts ← SQLite FTS5 memory store + embedding backfill
174
- │ ├── embeddings.ts ← TF-IDF embedding provider (local, 512-dim vectors)
175
- │ ├── search.ts ← Temporal decay, dedup, formatting
176
- │ ├── chunker.ts ← Vault file parser (## headers, frontmatter)
177
- │ ├── mmr.ts ← Maximal Marginal Relevance reranker
178
- │ ├── consolidation.ts ← Evening consolidation engine (dedup, summarize, extract)
179
- │ ├── context-assembler.ts ← Token-budgeted context slot filler
180
- │ └── graph-store.ts ← FalkorDB knowledge graph layer (optional)
181
- ├── tools/ ← MCP stdio server (30+ tools, decomposed by domain)
182
- │ ├── mcp-server.ts ← Server entry + registration
183
- │ ├── goal-tools.ts ← Goal lifecycle tools
184
- │ ├── vault-tools.ts ← Vault read/write/search tools
185
- │ ├── team-tools.ts ← Team agent tools
186
- │ ├── session-tools.ts ← Session management tools
187
- │ └── admin-tools.ts ← System admin tools
188
- ├── cli/
189
- │ ├── index.ts ← CLI commands (launch, stop, status, config, doctor)
190
- │ ├── setup.ts ← Interactive configuration wizard
191
- │ ├── dashboard.ts ← Local web dashboard (command center)
192
- │ └── cron.ts ← Cron job runner and scheduler
193
- ├── config.ts ← Paths, secrets, models (never pollutes process.env)
194
- ├── types.ts ← Shared TypeScript interfaces
195
- └── index.ts ← Main entry point (multi-channel startup)
105
+ ├── unleashed/<task>/ Long-running task progress + status
106
+ ├── self-improve/ ← Experiment log, state, pending proposals
107
+ ├── heartbeat/agents/<slug>/ Per-agent heartbeat state
108
+ └── vault/ Obsidian-compatible vault (see Vault section)
109
+ └── .memory.db SQLite FTS5 + vector index
110
+
111
+ src/ Package code (npm install location)
112
+ ├── agent/ The brain: assistant, hooks, agent manager,
113
+ proactive engine, self-improvement, advisor,
114
+ │ skill extraction, complexity classifier, …
115
+ ├── channels/ Discord, Slack, Telegram, WhatsApp, Webhook
116
+ (+ per-agent Discord/Slack bot managers)
117
+ ├── gateway/ Router, heartbeat schedulers, cron scheduler,
118
+ │ delivery queue, failure monitor
119
+ ├── memory/ SQLite FTS5 store, embeddings, MMR rerank,
120
+ │ chunker, consolidation, graph store
121
+ ├── tools/ MCP stdio server (100+ tools, by domain)
122
+ ├── cli/ CLI entry, setup wizard, dashboard, cron runner
123
+ ├── brain/ Ingestion pipeline + connectors
124
+ ├── analytics/ ← Tool-usage telemetry
125
+ ├── security/, secrets/ Secret/credential helpers, hardening
126
+ ├── vault-migrations/ ← Versioned vault upgrades
127
+ ├── config.ts Paths, secrets, models (never leaks to env)
128
+ ├── types.ts Shared TypeScript types
129
+ └── index.ts Multi-channel startup entry
196
130
  ```
197
131
 
198
132
  ### Code vs. data separation
@@ -220,143 +154,99 @@ Secrets never reach the Claude subprocess — `SAFE_ENV` filters credentials fro
220
154
 
221
155
  ### Memory architecture
222
156
 
223
- Three-layer retrieval merges full-text, vector, and recency signals into a single ranked context window:
224
-
225
- ```
226
- User message
227
-
228
- ├──▶ Layer 1: FTS5 (BM25 relevance)
229
- ├──▶ Layer 2: TF-IDF vector similarity (cosine, threshold 0.15)
230
- ├──▶ Layer 3: Recent chunks (time-windowed)
231
-
232
-
233
- ┌──────────────────┐ ┌────────────────────┐
234
- │ MMR rerank │────▶│ Context assembly │──▶ System prompt
235
- │ + deduplication │ │ (token-budgeted) │
236
- └──────────────────┘ └────────────────────┘
237
-
238
- │ salience boost on retrieval
239
-
240
- ┌──────────────┐ ┌────────────────────┐
241
- │ Assistant │────▶│ Auto-memory pass │──▶ Vault writes
242
- │ responds │ │ (background Sonnet) │ (MEMORY.md, people, tasks)
243
- └──────────────┘ └────────────────────┘
244
-
245
-
246
- ┌──────────────┐
247
- │ Session │──▶ Episodic chunk indexed
248
- │ summarization │ (sector='episodic')
249
- └──────────────┘
250
-
251
-
252
- ┌──────────────────────┐
253
- │ Evening consolidation │──▶ Dedup (Jaccard) + topic summarization (LLM)
254
- │ + embedding rebuild │ + principle extraction + TF-IDF vocab rebuild
255
- └──────────────────────┘
256
-
257
-
258
- ┌──────────────┐
259
- │ Startup │──▶ Temporal decay + pruning
260
- │ maintenance │ (stale memories sink, old data trimmed)
261
- └──────────────┘
262
- ```
263
-
264
- - **FTS5** — Full-text search with BM25 ranking, zero-cost, zero-latency
265
- - **TF-IDF embeddings** — Local 512-dim vectors (no API calls), vocabulary rebuilt during sync and evening consolidation, cosine similarity search over recent chunks
266
- - **MMR reranking** — Maximal Marginal Relevance via Jaccard similarity removes near-duplicates and promotes diversity in results
267
- - **Salience scoring** — Chunks gain score on retrieval, decay over time (7-day half-life). Formula: `log(access_count + 1) * 0.15 + recency_decay * 0.3`
157
+ Retrieval merges three signals (FTS5 BM25, TF-IDF cosine, recency), reranks with MMR for diversity, and fills a token-budgeted context window. After each turn, a background Sonnet pass extracts memories to the vault. Sessions get summarized into episodic chunks. A nightly consolidation pass dedups, summarizes, and rebuilds the embedding vocabulary. Startup applies temporal decay and prunes old data.
158
+
159
+ - **FTS5** — Full-text BM25 search, local, zero-cost
160
+ - **TF-IDF embeddings** — Local 512-dim vectors (no API calls), rebuilt nightly
161
+ - **MMR reranking** — Jaccard-based diversity, removes near-duplicates
162
+ - **Salience** Boost on retrieval, 7-day half-life decay
268
163
  - **Episodic memory** — Session summaries indexed as searchable chunks
269
- - **Wikilink graph** — `[[wikilinks]]` parsed and queryable for connection discovery
270
- - **Knowledge graph** — FalkorDB-powered typed relationships and multi-hop traversal (people projects topics). Visualized on a dark canvas in the dashboard with type legend and edge labels.
271
- - **Procedural skills** — Reusable how-to recipes auto-extracted from successful task executions. Stored as Markdown in `vault/00-System/skills/` and injected into cron jobs and unleashed tasks at runtime. Teach new skills manually via the dashboard Skills tab or let Clementine learn them from conversations.
272
- - **Evening consolidation** — Nightly pass: deduplicates chunks by Jaccard similarity (>70%), summarizes topic groups via LLM (Haiku), extracts recurring behavioral corrections into permanent rules, and rebuilds TF-IDF vocabulary + backfills embeddings
273
- - **Agent isolation** — Per-agent memory scoping via `agent_slug` column. Soft mode (default) boosts matching agent chunks 1.4x; strict mode filters to agent + global only
274
- - **Memory transparency** — Every memory write is logged to `memory_extractions` with user correction/dismissal support from the dashboard
275
- - **Temporal decay** — Applied on every startup; stale memories naturally sink
276
- - **Pruning** Episodic chunks >90 days with salience <0.01 are removed; old transcripts, access logs, and orphaned references trimmed
277
-
278
- ### MCP tools (30+)
279
-
280
- | Tool | Description |
281
- |------|-------------|
282
- | `memory_read` | Read vault notes (shortcuts: today, yesterday, memory, tasks, soul) |
283
- | `memory_write` | Write/append to vault (daily log, MEMORY.md sections, arbitrary notes) |
284
- | `memory_search` | FTS5 full-text search across all vault notes |
285
- | `memory_recall` | Combined FTS5 + recency search with salience boost |
286
- | `memory_connections` | Query the wikilink graph for a note |
287
- | `memory_timeline` | Chronological view of vault changes by date range |
288
- | `transcript_search` | Search past conversation transcripts |
289
- | `note_create` | Create notes (person, project, topic, task, inbox) |
290
- | `note_take` | Quick timestamped capture to daily log |
291
- | `daily_note` | Create or read today's daily note |
292
- | `task_list` | List tasks with status/project filters |
293
- | `task_add` | Add tasks with priority, due dates, projects |
294
- | `task_update` | Update task status (supports recurring tasks) |
295
- | `vault_stats` | Dashboard of vault health and activity |
296
- | `rss_fetch` | Fetch and parse RSS/Atom feeds |
297
- | `github_prs` | Check GitHub PRs (review-requested + authored) |
298
- | `browser_screenshot` | Take screenshots via Kernel cloud browser |
299
- | `set_timer` | Set short-term reminders (notifies via active channels) |
300
- | `outlook_inbox` | Read recent emails from Outlook inbox |
301
- | `outlook_search` | Search Outlook emails by query |
302
- | `outlook_calendar` | View upcoming calendar events |
303
- | `outlook_draft` | Create an email draft in Outlook |
304
- | `outlook_send` | Send an email from Outlook (Tier 3, requires approval) |
305
- | `discord_channel_send` | Post messages to any Discord text channel by ID |
306
- | `workspace_config` | Add, remove, or list workspace directories at runtime |
307
- | `workspace_list` | Scan workspace directories for local project roots |
308
- | `workspace_info` | Read a project's README, CLAUDE.md, manifest, and directory tree |
309
- | `add_cron_job` | Create scheduled tasks (supports standard and unleashed mode, project context) |
310
- | `self_restart` | Restart the daemon (for self-updates and config changes) |
311
- | `analyze_image` | Analyze images with vision capabilities |
312
- | `memory_report` | Generate a transparency report of all memory extractions |
313
- | `memory_correct` | Correct or dismiss a previously extracted memory |
314
- | `feedback_log` | Log user feedback on responses |
315
- | `feedback_report` | View feedback history and patterns |
316
- | `team_list` | List all team agents with status, channel, and capabilities |
317
- | `team_message` | Send a message to another agent (permission-scoped, synchronous) |
318
- | `create_agent` | Create a new agent with name, role, tools, project, and team connections |
319
- | `self_improve_status` | Check self-improvement state, pending approvals, experiment history |
320
- | `self_improve_run` | Trigger a self-improvement analysis cycle |
164
+ - **Wikilink + knowledge graph** — `[[wikilinks]]` graph + optional FalkorDB typed relationships (visualized in dashboard)
165
+ - **Procedural skills** — Auto-extracted from successful tasks, stored at `vault/00-System/skills/`, injected into future runs
166
+ - **Evening consolidation** — Nightly: Jaccard dedup (>70%), topic summarization (Haiku), behavioral-rule extraction, vocabulary rebuild
167
+ - **Agent isolation** — Per-agent scoping via `agent_slug`; soft (1.4× boost) or strict modes
168
+ - **Transparency** — Every write logged to `memory_extractions`; correct/dismiss from dashboard
169
+ - **Pruning** — Episodic >90 days with salience <0.01 removed; old transcripts and access logs trimmed
170
+
171
+ ### MCP tools (100+)
172
+
173
+ Tools are grouped by domain. Run `clementine tools` to see the live list.
174
+
175
+ | Group | Examples |
176
+ |-------|----------|
177
+ | **Memory** | `memory_read`, `memory_write`, `memory_search`, `memory_recall`, `memory_connections`, `memory_timeline`, `memory_consolidate`, `memory_correct`, `memory_report`, `memory_graph_*` |
178
+ | **Vault & notes** | `note_create`, `note_take`, `daily_note`, `task_list`, `task_add`, `task_update`, `vault_stats`, `transcript_search` |
179
+ | **Workspace** | `workspace_config`, `workspace_list`, `workspace_info` |
180
+ | **External** | `web_search`, `rss_fetch`, `github_prs`, `browser_screenshot`, `analyze_image`, `outlook_*`, `sf_*` (Salesforce), `discord_channel_*` |
181
+ | **Agents & teams** | `create_agent`, `update_agent`, `delete_agent`, `team_list`, `team_message`, `team_request`, `team_status`, `delegate_task`, `wake_agent` |
182
+ | **Goals & background** | `goal_create`, `goal_update`, `goal_work`, `start_background_task`, `get_background_task`, `discover_work` |
183
+ | **Cron & workflows** | `add_cron_job`, `cron_list`, `cron_run_history`, `trigger_cron_job`, `workflow_create`, `workflow_run`, `workflow_save`, `workflow_*` |
184
+ | **Self-improvement** | `self_improve_run`, `self_improve_status`, `self_edit_source`, `prompt_override_*`, `decision_reflection`, `feedback_log`, `feedback_report` |
185
+ | **System** | `self_restart`, `self_update`, `set_timer`, `env_set`, `allow_tool`, `setup_integration`, `auth_profile_status` |
321
186
 
322
187
  ---
323
188
 
324
189
  ## CLI reference
325
190
 
191
+ Run `clementine --help` to see everything; the most common commands:
192
+
193
+ **Daemon**
194
+ ```
195
+ clementine launch [-f] [--install] Start daemon (foreground / macOS login service)
196
+ clementine stop | restart | rebuild Lifecycle controls
197
+ clementine status PID, uptime, active channels
198
+ clementine update [--dry-run] Pull latest, rebuild, reinstall (preserves config)
199
+ clementine doctor [--fix] Verify (and optionally repair) config and vault
200
+ clementine dashboard Open the web command center (localhost:3030)
201
+ clementine tools List available MCP tools, plugins, and channels
202
+ ```
203
+
204
+ **Config & secrets**
326
205
  ```
327
- clementine launch Start as background daemon (default)
328
- clementine launch -f Start in foreground (debug mode)
329
- clementine launch --install Install as macOS login service (survives reboots)
330
- clementine stop Stop the daemon
331
- clementine restart Stop + relaunch
332
- clementine rebuild Build + restart daemon + dashboard in one step
333
- clementine status Show PID, uptime, active channels
334
- clementine update Pull latest, rebuild, reinstall (preserves config)
335
- clementine update --dry-run Preview update without making changes
336
- clementine doctor Verify configuration and vault health
337
- clementine doctor --fix Auto-fix common issues (redis, sqlite, FalkorDB)
338
- clementine dashboard Open the local web command center (localhost:3030)
339
- clementine tools List available MCP tools, plugins, and channels
340
- clementine config setup Interactive configuration wizard
341
- clementine config set KEY VAL Set a single config value
342
- clementine config get KEY Read a config value
343
- clementine config edit Open .env in your editor ($EDITOR)
344
- clementine memory search <q> Search memory from the terminal (FTS5)
345
- clementine projects list Show all linked projects
346
- clementine projects add <path> Link a project directory (-d desc, -k keywords)
347
- clementine projects remove <p> Unlink a project directory
348
- clementine cron list List all cron jobs and last run status
349
- clementine cron run <job> Run a specific cron job
350
- clementine cron run-due Run all due jobs (for OS scheduler)
351
- clementine cron runs [job] View run history (with retry/error details)
352
- clementine cron install Install OS-level scheduler (launchd/crontab)
353
- clementine cron uninstall Remove OS-level scheduler
354
- clementine heartbeat Run a one-shot heartbeat check
355
- clementine self-improve status Show self-improvement state and baseline metrics
356
- clementine self-improve run Trigger a self-improvement cycle
357
- clementine self-improve history Show experiment history
358
- clementine self-improve apply <id> Approve and apply a pending change
359
- clementine --help Show all commands
206
+ clementine setup Interactive setup wizard
207
+ clementine config set KEY VAL Write to ~/.clementine/.env
208
+ clementine config get KEY
209
+ clementine config list Show all overrides
210
+ clementine config edit Open .env in $EDITOR
211
+ clementine login | auth Authenticate Claude Code / OAuth providers
212
+ ```
213
+
214
+ **Chat & memory**
215
+ ```
216
+ clementine chat Interactive REPL
217
+ clementine memory status Index size, recent activity
218
+ clementine memory search <q> FTS5 search
219
+ clementine memory dedup | reembed Maintenance
220
+ clementine brain digest Run the brain digest pipeline
221
+ ```
222
+
223
+ **Projects & agents**
224
+ ```
225
+ clementine projects list | add <p> | remove <p>
226
+ clementine agent list | new <slug> | show <slug>
227
+ clementine skills list | pending | approve <name> | reject <name> | search <q>
228
+ ```
229
+
230
+ **Cron, workflows, heartbeat**
231
+ ```
232
+ clementine cron list | run <job> | run-due | runs [job]
233
+ clementine cron add <name> <schedule> <prompt>
234
+ clementine cron install | uninstall OS-level scheduler (launchd / crontab)
235
+ clementine workflow list | run <name>
236
+ clementine heartbeat One-shot heartbeat tick
237
+ ```
238
+
239
+ **Self-improvement**
240
+ ```
241
+ clementine self-improve status | run | history | pending | apply <id>
242
+ ```
243
+
244
+ **Diagnostics**
245
+ ```
246
+ clementine advisor | rules Live advisor rules
247
+ clementine mode <mode> Switch operating mode
248
+ clementine analytics | tool-usage Telemetry on tool usage
249
+ clementine ingest seed <path> | run <slug> | list
360
250
  ```
361
251
 
362
252
  ### Daemon behavior
@@ -369,27 +259,17 @@ clementine --help Show all commands
369
259
 
370
260
  ### Dashboard
371
261
 
372
- Run `clementine dashboard` to open a local web command center at `http://localhost:3030`. The dashboard provides:
373
-
374
- - **Metrics** Time saved estimates, session counts, cron job stats, memory size
375
- - **Chat** — Talk to your assistant directly from the browser
376
- - **Memory search** Full-text search across all vault notes (FTS5)
377
- - **Scheduled tasks** Create, edit, run, toggle, and delete cron jobs with a visual schedule builder
378
- - **Project-aware cron** Assign cron jobs to specific project directories
379
- - **Unleashed mode** Create long-running autonomous tasks, monitor phase progress, cancel running tasks
380
- - **Projects** Browse all discovered workspace projects with type, description, and tool badges
381
- - **Live status** — Daemon health, LaunchAgent status, active channels
382
- - **Sessions** View and manage active conversation sessions
383
- - **The Office** — Visual agent management with desk-station cards showing status, avatars, channels, and tools
384
- - **Hiring Interview** — Click "Hire a New Employee" and Clementine interviews you to build the agent config conversationally
385
- - **Manual Agent Setup** — Form modal with project dropdown (auto-populated from discovered projects) and categorized tool browser with checkboxes
386
- - **Auto-restart** — Daemon restarts automatically when the agent roster changes (from either the interview or manual path)
387
- - **Training Center** — Click any agent to open a 4-tab detail view: Schedule (per-agent cron jobs), Skills (per-agent procedural memory), Execution Traces (tool call history with timing), and Prompt Lab (test prompts against the agent)
388
- - **Skills** — Teach, view, and delete procedural skills. Skills are auto-extracted from successful tasks or taught manually via the dashboard.
389
- - **Self-Improvement** — View experiment history, approve/deny pending proposals, monitor baseline metrics
390
- - **Settings** — API key management, model config, custom env vars, service status
391
-
392
- No extra dependencies — the dashboard uses Express, which is already installed.
262
+ Run `clementine dashboard` to open the command center at `http://localhost:3030`. Five pages:
263
+
264
+ | Page | What's there |
265
+ |------|--------------|
266
+ | **Home** | Chat with Clementine, today's briefing, recent activity, KPIs |
267
+ | **Build** | Workflows, scheduled tasks (visual cron builder), skills, unleashed tasks |
268
+ | **Team** | Agents (hire / edit / let go), goals, delegations, decision-reflection reports |
269
+ | **Brain** | Memory search (FTS5), knowledge graph, ingestion sources, vault health |
270
+ | **Settings** | Channels, integrations, API keys, model config, env vars, service status |
271
+
272
+ Cron jobs can be project-aware (assign a `work_dir`) and switched between standard and unleashed mode. The agent roster auto-restarts the daemon on changes. No extra deps — runs on Express.
393
273
 
394
274
  ---
395
275
 
@@ -475,13 +355,13 @@ clementine restart
475
355
 
476
356
  ## Models
477
357
 
478
- | Tier | Model Alias | Use case |
479
- |------|-------------|----------|
480
- | `haiku` | `haiku` (latest Haiku) | Lightweight tasks, cron noise filtering |
481
- | `sonnet` | `sonnet` (latest Sonnet) | Default conversation + auto-memory extraction |
482
- | `opus` | `opus` (latest Opus) | Available via config or agent profiles |
358
+ | Tier | Use case |
359
+ |------|----------|
360
+ | `haiku` | Lightweight tasks, cron noise filtering |
361
+ | `sonnet` | Default conversation + auto-memory extraction |
362
+ | `opus` | Per-agent override or global default |
483
363
 
484
- Model aliases always resolve to the latest version via the Claude Code SDK. To pin a specific version, set `DEFAULT_MODEL_TIER` to a full model name (e.g. `claude-sonnet-4-6`).
364
+ Aliases resolve to the latest version via the Claude Code SDK. To pin a specific version, set `DEFAULT_MODEL_TIER` to a full model name (e.g. `claude-sonnet-4-6`). Each agent can override the model in its `agent.md` frontmatter.
485
365
 
486
366
  Change the default with `clementine config set DEFAULT_MODEL_TIER opus`, then `clementine restart`.
487
367
 
@@ -545,14 +425,12 @@ Clementine supports multi-agent teams — each agent gets its own Discord bot, c
545
425
 
546
426
  ### Creating agents
547
427
 
548
- Two paths to create a new agent:
428
+ Open the **Team** page in the dashboard, then either:
549
429
 
550
- | Method | How |
551
- |--------|-----|
552
- | **Hiring interview** | Click "Hire a New Employee" in the dashboard (or an empty desk card). Clementine asks 3–5 questions about the agent's name, role, tools, project, and team connections, then calls `create_agent` automatically. |
553
- | **Manual setup** | Click "Manual Setup" to open a form with project dropdown, categorized tool browser, model selector, and team connection fields. |
430
+ - **Hire a New Employee** — Clementine interviews you (3–5 questions: name, role, tools, project, team connections) and calls `create_agent`.
431
+ - **Manual Setup** — form with project dropdown, categorized tool browser, model selector, and team-connection fields.
554
432
 
555
- Both paths trigger an automatic daemon restart when the new agent is detected.
433
+ Both paths auto-restart the daemon when the new agent appears.
556
434
 
557
435
  ### Agent configuration
558
436
 
@@ -577,14 +455,6 @@ Agents communicate via the `team_message` tool. Messages are permission-scoped
577
455
 
578
456
  Messages are delivered synchronously: the sender waits for the recipient's response. Conversation depth is tracked to prevent infinite loops.
579
457
 
580
- ### The Office (dashboard)
581
-
582
- The dashboard's "The Office" page shows each agent as an animated desk station with:
583
- - Live status indicator (online / connecting / error / offline)
584
- - Discord bot avatar (auto-pulled) or initial
585
- - Channel assignment, model badge, project badge, tool count
586
- - Edit and "Let Go" (delete) actions
587
-
588
458
  ### Decision-loop reflection
589
459
 
590
460
  Each agent's autonomous decisions are recorded to a proactive ledger (action chosen, signal source, eventual outcome). The `decision_reflection` MCP tool reads that ledger, computes per-action success rates, and surfaces calibration patterns:
@@ -657,20 +527,14 @@ The dashboard provides a visual schedule builder with dropdowns for frequency (d
657
527
 
658
528
  ## Unleashed mode
659
529
 
660
- For tasks that take hours — codebase refactors, research projects, content generation pipelines — unleashed mode runs autonomously with phased execution and checkpointing.
661
-
662
- ```
663
- Phase 1 (75 turns) ──▶ Checkpoint ──▶ Phase 2 (75 turns) ──▶ Checkpoint ──▶ ...
664
- │ │ │ │
665
- └─ Session resume ─────┘ └─ Session resume ─────┘
666
- ```
530
+ For tasks that take hours — codebase refactors, research projects, content pipelines — unleashed mode runs autonomously in phases with session resumption between each.
667
531
 
668
532
  ### How it works
669
533
 
670
- 1. The task runs in phases (default 75 turns per phase)
671
- 2. Between phases, the SDK session is **resumed** — the agent keeps its full conversation history
672
- 3. Progress is saved to `~/.clementine/unleashed/<task>/` (JSONL log + status file)
673
- 4. The agent can spawn sub-agents for parallel work streams
534
+ 1. Runs in phases (default 75 turns each)
535
+ 2. Between phases, the SDK session is **resumed** — full conversation history preserved
536
+ 3. Progress saved to `~/.clementine/unleashed/<task>/` (status + JSONL log)
537
+ 4. Can spawn sub-agents for parallel work
674
538
  5. Cancel anytime via the dashboard or by touching a `CANCEL` file
675
539
 
676
540
  ### Safety guardrails
@@ -719,19 +583,7 @@ Progress is also logged to `~/.clementine/unleashed/<task>/progress.jsonl` for d
719
583
 
720
584
  ## Self-improvement
721
585
 
722
- Clementine can autonomously improve herself using an iterative loop inspired by Karpathy's autoresearch pattern: **gather data, diagnose weaknesses, hypothesize a fix, evaluate the fix, and propose the change for approval**.
723
-
724
- ```
725
- ┌──────────┐ ┌──────────┐ ┌─────────────┐ ┌──────────┐ ┌──────────┐
726
- │ Gather │───▶│ Diagnose │───▶│ Hypothesize │───▶│ Evaluate │───▶│ Gate │
727
- │ feedback │ │ weakness │ │ a change │ │ LLM judge│ │ approve? │
728
- │ cron logs│ │ patterns │ │ (minimal) │ │ 0-10 │ │ │
729
- └──────────┘ └──────────┘ └─────────────┘ └──────────┘ └──────────┘
730
- │ │
731
- │ ┌──────────────────────────────────────┐ │
732
- └──────────────│ Repeat until plateau or time limit │◀────────────┘
733
- └──────────────────────────────────────┘
734
- ```
586
+ Clementine runs an iterative self-improvement loop: **gather data diagnose weakness hypothesize a fix LLM-judge it gate for human approval**. Repeats until plateau or time limit.
735
587
 
736
588
  ### What it targets
737
589
 
@@ -800,6 +652,21 @@ After the loop completes, memory maintenance runs automatically (temporal decay
800
652
 
801
653
  The vault is an Obsidian-compatible folder of Markdown files with YAML frontmatter, `[[wikilinks]]`, and `#tags`. Open `~/.clementine/vault/` in Obsidian to browse your assistant's memory visually.
802
654
 
655
+ Folder structure under `~/.clementine/vault/`:
656
+
657
+ ```
658
+ 00-System/ SOUL.md, MEMORY.md, HEARTBEAT.md, CRON.md, AGENTS.md
659
+ agents/<slug>/agent.md ← per-agent config
660
+ skills/ ← procedural skills
661
+ 01-Daily-Notes/ YYYY-MM-DD.md auto-generated daily logs
662
+ 02-People/ Person notes (auto-created from conversations)
663
+ 03-Projects/ Project notes
664
+ 04-Topics/ Knowledge topics
665
+ 05-Tasks/ TASKS.md master list with {T-NNN} IDs
666
+ 06-Templates/ Note templates
667
+ 07-Inbox/ Quick captures
668
+ ```
669
+
803
670
  Key system files:
804
671
 
805
672
  | File | Purpose |
@@ -807,7 +674,8 @@ Key system files:
807
674
  | `SOUL.md` | Core personality and behavioral instructions |
808
675
  | `MEMORY.md` | Auto-extracted facts, preferences, people context |
809
676
  | `HEARTBEAT.md` | Autonomous check-in configuration |
810
- | `CRON.md` | Scheduled task definitions (cron syntax) |
677
+ | `CRON.md` | Scheduled task definitions |
678
+ | `AGENTS.md` | Master roster of agents |
811
679
  | `TASKS.md` | Master task list with `{T-NNN}` IDs |
812
680
 
813
681
  ---
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Clementine CLI — browser-harness integration (Phase 1, beta).
3
+ *
4
+ * Subcommands:
5
+ * clementine browser status — show install / enable / CDP state
6
+ * clementine browser install — set up Python venv + clone harness
7
+ * clementine browser enable — register MCP server in mcp-servers.json
8
+ * clementine browser disable — remove the MCP entry (keeps files)
9
+ *
10
+ * Safety:
11
+ * - All subcommands fail soft. Missing Python or unsupported OS just prints
12
+ * a clear message and exits 0 (or 1 for hard errors); the daemon never
13
+ * auto-installs anything.
14
+ * - Enabling only writes a single entry to ~/.clementine/mcp-servers.json
15
+ * that mcp-bridge.ts already understands. No changes to assistant.ts.
16
+ * - If Python or the MCP server fail at runtime, the SDK logs the error and
17
+ * the rest of Clementine keeps running (every other MCP server is
18
+ * unaffected).
19
+ */
20
+ export declare function cmdBrowserStatus(): Promise<void>;
21
+ export declare function cmdBrowserInstall(): Promise<void>;
22
+ export declare function cmdBrowserEnable(): Promise<void>;
23
+ export declare function cmdBrowserDisable(): Promise<void>;
24
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Clementine CLI — browser-harness integration (Phase 1, beta).
3
+ *
4
+ * Subcommands:
5
+ * clementine browser status — show install / enable / CDP state
6
+ * clementine browser install — set up Python venv + clone harness
7
+ * clementine browser enable — register MCP server in mcp-servers.json
8
+ * clementine browser disable — remove the MCP entry (keeps files)
9
+ *
10
+ * Safety:
11
+ * - All subcommands fail soft. Missing Python or unsupported OS just prints
12
+ * a clear message and exits 0 (or 1 for hard errors); the daemon never
13
+ * auto-installs anything.
14
+ * - Enabling only writes a single entry to ~/.clementine/mcp-servers.json
15
+ * that mcp-bridge.ts already understands. No changes to assistant.ts.
16
+ * - If Python or the MCP server fail at runtime, the SDK logs the error and
17
+ * the rest of Clementine keeps running (every other MCP server is
18
+ * unaffected).
19
+ */
20
+ import { execSync, spawnSync } from 'node:child_process';
21
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
22
+ import os from 'node:os';
23
+ import path from 'node:path';
24
+ import { fileURLToPath } from 'node:url';
25
+ const BOLD = '\x1b[1m';
26
+ const DIM = '\x1b[0;90m';
27
+ const GREEN = '\x1b[0;32m';
28
+ const YELLOW = '\x1b[1;33m';
29
+ const RED = '\x1b[0;31m';
30
+ const CYAN = '\x1b[0;36m';
31
+ const RESET = '\x1b[0m';
32
+ const __filename = fileURLToPath(import.meta.url);
33
+ const __dirname = path.dirname(__filename);
34
+ const BASE_DIR = process.env.CLEMENTINE_HOME || path.join(os.homedir(), '.clementine');
35
+ const PACKAGE_ROOT = path.resolve(__dirname, '..', '..');
36
+ const MCP_SCRIPT = path.join(PACKAGE_ROOT, 'vendor', 'browser-harness-mcp', 'server.py');
37
+ const HARNESS_HOME = path.join(BASE_DIR, 'browser-harness');
38
+ const VENV_DIR = path.join(BASE_DIR, 'browser-harness-mcp-venv');
39
+ const VENV_PYTHON = path.join(VENV_DIR, 'bin', 'python3');
40
+ const MCP_SERVERS_FILE = path.join(BASE_DIR, 'mcp-servers.json');
41
+ const HARNESS_REPO = 'https://github.com/browser-use/browser-harness.git';
42
+ const SERVER_NAME = 'browser-harness';
43
+ function commandExists(cmd) {
44
+ const result = spawnSync('which', [cmd], { stdio: 'pipe' });
45
+ return result.status === 0;
46
+ }
47
+ function pythonVersion() {
48
+ try {
49
+ const out = execSync('python3 --version', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
50
+ return out.trim();
51
+ }
52
+ catch {
53
+ return null;
54
+ }
55
+ }
56
+ function loadMcpServers() {
57
+ if (!existsSync(MCP_SERVERS_FILE))
58
+ return {};
59
+ try {
60
+ return JSON.parse(readFileSync(MCP_SERVERS_FILE, 'utf-8'));
61
+ }
62
+ catch {
63
+ return {};
64
+ }
65
+ }
66
+ function saveMcpServers(servers) {
67
+ if (!existsSync(BASE_DIR))
68
+ mkdirSync(BASE_DIR, { recursive: true });
69
+ writeFileSync(MCP_SERVERS_FILE, JSON.stringify(servers, null, 2) + '\n');
70
+ }
71
+ export async function cmdBrowserStatus() {
72
+ const py = pythonVersion();
73
+ const mcpScriptOk = existsSync(MCP_SCRIPT);
74
+ const venvOk = existsSync(VENV_PYTHON);
75
+ const harnessOk = existsSync(path.join(HARNESS_HOME, 'src'));
76
+ const servers = loadMcpServers();
77
+ const enabled = Object.prototype.hasOwnProperty.call(servers, SERVER_NAME);
78
+ console.log();
79
+ console.log(` ${BOLD}Browser Harness${RESET} ${DIM}(beta)${RESET}`);
80
+ console.log();
81
+ console.log(` ${py ? GREEN + '✓' : RED + '✗'}${RESET} python3 ${DIM}${py ?? 'not found'}${RESET}`);
82
+ console.log(` ${mcpScriptOk ? GREEN + '✓' : RED + '✗'}${RESET} MCP wrapper ${DIM}${MCP_SCRIPT}${RESET}`);
83
+ console.log(` ${venvOk ? GREEN + '✓' : YELLOW + '○'}${RESET} venv installed ${DIM}${VENV_DIR}${RESET}`);
84
+ console.log(` ${harnessOk ? GREEN + '✓' : YELLOW + '○'}${RESET} harness cloned ${DIM}${HARNESS_HOME}${RESET}`);
85
+ console.log(` ${enabled ? GREEN + '✓' : DIM + '○'}${RESET} MCP entry ${DIM}${enabled ? 'enabled' : 'disabled'} in mcp-servers.json${RESET}`);
86
+ console.log();
87
+ if (!py) {
88
+ console.log(` ${YELLOW}Install Python 3.10+ first:${RESET}`);
89
+ console.log(` ${CYAN}brew install python@3.12${RESET}`);
90
+ console.log();
91
+ }
92
+ else if (!venvOk || !harnessOk) {
93
+ console.log(` Next: ${BOLD}clementine browser install${RESET}`);
94
+ console.log();
95
+ }
96
+ else if (!enabled) {
97
+ console.log(` Next: ${BOLD}clementine browser enable${RESET}`);
98
+ console.log();
99
+ }
100
+ else {
101
+ console.log(` ${GREEN}Ready.${RESET} ${DIM}Restart the daemon to pick up changes: clementine restart${RESET}`);
102
+ console.log();
103
+ }
104
+ }
105
+ export async function cmdBrowserInstall() {
106
+ console.log();
107
+ console.log(` ${BOLD}Installing browser-harness${RESET} ${DIM}(beta)${RESET}`);
108
+ console.log();
109
+ if (!pythonVersion()) {
110
+ console.error(` ${RED}python3 not found.${RESET} Install Python 3.10+ first:`);
111
+ console.error(` ${CYAN}brew install python@3.12${RESET}`);
112
+ console.error();
113
+ process.exit(1);
114
+ }
115
+ if (!existsSync(MCP_SCRIPT)) {
116
+ console.error(` ${RED}MCP wrapper not found at:${RESET} ${MCP_SCRIPT}`);
117
+ console.error(` ${DIM}This means the package was installed without vendor/ files. Reinstall:${RESET}`);
118
+ console.error(` ${CYAN}npm install -g clementine-agent@latest${RESET}`);
119
+ process.exit(1);
120
+ }
121
+ if (!existsSync(BASE_DIR))
122
+ mkdirSync(BASE_DIR, { recursive: true });
123
+ // Step 1: clone the harness if missing
124
+ if (!existsSync(HARNESS_HOME)) {
125
+ if (!commandExists('git')) {
126
+ console.error(` ${RED}git not found.${RESET} Install git, then re-run.`);
127
+ process.exit(1);
128
+ }
129
+ console.log(` ${DIM}→ cloning ${HARNESS_REPO}${RESET}`);
130
+ try {
131
+ execSync(`git clone --depth 1 ${HARNESS_REPO} "${HARNESS_HOME}"`, { stdio: 'inherit' });
132
+ }
133
+ catch {
134
+ console.error(` ${RED}Clone failed.${RESET} Check network / git access and try again.`);
135
+ process.exit(1);
136
+ }
137
+ }
138
+ else {
139
+ console.log(` ${GREEN}✓${RESET} harness already cloned at ${DIM}${HARNESS_HOME}${RESET}`);
140
+ }
141
+ // Step 2: create venv if missing
142
+ if (!existsSync(VENV_PYTHON)) {
143
+ console.log(` ${DIM}→ creating venv at ${VENV_DIR}${RESET}`);
144
+ try {
145
+ execSync(`python3 -m venv "${VENV_DIR}"`, { stdio: 'inherit' });
146
+ }
147
+ catch {
148
+ console.error(` ${RED}venv creation failed.${RESET}`);
149
+ process.exit(1);
150
+ }
151
+ }
152
+ else {
153
+ console.log(` ${GREEN}✓${RESET} venv already exists`);
154
+ }
155
+ // Step 3: install MCP deps + harness deps
156
+ console.log(` ${DIM}→ installing python deps (mcp, websockets, browser-harness)${RESET}`);
157
+ try {
158
+ execSync(`"${VENV_PYTHON}" -m pip install --upgrade pip --quiet`, { stdio: 'inherit' });
159
+ execSync(`"${VENV_PYTHON}" -m pip install --quiet "mcp>=1.0.0" "websockets>=12.0"`, { stdio: 'inherit' });
160
+ // Install harness deps from its pyproject.toml if present
161
+ const harnessPyproject = path.join(HARNESS_HOME, 'pyproject.toml');
162
+ if (existsSync(harnessPyproject)) {
163
+ execSync(`"${VENV_PYTHON}" -m pip install --quiet -e "${HARNESS_HOME}"`, { stdio: 'inherit' });
164
+ }
165
+ }
166
+ catch {
167
+ console.error(` ${RED}pip install failed.${RESET} Inspect output above and re-run when fixed.`);
168
+ process.exit(1);
169
+ }
170
+ console.log();
171
+ console.log(` ${GREEN}✓${RESET} Install complete.`);
172
+ console.log();
173
+ console.log(` ${BOLD}Next steps:${RESET}`);
174
+ console.log(` 1. Enable Chrome remote debugging — open Chrome with:`);
175
+ console.log(` ${CYAN}/Applications/Google\\ Chrome.app/Contents/MacOS/Google\\ Chrome \\${RESET}`);
176
+ console.log(` ${CYAN}--remote-debugging-port=9222${RESET}`);
177
+ console.log(` 2. Enable the MCP server: ${BOLD}clementine browser enable${RESET}`);
178
+ console.log(` 3. Restart the daemon: ${BOLD}clementine restart${RESET}`);
179
+ console.log();
180
+ }
181
+ export async function cmdBrowserEnable() {
182
+ if (!existsSync(VENV_PYTHON) || !existsSync(MCP_SCRIPT)) {
183
+ console.error();
184
+ console.error(` ${RED}Not installed yet.${RESET} Run ${BOLD}clementine browser install${RESET} first.`);
185
+ console.error();
186
+ process.exit(1);
187
+ }
188
+ const servers = loadMcpServers();
189
+ servers[SERVER_NAME] = {
190
+ type: 'stdio',
191
+ command: VENV_PYTHON,
192
+ args: [MCP_SCRIPT],
193
+ env: {
194
+ BROWSER_HARNESS_HOME: HARNESS_HOME,
195
+ BROWSER_CDP_URL: process.env.BROWSER_CDP_URL || 'ws://localhost:9222',
196
+ },
197
+ description: 'Drive the user\'s real Chrome via CDP (browser-use/browser-harness)',
198
+ enabled: true,
199
+ source: 'user',
200
+ };
201
+ saveMcpServers(servers);
202
+ console.log();
203
+ console.log(` ${GREEN}✓${RESET} Registered ${BOLD}${SERVER_NAME}${RESET} in mcp-servers.json`);
204
+ console.log(` ${DIM}Restart the daemon to pick up the change: clementine restart${RESET}`);
205
+ console.log();
206
+ }
207
+ export async function cmdBrowserDisable() {
208
+ const servers = loadMcpServers();
209
+ if (!Object.prototype.hasOwnProperty.call(servers, SERVER_NAME)) {
210
+ console.log();
211
+ console.log(` ${DIM}${SERVER_NAME} is already disabled.${RESET}`);
212
+ console.log();
213
+ return;
214
+ }
215
+ delete servers[SERVER_NAME];
216
+ saveMcpServers(servers);
217
+ console.log();
218
+ console.log(` ${GREEN}✓${RESET} Removed ${BOLD}${SERVER_NAME}${RESET} from mcp-servers.json`);
219
+ console.log(` ${DIM}venv and harness clone are kept. To fully remove:${RESET}`);
220
+ console.log(` ${CYAN}rm -rf "${VENV_DIR}" "${HARNESS_HOME}"${RESET}`);
221
+ console.log(` ${DIM}Restart the daemon: clementine restart${RESET}`);
222
+ console.log();
223
+ }
224
+ //# sourceMappingURL=browser.js.map
package/dist/cli/index.js CHANGED
@@ -24,6 +24,7 @@ import { cmdCronList, cmdCronRun, cmdCronRunDue, cmdCronRuns, cmdCronAdd, cmdCro
24
24
  import { cmdDashboard } from './dashboard.js';
25
25
  import { cmdChat } from './chat.js';
26
26
  import { cmdIngestSeed, cmdIngestRun, cmdIngestList, cmdIngestStatus } from './ingest.js';
27
+ import { cmdBrowserStatus, cmdBrowserInstall, cmdBrowserEnable, cmdBrowserDisable } from './browser.js';
27
28
  import { isSensitiveEnvKey } from '../secrets/sensitivity.js';
28
29
  const __filename = fileURLToPath(import.meta.url);
29
30
  const __dirname = path.dirname(__filename);
@@ -4549,5 +4550,25 @@ ingestCmd
4549
4550
  .command('status <slug>')
4550
4551
  .description('Show recent runs and metadata for a source')
4551
4552
  .action(cmdIngestStatus);
4553
+ // ── Browser harness (beta) ──────────────────────────────────────────
4554
+ const browserCmd = program
4555
+ .command('browser')
4556
+ .description('Browser harness — drive your real Chrome via CDP (beta, opt-in)');
4557
+ browserCmd
4558
+ .command('status')
4559
+ .description('Show install and enable state of the browser harness MCP')
4560
+ .action(cmdBrowserStatus);
4561
+ browserCmd
4562
+ .command('install')
4563
+ .description('Clone browser-harness and install Python deps into a private venv')
4564
+ .action(cmdBrowserInstall);
4565
+ browserCmd
4566
+ .command('enable')
4567
+ .description('Register the browser harness MCP server in mcp-servers.json')
4568
+ .action(cmdBrowserEnable);
4569
+ browserCmd
4570
+ .command('disable')
4571
+ .description('Remove the browser harness MCP entry (keeps installed files)')
4572
+ .action(cmdBrowserDisable);
4552
4573
  program.parse();
4553
4574
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clementine-agent",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Clementine — Personal AI Assistant (TypeScript)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -86,6 +86,7 @@
86
86
  "dist/",
87
87
  "vault/",
88
88
  "scripts/",
89
+ "vendor/",
89
90
  "install.sh",
90
91
  "README.md",
91
92
  ".env.example"
@@ -0,0 +1,27 @@
1
+ # Browser Harness MCP Bridge
2
+
3
+ Stdio MCP server that wraps [browser-use/browser-harness](https://github.com/browser-use/browser-harness) so Clementine can drive your real Chrome via CDP.
4
+
5
+ **Status:** Phase 1 plumbing — tools return `[stub]` placeholders until the harness primitives are wired in.
6
+
7
+ ## Setup
8
+
9
+ ```bash
10
+ clementine browser install # clone harness + install Python deps
11
+ clementine browser enable # register MCP server in ~/.clementine/mcp-servers.json
12
+ clementine restart
13
+ ```
14
+
15
+ To remove: `clementine browser disable` (the venv and harness clone are kept; delete `~/.clementine/browser-harness*` to fully remove).
16
+
17
+ ## Tools
18
+
19
+ | Tool | Tier | Description |
20
+ |------|------|-------------|
21
+ | `browser_status` | 1 | Diagnostic: install state + CDP URL |
22
+ | `browser_screenshot` | 1 | Capture active tab |
23
+ | `browser_inspect` | 1 | Read page HTML or selector |
24
+ | `browser_navigate` | 2 | Open a URL in connected Chrome |
25
+ | `browser_run_python` | 3 | Execute Python in `agent-workspace/` (approval required) |
26
+
27
+ Tier policies are enforced by Clementine's `src/agent/hooks.ts`. Tier 3 actions require explicit approval and run only with a per-domain allowlist (Phase 2).
@@ -0,0 +1,13 @@
1
+ [project]
2
+ name = "clementine-browser-harness-mcp"
3
+ version = "0.1.0"
4
+ description = "MCP bridge between Clementine and browser-use/browser-harness"
5
+ requires-python = ">=3.10"
6
+ dependencies = [
7
+ "mcp>=1.0.0",
8
+ "websockets>=12.0",
9
+ ]
10
+
11
+ [build-system]
12
+ requires = ["hatchling"]
13
+ build-backend = "hatchling.build"
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Clementine ↔ browser-harness MCP bridge.
4
+
5
+ Stdio MCP server that exposes browser-harness primitives to the Claude Agent
6
+ SDK. Fails gracefully: if browser-harness or its deps aren't installed, the
7
+ server still starts and every tool returns a clear "not installed" message
8
+ so the rest of Clementine keeps working.
9
+
10
+ Wire-up:
11
+ mcpServers in ~/.clementine/mcp-servers.json:
12
+ {
13
+ "browser-harness": {
14
+ "type": "stdio",
15
+ "command": "<venv>/bin/python3",
16
+ "args": ["<package>/vendor/browser-harness-mcp/server.py"],
17
+ "env": {
18
+ "BROWSER_HARNESS_HOME": "~/.clementine/browser-harness",
19
+ "BROWSER_CDP_URL": "ws://localhost:9222"
20
+ }
21
+ }
22
+ }
23
+
24
+ Run `clementine browser install` and `clementine browser enable` to set up.
25
+ """
26
+ from __future__ import annotations
27
+
28
+ import os
29
+ import sys
30
+ from pathlib import Path
31
+
32
+ # Best-effort: load browser-harness from the user's data home.
33
+ HARNESS_HOME = Path(
34
+ os.environ.get(
35
+ "BROWSER_HARNESS_HOME",
36
+ Path.home() / ".clementine" / "browser-harness",
37
+ )
38
+ ).expanduser()
39
+
40
+ CDP_URL = os.environ.get("BROWSER_CDP_URL", "ws://localhost:9222")
41
+
42
+ _HARNESS_AVAILABLE = False
43
+ _HARNESS_ERROR: str | None = None
44
+
45
+ try:
46
+ if (HARNESS_HOME / "src").is_dir():
47
+ sys.path.insert(0, str(HARNESS_HOME / "src"))
48
+ # The actual harness module — import is lazy to keep startup cheap.
49
+ import browser_harness # type: ignore # noqa: F401
50
+ _HARNESS_AVAILABLE = True
51
+ except Exception as e: # noqa: BLE001
52
+ _HARNESS_ERROR = f"{type(e).__name__}: {e}"
53
+
54
+ try:
55
+ from mcp.server.fastmcp import FastMCP
56
+ except Exception as e: # noqa: BLE001
57
+ sys.stderr.write(
58
+ "browser-harness MCP: 'mcp' package not installed. "
59
+ "Run `clementine browser install` to set up.\n"
60
+ f"Underlying error: {e}\n"
61
+ )
62
+ sys.exit(1)
63
+
64
+
65
+ server = FastMCP("browser-harness")
66
+
67
+
68
+ def _not_ready_message() -> str:
69
+ if _HARNESS_AVAILABLE:
70
+ return ""
71
+ return (
72
+ "browser-harness is not installed. Run `clementine browser install` "
73
+ "to clone the harness into ~/.clementine/browser-harness and install "
74
+ f"Python dependencies. (Underlying: {_HARNESS_ERROR})"
75
+ )
76
+
77
+
78
+ @server.tool()
79
+ def browser_status() -> str:
80
+ """Report whether browser-harness is installed and the CDP target it's pointed at."""
81
+ parts = [
82
+ f"harness_installed: {_HARNESS_AVAILABLE}",
83
+ f"harness_home: {HARNESS_HOME}",
84
+ f"cdp_url: {CDP_URL}",
85
+ ]
86
+ if not _HARNESS_AVAILABLE and _HARNESS_ERROR:
87
+ parts.append(f"error: {_HARNESS_ERROR}")
88
+ return "\n".join(parts)
89
+
90
+
91
+ @server.tool()
92
+ def browser_navigate(url: str) -> str:
93
+ """Open a URL in the connected Chrome via CDP. Tier 2 (logged)."""
94
+ msg = _not_ready_message()
95
+ if msg:
96
+ return msg
97
+ # TODO: implement via browser_harness CDP helpers
98
+ return f"[stub] would navigate to {url} via {CDP_URL}"
99
+
100
+
101
+ @server.tool()
102
+ def browser_screenshot() -> str:
103
+ """Capture a screenshot of the active tab and return its file path. Tier 1."""
104
+ msg = _not_ready_message()
105
+ if msg:
106
+ return msg
107
+ # TODO: implement via browser_harness CDP helpers
108
+ return f"[stub] would screenshot active tab via {CDP_URL}"
109
+
110
+
111
+ @server.tool()
112
+ def browser_inspect(selector: str = "body") -> str:
113
+ """Read the current page HTML or a specific selector. Tier 1 (read-only)."""
114
+ msg = _not_ready_message()
115
+ if msg:
116
+ return msg
117
+ # TODO: implement via browser_harness CDP helpers
118
+ return f"[stub] would inspect '{selector}' via {CDP_URL}"
119
+
120
+
121
+ @server.tool()
122
+ def browser_run_python(code: str) -> str:
123
+ """Run Python in the harness workspace. Tier 3 (autonomous-blocked, requires approval)."""
124
+ msg = _not_ready_message()
125
+ if msg:
126
+ return msg
127
+ # TODO: thread through agent-workspace/agent_helpers.py — see SKILL.md
128
+ return f"[stub] would run python ({len(code)} bytes) in {HARNESS_HOME}/agent-workspace"
129
+
130
+
131
+ if __name__ == "__main__":
132
+ # FastMCP handles stdio transport automatically.
133
+ server.run()