AI decision logging for development projects — branch-aware by default.
Codebases lose the why behind their code faster than the what. logmind captures architectural and implementation decisions as you make them, attaches them to the relevant git branch, and surfaces them to the next human or AI that works in the repo. One CLI command per decision; the package handles the docs, the branch routing, and the merge-time aggregation.
Key concept: Install once, init anywhere, log everything. Feature
branches get their own decision file; on PR merge a GitHub Action appends
a one-line summary to docs/decisions.md linking the PR + the branch
detail. docs/timeline.md is the main-canonical, source-derived union of
every decision file in the repo — the one start-here doc for a cold agent.
AGENTS.md is the canonical agent-instruction file; per-tool files
(CLAUDE.md, .cursorrules, ...) are 2-line stubs pointing to it.
logmind log is the commit primitive, not a wrapper around one. A
commit-msg hook plus a Claude Code PreToolUse hook (both installed by
logmind init / refreshed by logmind doctor --fix) block a substantive
raw git commit and steer you back to logmind log — escape hatches are
[skip-logmind], LOGMIND_ALLOW_GIT_COMMIT=1, and git.enforce_commits: false. After every log, stderr may carry an advisory pulse — a stale
component or a spec that's drifted 20+ decisions behind — worth a
logmind doctor --fix or a look at the project's spec file
(context.spec_file, scaffolded via logmind init --spec).
# Homebrew (recommended on macOS + Linux)
brew install thrillmade/tap/logmind
# Or — curl one-liner (auto-fetches the latest release)
curl -fsSL https://logmind.dev/install.sh | bash
# Pin to a specific version on either path:
LOGMIND_VERSION=v2.0.0 curl -fsSL https://logmind.dev/install.sh | bashVerify the install:
logmind --version # logmind 2.0.0 (spec 1.5.0)The curl installer is idempotent — re-running it when the same version
is already installed is a fast no-op, so you can drop it into a
shell-rc or laptop bootstrap script without worrying about churn. It
also auto-detects GITHUB_ACTIONS=true and nudges you toward the
dedicated CI install path described next.
Use the thrillmade/setup-logmind
action. It handles platform detection, version pinning, and step
caching:
- uses: thrillmade/setup-logmind@v1
with:
token: ${{ github.token }}
- run: logmind check-linksThe token: ${{ github.token }} line matters: composite actions can't
default an input to github.token, so without it setup-logmind's
release-lookup call is anonymous — shared GitHub-hosted-runner IP
ranges routinely exhaust the unauthenticated api.github.com rate
limit and 403 before logmind installs. Pass it explicitly.
logmind init (v1.1.0+) installs a .github/dependabot.yml block that
tells Dependabot to bump the action ref on every new logmind release.
You pin once, and the ecosystem keeps you current — no manual sweeps,
no pip install logmind==... lines, no curl-install inside CI.
Both paths deliver signed + notarized binaries from the
GitHub Releases page —
no Python toolchain, no pyenv shim version skew, no pip cache surprises.
See docs/install.md for the full install matrix
(go install for builds-from-source, manual binary download, checksum
verification, and the legacy Python path).
Heads up on
pip install logmind— the Python wheel is frozen at v0.6.16 as the last published Python release. New installs should use the Go binary above. The PyPI package is kept on PyPI only to honour old pinning; it receives no further updates. The legacy install section at the bottom has the details for users migrating off it.
docs/timeline.md and docs/file-structure.md are purely derived —
under derived_docs: {mode: integration-point} in .logmind/config.yml, a
branch never edits them; they regenerate only on main. This is opt-in:
mode defaults to "driver", which reproduces the pre-v2.0.0 behavior
(derived docs regenerate on every branch, nothing restores or blocks
anything) — set mode: integration-point to turn the invariant on. Once
adopted, it's enforced in layers, each closing a gap the previous one can't
reach:
- L0 — the
post-merge/post-rewritegit hooks regenerate on the default branch only; a feature branch is never touched. (In driver mode they regenerate on every branch instead.) - L1 —
logmind logrestores both files toHEADbefore staging, on a non-default branch. - L2 (pin-preservation) — catches a raw
git committhat L0/L1 can't reach, e.g. afterlogmind warpdeliberately pullsmain's newer copy into your working tree for review. L2a is apre-commitgit hook (pure git, nologmindbinary required, never blocks a commit), installed only in integration-point mode. L2b is the same restore run inside the Claude Code harness's PreToolUse guard, before its allow/block decision — this additionally catchesgit commit --no-verify(which skips every git hook, including L2a) and works in a fresh clone (git hooks aren't cloned;.claude/settings.jsonis). - L3 — the
regen-timeline.ymlGitHub Action'scheck-derived-docsjob first checks whether this repo declared integration-point mode; an unadopted (driver-mode) repo passes with an explanatory message instead of blocking. An adopted repo's PR gate blocks a PR that modified either derived doc, and on every push tomainregenerates both files and commits + pushes them back (needs aLOGMIND_AUTO_REGEN_PATsecret, fine-grained, repo-scoped, Contents: write; without it, the workflow just warns thatmainis momentarily stale — never a conflict risk, only a freshness gap).
Set derived_docs.min_binary (e.g. "2.0.0") alongside mode: integration-point — logmind doctor warns when the running binary is
older than that floor.
L0-L2 are local guardrails, not guarantees — every one is bypassable
(--no-verify, a deleted or disabled hook, hand-editing
.claude/settings.json, or a tool that never goes through git or Claude
Code). L3 (CI) is the only non-bypassable enforcement, since it runs
server-side on every PR regardless of what did or didn't happen locally —
and even it only applies once a repo has adopted integration-point mode.
For the derived files to stay conflict-free across concurrent PRs, the following is recommended (belt-and-suspenders — L0-L3 already make a derived-doc conflict impossible by construction on any single merge):
- Strict required status checks on
main—Settings → Branches → Branch protection rule (or Ruleset)→ "Require branches to be up to date before merging". This forces a PR to be rebased on latestmainbefore merge, which keepsdocs/timeline.md(and any other derived file) conflict-free across concurrent PRs.
Without that toggle, the derived-doc invariant still holds per merge — a
branch's copy is always byte-identical to its own merge-base, so git takes
main's (regenerated) side automatically, and the logmind-timeline merge
driver is belt-and-suspenders for the rare case a branch diverges anyway.
Being up to date mainly helps avoid unrelated conflicts elsewhere (e.g. two
branches editing the same decision file) and keeps history linear.
If you'd rather not click through the GitHub UI, the
clud-bug-logmind variant of
reporulez ships the canonical ruleset for repos using both logmind
and clud-bug — strict status checks pinned to logmind's check names,
required thread resolution, squash-only, the works:
curl -fsSL https://raw.githubusercontent.com/thrillmade/reporulez/main/bin/apply.sh \
| bash -s -- owner/your-repo clud-bug-logmind# After brew/curl install, `logmind` is globally available
# Initialize in your project
cd your-project
logmind init
# OR — install the full SkDD toolchain (logmind + clud-bug):
logmind init && npx clud-bug@latest init
# Log decisions via CLI
logmind log "Use PostgreSQL for database" \
-r "Need ACID compliance" \
-a "MongoDB" -a "SQLite"
# View and search decisions
logmind show
logmind search "postgres"
# One-read agent cold-start context: file-structure + timeline in one go
logmind context
logmind context --stats # token receipt instead of the payload
# Repo signature skeleton (Go + TS/JS, function bodies dropped)
logmind repomap
logmind repomap --map-tokens 4000 # pack to a token budget, ranked by importance
# Health check — version drift, hook drift, missing timeline markers
logmind doctor
logmind doctor --fix
# Set the branch's one-sentence timeline headline
logmind headline "Added JWT session auth with refresh-token rotation"
# Terse, chainable machine output for scripted/agent invocations
LOGMIND_QUIET=1 logmind log "Use PostgreSQL" -r "Need ACID compliance"
# Enforce decision logging with a pre-commit hook
logmind install-hook # installs .git/hooks/pre-commit
logmind check-decisions # run manually or in CI
# Manage AI agents
logmind agents list
logmind agents add windsurf
# Publish a local skill to the public catalog (local → catalog PR)
logmind skill push critical-issues-only # opens PR on thrillmade/agent-skills
logmind skill push my-skill --dry-run # preview without clone/push
logmind skill push my-skill --catalog acme/private-skills
# View and modify configuration
logmind config list
logmind config get git.auto_push
logmind config set git.auto_push false
# Upgrade logmind
brew upgrade thrillmade/tap/logmind # or re-run the curl installerSkills are AUTHORED in the consumer repo first (.claude/skills/<name>/SKILL.md),
then optionally promoted to a catalog repo via logmind skill push. Four
layered guards keep proprietary skills from leaking into a public catalog:
- Layer 1 — frontmatter markers —
private: trueordo-not-promote: truein the SKILL.md frontmatter blocks the push before any clone happens. - Layer 2 — directory convention — skills placed under
.claude/skills-private/<name>/are private by default (Vault-style). Placement wins over an explicitprivate: falseoverride. - Layer 3 — content scanner — every SKILL.md body is scanned for
credential-shaped tokens (Stripe, Slack, GitHub, npm, AWS, GCP),
internal-process keywords (
confidential,proprietary,nda, …), org-internal domain references (configurable via.logmind/config.yml privacy_scanner.org_domains), and local-machine paths (/Users/<name>/,/home/<name>/). Hits are block-severity (rejects the push) or warn-severity (prints to stderr, continues). Config can WIDEN the deny set but never weaken the hardcoded baseline. - Layer 4 — repo-visibility check — if the source repo is private
(or GHEC "internal") and the catalog target is public, the push is
rejected. Set
allow_promote_from_private: truein.logmind/config.ymlto acknowledge cross-visibility promotion. Layers 1-3 still run.
There is no --force flag — these are guard rails, not toggles. See
logmind skill push --help for the full surface.
Working on logmind itself? It's a Go module — clone, build, run.
# Clone the repo
git clone https://github.com/thrillmade/logmind.git
cd logmind
# Build + install the dev binary
go build -o ./bin/logmind ./cmd/logmind
./bin/logmind --version
# Run tests
go test ./...See CONTRIBUTING.md for the full dev loop (lint, snapshot tests, release workflow).
- Install - Full install matrix (brew, curl, go install, manual, legacy Python)
- Plan & Architecture - Vision, approach, and technical details
- AI Agent Files - How logmind integrates with AI instruction files
- First Decision Example - What the initial decision looks like
- Install the
logmindbinary (brew / curl) - Init creates
docs/folder, inserts the canonical block intoAGENTS.md(2-line stubs for per-tool files), and installs the commit-msg + Claude Code PreToolUse hooks that block a substantive rawgit commit - Log a decision —
logmind logis the commit: appends the entry, archives old ones (keeps 20 recent), regeneratesdocs/timeline.md(the main-canonical, cross-branch union) anddocs/file-structure.md, commits, and pushes. Stderr may carry a pulse advisory afterward — a stale component or a spec falling behind. - Context —
logmind contextgives an agent the file structure + timeline in one cache-friendly read instead of reconstructing state fromgit log/ls -R/grep;logmind repomapadds the API surface on top
- Simple: Two markdown files (recent + archive), no database
- Focused: Only 20 most recent decisions for relevant AI context
- Git-native: Every decision is a commit, git history is your audit trail
- AI-friendly: Recent decisions + file structure = complete context
- Automatic: Commits and pushes on every log
See docs/plan.md for complete architecture and roadmap.
Deprecated. The Python wheel logmind is frozen at v0.6.16 — the last
published Python release before the v1.0 Go rewrite. New installs should
use the Go binary at the top of this README. The PyPI package stays
listed only so consumer repos that pinned logmind==0.6.x keep
resolving; it receives no further updates, no security backports, and no
feature parity with v1.0+.
If you're already on the Python wheel and want to migrate, swap one line in your install step:
# Before — pinned to v0.6.x Python wheel
pipx install 'logmind==0.6.16' # OR: pip install 'logmind==0.6.16'
# After — Go binary, signed + notarized
brew install thrillmade/tap/logmind
# OR
curl -fsSL https://logmind.dev/install.sh | shSee docs/install.md#deprecated-python-install for the full migration matrix (CI YAML one-liners, dependency-import hand-off, and what features have moved or been retired). The Python v0.6.x release notes are preserved at docs/changelog-python.md for historical reference.
Skills-Driven Development (Zak Elfassi's methodology) gives you the loop; the thrillmade toolchain ships the parts:
- logmind — the why behind every change (decision logging as commit primitive); skill-creation + testing + auditing
- clud-bug — skill-driven PR review at gate time; every finding cites the skill that motivated it
- agent-skills — public catalog of reusable skills
- skills.sh — skill discovery + install
End-to-end agentic auto dev: write skills first → log the why → run them against PRs → iterate based on usage. The tools work independently; better together.