> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sudocode.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Storage Model

> Git-native 3-layer distributed database architecture

## 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.

<Note>
  **Core Philosophy:** Context is code. Specifications, issues, and relationships are stored as version-controlled artifacts that travel with your codebase through git.
</Note>

### 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:

```
your-project/
├── src/                    # Your code
├── tests/                  # Your tests
└── .sudocode/              # Your context (specs, issues, relationships)
    ├── specs/
    │   ├── auth-system.md
    │   └── specs.jsonl     # Source of truth
    ├── issues/
    │   ├── ISSUE-001.md
    │   └── issues.jsonl    # Source of truth
    └── sudocode.db         # Query cache (gitignored)
```

**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:

<CardGroup cols={3}>
  <Card title="Layer 1: Markdown" icon="file-lines">
    **Human interface**

    * Editable files
    * `.md` format
    * YAML frontmatter
    * Git-tracked
  </Card>

  <Card title="Layer 2: JSONL" icon="database">
    **Source of truth**

    * Structured data
    * Line-delimited JSON
    * Git-friendly diffs
    * Append-only log
  </Card>

  <Card title="Layer 3: SQLite" icon="bolt">
    **Query cache**

    * Fast lookups
    * Relational queries
    * Graph traversal
    * Gitignored, rebuilt
  </Card>
</CardGroup>

### Why Three Layers?

Each layer optimizes for different needs:

| Need              | Layer            | Why                             |
| ----------------- | ---------------- | ------------------------------- |
| **Human editing** | Markdown         | Familiar format, readable diffs |
| **Git tracking**  | JSONL            | Structured, line-based diffs    |
| **Fast queries**  | SQLite           | Relational queries, indexes     |
| **Relationships** | SQLite           | Graph traversal, joins          |
| **Offline work**  | All layers       | Local-first design              |
| **Distribution**  | JSONL + Markdown | Git push/pull                   |

## 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

```
.sudocode/
├── specs/
│   ├── authentication-system.md
│   ├── oauth-integration.md
│   └── api-design.md
└── issues/
    ├── ISSUE-001.md
    ├── ISSUE-002.md
    └── ISSUE-003.md
```

### Format

Markdown files use **YAML frontmatter** for metadata plus markdown body for content:

**Example spec file** (`.sudocode/specs/authentication-system.md`):

```markdown theme={null}
---
id: SPEC-005
title: OAuth 2.0 Authentication System
priority: 0
status: approved
tags:
  - auth
  - oauth
  - security
created_at: '2025-10-29T08:00:00Z'
updated_at: '2025-10-29T14:30:00Z'
---

# OAuth 2.0 Authentication System

## Overview

Implement OAuth 2.0 authentication to allow users to sign in
with Google and GitHub accounts.

## Requirements

- Support Google OAuth 2.0
- Support GitHub OAuth 2.0
- Secure token storage
- Token refresh capability

## Architecture

### Components
- OAuth middleware (Express)
- Token storage (Redis)
- Session management

...
```

**Example issue file** (`.sudocode/issues/ISSUE-042.md`):

```markdown theme={null}
---
id: ISSUE-042
title: Implement OAuth token exchange
status: in_progress
priority: 1
tags:
  - auth
  - oauth
created_at: '2025-10-29T10:00:00Z'
updated_at: '2025-10-29T15:00:00Z'
---

# Implement OAuth token exchange

Exchange authorization codes for access/refresh tokens.

## Tasks
- [ ] Implement token exchange endpoint
- [ ] Set up Redis token storage
- [ ] Encrypt tokens at rest
- [ ] Handle token expiration

Implements [[SPEC-005]]
```

### 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

```
.sudocode/
├── specs/
│   └── specs.jsonl         # All specs, one per line
└── issues/
    └── issues.jsonl        # All issues, one per line
```

### Format

Each line is a complete JSON object representing one entity:

**Example specs.jsonl**:

