Inspired by PR #1164 from Piyush Jha (@Hackinet). Groups commands under 'bd kv' subcommand for cleaner namespacing. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
4.5 KiB
Key-Value Store for Beads
Design document for
bd kvcommands Status: Draft - pending Dolt team review Date: 2026-01-21
Overview
Add a simple key-value store to beads for persisting lightweight metadata that doesn't fit the issue model. This enables storing things like:
- Feature flags (
bd kv set debug_mode true) - Project configuration (
bd kv set entry_point src/main.ts) - Workflow state across sessions (
bd kv set current_sprint 42) - Agent memory that survives context cycling
Commands
bd kv set <key> <value> # Set a key-value pair
bd kv get <key> # Get a value (exit 1 if not found)
bd kv delete <key> # Delete a key
bd kv list [prefix] # List all pairs (optionally filtered by prefix)
All commands support --json for machine-readable output.
Examples
# Store project metadata
bd kv set primary_language go
bd kv set entry_point cmd/bd/main.go
# Retrieve values
bd kv get primary_language
# Output: go
# List all pairs
bd kv list
# Output:
# primary_language = go
# entry_point = cmd/bd/main.go
# List with prefix filter
bd kv list entry
# Output:
# entry_point = cmd/bd/main.go
# JSON output
bd kv list --json
# Output: [{"key":"primary_language","value":"go","set_at":"2026-01-21T10:30:00Z","set_by":"beads/crew/collins"},...]
# Delete a key
bd kv delete primary_language
Schema
Dolt Table: kv
CREATE TABLE kv (
`key` VARCHAR(255) PRIMARY KEY,
value TEXT NOT NULL,
set_at DATETIME NOT NULL,
set_by VARCHAR(255) NOT NULL
);
| Column | Type | Description |
|---|---|---|
key |
VARCHAR(255) | Primary key, the lookup key |
value |
TEXT | The stored value (always string) |
set_at |
DATETIME | When the value was set (UTC) |
set_by |
VARCHAR(255) | Actor who set it (e.g., "beads/crew/collins", "human") |
Design Decisions
Why not use the config table?
- Config is for beads internal settings (sync mode, integrations, etc.)
- Mixing user data with internal config creates namespace collisions
- Separate table is cleaner and avoids future conflicts
Why not make KV pairs into issues/beads?
- KV is meant to be lightweight - issues have significant overhead (id, title, description, status, priority, type, etc.)
- Different lifecycle - KV is "set and forget", issues are "open → work → close"
- Would pollute
bd listwith non-work entries
Why track set_at and set_by?
- Attribution: know who set a value and when
- Debugging: trace when configuration changed
- Future: enables conflict resolution in multi-writer scenarios
Sync Behavior
KV data syncs via the standard beads-sync mechanism:
- Export: On push, KV table exports to
.beads/kv.jsonl - Import: On pull,
.beads/kv.jsonlimports back to KV table - Merge: Last-write-wins based on
set_attimestamp
JSONL Format
.beads/kv.jsonl - one JSON object per line:
{"key":"primary_language","value":"go","set_at":"2026-01-21T10:30:00Z","set_by":"beads/crew/collins"}
{"key":"entry_point","value":"cmd/bd/main.go","set_at":"2026-01-21T10:31:00Z","set_by":"human"}
This format is:
- Human-readable and diffable in git
- Streaming-friendly (append without rewriting)
- Consistent with
issues.jsonlpattern
RPC Operations
For daemon mode, add these operations to the RPC protocol:
| Operation | Args | Response |
|---|---|---|
kv_set |
{key, value} |
{success: bool} |
kv_get |
{key} |
{value: string, found: bool} |
kv_delete |
{key} |
{success: bool} |
kv_list |
{prefix?: string} |
{items: [{key, value, set_at, set_by}]} |
Future Considerations
These are NOT in scope for v1, but the design accommodates them:
- Local-only keys: Convention could be
_local.prefix for keys that don't sync - TTL/expiration: Could add
expires_atcolumn later - Namespaces: Could add
namespacecolumn for scoping - Value types: Currently string-only; could add
--type=jsonflag later
Credit
This feature is inspired by PR #1164 from Piyush Jha (@Hackinet). The original PR proposed bd set/get/clear as top-level commands; this design groups them under bd kv for cleaner namespacing.
Questions for Dolt Team
- Any concerns with the schema design?
- Preferred approach for the DATETIME column - store as ISO string or native datetime?
- Any Dolt-specific considerations for the sync/merge behavior?
- Should we use Dolt's conflict resolution features, or handle last-write-wins in application code?