tapper - page.html
tapper is a Go command-line tool for managing Knowledge Exchange Graphs (KEGs) — a file-based, graph-style knowledge system where every note is a numbered node with stable links to other nodes.
It grew out of custom shell scripts (zet) originally inspired by the zettelkasten method of networked note-taking. The goal was a system that didn’t fight you for capturing and retrieving information, didn’t lock you into a platform, and could be queried and extended programmatically.
What is a KEG?
A KEG is a directory of numbered nodes. Each node is a folder (docs/123/) containing:
README.md— the note content, with links to other nodes using stable IDs ([Related](../456))meta.yaml— hand-edited metadata: tags and any entity-specific attributesstats.json— machine-managed usage data: created/updated timestamps, access time, access count; written only by the CLI, never edited by hand
A keg config file at the root registers indexes, aliases, and tag definitions. Indexes (under dex/) are regenerated deterministically from node metadata — things like nodes.tsv, per-tag indexes, and backlinks. This makes the graph queryable by both humans and tools.
Entities and typed nodes
Each KEG defines its own set of entity notes - canonical nodes that act as schemas for a particular type of content. When a node declares an entity type in its meta.yaml, it signals that it follows the structure defined by that entity note. You can think of it as a loose type system for notes: a project node is expected to have certain sections, a guide node has a particular shape, and so on.
This is a deliberate evolution from the original zet approach, where everything was flat. Entities give each KEG its own ontology — a vocabulary of node types that makes the graph predictable enough to query and automate against as it scales into the thousands of nodes.
I maintain several KEGs: pub (public notes), priv (private notes), and ecw (work notes).
Why I built it
The zettelkasten approach solves a real problem: most note tools (Notion, Obsidian) impose their own format, make syncing awkward, and aren’t designed to be queried by code. A KEG is just files and folders — easy to version-control, easy to read, and easy to automate against.
Over time I realised this structure was a natural fit for something beyond personal notes: persistent memory for AI agents. Because each node is a plain-text file with structured metadata and stable IDs, an AI can query, create, and link nodes using the same CLI commands a human would use. I now use my KEGs to pass notes and context between AI sessions — a way to give agents durable, cross-session memory without needing a database.
How it works in practice
Work naturally organises into chains of linked nodes. A task note describes the goal and tracks time; a plan note lays out the implementation steps and known risks; patch notes record each individual code change with its diff and QA checklist. Because every node links to related nodes by stable ID, you can navigate the whole thread — from the original request through every decision and change — without anything getting lost.
# Before starting, check whether a relevant node already exists.
tap tags --query "seo and product-listing"
tap grep "product listing"
# Read an existing node to get context.
tap cat 2087 # task: "Product tables loading in DOM"
# A task arrives. Create a new node, open it for editing.
tap create
tap edit 2107
# Before writing code, draft a plan node linked to the task.
tap create
tap edit 2065 # plan: implementation steps, risks, key files
# Each code change gets its own patch node linked back to the plan.
tap create
tap edit 2088 # patch: diff + QA checklist
# Later, trace what else touched this plan.
tap backlinks 2065The tool resolves KEGs by alias (pub, priv, ecw) via a layered YAML config — local, project-level, and global scopes are all supported.
Technical details
- Go + Cobra — CLI framework for subcommands and flag parsing
- cli-toolkit — foundational utilities for file I/O, logging, and context management
- YAML config with node/AST preservation — configuration edits preserve existing comments and formatting
- Atomic file writes — all node and config writes are atomic to prevent corruption
- Layered config — global, project, and local config scopes with well-defined precedence
What’s coming
The file-based backend works well for a single user, but sharing a KEG across a team requires everyone to have filesystem access to the same repo. An API-based backend is in progress to replace this - same node model, same CLI interface, but reads and writes go through an HTTP API instead of the local filesystem. This makes it straightforward for multiple people or multiple agents to collaborate on a shared knowledge base without needing a shared mount or a git-pull workflow.
AI integration is also expanding. Currently, AI agents interact with tapper through skills - structured prompts that describe how to call the CLI to query, create, and link nodes. An MCP server is in the works, which will let agents talk to tapper directly over the Model Context Protocol rather than shelling out to the CLI.