@onebrain-ai/cli 2.2.2 → 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 +70 -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;
|
|
@@ -10149,19 +10185,28 @@ function migrateLegacyQmdEntries(groups, keepCanonical) {
|
|
|
10149
10185
|
}
|
|
10150
10186
|
} else {
|
|
10151
10187
|
const before = group.hooks.length;
|
|
10152
|
-
group.hooks = group.hooks.filter((h) =>
|
|
10188
|
+
group.hooks = group.hooks.filter((h) => {
|
|
10189
|
+
const cmd = h.command ?? "";
|
|
10190
|
+
return !isLegacyQmdCmd(cmd) && !isCanonicalQmdEntry(h);
|
|
10191
|
+
});
|
|
10153
10192
|
if (group.hooks.length !== before)
|
|
10154
10193
|
touched = true;
|
|
10155
10194
|
}
|
|
10156
10195
|
}
|
|
10157
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
|
+
}
|
|
10158
10203
|
let seenCanonical = false;
|
|
10159
10204
|
for (const group of groups) {
|
|
10160
10205
|
if (!group.hooks)
|
|
10161
10206
|
continue;
|
|
10162
10207
|
const before = group.hooks.length;
|
|
10163
10208
|
group.hooks = group.hooks.filter((h) => {
|
|
10164
|
-
if (h
|
|
10209
|
+
if (!isCanonicalQmdEntry(h))
|
|
10165
10210
|
return true;
|
|
10166
10211
|
if (seenCanonical)
|
|
10167
10212
|
return false;
|
|
@@ -10186,10 +10231,13 @@ function applyQmdHook(settings) {
|
|
|
10186
10231
|
settings.hooks["PostToolUse"] = [];
|
|
10187
10232
|
const groups = settings.hooks["PostToolUse"];
|
|
10188
10233
|
const migrated = migrateLegacyQmdEntries(groups, true);
|
|
10189
|
-
const already = groups.some((g) => g.hooks?.some((h) => h
|
|
10234
|
+
const already = groups.some((g) => g.hooks?.some((h) => isCanonicalQmdEntry(h)));
|
|
10190
10235
|
if (already)
|
|
10191
10236
|
return migrated ? "migrated" : "ok";
|
|
10192
|
-
groups.push({
|
|
10237
|
+
groups.push({
|
|
10238
|
+
matcher: QMD_MATCHER,
|
|
10239
|
+
hooks: [{ type: "command", command: QMD_SPEC.command, args: [...QMD_SPEC.args] }]
|
|
10240
|
+
});
|
|
10193
10241
|
return "added";
|
|
10194
10242
|
}
|
|
10195
10243
|
function applyPermissions(settings) {
|
|
@@ -10329,14 +10377,14 @@ async function registerHooksCommand(vaultDir) {
|
|
|
10329
10377
|
process.exit(1);
|
|
10330
10378
|
}
|
|
10331
10379
|
}
|
|
10332
|
-
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";
|
|
10333
10381
|
var init_register_hooks = __esm(() => {
|
|
10334
10382
|
init_dist2();
|
|
10335
10383
|
init_lib();
|
|
10336
10384
|
init_harness();
|
|
10337
10385
|
import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
10338
|
-
|
|
10339
|
-
Stop: "onebrain checkpoint stop"
|
|
10386
|
+
HOOK_SPECS = {
|
|
10387
|
+
Stop: { command: "onebrain", args: ["checkpoint", "stop"] }
|
|
10340
10388
|
};
|
|
10341
10389
|
HOOK_EVENTS = ["Stop"];
|
|
10342
10390
|
PERMISSIONS_TO_ADD = [
|
|
@@ -10356,6 +10404,7 @@ var init_register_hooks = __esm(() => {
|
|
|
10356
10404
|
"WebSearch"
|
|
10357
10405
|
];
|
|
10358
10406
|
ALLOWED_HOOK_EVENTS2 = new Set(["Stop", "PostToolUse"]);
|
|
10407
|
+
QMD_SPEC = { command: "onebrain", args: ["qmd-reindex"] };
|
|
10359
10408
|
});
|
|
10360
10409
|
|
|
10361
10410
|
// src/commands/internal/vault-sync.ts
|
|
@@ -10991,7 +11040,7 @@ var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
|
10991
11040
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
10992
11041
|
function resolveBinaryVersion() {
|
|
10993
11042
|
if (true)
|
|
10994
|
-
return "2.2.
|
|
11043
|
+
return "2.2.4";
|
|
10995
11044
|
try {
|
|
10996
11045
|
const pkg = require_package();
|
|
10997
11046
|
return pkg.version ?? "dev";
|
|
@@ -13289,8 +13338,8 @@ function patchUtf8(stream) {
|
|
|
13289
13338
|
}
|
|
13290
13339
|
|
|
13291
13340
|
// src/index.ts
|
|
13292
|
-
var VERSION = "2.2.
|
|
13293
|
-
var RELEASE_DATE = "2026-05-
|
|
13341
|
+
var VERSION = "2.2.4";
|
|
13342
|
+
var RELEASE_DATE = "2026-05-12";
|
|
13294
13343
|
patchUtf8(process.stdout);
|
|
13295
13344
|
patchUtf8(process.stderr);
|
|
13296
13345
|
var VERSION_STRING = `OneBrain v${VERSION} \u2014 released ${RELEASE_DATE}`;
|