Leaven installs a memory vault, Claude Code hooks, skills, and one agent (researcher)
into ~/.claude; the optional workflow part adds four more agents. It runs on macOS,
WSL, and Linux. For the step-by-step versions see Windows and
Mac; how it works is the tour.
Quick start
Install the prerequisites first. The repository is private, so log in
before cloning, and the owner must have invited you; "repository not found" means no
access or the wrong gh account (gh auth status).
gh auth login && gh auth setup-git
gh repo clone akproductons/leaven ~/leaven -- --branch "$(gh release view -R akproductons/leaven --json tagName -q .tagName)" -c advice.detachedHead=false
cd ~/leavenThen run one of these:
./install.shThe full-screen installer: pick a preset, tick parts, choose the vault and GitHub backup.
It needs a terminal and gh logged in.
./install.sh --preset engineerplaywright and workflow; the zsh, tools, and terminal parts are not installed. One
catch: playwright needs npx, and install.sh runs without your interactive shell setup.
If npx is not on its PATH (common when nvm, fnm, or asdf load lazily in .zshrc)
and claude is installed, it adds the mise part, which installs node, python, rust, and
more, and on Linux uses sudo to install compiler packages. Have npx on the PATH when
you run it, or run ./install.sh --parts workflow to skip playwright.
./install.sh --parts none --job-searchThe vault, hooks, and skills, plus the job-search workspace; no terminal parts.
With GitHub on, the flag commands back up to a private memory repo, and a private
job-search repo when job search is installed. Add --no-github to a flag command to skip
the login and both repos; commits then need git config --global user.name and
user.email set first. ./install.sh takes no flags: any flag skips the screens, so
./install.sh --no-github installs only the core. On the screens, turn backup off on the
"Where your notes go" screen instead.
./install.sh --preset engineer --no-githubTo move to a newer release later, see Updating.
Prerequisites
install.sh needs git and jq, and gh when GitHub backup is on. The installer
screens are downloaded with gh, so opening them for the first time needs gh logged in,
whichever choice you then make on them. Later runs use the cached copy, after checking its
checksum, without gh. Runs with flags never need that download. Without a usable copy
and gh, ./install.sh prints the flags to use instead.
Install Claude Code first, or the plugin step is
skipped and prints the /plugin commands to run later, and playwright is skipped too:
curl -fsSL https://claude.ai/install.sh | bashAdd ~/.local/bin to your PATH if claude is not found afterwards. Anthropic's
requirements list names
Ubuntu, Debian, and Alpine; it documents a dnf repository for Fedora and RHEL, and says
nothing about Arch. The installer supports Fedora and Arch anyway.
Install git, gh, and jq with your package manager; run only the block for your system.
macOS (Homebrew):
brew install git gh jqDebian and Ubuntu (including WSL):
sudo apt install -y git gh jqFedora:
sudo dnf install -y git gh jqArch:
sudo pacman -S --needed git github-cli jqThe installer's own GitHub login passes --git-protocol, so gh must be 2.5.2 or later.
Ubuntu 22.04's packaged gh (2.4.0) is too old; on an older release, install gh from
GitHub's repository instead: install_linux.md.
Install docs: git, GitHub CLI, jq.
The job-search PDF step and playwright need a browser, and the installer does not add
one. On macOS, brew install --cask google-chrome. On Debian and Ubuntu, Google Chrome
from google.com/chrome; under WSL, install it in Ubuntu.
On Fedora, sudo dnf install -y chromium; on Arch, sudo pacman -S --needed chromium.
Obsidian
The installer does not install Obsidian; the obsidian plugin it adds is Claude skills
only, and some of them (obsidian-cli) probably need the app running. The vault's own
skills do not need it. To use the vault in the app, install Obsidian 1.9 or later (on macOS,
brew install --cask obsidian; elsewhere obsidian.md/download;
under WSL, install it on Windows). Then:
- Choose Open folder as vault and pick
~/memory(under WSL, the Windows path the installer prints at the end). - In Settings, Core plugins, turn on Bases and Daily notes.
- In Settings, Daily notes, set the new file location to
Dailyand the date format toYYYY-MM-DD.
Without the app the vault still works as plain Markdown files and Claude reads and writes
it as usual; you lose the live tables (*.base files) and the graph view.
Installer options
When the screens open
./install.sh with no arguments, run in a terminal (stdin and stdout both attached), opens
the full-screen installer: welcome, preset, checklist, vault and GitHub backup, summary.
It only collects choices and prints them as the flags below; install.sh then runs
them, so every choice the screens offer is a flag and the protections apply to all of
them. Cancelling installs nothing (with --update, the clone stays on the new release; see Updating).
Any flag skips the screens, except --update, which opens them only when there is
something to choose (see Updating). With no terminal and no flags, install.sh installs
the core only. If the screens can't run (no gh or login, no network, a
checksum mismatch, an unsupported CPU), install.sh prints the reason and the flags to
use, and changes nothing.
Flags
--preset starter|builder|engineer: the preset's ticks, no screens.starteris "I'm new to the terminal",builderis "I build things",engineeris "I'm an engineer with my own setup" (leaves your shell and terminal alone). Ticks:starteris the six terminal parts,builderis all seven parts,engineerisplaywright,workflow.--parts <list>|none: exactly these parts, comma-separated, no screens. It replaces a preset's ticks when both are given;noneinstalls only the core. The parts:zsh,tools,mise,statusline,playwright,wezterm,workflow.workflowis installed byinstall.shitself, notextras/install.sh.playwrightregisters a server withclaudeand uses your ownnpx; withoutclaudeit is skipped, and with nonpxon the PATHmiseis added and the installer says so. The registration is tied to thatnpxpath, so after you switch node versions runextras/install.sh --parts playwrightagain.--vault <path>: where the vault goes. Default:~/memory; under WSL,Documents/Memoryin the Windows profile, with~/memorylinked to it.--no-github: skip the installer's GitHub login and the backup repos. Commits need a git identity in that case, and a vault with no remote gets a commit-only instruction.--job-search: also create~/job-searchfromjob-search/. Off by default. Once the folder exists, plain reruns keep updating its tracker app. Installsnodeandpopplerthroughbrew,apt,dnf, orpacmanwhen either is missing, after every check that can stop the run; a node older than 18 is reported and left alone. With no terminal and a sudo password needed, or when the install fails, it prints the command to run and carries on.--update: see Updating. It takes no other flag.
--vault, --no-github, and --job-search on their own install only the core (plus job
search) and write no choices. --preset and --parts also save the preset, parts, vault,
backup, and job-search choices, and the parts you have been offered, to
~/.config/leaven/choices for the next run, and install the chosen terminal parts through
extras/install.sh.
What it writes
A second backup made in the same second gets -2 added to its name (-3 for a third), in the
.bak-<stamp> files and in backup-<stamp>/.
- The vault, from
vault/, as a git repo with one commit. With GitHub on, a private<login>/memoryrepo is created and pushed. ~/memory, only when the vault is elsewhere: a symlink to it. The hooks read this path. Without--vault, a~/memorythat holdsBearing.md, itself or through a link, is used as the vault. So is a link to an empty folder and, on macOS and Linux, an empty folder. Anything else stops before login. With--vault, anything at~/memoryother than that vault or a link to it stops before login and is never repointed.~/job-searchand a private<login>/job-searchrepo, with--job-search.~/.claude/hooks/session-bearing.shandmemory-write-zones.sh.~/.claude/skills/{bod,decision-capture,meeting-capture,memory-groom,weekly-review}.~/.claude/agents/researcher.md.~/.claude/settings.json: the pack's keys merged under yours; when that changes the file, the old one is first copied tosettings.json.bak-<stamp>.~/.claude/CLAUDE.md: one section betweenleaven memorymarkers, rewritten each run; when that changes the file, the old one is first copied toCLAUDE.md.bak-<stamp>.- With the
workflowpart:~/.claude/agents/{builder,planner,reviewer,scout}.md,~/.claude/skills/{delegate,headless-review}, the rules in~/.claude/rules/leaven/(git/anddevelopment/), and the standardsheadless-reviewchecks against in~/.claude/leaven/standards/. ~/.config/leaven/installed: the hooks, skills, agents, rules, and standards the pack owns.~/.config/leaven/state/: a copy of what the pack last wrote for each of those, and of each file a terminal part places. The next run compares the installed copy with the saved one; one that differs is backed up first, and one that matches is replaced quietly. An install from before these copies existed has none, so the first run after that backs up anything that differs from the new release.~/.config/leaven/choices: the saved choices, with--presetor--partsor the screens.~/.config/leaven/bin/: the installer screens program, cached after its checksum is checked againsttui/pin; it is checked again before every run.- Files a terminal part places (
~/.config/leaven/shell.zsh,~/.config/starship.toml,~/.claude/statusline.sh,~/.wezterm.lua(in the Windows profile under WSL), the bat config): one you edited, or that was there before the pack, is copied to<file>.bak-<stamp>beside it, not intobackup-<stamp>/. Thezshpart appends onesourceline to~/.zshrcand does not back it up. Thestatuslinepart setsstatusLinein~/.claude/settings.jsonwhen it has none. ~/.config/leaven/backup-<stamp>/: copies of anything replaced on the strength of an earlier install, rather than the manifest, and of any skill, hook, agent, rule, or standard you edited that a run replaced or, for a rule or standard a release dropped, removed.git config --global user.nameanduser.email, each only when that one is unset, from the GitHub account (noreply address).- With GitHub on:
gh auth loginwhen you are not logged in (gh's own config), andgh auth setup-git(a credential helper in the global gitconfig). - Keys in
settings.json:autoMemoryEnabled,autoMemoryDirectory, and thePreToolUseandSessionStarthooks. - Plugins
mattpocock-skillsandobsidian, from the marketplacesanthropics/claude-plugins-officialandkepano/obsidian-skills, throughclaude plugin, which manages its own settings entries. - With an old install:
~/.config/claude-wsl-packmoves to~/.config/leaven, and its~/.zshrcsource line is repointed.
When GitHub is on but there is no terminal
A run with GitHub on, no terminal, and gh logged out cannot log in. It prints that the
backup is skipped this time and carries on, and the saved github choice stays on. If your
git identity is also unset, it then stops with set your git identity first, because that
identity normally comes from the GitHub account; set user.name and user.email or log in
with gh auth login and rerun. The same stop applies under --no-github.
How Claude finds the vault
autoMemoryEnabledandautoMemoryDirectory(~/memory/Auto Memory) insettings.jsonsend Claude's auto memory into the vault.- The
SessionStarthooksession-bearing.shinjects~/memory/Bearing.mdat the start of each session, plus any note tagged for the current git repo. - The
PreToolUsehookmemory-write-zones.shmakes Claude ask before it edits a curated note;Auto Memory/andDaily/are open. - The
CLAUDE.mdsection names the vault, tells Claude to capture decisions intoAuto Memory/and to commit the vault itself (and push it if it has a remote), and explains how to run an update from this clone.
Both hooks read ~/memory, which is why a vault elsewhere gets a link there.
Your settings win. If your settings.json already sets autoMemoryDirectory to something
else, the installer prints your autoMemoryDirectory is <path>, so Claude's memory capture lands there, outside the vault, and leaves it; sessions still get Bearing.md, but capture
lands outside the vault. The check compares the literal string to ~/memory/Auto Memory,
so the same place written another way, such as an expanded $HOME path, still prints the
warning; it is harmless. It checks no other key that way: a false in your
autoMemoryEnabled goes unreported. A hook file with a pack hook's name that the pack did
not install is skipped with a skipped hook line and that hook is not wired in, so the
injection or the write gate is missing until you rename or remove yours.
What it refuses to touch
- A hook, skill, agent, rule, or standard with the same name that the pack did not install:
skipped with a
skippedline, and the matching hook is not wired intosettings.json. - Your own files in
~/.claude/rules: the workflow rules go in theleaven/subfolder only. A~/.claude/rulesthat links into your dotfiles stays a link. - Any key in your
settings.jsonthat the pack also sets: your value wins at every level. Your hook lists stay as they are; a pack hook is added only when its command is not already there. - Symlinks. A
~/.claude/skills,agents, orhooksthat links into your dotfiles stays a link, and the pack files are written into it. A symlinkedsettings.jsonorCLAUDE.mdstays a link too. - A
~/job-searchthat is not the pack's workspace (no.claude/skills/review-writing/SKILL.mdandtools/check-tells.sh): never updated, committed to, or pushed. - A GitHub repo named
memoryorjob-searchthat a folder without anorigindid not come from: the installer stops before pushing. - A vault that already has files: left as is.
test/ shows the behaviour: install-test.sh for plain, --job-search, --preset,
--parts, and --update runs and the saved choices; dotfiles-test.sh for an engineer's
linked ~/.claude; extras-test.sh for the terminal parts on each platform;
screens-pty-test.py for the installer screens in a real terminal session.
The terminal parts are optional
extras/install.sh holds six parts: zsh (zsh, its plugins, the shell config, starship,
and the default shell), tools (fzf, zoxide, ripgrep, fd, bat, eza, btop, yazi), mise
(node, pnpm, python, uv, rust, and the compiler and headers they need), statusline (the
Claude Code status line), playwright (the Playwright MCP server), and wezterm. It
supports macOS, Ubuntu, Debian, Fedora, and Arch. On Linux and WSL it uses sudo for
system packages, the WezTerm repository, and changing your default shell; as root it runs
them directly. It checks sudo once, before the first package step: in a terminal it asks
for your password then and prints sudo is not installed or sudo did not accept your password on failure; with no terminal it goes on only if sudo needs no password.
Without sudo it installs no system package: if every package is already there it prints system packages already installed; skipped the sudo step, otherwise it stops with new packages need your password: ..., these packages are not installed: ..., or install these packages yourself: ..., and install.sh follows with the terminal parts did not finish. macOS uses Homebrew without sudo.
install.sh runs it for the parts you choose; skipping them leaves your shell and terminal
alone.
Run it directly to install some without going through install.sh:
extras/install.sh
extras/install.sh --parts zsh,tools,mise,statusline,playwright,weztermThe first line, with no --parts, installs all six; name fewer parts to take only those. It writes no choices file. To take
single pieces by hand instead, copy files from extras/ (shell.zsh, starship.toml,
statusline.sh, wezterm.lua) and source what you want.
The engineering workflow is optional
The workflow part (./install.sh --parts workflow, or --preset builder or
--preset engineer; --preset starter leaves it out) adds:
- Agents
builder,planner,reviewer, andscout, next toresearcher.scoutruns onhaiku,builderandrevieweronsonnet, andplanneron the model your session uses, since a pinnedfablecan bill usage credits or be unavailable on some plans. - Skills
delegate(which agent to use for which job) andheadless-review(a multi-reviewer pass over a branch: about a dozenclaude -pcalls per run, so it is for a large change or when you ask; the everyday review is onerevieweragent). It needsjqand reads the standards below. - Rules for git (commits, branches, worktrees, pushing), delegation, testing, and code
style, for code projects. Claude Code loads
~/.claude/rules/recursively. The sevengit/rules plusdelegation,find-the-seams-before-implementing, andquestions-are-not-instructions, about 2,100 tokens, load in every session; the testing, comment, extraction, export, design, docs, and no-internal-references rules carry apathsfilter and load only when Claude reads or edits a matching file. They defer to a project's own conventions. A rerun restores a deleted file and skips one with the same name that you wrote; a release that drops a rule removes it on the next run with the part ticked. - Standards (
code-for-humans,parse-dont-validate,testing,typescript) in~/.claude/leaven/standards/. They are not loaded in sessions;headless-reviewpastes them into its reviewers.
The rules and agent instructions tell Claude not to push or open a pull request unless you
ask; that is instruction, not a lock. The memory vault and ~/job-search keep their own
instructions, which commit there and push if it has a remote. If a folder under ~/.claude cannot be written,
the part's files for it are skipped with a skipped line and the rest of the install goes
on. Unticking the part later stops
updates to these files and removes nothing. extras/install.sh never sees this part.
Browsers
Playwright works on every platform. The Chrome extension is not claimed on native Linux: Anthropic's Chrome docs imply it works but never say so, so use Playwright there. It does not work under WSL.
Claude Desktop
Anthropic ships a Claude Desktop beta for Debian and Ubuntu; see Claude Desktop on Linux. Elsewhere on Linux, use the CLI.
Job search on its own
job-search/ is a copy of the job-search kit. If you want only that, the kit works from
its own README, without this pack.
Updating
cd ~/leaven && ./install.sh --updateIt checks out the newest vX.Y.Z tag, restarts from that checkout's install.sh, and
reinstalls with your saved choices (~/.config/leaven/choices), or with what it finds on
disk when none are saved. It stops and changes nothing when tracked files in the clone have
uncommitted changes. In a terminal it opens the checklist when nothing is saved or a
release adds a part you have not been offered (new parts marked and unticked); otherwise it
runs through without asking. With no terminal it uses the saved ticks and prints a line
naming anything new, with the command that adds it. When the screens can't run and there
is something new to choose, it installs the saved ticks and prints the flags for the new
part. Cancelling the checklist installs nothing but leaves the clone on the new release;
run --update again to be offered the checklist. Unticking a part stops its updates;
nothing is uninstalled.
The clone command above starts the clone on the newest release. A clone on a release sits
on that tag, a detached HEAD with no branch, so git pull does not apply there; use
--update instead, which moves it to a newer release. A clone already on the newest release
stays where it is. ./install.sh prints a line when a clone is on main or another branch
instead. To get back on a branch:
git switch main && git pullA clone whose install.sh predates v0.10.0 has no --update and needs git pull on
main first (on the v0.9.0 tag, git switch main comes first). Versions and what
the numbers mean: releases.