```json theme={null}
{"id":"SPEC-001","uuid":"a1b2c3...","title":"Authentication System","content":"# Authentication System\n\n...","priority":0,"status":"approved","archived":0,"created_at":"2025-10-29T08:00:00Z","updated_at":"2025-10-29T09:00:00Z","parent_id":null,"file_path":"specs/authentication-system.md","relationships":[],"tags":["auth","security"]}
{"id":"SPEC-002","uuid":"d4e5f6...","title":"OAuth Integration","content":"# OAuth Integration\n\n...","priority":1,"status":"draft","archived":0,"created_at":"2025-10-29T08:30:00Z","updated_at":"2025-10-29T10:00:00Z","parent_id":"SPEC-001","file_path":"specs/oauth-integration.md","relationships":[{"from":"SPEC-002","from_type":"spec","to":"SPEC-001","to_type":"spec","type":"references"}],"tags":["auth","oauth"]}
```

**Example issues.jsonl**:

```json theme={null}
{"id":"ISSUE-001","uuid":"g7h8i9...","title":"Configure OAuth providers","content":"Set up OAuth providers...","status":"closed","priority":0,"assignee":null,"archived":0,"created_at":"2025-10-29T10:00:00Z","updated_at":"2025-10-29T14:00:00Z","closed_at":"2025-10-29T14:00:00Z","parent_id":null,"relationships":[{"from":"ISSUE-001","from_type":"issue","to":"SPEC-005","to_type":"spec","type":"implements"}],"tags":["auth","setup"],"feedback":[]}
{"id":"ISSUE-002","uuid":"j0k1l2...","title":"Implement token exchange","content":"Exchange codes for tokens...","status":"in_progress","priority":1,"assignee":"alice","archived":0,"created_at":"2025-10-29T10:30:00Z","updated_at":"2025-10-29T15:00:00Z","closed_at":null,"parent_id":null,"relationships":[{"from":"ISSUE-002","from_type":"issue","to":"SPEC-005","to_type":"spec","type":"implements"},{"from":"ISSUE-001","from_type":"issue","to":"ISSUE-002","to_type":"issue","type":"blocks"}],"tags":["auth","tokens"],"feedback":[{"id":"FEEDBACK-001","issue_id":"ISSUE-002","spec_id":"SPEC-005","feedback_type":"request","content":"Token expiration not specified...","anchor":{"type":"line","line":23},"dismissed":0}]}
```

### JSONL Structure

**Spec JSONL object:**

```json theme={null}
{
  "id": "SPEC-001",
  "uuid": "unique-uuid",
  "title": "Spec title",
  "content": "Full markdown content",
  "priority": 0,
  "status": "approved",
  "archived": 0,
  "created_at": "ISO timestamp",
  "updated_at": "ISO timestamp",
  "parent_id": null,
  "file_path": "specs/filename.md",
  "relationships": [
    {
      "from": "SPEC-001",
      "from_type": "spec",
      "to": "SPEC-002",
      "to_type": "spec",
      "type": "references"
    }
  ],
  "tags": ["tag1", "tag2"]
}
```

**Issue JSONL object:**

```json theme={null}
{
  "id": "ISSUE-001",
  "uuid": "unique-uuid",
  "title": "Issue title",
  "content": "Full content",
  "status": "open",
  "priority": 1,
  "assignee": null,
  "archived": 0,
  "created_at": "ISO timestamp",
  "updated_at": "ISO timestamp",
  "closed_at": null,
  "parent_id": null,
  "relationships": [...],
  "tags": ["tag1"],
  "feedback": [
    {
      "id": "FEEDBACK-001",
      "issue_id": "ISSUE-001",
      "spec_id": "SPEC-005",
      "feedback_type": "request",
      "content": "Feedback content",
      "anchor": {"type": "line", "line": 23},
      "dismissed": 0
    }
  ]
}
```

### Why JSONL?

