Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# npm
node_modules/
*.tgz

# Project-level install manifest written by `brain-md setup --project`
.brain.md/

# MindMux client runtime artifacts (task logs, etc.) — not part of the product
.mindmux/

Expand Down
26 changes: 21 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,26 @@ and anything readable straight from the code and git history stay where they are
**1. Install the tools once (global):**

```bash
./setup # symlinks skills/ into every detected agent (~/.claude/skills, ~/.codex/skills, …)
./uninstall # reverses it cleanly; never touches any project's brain data
npx brain-md setup # copies skills/ into every detected agent (~/.claude/skills, ~/.codex/skills, …)
npx brain-md uninstall # reverses it cleanly; never touches any project's brain data
```

Or install the package globally and use the `brain-md` command directly:

```bash
npm install -g brain-md
brain-md setup # interactive: confirms each detected runtime, then copies the bundles
brain-md uninstall # removes exactly what was installed
```

Flags:

- `--project` — install into the **current project's** `.claude/skills`, `.codex/skills`, … instead of your home dir, so a clone is self-contained and team-shareable.
- `--symlink` — symlink the bundles instead of copying (for developing the toolkit itself).
- `--yes` / `-y` — non-interactive; install into every runtime without asking (CI).

Copy is the default because symlinks break on Windows and when the source repo moves; `--symlink` stays available for local development.

**2. Initialize a project** — run the **brain-setup** skill in it. It scaffolds `BRAIN.md` +
the brain skeleton, wires the chosen agents' config files, and can install a pre-commit hook.

Expand Down Expand Up @@ -94,11 +110,11 @@ Agent $ brain read-page config-as-markdown

## The `brain` CLI

Reading and writing the brain both go through one zero-dependency Node CLI (run with `node`):
Reading and writing the brain both go through one zero-dependency Node CLI. After
`brain-md setup` it is on your `PATH` as `brain` (it also ships inside the brain-page
skill bundle, so agents can run it as `node <bundle>/bin/brain.mjs` directly):

```bash
brain() { node skills/brain-page/bin/brain.mjs "$@"; }

brain brain-dir # where is the brain?
brain list-pages # list pages
brain read-page my-decision # read a page
Expand Down
56 changes: 56 additions & 0 deletions bin/brain-md-uninstall.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env node
// brain-md-uninstall — reverse what `brain-md setup` installed.
//
// Reads the install manifest and removes exactly the skills it recorded —
// copies or symlinks — confirming one runtime at a time. This NEVER touches any
// project's brain knowledge; per-project BRAIN.md and brain/ are state, not
// tools, and removing the tools leaves them intact.
//
// Usage:
// brain-md-uninstall [--project] [--keep-state] [--yes]
//
// Equivalent to `brain-md uninstall`.

import { runUninstall } from "./lib/installer.mjs";

const HELP = `brain-md-uninstall — remove the brain.md toolkit

Usage:
brain-md-uninstall [options]

Options:
--project operate on the current project's install manifest
--keep-state keep the install manifest after removing
--yes, -y non-interactive: remove from every recorded runtime (CI)
-h, --help show this help

Project brain/ data is never touched.`;

const opts = { assumeYes: false, keepState: false, project: false };
for (const a of process.argv.slice(2)) {
switch (a) {
case "--yes":
case "-y":
opts.assumeYes = true;
break;
case "--keep-state":
opts.keepState = true;
break;
case "--project":
opts.project = true;
break;
case "-h":
case "--help":
console.log(HELP);
process.exit(0);
break;
default:
console.error(`brain-md-uninstall: unknown option '${a}'`);
process.exit(2);
}
}

runUninstall(opts).catch((e) => {
console.error(`brain-md-uninstall: ${e?.message || e}`);
process.exit(1);
});
88 changes: 88 additions & 0 deletions bin/brain-md.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env node
// brain-md — the brain-md installer.
//
// Fans the packaged skill bundles (and the brain CLI they carry) out into the
// global skills directory of each agent runtime you choose. Default mode copies
// the bundles (robust on Windows and after the source moves); --symlink keeps
// the old development behaviour; --project installs into the current project.
//
// Usage:
// brain-md [setup] [--project] [--symlink] [--yes]
// brain-md uninstall [--project] [--keep-state] [--yes]
//
// `npx brain-md setup` runs this with the `setup` subcommand.

import { runSetup, runUninstall } from "./lib/installer.mjs";

const HELP = `brain-md — installer for the Open Project Brain Standard toolkit

Usage:
brain-md [setup] [options] install the skills + brain CLI
brain-md uninstall [options] remove what setup installed

Options:
--project install into the current project's .claude/, .codex/, …
(self-contained checkout) instead of your home dir
--symlink symlink the bundles instead of copying (development)
--yes, -y non-interactive: act on every runtime without asking (CI)
--keep-state (uninstall) keep the install manifest
-h, --help show this help

Default (no subcommand) is \`setup\`. Installing never touches any project's
brain knowledge — that is per-project state created by the brain-setup skill.`;

function parse(argv) {
const opts = { assumeYes: false, symlink: false, project: false, keepState: false };
for (const a of argv) {
switch (a) {
case "--yes":
case "-y":
opts.assumeYes = true;
break;
case "--symlink":
opts.symlink = true;
break;
case "--project":
opts.project = true;
break;
case "--keep-state":
opts.keepState = true;
break;
case "-h":
case "--help":
console.log(HELP);
process.exit(0);
break;
default:
console.error(`brain-md: unknown option '${a}'`);
process.exit(2);
}
}
return opts;
}

async function main() {
const argv = process.argv.slice(2);
let sub = "setup";
if (argv.length && !argv[0].startsWith("-")) sub = argv.shift();

const opts = parse(argv);

switch (sub) {
case "setup":
return runSetup(opts);
case "uninstall":
return runUninstall(opts);
case "help":
console.log(HELP);
return;
default:
console.error(`brain-md: unknown command '${sub}' (expected 'setup' or 'uninstall')`);
process.exit(2);
}
}

main().catch((e) => {
console.error(`brain-md: ${e?.message || e}`);
process.exit(1);
});
18 changes: 18 additions & 0 deletions bin/brain.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env node
// `brain` — the reference CLI for the Open Project Brain Standard, exposed as a
// package bin. The canonical implementation ships inside the brain-page skill
// bundle (so a copied/symlinked bundle stays self-contained and runnable on its
// own); this entry point just delegates to it from within the npm package.
//
// All reads and writes into a project's brain/ go through this command. See
// `brain help` for the full subcommand reference.

import { dirname, join } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";

const here = dirname(fileURLToPath(import.meta.url)); // <pkg>/bin
const cli = join(dirname(here), "skills", "brain-page", "bin", "brain.mjs");

// Importing runs the CLI's main() against the current process.argv / cwd.
// Use a file:// URL so the absolute path also resolves on Windows ESM.
await import(pathToFileURL(cli).href);
Loading