✨ aver

A Versioned Knowledge Tracking Tool
A Quest for the Perfect Record

In an age of crumbling servers, forgotten spreadsheets, and SaaS subscriptions that devoured kingdoms… a fellowship arose in search of a better way.

A mystical library archive with candlelit tomes, ancient scrolls, and an ornate desk with open ledgers
The Archive Eternal β€” where knowledge dwells

Prologue: The Problem in the Realm

Across the lands, many orders struggled:

The sages all agreed:

"There must be a way to keep structured records…
With history… with search…
Without summoning a server daemon."

Thus began the quest.

The Fellowship of Seekers

Each hero came from a different discipline, seeking the same tool: a system to version and track evolving knowledge over time β€” safely, portably, and without dark magic.

Lyra Quillshade β€” Bard of the Publishing Guild

Lyra's struggles were many:

  • Manuscripts full of continuity errors
  • Fact-checking notes lost in margins
  • Editorial decisions trapped in comment threads
  • Versions of drafts scattered across realms

She sought:

"A living ledger of story issues, where every note is remembered, every revision traced, and nothing is locked in cursed proprietary scrolls."

She found a tool where each Record could be a continuity issue, a fact-check request, a layout problem, or a rights questionβ€”each tied to chapters, characters, and drafts, searchable forever.

Lyra wept (poetically).

Null Pointer β€” Rogue Software Bounty Hunter

Null had hunted bugs in many kingdoms:

  • Ticket systems that required tribute (monthly billing cycles)
  • Platforms that vanished, taking issues with them
  • Tools that could not travel offline
  • Histories hidden behind glass dashboards

Null wanted:

"Plain text. Full history. No gatekeepers."

He found a tool where every issue lived as a file, every change was recorded in Git history, search was fast and local, and no server dragon needed feeding.

Null nodded once. High praise.

Dr. Aria Voss β€” Scientific Sorcerer of the Seventh Lab

Aria tracked experimental anomalies, equipment misbehavior, environmental drift, and observations that did not fit the model. Her previous tools were spreadsheets of despair, notebooks of entropy, and institutional systems that no one maintained.

She needed:

"A versioned, searchable lab logbook that speaks both human and machine."

With structured metadata, she could now ask: "Show all runs where temperature > 37Β°C" or "All anomalies involving centrifuge-3." Her lab notes became queryable history.

The data spirits were appeased.

Toren Steelhand β€” Field Engineer of the Outer Works

Toren maintained machines older than some empires, equipment in places where the signal bars went to die, and logs written on clipboards and later forgotten.

He required:

"A rugged log that works offline, syncs when it can, and doesn't demand a glowing web altar."

He found records stored locally, synced through Git when back in civilization, with structured fields for pressure, temperature, batch, and shift. For the first time, field notes and central history matched.

Toren approved with a single grunt.

Elarion the Infinite β€” World-Building Deity & Dungeon Master

Elarion ruled a sprawling world with hundreds of NPCs, dozens of unresolved plot threads, and players who delighted in derailing destiny. He lamented:

"I cannot remember what happened 14 sessions ago in the ruined city of Valemire."

With the tool, each Record became a quest, an NPC arc, a world event, or a faction scheme. Each session added Notes. He could now ask: "All active quests in the Ashlands" or "NPCs currently hostile to the party." Canon was preserved. Retcons were minimized. Chaos remained… but documented.

Canon was upheld.

The Artifact They Discovered

At journey's end, the fellowship uncovered not a cloud platform, nor a SaaS throne… but something older. Simpler. Stronger.

✨ aver: A Versioned Knowledge Tracking Tool

A tool that provides:

  • Plain-text records (human-readable, future-proof)
  • Structured metadata (queryable, sortable)
  • Full version history (via Git)
  • Fast local search (via SQLite index)
  • No required server
  • Rebuildable index from source files

What This Tool Is

A file-native system for tracking structured records with history and search. Used for software issues, research logs, engineering deviations, editorial tracking, campaign lore, and any evolving body of knowledge that deserves to be versioned and remembered.

What It Is Not

It is a versioned record, not a command center.

Epilogue

And so the heroes returned to their domains: the Bard with her manuscripts, the Rogue with his bugs, the Sorcerer with her experiments, the Engineer with his machines, the Deity with their world. All carrying the same artifact.

A simple truth, etched into plain text:

What matters should be recorded.
What is recorded should be searchable.
What is searchable should endure.

aver awaits your first entry.

Quick Start: Get Up and Running in Minutes

This guide will get you started with Aver quickly. For comprehensive documentation, see the full manual.

Aver Quick Start Guide

What is Aver?

Aver is a lightweight knowledge tracking tool that stores structured data in plain Markdown files. Think of it as a flexible issue tracker, note-taking system, or knowledge base where your data stays readable and portable.