**Git-friendly diffs:**

```diff theme={null}
# Adding a new spec is one line
+{"id":"SPEC-003","title":"New Spec",...}

# Updating a spec is one changed line
-{"id":"SPEC-001","title":"Old Title",...}
+{"id":"SPEC-001","title":"New Title",...}
```

**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:**

```bash theme={null}
sudocode export --output .sudocode/
```

**After sync:**

```bash theme={null}
sudocode sync  # Syncs markdown → database → JSONL
```

## 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

```
.sudocode/
└── sudocode.db            # Gitignored, rebuilt from JSONL
```

<Warning>
  **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`.
</Warning>

### Schema

The database uses the following tables:

**Core entity tables:**

```sql theme={null}
CREATE TABLE specs (
    id TEXT PRIMARY KEY,
    uuid TEXT NOT NULL UNIQUE,
    title TEXT NOT NULL,
    file_path TEXT NOT NULL,
    content TEXT NOT NULL,
    priority INTEGER NOT NULL DEFAULT 2,
    archived INTEGER NOT NULL DEFAULT 0,
    archived_at DATETIME,
    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL,
    parent_id TEXT,
    FOREIGN KEY (parent_id) REFERENCES specs(id)
);

CREATE TABLE issues (
    id TEXT PRIMARY KEY,
    uuid TEXT NOT NULL UNIQUE,
    title TEXT NOT NULL,
    content TEXT NOT NULL,
    status TEXT NOT NULL DEFAULT 'open',
    priority INTEGER NOT NULL DEFAULT 2,
    assignee TEXT,
    archived INTEGER NOT NULL DEFAULT 0,
    archived_at DATETIME,
    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL,
    closed_at DATETIME,
    parent_id TEXT,
    FOREIGN KEY (parent_id) REFERENCES issues(id)
);
```

**Relationship table:**

```sql theme={null}
CREATE TABLE relationships (
    from_id TEXT NOT NULL,
    from_type TEXT NOT NULL,
    to_id TEXT NOT NULL,
    to_type TEXT NOT NULL,
    relationship_type TEXT NOT NULL,
    created_at DATETIME NOT NULL,
    metadata TEXT,
    PRIMARY KEY (from_id, from_type, to_id, to_type, relationship_type)
);
```

**Tags table:**

```sql theme={null}
CREATE TABLE tags (
    entity_id TEXT NOT NULL,
    entity_type TEXT NOT NULL,
    tag TEXT NOT NULL,
    PRIMARY KEY (entity_id, entity_type, tag)
);
```

**Feedback table:**

```sql theme={null}
CREATE TABLE feedback (
    id TEXT PRIMARY KEY,
    issue_id TEXT NOT NULL,
    spec_id TEXT NOT NULL,
    feedback_type TEXT NOT NULL,
    content TEXT NOT NULL,
    agent TEXT,
    anchor TEXT,
    anchor_status TEXT NOT NULL DEFAULT 'valid',
    original_anchor TEXT,
    dismissed INTEGER NOT NULL DEFAULT 0,
    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL,
    FOREIGN KEY (issue_id) REFERENCES issues(id),
    FOREIGN KEY (spec_id) REFERENCES specs(id)
);
```

**Events table (audit log):**

```sql theme={null}
CREATE TABLE events (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    entity_id TEXT NOT NULL,
    entity_type TEXT NOT NULL,
    event_type TEXT NOT NULL,
    actor TEXT NOT NULL,
    old_value TEXT,
    new_value TEXT,
    comment TEXT,
    created_at DATETIME NOT NULL,
    git_commit_sha TEXT,
    source TEXT
);
```

**View: ready\_issues** (unblocked work):

```sql theme={null}
CREATE VIEW ready_issues AS
SELECT i.*
FROM issues i
WHERE i.status = 'open'
  AND i.archived = 0
  AND NOT EXISTS (
    SELECT 1 FROM relationships r
    JOIN issues blocker ON r.to_id = blocker.id
    WHERE r.from_id = i.id
      AND r.from_type = 'issue'
      AND r.to_type = 'issue'
      AND r.relationship_type = 'blocks'
      AND blocker.status IN ('open', 'in_progress', 'blocked')
  )
