@onebrain-ai/cli 2.2.3 → 2.2.4
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 +36 -18
- package/dist/onebrain +67 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
</p>
|
|
24
24
|
|
|
25
25
|
<p align="center">
|
|
26
|
-
<strong>Your personal AI OS</strong> — persistent memory,
|
|
26
|
+
<strong>Your personal AI OS</strong> — persistent memory, 25+ skills, and a full local stack<br>
|
|
27
27
|
(Claude Code + Obsidian + tmux + Telegram), entirely on your own machine.
|
|
28
28
|
</p>
|
|
29
29
|
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
|
|
36
36
|
## What is OneBrain?
|
|
37
37
|
|
|
38
|
-
OneBrain is an AI operating system layer built on top of Obsidian. It gives your AI agent persistent memory, a structured knowledge vault, and
|
|
38
|
+
OneBrain is an AI operating system layer built on top of Obsidian. It gives your AI agent persistent memory, a structured knowledge vault, and 25+ pre-built skills — so every session picks up exactly where the last one left off.
|
|
39
39
|
|
|
40
40
|
Unlike chat-based AI tools, OneBrain lives in plain Markdown files you own forever. No cloud sync required. No proprietary format. Just your agent, your vault, your data.
|
|
41
41
|
|
|
@@ -70,7 +70,7 @@ OneBrain doesn't compete with Claude Code, Gemini CLI, or any other AI harness
|
|
|
70
70
|
|
|
71
71
|
| # | Layer | Role | What lives here |
|
|
72
72
|
|---|---|---|---|
|
|
73
|
-
| 01 | **OneBrain** | OS layer (plugin + CLI) |
|
|
73
|
+
| 01 | **OneBrain** | OS layer (plugin + CLI) | 25+ skills · lifecycle hooks · vault sync · indexing · checkpoints · harness routing |
|
|
74
74
|
| 02 | **Harness** | Agentic runtime | Bring your own — Claude Code · Gemini CLI · Codex · Qwen · ... |
|
|
75
75
|
| 03 | **LLM** | Intelligence source | Local (mlx, ollama) · cloud (claude, gemini, gpt) · raw API |
|
|
76
76
|
| 04 | **Obsidian Vault** | Source of truth | Plain Markdown — notes, memory, decisions, knowledge graph |
|
|
@@ -84,7 +84,7 @@ A great harness already knows how to talk to an LLM, edit files, and run shell c
|
|
|
84
84
|
| | What OneBrain adds | Why it matters |
|
|
85
85
|
|---|---|---|
|
|
86
86
|
| 🧠 | **Memory** — Identity, preferences, decisions, project state — promoted across four tiers as it earns trust | The harness alone starts every session from zero. OneBrain doesn't. |
|
|
87
|
-
| ⚡ | **Skills** —
|
|
87
|
+
| ⚡ | **Skills** — 25+ vault-aware verbs (`/braindump`, `/research`, `/distill`, `/learn`, `/wrapup`, …) | Pre-built workflows the harness would otherwise need you to script every time. |
|
|
88
88
|
| 🎯 | **Calibration** — Every correction, every preference, every learned habit tunes the agent to *you* | The longer you use it, the sharper it gets — your vault is the training data. |
|
|
89
89
|
| 🔀 | **Continuity** — Context lives in the vault, not the harness | Switch from Claude Code to Gemini CLI to Codex. Same memory. Same skills. Same agent. |
|
|
90
90
|
|
|
@@ -210,7 +210,7 @@ OneBrain doesn't just store markdown. Every feature exists to make you and the a
|
|
|
210
210
|
|---|---|---|
|
|
211
211
|
| 🧠 | **Persistent Memory** | Remembers your name, goals, preferences, and decisions across every session |
|
|
212
212
|
| 🖥️ | **Personal AI OS** | Full local stack: Claude Code + Obsidian + tmux + Telegram — no cloud infra needed |
|
|
213
|
-
| ⚡ | **
|
|
213
|
+
| ⚡ | **25+ Skills** | Braindump, research, consolidate, bookmark, import files, daily briefing, and more |
|
|
214
214
|
| 📂 | **Vault-native Markdown** | Plain Markdown, no lock-in. Your data stays yours forever |
|
|
215
215
|
| 🔀 | **Multi-Harness OS** | Switch between Claude Code, Gemini CLI, Codex, Qwen, or BYO LLM — context never breaks. [See architecture ↑](#the-harness-os-architecture) |
|
|
216
216
|
| 🔌 | **Zero Config** | Clone, open in Obsidian, run `/onboarding`. Ready in under 2 minutes |
|
|
@@ -340,37 +340,55 @@ Same vault. Same skills. Same memory. The LLM swaps; OneBrain doesn't notice.
|
|
|
340
340
|
|
|
341
341
|
<a id="commands"></a>
|
|
342
342
|
|
|
343
|
-
## 📋
|
|
343
|
+
## 📋 25+ Commands
|
|
344
344
|
|
|
345
|
-
|
|
345
|
+
Skills are organized by workflow phase. **Gemini CLI users:** prepend the `onebrain:` namespace, e.g. `/onebrain:braindump` instead of `/braindump` (avoids collisions with Gemini built-in commands like `/help` and `/tasks`).
|
|
346
|
+
|
|
347
|
+
### 📥 INPUT — Capture & ingest
|
|
346
348
|
|
|
347
349
|
| Command | What it does |
|
|
348
350
|
|---------|-------------|
|
|
349
|
-
| `/onboarding` | First-run setup — run this first |
|
|
351
|
+
| `/onboarding` | First-run setup — run this first · *first run only* |
|
|
350
352
|
| `/braindump` | Dump everything on your mind — it gets classified and filed |
|
|
351
353
|
| `/capture` | Quick note with auto-linking to related notes |
|
|
352
354
|
| `/bookmark [url]` | Save a URL with AI-generated name, description, and category to Bookmarks.md |
|
|
353
|
-
| `/consolidate` | Process inbox into permanent knowledge |
|
|
354
|
-
| `/connect` | Find connections between notes, suggest wikilinks |
|
|
355
|
-
| `/research [topic]` | Web research → structured note in your vault |
|
|
356
355
|
| `/summarize [url]` | Fetch a URL and save a deep summary note |
|
|
357
356
|
| `/import [path]` | Import local files (PDF, Word, images, scripts) into vault notes |
|
|
358
357
|
| `/reading-notes` | Turn a book or article into structured notes |
|
|
358
|
+
| `/research [topic]` | Web research → structured note in your vault |
|
|
359
|
+
|
|
360
|
+
### ⚙️ PROCESS — Synthesize & organize
|
|
361
|
+
|
|
362
|
+
| Command | What it does |
|
|
363
|
+
|---------|-------------|
|
|
364
|
+
| `/consolidate` | Process inbox into permanent knowledge |
|
|
365
|
+
| `/distill [topic]` | Crystallize a completed topic thread into a permanent knowledge note in `03-knowledge/` |
|
|
366
|
+
| `/connect` | Find connections between notes, suggest wikilinks |
|
|
367
|
+
| `/recap` | Cross-session synthesis — batch-promote recurring insights from session logs into `memory/` files (does NOT write to MEMORY.md) |
|
|
359
368
|
| `/weekly` | Review the week, surface patterns, set intentions |
|
|
360
369
|
| `/daily` | Daily briefing — surfaces tasks and last session context, then saves your focus as a daily note |
|
|
361
|
-
| `/
|
|
362
|
-
|
|
370
|
+
| `/learn` | Teach the agent something — facts about your world or behavioral preferences |
|
|
371
|
+
|
|
372
|
+
### 🔍 RECALL — Retrieve & navigate
|
|
373
|
+
|
|
374
|
+
| Command | What it does |
|
|
375
|
+
|---------|-------------|
|
|
376
|
+
| `/search` | General vault retrieval — answers what + why questions across MEMORY, sessions, plans, decisions logs, notes |
|
|
363
377
|
| `/tasks` | Live task dashboard in Obsidian — creates/updates `TASKS.md` with always-current query sections |
|
|
364
378
|
| `/moc` | Vault portal in Obsidian — creates/updates `MOC.md` with projects, areas, knowledge, tasks, and pinned links |
|
|
365
|
-
| `/wrapup` | Wrap up session — merges any auto-checkpoints and saves full summary to session log |
|
|
366
|
-
| `/learn` | Teach the agent something — facts about your world or behavioral preferences |
|
|
367
379
|
| `/memory-review` | Interactive review of memory files — keep, update, deprecate, or delete entries |
|
|
368
|
-
|
|
380
|
+
|
|
381
|
+
### 🔧 MAINTAIN — System housekeeping
|
|
382
|
+
|
|
383
|
+
| Command | What it does |
|
|
384
|
+
|---------|-------------|
|
|
385
|
+
| `/update` | Update skills, config, and plugins from GitHub |
|
|
386
|
+
| `/doctor` | Vault + config health check — broken links, orphan notes, stale memory entries, inbox backlog |
|
|
369
387
|
| `/reorganize` | Migrate flat notes into organized subfolders |
|
|
388
|
+
| `/clone` | Package your agent context for transfer to a new vault |
|
|
370
389
|
| `/qmd` | Set up fast vault search index — enables semantic search across all notes |
|
|
371
|
-
| `/doctor` | Vault + config health check — broken links, orphan notes, stale memory entries, inbox backlog |
|
|
372
|
-
| `/update` | Update skills, config, and plugins from GitHub |
|
|
373
390
|
| `/help` | List all available commands with descriptions |
|
|
391
|
+
| `/wrapup` | Wrap up session — merges any auto-checkpoints and saves full summary to session log |
|
|
374
392
|
|
|
375
393
|
<details>
|
|
376
394
|
<summary><strong>📁 Vault Structure</strong></summary>
|
package/dist/onebrain
CHANGED
|
@@ -9560,7 +9560,7 @@ var init_lib = __esm(() => {
|
|
|
9560
9560
|
var require_package = __commonJS((exports, module) => {
|
|
9561
9561
|
module.exports = {
|
|
9562
9562
|
name: "@onebrain-ai/cli",
|
|
9563
|
-
version: "2.2.
|
|
9563
|
+
version: "2.2.4",
|
|
9564
9564
|
description: "CLI for OneBrain \u2014 personal AI OS for Obsidian with persistent memory, 24+ skills, and Claude Code integration",
|
|
9565
9565
|
keywords: [
|
|
9566
9566
|
"onebrain",
|
|
@@ -10060,13 +10060,34 @@ async function writeSettings(settingsPath, settings) {
|
|
|
10060
10060
|
await writeFile2(tmpPath, JSON.stringify(settings, null, 4), "utf8");
|
|
10061
10061
|
await rename2(tmpPath, settingsPath);
|
|
10062
10062
|
}
|
|
10063
|
-
function
|
|
10063
|
+
function matchesSpec(entry, spec) {
|
|
10064
|
+
const fullCmd = [spec.command, ...spec.args].join(" ");
|
|
10065
|
+
if (entry.command === spec.command && JSON.stringify(entry.args ?? []) === JSON.stringify(spec.args)) {
|
|
10066
|
+
return true;
|
|
10067
|
+
}
|
|
10068
|
+
if (entry.command === fullCmd && !entry.args) {
|
|
10069
|
+
return true;
|
|
10070
|
+
}
|
|
10071
|
+
return false;
|
|
10072
|
+
}
|
|
10073
|
+
function rewriteIfShellForm(entry, spec) {
|
|
10074
|
+
const fullCmd = [spec.command, ...spec.args].join(" ");
|
|
10075
|
+
if (entry.command === fullCmd && !entry.args) {
|
|
10076
|
+
entry.command = spec.command;
|
|
10077
|
+
entry.args = [...spec.args];
|
|
10078
|
+
if (!entry.type)
|
|
10079
|
+
entry.type = "command";
|
|
10080
|
+
return true;
|
|
10081
|
+
}
|
|
10082
|
+
return false;
|
|
10083
|
+
}
|
|
10084
|
+
function checkHookPresence(groups, spec) {
|
|
10064
10085
|
let foundMigrate = false;
|
|
10065
10086
|
for (const group of groups) {
|
|
10066
10087
|
for (const entry of group.hooks ?? []) {
|
|
10067
|
-
|
|
10068
|
-
if (cmd === targetCmd)
|
|
10088
|
+
if (matchesSpec(entry, spec))
|
|
10069
10089
|
return "found";
|
|
10090
|
+
const cmd = entry.command ?? "";
|
|
10070
10091
|
if (cmd.includes("checkpoint-hook.sh"))
|
|
10071
10092
|
foundMigrate = true;
|
|
10072
10093
|
}
|
|
@@ -10096,22 +10117,30 @@ function applyHooks(settings) {
|
|
|
10096
10117
|
}
|
|
10097
10118
|
}
|
|
10098
10119
|
for (const event of HOOK_EVENTS) {
|
|
10099
|
-
const
|
|
10100
|
-
if (!
|
|
10120
|
+
const spec = HOOK_SPECS[event];
|
|
10121
|
+
if (!spec)
|
|
10101
10122
|
continue;
|
|
10102
10123
|
if (!hooks[event])
|
|
10103
10124
|
hooks[event] = [];
|
|
10104
10125
|
const groups = hooks[event];
|
|
10105
|
-
|
|
10126
|
+
let rewroteShellForm = false;
|
|
10127
|
+
for (const group of groups) {
|
|
10128
|
+
for (const entry of group.hooks ?? []) {
|
|
10129
|
+
if (rewriteIfShellForm(entry, spec))
|
|
10130
|
+
rewroteShellForm = true;
|
|
10131
|
+
}
|
|
10132
|
+
}
|
|
10133
|
+
const presence = checkHookPresence(groups, spec);
|
|
10106
10134
|
if (presence === "found") {
|
|
10107
|
-
result[event] = "ok";
|
|
10135
|
+
result[event] = rewroteShellForm ? "migrated" : "ok";
|
|
10108
10136
|
} else if (presence === "migrate") {
|
|
10109
10137
|
for (const group of groups) {
|
|
10110
10138
|
if (group.matcher === undefined)
|
|
10111
10139
|
group.matcher = "";
|
|
10112
10140
|
for (const entry of group.hooks ?? []) {
|
|
10113
10141
|
if ((entry.command ?? "").includes("checkpoint-hook.sh")) {
|
|
10114
|
-
entry.command =
|
|
10142
|
+
entry.command = spec.command;
|
|
10143
|
+
entry.args = [...spec.args];
|
|
10115
10144
|
if (!entry.type)
|
|
10116
10145
|
entry.type = "command";
|
|
10117
10146
|
}
|
|
@@ -10119,12 +10148,18 @@ function applyHooks(settings) {
|
|
|
10119
10148
|
}
|
|
10120
10149
|
result[event] = "migrated";
|
|
10121
10150
|
} else {
|
|
10122
|
-
groups.push({
|
|
10151
|
+
groups.push({
|
|
10152
|
+
matcher: "",
|
|
10153
|
+
hooks: [{ type: "command", command: spec.command, args: [...spec.args] }]
|
|
10154
|
+
});
|
|
10123
10155
|
result[event] = "added";
|
|
10124
10156
|
}
|
|
10125
10157
|
}
|
|
10126
10158
|
return result;
|
|
10127
10159
|
}
|
|
10160
|
+
function isCanonicalQmdEntry(entry) {
|
|
10161
|
+
return matchesSpec(entry, QMD_SPEC);
|
|
10162
|
+
}
|
|
10128
10163
|
function isLegacyQmdCmd(cmd) {
|
|
10129
10164
|
return /\bqmd\s+update\b/.test(cmd);
|
|
10130
10165
|
}
|
|
@@ -10137,7 +10172,8 @@ function migrateLegacyQmdEntries(groups, keepCanonical) {
|
|
|
10137
10172
|
let groupTouched = false;
|
|
10138
10173
|
for (const entry of group.hooks) {
|
|
10139
10174
|
if (isLegacyQmdCmd(entry.command ?? "")) {
|
|
10140
|
-
entry.command =
|
|
10175
|
+
entry.command = QMD_SPEC.command;
|
|
10176
|
+
entry.args = [...QMD_SPEC.args];
|
|
10141
10177
|
if (!entry.type)
|
|
10142
10178
|
entry.type = "command";
|
|
10143
10179
|
groupTouched = true;
|
|
@@ -10151,20 +10187,26 @@ function migrateLegacyQmdEntries(groups, keepCanonical) {
|
|
|
10151
10187
|
const before = group.hooks.length;
|
|
10152
10188
|
group.hooks = group.hooks.filter((h) => {
|
|
10153
10189
|
const cmd = h.command ?? "";
|
|
10154
|
-
return !isLegacyQmdCmd(cmd) &&
|
|
10190
|
+
return !isLegacyQmdCmd(cmd) && !isCanonicalQmdEntry(h);
|
|
10155
10191
|
});
|
|
10156
10192
|
if (group.hooks.length !== before)
|
|
10157
10193
|
touched = true;
|
|
10158
10194
|
}
|
|
10159
10195
|
}
|
|
10160
10196
|
if (keepCanonical) {
|
|
10197
|
+
for (const group of groups) {
|
|
10198
|
+
for (const entry of group.hooks ?? []) {
|
|
10199
|
+
if (rewriteIfShellForm(entry, QMD_SPEC))
|
|
10200
|
+
touched = true;
|
|
10201
|
+
}
|
|
10202
|
+
}
|
|
10161
10203
|
let seenCanonical = false;
|
|
10162
10204
|
for (const group of groups) {
|
|
10163
10205
|
if (!group.hooks)
|
|
10164
10206
|
continue;
|
|
10165
10207
|
const before = group.hooks.length;
|
|
10166
10208
|
group.hooks = group.hooks.filter((h) => {
|
|
10167
|
-
if (h
|
|
10209
|
+
if (!isCanonicalQmdEntry(h))
|
|
10168
10210
|
return true;
|
|
10169
10211
|
if (seenCanonical)
|
|
10170
10212
|
return false;
|
|
@@ -10189,10 +10231,13 @@ function applyQmdHook(settings) {
|
|
|
10189
10231
|
settings.hooks["PostToolUse"] = [];
|
|
10190
10232
|
const groups = settings.hooks["PostToolUse"];
|
|
10191
10233
|
const migrated = migrateLegacyQmdEntries(groups, true);
|
|
10192
|
-
const already = groups.some((g) => g.hooks?.some((h) => h
|
|
10234
|
+
const already = groups.some((g) => g.hooks?.some((h) => isCanonicalQmdEntry(h)));
|
|
10193
10235
|
if (already)
|
|
10194
10236
|
return migrated ? "migrated" : "ok";
|
|
10195
|
-
groups.push({
|
|
10237
|
+
groups.push({
|
|
10238
|
+
matcher: QMD_MATCHER,
|
|
10239
|
+
hooks: [{ type: "command", command: QMD_SPEC.command, args: [...QMD_SPEC.args] }]
|
|
10240
|
+
});
|
|
10196
10241
|
return "added";
|
|
10197
10242
|
}
|
|
10198
10243
|
function applyPermissions(settings) {
|
|
@@ -10332,14 +10377,14 @@ async function registerHooksCommand(vaultDir) {
|
|
|
10332
10377
|
process.exit(1);
|
|
10333
10378
|
}
|
|
10334
10379
|
}
|
|
10335
|
-
var import_picocolors4,
|
|
10380
|
+
var import_picocolors4, HOOK_SPECS, HOOK_EVENTS, PERMISSIONS_TO_ADD, ONEBRAIN_MARKER = "# onebrain", PATH_EXPORT = 'export PATH="$HOME/.bun/bin:$HOME/.npm-global/bin:$PATH"', ALLOWED_HOOK_EVENTS2, QMD_SPEC, QMD_MATCHER = "Write|Edit";
|
|
10336
10381
|
var init_register_hooks = __esm(() => {
|
|
10337
10382
|
init_dist2();
|
|
10338
10383
|
init_lib();
|
|
10339
10384
|
init_harness();
|
|
10340
10385
|
import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
10341
|
-
|
|
10342
|
-
Stop: "onebrain checkpoint stop"
|
|
10386
|
+
HOOK_SPECS = {
|
|
10387
|
+
Stop: { command: "onebrain", args: ["checkpoint", "stop"] }
|
|
10343
10388
|
};
|
|
10344
10389
|
HOOK_EVENTS = ["Stop"];
|
|
10345
10390
|
PERMISSIONS_TO_ADD = [
|
|
@@ -10359,6 +10404,7 @@ var init_register_hooks = __esm(() => {
|
|
|
10359
10404
|
"WebSearch"
|
|
10360
10405
|
];
|
|
10361
10406
|
ALLOWED_HOOK_EVENTS2 = new Set(["Stop", "PostToolUse"]);
|
|
10407
|
+
QMD_SPEC = { command: "onebrain", args: ["qmd-reindex"] };
|
|
10362
10408
|
});
|
|
10363
10409
|
|
|
10364
10410
|
// src/commands/internal/vault-sync.ts
|
|
@@ -10994,7 +11040,7 @@ var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
|
10994
11040
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
10995
11041
|
function resolveBinaryVersion() {
|
|
10996
11042
|
if (true)
|
|
10997
|
-
return "2.2.
|
|
11043
|
+
return "2.2.4";
|
|
10998
11044
|
try {
|
|
10999
11045
|
const pkg = require_package();
|
|
11000
11046
|
return pkg.version ?? "dev";
|
|
@@ -13292,8 +13338,8 @@ function patchUtf8(stream) {
|
|
|
13292
13338
|
}
|
|
13293
13339
|
|
|
13294
13340
|
// src/index.ts
|
|
13295
|
-
var VERSION = "2.2.
|
|
13296
|
-
var RELEASE_DATE = "2026-05-
|
|
13341
|
+
var VERSION = "2.2.4";
|
|
13342
|
+
var RELEASE_DATE = "2026-05-12";
|
|
13297
13343
|
patchUtf8(process.stdout);
|
|
13298
13344
|
patchUtf8(process.stderr);
|
|
13299
13345
|
var VERSION_STRING = `OneBrain v${VERSION} \u2014 released ${RELEASE_DATE}`;
|