A template for keeping everything you read, save, and write in one place you can still trust in ten years — and search, and cite, and hand to someone else.
It is the pattern behind the Stimpunks Knowledge System, stripped of anything Stimpunks-specific. Copy it, rename three things, and it is yours.
You do not need all of it. The first step needs no software at all. Stop wherever it stops being useful — most of the value is in step one, and each later step only adds convenience on top of a thing that already worked.
Planning to use an AI to help maintain this? It is already set up for that.
CLAUDE.mdcarries the rules and.claude/skills/holds five narrow tools — add a file, build the index, ask the garden, commit, check readability. Start with docs/working-with-claude.md. The important boundary is there too: the machine writes the index, never the sources, and never answers for them.
From The Stimpunks Knowledge System as Curriculum:
- One folder. Everything they read, save, or write goes in it, untouched.
- One index file, listing what's in the folder with a line about why each thing is there.
- A habit of adding to both.
That's it. That's a garden. No app, no subscription, no AI.
That is genuinely the whole idea. This repo is that, with the folders already made:
garden/
raw/ Your originals. NEVER edited, renamed, or reorganised. Kept flat.
wiki/ Your index. Points at raw/. Regenerated, not hand-maintained.
notes/ Your live writing. Edit this freely — it is a workspace, not an archive.
inbox/ Undecided things. Should usually be empty.
The one rule that makes it work: never edit anything in raw/. Not to tidy a filename,
not to fix a typo. Every derived thing — every summary, category, and index — lives
somewhere else and points back. That is the difference between provenance you can cite and
a pile you have been quietly rewriting.
Three routes. They differ in one way that matters: whether you end up with a git repository of your own. Step 2 depends on the answer, so pick one and note which.
A — Use this template (recommended). On the repo page, press Use this template → Create a new repository. GitHub makes you a brand-new repository that is yours, with these folders and one clean commit. No fork, no shared history, nothing to detach. Then bring it down:
git clone https://github.com/YOUR-USERNAME/YOUR-REPO.git my-garden
cd my-gardenYou now have a git repository you can actually push to. That last part matters more than it sounds — see the warning under route C.
B — Download the ZIP (no GitHub account needed). On the repo page, press the green Code button → Download ZIP, then unzip it wherever you keep your work. You get the folders and none of the git machinery, which is a perfectly good place to stop. The ZIP does not include any history.
C — Clone ours and detach. If you want our commit history to read later:
git clone https://github.com/Stimpunks/knowledge-garden-starter.git my-garden
cd my-garden
git remote remove origin # it is yours now; stop pointing at usOr throw our history away entirely and start your own from this moment:
rm -rf .git && git init
⚠️ Do not skip the detach step. A fresh clone still points at our repository, which you cannot write to — so your firstgit pushfails with a permissions error. On day one that looks exactly like you broke something, on the command you were most nervous about.git remote remove originprevents it. Route A avoids the problem altogether, which is why it is the recommendation.
Which folder am I in? Routes A and C put the garden at my-garden/garden/. Route B puts
it wherever you unzipped, in a folder named after the repo. Either way, the four folders
above live inside garden/.
You can do step 1 in Finder, in Obsidian, in anything. Put a PDF in
garden/raw/, write a line about why in garden/wiki/README.md, repeat. If you stop
here you already have the thing. Everything below is convenience.
Why write "why this is here"? Because that line is a small act of synthesis, repeated hundreds of times — and it is the exact skill a citation is testing.
Not for collaboration. For mercy: a history means you can always get back, so you stop being afraid to change things.
First, check whether you already have a repository. If you took route A or C above, you do — cloning gave you one. Skip
git init. Rungit statusif you are unsure: anything other than "not a git repository" means you are set.Running
git initagain is not dangerous, just confusing. At the top of your project it prints "Reinitialized existing Git repository" and changes nothing. Insidegarden/it makes a second repository nested in the first — your files keep being tracked by the outer one, butgit login there shows a history you do not recognise andgit pushfails saying there is nowhere to push to. Now you have two repositories and no way to tell which one you are talking to. Delete the straygarden/.gitand carry on.
⚠️ Check which folder you are in before you run any of this.git initfollowed bygit add .in the wrong place — your home folder, say — makes a repository out of everything you own and offers up your SSH keys and saved credentials to be committed with it.pwdprints where you are;lsshows whether you can seegarden/anddocs/from here. Of everything in this README, that is the one mistake with real consequences, and one command prevents it.
Route A or C — you already have a repository. From the top of your project:
git add .
git commit -m "My garden, day one"
git pushRoute B (the ZIP) — you have no repository yet. From the top of the folder you unzipped:
git init
git add .
git commit -m "My garden, day one"Either way you now have a record of every version of your thinking. See docs/terminal-week.md for a walk-through written for someone who has not used a terminal before — including what each command actually does, and what to do when it goes wrong.
Our own argument for this is in Teaching change management and revision control: get your shit in git. A commit history is a record of iterations, and a diff is how a human supervises a machine.
Once you have more than a few dozen files, maintaining the index by hand stops being fun.
garden/wiki/_generate.py walks raw/ and writes the index for you: a README plus one page
per shelf, every entry linking to the real file.
Edit garden/wiki/_config.json first — it is the only file you need to change. Set your
garden's name, and replace the three placeholder categories with your own shelves. Then:
cd garden
python3 wiki/_generate.py --no-conceptsRe-run it any time; it is safe and it overwrites. Anything whose filename matches no keyword lands in Unidentified, which is not a bug — it is your to-do list for the files whose names say nothing about what they are.
The index is disposable, the sources are not. If the generated index is wrong, change the config and re-run. Never hand-edit the generated pages: your edits get overwritten, which is worse than being refused.
A library you cannot search is half a library — and filenames are a terrible index of meaning. qmd is a local search engine for folders of Markdown: keyword search, meaning-based search, and a reranker, all running on your own machine with no vendor and no network.
npm install -g @tobilu/qmd
cd garden
qmd collection add ./notes --name notes
qmd collection add ./wiki --name wiki
qmd embed # first run downloads models; takes a while
qmd query "what did I read about X"The payoff is finding things by what they mean. "Why does being interrupted mid-task hurt so much" finds writing about monotropism without either of you using that word.
Note that qmd reads text. PDFs in raw/ are invisible to it unless you extract their
text first — see docs/searching-pdfs.md for the honest version of
that problem. If you build that cache, it is a third collection:
qmd collection add ./.qmd/library --name library1. qmd embed can finish successfully with work left to do. On a large first run it
stops at an internal batch limit, exits 0, and leaves documents unembedded. Nothing
warns you. Keyword search keeps working, so the failure is invisible: qmd query silently
cannot return hits that exist, and your first real search under-reports.
qmd status | grep -i pending # a "Pending: N" line means embedding is incompleteRe-run qmd embed until that line is gone. Exit code is not the completion signal
here; the pending count is. Until it reaches zero, treat every "I found nothing" as
"I found nothing yet."
2. Rebuild in order, or you get a confidently wrong index. The three steps feed each other, and none of them errors when run out of order:
pdftotext … # 1. extract text from new PDFs (Step 4, above)
python3 wiki/_generate.py --no-concepts # 2. rebuild the index over what is now readable
qmd update && qmd embed # 3. re-index and embed — last, alwaysEmbed before you extract and the new PDFs are absent. Embed before you regenerate and the index qmd searches is the old one. Both look like success.
3. A search hit is a pointer, not a citation. Two upstream behaviours to know about, both real in qmd 2.5.3:
qmd getfuzzy-matches on the file's base name and can hand back a different file than the one you asked for. Address hits by the#docidshown in the search result, and confirm you opened the file you meant.qmd://URIs are slugified, not filesystem paths — dots and spaces get rewritten, so you cannotcatone. Usegrep/lswhen you need the real path. (--full-pathis ignored onsearchandqueryin this version.)
If you cite the extracted copy instead of the original, you have cited a cache. Cite the
file in raw/.
The Stimpunks system has a layer that indexes ideas rather than files: one page per concept, gathering everything the whole garden holds about it. It works because it keys on a published glossary of 445 terms that already existed.
This is the one part of the pattern that does not travel on its own. If you do not have a controlled vocabulary, there is nothing for it to key on, and inventing one with a machine is how you end up with a taxonomy nobody believes. It is deliberately left out of this template. If you want it, that is a conversation, not a download.
It is not an app, a product, or a thing that requires a subscription. It is folders, a Python script, and a rule about not editing your own sources.
It also will not create capacity. It stops you wasting the capacity you have on finding things you already had.
CC0 1.0 — public domain. No attribution required, no conditions, no strings. Take it. Rename it. Sell it. Never mention us. You do not need permission and you do not owe us a line in your README.
That is a deliberate departure from everything else we publish, which is CC BY-SA — copyleft, chosen on purpose. A template is the one place that choice backfires. ShareAlike here would follow you into your own garden: your rules file, your categories, your notes. Nobody's private thinking should inherit a license from the empty folders it started in.
The Python is also available under MIT-0, which is MIT with the attribution clause removed. Use whichever you like. CC0 does not waive patent rights, so some organisations refuse CC0-licensed code outright — MIT-0 is there so that policy is never the reason you have to walk away.
The source-plus-index pattern comes from Andrej Karpathy's llm-wiki. Search is tobi/qmd. The access argument, and the insistence that originals are never edited because we get cited, is ours — Stimpunks Foundation.
Steal all of it.