ORDER BY priority ASC, created_at DESC;
```

**View: blocked\_issues** (blocked work):

```sql theme={null}
CREATE VIEW blocked_issues AS
SELECT i.*, blocker.id as blocker_id, blocker.title as blocker_title
FROM issues i
JOIN relationships r ON r.from_id = blocker.id
JOIN issues blocker ON r.to_id = blocker.id
WHERE r.relationship_type = 'blocks'
  AND blocker.status IN ('open', 'in_progress', 'blocked')
  AND i.archived = 0
ORDER BY i.priority ASC;
```

### Why SQLite?

**Fast local queries:**

```bash theme={null}
# Find all P0 open issues
sudocode issue list --priority 0 --status open

# Find issues ready to work on
sudocode ready

# Find what's blocking work
sudocode blocked
```

**Relationship traversal:**

```bash theme={null}
# Find all issues implementing SPEC-005
sudocode issue list --implements SPEC-005

# Find all blockers for ISSUE-042
sudocode show ISSUE-042  # Shows incoming 'blocks' relationships
```

**Full-text search:**

```bash theme={null}
# Search for "OAuth" in all issues
sudocode issue list --search OAuth
```

**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:**

```bash theme={null}
git pull
sudocode sync  # Detects JSONL changes, imports to database
```

**Manual import:**

```bash theme={null}
sudocode import --input .sudocode/
```

**Fresh clone:**

```bash theme={null}
git clone your-repo
cd your-repo
sudocode sync  # Builds database from JSONL
```

## Data Flow

### Bidirectional Sync

Data flows between layers depending on the operation:

```
┌─────────────┐
│  Markdown   │ ← Human edits
│   .md files │
└──────┬──────┘
       │
       │ Parse frontmatter + content
       ↓
┌─────────────┐
│   SQLite    │ ← CLI operations
│ sudocode.db │
└──────┬──────┘
       │
       │ Export (debounced)
       ↓
┌─────────────┐
│    JSONL    │ ← Git tracked (source of truth)
│ *.jsonl     │
└─────────────┘
```

### Direction 1: Markdown → Database → JSONL

**Triggered by:** Manual markdown edits, `sudocode sync --from-markdown`

<Steps>
  <Step title="Parse markdown file">
    * Read frontmatter (YAML)
    * Extract content (markdown body)
    * Parse cross-references `[[SPEC-ID]]`
  </Step>

  <Step title="Update database">
    * Upsert spec/issue record
    * Create relationships from cross-references
    * Update tags
    * Update timestamps
  </Step>

  <Step title="Export to JSONL (debounced)">
    * Wait 5 seconds for more changes
    * Query all entities from database
    * Write complete JSONL files
    * Include embedded relationships and tags
  </Step>

  <Step title="Git commit (manual)">
    * Commit markdown + JSONL changes together
    * Context travels with code
  </Step>
</Steps>

**Example:**

```bash theme={null}
# 1. Human edits markdown
vim .sudocode/specs/oauth-integration.md

# 2. Sync to database
sudocode sync --from-markdown

# Output:
# Syncing from markdown to database...
#   ✓ updated spec SPEC-002
# Exported to JSONL

