Set up for engineers

v0.10.7

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

Terminal
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 ~/leaven

Then run one of these:

Terminal
./install.sh

The full-screen installer: pick a preset, tick parts, choose the vault and GitHub backup. It needs a terminal and gh logged in.

Terminal
./install.sh --preset engineer

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

Terminal
./install.sh --parts none --job-search

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

Terminal
./install.sh --preset engineer --no-github

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

Terminal
curl -fsSL https://claude.ai/install.sh | bash

Add ~/.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):

Terminal
brew install git gh jq

Debian and Ubuntu (including WSL):

Terminal
sudo apt install -y git gh jq

Fedora:

Terminal
sudo dnf install -y git gh jq

Arch:

Terminal
sudo pacman -S --needed git github-cli jq

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

  1. Choose Open folder as vault and pick ~/memory (under WSL, the Windows path the installer prints at the end).
  2. In Settings, Core plugins, turn on Bases and Daily notes.
  3. In Settings, Daily notes, set the new file location to Daily and the date format to YYYY-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. starter is "I'm new to the terminal", builder is "I build things", engineer is "I'm an engineer with my own setup" (leaves your shell and terminal alone). Ticks: starter is the six terminal parts, builder is all seven parts, engineer is playwright,workflow.
  • --parts <list>|none: exactly these parts, comma-separated, no screens. It replaces a preset's ticks when both are given; none installs only the core. The parts: zsh,tools,mise,statusline,playwright,wezterm,workflow. workflow is installed by install.sh itself, not extras/install.sh. playwright registers a server with claude and uses your own npx; without claude it is skipped, and with no npx on the PATH mise is added and the installer says so. The registration is tied to that npx path, so after you switch node versions run extras/install.sh --parts playwright again.
  • --vault <path>: where the vault goes. Default: ~/memory; under WSL, Documents/Memory in the Windows profile, with ~/memory linked 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-search from job-search/. Off by default. Once the folder exists, plain reruns keep updating its tracker app. Installs node and poppler through brew, apt, dnf, or pacman when 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>/memory repo is created and pushed.
  • ~/memory, only when the vault is elsewhere: a symlink to it. The hooks read this path. Without --vault, a ~/memory that holds Bearing.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 ~/memory other than that vault or a link to it stops before login and is never repointed.
  • ~/job-search and a private <login>/job-search repo, with --job-search.
  • ~/.claude/hooks/session-bearing.sh and memory-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 to settings.json.bak-<stamp>.
  • ~/.claude/CLAUDE.md: one section between leaven memory markers, rewritten each run; when that changes the file, the old one is first copied to CLAUDE.md.bak-<stamp>.
  • With the workflow part: ~/.claude/agents/{builder,planner,reviewer,scout}.md, ~/.claude/skills/{delegate,headless-review}, the rules in ~/.claude/rules/leaven/ (git/ and development/), and the standards headless-review checks 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 --preset or --parts or the screens.
  • ~/.config/leaven/bin/: the installer screens program, cached after its checksum is checked against tui/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 into backup-<stamp>/. The zsh part appends one source line to ~/.zshrc and does not back it up. The statusline part sets statusLine in ~/.claude/settings.json when 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.name and user.email, each only when that one is unset, from the GitHub account (noreply address).
  • With GitHub on: gh auth login when you are not logged in (gh's own config), and gh auth setup-git (a credential helper in the global gitconfig).
  • Keys in settings.json: autoMemoryEnabled, autoMemoryDirectory, and the PreToolUse and SessionStart hooks.
  • Plugins mattpocock-skills and obsidian, from the marketplaces anthropics/claude-plugins-official and kepano/obsidian-skills, through claude plugin, which manages its own settings entries.
  • With an old install: ~/.config/claude-wsl-pack moves to ~/.config/leaven, and its ~/.zshrc source 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

  • autoMemoryEnabled and autoMemoryDirectory (~/memory/Auto Memory) in settings.json send Claude's auto memory into the vault.
  • The SessionStart hook session-bearing.sh injects ~/memory/Bearing.md at the start of each session, plus any note tagged for the current git repo.
  • The PreToolUse hook memory-write-zones.sh makes Claude ask before it edits a curated note; Auto Memory/ and Daily/ are open.
  • The CLAUDE.md section names the vault, tells Claude to capture decisions into Auto 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 skipped line, and the matching hook is not wired into settings.json.
  • Your own files in ~/.claude/rules: the workflow rules go in the leaven/ subfolder only. A ~/.claude/rules that links into your dotfiles stays a link.
  • Any key in your settings.json that 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, or hooks that links into your dotfiles stays a link, and the pack files are written into it. A symlinked settings.json or CLAUDE.md stays a link too.
  • A ~/job-search that is not the pack's workspace (no .claude/skills/review-writing/SKILL.md and tools/check-tells.sh): never updated, committed to, or pushed.
  • A GitHub repo named memory or job-search that a folder without an origin did 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:

Terminal
extras/install.sh
extras/install.sh --parts zsh,tools,mise,statusline,playwright,wezterm

The 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, and scout, next to researcher. scout runs on haiku, builder and reviewer on sonnet, and planner on the model your session uses, since a pinned fable can bill usage credits or be unavailable on some plans.
  • Skills delegate (which agent to use for which job) and headless-review (a multi-reviewer pass over a branch: about a dozen claude -p calls per run, so it is for a large change or when you ask; the everyday review is one reviewer agent). It needs jq and 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 seven git/ rules plus delegation, find-the-seams-before-implementing, and questions-are-not-instructions, about 2,100 tokens, load in every session; the testing, comment, extraction, export, design, docs, and no-internal-references rules carry a paths filter 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-review pastes 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

Terminal
cd ~/leaven && ./install.sh --update

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

Terminal
git switch main && git pull

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