Skip to content

Latest commit

 

History

62 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nark — Noah's Ark

Structured memory for AI agents. A local-first knowledge vault that stores markdown notes as content-addressed objects and indexes them in SQLite for fast search and browsing.

Install

From GitHub Releases

# macOS (Apple Silicon)
gh release download --repo SeanoChang/ironvault --pattern '*aarch64-apple-darwin'
chmod +x nark-* && mv nark-* ~/.local/bin/nark

# Linux
gh release download --repo SeanoChang/ironvault --pattern '*x86_64-unknown-linux-gnu'
chmod +x nark-* && mv nark-* ~/.local/bin/nark

From source

git clone https://github.com/SeanoChang/ironvault.git
cd ironvault
cargo build --release
ln -sf "$(pwd)/target/release/nark" ~/.local/bin/nark

Quick start

# Initialize the vault
nark init

# Write a note (full frontmatter)
nark write path/to/note.md

# Quick-capture a note (minimal ceremony)
nark jot --author noah --domain systems --body "CAS deduplication is automatic"

# Pre-session vault briefing (markdown output for agent context)
nark orient "systems architecture" --limit 5

# Search for notes
nark search "capability tokens"
nark search --domain finance --since 7d

# Browse the knowledge tree
nark ls
nark ls systems/build/spec

# Quick research — search + body previews
nark about "BLAKE3 hashing"

# Inspect a note's metadata
nark peek <note-id>

# Read full note content
nark read <note-id>

# Edit an existing note
nark edit <note-id> append --body "New section content"
nark append <note-id> "Quick append shortcut"

Commands

Orientation & Search

Command What it does Cost
nark orient <query> [--domain] [--kind] [--tag] [--since] [--before] [--limit] Pre-session vault briefing — outputs markdown for agent context injection Medium — registry + vault reads
nark search <query> [--domain] [--kind] [--intent] [--tag] [--since] [--before] Ranked search (BM25 + cosine + graph) Cheap — registry only
nark search <query> --bm25 BM25-only mode — skip cosine and graph Cheap — registry only
nark search <query> --semantic Semantic mode — bypass BM25, cosine against all notes Medium — needs embeddings
nark about <topic> [--since] [--before] [--limit] Search + body previews in one call Medium — registry + vault reads
nark related <id> [--limit] [--link] Find similar notes by embedding similarity Medium — needs embeddings
nark stats Vault overview — counts, distributions, recent notes Cheap — registry only
nark ls [path] [--tags] Browse domain/intent/kind tree Cheap — registry only

Reading

Command What it does Cost
nark peek <id> Note metadata (title, domain, tags, etc.) Cheap — registry only
nark read <id> Full note content (frontmatter + body) Heavy — vault CAS read

Writing

Command What it does Cost
nark jot --author <author> [--domain] [--body] [--from <id>] Quick-capture a note with minimal ceremony Write — vault + registry
nark write <paths...> [--auto-link] Ingest markdown notes from files/directories/stdin Write — vault + registry
nark edit <id> <operations...> [--auto-link] Surgical edits (replace, append, prepend, set) — creates MVCC version Write — vault + registry
nark append <id> [body] Append content to a note (shortcut for edit append) Write — vault + registry

Organization

Command What it does Cost
nark tag <id> +add -remove Add/remove tags without creating a new version Write — registry only
nark tag --domain <d> +tag [--confirm] Bulk tag by filter (dry-run by default) Write — registry only
nark tag --list List all tags with usage counts Cheap — registry only
nark tag --find <tags...> Find notes by tag (AND logic) Cheap — registry only
nark link <sources...> --target <id> [--rel <type>] Create typed links between notes Write — vault + registry
nark links <id> Show a note's link neighborhood Cheap — registry only

History

Command What it does Cost
nark history <id> List version chain for a note Cheap — registry only
nark diff <id> [--from <ver>] [--to <ver>] Compare two versions (unified diff) Medium — vault reads
nark rollback <id> <version-id> Restore an old version as new head Write — vault + registry

Lifecycle

Command What it does Cost
nark delete <ids...> [-f] [-rf] Soft-delete (retract), hard-delete, or full purge Write — registry (+ vault for -rf)
nark retract [ids...] [--domain] [--kind] [--tag] [--since] [--before] [--confirm] Bulk soft-delete by filter or ID Write — registry only

Setup & Maintenance

Command What it does Cost
nark init Create vault dirs + registry database One-time setup
nark embed init Download ONNX Runtime + nomic-embed-text-v1.5 model Setup
nark embed build Backfill embeddings for all notes Write — registry only
nark embed migrate Upgrade from bge to nomic (download + cleanup + re-embed) Setup + Write
nark reset [--confirm] Destroy and recreate registry (vault objects kept) Destructive
nark update Download latest release binary from GitHub Maintenance

Agent workflow

orient → search/ls → peek → read → write/jot
  brief     cheap      cheap   heavy   write

Start with a briefing, search to narrow down, commit to reading only what matters.

Note format

Notes are markdown files with YAML frontmatter:

---
title: "CAS Write Discipline"
author: "noah"
domain: "systems"
intent: "build"
kind: "spec"
trust: "verified"
status: "active"
tags: ["cas", "storage", "blake3"]
aliases: ["CAS", "content-addressed store"]
---
# CAS Write Discipline

Content goes here...

Frontmatter fields