# 3. Commit changes
git add .sudocode/
git commit -m "Update OAuth spec with security requirements"
```

### Direction 2: Database → JSONL → Markdown

**Triggered by:** CLI operations, `sudocode sync --to-markdown`

<Steps>
  <Step title="CLI modifies database">
    * `sudocode issue create` → INSERT into issues table
    * `sudocode spec update` → UPDATE specs table
    * `sudocode link` → INSERT into relationships table
  </Step>

  <Step title="Export to JSONL (auto, debounced)">
    * Wait 5 seconds after last change
    * Query all entities
    * Write complete JSONL files
  </Step>

  <Step title="Sync to markdown (optional)">
    * `sudocode sync --to-markdown` regenerates markdown files
    * Frontmatter updated from database
    * Content preserved
  </Step>

  <Step title="Git commit (manual)">
    * Commit JSONL + markdown changes
  </Step>
</Steps>

**Example:**

```bash theme={null}
# 1. Create issue via CLI
sudocode issue create "Implement token refresh" \
  --priority 1 \
  --tags auth,tokens

# Output:
# Created ISSUE-053
# Exported to JSONL (debounced)

# 2. Sync to markdown (optional)
sudocode sync --to-markdown

# Output:
# Synced 1 entity to markdown
#   ✓ created issue ISSUE-053 → ISSUE-053.md

# 3. Commit changes
git add .sudocode/
git commit -m "Create token refresh issue (ISSUE-053)"
```

### Direction 3: JSONL → Database (After Git Pull)

**Triggered by:** `git pull`, `sudocode sync`, `sudocode import`

<Steps>
  <Step title="Git pull updates JSONL">
    * Teammate committed changes
    * JSONL files updated
    * Local markdown may be stale
  </Step>

  <Step title="Detect changes">
    * Compare JSONL modification time vs database
    * JSONL is newer → import needed
  </Step>

  <Step title="Import to database">
    * Parse JSONL files line by line
    * Upsert each entity (insert or update)
    * Rebuild relationships table
    * Rebuild tags table
    * Handle feedback anchors
  </Step>

  <Step title="Sync to markdown (optional)">
    * Update markdown files from database
    * Preserve content, update frontmatter
    * Create new markdown files if needed
  </Step>
</Steps>

**Example:**

```bash theme={null}
# 1. Pull changes
git pull

# Output:
# Updating abc123..def456
# .sudocode/issues/issues.jsonl | 2 ++
# 1 file changed, 2 insertions(+)

# 2. Sync database
sudocode sync

# Output:
# Detecting sync direction...
#   Issues JSONL is newer (2025-10-29 15:00 > 14:30)
# → Syncing FROM JSONL TO database
#
# Importing from JSONL...
#   ✓ updated issue ISSUE-042
#   ✓ created issue ISSUE-053
# Syncing to markdown...
#   ✓ updated ISSUE-042.md
#   ✓ created ISSUE-053.md
#
# ✓ Synced 2 entities

# 3. Now database and markdown are up to date
```

## Auto-Sync Mechanisms

### File Watching

sudocode can watch for file changes and auto-sync:

```bash theme={null}
sudocode sync --watch
```

**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:

```bash theme={null}
# Sync from markdown to database
sudocode sync --from-markdown

# Sync from database to markdown
sudocode sync --to-markdown

# Auto-detect direction
sudocode sync
```

**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:

<Steps>
  <Step title="Developer A creates spec">
    ```bash theme={null}
    sudocode spec create "New Feature" --priority 0
    # Creates SPEC-010
    # Exports to specs.jsonl
    git add .sudocode/
    git commit -m "Add new feature spec (SPEC-010)"
    git push
    ```
  </Step>

  <Step title="Developer B pulls changes">
    ```bash theme={null}
    git pull
    # .sudocode/specs/specs.jsonl updated
    sudocode sync
    # Imports SPEC-010 to local database
    # Creates specs/new-feature.md
    ```
  </Step>

  <Step title="Developer B creates issues">
    ```bash theme={null}
    sudocode issue create "Implement feature foundation" \
      --implements SPEC-010
    # Creates ISSUE-055
    # Links to SPEC-010
    git add .sudocode/
    git commit -m "Create implementation issues for SPEC-010"
    git push
    ```
  </Step>

  <Step title="Developer A pulls and sees new work">
    ```bash theme={null}
    git pull
    sudocode sync
    sudocode ready
    # Shows ISSUE-055 is ready to work on
    ```
  </Step>
</Steps>

### Merge Conflicts

**JSONL conflicts:**

```diff theme={null}
<<<<<<< HEAD
{"id":"SPEC-001","title":"Authentication System","priority":0,...}
=======
{"id":"SPEC-001","title":"Auth System","priority":1,...}
>>>>>>> feature-branch
```

**Resolution:**

1. **Manual:** Choose one version or merge fields
2. **AI-assisted:** Ask AI to merge based on semantics
3. **Import after resolution:**
   ```bash theme={null}
   # After resolving conflict
   sudocode import --input .sudocode/
   sudocode sync --to-markdown
   ```

### Branching Strategy

Context travels with code branches:

```bash theme={null}
# Create feature branch
git checkout -b feature/oauth-integration

