Skip to content
Open
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,6 @@ PROGRESS.json
# Runtime output
tmp/
/scripts/eval/behavior/results/

# A pack's built dist/ is never committed — build it from source.
scripts/spike/*/dist/
26 changes: 8 additions & 18 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ root `~/.brains-dev`, its own single-instance socket and keychain item, signed
with the local self-signed cert — so the parity harness can drive both at once
and neither one's data is the other's. `src-tauri/tauri.conf.json` + `tauri.dev.conf.json` hold
it; `src-tauri/src/identity.rs` asserts the two never drift. `BRAINS_HOME`
overrides the data root for both. Removable apps keep their own ids — `exo` is one,
overrides the data root for both. Removable apps keep their own ids, and this repo tracks none of them —
not the product.

## Map
Expand Down Expand Up @@ -111,13 +111,12 @@ not the product.
manifests and restages the closure) → commit the manifest diff.
`cargo test --workspace`, the frontend suites and `tauri build` all pass
with it gone; that app's own tests and eval checks SKIP, out loud.
THE REMOVABLE APP THIS REPO CARRIES is `src/apps/exo`, the daily loop: TRACKED (one
folder, in the commit) and gated OFF, which is the first state above and not
a special case — nothing is armed, listed or spoken, and a plain session's
prompt is byte-identical with it deleted (spec 30). Two things open a gate,
and they OR: `apps.<id>.enabled` in settings.json, and `BRAINS_ENABLE_APPS`
— a comma list of ids THIS LAUNCH forces on
(`brains_storage::ENABLE_APPS_ENV`; `npm run dev:app` sets it from a glob,
THIS REPO TRACKS NO REMOVABLE APP. They come from external repos, installed
from a git URL in Settings → Apps (`docs/packs/AUTHORING.md`), and land
hash-verified at `<data-root>/packs/<id>/`. The three states above are their
states. Two things open a gate, and they OR: `apps.<id>.enabled` in
settings.json, and `BRAINS_ENABLE_APPS` — a comma list of ids THIS LAUNCH
forces on (`brains_storage::ENABLE_APPS_ENV`; `npm run dev:app` sets it from a glob,
so local dev runs with whatever is installed). The override can only OPEN a
gate, both halves read it (native `Settings::gate_open`, webview
`settings_forced_apps`), and a release started from Finder inherits nothing.
Expand Down Expand Up @@ -205,13 +204,4 @@ keychain; don't add keychain-touching test paths outside release checks.

No names, addresses, machine paths (`/Users/<you>`), account ids or tokens in
tracked files — including fixtures, which use invented accounts
(`Ada Lovelace <ada@example.test>`) and invented ids.

ONE DELIBERATE EXCEPTION, and it is the whole of it: `src/apps/exo` — a REMOVABLE APP,
its skills, and the manifest entries the build scans out of them. A removable app IS
somebody's personal app; its prompts name that person's brains boards and their
own daily loop, and stripping that would leave an app that does nothing. It is
tracked (rule 6) and gated off, so it ships as a folder nobody else's build
runs. Tokens and machine paths are still never in it. Everything outside that
folder holds the line above, and an app you'd rather not publish at all stays
private through `.gitignore` (rule 6), not through discipline.
(`Ada Lovelace <ada@example.test>`) and invented ids. No exceptions.
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"src/engines/context",
"src/engines/brains/native",
"src/engines/browser",
"src/engines/apps",
"src/engines/recording",
"src/engines/storage",
"src-tauri",
Expand All @@ -27,6 +28,7 @@ brains-native = { path = "src/engines/brains/native" }
brains-model = { path = "src/engines/model" }
brains-local-agents = { path = "src/engines/agents/local" }
brains-context = { path = "src/engines/context" }
brains-apps = { path = "src/engines/apps" }
brains-recording = { path = "src/engines/recording" }
brains-browser = { path = "src/engines/browser" }

Expand Down
48 changes: 19 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,32 +378,24 @@ scope). A removable app has **three** states:
keeps the third state true, and `scripts/eval/checks/removable app-removable.mjs`
enforces it mechanically.

### The removable app this repo carries
### Where removable apps come from

`src/apps/exo` — the daily loop (Mo plans and reviews the day, Iris reads
identity, Awareness grades its own predictions, all on brains boards). It is
**present and gated off**: it ships tracked in this repo, in one folder, and a
build does nothing with it until its gate opens. That is the *switched off*
state above, not a special case — no slot is armed, it is not in the + menu,
and a plain session's system prompt is byte-identical with the gate open and
with it shut (`with_a_packs_gate_on_a_plain_session_byte_matches_the_ungated_base`).

It is also the personal app it looks like: its skills carry their author's own
board ids and daily-loop wording. That is what a removable app is for, and it is the
reason the gate is the boundary it is.
This repo tracks none. A removable app lives in its own git repo and is
installed from **Settings → Apps** by pasting its URL — clone, build, verify,
install, gate open, tab in the + menu. The contract an external repo follows is
[docs/packs/AUTHORING.md](docs/packs/AUTHORING.md); an installed one lives
hash-verified at `<data-root>/packs/<id>/`.

### Running with a removable app locally

Two ways to open a gate, and they OR:

- **Settings → Developer → Installed removable apps** — the switch, per removable app. It writes
`apps.<id>.enabled` into your `settings.json` and takes effect live, both
directions, without a restart.
- **Settings → Apps** — install, update and uninstall, and the gate switch per
installed app. The switch writes `apps.<id>.enabled` into your `settings.json`
and takes effect live, both directions, without a restart.
- **`BRAINS_ENABLE_APPS=<id>[,<id>…]`** — a comma list of app ids this *launch*
forces on, whatever the file says. `npm run dev:app` sets it from
`scripts/dev/installed-removable apps.mjs` (a glob of `src/apps/*/app.json`), so local
dev always runs with whatever this checkout carries. Name the variable in
`.env` to override the list.
forces on, whatever the file says. Useful for dev and tests against a
temporary install.

The environment override can only ever open a gate, never close one, and both
halves of the app read the same answer — native through
Expand All @@ -415,16 +407,14 @@ the switch there writes a file that is not what is answering.
A **release build started from Finder inherits nothing** and stays default-off.
The variable is a developer's tool, not a shipping mode.

### Adding your own

1. `mkdir src/apps/mine` and write `app.json` with `"gate": "apps.mine.enabled"`.
2. `index.ts` — register the app with `core/app-registry`, gated on that key.
3. Optionally `context.json` (what a session is told, gated on the same key),
`mine.agents.json` + `skills/*.md` (what runs on a schedule), and
`eval/*.yaml` (your own eval lane — `npm run eval` discovers it).
4. `npm run build` to regenerate the manifests, then commit the manifest diff.
To keep the removable app private instead, add `src/apps/mine/` to `.gitignore`; the
committed manifests will not mention it.
1. Start a repo with `pack.json` (`id`, `gate: "apps.<id>.enabled"`, `title`,
`description`, `version`).
2. `index.ts` — register the app with the host's registry, gated on that key.
3. Optionally `context.json` (what a session is told), `*.agents.json` +
`skills/*.md` (what runs on a schedule), and `eval/*.yaml` (your own lane).
4. A build script that emits a self-contained `dist/`. Then install it from
Settings → Apps. [docs/packs/AUTHORING.md](docs/packs/AUTHORING.md) is the
full contract, and `scripts/spike/hello-pack` is a worked example.

---

Expand Down
Loading
Loading