Kluris turns your AI agents into a subject matter expert that never sleeps and never quits.
When your best engineer sleeps, Kluris doesn't. When they leave, Kluris stays.
🎥 New here? Take the guided tour at kluris.ngvoicu.dev.
curl -fsSL https://kluris.ngvoicu.dev/install.sh | sh # macOS, Linux
irm https://kluris.ngvoicu.dev/install.ps1 | iex # Windows PowerShell
What is Kluris?
Kluris gives every AI coding agent on your team the same shared knowledge: architecture, decisions, conventions, learnings. Your agents work like a colleague who knows every project, not a generic assistant starting from scratch in each chat.
The knowledge lives in a brain: a git repository of plain markdown that agents read, search and write. Agent and human curate it together. The agent proposes what to write down; a human reviews and approves every piece.
Kluris itself is one small binary. It creates and maintains brains, searches
them, and installs each brain into your agents as a skill named
kluris-<brain>.
Why it saves tokens
A brain is a summary your agent reads instead of the raw files. Without one, the agent crawls the repository (and every sibling repository it needs) at the start of every chat. With one, it loads a compact snapshot and goes straight to the note it needs.
Without Kluris, an illustrative cold start on a medium repository:
tree + README + CLAUDE.md ~3,000 tokens
grep for related symbols ~2,000 tokens
read 4-8 relevant files ~15,000 tokens
read 2-3 sibling-project files ~8,000 tokens
─────────────
~28,000 tokens just to orient
With Kluris, the same task:
kluris wake-up --json snapshot ~1,200 tokens (brain.md + lobes + recent + glossary)
kluris search "<query>" --json ~400 tokens (ranked hits with snippets)
read 1-2 matching neurons ~1,500 tokens
─────────────
~3,100 tokens, about 9x less spent on orientation
These are rough estimates, not a benchmark; the numbers depend on the repository, the agent and the prompt. The shape holds: a targeted lookup replaces a wide crawl, and the saving grows with every project you touch.
Why not a wiki, Notion or CLAUDE.md?
- Wikis and Notion are written for people. Agents can't search across them or write back. A brain is markdown in git, made for agents and readable by people.
- CLAUDE.md belongs to one project and one tool. A brain sits above all your projects and works with every agent on the team.
- Agent memory is controlled by the agent. A brain is curated by people: you decide what goes in, review every entry and correct what is wrong.
Install
Kluris is a single binary. It needs no administrator rights and nothing else
installed; git is the only other tool it uses.
macOS and Linux:
curl -fsSL https://kluris.ngvoicu.dev/install.sh | sh
Windows (PowerShell):
irm https://kluris.ngvoicu.dev/install.ps1 | iex
The installer puts kluris in ~/.kluris/bin (%USERPROFILE%\.kluris\bin on
Windows) and adds that folder to your PATH: your shell's startup files on
macOS and Linux, your user PATH on Windows. Open a new terminal, then run:
kluris doctor
To install a particular release, set KLURIS_VERSION:
curl -fsSL https://kluris.ngvoicu.dev/install.sh | KLURIS_VERSION=3.1.1 sh
$env:KLURIS_VERSION = '3.1.1'; irm https://kluris.ngvoicu.dev/install.ps1 | iex
Set KLURIS_NO_MODIFY_PATH=1 the same way to leave your PATH and shell files
alone.
Platforms: macOS (Apple Silicon and Intel), Linux x86_64 and arm64 (with static musl builds, which the installer picks when the system's glibc is too old), Windows x86_64 and arm64.
Update
kluris self-update # install the newest release, then run kluris doctor
kluris self-update --check # only show the installed and the newest version
kluris self-update --version 3.1.1
self-update checks the download's SHA-256 before it replaces the binary.
Behind GitHub's rate limit for anonymous requests, set KLURIS_GITHUB_TOKEN
to a GitHub token.
Uninstall
kluris self-uninstall
This stops and removes the sync services (kluris sync --install-service),
then takes out the binary, the PATH setup and the installer's receipt. Your
config, the companion playbooks, the agent skills and every brain stay.
kluris self-uninstall --purge also deletes ~/.kluris and every agent skill
Kluris wrote, after asking (--yes skips the question). Brains are never
touched.
Verify a download
Every archive on the releases page
has a .sha256 file beside it, the release has one sha256.sum, and every
artifact carries a GitHub attestation:
shasum -a 256 -c kluris-aarch64-apple-darwin.tar.gz.sha256 # or sha256sum -c
gh attestation verify kluris-aarch64-apple-darwin.tar.gz --repo ngvoicu/kluris
The install commands above check the archive's SHA-256 for you, on every OS.
Quick start
Kluris lives in two places:
| Where | What you type | What it is |
|---|---|---|
| Your terminal | kluris … |
The CLI: create, register, maintain and inspect brains |
| Your AI agent | /kluris-<brain> … |
The brain's skill: the agent searches, learns and remembers through the CLI |
1. Create a brain, in your terminal:
kluris create # a short wizard: name, description, location, type, git, companions
or non-interactively:
mkdir -p ~/brains
kluris create acme --description "Acme platform knowledge" --path ~/brains
Brain created: acme (product-group)
Path: /Users/you/brains/acme
Lobes: 3
Agent skill installed: kluris-acme
Claude/Codex/Antigravity/etc: /kluris-acme
Hermes: /skill kluris-acme (or start with `hermes -s kluris-acme`)
Created a new Hermes profile later? Run `kluris doctor` to refresh Kluris skills.
Or join your team's brain. A brain is a plain git repository: clone it and register the folder (Kluris uses it in place, it copies nothing):
git clone git@github.com:acme/acme-brain.git ~/brains/acme
kluris register ~/brains/acme
2. Use it, inside your AI agent, with any project open:
> /kluris-acme learn everything about this service
The agent studies the code and walks you through each finding. You see every note before it is written, and you approve, edit or skip it.
After an update, kluris doctor checks your setup and rewrites every
brain's skill (self-update runs it for you).
Agents
Every brain is installed as one skill, kluris-<brain>, a SKILL.md with
instructions and the kluris commands to run. Kluris writes it to:
| Folder | Read by |
|---|---|
~/.agents/skills/ |
Cursor, Codex, Devin, OpenCode, Kilo Code, Junie and every other agent that reads this shared folder |
~/.claude/skills/ |
Claude Code |
~/.hermes/skills/ and every ~/.hermes/profiles/*/skills/ |
Hermes Agent |
~/.gemini/config/skills/ |
Antigravity CLI (agy) |
$COPILOT_HOME/skills/ (when COPILOT_HOME is set) |
GitHub Copilot |
How to call it:
- Most agents:
/kluris-acme, then what you want (/kluris-acme search auth flow). - Hermes:
/skill kluris-acmeinside a session, or start withhermes -s kluris-acme.
The skill is plain instructions plus shell commands, so any agent that loads
SKILL.md skills and can run a shell can use it. Created a new Hermes profile,
or set COPILOT_HOME, after adding a brain? Run kluris doctor to install the
skills there too.
Working with a brain
Everything in this section happens inside your AI agent. The patterns are free-form: say it naturally.
Onboard a project
Point the project at the brain, so every agent that opens the repository finds it:
> /kluris-acme setup this project
The agent adds a short ## Knowledge base section to the project's
CLAUDE.md and AGENTS.md (creating them if needed), each change approved by
you:
## Knowledge base
Read and write to the **acme** brain through kluris (never edit
brain files by hand). Use the `/kluris-acme` skill — search,
learn, remember, create.
Then have it learn the project:
> /kluris-acme learn the API endpoints and data model
> /kluris-acme learn the Docker and deployment setup
Remember decisions and knowledge
> /kluris-acme remember we chose raw SQL over an ORM for the reporting queries
> /kluris-acme remember all timestamps must be TIMESTAMPTZ
> /kluris-acme create a decision record about the auth architecture
> /kluris-acme create an incident report for the January outage
> /kluris-acme remember from this session
remember from this session goes back over the whole chat and proposes a note
for everything worth keeping, one at a time. Use it at the end of a working
session.
Before it writes, the agent syncs the brain with your team; after you approve,
it commits exactly the files it wrote with kluris commit and pushes them with
kluris sync. If a teammate changed the same thing, it shows you both
versions, asks which to keep (or proposes a merge), and settles it with
kluris resolve.
Use the brain while coding
> /kluris-acme search token refresh
> /kluris-acme what do we know about the auth flow?
> /kluris-acme implement the new endpoint following our conventions
> /kluris-acme use brain knowledge and codebase and let's write a spec for OAuth sign-in
The agent checks the brain before it answers or writes code, and flags code that contradicts a recorded decision. "Use brain knowledge and codebase" asks it to ground the work in both: the team's decisions and the code as it is.
Review the brain
> /kluris-acme review this brain for gaps and stale neurons
> /kluris-acme review this brain and create more synapses
> /kluris-acme fix the broken synapses
Maintain it, in your terminal
kluris dream # regenerate the maps, fix what is safe to fix, validate links
kluris status # lobes, neuron counts and recent commits
kluris mri # write the brain's visual map and print its link
A brain is a git repository: commit, push and pull it with git like any
other. Run kluris dream before you commit structural changes so the
regenerated maps go into the same commit, or let kluris commit --brain <name> --paths a.md,b.md do it: it commits just those files and the
map.md/brain.md files they change, under your git identity, and leaves
every other change in the brain as it is.
Keep it in sync with your team
kluris sync --brain acme # fetch, merge and push one brain
kluris sync --brain all --json # every brain, for scripts and agents
For each brain, kluris sync fetches its branch's upstream (it never asks
for credentials), fast-forwards when the brain is behind, pushes when it is
ahead, and merges when both sides have new commits:
- Merged on their own: changes to different files; the generated
map.mdandbrain.mdfiles, rebuilt from the merged brain rather than merged line by line;created(the earlier date) andupdated(the later one);relatedandtags, both lists joined; edits to different parts of the same neuron; a file one side adds in a folder the other side renamed, which moves into the renamed folder (renaming a folder never drops a teammate's file). - Left for a person: overlapping edits, a file deleted on one side and edited
on the other, different
parentvalues, any other frontmatter field changed differently on both sides, a file on one side where the other has a directory (or a rename git cannot settle), and, when the history has several merge bases (both sides merged each other), any file changed on both sides. Nothing changes then (no file, no commit, no push) until the conflict is settled withkluris resolve, and a later sync reports the same open conflict.
A file with uncommitted changes is never overwritten, nor is an untracked or
ignored file where an incoming file lands: that brain is not synced until you
commit, stash or move it. The repository's pre-merge-commit,
prepare-commit-msg, commit-msg, post-merge and pre-push hooks run as
git runs them, and git's reference-transaction and post-index-change
hooks run on every ref and index update (--no-verify skips
pre-merge-commit and commit-msg); a merge hook may change the message,
but one that stages files into the merge stops it, with nothing merged. The
brain must be the root of its own git repository, and git must be 2.38 or
newer.
With --json, each brain's entry has name, fetched, merged, pushed,
auto_merged (neurons merged on their own), conflicts (each with path,
kind (content, delete_edit, parent, frontmatter, structure or
ambiguous_base) and the base, ours and theirs blob ids, null where
a side has no file there), skipped_dirty (uncommitted files left as they
are), offline (no upstream, or no network: the host does not resolve,
the connection is refused or times out, or the fetch or push runs past its
minute), blocked (uncommitted files in the way) and refused (why the
brain was left alone: an open conflict, listed in conflicts, a locked ref,
a remote-tracking ref Kluris will not move, a remote that turned it away, or
under --brain all any other reason; else
null). The exit
code is 1 when a brain has a conflict, is blocked or was refused.
The fetch has a one-minute limit. Sync learns the upstream's commit from
its own git ls-remote origin main, then fetches that branch alone (no
tags, other branches or pruning) for its objects, writing no ref and no
FETCH_HEAD, so a fetch stopped at the limit leaves no lock behind; then it
checks the commit is here, locally (a partial clone never fetches it for
that) and within the same minute. It reads nothing another git in the brain
can rewrite (an editor's fetch, or one of yours), so what sync merges and
pushes is always the commit origin listed. Kluris then moves the
remote-tracking ref (origin/main) to that commit, unless another git fetch moved it meanwhile, in which case Kluris keeps that and fetches once
more. When origin moves its branch away from the listed commit before the
fetch brings it, Kluris fetches again; if that happens on the second try
too, kluris sync changes nothing and its refused says so: run it again.
A push has the same limit; once the remote took it, git moves origin/main
itself, so a push stopped at that very moment can leave that ref's lock
behind on Windows.
When the fetch cannot update the remote-tracking ref because a lock file is
in the way (such as .git/refs/remotes/origin/main.lock, left by a git that
was stopped), kluris sync changes nothing and its refused names that
file. If no git is running in the brain, remove the file and run kluris sync again; Kluris never removes it.
Kluris moves only a remote-tracking ref of its own: one under
refs/remotes/ that is not a symbolic ref, checked before the fetch, after
it and right before each push. When the branch's upstream maps
somewhere else (a remote.origin.fetch such as
+refs/heads/main:refs/heads/main, which makes refs/heads/main its own
tracking ref) or origin/main is a symbolic ref (to refs/heads/main, say),
moving it would move a branch while its files stayed behind, so kluris sync changes nothing and its refused names the ref and the fix: map the
branch into refs/remotes/origin/ with git config --replace-all remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*', or remove the
symbolic ref with git symbolic-ref --delete refs/remotes/origin/main; the
next sync makes it a plain ref.
When the remote answers but turns the brain away (an ssh key or a token it
rejects, a repository you cannot access or that does not exist), kluris sync stops and its refused gives git's message on one line, then the
fix: check that this machine can run git fetch origin in this brain
without a prompt (git push origin when only the push is turned away). A
refused fetch changes nothing. A refused push keeps what the sync brought
in or merged locally (merged is true, pushed is false), and the
next sync that can push sends it. Kluris never asks for credentials, so
whatever needs a prompt there fails here too. Anything git says that is not
known network trouble is shown this way, never taken for offline: Kluris
reads network trouble only in the lines git, ssh and curl print for it,
never in a quoted URL or path or in what the remote sent, so a missing
repository named timed out.git is still refused.
Settle a conflict
kluris status shows an open conflict and its paths. Choose for each path:
kluris resolve --brain acme knowledge/auth.md --ours # keep this brain's version
kluris resolve --brain acme knowledge/oauth.md --theirs # keep the remote's
kluris resolve --brain acme knowledge/jwt.md --file merged.md # keep what you merged by hand
--ours and --theirs keep that side's version, a deletion included; for a
structure conflict, that side's whole structure (its file, or its directory
and everything in it), and --file is refused there when a side has a
directory.
--file content is checked first: its frontmatter must read, and a YAML
neuron needs its #--- block. Each call records one choice; with the last
one the merge is committed under your git identity, the brain moves to it
(uncommitted changes in the way stop it, and the choices are kept) and the
result is pushed, merging again if the remote moved meanwhile. If you
committed after the conflict was found, start over with
kluris resolve --brain acme --abort, which drops the open conflict and
changes nothing else, then kluris sync.
With --json, a call prints path, choice, remaining (the paths still
to settle), committed, commit and pushed; --abort prints aborted
and dropped. While a conflict is open, kluris status --json adds
sync: {blocked: true, conflicts: [...]} to that brain.
Stay in sync while you work
kluris sync --watch --brain acme # in a terminal, until Ctrl-C
kluris sync --watch --brain all --interval 60 # every brain, once a minute
kluris sync --install-service --brain acme # in the background, from login on
kluris sync --uninstall-service --brain acme
kluris sync --watch checks every 30 seconds (--interval, at least 5)
whether the remote's branch moved (git ls-remote, which never asks for
credentials) or you made a commit, and when either did it runs one
kluris sync for that brain, with the same rules, and prints one line
(--json: the document kluris sync --json prints, one per line). A
conflict, a block or a refusal is printed once; each tick that brain is
looked at again (one git status), and it is synced as soon as its branch
or the remote moves (kluris resolve, your commit, a teammate's push) or
the cause clears without a commit (an edit undone, a rebase aborted). As
some causes clear without anything git status shows (an ignored file
deleted, a pre-push hook repaired), it is also synced again a minute
later, then after 2, 4 and 8 minutes and every 10 minutes from then on;
the wait starts over when a head moves or the local state changes.
Offline it stays quiet and picks up when the remote answers again; a remote
that turns the brain away is a refusal, printed once and tried again on
that schedule. Ctrl-C
lets a sync in progress finish, then exits with 0.
--install-service makes your system run that watch for one brain, from
login on, as you, withou