# Create spec in branch
sudocode spec create "OAuth Integration" --priority 0

# Spec only exists in this branch
git commit -am "Add OAuth spec"

# Switch to main - spec is gone
git checkout main
sudocode spec list  # SPEC-005 not found

# Switch back - spec returns
git checkout feature/oauth-integration
sudocode spec list  # SPEC-005 exists
```

**Benefits:**

* Experimental specs in feature branches
* Merge specs with code when merging branch
* Context and code always in sync

## Best Practices

### Do's

<AccordionGroup>
  <Accordion title="✓ Commit JSONL with code">
    Always commit `.sudocode/` changes alongside related code:

    ```bash theme={null}
    git add .sudocode/ src/
    git commit -m "Implement OAuth (ISSUE-042)

    - Added OAuth token exchange
    - Updated SPEC-005 with learned details
    "
    ```

    Benefits:

    * Context travels with implementation
    * Code review includes design decisions
    * Git history is complete
  </Accordion>

  <Accordion title="✓ Run sync after git pull">
    Always sync database after pulling:

    ```bash theme={null}
    git pull
    sudocode sync
    ```

    Or use a git hook:

    ```bash theme={null}
    # .git/hooks/post-merge
    #!/bin/sh
    if [ -f .sudocode/specs/specs.jsonl ]; then
      sudocode sync
    fi
    ```
  </Accordion>

  <Accordion title="✓ Use watch mode during active development">
    For frequent spec editing:

    ```bash theme={null}
    # Terminal 1: Watch and auto-sync
    sudocode sync --watch

    # Terminal 2: Edit specs
    vim .sudocode/specs/auth-spec.md
    ```

    Changes sync automatically.
  </Accordion>

  <Accordion title="✓ Gitignore the database">
    Always add to `.gitignore`:

    ```
    .sudocode/sudocode.db
    .sudocode/sudocode.db-shm
    .sudocode/sudocode.db-wal
    ```

    Database is rebuilt from JSONL, never commit it.
  </Accordion>

  <Accordion title="✓ Use branches for experimental specs">
    Create specs in feature branches:

    ```bash theme={null}
    git checkout -b experiment/new-approach
    sudocode spec create "Experimental Approach"
    # Test the idea
    # If good: merge branch
    # If bad: delete branch (spec goes away)
    ```
  </Accordion>
</AccordionGroup>

### Don'ts

<AccordionGroup>
  <Accordion title="✗ Don't commit sudocode.db">
    **Wrong:**

    ```bash theme={null}
    git add .sudocode/sudocode.db
    ```

    **Right:**

    ```bash theme={null}
    # Add to .gitignore
    echo ".sudocode/sudocode.db*" >> .gitignore
    ```

    Database is a cache, not source of truth.
  </Accordion>

  <Accordion title="✗ Don't manually edit JSONL files">
    **Wrong:**

    ```bash theme={null}
    vim .sudocode/specs/specs.jsonl  # Manual editing
    ```

    **Right:**

    ```bash theme={null}
    # Edit markdown or use CLI
    vim .sudocode/specs/auth-spec.md
    sudocode sync --from-markdown
    ```

    JSONL is auto-generated, edits will be overwritten.
  </Accordion>

  <Accordion title="✗ Don't skip sync after git pull">
    **Wrong:**

    ```bash theme={null}
    git pull
    # Continue working without sync
    sudocode ready  # Stale data!
    ```

    **Right:**

    ```bash theme={null}
    git pull
    sudocode sync  # Update database
    sudocode ready  # Fresh data
    ```
  </Accordion>

  <Accordion title="✗ Don't force-resolve merge conflicts">
    **Wrong:**

    ```bash theme={null}
    # During merge conflict
    git checkout --theirs .sudocode/specs.jsonl
    # Loses your changes!
    ```

    **Right:**

    ```bash theme={null}
    # Resolve conflicts manually or with AI
    # Then import
    sudocode import --input .sudocode/
    ```
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Database out of sync after git pull">
    **Symptoms:** `sudocode list` shows stale data

    **Cause:** Pulled JSONL changes not imported to database

    **Solution:**

    ```bash theme={null}
    sudocode sync
    # Or force import
    sudocode import --input .sudocode/
    ```
  </Accordion>

  <Accordion title="Markdown files missing after git pull">
    **Symptoms:** JSONL has entities but no markdown files

    **Cause:** Markdown files not synced from database

    **Solution:**

    ```bash theme={null}
    sudocode sync --to-markdown
    ```

    Regenerates all markdown files from database.
  </Accordion>

  <Accordion title="JSONL changes not committed">
    **Symptoms:** CLI changes work locally but teammates don't see them

    **Cause:** JSONL files not committed to git

    **Solution:**

    ```bash theme={null}
    git status
    # Shows .sudocode/issues/issues.jsonl modified

    git add .sudocode/
    git commit -m "Update issues"
    git push
    ```
  </Accordion>

  <Accordion title="Database corrupted or locked">
    **Symptoms:** `Error: database is locked` or `database disk image is malformed`

    **Cause:** Concurrent access or corruption

    **Solution:**

    ```bash theme={null}
    # Delete database (it's a cache)
    rm .sudocode/sudocode.db*

    # Rebuild from JSONL
    sudocode import --input .sudocode/
    ```

    JSONL is source of truth, database can always be rebuilt.
  </Accordion>

  <Accordion title="Merge conflict in JSONL">
    **Symptoms:** Git merge conflict in `specs.jsonl` or `issues.jsonl`

    **Cause:** Two branches modified same entity

    **Solution:**

    **Option 1: Manual resolution**

    ```bash theme={null}
    # Edit JSONL file, choose correct version
    vim .sudocode/specs/specs.jsonl
    # Resolve conflict markers
    git add .sudocode/specs/specs.jsonl
    sudocode import --input .sudocode/
    ```

    **Option 2: AI-assisted**

    ```bash theme={null}
    # Ask AI to merge based on semantics
    # "Please merge these two versions of SPEC-001, keeping both changes"
    # AI provides merged JSON
    # Update JSONL manually
    sudocode import --input .sudocode/
    ```
  </Accordion>
</AccordionGroup>

## Architecture Diagrams

### 3-Layer Architecture

```
┌─────────────────────────────────────────────────────────┐
│                     Layer 1: Markdown                   │
│                  Human-editable files                   │
│                                                         │
│  .sudocode/specs/auth-system.md                        │
│  .sudocode/issues/ISSUE-042.md                         │
│                                                         │
│  YAML frontmatter + Markdown body                      │
│  Cross-references: [[SPEC-001]]                        │
└───────────────────────┬─────────────────────────────────┘
                        │
                        │ Parse / Generate
                        ↓
