Skip to main content

Overview

sudocode uses a 3-layer storage architecture that combines the best of human-editable files, version control, and fast database queries. This “distributed git database” approach makes context durable, queryable, and fully version-controlled alongside your code.
Core Philosophy: Context is code. Specifications, issues, and relationships are stored as version-controlled artifacts that travel with your codebase through git.

Git-Native Storage Philosophy

Traditional issue trackers store context in centralized databases:
  • GitHub Issues - Hosted database, accessed via API
  • Jira - Cloud or self-hosted database
  • Linear - Centralized SaaS database
Problem: Context is separate from code, doesn’t travel with branches, hard to query offline. sudocode’s approach: Context is stored in git itself:
  • Version controlled alongside code
  • Branches include their context
  • Works offline
  • Queryable locally
  • Distributed by default

Context-as-Code Principle

Just as you version control your code, sudocode version controls your development context:
Benefits:
  • Context travels with code through branches
  • Full git history of decisions and changes
  • Merge conflicts are git merge conflicts
  • Works offline, no API required
  • Fast local queries via SQLite

The 3-Layer Architecture

sudocode uses three storage layers, each serving a specific purpose:

Layer 1: Markdown

Human interface
  • Editable files
  • .md format
  • YAML frontmatter
  • Git-tracked

Layer 2: JSONL

Source of truth
  • Structured data
  • Line-delimited JSON
  • Git-friendly diffs
  • Append-only log

Layer 3: SQLite

Query cache
  • Fast lookups
  • Relational queries
  • Graph traversal
  • Gitignored, rebuilt

Why Three Layers?

Each layer optimizes for different needs:

Layer 1: Markdown Files

Purpose

Markdown files provide a human-editable interface to specs and issues. Developers can edit context using their favorite text editor, just like editing code.

Location

Format

Markdown files use YAML frontmatter for metadata plus markdown body for content: Example spec file (.sudocode/specs/authentication-system.md):
Example issue file (.sudocode/issues/ISSUE-042.md):

Frontmatter Fields

Specs:
  • id - Unique identifier (SPEC-001, SPEC-002, etc.)
  • title - Human-readable title
  • priority - 0-4 (0=highest)
  • status - draft, review, approved, deprecated
  • tags - Array of tags
  • created_at - ISO 8601 timestamp
  • updated_at - ISO 8601 timestamp
  • parent_id - Parent spec ID (optional)
Issues:
  • id - Unique identifier (ISSUE-001, ISSUE-002, etc.)
  • title - Human-readable title
  • status - open, in_progress, blocked, closed
  • priority - 0-4 (0=highest)
  • tags - Array of tags
  • assignee - Assigned user (optional)
  • created_at - ISO 8601 timestamp
  • updated_at - ISO 8601 timestamp
  • closed_at - ISO 8601 timestamp (if closed)
  • parent_id - Parent issue ID (optional)

When to Edit Markdown

Manual editing:
  • Creating new specs
  • Updating spec content
  • Refining requirements
  • Adding cross-references with [[SPEC-ID]] syntax
Auto-generated:
  • CLI operations sync back to markdown
  • sudocode sync --to-markdown regenerates from database

Layer 2: JSONL Files (Source of Truth)

Purpose

JSONL (JSON Lines) files are the source of truth for all sudocode data. These files are:
  • Git-tracked (committed to repository)
  • Line-delimited (one JSON object per line)
  • Merge-friendly (line-based diffs)
  • Complete (includes all metadata, relationships, tags)

Location

Format

Each line is a complete JSON object representing one entity: Example specs.jsonl:
Example issues.jsonl:

JSONL Structure

Spec JSONL object:
Issue JSONL object:

Why JSONL?

Git-friendly diffs:
Append-only log:
  • New entities are appended
  • Updates replace entire line
  • Git shows clear line-by-line changes
Complete data:
  • All relationships embedded
  • All tags embedded
  • All feedback embedded
  • Single file per entity type

When JSONL is Updated

Automatic export (debounced):
  • After any CLI command that modifies data
  • Debounce: 5 seconds (batches rapid changes)
  • Triggered by: sudocode issue create, sudocode spec update, etc.
Manual export:
After sync:

Layer 3: SQLite Database (Query Cache)

Purpose

SQLite provides fast queries and relational operations:
  • Complex filters (status, priority, tags)
  • Graph queries (find blockers, find ready work)
  • Relationship traversal
  • Full-text search
  • Aggregations and statistics

Location

Never commit sudocode.db to git! It’s a cache that should be rebuilt locally from JSONL files. Add .sudocode/sudocode.db to your .gitignore.

Schema

The database uses the following tables: Core entity tables:
Relationship table:
Tags table:
Feedback table:
Events table (audit log):
View: ready_issues (unblocked work):
View: blocked_issues (blocked work):

Why SQLite?

Fast local queries:
Relationship traversal:
Full-text search:
Performance:
  • Indexed lookups: O(log n)
  • Complex joins: Optimized by SQLite
  • View queries: Precomputed logic
  • Works offline: No API calls

When Database is Rebuilt

After git pull:
Manual import:
Fresh clone:

Data Flow

Bidirectional Sync

Data flows between layers depending on the operation:

Direction 1: Markdown → Database → JSONL

