Agent Wiki
Website: https://tacotakumi.github.io/agent-wiki/
AI agents earn hard-won knowledge in every conversation, then lose it the moment the session ends. Agent Wiki is the memory they keep instead: a single plain-markdown vault your agents search before reaching for the web, and write back to whenever they learn something worth keeping. Underneath it is just files - grep it, open it in Obsidian, script it in Python. No database, no lock-in. (Inspired by Karpathy's LLM wiki concept.)
One small CLI (awiki) is the only door in, so the same commands work whether the
vault is a local folder or a server shared across every project and machine you
point at it. Onboarding an agent takes one command: awiki guide prints a
self-installing block for your CLAUDE.md / AGENTS.md that teaches the agent to
search the wiki first, read a page whole or in slices, and save what is worth keeping.
Features
- Plain markdown, no database - the whole vault is files with YAML frontmatter and
[[wikilinks]].catit,grepit, open it in Obsidian/Logseq, or script against it in Python. Nothing to run. See How the vault works. - OKF-aligned format - the vault is ~80% conformant with Google's Open Knowledge Format by convergent design (markdown + frontmatter, generated
index.md/log.md, no prescribed taxonomy, untyped links, arbitrary frontmatter keys preserved). - Ingest files and URLs - copy a file or fetch a web page into an immutable
raw/archive (HTML via trafilatura, PDFs supported). Every ingest writes a sha256 provenance sidecar so drift is detectable. Seeawiki ingest. - Edit-the-raw, re-ingest - pages are rendered from their
raw/source. Edit the source andawiki reingest; if a page has drifted, you get a diff instead of a silent clobber. Seeawiki reingest. - Fast search + full-page read - multi-word AND search with coverage ranking (ripgrep-backed), then
awiki show <path>prints any page verbatim. Seeawiki search. - Ongoing session ingestion - every time Claude Code, pi, or OpenCode starts, a one-line hook kicks off a detached, lock-safe
awiki syncthat files every finished session from all three agents into the vault. Set it up once per agent; never run sync by hand again. See Ongoing session ingestion. - Conversation capture - adapters pull Claude Code, pi, and OpenCode sessions (plus a drop-zone for any agent) into the vault, with optional LLM summarization. See Ingesting conversations.
- Auto-context hook - a
UserPromptSubmithook silently surfaces relevant pages to your agent on every prompt, so it knows what it already knows. See Auto-context hook. - Tag vocabulary - an optional, CLI-managed vocabulary canonicalizes tags (aliases to preferred), with
awiki tag fixand a lint-based CI gate. Seeawiki tag. - Vault linting - audit broken links, orphans, raw/page drift, stale pages, oversized pages, index gaps, and tag issues in one pass. See
awiki lint. - Network vault -
awiki serveshares one vault over HTTP; remote machines use the sameawikiCLI transparently. Named users hold per-vault reader/writer/admin grants, and each user's bearer tokens can be scoped down further. An optional read-only web viewer signs users in with a password or through a reverse proxy. See Network server. - Multiple named vaults - one config registers many vaults (local paths or remote URLs); reads span them all with
vault:-qualified results, writes stay narrow, and a repo can carry its own trust-gated.agent-wiki/config.yaml. See Multiple vaults. - Agent-first integration - agent skills plus a self-installing
awiki guideblock that teaches any agent (viaCLAUDE.md/AGENTS.md) to search the wiki first and save what is worth keeping. See Using awiki with your agent.
Quick start
Requires Python 3.10+. The distribution is agent-wiki-kb; it installs two
identical commands, awiki and aw.
pip install agent-wiki-kb # or: uv tool install agent-wiki-kb / pipx install agent-wiki-kb
Then set up the machine you want to work on:
awiki init ~/vaults/agent-wiki # create the vault
awiki skills install # install the bundled skills into your agent harness(es)
awiki hook install --agent claude # sessions flow in on every start; relevant pages on every prompt
Also using pi or OpenCode? awiki hook install --agent pi and
awiki hook install --agent opencode wire those in the same way. See
Ongoing session ingestion.
A vault is not per-repo. One vault serves every project you work on, and it can
serve more than one machine too: awiki serve shares it over HTTP, and remote
machines drive it through the same awiki commands. So awiki init <path> here
creates a local vault, and awiki init --remote <url> --token <secret> on
another machine points at this one instead. See
Network server. Prove it works:
awiki ingest my-notes.md --topic research --tags python,testing
awiki search "python testing"
awiki show research/my-notes.md
awiki status
That is the whole setup. Start your coding agent and say:
We use awiki here. Run
awiki guideand wire it into this project's memory file.
Ongoing session ingestion
Every conversation your agents have is a session transcript sitting in some
per-agent store. Agent Wiki keeps those flowing into the vault automatically: any
agent starting on the machine triggers a background sweep that ingests every
finished session from every source, so the sessions topic stays current
without you ever running awiki sync by hand. One command per agent:
awiki hook install --agent claude # Claude Code: SessionStart hook in ~/.claude/settings.json
awiki hook install --agent pi # pi: extension in ~/.pi/agent/extensions/
awiki hook install --agent opencode # OpenCode: plugin in ~/.config/opencode/plugins/
Each hook runs awiki sync --detach when the agent starts. That command returns
in well under a second: the sync itself runs in a detached background process,
consults its state file before parsing anything (an unchanged session costs one
stat), and writes its log to the awiki state dir
(~/.local/state/agent-wiki/locks/<vault-digest>/sync.log; the command prints
the exact path on stderr, and nothing on stdout, so an agent's hook output stays
clean). The log holds the latest run; if another sweep already holds the vault
lock, the new one appends a one-line "already running" notice and exits at once
instead of queueing, so several agents starting together are safe. The sweep
targets the default vault; narrow it with --vault. When the default vault is
remote, the sweep is a no-op on this machine: the server owns its session
sources, so run the sweep there.
Why startup and not session end? No agent offers a reliable "session finished"
signal (Claude Code's SessionEnd has a 1.5 s budget and skips on hangup;
OpenCode has no exit event), but the next agent start is guaranteed. Sessions
modified in the last 60 minutes are treated as live and picked up on a later
sweep. Run awiki sync once by hand after installing to catch up on history -
Claude Code prunes transcripts after 30 days by default.
awiki hook install --agent claude also installs the
auto-context hook; --only sweep or --only context
narrows to one. awiki hook status shows each hook's state and
awiki hook uninstall removes only what awiki wrote. Use --agent manual to
print the wiring for any other host.
Using awiki with your agent
The installed skills make your agent able to use the wiki; a note in the
project memory file (CLAUDE.md, AGENTS.md, GEMINI.md, ...) makes it
routine. awiki guide prints that note, wrapped in a short header addressed to
the agent telling it to add the block once and leave it alone if it is already
there:
awiki guide # the agent-directed header plus the block: tell your agent to run this
awiki guide --raw # just the block, for pasting into a memory file by hand
Point an agent at it ("set up awiki usage instructions") and it will adapt the
wording to your project's name, domain, and the surrounding file's tone, then
append it to the right memory file. The awiki ... commands and skill names are
literal and get copied verbatim. The block is static - there are no version
markers and nothing to keep in sync as awiki evolves.
This is the block:
## Knowledge base: the Agent Wiki (awiki)
Durable, hard-won knowledge - decisions, research, tool/config details, fixes - lives in the
**Agent Wiki**, one markdown vault **shared across all your projects** (and the assistant itself),
reached through the `awiki` CLI. Go there first for project- or domain-specific knowledge, and
before re-deriving something that was likely figured out before.
**Search, then read the page.** `awiki search "<query>"` lists matching pages (title, path,
snippets); multi-word queries match every term, so add words to narrow. `awiki show <path>` prints
a page whole - right for most, wasteful for a long log or watch page. Slice those instead:
`--outline` lists the headings, `--section "<heading text>"` prints that one section with its
subsections, and `--head N` / `--tail N` keep only the first or last N child sections of it,
or of the whole page when no `--section` is given.
awiki show research/postgres-tuning.md --section "Connection pooling"
**Save what's worth keeping** - a decision, a non-obvious fix, a reusable pattern - with the
**`awiki-save`** skill (or **`awiki-ingest`** to pull an existing file into the vault).
**Never hand-edit a page** - each is rendered from a source in `raw/`. To change one, edit its
`raw/<name>` source (find it with `awiki raw <name>`), then run `awiki reingest <name>` to
re-render it; no `--force` needed when only the raw changed.
If `awiki` isn't installed or no vault is configured, skip the wiki and proceed normally.
Prompts that map onto it:
- "Check the wiki for X." - searches, then reads the matching pages, whole or a section at a time.
- "Save that to the wiki." - the
awiki-saveskill writes the conversation's findings into a page. - "Pull this file into the wiki." - the
awiki-ingestskill ingests an existing file. - "Fix the X page." - edits
raw/<name>and re-renders withawiki reingest, never the page itself.
The verb was
awiki directionsbefore v0.5.0; it still works as a hidden alias, butawiki guideis the name going forward.
Why a wiki, and why one CLI
Agent Wiki is a persistent, compounding knowledge store that agents maintain alongside you: agent-first, but human-readable throughout. The human curates sources and asks questions; the agent handles the bookkeeping - filing research, maintaining cross-references, surfacing relevant knowledge before reaching for the web.
Agents reach the vault through a single, narrow door: the awiki CLI. That
indirection is deliberate. The very same command works whether the vault is a
local folder or a server across the network - point the CLI at a remote vault and
every command transparently forwards over HTTP, so a laptop, an edge assistant,
and a workstation can all read and write one shared brain with identical
commands.
It is also a safeguard. Because the CLI is the only way in, it enforces the
vault's invariants no matter who is driving: raw/ sources stay immutable, pages
are re-rendered from their source rather than hand-edited, drift is surfaced as
a diff instead of a silent clobber, and remote access is gated by per-user
tokens with per-vault reader/writer/admin roles. A less capable local model does not need to
understand the vault's layout or be trusted to edit markdown by hand - it calls a
handful of commands and the guardrails hold, while the heavier reasoning can live
on a bigger model or the vault host.
How the vault works
The system follows Karpathy's three-layer architecture:
You / Your Agent
|
+-----------+
| CLI/Skills| awiki commands + agent skills
+-----------+
|
+--------------+--------------+
| | |
+--------+ +----------+ +--------+
| Raw | | Wiki | | Config |
| Sources| | Pages | | Schema |
+--------+ +----------+ +--------+
Immutable Markdown + wiki.yaml
input docs frontmatter + config.yaml
[[wikilinks]]
Raw sources (raw/) - immutable input documents. Ingest copies files here.
Nothing modifies them.
Wiki pages (topic folders) - markdown files with YAML frontmatter, organized
by topic. Pages use [[wikilinks]] for cross-references. The agent and CLI create
and update these.
Config/schema - wiki.yaml inside the vault defines topics and metadata.
~/.config/agent-wiki/config.yaml stores the vault location.
The edit loop
A page is rendered from its raw source, so you never hand-edit a page in a topic folder. To change one, edit the raw and re-render:
$EDITOR "$(awiki raw my-notes.md)" # open the raw source
awiki reingest my-notes.md # re-render the page from it
Each page carries a render_hash of its body in frontmatter. Editing the raw
never trips the drift guard - reingest rebuilds cleanly. A page that was
hand-edited out of band does trip it, and reingest prints a diff and stops
rather than clobbering your edit.
Vault structure
~/vaults/agent-wiki/
wiki.yaml # vault config: topics, name, version
index.md # auto-generated page index (awiki index)
log.md # append-only activity log
raw/ # immutable source documents
projects/ # topic folder (supports arbitrary nesting)
decisions/ # topic folder
research/ # topic folder
tools/ # topic folder
Wiki page format
---
title: Payments Service API
topic: projects
tags: [payments, api, backend]
created: 2026-04-14
updated: 2026-04-14
sources: [raw/payments-service-notes.md]
---
# Payments Service API
REST API serving the mobile app and external integrations.
See [[Auth Tokens]] for authentication details.
Obsidian / Logseq compatibility
The vault is compatible with Obsidian and Logseq out of the box: markdown files
with YAML frontmatter, [[wikilinks]] for cross-references, and a standard folder
structure. Open the vault directory in Obsidian as a vault and everything just
works.
Command reference
Two global options apply to every command:
awiki --version- print the installed version and exit.awiki --vault PATH- use this vault for one invocation, overriding the configured one (also settable viaAWIKI_VAULT). Forces a local vault. See Configuration.
Setup and orientation
awiki init [path]
Create a new vault at the given path (defaults to the current directory). Sets up
the directory structure and saves the vault location to
~/.config/agent-wiki/config.yaml. The first vault gets the standard default
topics (projects, decisions, research, tools, sessions); pass --topics to
choose your own, with the first listed becoming the vault's default_topic.
awiki init ~/vaults/agent-wiki
awiki init ~/vaults/personal-wiki --name personal # create AND register under a name
awiki init ~/vaults/recipes --name recipes --topics "recipes, techniques"
awiki init --remote https://wiki.example.com --token <secret> # point at a served vault instead
awiki init --clear # drop the remote config from this client
A vault created beside existing ones does not clone the default topics, since
topics duplicated across vaults make every unqualified --topic ambiguous.
Without --topics, such an init prompts for a topic list when run on a
terminal and otherwise creates the vault with no topics, printing a warning
that explains how to add them later; ingest into a vault with no
default_topic requires --topic.
A registered name whose vault directory has been deleted does not block
re-initing: init --name reclaims the stale name and repoints it at the new
vault.
Local and remote vaults are mutually exclusive: setting one clears the other. See
Network server for the remote side, and
Multiple vaults for named registration with --name.
awiki vault list|add|trust
Manage the named vault registry: vault list is a read-only view (name, kind,
target, reachability, declaring config, default marker), vault add NAME PATH|URL registers an existing vault, and vault trust DIR allows a
repo-local .agent-wiki/config.yaml to be honored. See
Multiple vaults.
awiki guide [--raw]
Print the self-installing block for your agent's memory file. Runs without a vault, so a fresh agent can run it in any repo. See Using awiki with your agent.
awiki skills install|status|update|uninstall
Install the bundled agent skills into the harnesses on your machine and keep them current. See Agent skills.
awiki hook install|uninstall|status [--agent claude|pi|opencode|manual] [--config-path PATH] (install/uninstall also take --only context|sweep)
Wire awiki's two hooks into an agent CLI: the startup sweep (awiki sync --detach on every agent start) and, where the host supports it, the
auto-context hook (awiki context on every prompt).
awiki hook install --agent claude # SessionStart sweep + UserPromptSubmit context in ~/.claude/settings.json
awiki hook install --agent pi # writes ~/.pi/agent/extensions/awiki-sync.ts (session_start sweep)
awiki hook install --agent opencode # writes ~/.config/opencode/plugins/awiki-sync.js (session.created sweep)
awiki hook install --agent claude --only context # just one of the two
awiki hook status --agent claude # per-hook installed / not installed
awiki hook uninstall --agent claude # remove only the awiki entries, preserve others
awiki hook install --agent manual # print copy-paste wiring for any host
Every backend is idempotent and atomic. The Claude backend edits
settings.json in place, preserves all other keys, and refuses to touch a file
that is not valid JSON. The pi and OpenCode backends each write one
marker-tagged file and will never delete a file they did not write; pi and
OpenCode have no prompt-submit event, so --only context is a no-op there. Use
--config-path to target a non-default settings/extension/plugin file (handy
for tests). The manual backend touches no files - it prints the contract for
both hooks so you can wire Codex, Cursor, and others by hand. See
Ongoing session ingestion and
Auto-context hook.
awiki doctor [--fix] [--dry-run] [--reconcile-raw]
Inspect the vault for drift from the current schema and offer to fix each finding.
Run this after upgrading awiki: it adds missing wiki.yaml sections
(conversations, summarizer, sources), missing topic dirs, missing
raw/sessions/ and incoming/, and warns when an enabled source points at a path
that does not exist. Interactive by default - use --fix to apply everything,
--dry-run to just report.
doctor also reports raw content drift - pages whose body no longer matches
their raw/ source (for example after editing a page directly). Rewriting raw from
the canonical page is a deliberate, server-local operation: run
awiki doctor --reconcile-raw on the machine that holds the vault. It is excluded
from a blanket --fix, prompts before overwriting (default No), and cannot be
triggered by a remote client - there is no HTTP path for it.
doctor also reports session titles taken from harness text (check
session-titles): Claude Code sessions synced before the title fix, whose title
starts with a tag such as <local-command-caveat>. Its fix derives the title
again from the turns kept in the raw/sessions/ bundle and writes it to the
bundle's title field and to the session page's title and heading. This is a
sanctioned raw/ write limited to that one field. The new title comes only from
the bundle itself, so the fix runs under a plain --fix and from a remote client.
Getting knowledge in
awiki ingest <files-or-urls>
awiki ingest <files-or-urls> [--topic <topic>] [--tags <tags>] [--update] [--force] [--tag-mode off|warn|strict]
Ingest one or more files or URLs into the vault. Each source is copied (or
fetched) into raw/ (immutable archive) and a wiki page is created in the
appropriate topic folder with YAML frontmatter.
awiki ingest notes.md # uses default topic (research)
awiki ingest notes.md --topic tools --tags cli,python
awiki ingest *.md --topic research # glob support
awiki ingest https://example.com/post # fetch + ingest a web page
awiki ingest notes.md --update # overwrite raw + update the linked page
- Title is extracted from the first
# heading, or derived from the filename (for URLs, from the fetched page's title, then the URL). - The original source is preserved in
raw/and never modified. - Every ingest writes a provenance sidecar (
raw/<name>.meta.yaml) recording the source, fetcher, and a sha256 of the raw body.awiki lintuses this to detect drift. - A file is identified by its
raw/basename. Without--update, ingesting a source whose basename already exists inraw/is refused so nothing is silently clobbered. In a glob, the colliding file is skipped and the rest proceed; the command exits non-zero if any file was skipped. --updateoverwritesraw/<basename>from an external source and rewrites its linked wiki page (located via the page'ssources:frontmatter): the body is refreshed,createdis preserved,updatedis bumped, and tags are kept unless--tagsis given. If the title or--topicchanged, the page file is renamed/moved to match. (To rebuild a page after editing the vault's ownraw/copy, useawiki reingestinstead.)--forceproceeds even when the target page has diverged from itsraw/source (otherwise ingest shows the diff and stops).--tag-mode off|warn|strictforces the tag-vocabulary mode for this ingest only (seeawiki tag); it does not change the vault's configured mode.
Ingesting URLs. awiki ingest <url> fetches the page and ingests it like any
other source:
- HTML is extracted to clean markdown via trafilatura; PDFs via
pymupdf4llm(withpdfplumberselectable). - The original fetched artifact is archived byte-identically under
raw/assets/, and the page carries an inlinesource_url. - URLs are normalized for dedup, and a sha256 check skips re-ingesting an unchanged URL. Non-text content types are rejected with a friendly error.
- On the network server, the client does the fetch, so URL ingest works whether the vault is local or remote.
awiki reingest <name>
Rebuild a page from its own raw/<name> source after you edit that raw file.
This is the canonical page-edit loop: pages are rendered from raw/, so you
never hand-edit a page in a topic folder.
# edit raw/my-notes.md, then:
awiki reingest my-notes.md
awiki reingest my-notes.md --force # rebuild even if the page diverged from its raw
- The body is taken verbatim from the raw; frontmatter (title from the first
# H1, tags,created) is regenerated - keep the H1 stable, or the slug (and thus the page path) changes and can orphan the page. - If the page has diverged from its raw (for example someone edited the page directly),
reingestprints a diff and stops. Fold anything worth keeping into the raw, then re-run with--force. reingestonly propagates the raw's content into the page - it never authors the change itself. Contrastingest --update, which pulls from an external file.- Editing the
raw/source never trips the drift guard -reingestrebuilds cleanly, no--forceneeded. The guard is only for the other case: a page that was hand-edited out of band.
awiki raw <name>
Print a page's raw/<name> source path - the file you actually edit before
awiki reingest. Output goes to stdout so it drops straight into command
substitution; pair it with reingest for the whole edit loop in two commands.
$EDITOR "$(awiki raw my-notes.md)" # open the raw source
awiki reingest my-notes.md # re-render the page from it
- Errors exactly as
reingestdoes on a missing or ambiguous<name>. - On a remote vault the raw lives on the server:
rawprints the server-side reference and notes on stderr that it is not directly editable from the client.
awiki sync [--source claude-code|opencode|pi|drop-zone] [--since DATE] [--include-live] [--dry-run] [--detach]
Ingest conversations from configured sources. Sessions modified in the last 60
minutes are treated as live and skipped unless --include-live (or the
source's include_live: true) is set. --detach forks the sync into a
background process and returns at once (this is what the startup hooks run):
output goes to a per-vault log in the awiki state dir, and a run that finds the
vault lock held exits cleanly instead of waiting. See
Ongoing session ingestion and
Ingesting conversations.
awiki ingest-conversation <bundle.md>
Ingest a single bundle file. The entry point for external producers (for example a personal assistant) that write bundles directly rather than using an adapter.
awiki adapt <source> <path-or-id> [-o FILE]
Low-level: convert a single session into a conversation bundle without ingesting. Useful for hooks, scripts, and debugging an adapter.
Getting knowledge out
awiki search <query>
awiki search <query> [--topic <topic>] [--limit N]
Full-text search across all wiki pages. Multi-word queries match all terms
anywhere in a page (AND across the page); pages matching only some terms are
listed separately as lower-ranked partial matches, ordered by how many terms they
cover. Uses ripgrep when available, otherwise a built-in case-insensitive
substring scan. Skips raw/, index.md, and log.md. --limit caps how many
all-terms results are shown (default 20).
awiki search "authentication"
awiki search "claude code hooks" # pages containing all three terms rank first
awiki search "docker" --topic tools
awiki show <path>
Print a wiki page (or any file in the vault) by its vault-relative path - the
path awiki search prints in its results. Output is the file verbatim, including
YAML frontmatter. Use it to read a full page after locating it with awiki search.
awiki search "raft consensus" # prints e.g. research/raft-consensus.md
awiki show research/raft-consensus.md # prints that page in full
- Accepts any file inside the vault (topic pages,
raw/,index.md,log.md). - Paths that escape the vault are rejected; missing files and binary (non-UTF-8) files report an error and exit non-zero.
Reading part of a long page. Four flags slice the output so a long log or watch page does not have to be read whole. Any of them drops the YAML frontmatter, so what you get is plain markdown; without them the output stays byte-identical to the file.
awiki show projects/feed-log.md --outline # just the heading lines
awiki show projects/feed-log.md --section "check log" # one section, subsections included
awiki show projects/feed-log.md --section "check log" --head 3 # its first 3 entries
awiki show projects/feed-log.md --tail 2 # the last 2 top-level sections
--outlineprints every heading line verbatim, in file order, and nothing else. Headings inside fenced code blocks are not counted.--section TEXTmatches TEXT against each heading's text, case-insensitively, as a substring. The first match wins and prints through the line before the next heading of the same or a higher level. Other matching headings are listed on stderr; no match exits non-zero.--head Nand--tail Nkeep the first or last N child sections of the--sectionselection, or of the page's top-level sections when no section is given. The heading and the text above the first child are always kept.--headand--tailcannot be combined with each other or with--outline, and N must be at least 1.--sectionand--outlinetogether list the headings inside the selected section.
awiki status
Show a vault overview: page count per topic, raw file count, and last activity.
awiki log [--last N]
Show the activity log. Each ingest and maintenance action is recorded with a timestamp.
awiki log
awiki log --last 5
awiki index
Rebuild index.md from all wiki pages, grouped by topic. Each entry shows the page
title (as a wikilink), file path, tags, and last updated date.
awiki context [--output-format claude-json|plain]
Auto-context hook payload. Reads {"prompt": "..."} JSON from stdin, extracts
keywords with YAKE, searches the vault, and emits a compact pointer block to
stdout. Designed to be wired into an agent CLI's UserPromptSubmit-style hook so
the model sees relevant page titles before answering. Silent-fails on every error
path - never blocks the prompt.
echo '{"prompt":"how do I configure ingest"}' | awiki context
# {"hookSpecificOutput": {"additionalContext": "<!-- agent-wiki: 3 possibly-relevant pages... -->\n## research\n- [Ingest Pipeline](research/ingest-pipeline.md)\n..."}}
Skips short prompts (under 15 characters or under 3 words) and slash commands.
Toggleable via auto_context: true|false in wiki.yaml or the
AWIKI_AUTO_CONTEXT=0|1 env var. Diagnostics go to
~/.cache/agent-wiki/context.log. See Auto-context hook.
Maintenance
awiki lint
awiki lint [--strict] [--refetch]
Audit the vault for issues:
- LINK - broken
[[wikilinks]]pointing to pages that do not exist - ORPHAN - pages with no incoming wikilinks
- RAW - files in
raw/that have no corresponding wiki page - META - pages missing YAML frontmatter
- DRIFT - a page whose body no longer matches its
raw/source - SOURCE - a
raw/file edited in place (drifted from its recorded sha256) - STALE - a page whose body lags its newest source
- SIZE - pages over
page_max_lines(default 500), flagged as split candidates - INDEX - pages missing from
index.md - TAG - tag-audit findings: alias-fixable or novel tags, or vocabulary conflicts (only when a
tags:vocabulary is configured) - UPSTREAM - a URL source whose upstream content changed (only with
--refetch)
awiki lint
awiki lint --strict # CI gate: exit non-zero if any TAG finding exists
awiki lint --refetch # also re-fetch URL sources and flag upstream changes (network; local vaults only)
Tuning the SIZE threshold. The page-length that trips a SIZE finding is
page_max_lines, an optional integer in a lint: block in wiki.yaml. The
built-in default is 500 lines, counted on the page body with the frontmatter
excluded. Hand-edit the block like topics; an unrecognised key in the block, or
a value that is not a whole number of at least 1, makes awiki lint fail and
name the key.
lint:
page_max_lines: 500
awiki tag add|suggest|fix
Manage an optional tag vocabulary that canonicalizes tags across the vault. The
vocabulary lives in a tags: block in wiki.yaml (mode: off | warn | strict
plus a preferred-to-aliases map - see
Vault config). It is inert until configured.
awiki tag add cli --alias command-line --alias commandline # persist a preferred term + aliases
awiki tag suggest # draft a vocabulary from tags already in use
awiki tag suggest --write # merge that draft into wiki.yaml
awiki tag fix # preview: which pages' tags would canonicalize
awiki tag fix --write # apply: rewrite page frontmatter tags in place
awiki tag fix --topic research # narrow to one topic (or pass a path)
tag addappends a preferred term (and optional--aliasentries, repeatable) to the vocabulary via a comment-preservingwiki.yamlwriter. Idempotent; refuses to bind an alias already claimed by another term.tag suggestscans every page, counts tag frequencies, and prints a validtags:block covering all in-use tags, grouping related tags as alias candidates.--writemerges it intowiki.yaml. String heuristics only, no ML.tag fixcanonicalizes existing pages' frontmatter tags against the vocabulary - aliases are rewritten to their preferred term; novel out-of-vocabulary tags are reported but left for you (adopt viatag add, or remove). Preview by default;--writerewrites frontmatter only - the page body stays byte-identical andraw/is never touched.
Ingest also applies the vocabulary at write time; awiki lint reports
fixable/novel tags as TAG findings, and awiki lint --strict gates on them.
Serving a vault
awiki serve [--bind HOST] [--port PORT] [--viewer]
Run the HTTP server for the local vault so remote machines can use it through the
same CLI. One vault per instance: the default vault, or pick one with
awiki --vault NAME serve --port PORT. --viewer also serves a read-only web
viewer of the local registry vaults at /, behind a sign-in. serve refuses to
start while server.yaml still holds tokens from an older install (see
Upgrading from awiki token). See
Network server and Multiple vaults.
awiki user add|list|passwd|remove|grant|ungrant
Manage the server's users and their per-vault grants. Local on the server host; the user store lives in the config dir, never in the vault. A password is only ever typed at a prompt. See Users and grants.
awiki user token add|list|revoke|migrate
Manage a user's bearer tokens and their optional scopes, and move tokens from an
older server.yaml into the user store. A secret is printed once, when it is
made. See Tokens and scopes.
Ingesting conversations
Conversations are pulled in via adapters that turn agent-native session stores
into a canonical Conversation Bundle (a single markdown file with frontmatter,
stored under raw/sessions/). Bundles are then ingested into the sessions topic
like any other wiki page.
Four adapters ship today:
- claude-code - reads Claude Code JSONL transcripts from
~/.claude/projects/<slug>/*.jsonl. - pi - reads pi session files from
~/.pi/agent/sessions/<cwd-slug>/<timestamp>_<uuid>.jsonl(session format v3; one file is one session). - opencode - reads OpenCode's SQLite store (opened read-only). The path comes from
sources.opencode.db_pathif set, else fromopencode db pathwhen the binary is onPATH, else~/.local/share/opencode/opencode.db. - drop-zone - picks up pre-written bundles from a configured directory (default:
<vault>/incoming/). This is how external agents without a built-in adapter (for example a personal assistant) file conversations.
Normally the startup hooks run the sync for you (see Ongoing session ingestion). Run it by hand for a first catch-up or to inspect what is pending:
awiki sync # all enabled sources
awiki sync --source pi # one source only
awiki sync --dry-run # show what would be added
awiki sync --since 2026-04-01 # older stuff only
awiki sync --include-live # also sessions touched in the last 60 minutes
awiki sync --detach # what the hooks run: background, logs to the state dir
Sync is state-tracked in <vault>/.awiki-sync-state.json, so reruns are
idempotent. A changed session (mtime or content hash) gets re-ingested; unchanged
sessions are skipped without being parsed. Session pages are pointers to their
transcript, so awiki doctor leaves them out of its raw-drift and render-hash
checks and --reconcile-raw never touches raw/sessions/. The one doctor fix
that writes there is session-titles, which changes only a bundle's title
field.
Writing bundles directly (for external agents)
See Doc/conversation-bundle-schema.md
for the full spec. Minimum bundle:
---
type: conversation
agent: my-assistant
session_id: 2026-04-18-1030
title: "Quick question about sqlite locking"
---
# Quick question about sqlite locking
## user
...
## assistant
...
Drop it into <vault>/incoming/ (or whatever sources.drop_zone.path points to)
and the next awiki sync will move it into raw/sessions/ and create a wiki page
under sessions/. Malformed bundles are quarantined under incoming/rejected/
with a .reason sidecar - nothing is silently dropped.
Summarization (optional)
By default the wiki page for a conversation is a link back to the full transcript
in raw/sessions/. You can swap in a summarizer via wiki.yaml:
summarizer:
type: none # none | claude-p | local-openai
claude_p:
args: ["-p"]
local_openai:
base_url: http://127.0.0.1:8080/v1
model: ""
max_tokens: 600
none- no LLM calls. Fast, offline, zero external deps.claude-p- shells out to theclaudeCLI in-pmode. Uses your existing Claude Code credentials; no API key.local-openai- POSTs to any OpenAI-compatible endpoint (for example allama.cppserver). Stays local; no external traffic.
If a summarizer is configured, each wiki page body is replaced with a structured
summary (Context / Decisions / Key Exchanges / Open Threads). The raw transcript
stays in raw/sessions/ regardless.
Auto-context hook
Instead of relying on a memory-file prompt, you can have agent-wiki inject pointers to relevant pages on every user prompt:
awiki hook install --agent claude # both hooks: startup sweep + auto-context
awiki hook install --agent claude --only context # just the auto-context hook
This adds a UserPromptSubmit hook to ~/.claude/settings.json that runs
awiki context for each prompt. The hook extracts keywords with YAKE, searches
the vault, and silently injects a small block of page pointers (capped at 5) so
the model knows what is available without you having to ask. Skips slash commands
and short prompts. Toggle off per-vault with auto_context: false in wiki.yaml
(local vaults only - a remote vault's server-side flag does not travel over the
wire, so the hook always includes a reachable remote vault) or one-shot with
AWIKI_AUTO_CONTEXT=0.
pi and OpenCode have no prompt-submit event, so this hook is Claude Code only
today. For other agent CLIs (Codex, Cursor, and so on),
awiki hook install --agent manual prints the wiring contract so you can hook it
up by hand.
Agent skills
Three skills wrap the common flows for an agent. They ship as SKILL.md skills
(usable by Claude Code and other agents that support the format), and because each
one just shells out to the plain awiki CLI, any agent that can run a shell
command can offer the same flows even without native skill support. They ride
inside the wheel as package data under src/agent_wiki/skills/.
awiki skills install # install all three into every detected harness (user scope)
awiki skills install --scope project # install into the current project, not your user config
awiki skills install --harness claude # limit to one detected harness
awiki skills status # show each skill's state per harness
awiki skills update # refresh stale installs to the bundled version
awiki skills uninstall # remove the skills this package installed
install copies all three into whatever agent harness it detects (Claude Code,
pi, Hermes, opencode).
/awiki-search- search the wiki before resorting to web searches. The agent runsawiki searchand presents results./awiki-save- save content from the current conversation to the wiki: the agent generates a markdown summary, then ingests it viaawiki ingest, asking for topic and tags if they are not obvious from context./awiki-ingest- ingest an existing file into the vault. The agent confirms the file path, asks for topic and tags, and runsawiki ingest.
Configuration
User config (~/.config/agent-wiki/config.yaml)
vault_path: ~/vaults/agent-wiki
Set automatically by awiki init. Override to point to a different vault.
The config directory can be overridden with the AGENT_WIKI_CONFIG_DIR
environment variable.
The config can also hold a named vault registry instead of the single
vault_path (see Multiple vaults):
default_vault: work
vaults:
work:
path: ~/vaults/work-wiki
personal:
path: ~/vaults/personal-wiki
team:
url: https://wiki.example.com:8731
token: <secret>
Each entry declares path: (a local vault) or url: plus optional token:
(a remote one), mixed freely. A legacy vault_path/server config keeps
working unchanged - it reads as a single vault named main - and config
writes stay in the legacy form until the first write that needs more (a
second vault, a named init, a remote entry), which rewrites the file to the
vaults: schema. The default vault is default_vault if set, else the vault
named main, else a sole configured vault. No command writes default_vault
and there is no awiki use - repoint the default by editing the file.
To use a different vault for a single invocation without touching the
config, pass --vault NAME|PATH (or set AWIKI_VAULT). A bare value that
matches a configured vault name narrows to that vault - including a remote
one; any other value is a config-free local vault at that path (./ or an
absolute path forces path interpretation):
awiki --vault personal status # a configured vault, by name
awiki --vault /tmp/scratch-vault status # any local vault, by path
AWIKI_VAULT=~/vaults/other awiki search "raft"
Vault config (wiki.yaml)
vault:
name: agent-wiki
version: 1
topics:
- projects
- decisions
- research
- tools
default_topic: research
# Conversation sources for `awiki sync` (written by `awiki init`; edit by hand).
# Each source takes `enabled`, an optional `include_live`, and a location:
conversations:
topic: sessions
sources:
claude_code:
enabled: true
path: ~/.claude/projects
pi:
enabled: true
path: ~/.pi/agent/sessions
opencode:
enabled: true # no db_path: resolved via `opencode db path`, then the default
drop_zone:
enabled: true
path: incoming # relative to the vault
# Optional: a tag vocabulary that canonicalizes tags across the vault.
tags:
mode: warn # off | warn | strict
cli: # preferred term ...
- command-line # ... and its aliases
- commandline
Add new topics by editing this file and creating the corresponding directory -
the topics / default_topic keys are hand-edited (awiki init --topics only
seeds the initial list).
The tags: block is different: it has a sanctioned CLI write path. Manage it with
awiki tag add and awiki tag suggest --write (both
use a comment-preserving writer) rather than editing it by hand.
Multiple vaults
One machine can hold several vaults - say a work wiki, a personal one, and
a shared team vault served over HTTP - all reachable from one CLI. Register
them in the user config's vaults: map (see
User config) or with the CLI:
awiki init ~/vaults/personal-wiki --name personal # create and register
awiki vault add work ~/vaults/work-wiki # register an existing vault
awiki vault add team https://wiki.example.com:8731 --token <secret>
awiki vault list # name, kind, target, reachability, default marker
A vault name uses lowercase letters, digits and hyphens only (work,
team-2). init and vault add refuse any other name. A name typed into a
config file by hand that breaks the rule is left out with a warning, and a
command that names it (--vault, AWIKI_VAULT, default_vault) stops.
An init beside an existing vault does not clone the default topics - it
prompts for (or takes --topics) a topic list of its own, so --topic
routing stays unambiguous. See awiki init.
With a single configured vault nothing changes - every command behaves and prints exactly as before. With more than one:
- Reads span vaults.
awiki searchprints one merged coverage-ranked list; every hit path carries avault:qualifier (work:research/raft.md) that pastes straight intoshow,raw, orreingest. Unqualified references resolve across vaults: a unique match wins silently, an ambiguous one is a hard error listing the qualified candidates. One limitation: an unqualifiedraworreingestname only probes local vaults - a remote vault's raws live server-side and are never probed by name. To target a remote vault's raw, qualify the name (work:notes.md); the qualified form always reaches the named vault. The auto-context hook spans vaults too, skips unreachable ones, and a vault withauto_context: falsein itswiki.yamlstays out of the hook while remaining fully searchable. The opt-out is local-only: the serve wire contract exposes noauto_contextflag, so a remote vault's server-sideauto_context: falsecannot suppress it in the hook - a reachable remote vault is always included. - Writes stay narrow.
ingest --topicroutes to the unique vault whosewiki.yamldeclares that topic; a topic declared by two vaults is a hard error resolved by--vaultor avault:prefix on the topic. Everything else that mutates (tag,sync,doctorfixes) acts on the default vault only unless you narrow with--vault. - Maintenance sweeps are sectioned.
lint,doctor(diagnostics), andindexvisit every vault with a labeled section per vault; a vault that cannot support an operation is skipped with a printed notice, and skips never change the exit code.lint --strictexits nonzero on a TAG finding in any vault.
Per-project vaults
A repo can carry its own .agent-wiki/config.yaml declaring extra vaults
(and optionally its own default_vault). awiki finds the nearest one walking
up from the current directory to $HOME and merges it additively over the
global config, the local file winning on name collision. A relative path:
in a local config resolves against the directory containing .agent-wiki,
so the config means the same vault from any subdirectory. Because a checked-in
config is repo-controlled content, it is honored only after you trust its
directory explicitly:
awiki vault trust ~/code/my-project
An untrusted local config is ignored with a one-line stderr notice naming the file and the trust command - never silently. A vault absent from the merged view is invisible to every command, even if its directory exists on disk.
Serving
awiki serve serves exactly one vault per instance - the default vault
unless you pick one with --vault NAME - and --port overrides the
server.yaml port, so one config dir can serve several vaults from separate
processes on different ports. The HTTP wire contract stays vault-implicit
(no vault selector in the routes). A single multiplexed server that mounts
several vaults under one port is the planned evolution of this design.
User grants and token scopes name vaults by their registry name, so the same
grant map applies to every vault you serve. --vault NAME (or
AWIKI_VAULT=NAME) keeps the registry name. A path override is always served
under the name local, even when the path is a registered vault's path, so
--vault /home/you/wiki needs a grant on local, not on main. See
Users and grants.
Network server
A vault can be served over HTTP so a remote AI assistant reads from and contributes
to the same vault using the same awiki CLI as a transparent client. The CLI
talks to a VaultService facade; locally that is an in-process call, remotely it is
an HTTP round-trip - every command behaves the same either way.
Server host
The HTTP server ships in the default install - no extra to install. Add a user, give them a role, make them a token and run the daemon:
awiki user add you --password # asks for the password twice
awiki user grant you '*' admin # admin on every vault
awiki user token add you laptop # prints the secret ONCE; only its hash is stored
awiki serve # binds 127.0.0.1:8731 by default
There is no anonymous access: every /v1 API request needs a bearer token, and
every viewer page needs a signed-in session. Users, grants, tokens, sessions and
sign-in failures live in one SQLite file, state.db, in the config dir
(~/.config/agent-wiki/, respects AGENT_WIKI_CONFIG_DIR), never in the
vault. The awiki user commands are local on the server host, and a change made
with them applies to a running server at its next request - no restart needed.
No API route and no viewer page can create users or change grants.
serve warns at startup when the store has no users (nobody can sign in or use
the API yet), and for each grant or token scope that names a vault not in the
registry. The server does not serve /docs, /redoc or /openapi.json.
Users and grants
awiki user add alice --password # password sign-in; asked twice at the prompt
awiki user add bob # no password: signs in only through the reverse proxy
awiki user list # password set, grants, token count; marks stale vault names
awiki user passwd alice # set a new password; ends alice's sessions
awiki user passwd alice --clear # remove the password: alice becomes proxy-only
awiki user remove bob # deletes bob with his grants, tokens and sessions
A user name is 1 to 64 characters of a-z 0-9 . _ - @, starting with a letter or
digit, and is stored lowercase. A password is never taken as an option value, so
it stays out of shell history and the process list. passwd in either form ends
all of that user's sessions and clears their failed sign-ins.
Each user holds a grant map of vault name to role:
awiki user grant alice '*' writer # writer on every vault, including ones added later
awiki user grant alice personal none # ...except personal
awiki user grant alice work admin # ...and admin on work
awiki user ungrant alice work # remove the work entry again
Roles are ranked none < reader < writer < admin. grant replaces any entry
for that vault. The entry '*' matches every vault, including vaults registered
later, and the most specific entry wins: a vault's own entry beats '*', whether
it is higher or lower. A vault with no entry and no '*' gets none. Quote the
'*' so the shell does not expand it.
What each role allows on the /v1 API:
reader- search, show, status, log, lint, context; also reading the vault in the web viewer.writer- everything a reader can, plus ingest, reingest, ingest-conversation, index, sync and adapt.admin- everything a writer can, plusdoctor. A vault admin manages nothing but that vault: users and grants are changed only withawiki useron the server host.none- nothing; the vault does not exist for that user.
A request without a token, or with an unknown one, gets 401; a role below what
the route needs, including none, gets 403.
Tokens and scopes
A token belongs to a user and acts as that user on the API. A remote client uses
it with awiki init --remote <url> --token <secret> or a token: in its vault
registry.
awiki user token add alice laptop # all of alice's grants
awiki user token add alice agent --scope '*=writer' --scope personal=none
awiki user token add alice dashboard --scope '*=reader' # read-only everywhere
awiki user token list alice # name, last 4 characters, scope, created, last used
awiki user token revoke alice dashboard
add prints the secret once (awp_ and 43 URL-safe characters); the store
keeps only its SHA-256 hash and last 4 characters. A token name is unique per
user. --scope VAULT=ROLE is repeatable and takes the same vaults, '*' and
roles as a grant.
A scope can only narrow the owner's grants, never widen them. The token's
role on a vault is the lower of the two: the owner's grant for that vault and
the token's scope for that vault, each resolved the same way (the vault's own
entry, else '*', else none). A token with no scope acts with the owner's
grants as they are. In the examples above, if alice has '*' writer and
personal none:
agent(*=writer,personal=none) can write to every vault exceptpersonal, where it can do nothing at all - a token for an agent that must never touch your personal notes.dashboard(*=reader) can only read, even on vaults where alice is an admin.- A scope of
work=adminwould still give onlywriteronwork, because the grant caps it.
Nothing is cached: a grant change, a revoke or a user removal takes effect at the token's next request. A token's last-used time is written at most once a minute. A bearer token never signs in to the web viewer, so a token cannot make or revoke other tokens.
Web viewer and sign-in
awiki serve --viewer also serves a read-only HTML viewer of the local registry
vaults at /, beside the API on the same port. Every viewer page except the
sign-in page and the favicons needs a signed-in session; without one it
redirects to /signin. A signed-in user sees only the vaults their grants give
them at least reader on, in the vault list, search and tag pages, and a vault
they cannot read answers 404, the same as one that does not exist. Every page
shows "Signed in as NAME", a Settings link to the user page and a sign-out button.
Sessions are kept server-side; the browser holds only the awiki_session
cookie (HttpOnly, SameSite=Lax, and Secure over https). A session ends 12
hours after its last use; each use extends it. Signing out ends the session.
Every form that changes state carries the session secret in a hidden field, and
a post without it, or with the wrong one, is refused with 403.
A session cookie never authenticates the /v1 API; API clients always use a
bearer token.
Password sign-in
A user with a password signs in at /signin with their name and password. A
wrong name, a proxy-only user and a wrong password all get the same answer.
Five failed password sign-ins for one user within 15 minutes lock that user's
password sign-in for 15 minutes, even for the right password. The lock holds
across a server restart. A successful sign-in or awiki user passwd clears the
failures. The lock does not affect that user's tokens or proxy sign-in.
While the store has no users, the sign-in page says to run awiki user add.
Reverse-proxy sign-in
If a reverse proxy in front of awiki serve already signs users in (Authelia,
oauth2-proxy, Authentik, a web server's own auth), the viewer can take the
user's name from a header the proxy sets. Turn it on in
~/.config/agent-wiki/server.yaml:
auth_proxy: true # default false
auth_proxy_header: X-WEBAUTH-USER # the default
auth_trusted_proxies: # default: 127.0.0.1 and ::1
- 127.0.0.1
- ::1
- The header counts only when the request's socket peer is in
auth_trusted_proxies(addresses or CIDR ranges).X-Forwarded-Forand similar headers never change which peer is checked, and from any other peer the header is ignored. The header must appear exactly once. - The header must name an existing user. An unknown name gets a
403page; no account is created. Add proxy users withawiki user add NAME(no--password) and give them grants as usual. - A header naming a different user than the browser's current session ends that session and signs in the named user.
- The header never authenticates the
/v1API; API clients still need a bearer token. - Configure the proxy to replace the header on every request, so a client cannot send its own value through it. Use a header name with hyphens, not underscores;
serverefuses an underscore name.
With auth_proxy on, serve refuses to start if auth_trusted_proxies is
empty, contains *, contains a range that matches every address (such as
0.0.0.0/0 or ::/0), or contains an entry that is not an address or a range.
A proxy session has no password to change; password sign-in still works for
users who have one.
The user page
The user page at /user (the Settings link in the header) shows:
- the theme choice (Auto, Light or Dark);
- your own tokens: make one with a name and an optional scope, list them, and revoke them. A new secret is shown once, on the page that made it;
- for a password session only, a change-password form. It asks for the current password and the new one twice; on success your current session stays signed in, your other sessions end and failed sign-ins are cleared.
The user page cannot change grants, and a token cannot reach it.
Upgrading from awiki token
Older releases kept role-carrying tokens in server.yaml and managed them with
awiki token. That command group is gone, and awiki serve refuses to start
while server.yaml still holds a tokens list, naming the command below. Move
the tokens into the user store once, on the server host:
awiki user add you # add --password to also sign in to the viewer
awiki user grant you '*' admin
awiki user token migrate --to you
# then restart awiki serve (for example: sudo systemctl restart agent-wiki)
migrate imports each token with its name and secret unchanged, so remote
clients keep working without a new --token. Each gets the scope '*' with
its old role, so its access stays the same as long as the owner's grant is at
least that role. Imported tokens list as legacy instead of their last 4
characters, since the secret was never kept. The tokens key is then removed
from server.yaml; its other keys stay. Running it again imports nothing
twice. A token whose name the user already has is skipped and left in
server.yaml; revoke or rename the clashing token, or migrate to another
user, and run it again.
Running as a service (systemd)
A sample unit ships at
agent-wiki.service:
[Unit]
Description=Agent Wiki server
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/awiki serve --bind 127.0.0.1 --port 8731
Restart=on-failure
User=you
[Install]
WantedBy=multi-user.target
Install it as a system service:
sudo cp agent-wiki.service /etc/systemd/system/
sudoedit /etc/systemd/system/agent-wiki.service # set User= and the ExecStart path
sudo systemctl daemon-reload
sudo systemctl enable --now agent-wiki
sudo systemctl status agent-wiki # confirm it's running
Edit User= to the account that owns the vault, and point ExecStart at your
installed awiki binary - run which awiki to find it (inside a uv venv it lives
in .venv/bin/awiki, not /usr/local/bin). Keep --bind/--port consistent with
how you terminate TLS in front of it (see below).
TLS
awiki serve speaks plain HTTP and binds to loopback by default. For remote access,
terminate TLS at a reverse proxy (nginx/Caddy) in front of it and point clients at the
HTTPS URL - the server itself does not manage certificates.
The viewer's session cookie is marked Secure when the request arrived over
https. Behind a proxy that ends TLS, every request reaches awiki serve as plain
http, so the server also counts X-Forwarded-Proto: https, but only from a
socket peer in auth_trusted_proxies (loopback by default), whether or not
auth_proxy is on. Have the proxy set that header, and list a proxy on
another host in auth_trusted_proxies; serve checks that list even with
auth_proxy off.
Remote client
On another machine, point the CLI at the server:
awiki init --remote https://wiki.example.com --token <secret>
awiki search "raft consensus" # transparently runs over HTTP
awiki init --clear # drop the remote config from this client
Local and remote vaults are mutually exclusive: setting one clears the other.
Switching between local and remote
Switching only rewrites the client config at ~/.config/agent-wiki/config.yaml -
it never reads, moves, or deletes vault files. Pointing a machine that already has a
local vault at a remote server is safe: the local vault stays on disk untouched, and
awiki simply routes commands to the server instead.
One sharp edge: the config is overwritten, not merged, so switching to remote
drops the vault_path pointer, and awiki init --clear only removes the remote
config (it does not restore vault_path). Because awiki init <path> refuses an
existing vault ("Vault already exists"), the way back to a local vault is to put the
vault_path line back in config.yaml. Back it up before switching so the return
trip is a one-liner:
cp ~/.config/agent-wiki/config.yaml ~/.config/agent-wiki/config.yaml.local-bak
awiki init --remote https://wiki.example.com --token <secret>
# ...later, to go back to the local vault:
cp ~/.config/agent-wiki/config.yaml.local-bak ~/.config/agent-wiki/config.yaml
Your local vault files are never destroyed by either direction of the switch - you
can also ingest them into the remote later with
awiki ingest <path-to-old-vault>/... (plain ingest uploads from the client;
sync/adapt are server-side - see below).
Server-host semantics
A few commands act on the server's machine, not the client's:
syncandadaptread the server's configured session directories and take server-side paths/refs - they do not see files on the client.hookis always local (it wires the client's agent CLI; there is no server hook).- Mutating operations serialize via per-vault file locks; under contention a request may return
503(the CLI surfaces this as "server busy, try again").
Roadmap
These are planned but not yet implemented:
- Smart ingestion - use
claude -por a local model to extract entities, generate cross-references, and decide which existing pages to update during ingest - Shared wikis - sync topics between personal and team wikis, with per-topic read/write permissions
- Additional agent support - AGENTS.md and wrappers for Cursor, Codex, and other agents
- Research agent - a dedicated agent that combines wiki search with web search, filing results back into the wiki automatically
- Auto-capture - agent notices high-value findings during conversations and suggests saving them (with user confirmation)
Install from source
From a checkout, with uv installed
(curl -LsSf https://astral.sh/uv/install.sh | sh):
uv tool install . # install `awiki` globally, from the repo root
uv tool install --reinstall . # update after pulling changes
uv tool uninstall agent-wiki-kb
pipx install . and pip install . work the same way if you prefer them.
To build distributables instead, uv build writes the wheel and sdist into
dist/; install the wheel anywhere with
uv tool install ./dist/agent_wiki_kb-<version>-py3-none-any.whl (no source
checkout needed).
Optional extras
- ripgrep (
rg) - search uses ripgrep when available, and falls back to a built-in Python scan. - pdfplumber - a permissive-licensed PDF extractor as an alternative to the default;
pip install 'agent-wiki-kb[pdf-permissive]'and setpdf_extractor: pdfplumberinwiki.yaml.
Development
uv venv && source .venv/bin/activate
uv pip install -e .
uv pip install pytest # tests are not in the dependencies
python -m pytest -v
Project structure
agent-wiki/
src/agent_wiki/
cli.py # Click CLI with all commands
config.py # user and vault config loading
vault.py # vault initialization
ingest.py # ingestion to raw/ + wiki page creation
fetch.py # URL fetch + extraction (HTML, PDF)
search.py # full-text search (ripgrep + Python fallback)
show.py # print a vault file by vault-relative path
index.py # rebuild index.md
lint.py # audit links, orphans, drift, frontmatter, tags
page.py # page model: frontmatter, slugify, wikilinks
tags.py # tag canonicalization engine
tag_yaml.py # comment-preserving wiki.yaml tags writer
tag_fix.py # whole-vault tag canonicalization
tag_suggest.py # vocabulary drafting from tags in use
context.py # auto-context hook: keyword extract, search, format
guide.py # the `awiki guide` block
doctor.py # schema drift inspection and repair
conversation.py # conversation bundle model
sync.py # adapter-driven conversation sync
summarize.py # optional LLM summarization backends
service.py # VaultService facade (local or remote)
remote.py # HTTP client for a served vault
server/ # HTTP server: API routes, users, grants, tokens, sessions (SQLite store)
viewer/ # read-only web viewer, sign-in and the user page
server_config.py # server.yaml: bind, port and reverse-proxy sign-in
locking.py # per-vault file locks
log.py # append-only activity log
redact.py # secret redaction on ingest
adapters/ # claude_code, opencode, pi, drop_zone
hooks/ # per-agent install backends (claude, pi, opencode, manual; managed_file shared)
data/guide.md # the canonical memory-file block
skills/ # bundled agent skills (package data)
tests/ # pytest suite
Doc/ # design notes and schemas
Design notes and schemas live in
Doc/; the release
history is in
CHANGELOG.md.
License
Metadata
Release files for agent-wiki-kb 0.13.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| agent_wiki_kb-0.13.2.tar.gz | 555.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agent_wiki_kb-0.13.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 788.0 kB
Release files / agent_wiki_kb-0.13.2.tar.gz
| Download URL | agent_wiki_kb-0.13.2.tar.gz |
|---|---|
| Size | 555.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b5093c4c8775be9596a6504a2890e34d060eaff17a6a7e132c74ef264f87aec5
|
|
BLAKE2b-256 checksum How to use checksums |
12ad006f1d00ebb3706217ff5b663c4df56c73faf0a6bee11fa88d06f16ac103
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Release files / agent_wiki_kb-0.13.2-py3-none-any.whl
| Download URL | agent_wiki_kb-0.13.2-py3-none-any.whl |
|---|---|
| Size | 232.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
681c3083f6ef418094bbf6f898f77dab9d4ba228d2288a2d2ac5d22547f41bbe
|
|
BLAKE2b-256 checksum How to use checksums |
4eb5301eb9f87943058b104e71fbf66666600e643b1fd2184c239c67b5bcea87
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|