┌─────────────────────────────────────────────────────────┐
│                   Layer 3: SQLite                       │
│                   Query cache (local)                   │
│                                                         │
│  sudocode.db (gitignored)                              │
│                                                         │
│  Tables: specs, issues, relationships,                 │
│          tags, feedback, events                        │
│  Views: ready_issues, blocked_issues                   │
│                                                         │
│  Fast queries, joins, graph traversal                  │
└───────────────────────┬─────────────────────────────────┘
                        │
                        │ Export / Import
                        ↓
┌─────────────────────────────────────────────────────────┐
│                   Layer 2: JSONL                        │
│              Source of truth (git-tracked)              │
│                                                         │
│  .sudocode/specs/specs.jsonl                           │
│  .sudocode/issues/issues.jsonl                         │
│                                                         │
│  One JSON object per line                              │
│  Embedded relationships and tags                       │
│  Git-friendly line-based diffs                         │
│                                                         │
│  ✓ Committed to git                                    │
│  ✓ Distributed via git push/pull                       │
└─────────────────────────────────────────────────────────┘
```

### Data Flow

```
User Actions:
┌────────────────┐         ┌────────────────┐
│ Edit markdown  │         │  CLI commands  │
│   (vim, VSCode)│         │ (issue create) │
└───────┬────────┘         └───────┬────────┘
        │                          │
        │                          ↓
        │                  ┌───────────────┐
        │                  │    SQLite     │
        │                  │   Database    │
        │                  └───────┬───────┘
        │                          │
        ↓                          │