Key Concept: Aver manages records (the things you're tracking) and notes (chronological updates to those records). Everything is stored as text files with YAML frontmatter for metadata.

The Sovereignty Advantage: A single git commit can include both the fix and the updated status of the record creating an Atomic History. 100 years from now, someone can check out your repository and see not just how the code changed, but the exact context of the decision, all without needing an API key for a defunct service.

Installation


# Install dependencies
pip install pyyaml tomli tomli_w

# Make executable and add to PATH
chmod +x aver.py
sudo ln -s /path/to/aver.py /usr/local/bin/aver

Basic Workflow

1. Initialize a Database


cd /path/to/your/project
aver admin init

This creates:

2. Set Your User Info


aver admin config set-user --handle yourname --email [email protected]

3. Create Your First Record


aver record new --title "Fix login bug" --status open

This opens your editor (set via $EDITOR) with a template. Save and close to create the record.

4. Add a Note to the Record


aver note add REC-001 --message "Investigated - issue is in auth module"

5. Search and List


# List all records
aver record list

# Search by field
aver record search --ksearch status=open

# View a specific record
aver record view REC-001

# List notes for a record
aver note list REC-001

Understanding Fields

Aver has two types of fields:

Special Fields (Configured)

Example: title, status, created_by, author

Custom Fields (Ad-hoc)

Example: --text server=web-01 --number port=8080

Common Commands

Records


# Create with editor
aver record new

# Create with fields
aver record new --title "Task name" --status open --priority high

# See available fields for your config
aver record new --help-fields

# Update a record
aver record update REC-001 --status closed

# Import from file
aver record new --from-file record.md

Notes


# Add with editor
aver note add REC-001

# Add with message
aver note add REC-001 --message "Fixed and tested"

# See available fields for this record's notes
aver note add REC-001 --help-fields

# Search notes
aver note search --ksearch category=bugfix

Templates (Optional but Powerful)

Templates let you define different field sets for different record types. For example:

Bug Template (config.toml):


[template.bug]
record_prefix = "BUG"
note_prefix = "COMMENT"

[template.bug.record_special_fields.severity]
type = "single"
value_type = "integer"
accepted_values = ["1", "2", "3", "4", "5"]
default = "3"

[template.bug.note_special_fields.category]
type = "single"
value_type = "string"
accepted_values = ["investigation", "bugfix", "workaround"]

Usage:


# Create bug with custom ID prefix
aver record new --template bug --title "App crashes on login" --severity 2

# Add categorized note
aver note add BUG-001 --message "Root cause found" --category investigation

File Structure


project/
β”œβ”€β”€ .aver/
β”‚   β”œβ”€β”€ aver.db          # SQLite index (ignore in Git)
β”‚   └── config.toml      # Your field definitions
β”œβ”€β”€ records/
β”‚   β”œβ”€β”€ REC-001.md       # A record
β”‚   └── BUG-042.md       # Another record
└── updates/
    β”œβ”€β”€ REC-001/
    β”‚   β”œβ”€β”€ NT-001.md    # A note
    β”‚   └── NT-002.md    # Another note
    └── BUG-042/
        └── COMMENT-001.md

Record file (REC-001.md):


---
title: Fix login bug
status: open
priority: high
created_by: alice
created_at: 2024-02-15 10:30:00
---
Users cannot log in when using special characters in password.
Affects approximately 5% of users.

Note file (NT-001.md):


---
author: alice
timestamp: 2024-02-15 11:00:00
category: investigation
---
Investigated the issue. Found that password validation
is incorrectly escaping special characters.

Configuration Basics

Edit .aver/config.toml to define your special fields:


# Default ID prefixes
default_record_prefix = "REC"
default_note_prefix = "NT"

# Global record fields (apply to ALL records)
[record_special_fields.title]
type = "single"
value_type = "string"
editable = true
enabled = true
required = true

[record_special_fields.status]
type = "single"
value_type = "string"
editable = true
enabled = true
required = true
accepted_values = ["open", "in_progress", "closed"]
default = "open"

[record_special_fields.created_by]
type = "single"
value_type = "string"
editable = false
enabled = true
required = true
system_value = "user_name"  # Auto-populated

# Global note fields (apply to ALL notes)
[note_special_fields.author]
type = "single"
value_type = "string"
editable = false
enabled = true
required = true
system_value = "user_name"  # Auto-populated

[note_special_fields.timestamp]
type = "single"
value_type = "string"
editable = false
enabled = true
required = true
system_value = "datetime"  # Auto-populated

Key Tips

  1. Use --help-fields to discover what fields are available:

aver record new --help-fields

aver note add REC-001 --help-fields

```

  1. Records and notes have different fields - Notes can track different information than their parent records.
  1. Special fields are validated - The system won't let you set status=invalid if it's not in accepted_values.
  1. System values are automatic - Fields like author, timestamp, created_by are auto-populated.
  1. Everything is plain text - You can edit files directly, use grep, and version control with Git.
  1. Reindex after manual edits:

aver admin reindex

```

Multiple Projects (Libraries)

Work with multiple databases:


# Add library aliases
aver admin config add-alias --alias work --path ~/work/aver-db
aver admin config add-alias --alias personal --path ~/personal/aver-db

# Use them
aver --use work record list
aver --use personal record new --title "Personal task"

Next Steps

Quick Reference

Task Command
Initialize database aver admin init
Set user aver admin config set-user --handle name --email email
Create record aver record new --title "..." --status open
List records aver record list
Search records aver record search --ksearch status=open
Add note aver note add REC-001 --message "..."
List notes aver note list REC-001
Search notes aver note search --ksearch category=bugfix
Show available fields aver record new --help-fields
Show note fields aver note add REC-001 --help-fields
Reindex aver admin reindex

Remember: Your data is just Markdown files. You can always read, edit, or process them with any text tool. Aver just adds structure, validation, and fast searching on top.

The User Manual: A Complete Guide

This manual provides comprehensive documentation for Aver, the versioned knowledge tracking tool. From installation to advanced features, everything you need to know is contained within.

Aver: A Versioned Knowledge Tracking Tool

User Manual - Updated Edition

Table of Contents

1. Introduction

2. Getting Started

3. Core Concepts

4. Working with Records

5. Working with Notes (Updates)

6. Special Fields System

7. Configuration and Templates

8. Advanced Features

9. Command Reference

10. Administrator's Guide

1. Introduction

What is Aver?

Aver (pronounced "AH-ver") is a lightweight, flexible knowledge tracking tool designed to help you organize, track, and search through structured information. At its core, Aver manages records (primary items you're tracking) and notes (chronological updates to those records).

Unlike traditional database systems that lock your data away in proprietary formats, Aver stores everything in plain Markdown files with YAML frontmatter. This means your data is always readable, portable, and easy to work with using standard text tools. SQLite is used only for indexing and searchingβ€”your actual data lives in files you can read, edit, and version control.

Why Use Aver?

Human-Readable Storage: Every record and note is stored as a Markdown file. You can read them with any text editor, search them with grep, and track changes with Git.

Flexible Metadata: Aver supports two types of fields:

Fast Searching: Despite using plain text files, Aver maintains a SQLite index that enables lightning-fast searches across thousands of records.

Template System: Define record and note templates with their own special fields, enabling different workflows for different types of records (bugs, features, experiments, etc.).

Git-Friendly: Because everything is text files, your entire database works beautifully with version control.

Offline-First: No internet required. No cloud dependencies. Your data stays on your machine.

Key Features

How It Works

Aver uses a three-layer architecture:

1. Storage Layer (Markdown Files)

2. Index Layer (SQLite)

3. Application Layer (Python CLI)

3. Core Concepts

Records vs Notes (Updates)

Records are the primary entities you're tracking. Each record represents one "thing" in your system:

Notes (also called updates) are chronological entries attached to a record. They represent changes, observations, or progress:

Records and notes can have completely different sets of special fields, allowing notes to track different information than their parent records.

Special Fields vs Custom Fields

Special Fields are predefined in your configuration:

Custom Fields are ad-hoc key-value pairs:

Example:


---
# Special fields (no type hints)
title: Database Connection Error
status: open
priority: high
created_by: alice
created_at: 2024-02-15 10:30:00

# Custom fields (with type hints)
server_ip__string: 192.168.1.100
retry_count__integer: 5
---

Templates

Templates define:

  1. ID Prefixes: Custom prefixes for records (BUG-, FEAT-) and notes (COMMENT-, FEEDBACK-)
  2. Special Fields: Template-specific fields that add to or override global fields
  3. Content Templates: Pre-filled text for records and notes

Templates allow you to have different field sets for different types of records. For example:

4. Working with Records

Creating a New Record

Basic creation (opens editor):


aver record new

With special fields (if defined in config):


aver record new --title "Cannot connect to database" --status open --priority high

Using a template:


aver record new --template bug --title "Login fails" --severity 3

With custom fields:


aver record new --title "Server down" --text location=us-west-2 --number error_code=500

From a file:


aver record new --from-file bug-report.md

With a custom record ID:


aver record new --use-id MY-CUSTOM-ID --title "Custom ID record"

The ID must use only A-Z, a-z, 0-9, _, and -, and must be unique. If omitted, an ID is auto-generated.

Using --help-fields for Records

To see what special fields are available for records:

Global fields:


aver record new --help-fields

Template-specific fields:


aver record new --template bug --help-fields

This shows:

Example output:


Available fields for record creation (template: bug):

  title (single, string)
    Required

  status (single, string)
    Required
    Accepted: new, confirmed, in_progress, fixed, verified, closed
    Default: new

  severity (single, integer)
    Required
    Accepted: 1, 2, 3, 4, 5
    Default: 3

  priority (single, string)
    Accepted: low, medium, high, critical
    Default: medium

  tags (multi, string)

Usage:
  aver record new --template bug --title "..." --status new --severity 3

5. Working with Notes (Updates)

Adding a Note

Basic note (opens editor):


aver note add REC-001

With message:


aver note add REC-001 --message "Investigated issue, found root cause in auth module"

With special fields (if note fields defined):


aver note add BUG-042 --message "Applied fix" --category bugfix --priority critical

From a file:


aver note add BUG-042 --from-file investigation-notes.md

Using --help-fields for Notes

Notes can have their own special fields, different from records. To see available note fields for a specific record:


aver note add BUG-042 --help-fields

Example output:


Available fields for BUG-042 (template: bug):

  category (single, string)
    Accepted: investigation, bugfix, workaround, regression, documentation

  priority (single, string)
    Accepted: low, medium, high, critical
    Default: medium

Usage:
  aver note add BUG-042 --category=investigation --priority=high
  aver note add BUG-042 --message 'Found it' --category=bugfix

Important: Note fields are template-specific and inherit from:

  1. Global note_special_fields (like author, timestamp)
  2. Template's note_special_fields (like category, priority)

Viewing Notes


aver note list BUG-042

Searching Notes

Search notes by their special fields:


# Search by note field
aver note search --ksearch category=bugfix

# Search by priority
aver note search --ksearch priority=critical

6. Special Fields System

Understanding Special Fields

Special fields are the heart of Aver's structured data system. They provide:

Record Special Fields

Record special fields are defined globally and can be overridden by templates. Common examples:

System-populated fields:

User-defined fields:

Note Special Fields

Notes have their own special fields, completely independent from record fields:

Global note fields (apply to all notes):

Template-specific note fields (only for notes in templated records):

Key insight: When you add a note to a bug record, the note gets:

System Values

System values automatically populate special fields:

System Value Description Example
datetime Full timestamp 2024-02-15 10:30:00
datestamp Date only 2024-02-15
user_name User handle alice
user_email User email [email protected]
recordid Record ID BUG-042
updateid Note ID COMMENT-001
template_id Template name bug
is_system_update 1 for system-generated notes, 0 for user notes 1

Configuration example:


[record_special_fields.created_by]
type = "single"
value_type = "string"
editable = false
enabled = true
required = true
system_value = "user_name"
index_values = true

Field Properties

Each special field has these properties:

type: single or multi

value_type: string, integer, float, or securestring

editable: true or false

enabled: true or false

required: true or false

index_values: true or false (default: true)

system_value: System value source (optional)

accepted_values: List of valid values (optional)

default: Default value (optional)

Default Values

Defaults can be static or dynamic:

Static default:


[record_special_fields.priority]
type = "single"
value_type = "string"
default = "medium"

Dynamic default (references system value):


[note_special_fields.created_date]
type = "single"
value_type = "string"
default = "${datestamp}"

Secure Fields (securestring)

Aver supports a special value_type = "securestring" for fields that contain sensitive data like passwords, API keys, and authentication tokens.

How it works:

Configuration example:


[record_special_fields.api_token]
type = "single"
value_type = "securestring"
editable = true
enabled = true
required = false

Usage:


# Set a secure field value on creation
aver record new --api_token mysecretkey123

# View record β€” secure field shown as mask
aver record view REC-001
#   api_token: {securestring}

# Search by exact value (works even though display is masked)
aver record list --ksearch api_token=mysecretkey123

# Search using IN-list
aver record list --ksearch 'api_token^key1|key2|key3'

# Exclude by value
aver record list --ksearch api_token!=mysecretkey123

Editor behavior for editable securestring fields: When you open a record in the YAML editor, the field appears as {securestring}. If you leave it unchanged, the original value is preserved. To update it, replace the mask with the new value.

Non-editable securestring fields: Fields with editable = false can be set at creation time and cannot be changed afterward. They are never shown in the editor.

Security note: Plaintext values are stored in Markdown files and indexed in SQLite. Aver's masking is a display-layer feature to prevent accidental exposure in terminal output, logs, and exports. If you need true encryption at rest, consider encrypting the database directory.

System-Generated Notes (is_system_update)

Aver automatically creates notes on your behalf in two situations:

  1. Record creation β€” an initial note is created when a new record is saved, capturing the full initial state.
  2. Record updates β€” when you update a record's content or metadata, aver appends a note recording what changed and what the previous values were.

These system-generated notes are functionally identical to user notes, but it can be useful to distinguish them in searches and integrations. The is_system_update system value enables this.

Configuration:


[note_special_fields.is_system_update]
type = "single"
value_type = "integer"
editable = false
enabled = true
required = false
system_value = "is_system_update"
index_values = true

When this field is defined, every note receives the value automatically:

Filtering system notes out of search results:


# Show only user-authored notes
aver note search --ksearch is_system_update=0

# Show only system-generated tracking notes
aver note search --ksearch is_system_update=1

# Combine with other filters
aver note search --ksearch is_system_update=0 --ksearch category=investigation

JSON IO:


{"command": "search-notes", "params": {"ksearch": ["is_system_update=0"]}}

7. Configuration and Templates

Global Configuration

Aver uses a config.toml file in the database directory (.aver/config.toml).

Basic structure:


default_record_prefix = "REC"
default_note_prefix = "NT"

# Global record fields (apply to ALL records)
[record_special_fields.FIELDNAME]
# ... field definition

# Global note fields (apply to ALL notes)
[note_special_fields.FIELDNAME]
# ... field definition

# Templates
[template.TEMPLATENAME]
# ... template definition

Record Special Fields Configuration

Define fields that apply to all records:


[record_special_fields.title]
type = "single"
value_type = "string"
editable = true
enabled = true
required = true
index_values = true

[record_special_fields.status]
type = "single"
value_type = "string"
editable = true
enabled = true
required = true
accepted_values = ["open", "in_progress", "resolved", "closed"]
default = "open"
index_values = true

[record_special_fields.created_by]
type = "single"
value_type = "string"
editable = false
enabled = true
required = true
system_value = "user_name"
index_values = true

[record_special_fields.created_at]
type = "single"
value_type = "string"
editable = false
enabled = true
required = true
system_value = "datetime"
index_values = true

[record_special_fields.tags]
type = "multi"
value_type = "string"
editable = true
enabled = true
required = false

Note Special Fields Configuration

Define fields that apply to all notes:


[note_special_fields.author]
type = "single"
value_type = "string"
editable = false
enabled = true
required = true
system_value = "user_name"
index_values = true

[note_special_fields.timestamp]
type = "single"
value_type = "string"
editable = false
enabled = true
required = true
system_value = "datetime"
index_values = true

These global note fields appear in EVERY note, regardless of template.

Template System

Templates define:

  1. Custom ID prefixes
  2. Record-specific special fields (add to or override global record fields)
  3. Note-specific special fields (add to or override global note fields)
  4. Template record IDs (for content templates)
Connecting Content Templates with Field Enforcement

record new --template bug does two things at once:

  1. Field enforcement β€” the new record is validated against the bug template's field rules.
  2. Content import β€” if a record file named bug.md (matching the template ID) exists in the records/ directory, its body text is copied into the new record as initial content.

Admins can create a bug.md record file to provide a standard starting document (checklists, instructions, boilerplate) that gets pre-filled whenever someone creates a new bug record. This is an optional convention β€” if no such file exists, record new --template bug still works normally with an empty body.

record update --template is field-scope only: it scopes validation to the named template's field rules but never imports content from any record file.

Complete template example:


[template.bug]
record_prefix = "BUG"
note_prefix = "COMMENT"

# Template record special fields (adds to global record fields)
[template.bug.record_special_fields.severity]
type = "single"
value_type = "integer"
editable = true
enabled = true
required = true
accepted_values = ["1", "2", "3", "4", "5"]
default = "3"
index_values = true

[template.bug.record_special_fields.status]
type = "single"
value_type = "string"
editable = true
enabled = true
required = true
accepted_values = ["new", "confirmed", "in_progress", "fixed", "verified", "closed"]
default = "new"
index_values = true

# Template note special fields (adds to global note fields)
[template.bug.note_special_fields.category]
type = "single"
value_type = "string"
editable = true
enabled = true
required = false
accepted_values = ["investigation", "bugfix", "workaround", "regression", "documentation"]
index_values = true

[template.bug.note_special_fields.priority]
type = "single"
value_type = "string"
editable = true
enabled = true
required = false
accepted_values = ["low", "medium", "high", "critical"]
default = "medium"
index_values = true

Template Special Fields

How template fields work:

For records: Additive + Override

For notes: Additive + Override

Example: Bug template records have:

Example: Notes in bug records have:

8. Advanced Features

Search Queries

Search by special fields:


# Record search
aver record search --ksearch status=open
aver record search --ksearch "priority=high"
aver record search --ksearch "severity#>2"

# Note search
aver note search --ksearch category=bugfix
aver note search --ksearch priority=critical
Search Operators
Operator Description Example
= Equals status=open
!= Not equals status!=closed
> Greater than severity>2
< Less than severity<4
>= Greater or equal severity>=3
<= Less or equal severity<=3
^ In (matches any of a pipe-delimited list) status^open|in_progress
The ^ (In) Operator

The ^ operator matches records or notes where the field value is any one of a pipe-delimited list of values. It is equivalent to a SQL IN(...) clause.


# Match records where status is open OR closed
aver record list --ksearch 'status^open|closed'

# Match records where priority is high OR critical
aver record list --ksearch 'priority^high|critical'

# Combine with other filters (AND logic between different --ksearch flags)
aver record list --ksearch 'status^open|in_progress' --ksearch priority=high

# Works with note search too
aver note search --ksearch 'category^bugfix|investigation'

A single-value ^ expression (status^open) is equivalent to status=open.

Multiple --ksearch flags are always combined with AND logic; the ^ operator provides OR logic within a single field.

Database Management

Initialize a new database:


aver admin init

Reindex after manual changes:


aver admin reindex
The file_index Table

Every time a record or note is indexed, Aver records three pieces of file metadata in the file_index SQLite table (.aver/aver.db):

Column Type Description
id INTEGER Auto-increment primary key
file_path TEXT Absolute path to the Markdown file
file_hash TEXT MD5 hex digest of the file's UTF-8 content
file_mtime TEXT File modification time (ISO 8601 UTC) at index time

When indexing from existing files (e.g., admin reindex), file_mtime is read from the filesystem. When a file is indexed immediately after being written (e.g., record new, note add), file_mtime reflects the mtime of the newly written file.

This table is useful for:

admin reindex uses this table to skip unchanged files. Entries are updated each time a file is reindexed. Use --force to bypass the table entirely and reindex everything unconditionally.

Library Aliases

Work with multiple databases using library aliases:

Add a library:


aver admin config add-alias --alias work --path /path/to/work/database

Use a library:


aver --use work record list
aver --use work record new --title "Work task"

Set per-library user:


aver admin config set-user --library work --handle work_user --email [email protected]

Importing from Files

Import a record from Markdown:


aver record new --from-file record.md

File format:


---
title: Imported Record
status: open
priority: high
custom_field: custom_value
---
This is the record description.

Important notes:

Import a note:


aver note add REC-001 --from-file note.md

Note file format:


---
category: investigation
priority: high
---
Investigation findings...

9. Command Reference

admin init

Initialize a new database in the current directory.


aver admin init

Creates:

admin config

Manage configuration and user settings.

Set global user:


aver admin config set-user --handle alice --email [email protected]

Set library-specific user:


aver admin config set-user --library work --handle work_alice --email [email protected]

Add library alias:


aver admin config add-alias --alias project1 --path /path/to/database

List library aliases:


aver admin config list-aliases

record new

Create a new record.

Basic:


aver record new

With fields:


aver record new --title "Fix login" --status open --priority high

With template:


aver record new --template bug --title "App crashes" --severity 3

Show available fields:


aver record new --help-fields
aver record new --template bug --help-fields

From file:


aver record new --from-file record.md

With custom record ID:


aver record new --use-id MY-CUSTOM-ID --title "Custom ID record"

record unmask

Show the plaintext values of one or more fields on a record. Securestring fields are returned unmasked; all other field types are returned with their normal value. Fields that do not exist on the record are silently omitted.


aver record unmask REC-001 --fields "api_token"
aver record unmask REC-001 --fields "api_token,title,status"

Example output:


api_token: s3cr3t-v4lu3
title: My Record

For programmatic use, the unmask command is available via JSON IO:


{"command": "unmask", "params": {"record_id": "REC-001", "fields": ["api_token", "title"]}}

record update

Update an existing record.


aver record update REC-001 --status closed
aver record update BUG-042 --priority critical --description "Updated description"

With template scope β€” restrict field enforcement to a specific template without importing any content:


aver record update REC-001 --template bug --severity 3

Note: --template on record update is field-scope enforcement only. It does not copy any content from a template record. This differs from record new --template, which also copies initial content if a record named after the template exists.

Show available fields for this record (template-aware):


aver record update REC-001 --help-fields
aver record update REC-001 --help-fields --template bug

record list

List records.


aver record list
aver record list --limit 10

Paginate with --offset:


# First page: records 1–10
aver record list --limit 10 --offset 0

# Second page: records 11–20
aver record list --limit 10 --offset 10

# With search filters
aver record list --ksearch status=open --limit 25 --offset 25

--offset skips the first N results. Use with --limit for cursor-style pagination. Default is 0.

Count matching records (requires --ksearch):


aver record list --ksearch status=open --count
aver record list --ksearch "priority=high" --count

Returns only the integer count of matching records with no other output.

Return records with the maximum value of a key (requires --ksort):


aver record list --ksort severity --max severity
aver record list --ksearch status=open --ksort severity --max severity
aver record list --ksort priority --max priority,severity
aver record list --ksort priority --max priority --max severity

--max runs the full query (ksearch + ksort + limit) as a working set, then post-filters to return only records that hold the maximum value for any of the specified keys (keys are evaluated independently; OR logic). --ksort is required to ensure the relevant records are within the result window.

The max parameter is also available via JSON IO as a search-records parameter:


{"command": "search-records", "params": {"ksort": "severity", "max": "severity"}}
{"command": "search-records", "params": {"ksearch": "status=open", "ksort": "severity", "max": ["severity", "priority"]}}

--offset is also available via JSON IO for both search-records and search-notes:


{"command": "search-records", "params": {"ksearch": "status=open", "limit": 25, "offset": 25}}
{"command": "search-notes", "params": {"ksearch": "category=bugfix", "limit": 20, "offset": 20}}

Search for records.


aver record search --ksearch status=open
aver record search --ksearch "priority=high"
aver record search --ksearch "severity#>=3"

note add

Add a note to a record.

Basic:


aver note add REC-001

With message:


aver note add REC-001 --message "Investigation complete"

With note fields:


aver note add BUG-042 --message "Applied fix" --category bugfix --priority high

Show available fields:


aver note add BUG-042 --help-fields

For automation (suppress editor):


aver note add REC-001 --message "Automated check complete" --no-validation-editor
echo "Note text" | aver note add REC-001 --no-validation-editor

--no-validation-editor prevents the editor from opening on validation failure. If no --message and no stdin are provided, the command errors immediately rather than prompting.

From file:


aver note add REC-001 --from-file note.md

note list

List notes for a record.


aver note list REC-001
aver note list BUG-042

Search notes across all records.


aver note search --ksearch category=bugfix
aver note search --ksearch priority=critical

Paginate with --offset:


# First page: notes 1–20
aver note search --ksearch category=bugfix --limit 20 --offset 0

# Next page: notes 21–40
aver note search --ksearch category=bugfix --limit 20 --offset 20

Count matching notes:


aver note search --ksearch category=bugfix --count
aver note search --ksearch priority=critical --count

Returns only the integer count of matching notes with no other output.

note unmask

Show the plaintext values of one or more fields on a specific note. Securestring fields are returned unmasked; all other field types are returned with their normal value. Fields that do not exist on the note are silently omitted.


aver note unmask REC-001 NT-001 --fields "session_token"
aver note unmask REC-001 NT-001 --fields "session_token,author,timestamp"

For programmatic use, the unmask command is available via JSON IO (include note_id to target a note):


{"command": "unmask", "params": {"record_id": "REC-001", "note_id": "NT-001", "fields": ["session_token"]}}

admin reindex

Rebuild the search index β€” all records, or a specific set of records.


# Full reindex (all records)
aver admin reindex

# Selective reindex (one or more records)
aver admin reindex REC-001
aver admin reindex REC-001 BUG-042 FEAT-007

# Verbose progress output
aver admin reindex --verbose

# Force reindex even if files appear unchanged
aver admin reindex --force
aver admin reindex REC-001 --force

# Skip mtime shortcut; always compare MD5 hash
aver admin reindex --skip-mtime
aver admin reindex REC-001 --skip-mtime

# Skip field validation (index records even if they violate template rules)
aver admin reindex --skip-validation
Validation during reindex

By default, admin reindex validates each record against its template field rules before indexing it. Records that fail validation are not indexed and the command exits with an error listing every violation. This prevents non-conforming data from silently entering the search index.

The same rules as admin validate apply: required-field presence and accepted_values constraints, using the template-specific field set for records that carry a template_id.

Use --skip-validation to bypass this check and index all records regardless of conformance β€” useful when intentionally importing legacy data or working with records that pre-date a schema change.

How change detection works

admin reindex is optimised to skip files that have not changed, making repeated full reindexes fast on large record sets. The check proceeds in two steps:

  1. mtime check (fast): If the file's modification time matches the value stored in file_index, the file is assumed unchanged and skipped.
  2. MD5 hash check (slower, only if mtime differs): If the mtime has changed, the file is read and its MD5 hash is compared against the stored value. If the hash matches the file is still skipped; if it differs, the file is reindexed.
Flag Behaviour
(none) mtime check β†’ hash check on mtime miss β†’ skip if match
--skip-mtime Skip mtime check; always read file and compare MD5 hash
--force Skip all change detection; always reindex every file
--skip-validation Skip template field validation before indexing

Use --skip-mtime when files may have been copied with preserved timestamps (e.g. cp -p, rsync -a, git checkout). Use --force after schema changes or to recover from a corrupted index.

admin template-data

Show field definitions for a template β€” record fields and note fields β€” as defined in config.toml. Useful for building UIs or validating data before submission.

Show all templates (human-readable):


aver admin template-data

Show a specific template:


aver admin template-data bug

When no template_id is given, global defaults (no template) are also included.

Example human-readable output:


======================================================================
Template: bug
  Record prefix: BUG
  Note prefix:   COMMENT
======================================================================

  Record fields:
    created_at  (single, string)  [read-only, system:datetime]
    created_by  (single, string)  [required, read-only, system:user_name]
    severity    (single, integer)  [required]
      Accepted: 1, 2, 3, 4, 5
      Default:  3
    status      (single, string)  [required]
      Accepted: new, confirmed, in_progress, fixed, verified, closed
      Default:  new
    title       (single, string)  [required]

  Note fields:
    author      (single, string)  [required, read-only, system:user_name]
    category    (single, string)
      Accepted: investigation, bugfix, workaround, regression, documentation
    timestamp   (single, string)  [required, read-only, system:datetime]

Example JSON output (single template):


{
  "template_id": "bug",
  "record_prefix": "BUG",
  "note_prefix": "COMMENT",
  "record_fields": {
    "title":      {"type": "single", "value_type": "string", "editable": true, "required": true},
    "status":     {"type": "single", "value_type": "string", "editable": true, "required": true,
                   "accepted_values": ["new","confirmed","in_progress","fixed","verified","closed"],
                   "default": "new"},
    "severity":   {"type": "single", "value_type": "integer", "editable": true, "required": true,
                   "accepted_values": ["1","2","3","4","5"], "default": "3"},
    "created_by": {"type": "single", "value_type": "string", "editable": false, "required": true,
                   "system_value": "user_name"},
    "created_at": {"type": "single", "value_type": "string", "editable": false, "required": false,
                   "system_value": "datetime"}
  },
  "note_fields": {
    "author":    {"type": "single", "value_type": "string", "editable": false, "required": true,
                  "system_value": "user_name"},
    "timestamp": {"type": "single", "value_type": "string", "editable": false, "required": true,
                  "system_value": "datetime"},
    "category":  {"type": "single", "value_type": "string", "editable": true, "required": false,
                  "accepted_values": ["investigation","bugfix","workaround","regression","documentation"]}
  }
}

This command is also available via JSON IO as the template-data command (see JSON IO documentation).

admin validate

Check that on-disk record files conform to template field rules. Validation covers:

Validate all records:


aver admin validate

Validate specific records:


aver admin validate REC-001
aver admin validate REC-001 BUG-042 FEAT-007

List only failing record IDs (one per line, useful in scripts):


aver admin validate --failed-list
aver admin validate REC-001 BUG-042 --failed-list
Exit code Meaning
0 All checked records conform (or no records found)
1 One or more records failed validation

Example summary output (default mode):


Validation summary: 42 record(s) checked
  Conforming:     39
  Non-conforming: 3

  FAIL  REC-KPZZ17D: field 'status': invalid value 'invalid' (accepted: open, in_progress, resolved, closed)
  FAIL  REC-KSDJO4D: required field 'title' is missing or empty
  FAIL  BUG-0042AB: field 'severity': invalid value '9' (accepted: 1, 2, 3, 4, 5)

Use --failed-list to get a plain list of failing record IDs.

Example --failed-list output:


REC-KPZZ17D
REC-KSDJO4D
BUG-0042AB

admin validate only checks record files; it does not validate note files.

admin validate-config

Check that the project configuration (config.toml) and user configuration are semantically correct. Catches problems before they cause silent failures or cryptic runtime errors.

Checks performed:

aver admin validate-config

Example output (clean config):

Config validation: OK

Example output (errors found):

Config validation: 2 error(s) found

  ERROR  [record_special_fields.severity] value_type 'blob' is not valid (must be one of: float, integer, securestring, string)
  ERROR  [record_special_fields.status] default value 'unknown' is not in accepted_values: ['open', 'closed']
Exit codeMeaning
0Configuration is valid
4One or more configuration errors found
1Database or config file could not be loaded

Startup warnings: Every aver command automatically runs this check and prints [CONFIG WARNING] lines to stderr for any issues. The command still runs β€” warnings are informational only. Use --no-validate-config (a global flag) to suppress them. This flag has no effect on admin validate-config itself, which always validates.

aver --no-validate-config record list    # suppress startup warnings
aver admin validate-config               # always validates, ignores --no-validate-config

10. Administrator's Guide

Setting Up Special Fields

Planning your field structure:

  1. Identify record types: What are you tracking? (bugs, features, tasks, experiments)
  2. Define global fields: Fields that apply to ALL records and notes
  3. Define template fields: Fields specific to each record type

Global fields (all records):

Global note fields (all notes):

Template-specific fields:

Designing Templates

Best practices:

  1. Start simple: Begin with a few templates (bug, feature)
  2. Use clear prefixes: BUG-, FEAT-, TASK- for records; COMMENT-, FEEDBACK- for notes
  3. Inherit smartly: Let templates add to global fields, not replace them
  4. Constrain carefully: Use accepted_values for fields with clear options
  5. Default wisely: Set defaults for common values to reduce typing

Example workflow:


# Global fields apply to everything
[record_special_fields.created_by]
system_value = "user_name"
editable = false
required = true

[note_special_fields.author]
system_value = "user_name"
editable = false
required = true

# Bug template adds severity and specific status values
[template.bug]
record_prefix = "BUG"
note_prefix = "COMMENT"

[template.bug.record_special_fields.severity]
type = "single"
value_type = "integer"
accepted_values = ["1", "2", "3", "4", "5"]
default = "3"

[template.bug.note_special_fields.category]
accepted_values = ["investigation", "bugfix", "workaround"]

Managing Multiple Databases

Use library aliases for different projects:


# Set up libraries
aver admin config add-alias --alias personal --path ~/Documents/aver-personal
aver admin config add-alias --alias work --path ~/Work/aver-work

# Configure different users per library
aver admin config set-user --library personal --handle myhandle --email [email protected]
aver admin config set-user --library work --handle work.name --email [email protected]

# Use them
aver --use personal record new --title "Personal task"
aver --use work record new --template bug --title "Work bug"

Best Practices

  1. Define system fields early: created_by, created_at, author, timestamp should be in every config
  1. Use templates for workflows: Different record types need different fields
  1. Make non-editable fields clear: System-populated fields should be editable = false
  1. Provide defaults: Reduce typing with sensible defaults
  1. Document your fields: Use clear field names and constrained values
  1. Test with small data first: Set up your config, create test records, iterate
  1. Version control your config: Keep config.toml in Git to track changes
  1. Don't over-constrain: Only use accepted_values when truly necessary

Exit Codes

Aver uses distinct exit codes so scripts can respond precisely to different outcomes without parsing error text.

CodeNameMeaning
0SuccessCommand completed successfully
1ErrorGeneral or unexpected error (I/O failure, internal error)
2Usage errorBad arguments, incompatible flags, constraint violations
3Not foundRecord, note, or template does not exist
4Validation failureField rules violated (required field missing, value not in accepted_values, wrong type)
130InterruptedUser pressed Ctrl-C

Examples


# Check for "not found" specifically
aver record view REC-999
if [ $? -eq 3 ]; then
  echo "Record does not exist"
fi

# Check for validation failure
aver record new --no-validation-editor --title "Bug" --status invalid
if [ $? -eq 4 ]; then
  echo "Validation failed"
fi

# admin validate exits 4 when records fail, 0 when all pass
aver admin validate
echo "Exit code: $?"

Notes

Conclusion

Aver's special fields system provides structure and validation while maintaining the flexibility of plain text storage. By understanding the distinction between global and template-specific fields, and between record and note fields, you can create powerful, type-safe workflows for any tracking need.

Key takeaways:

Getting help:

Next steps:

Happy tracking!

Tales from the Field

The Incident Master's Journey

# 1. Consecrate a vault (once per quest)
aver admin init

# 2. Report a calamity
aver record new \
  --text "title=Production API returning 500 errors" \
  --text "status=open" \
  --text "severity=critical" \
  --text-multi "tags=production" \
  --text-multi "tags=api"

# 3. Inscribe thoughts as they come
aver note add REC-XXXXX --message "Checking application logs"

aver note add REC-XXXXX \
  --message "Found memory leak in request handler" \
  --text "category=rca"

# 4. Update the record's state
aver record update REC-XXXXX --text "status=investigating"

# 5. Chronicle the solution
aver note add REC-XXXXX \
  --message "Deployed hotfix v2.3.1" \
  --number "time_to_resolve=45"

# 6. Seal it closed
aver record update REC-XXXXX \
  --text "status=resolved" \
  --text "resolution=Memory leak fixed in v2.3.1"

The Lorekeeper's Archive

# Create a tome of knowledge
aver record new \
  --text "title=How to reset user passwords" \
  --text "type=howto" \
  --text-multi "tags=admin" \
  --text-multi "tags=security" \
  --description "Step-by-step guide..."

# Find all how-to articles
aver record list --ksearch "type=howto"

# Find all security-related knowledge
aver record list --ksearch "tags=security"

The Timekeeper's Ledger

# Log your labors with time
aver note add REC-XXXXX \
  --message "Refactored authentication module" \
  --number "hours=4" \
  --text "work_type=development"

# Later, find all labors you've tracked
aver note search --ksearch "hours>0"

The Multi-Library Keeper

# Register your libraries
aver admin config add-alias --alias work --path /home/you/work/.aver
aver admin config add-alias --alias oss --path /home/you/opensource/.aver

# Set different identities for each
aver admin config set-user --library work \
  --handle "you-corp" --email "[email protected]"
aver admin config set-user --library oss \
  --handle "you-oss" --email "[email protected]"

# Work on different projects without changing directory
aver record list --use work
aver note add REC-XXXXX --use oss --message "Fixed the build"

# See what you've set up
aver admin config list-aliases

Global Flags

These flags apply to every aver command and must appear before the subcommand:

FlagDescription
--location PATHUse the database at the given .aver directory path
--use ALIASUse a named library alias
--chooseInteractively select a database when multiple are available
--use-git-idUse git identity instead of aver config identity for this invocation
--no-use-git-idUse aver config identity even if it differs from git
--no-validate-configSuppress startup config validation warnings

Startup config validation: Every aver command automatically checks the project and user configuration and prints [CONFIG WARNING] lines to stderr for any issues found. The command still runs β€” warnings are informational only. Use --no-validate-config to suppress them in scripts or CI. This flag has no effect on admin validate-config, which always validates regardless.

aver --no-validate-config record list    # suppress startup warnings
aver --no-validate-config json io        # suppress warnings in JSON IO mode
aver admin validate-config               # always validates, ignores --no-validate-config

Git Identity Verification

When you perform a write operation (record new, record update, note add) inside a git repository, aver checks whether your aver config identity matches the git identity (git config user.name and git config user.email).

If the identities differ, aver requires you to resolve the mismatch. There are three ways:

Per-Invocation Flags

# Use git identity for this one command
aver record new --use-git-id --text "title=Fix from git user"

# Use aver config identity, ignoring the mismatch
aver note add REC-XXXXX --no-use-git-id --message "Note from config user"

Persistent Configuration

Add prefer_git_identity to your config to resolve the mismatch automatically. This can be set at the per-library level or globally:

# Per-library (only affects this database)
[libraries.myproject]
path = "/home/you/projects/.aver"
prefer_git_identity = true    # always use git identity
# prefer_git_identity = false  # always use aver config identity

# Global (affects all databases without a library-level setting)
[user]
handle = "you"
email = "[email protected]"
prefer_git_identity = false

The resolution order is: per-library config β†’ global config β†’ CLI flag β†’ error with instructions.

When --use-git-id is used, aver prints a notice showing how to configure prefer_git_identity so the flag won't be needed in the future.

The Aver Compact

Aver is small by design. These are not limitations to be overcome, but boundaries chosen deliberately.

  1. The scrolls are the source
    Markdown files are authoritative. The index may be destroyed and rebuilt at will.
  2. State changes, history accumulates
    Records change to reflect current understanding. Notes only grow, preserving context over time.
  3. Versioning over verification
    Aver does not attempt to prove correctnessβ€”only to preserve authorship, order, and change over time.
  4. Meaning belongs to the archive
    Field names and semantics are defined by each repository, not by Aver itself. Your domain, your language.
  5. Nothing happens without a command
    Reindexing, configuration, and structure are explicit acts. Aver does not act on your behalf unless asked.

These boundaries keep Aver predictable, auditable, and hard to surprise. The tool serves the archive; the archive does not serve the tool.

When Darkness Falls

"No record vault can be found"

The Cause: Aver cannot perceive a .aver directory.

The Remedy:

  1. Consecrate a vault: aver admin init
  2. Name its location: aver record list --location /path/to/.aver
  3. Use a library alias: aver record list --use myproject
  4. Confirm you are in the right realm

"User identity has not been declared"

The Remedy:

aver admin config set-user --handle "yourname" --email "[email protected]"

"Identity mismatch between aver config and git"

The Cause: Your aver config identity differs from your git identity (git config user.name / user.email).

The Remedy:

"Search results seem incorrect"

The Remedy:

aver admin reindex --verbose

Wisdom for the Ages

  1. Title with care: Future seekers will search by these words
  2. Speak consistent keystones: Your fellowship will thank you
  3. Tags are your allies: Bestow them freely; they unlock many searches
  4. Notes hold the tale: Future you will hunger for this context
  5. Keep .aver in your repository: Plain text and Git history marry well
  6. Define your keystones: Use config.toml to enforce consistency
  7. Treat lengthy notes as prose: Write them in your editor, not at the command line
  8. Let records evolve: They are meant to change as understanding deepens
  9. Let notes accumulate: They are meant to preserve the path you walked
  10. Use library aliases: Name your archives; --use work is kinder than --location /long/path/to/.aver

The Code

The artifact's source is held in a repository of version control, where all its mysteries are laid bare.

πŸ“– Find the source on GitHub:

github.com/dentm42/aver

Here you may read the code, report troubles, contribute improvements, and join the fellowship in its ongoing quest.

Key Features Awaiting You

License

See the repository for terms of use and license information. The code is shared freely with the fellowship.