AIOS: An AI Operating System in Plain Markdown
I open-sourced the AI operating system I run daily: a git-versioned markdown vault, cross-repo wiring, and a nightly ingest loop. Fifteen minutes to set up.
TL;DR: I open-sourced the vault I actually run — AIOS, MIT-licensed, plain markdown and shell scripts, no database, no lock-in. Clone it, run
/aios-bootstrap, answer questions for ten minutes, and you have a vault your coding agent reads at the start of every session and writes back to at the end. Wire a repo to it with one command and the loop closes: code → digest → nightly ingest → brain → next session starts smarter than the last one. It works with Claude Code today because that’s what I use; the canonical behavior is markdown, so swapping the tool later doesn’t cost you the vault.
Why I open-sourced it
I’ve written the theory here before. Building an AI memory that outlives any single agent made the portability argument: your accumulated context is worthless the day you switch tools if it only lives in one vendor’s chat history or config format. Build an LLM wiki your coding agent actually reads laid out the architecture — three layers (immutable sources, model-written synthesis, a read-first index), three operations (ingest, query, lint), two rules that stop it rotting. Both posts describe a shape. Neither one hands you the thing.
AIOS is the thing. It’s the actual vault I run across every repo I touch, templated so you can clone it and have your own running in about fifteen minutes.
The design bet underneath it is an inversion of how most people think
about agent memory. The usual fixes — a bigger context window, a vector
store, a CLAUDE.md that grows until nobody reads it — all
treat memory as a retrieval problem: throw everything in,
search it at query time. AIOS treats it as an editorial
problem instead. Sessions produce raw signal — commits, diffs,
decisions. A periodic ingest pass compounds that signal into durable,
hand-shaped project notes. A read-first index — the Knowledge Map —
points at them, one line each, cheap enough to load whole.
Why that editorial pass beats a bigger context window or a vector store is the whole case the wiki post makes — AIOS is that architecture shipped, not re-argued here.
Setup: clone it, re-init git, and let it interview you
The whole quickstart:
git clone https://github.com/sublimecoder/aios ~/code/aios
cd ~/code/aios
rm -rf .git && git init # fresh history — see below
claudeThe rm -rf .git && git init step isn’t cosmetic.
You’re about to fill this repo with identity files, project history, and
decisions you made under deadline pressure — the exact things you don’t
want sitting in a public template’s commit graph, discoverable by anyone
who forks upstream before you scrub it. Re-initializing gives you a
clean history from commit one, and git history is forever in the
direction that matters: a later fix can’t un-share something an earlier
commit exposed. If any part of what you put in this vault is private,
the repo needs to be private too — that’s a decision to make before the
first commit, not after.
Once you’re in a Claude Code session inside the fresh clone, run:
/aios-bootstrap
That command just reads BOOTSTRAP.md and executes it as
a prompt — the whole bootstrap process is itself a markdown file, which
is the pattern repeating at the meta level. It interviews you for about
ten minutes, mostly you answering questions, and writes the vault around
your actual answers instead of plausible-sounding defaults. A few things
it’s strict about:
- Interview first, write second. It won’t create a file until it has real answers, asked in small batches instead of one long form.
- Never invents biography. If it doesn’t know something about you, it asks. An identity file full of plausible-but-wrong facts is worse than an empty one.
- Default to less. One scope, no wall, no optional subsystems, unless your answers actually demand more.
The first real question is about scopes — a scope is a bucket of context: a job, a side project, a client. Its whole job is routing, keeping one project’s accumulated memory out of an unrelated one and telling the agent which identity file governs the current session. And here’s the honest part most tools with this feature won’t tell you: one scope is the right answer for most people. The bootstrap won’t talk you into more. If you hesitate when it asks how many contexts you need, the correct answer is one — adding a second scope later is a two-line edit to a TSV file, not a redesign.
Wiring repos: the loop that makes it compound
A vault that only holds what you type into it by hand is just notes. The part that makes AIOS actually compound is wiring your code repos into it, so sessions feed the vault automatically:
scripts/aios-wire-repo.sh ~/code/acme-api work
scripts/aios-install-nightly.sh # drain queue at 03:00The loop it closes looks like this:
code session in any repo
│
│ SessionStart → aios-context.sh
│ loads the project's brain into the session
▼
you work
│
│ Stop → aios-digest.sh
│ queues a signal-only digest in the vault
│ (branch, commits, diff-stat)
▼
/aios-ingest (nightly, or by hand)
│
│ synthesizes the queue into durable facts
▼
AIOS/Projects/<scope>/<project>.md + Knowledge Map
│
└────► next session starts here, knowing more
aios-wire-repo.sh does exactly three things, all
idempotent, all scoped to the vault and the one repo you point it
at:
- Adds a row to
AIOS/Systems/repo-layers.tsv— the manifest. - Merges two hooks into that repo’s
.claude/settings.json:SessionStart→aios-context.sh,Stop→aios-digest.sh. - Drops a git-ignored
CLAUDE.local.mdin the repo, naming the scope and pointing back at the vault. That file is a durable pointer for the contexts the hook doesn’t reach — subagents,claude -pruns, other editors — and it deliberately doesn’t duplicate the brain content the hook already injects.
Both hooks write only to the vault, never to the invoking repo. And the manifest is never guessed: a repo you haven’t wired is a silent no-op — no context loaded, no digest written. That’s a deliberate design choice over the alternative, which is a tool that infers your scope from directory names and occasionally infers wrong in a way you don’t notice until a client’s context leaks into a portfolio project.
You can verify any of it without touching a real session:
scripts/aios-wire-repo.sh --check ~/code/acme-apiThis is where CLAUDE.local.md matters beyond the pointer
function — it’s the piece I already wrote about as the onboarding doc your agent
reads first. Claude Code loads memory files in
order and concatenates them: policy, then your global
~/.claude/CLAUDE.md, then the repo’s own
CLAUDE.md, then CLAUDE.local.md last. Local
instructions ride alongside the repo’s committed rules instead of
overriding them, which is exactly the property you want — the repo’s own
onboarding doc stays authoritative, and the vault pointer just tells the
agent where the rest of what it knows lives.
The nightly ingest: unattended, and scoped so it can’t leak anything
Digests pile up in a queue and do nothing until they’re ingested. Schedule that once — launchd on macOS, cron everywhere else, 03:00 local by default:
scripts/aios-install-nightly.sh # 03:00 local
scripts/aios-install-nightly.sh --status
scripts/aios-install-nightly.sh --dry-runWhat actually runs, unattended, every night:
claude -p "/aios-ingest", but with a scoped tool allowlist
instead of --dangerously-skip-permissions:
--allowedTools \
"Read,Write,Edit,Grep,Glob,Bash,Task,TodoWrite"
That’s the detail I’d flag if you read nothing else in this section. Network and browser tools are denied by omission, so an agent running unattended, on a cron job, at 3am, with nobody watching, has no exfiltration surface even if something in the queue tried to make it do something it shouldn’t. It commits the vault when it’s done. It never pushes.
There’s also a fail-closed guard I’d want in any tool that’s writing
scheduled jobs to my machine: the launchd label and the crontab line are
global to the machine, not per-vault. If you already have a nightly
ingest running for a different AIOS vault, installing a second one would
silently disable the first — so the installer refuses instead, and tells
you what’s already scheduled. You have to override it on purpose
(AIOS_FORCE=1), not by accident.
Nightly, /aios-ingest fans out one subagent per queued
digest so a backlog stays cheap, and compounds everything into
AIOS/Projects/<scope>/<project>.md plus the
Knowledge Map. A clean vault with nothing queued logs
queue empty, skipping and exits 0 — that’s a pass, not a
failure. The job is a no-op exactly as often as it should be.
What a week of actually using it looks like
Day to day, there are three commands, and I use them in this order of frequency:
/aios-log <fact>, mid-session,
whenever I learn something I’d otherwise re-learn in three weeks. “The
Postgres pool caps at 20; raising it starves pgbouncer” — that kind of
thing. It auto-detects scope and project from the working directory,
appends a dated line to the vault’s log, updates the identity file if
the fact is durable, and commits. It never touches the repo I’m working
in.
Nothing, most nights, because the nightly job is already draining the queue I didn’t manually log. This is the actual point of the whole system. The discipline that scales is the one that doesn’t require me to remember to do it.
/wiki-lint, roughly weekly. A health
check over the vault: schema drift, stale notes, orphaned pages nothing
links to, contradictions between two synthesis notes. It proposes; it
never edits on its own. I read the report and decide what to fix.
Across a week, the effect is that Monday’s session starts already knowing what Friday’s session figured out — the port conflict I fought with, the flaky test I diagnosed, the decision I made about which retry strategy to use and why I rejected the other one. That’s the entire pitch of the wiki architecture post made concrete: direct-load, graph-traverse, then RAG the tail, except now it’s a script you run once instead of a pattern you have to rebuild by hand in every project.
The optional wall (most people should skip this)
Some people need more than routing between scopes — two contexts that can genuinely never appear in the same file. A pen name that can’t be tied to a legal name. Employer code that can’t reach a public portfolio. One client’s internals that can’t surface in another client’s repo.
For that, the scope manifest has a tokens column. Fill
it in with the identifying strings for a scope — names, domains,
codenames — and two mechanisms activate: a write-time hook that blocks a
save if it drops one scope’s tokens into another scope’s folder, and a
subagent that runs at publish time to catch the crossings a plain grep
can’t, like a codename plus a URL that are only identifying
together.
Leave tokens as -, which is the default,
and both stay inert. I’d guess most people reading this should leave it
that way. The bootstrap won’t even ask unless you named two or more
scopes in the first question, and it says so plainly when you skip it:
wall left off, turn it on later by filling in one column.
Verify it before you trust it
Every moving part in AIOS ships with a self-check, and none of them touch a real vault, a real LaunchAgent, or a real crontab entry:
bash .claude/hooks/test_vault_write_guard.sh # 21 passed
bash scripts/test_aios_wire_repo.sh # 25 passed
bash scripts/test_aios_install_nightly.sh # 15 passedFor the end-to-end loop specifically — confirming a real repo
actually feeds a real vault — the sequence is: wire a repo, work a
session in it, exit, and check that a digest landed in the queue; then
run the nightly job once by hand (--dry-run) and confirm
the vault’s git log picked up a new commit. If the digest never shows
up, the Stop hook didn’t fire or the repo isn’t in the
manifest, and --check will tell you which.
Try it, break it, tell me what’s wrong with it
Everything above is markdown and shell scripts, MIT-licensed, at github.com/sublimecoder/aios. Clone it, run the bootstrap, wire in whatever you’re working on this week. If something’s confusing, undocumented, or just wrong, open an issue — I’m running this vault myself daily, so a bad edge case in the wiring script or a gap in the bootstrap interview is something I’ll hit too, not just you.
If you’re standing up something like this across a team rather than for yourself — deciding where the scope boundaries actually need to be, or where the line is between a real productivity investment and tool sprawl — that’s the kind of thing I help AI startups think through in fractional engineering leadership engagements.