Triggered by: Manual markdown edits, sudocode sync --from-markdown
1

Parse markdown file

  • Read frontmatter (YAML)
  • Extract content (markdown body)
  • Parse cross-references [[SPEC-ID]]
2

Update database

  • Upsert spec/issue record
  • Create relationships from cross-references
  • Update tags
  • Update timestamps
3

Export to JSONL (debounced)

  • Wait 5 seconds for more changes
  • Query all entities from database
  • Write complete JSONL files
  • Include embedded relationships and tags
4

Git commit (manual)

  • Commit markdown + JSONL changes together
  • Context travels with code
Example:

Direction 2: Database → JSONL → Markdown

Triggered by: CLI operations, sudocode sync --to-markdown
1

CLI modifies database

  • sudocode issue create → INSERT into issues table
  • sudocode spec update → UPDATE specs table
  • sudocode link → INSERT into relationships table
2

Export to JSONL (auto, debounced)

  • Wait 5 seconds after last change
  • Query all entities
  • Write complete JSONL files
3

Sync to markdown (optional)

  • sudocode sync --to-markdown regenerates markdown files
  • Frontmatter updated from database
  • Content preserved
4

Git commit (manual)

  • Commit JSONL + markdown changes
Example:

Direction 3: JSONL → Database (After Git Pull)

Triggered by: git pull, sudocode sync, sudocode import
1

Git pull updates JSONL

  • Teammate committed changes
  • JSONL files updated
  • Local markdown may be stale
2

Detect changes

  • Compare JSONL modification time vs database
  • JSONL is newer → import needed
3

Import to database

  • Parse JSONL files line by line
  • Upsert each entity (insert or update)
  • Rebuild relationships table
  • Rebuild tags table
  • Handle feedback anchors
4

Sync to markdown (optional)

  • Update markdown files from database
  • Preserve content, update frontmatter
  • Create new markdown files if needed
Example:

Auto-Sync Mechanisms

File Watching

sudocode can watch for file changes and auto-sync:
What it does:
  • Watches .sudocode/specs/ and .sudocode/issues/ directories
  • Detects markdown file changes
  • Debounces changes (2 seconds)
  • Auto-syncs to database
  • Auto-exports to JSONL
Use case: Active development with frequent spec edits

Debouncing

To avoid excessive writes, sudocode debounces exports: Export debounce: 5 seconds
  • Waits 5 seconds after last database change
  • Batches multiple rapid changes
  • Writes JSONL once
File watch debounce: 2 seconds
  • Waits 2 seconds after last file change
  • Prevents sync on every keystroke
  • Syncs once after editing

Manual Sync

For explicit control:
Auto-detection logic:
  1. Compare markdown file modification times
  2. Compare JSONL file modification times
  3. Determine which is newer
  4. Sync in that direction

Git Distribution

Team Collaboration Workflow

JSONL files enable seamless team collaboration through git:
1

Developer A creates spec

2

Developer B pulls changes

3

Developer B creates issues

4

Developer A pulls and sees new work

Merge Conflicts

JSONL conflicts:
Resolution:
  1. Manual: Choose one version or merge fields
  2. AI-assisted: Ask AI to merge based on semantics
  3. Import after resolution:

Branching Strategy

Context travels with code branches:
Benefits:
  • Experimental specs in feature branches
  • Merge specs with code when merging branch
  • Context and code always in sync

Best Practices

Do’s

Always commit .sudocode/ changes alongside related code:
Benefits:
  • Context travels with implementation
  • Code review includes design decisions
  • Git history is complete
Always sync database after pulling:
Or use a git hook:
For frequent spec editing:
Changes sync automatically.
Always add to .gitignore:
Database is rebuilt from JSONL, never commit it.
Create specs in feature branches:

Don’ts

Wrong:
Right:
Database is a cache, not source of truth.
Wrong:
Right:
JSONL is auto-generated, edits will be overwritten.
Wrong:
Right:
Wrong:
Right:

Troubleshooting

Symptoms: sudocode list shows stale dataCause: Pulled JSONL changes not imported to databaseSolution:
Symptoms: JSONL has entities but no markdown filesCause: Markdown files not synced from databaseSolution:
Regenerates all markdown files from database.
Symptoms: CLI changes work locally but teammates don’t see themCause: JSONL files not committed to gitSolution:
Symptoms: Error: database is locked or database disk image is malformedCause: Concurrent access or corruptionSolution:
JSONL is source of truth, database can always be rebuilt.
Symptoms: Git merge conflict in specs.jsonl or issues.jsonlCause: Two branches modified same entitySolution:Option 1: Manual resolution
Option 2: AI-assisted

Architecture Diagrams

3-Layer Architecture

Data Flow

Sync Commands

Manual sync operations

Export Command

Export to JSONL

Import Command

Import from JSONL

Specs Concept

Specification structure

Issues Concept

Issue structure

Relationships

Linking entities

Next Steps

1

Initialize sudocode

2

Verify .gitignore

3

Create first spec

Observe:
  • Markdown file created
  • Database updated
  • JSONL exported
4

Commit to git

JSONL travels with code!
5

Set up sync hook (optional)

Auto-sync after git pull.

Spec-Driven Development

Learn how to use the storage model in practice