Field Purpose Values
domain Knowledge area Free text (e.g. systems, security, finance, ai_ml)
intent Why it exists Free text (e.g. build, debug, operate, research)
kind What it is Built-in (spec, decision, runbook, report, reference, incident, experiment, dataset) + config extras
trust Confidence level hypothesis, reviewed, verified
status Lifecycle state active, deprecated, retracted, draft
tags Free-form labels Any lowercase alphanumeric + hyphens
aliases Search synonyms (3x FTS5 weight) Free-form strings, optional

Domain and intent are free text. Kind accepts built-in values plus any extras defined in config.toml. Trust and status are enforced enums. Tags and aliases are optional (default to []).

Architecture

~/.ark/
├── config.toml          # Optional — search tuning knobs
├── registry.db          # SQLite — indexes, FTS5, edges, embeddings
├── objects/
│   ├── fm/              # Content-addressed frontmatter (YAML)
│   └── md/              # Content-addressed bodies (Markdown)
├── notes/
│   └── <note-id>/
│       ├── head         # Current version pointer
│       └── versions/    # Version history (.ref + .json)
├── onnxruntime/         # ONNX Runtime dylib (nark embed init)
├── models/
│   └── nomic-embed-text-v1.5/  # Embedding model (nark embed init)
└── tmp/                 # Atomic write staging
  • Content-addressed storage — files stored by BLAKE3 hash. Deduplication is automatic.
  • Append-only versions — every write creates a new version. Old versions are never overwritten.
  • SQLite registrycurrent_notes materialized view for fast queries, note_text FTS5 table for search, note_versions for history, note_edges for typed links, note_embeddings for vector search.

Search pipeline

Search runs a 6-step ranked pipeline:

pre-filter → BM25 candidates → graph expand → cosine rank → blend → threshold
  1. Pre-filter — apply --domain, --kind, --intent, --tag filters
  2. BM25 candidates — FTS5 full-text search returns top-k candidates (recall, not ranking)
  3. Graph expand — follow note edges to discover related notes not in the BM25 set
  4. Cosine rank — score candidates against the query embedding (primary ranking signal)
  5. Blend — combine three signals: cosine * 0.50 + graph * 0.25 + activation * 0.25
  6. Threshold — drop results below the minimum score, return top-n

The pipeline degrades gracefully:

  • No embeddings, no graph — BM25 rank + activation only
  • No embeddings, with graph — graph scores + activation only
  • Full pipeline — all three signals blended

Search modes

Flag Mode What it does
(default) Normal Full 6-step pipeline
--bm25 BM25-only Skip cosine + graph. Fast exact-term search.
--semantic Semantic Bypass BM25, cosine against all notes. Requires embeddings.

--bm25 and --semantic are mutually exclusive.

FTS5 syntax

nark uses SQLite FTS5. Plain words work, but you can also use:

Syntax Example Meaning
plain words BLAKE3 hashing Both words must appear (implicit AND)
"phrase" "content addressed" Exact phrase match
OR BLAKE3 OR SHA256 Either word
NOT BLAKE3 NOT deprecated Exclude matches
column: title:BLAKE3 Match in specific column
prefix* blake* Prefix match

Edges

Notes can be linked with typed, weighted edges:

Edge type Weight Direction Meaning
references 1.0 bidirectional General citation
depends-on 2.0 bidirectional Hard dependency
supersedes 3.0 old → new only Replacement (directional)
contradicts 1.5 bidirectional Conflicting information
extends 1.5 bidirectional Builds upon
informed-by 1.0 bidirectional Loosely inspired by

Edges are created via frontmatter links: fields or the nark link command. Graph expansion during search uses these edges to surface related notes.

Embeddings

Embeddings are optional but unlock cosine-ranked search and semantic mode.

# Download ONNX Runtime + nomic-embed-text-v1.5 model
nark embed init

# Backfill embeddings for all notes
nark embed build

# Upgrading from bge-base-en-v1.5? One command handles everything:
nark embed migrate

By default, embeddings are computed locally via ONNX (no API calls). Optionally, configure OpenAI as the embedding provider in config.toml:

[embedding]
provider = "openai"                    # default: "local"
api_model = "text-embedding-3-small"   # optional override

Requires OPENAI_API_KEY in the environment. Without embeddings, search falls back to BM25 + activation scoring.

Configuration

Place a config.toml in your vault directory (~/.ark/config.toml). All fields are optional — missing values use defaults.

[embedding]
provider = "local"    # "local" (ONNX) or "openai"
# api_model = "text-embedding-3-small"  # only used when provider = "openai"

[search]
threshold = 0.10      # minimum score to return a result
top_n = 20            # max results

[search.bm25]
top_k = 100           # BM25 candidate pool size
weight_title = 5.0    # FTS5 column weights
weight_body = 1.0
weight_spine = 2.0
weight_aliases = 3.0
weight_keywords = 10.0

[search.weights]
cosine = 0.50         # blend weights (must sum to 1.0)
graph = 0.25
activation = 0.25

[search.graph]
decay = 0.5           # graph score decay per hop
max_hops = 1          # max graph traversal depth
respect_domain_filter = false  # restrict graph expansion to filtered domain

Release

# Manual release (current platform only)
./scripts/release.sh 0.1.0

# Automated: push a tag to trigger CI builds for all platforms
git tag -a v0.1.0 -m "Release v0.1.0"
git push origin v0.1.0

About

Structured memory vault for AI agents — local-first, content-addressed, SQLite-indexed

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages