@justestif/pk
v0.13.0
Published
Project knowledge — structured intake, search, and recall
Downloads
287
Readme
pk
Structured project memory for AI agents. Decisions, questions, notes, and sources — organized, searchable, stored locally.
Install
CLI
One-liner (macOS / Linux):
curl -fsSL https://justestif.github.io/pk/install.sh | bashOr manually:
# npm
npm install -g @justestif/pk
# bun
bun install -g @justestif/pk
# Homebrew
brew install justEstif/tap/pkRequires:
Note: If you have GPG commit signing enabled globally (
commit.gpgsign=true),pk initbypasses it for the knowledge repo to avoid interactive prompts. No configuration needed.
Setup
pk initTip: You can override the knowledge directory at any time by setting
PK_KNOWLEDGE_DIRin your shell or a.envfile your shell loads:export PK_KNOWLEDGE_DIR=~/.pk/my-projectAll pk commands read this variable directly — no re-init needed. This is also how you switch between projects without changing harness config.
Interactive: picks a project name and one or more harnesses (space to toggle, enter to confirm).
Non-interactive:
pk init --harness opencode # local: knowledge in .pk/ (default)
pk init my-project --harness opencode --global # global: knowledge in ~/.pk/my-project/
pk init my-project --harness opencode,pi --global # multiple harnessesAvailable harnesses: opencode (OpenCode), pi (Pi).
pk init does four things:
- Creates the knowledge store — in
.pk/(local, default) or~/.pk/<name>/(with--global) - Writes config: local mode creates
.pk/config.jsonin the project; global mode setscurrentProjectin~/.pk/config.json - Adds
.pk/to your project's.gitignore(local mode only) - Installs plugin/extension and skill to global locations (
~/.config/opencode/plugins/,~/.pi/agent/extensions/,~/.agents/skills/pk/)
| Harness | Files written (global) |
| ----------------- | ------------------------------------------------------------------------------ |
| opencode | ~/.config/opencode/plugins/pk-eval.ts |
| pi | ~/.pi/agent/extensions/pk-eval.ts |
| both | ~/.agents/skills/pk/ |
Override:
PK_KNOWLEDGE_DIRenv var takes precedence over all resolution. For persistent switching, usepk use <name>.
Commands
pk init [name] [--harness h1,h2,...] # set up project + global harness
pk use <name> # set current global project
pk projects # list global projects
pk new <type> <title> [--tags t1,t2] [--expires YYYY-MM-DD]
pk delete <path> # JSON output, non-interactive
pk search <query> [--limit 5] [--type] [--status] [--tag]
pk gc [--dry-run] [--compress] # lifecycle: decay + expiry + compress
pk synthesize [query] [--all]
pk history [--limit 20] [--type <type>] [--filter-type <type>] [--filter-tag <tag>] [--filter-operation <op>]
pk read <path>
pk write <path> # write content from stdin + commit
pk vocab
pk index # rebuild FTS5 + markdown indexes
pk lint [paths...]
pk prime # output priming context for hooks
pk instructions <command>
pk config [--embedding <model>] [--no-embedding] [--base-url <url>]All commands output JSON by default. Use --pretty for human-readable output.
Note types
| Type | Purpose |
| ---------- | -------------------------------------------------- |
| note | Durable project knowledge |
| decision | Chosen direction with rationale and consequences |
| question | Unresolved uncertainty that blocks or informs work |
| source | Raw input preserved for provenance |
| index | Navigation/map-of-content over a topic or tag |
Example
pk init --harness opencode
pk new decision "Use SQLite for search index" --tags search,architecture
pk new question "Should we support multi-project mode?" --tags scope
pk index
pk search "sqlite"
pk synthesizeLifecycle
Knowledge has a lifecycle. Notes decay, expire, and get superseded.
- Decay: notes not accessed fade over time (exponential decay, 30-day half-life).
pk gcarchives notes below threshold. - Expiry:
pk new note "Title" --expires 2026-12-31adds an expiry date.pk gcarchives expired notes automatically. - Compression:
pk gc --compressidentifies similar/duplicate notes (Jaccard similarity ≥ 0.5 within same type) and detects near-duplicate tags (plural variants, edit distance ≤ 2). Tag normalization is applied automatically — variants are replaced with the canonical (most-used) form. Similar note pairs are reported for manual review. Use--dry-runto preview without changes. Run weekly. - Contradictions: when new knowledge supersedes old, mark the old note
status: supersededand link to the new one.pk lintwarns on high-overlap note pairs.
# Daily: decay scoring + archive stale + purge expired
pk gc
# Weekly: find similar notes for merge
pk gc --compress
# Preview without changes
pk gc --dry-run --prettyConfigure decay speed: PK_DECAY_HALF_LIFE=30 (default, days).
Knowledge structure
Notes live as plain markdown files — human-editable and git-diffable.
Agents read and write them exclusively through the CLI. Humans can edit files directly, but should run pk write <path> < <file> or commit manually afterward to keep the git history clean.
Local (default — .pk/ in your project):
your-project/
.pk/
notes/
decisions/
questions/
sources/
indexes/ ← generated by pk index
.index.db ← FTS5 search index, gitignored
config.json ← points to this knowledge storeGlobal (--global — shared across machines, survives project moves):
~/.pk/
config.json ← currentProject: which global project is active
<project-name>/
notes/ decisions/ questions/ sources/ ...Run pk index after creating or editing notes to update .index.db and indexes/.
pk vocab lists all tags by frequency — useful for orienting before searching.
pk history shows all knowledge operations (create, update, delete) as git commits and synthesize operations as git notes. Supports filtering by type, tag, and operation.
Embeddings (optional)
pk can generate embeddings via a local Ollama model and store them alongside the FTS5 index. Once configured, pk search automatically uses hybrid search — BM25 keyword ranking fused with vector similarity via RRF.
# Install Ollama — https://ollama.com
ollama pull nomic-embed-text
# Enable embeddings
pk config --embedding nomic-embed-text
# Rebuild index to generate embeddings
pk index
# Search now uses hybrid automatically
pk search "slow database queries"Embeddings are stored in .index.db and rebuilt on pk index. If no embedding model is configured, search falls back to keyword-only FTS.
License
MIT
