Skip to content

Commit c7b5cb3

Browse files
machbuildsclaude
andcommitted
v0.1.1: nucleus + learnings refactor — both fully user-owned, ~/.atom/ namespace
Architectural refactor of the cross-project knowledge story. Locks the mental model into two distinct, both 100%-user-owned layers: nucleus = your MEMORY of every session (raw, low bar, project-tagged) → ~/.atom/nucleus/projects/<slug>/learnings.jsonl learnings = your PLAYBOOK of patterns to carry forward (curated, high bar) → ~/.atom/learnings/<type>/<key>.md → auto-copied into every new project you bootstrap Both are the user's data. Nothing leaves their machine without explicit action. Optional sync goes to *their own* private GitHub repos. Storage rename: ~/.nucleus/ → ~/.atom/nucleus/ (one-shot migration runs on first nucleus invocation; mv the directory if the new location is empty and the legacy one exists). Promote target rename: nucleus promote <id> now writes into the user's ~/.atom/learnings/, NOT into the atom repo's learnings/ directory. That maintainer-curated `learnings/` directory is gone — it conflated maintainer wisdom with user data and broke the privacy model. New CLIs: bin/learnings/ Mirror of nucleus shape: init / list / show / remove / sync. Stores at ~/.atom/learnings/. The promote target for `nucleus promote`. bin/atom/ Top-level help dispatcher. `atom --help` (or `atom`) prints the unified command table for every CLI in the system. No subcommand routing; pure discovery surface. ./atom-setup now installs 5 CLIs globally (was 3): atom, atom-setup, nucleus, learnings, model-race. Cheatsheet at end nudges the user to run `nucleus init && learnings init` once per machine. scripts/copy-learnings.mjs sources from ~/.atom/learnings/ by default (was ./learnings). atom-setup writer.js does the same. scaffold/AGENTS.md Tooling section rewritten with the nucleus-vs- learnings distinction unmissable. Two clearly labeled sections, the generalization test framed at the promotion bridge, setup nudge documented for AI tools. scaffold/.claude/skills/nucleus/SKILL.md updated with the same two- layer framing and a setup-nudge instruction for first-session detection. README.md gets a nucleus-vs-learnings comparison table at the top of the "What is nucleus" section, replacing the metaphor-first prose. All package versions bumped to 0.1.1. CHANGELOG.md gains a [0.1.1] entry covering the rename, the user- owned shift, the two new CLIs, and the cheatsheet nudges. Regression suite (scripts/test-atom-setup.sh) version assertion bumped to 0.1.1; all 57 assertions still pass locally. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 3bbbd35 commit c7b5cb3

38 files changed

Lines changed: 1332 additions & 261 deletions

