Skip to content

Commit 76ad388

Browse files
committed
chore: bootstrap memory-os prototype
Consolidates the Knowledge OS stack into one repo so the studio can evolve it as a single surface instead of three under-published packages. Cloned in (current source, no .git/node_modules/dist): - packages/kernel/ from E:/AI/ai-loadout (npm @mcptoolshop/ai-loadout@1.4.3) - packages/memories/ from E:/AI/claude-memories (unpublished, README rewritten 2026-06-10) - packages/rules/ from E:/AI/claude-rules (unpublished, README rewritten 2026-06-10) - apps/hook/ from ~/.claude/loadout-hook (mirror; live copy stays wired in settings.json) Picker docs: - .claude/CLAUDE.md source-of-truth rules + working conventions - ROADMAP.md five-phase plan (workspace wiring -> CLI surface -> docs -> npm -> publish + retire upstream) Reasoning for consolidation: memory/Feedback/feedback_consolidate_when_cant_juggle_repos.md (decompose-by-secrets is correct for teams of N humans; operational visibility wins for solo + LLM-crew.) PROTOTYPE state - upstream sources at E:/AI/{ai-loadout,claude-memories,claude-rules} remain source-of-truth until Phase 5 retirement.
0 parents  commit 76ad388

317 files changed

Lines changed: 46969 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/CLAUDE.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# memory-os — project instructions
2+
3+
## What this is
4+
5+
**memory-os is the Knowledge OS for the studio**, consolidated into one repo so it can evolve as a single surface. It folds together three previously-separate npm packages:
6+
7+
| Was | Now lives at | Role |
8+
|---|---|---|
9+
| `@mcptoolshop/ai-loadout` | `packages/kernel/` | Dispatch table, matching, resolver, runtime |
10+
| `@mcptoolshop/claude-memories` | `packages/memories/` | MEMORY.md parser + index/validate/stats |
11+
| `@mcptoolshop/claude-rules` | `packages/rules/` | CLAUDE.md parser + split/analyze/stats |
12+
13+
Plus the runtime pointer-injection hook earned in the 2026-06-10 session:
14+
15+
| Was | Now lives at | Role |
16+
|---|---|---|
17+
| `~/.claude/loadout-hook/` | `apps/hook/` | UserPromptSubmit hook — injects pointer lines to relevant memory entries |
18+
19+
## Status — PROTOTYPE (2026-06-10)
20+
21+
This is a **prototype consolidation**, not a finished product. Expect 1–2 months of work to reach shippable state. Pick up via `ROADMAP.md` at the repo root.
22+
23+
## Source-of-truth rule (load-bearing)
24+
25+
Until memory-os reaches first-shippable, the **upstream source-of-truth** still lives at:
26+
27+
- `E:/AI/ai-loadout/` (kernel — npm `@mcptoolshop/ai-loadout@1.4.3`, the only one published)
28+
- `E:/AI/claude-memories/` (memories — local-only, README rewritten 2026-06-10 to admit not-on-npm)
29+
- `E:/AI/claude-rules/` (rules — local-only, README rewritten 2026-06-10 to admit not-on-npm)
30+
- `~/.claude/loadout-hook/` (hook — wired into `~/.claude/settings.json`, runs every UserPromptSubmit)
31+
32+
**Do not edit the three upstream source repos from inside memory-os.** Edits inside memory-os stay inside memory-os until the explicit retirement step in `ROADMAP.md` (Phase 5).
33+
34+
**The live hook** at `~/.claude/loadout-hook/` is what's actually running in every session. `apps/hook/` here is a mirror for refactor work. If you change the hook contract, update both — and the wired path in `~/.claude/settings.json`.
35+
36+
## Why this consolidation
37+
38+
The "three small packages, one kernel + two adapters" design is architecturally clean (decompose-by-secrets, Parnas 1972) but operationally broken for the studio's solo + LLM-crew shape. Multi-repo work fragments Claude context across sessions, lets unpublished adapters rot (only kernel was published), and forces serial advancement when one-repo work could be parallel-within-session. Full reasoning: `C:/Users/mikey/.claude/projects/F--AI/memory/Feedback/feedback_consolidate_when_cant_juggle_repos.md`.
39+
40+
## Working rules
41+
42+
- **Read `ROADMAP.md` first.** It's the dispatch table for this repo.
43+
- **Read the global rules** at `C:/Users/mikey/.claude/CLAUDE.md` and the workspace rules at `E:/AI/.claude/CLAUDE.md` — they apply here too.
44+
- **Read the canonical memory store** at `C:/Users/mikey/.claude/projects/F--AI/memory/MEMORY.md` before any Write/Edit (enforced by hook).
45+
- The `loadout-hook` from session 2026-06-10 is live — it injects pointer lines on every prompt. Use them; don't paraphrase from the summaries.
46+
- Workflow standards apply: any new pipeline/script/SKILL.md needs the six-standards compliance block (`workflow_standards.md`).
47+
48+
## Standards compliance — repo bootstrap
49+
50+
This repo is a prototype clone-in, not a workflow. The six-standards rule applies to workflows authored INSIDE this repo (CI pipelines, swarm dispatchers, multi-step builds), not to the bootstrap itself.
51+
52+
## Quick orientation
53+
54+
- `packages/kernel/` — published as `@mcptoolshop/ai-loadout@1.4.3`. Stable API surface (`matchLoadout`, `planLoad`, `resolveLoadout`, `recordLoad`). Don't break this.
55+
- `packages/memories/` — CLI `claude-memories` (installed globally from this directory's upstream). Commands: `analyze`, `index`, `validate`, `stats`, `health`.
56+
- `packages/rules/` — CLI `claude-rules` (installed globally from upstream). Commands: `analyze`, `split`, `validate`, `stats`, `init-signals`.
57+
- `apps/hook/` — Node project, single mjs entrypoint, depends on `@mcptoolshop/ai-loadout` (npm). When Phase 1 lands, swap to a workspace dep on `packages/kernel`.

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
node_modules/
2+
dist/
3+
coverage/
4+
.nyc_output/
5+
.turbo/
6+
.cache/
7+
*.log
8+
.DS_Store
9+
Thumbs.db
10+
.env
11+
.env.local
12+
*.tsbuildinfo

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# memory-os
2+
3+
> **Prototype, 2026-06-10.** Consolidated Knowledge OS for the studio — folds `ai-loadout` (kernel) + `claude-memories` (MEMORY.md adapter) + `claude-rules` (CLAUDE.md adapter) + the runtime UserPromptSubmit pointer-injection hook into a single repo. Not yet wired as workspaces, not yet published, not yet on a remote.
4+
5+
## Pickers start here
6+
7+
- Read [`.claude/CLAUDE.md`](.claude/CLAUDE.md) — project instructions and source-of-truth rules
8+
- Read [`ROADMAP.md`](ROADMAP.md) — five-phase consolidation plan, ~1–2 months of session work
9+
- Then dive in
10+
11+
## Layout
12+
13+
```
14+
memory-os/
15+
├── packages/
16+
│ ├── kernel/ # was @mcptoolshop/ai-loadout (npm 1.4.3 — only one published)
17+
│ ├── memories/ # was @mcptoolshop/claude-memories (unpublished)
18+
│ └── rules/ # was @mcptoolshop/claude-rules (unpublished)
19+
├── apps/
20+
│ └── hook/ # mirror of ~/.claude/loadout-hook/ (the LIVE one)
21+
├── .claude/
22+
│ └── CLAUDE.md
23+
├── ROADMAP.md
24+
└── README.md
25+
```
26+
27+
## Why consolidate
28+
29+
Decompose-by-secrets (Parnas 1972) was the clean answer for a team of N humans. The studio runs 1 human + LLM crew — multi-repo work fragments Claude context across sessions and lets unpublished adapters rot. One named umbrella repo serves the operator. Full reasoning: `memory/Feedback/feedback_consolidate_when_cant_juggle_repos.md` in the canonical memory store.
30+
31+
## License
32+
33+
MIT (matches all three upstream sources).

ROADMAP.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# memory-os — ROADMAP
2+
3+
> Estimated horizon: **1–2 months** of session work to reach shippable.
4+
> Picker: whoever opens the next session in this tree. Read `.claude/CLAUDE.md` first.
5+
6+
## Phase 0 — Initial bootstrap (DONE, this commit)
7+
8+
- [x] Clone in the three upstream sources (`ai-loadout`, `claude-memories`, `claude-rules`) under `packages/`
9+
- [x] Clone in the runtime hook under `apps/hook/`
10+
- [x] Drop CLAUDE.md and this ROADMAP for the next picker
11+
- [x] `git init` + initial commit (no remote yet — that's Phase 5)
12+
13+
Out of scope for the bootstrap: no workspace wiring, no shared tests, no docs site, no remote, no publish.
14+
15+
## Phase 1 — Workspace wiring (1 session)
16+
17+
Goal: make the four trees install + build + test under one root.
18+
19+
- [ ] Root `package.json` with `workspaces: ["packages/*", "apps/*"]`
20+
- [ ] One root `tsconfig.base.json` extended by each package
21+
- [ ] Each package keeps its own `package.json`, but versions follow the root version
22+
- [ ] `apps/hook` swaps its `@mcptoolshop/ai-loadout` dep for `"@memory-os/kernel": "workspace:*"`
23+
- [ ] `npm ci` at the root produces a working install; `npm run build --workspaces` builds all four
24+
- [ ] Each package's existing test suite still runs (`npm test --workspaces`)
25+
26+
Gate: green build at root, all existing tests pass, hook still injects when invoked with stdin JSON.
27+
28+
## Phase 2 — Unified CLI surface (1–2 sessions)
29+
30+
Goal: one `memory-os` binary that wraps the three CLI surfaces.
31+
32+
- [ ] New `packages/cli/` with `bin: { "memory-os": "..." }`
33+
- [ ] Subcommands:
34+
- `memory-os memories <index|validate|stats|health>` — wraps `packages/memories/`
35+
- `memory-os rules <analyze|split|validate|stats>` — wraps `packages/rules/`
36+
- `memory-os resolve|explain|usage|dead|overlaps|budget|validate` — wraps `packages/kernel/`
37+
- `memory-os hook test` — drives `apps/hook` with a sample prompt
38+
- [ ] Old binaries (`claude-memories`, `claude-rules`, `ai-loadout`) get thin shim binaries that delegate + emit a deprecation warning for one minor release
39+
- [ ] `--help` is complete and accurate (Hard Gate C of shipcheck)
40+
41+
Gate: shipcheck `init` + `audit` runs cleanly on the new CLI; hard gates A–D green.
42+
43+
## Phase 3 — Docs + landing (1 session)
44+
45+
Goal: one Starlight handbook + one landing page covers the whole layer.
46+
47+
- [ ] `site/` at the root, Astro + Starlight (use the `handbook` skill)
48+
- [ ] Sections: Kernel, Memories, Rules, Runtime hook, Migration from the three legacy packages
49+
- [ ] Single landing page replaces the three separate `mcp-tool-shop-org.github.io/{ai-loadout,claude-memories,claude-rules}/` pages
50+
- [ ] CNAME + GitHub Pages wiring (Phase 5 dependency — actual deploy after publish)
51+
52+
## Phase 4 — npm + GitHub bootstrap (1 session)
53+
54+
Goal: reserve the name on npm, set up Trusted Publishing, create the GitHub repo.
55+
56+
- [ ] Reserve `@mcptoolshop/memory-os` via the `npm-placeholder` skill (v0.0.0 placeholder + OIDC config)
57+
- [ ] Create `mcp-tool-shop-org/memory-os` on GitHub (private at first; flip to public at Phase 5 publish)
58+
- [ ] Add remote, push the initial bootstrap commit + Phases 1–3 commits
59+
- [ ] CI workflow: lint + test on push (per workflow-standards.md — paths-gated, ubuntu-latest, concurrency block)
60+
61+
## Phase 5 — First real publish + upstream retirement (1 session)
62+
63+
Goal: ship `@mcptoolshop/memory-os@1.0.0`, retire the three upstream repos.
64+
65+
- [ ] Shipcheck full audit (`memory/shipcheck.md`)
66+
- [ ] Run translations BEFORE publish (per the release-ordering rule in global CLAUDE.md)
67+
- [ ] `npm publish` via Trusted Publishing
68+
- [ ] `gh release create v1.0.0`
69+
- [ ] Cut over `~/.claude/settings.json` hook command from `node ~/.claude/loadout-hook/loadout-hook.mjs` to `npx @mcptoolshop/memory-os hook` (or equivalent)
70+
- [ ] Deprecate the three upstream npm names (only `ai-loadout` is published; npm-deprecate that one with a pointer to memory-os)
71+
- [ ] Archive the three upstream local repos at `E:/AI/{ai-loadout,claude-memories,claude-rules}/` — move to `E:/DEEP_MEMORY/retired/` with a README explaining where they went
72+
- [ ] Delete `~/.claude/loadout-hook/` once the npx-based hook is verified working
73+
74+
Gate: shipcheck 31/31, CI green, hook works through `npx @mcptoolshop/memory-os hook`, no broken pointer chains anywhere in the studio.
75+
76+
## Out of scope (for now)
77+
78+
- Replacing the kernel's matching algorithm with embeddings — separate research project; possibly a `memory-os/research/` tree later
79+
- Multi-rig sync of `~/.ai-loadout/index.json` — out of scope until there's a second rig
80+
- Web UI for browsing the dispatch table — nice-to-have, not in the critical path
81+
82+
## Open questions (for the director)
83+
84+
- Naming: keep `memory-os` or rebrand at Phase 4? (Sister names in the studio: Game Foundry OS, Research OS, Testing OS — pattern is consistent.)
85+
- Should the kernel CLI surface (`ai-loadout resolve`, etc.) be preserved verbatim under `memory-os resolve`, or restructured? Verbatim = lower migration cost; restructured = chance to fix any ergonomics warts.
86+
- License — three sources are all MIT, root stays MIT?
87+
88+
## When this is done
89+
90+
When all five phases pass, this file is the source-of-truth for "what shipped"; flip it to a CHANGELOG-style retrospective and start the next iteration.

apps/hook/loadout-hook.mjs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#!/usr/bin/env node
2+
// UserPromptSubmit hook — inject pointers (not payloads) to relevant memory entries.
3+
//
4+
// Design (FIXED — see kickoff 2026-06-10):
5+
// • Read ~/.ai-loadout/index.json (refreshed by the freshness ritual in CLAUDE.md)
6+
// • matchLoadout(prompt, index) against it
7+
// • Emit AT MOST 5 entries as one-line pointers: "- <id> — <summary> → <path>"
8+
// • Total additionalContext kept ≤ ~200 tokens
9+
// • Below-threshold match emit nothing (silent)
10+
// • Always-record loaded events to ~/.ai-loadout/usage.jsonl
11+
//
12+
// Off-switch: AI_LOADOUT_HOOK=off no-op exit 0.
13+
// Latency budget: < 500 ms cold. Never blocks.
14+
15+
import { readFileSync, appendFileSync, existsSync, mkdirSync } from 'node:fs';
16+
import { dirname, resolve } from 'node:path';
17+
import { homedir } from 'node:os';
18+
19+
if (process.env.AI_LOADOUT_HOOK === 'off') {
20+
process.exit(0);
21+
}
22+
23+
const HOME = homedir();
24+
const INDEX_PATH = resolve(HOME, '.ai-loadout', 'index.json');
25+
const USAGE_PATH = resolve(HOME, '.ai-loadout', 'usage.jsonl');
26+
const MAX_ENTRIES = 5;
27+
const MAX_LINE_CHARS = 180;
28+
29+
function readStdinSync() {
30+
try {
31+
return readFileSync(0, 'utf8');
32+
} catch {
33+
return '';
34+
}
35+
}
36+
37+
function safeExit(code) {
38+
try { process.exit(code); } catch { /* ignore */ }
39+
}
40+
41+
function clip(s, n) {
42+
if (!s) return '';
43+
s = String(s);
44+
if (s.length <= n) return s;
45+
return s.slice(0, n - 1).trimEnd() + '…';
46+
}
47+
48+
async function main() {
49+
if (!existsSync(INDEX_PATH)) { safeExit(0); return; }
50+
51+
const stdin = readStdinSync();
52+
let payload;
53+
try { payload = JSON.parse(stdin); } catch { safeExit(0); return; }
54+
const prompt = (payload.prompt || payload.user_prompt || payload.message || '').toString();
55+
if (!prompt.trim()) { safeExit(0); return; }
56+
57+
let index;
58+
try { index = JSON.parse(readFileSync(INDEX_PATH, 'utf8')); } catch { safeExit(0); return; }
59+
60+
let matchLoadout;
61+
try {
62+
({ matchLoadout } = await import('@mcptoolshop/ai-loadout'));
63+
} catch {
64+
safeExit(0); return;
65+
}
66+
67+
let results;
68+
try { results = matchLoadout(prompt, index); } catch { safeExit(0); return; }
69+
const top = (results || []).filter(r => r && r.entry && r.entry.priority !== 'manual').slice(0, MAX_ENTRIES);
70+
if (top.length === 0) { safeExit(0); return; }
71+
72+
const lines = top.map(r => {
73+
const id = r.entry.id || '(unnamed)';
74+
const sum = r.entry.summary || '';
75+
const pth = r.entry.path || '';
76+
return clip(`- ${id}${sum}${pth}`, MAX_LINE_CHARS);
77+
});
78+
79+
const additionalContext =
80+
'[loadout-hook] Memory entries relevant to this prompt (open the file pointer before acting, do not paraphrase from the summary):\n' +
81+
lines.join('\n');
82+
83+
// Record usage (best-effort; never block)
84+
try {
85+
if (!existsSync(dirname(USAGE_PATH))) mkdirSync(dirname(USAGE_PATH), { recursive: true });
86+
const ts = new Date().toISOString();
87+
const taskHash = (payload.prompt_id || payload.session_id || '').toString().slice(0, 12) || ts.replace(/[-:.TZ]/g, '').slice(0, 14);
88+
const events = top.map(r => JSON.stringify({
89+
timestamp: ts,
90+
taskHash,
91+
entryId: r.entry.id,
92+
trigger: 'UserPromptSubmit',
93+
mode: r.mode || 'lazy',
94+
tokensEst: r.entry.tokens_est || 0
95+
})).join('\n') + '\n';
96+
appendFileSync(USAGE_PATH, events, 'utf8');
97+
} catch { /* swallow */ }
98+
99+
process.stdout.write(JSON.stringify({
100+
suppressOutput: true,
101+
hookSpecificOutput: {
102+
hookEventName: 'UserPromptSubmit',
103+
additionalContext
104+
}
105+
}));
106+
safeExit(0);
107+
}
108+
109+
main().catch(() => safeExit(0));

apps/hook/package.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "loadout-hook",
3+
"version": "1.0.0",
4+
"private": true,
5+
"type": "module",
6+
"description": "UserPromptSubmit hook that injects pointers to relevant memory entries from ~/.ai-loadout/index.json",
7+
"main": "loadout-hook.mjs",
8+
"scripts": {
9+
"test": "node loadout-hook.mjs"
10+
},
11+
"dependencies": {
12+
"@mcptoolshop/ai-loadout": "^1.4.3"
13+
}
14+
}

apps/hook/smoke-test.ps1

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
$ErrorActionPreference = 'Continue'
2+
$hook = 'C:/Users/mikey/.claude/loadout-hook/loadout-hook.mjs'
3+
4+
$prompts = @(
5+
@{ label = '1. GAME prompt (Star Freight visual canon)';
6+
payload = @{ prompt = 'I want to update the Star Freight visual canon — the Renna identity packet needs a new portrait variant. Open the right canon paths and the workflow profile.' } },
7+
@{ label = '2. TOOL prompt (shipcheck a repo before publish)';
8+
payload = @{ prompt = 'Run shipcheck audit on the role-os repo before npm publish — full treatment afterwards if it passes.' } },
9+
@{ label = '3. GENERIC prompt (mundane filesystem)';
10+
payload = @{ prompt = 'list the files in the current directory' } }
11+
)
12+
13+
foreach ($p in $prompts) {
14+
Write-Output ('=' * 78)
15+
Write-Output $p.label
16+
Write-Output ('=' * 78)
17+
$body = $p.payload | ConvertTo-Json -Compress
18+
$start = [System.Diagnostics.Stopwatch]::StartNew()
19+
$out = $body | & node $hook 2>$null
20+
$start.Stop()
21+
$ms = $start.ElapsedMilliseconds
22+
if (-not $out -or $out.Trim().Length -eq 0) {
23+
Write-Output "(silent — no pointer injection)"
24+
} else {
25+
try {
26+
$parsed = $out | ConvertFrom-Json
27+
$ctx = $parsed.hookSpecificOutput.additionalContext
28+
Write-Output $ctx
29+
} catch {
30+
Write-Output "RAW OUTPUT: $out"
31+
}
32+
}
33+
Write-Output ""
34+
Write-Output ("latency: {0} ms" -f $ms)
35+
Write-Output ""
36+
}

0 commit comments

Comments
 (0)