┌────────────────┐         Export (debounced)
│  Parse YAML +  │                │
│  Markdown      │                ↓
└───────┬────────┘         ┌──────────────┐
        │                  │    JSONL     │◄── Git tracked
        │                  │ (Source of   │    (push/pull)
        └──────────────────►  Truth)      │
                           └──────────────┘
                                  │
                            Import after
                             git pull
                                  │
                                  ↓
                           ┌──────────────┐
                           │   SQLite     │
                           │   Rebuilt    │
                           └──────────────┘
```

## Related Documentation

<CardGroup cols={3}>
  <Card title="Sync Commands" icon="arrows-rotate" href="/cli/sync">
    Manual sync operations
  </Card>

  <Card title="Export Command" icon="file-export" href="/cli/export">
    Export to JSONL
  </Card>

  <Card title="Import Command" icon="file-import" href="/cli/import">
    Import from JSONL
  </Card>

  <Card title="Specs Concept" icon="file-lines" href="/concepts/specs">
    Specification structure
  </Card>

  <Card title="Issues Concept" icon="list-check" href="/concepts/issues">
    Issue structure
  </Card>

  <Card title="Relationships" icon="link" href="/concepts/relationships">
    Linking entities
  </Card>
</CardGroup>

## Next Steps

<Steps>
  <Step title="Initialize sudocode">
    ```bash theme={null}
    cd your-project
    sudocode init
    ```
  </Step>

  <Step title="Verify .gitignore">
    ```bash theme={null}
    echo ".sudocode/sudocode.db*" >> .gitignore
    ```
  </Step>

  <Step title="Create first spec">
    ```bash theme={null}
    sudocode spec create "Your Feature" --priority 0
    ```

    Observe:

    * Markdown file created
    * Database updated
    * JSONL exported
  </Step>

  <Step title="Commit to git">
    ```bash theme={null}
    git add .sudocode/
    git commit -m "Add feature spec"
    ```

    JSONL travels with code!
  </Step>

  <Step title="Set up sync hook (optional)">
    ```bash theme={null}
    # .git/hooks/post-merge
    #!/bin/sh
    if [ -f .sudocode/specs/specs.jsonl ]; then
      sudocode sync --from-jsonl
    fi
    chmod +x .git/hooks/post-merge
    ```

    Auto-sync after git pull.
  </Step>
</Steps>

<Card title="Spec-Driven Development" icon="diagram-project" href="/workflows/spec-driven-development">
  Learn how to use the storage model in practice
</Card>