CHANGELOG.md

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,41 @@ All notable changes to atom land here. Format: [Keep a Changelog](https://keepac
66

77
Tracking work targeting v0.2. See `docs/planning/` for in-flight build plans.
88

9+
## [0.1.1] — 2026-05-06
10+
11+
Architectural refactor of the nucleus + learnings story. **No new features**, but the conceptual model is now coherent and the storage layout is namespaced under `~/.atom/`.
12+
13+
### Changed
14+
15+
- **`learnings` is now user-owned, not maintainer-curated.** Previously, `learnings/` was a directory in the atom repo where the maintainer's curated wisdom lived; new projects inherited it at clone time. That conflated maintainer content with user data and confused the privacy story. Now `learnings` is the user's *own* playbook, lives at `~/.atom/learnings/` on their machine, and follows them across every new project they bootstrap. atom ships the system; the content is theirs alone. Optional sync to *their* private GitHub repo (separate from the nucleus sync repo).
16+
- **Storage moved from `~/.nucleus/` to `~/.atom/nucleus/`.** Namespace consistency with `~/.atom/learnings/` and any future per-machine atom state (config, cache, etc.). Migration is one-shot: `nucleus` detects `~/.nucleus/` on first run and renames it to `~/.atom/nucleus/`.
17+
- **`nucleus promote <id>`** now writes into `~/.atom/learnings/<type>/<key>.md` (the user's playbook) instead of the atom repo's `learnings/`.
18+
- **`scripts/copy-learnings.mjs`** sources from `~/.atom/learnings/` by default (was `./learnings`).
19+
- **`atom-setup` writer** copies learnings from the user's `~/.atom/learnings/` into the new project, filtered by stack tags. No-op when the user hasn't run `learnings init` or hasn't promoted anything yet.
20+
- **README, AGENTS.md, planning docs** rewritten to make the nucleus-vs-learnings distinction unmissable. Both layers framed as "100% yours."
21+
22+
### Added
23+
24+
- **`learnings` CLI** at `bin/learnings/``init`, `list`, `show`, `remove`, `sync`. Mirrors the nucleus CLI's shape. Promote target for `nucleus promote`.
25+
- **`atom` CLI** at `bin/atom/` — top-level help dispatcher. `atom --help` (or `atom`) prints the unified command table for every CLI in the atom system. No subcommand routing; pure discovery surface.
26+
- **Setup nudges** in the post-`atom-setup` cheatsheet and Claude nucleus skill: prompt the user to run `nucleus init && learnings init` once per machine.
27+
28+
### Removed
29+
30+
- **`atom/learnings/`** (the maintainer-curated directory) — removed from the repo. The system (taxonomy doc, copy script, promote flow) stays; the content is no longer atom's.
31+
32+
### CLI count
33+
34+
`./atom-setup` now installs **5 CLIs** globally: `atom`, `atom-setup`, `nucleus`, `learnings`, `model-race`.
35+
936
## [0.1.0] — 2026-05-05
1037

1138
First feature-complete release. atom is a project-starter template with cross-project memory, multi-tool AI support, and an opinionated dev workflow.
1239

1340
### Added
1441

1542
- **`atom-setup`** — interactive wizard (Node + clack). Four modes: `--bare`, `--minimal`, default, `--full`. Ten sections cover project basics, stack, license, Docker tier, CI/CD, git. Pre-flight detection, smart defaults from environment, resumable state, dry-run, final confirmation screen.
16-
- **`nucleus`** — cross-project learning store CLI. Subcommands: `init`, `add`, `search`, `sync`, `promote`, `slug`. JSONL storage at `~/.nucleus/projects/<slug>/`, optional GitHub sync, keyword + structured filter search, three capture modes (claude-managed, auto-timer, manual).
43+
- **`nucleus`** — cross-project learning store CLI. Subcommands: `init`, `add`, `search`, `sync`, `promote`, `slug`. JSONL storage at `~/.atom/nucleus/projects/<slug>/`, optional GitHub sync, keyword + structured filter search, three capture modes (claude-managed, auto-timer, manual).
1744
- **`learnings/`** — graduation layer for nucleus entries that pass the generalisation test. Files inherit into bootstrapped projects via `scripts/copy-learnings.mjs`, filtered by stack tags from `docs/LEARNINGS_TAXONOMY.md`.
1845
- **`model-race`** — parallel AI model comparison via Git worktrees. Subcommands: `start`, `status`, `spec`, `launch`, `score`, `judge`, `merge`, `abort`. Weighted scorecard (pass-fail and numeric-min metrics), opt-in LLM judge, configurable per-project via `model-race.config.json`.
1946
- **Docker** — four optional tiers in `extras/docker/`: None, Dockerfile only, + compose, + devcontainer. Smart-defaulted from stack and deploy target. Production-grade defaults: multi-stage build, non-root user, healthcheck, pinned base image, BuildKit cache mounts, multi-arch CI workflow.
@@ -30,5 +57,6 @@ First feature-complete release. atom is a project-starter template with cross-pr
3057
- Stack presets currently include `nextjs` only. Other stacks fall back to the generic scaffold and will land per-stack in v0.2.
3158
- Constitution generation is a TODO marker in the cheatsheet; v0.2 will wire `speckit-constitution` automatically.
3259

33-
[Unreleased]: https://github.com/machbuilds/atom/compare/v0.1.0...HEAD
60+
[Unreleased]: https://github.com/machbuilds/atom/compare/v0.1.1...HEAD
61+
[0.1.1]: https://github.com/machbuilds/atom/releases/tag/v0.1.1
3462
[0.1.0]: https://github.com/machbuilds/atom/releases/tag/v0.1.0

INSTALL.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ If `./atom-setup` fails with `EACCES`, use `sudo ./atom-setup` or set up an npm
4848

4949
### 2. nucleus init
5050

51-
Run once on each machine to set up `~/.nucleus`:
51+
Run once on each machine to set up `~/.atom/nucleus`:
5252

5353
```bash
5454
nucleus init
@@ -65,7 +65,7 @@ nucleus add "test entry" --type pattern --confidence low
6565
nucleus search "test"
6666
```
6767

68-
The first command appends an entry; the second should find it. Once verified you can delete the test entry by editing `~/.nucleus/projects/<slug>/learnings.jsonl` directly.
68+
The first command appends an entry; the second should find it. Once verified you can delete the test entry by editing `~/.atom/nucleus/projects/<slug>/learnings.jsonl` directly.
6969

7070
### 3. AI CLI of your choice
7171

README.md

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ Plus `--resume` (pick up an interrupted setup), `--dry-run` (preview without wri
9292
| Feature | What it does |
9393
|---|---|
9494
| **`atom-setup`** | Interactive wizard (Node + clack). 4 modes: `--bare` / `--minimal` / default / `--full`. 10 sections cover project basics, stack, license, Docker tier, CI, git. Pre-flight detection, smart defaults, resumable state. |
95-
| **`nucleus`** | Cross-project learning store at `~/.nucleus`. Captures durable lessons mid-session; surfaces them in any future project. JSONL storage, optional GitHub sync, keyword + structured filter search. |
96-
| **`learnings/`** | Graduation layer for `nucleus` entries that prove generalizable. Files inherit into every bootstrapped project, filtered by stack tags. |
95+
| **`nucleus`** | Your **memory** — raw notes from every session, project-tagged, captured fast. Lives at `~/.atom/nucleus/`. JSONL storage, keyword + structured filter search. Optionally synced to your own private GitHub repo. |
96+
| **`learnings`** | Your **playbook** — patterns you've decided to carry forward. Lives at `~/.atom/learnings/`. Auto-copied into every new project you bootstrap (filtered by stack tags). Optionally synced to your own private GitHub repo. |
9797
| **`model-race`** | Parallel AI model comparison via Git worktrees. Race the same spec through claude/codex/gemini, score with weighted metrics, optional LLM judge, merge the winner. |
9898
| **Docker, optional** | Four tiers: None / Dockerfile / + compose / + devcontainer. Smart-defaulted from your stack. Production-grade out of the box (multi-stage, non-root, healthcheck, multi-arch CI). |
9999
| **Multi-AI tool support** | `AGENTS.md` is the canonical spec; `CLAUDE.md` / `GEMINI.md` / `.cursorrules` / `.github/copilot-instructions.md` are forwarders. Claude, Codex CLI, Gemini CLI, Cursor, and Copilot all read the same instructions. |
@@ -104,32 +104,41 @@ Plus `--resume` (pick up an interrupted setup), `--dry-run` (preview without wri
104104

105105
## What is nucleus?
106106

107-
**nucleus is atom's cross-project learning store.** It's a CLI (`nucleus add`, `nucleus search`, `nucleus promote`, `nucleus sync`) backed by a JSONL file at `~/.nucleus/projects/<slug>/learnings.jsonl` on your machine. You capture durable lessons mid-session — pitfalls, patterns, architecture decisions with rationale — and they surface in any future session, in any project, with `nucleus search`.
107+
atom ships with two layers of cross-project knowledge. They're easy to confuse, so the distinction matters:
108108

109-
Think of it as **the brain of your project work that travels across every clone.** Every atom has a nucleus at its center holding its identity; `nucleus` does the same for your projects: the core knowledge that makes each project what it is.
109+
| | **nucleus** | **learnings** |
110+
|---|---|---|
111+
| What it is | Your **memory** of every session | Your **playbook** of patterns to carry forward |
112+
| Bar to capture | Low — "worth noting" | High — "worth carrying into every future project" |
113+
| Granularity | Raw, project-tagged | Curated, generalized, per-type |
114+
| Lives where | `~/.atom/nucleus/` | `~/.atom/learnings/` |
115+
| Auto-copied to new projects? | No | Yes (filtered by stack tags) |
116+
| Optional sync | Your own private GitHub repo | Your own private GitHub repo (separate from nucleus) |
117+
118+
**Both are 100% yours.** Nothing leaves your machine without your explicit action. atom is the system; the content is yours.
110119

111120
### Why it exists
112121

113122
Code can be rewritten. The lessons you learned writing it are harder to recover. They sit in your head, get half-remembered, and quietly disappear when you start the next project. Most coding sessions teach you something — a pitfall, a pattern, an architecture decision with rationale. Without a capture system, that learning evaporates the moment the session ends.
114123

115-
`nucleus` catches those lessons mid-session and lets future sessions, in any project, benefit from them. Together with atom's structure, you get more than a starter template: code you can rewrite, plus knowledge you can't.
124+
`nucleus` catches those lessons mid-session, low bar, project-tagged. `learnings` is the curated subset you've decided to carry forward — auto-copied into every new project you bootstrap. Together they give you code you can rewrite **plus knowledge you can't**.
116125

117126
### The flow
118127

119128
```
120129
session
121130
122-
▼ nucleus add (raw, project-tagged)
123-
~/.nucleus/projects/<slug>/learnings.jsonl
131+
▼ nucleus add (raw, project-tagged, low bar)
132+
~/.atom/nucleus/projects/<slug>/learnings.jsonl
124133
125134
▼ nucleus promote <id> (passes generalization test)
126-
atom/learnings/<type>/<slug>.md (curated, ships to new projects)
135+
~/.atom/learnings/<type>/<key>.md (your local playbook)
127136
128-
refine into prose
129-
atom/docs/LESSONS_LEARNED.md (essay form)
137+
atom-setup new project (filtered by stack)
138+
<new-project>/learnings/<type>/<key>.md (carried forward)
130139
```
131140

132-
The first arrow is automated when Claude is your AI (claude-managed capture mode is the default). The second is human-in-the-loop — `nucleus promote` opens `$EDITOR` so you can refine the draft before it lands. The third is rare and intentional.
141+
The first arrow is automated when Claude is your AI (`claude-managed` capture mode is the default). The second is human-in-the-loop — `nucleus promote` opens `$EDITOR` so you can refine the draft before it lands. The third runs every time you bootstrap a project from atom — your playbook follows you.
133142

134143
### Capture modes
135144

@@ -139,7 +148,7 @@ The first arrow is automated when Claude is your AI (claude-managed capture mode
139148
| **`auto-timer`** | A background process drains a session log every N minutes (5/15/30/60). For users who don't want to think about it. |
140149
| **`manual`** | Claude surfaces "worth capturing?" suggestions; you run `nucleus add` yourself. For users who want full control. |
141150

142-
Picked at `atom-setup` time, configurable later via `~/.nucleus/config.json`.
151+
Picked at `atom-setup` time, configurable later via `~/.atom/nucleus/config.json`.
143152

144153
---
145154

@@ -151,7 +160,7 @@ Picked at `atom-setup` time, configurable later via `~/.nucleus/config.json`.
151160
| Interactive wizard | yes (4 modes) | yes | yes | no |
152161
| Stack presets | yes | partial | yes | no |
153162
| AI-tool integration | yes (multi-tool via AGENTS.md) | no | no | no |
154-
| Cross-project learning store | yes (nucleus) | no | no | no |
163+
| Cross-project memory + playbook | yes (nucleus + learnings) | no | no | no |
155164
| Parallel-model workflow | yes (model-race) | no | no | no |
156165
| Constitution / principles | yes | no | no | no |
157166
| Production Docker defaults | yes (4 tiers, opt-in) | partial | no | no |
@@ -209,14 +218,14 @@ atom/
209218
│ ├── .claude/ Claude-specific skills (nucleus + agent skills)
210219
│ └── package.json Baseline scripts
211220
212-
├── learnings/ Generalised, structured learnings (graduation layer)
213-
214221
├── bin/ Global CLIs (install once per machine)
222+
│ ├── atom/ Top-level help dispatcher (`atom --help`)
215223
│ ├── atom-setup/ Interactive wizard
216-
│ ├── nucleus/ Cross-project learning store CLI
224+
│ ├── nucleus/ Your session memory CLI
225+
│ ├── learnings/ Your playbook CLI
217226
│ └── model-race/ Parallel AI model comparison via Git worktrees
218227
219-
├── scripts/ Maintenance scripts (e.g. copy-learnings.mjs)
228+
├── scripts/ Maintenance scripts (e.g. copy-learnings.mjs, test-atom-setup.sh)
220229
221230
└── extras/ Opt-in stack presets, copied based on user choice
222231
├── docker/ Dockerfile, compose, devcontainer, CI
@@ -300,7 +309,7 @@ atom/
300309
atom evolves with every project that's shipped from it. The flow:
301310

302311
1. **During the project**, capture learnings via `nucleus add` (or `docs/INBOX.md` if you prefer manual).
303-
2. **At the end of the project**, run `nucleus promote <id>` for entries that pass the generalization test. Files land in `atom/learnings/<type>/<slug>.md`.
312+
2. **At the end of the project**, run `nucleus promote <id>` for entries that pass the generalization test. Files land in your local playbook at `~/.atom/learnings/<type>/<slug>.md` and ride forward into every new project you bootstrap.
304313
3. **Periodically**, refine those into prose for `docs/LESSONS_LEARNED.md`.
305314

306315
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the rules and the generalization test.

atom-setup

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ if [ "$NODE_MAJOR" -lt 18 ]; then
3838
exit 1
3939
fi
4040

41-
CLIS=(atom-setup nucleus model-race)
41+
CLIS=(atom atom-setup nucleus learnings model-race)
4242

4343
# Find the GLOBAL atom-setup (skip cwd in PATH so we don't recurse into
4444
# this script). Used both for "already installed?" detection and for the

bin/atom-setup/bin/atom-setup.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,9 @@ function printCheatsheet(state, preflight) {
257257
const tasks = [];
258258

259259
if (a.nucleusEnabled) {
260-
tasks.push(`${color.cyan('•')} Initialize nucleus on this machine: ${color.cyan('nucleus init')}`);
260+
tasks.push(`${color.cyan('•')} Initialize nucleus (your session memory): ${color.cyan('nucleus init')}`);
261+
tasks.push(`${color.cyan('•')} Initialize learnings (your local playbook): ${color.cyan('learnings init')}`);
262+
tasks.push(` ${color.dim('Both are 100% yours. Optional GitHub sync to your private repo.')}`);
261263
}
262264
if (a.mem0) {
263265
tasks.push(`${color.cyan('•')} Set up mem0 MCP: see ${color.cyan('docs/INSTALL.md')} (or wherever it lives in scaffold)`);
@@ -275,6 +277,8 @@ function printCheatsheet(state, preflight) {
275277
tasks.push(`${color.cyan('•')} Push to your remote when ready: ${color.cyan(`git remote add origin ${a.gitRemote} && git push -u origin main`)}`);
276278
}
277279

280+
tasks.push(`${color.cyan('•')} See every atom command in one place: ${color.cyan('atom --help')}`);
281+
278282
if (tasks.length > 0) {
279283
note(tasks.join('\n'), `What's next`);
280284
}

bin/atom-setup/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@atom/atom-setup",
3-
"version": "0.1.0",
3+
"version": "0.1.1",
44
"description": "Interactive wizard that transforms a cloned atom checkout into a personalized project.",
55
"type": "module",
66
"bin": {

bin/atom-setup/src/lib/writer.js

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
existsSync, readdirSync, statSync, copyFileSync, mkdirSync,
66
writeFileSync, rmSync, renameSync, readFileSync,
77
} from 'node:fs';
8+
import { homedir } from 'node:os';
89
import { join, dirname, relative } from 'node:path';
910
import { spawnSync } from 'node:child_process';
1011
import {
@@ -13,6 +14,9 @@ import {
1314
} from './manifest.js';
1415
import { renderLicense } from './licenses.js';
1516

17+
const ATOM_HOME = process.env.ATOM_HOME || join(homedir(), '.atom');
18+
const USER_LEARNINGS_DIR = process.env.ATOM_LEARNINGS_HOME || join(ATOM_HOME, 'learnings');
19+
1620
export async function applyState(state, cwd, opts = {}) {
1721
const log = opts.log || (() => {});
1822
const dryRun = opts.dryRun === true;
@@ -36,8 +40,11 @@ export async function applyState(state, cwd, opts = {}) {
3640
copyDockerTier(root, answers.dockerTier, log, dryRun);
3741
}
3842

39-
// 5. Filter and copy learnings (from learnings/ source dir).
40-
if (existsSync(join(root, 'learnings'))) {
43+
// 5. Filter and copy learnings (from the user's local playbook at
44+
// ~/.atom/learnings/, NOT from anything in the atom repo).
45+
// No-op if the user has not yet promoted any learnings or hasn't
46+
// run `learnings init`.
47+
if (existsSync(USER_LEARNINGS_DIR)) {
4148
copyLearnings(root, answers.stack, log, dryRun);
4249
}
4350

@@ -96,13 +103,15 @@ function copyDockerTier(root, tier, log, dryRun) {
96103
}
97104

98105
function copyLearnings(root, stack, log, dryRun) {
99-
const src = join(root, 'learnings');
106+
const src = USER_LEARNINGS_DIR;
100107
const tags = new Set(STACK_TAGS[stack] || ['universal']);
101108

102109
function walk(dir) {
103110
for (const entry of readdirSync(dir)) {
104111
const p = join(dir, entry);
105-
if (statSync(p).isDirectory()) {
112+
let s;
113+
try { s = statSync(p); } catch { continue; }
114+
if (s.isDirectory()) {
106115
walk(p);
107116
} else if (entry.endsWith('.md') && entry !== 'README.md') {
108117
const rel = relative(src, p);
@@ -114,13 +123,12 @@ function copyLearnings(root, stack, log, dryRun) {
114123
if (!matches(appliesTo, tags)) continue;
115124

116125
if (dryRun) {
117-
log(`(dry-run) learning copy: ${rel}`);
126+
log(`(dry-run) learning copy from playbook: ${rel}`);
118127
continue;
119128
}
120-
if (dst === p) continue;
121129
mkdirSync(dirname(dst), { recursive: true });
122130
copyFileSync(p, dst);
123-
log(`learning copy: ${rel}`);
131+
log(`learning copy from playbook: ${rel}`);
124132
}
125133
}
126134
}

0 commit comments

Comments
 (0)