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
claude

The 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:00

The 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:

  1. Adds a row to AIOS/Systems/repo-layers.tsv — the manifest.
  2. Merges two hooks into that repo’s .claude/settings.json: SessionStartaios-context.sh, Stopaios-digest.sh.
  3. Drops a git-ignored CLAUDE.local.md in 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 -p runs, 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-api

This 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-run

What 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 passed

For 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.