Architecture
Deep dive into BackMark's technical architecture, design decisions, and implementation details.
Project Structure
Directory Layout
When you initialize BackMark, it creates this structure:
your-project/
├── backlog/ # BackMark root directory
│ ├── tasks/ # Task markdown files
│ │ ├── 1.md
│ │ ├── 2.md
│ │ └── ...
│ ├── templates/ # Custom task templates
│ │ ├── feature.md
│ │ ├── bugfix.md
│ │ └── custom-template.md
│ ├── config.yml # Project configuration
│ └── .cache/ # Performance cache (auto-generated)
│ └── tasks-index.db
└── [your project files]
tasks/ Directory
Contains all task files as Markdown with YAML frontmatter.
- Naming:
{id}.md - Each file is a complete task
- Human-readable and editable
- Perfect for version control
.cache/ Directory
Optional LokiJS database for fast queries.
- Auto-generated when indexing enabled
- Syncs with file mtime
- Safe to delete (regenerates)
- 50-250x faster than file scanning
Task File Structure
Anatomy of a Task File
Every task file has two parts: YAML frontmatter (metadata) and Markdown body (content).
---
# === Core Metadata ===
id: 42
title: "Implement fuzzy search"
status: "In Progress"
priority: "high"
# === Dates ===
# Manual (user-planned)
start_date: "2024-11-01"
end_date: "2024-11-05"
release_date: "2024-11-10"
# Automatic (system-tracked)
created_date: "2024-11-01T09:00:00Z"
updated_date: "2024-11-06T14:30:00Z"
closed_date: null
# === Organization ===
milestone: "v1.0"
assignees: ["@alice", "Claude"]
labels: ["feature", "search", "performance"]
# === Hierarchy ===
parent_task: null
subtasks: [43, 44, 45]
dependencies: [40, 41]
blocked_by: []
# === Acceptance Criteria ===
acceptance_criteria:
- text: "Search works with fuzzy matching"
checked: true
- text: "Response time under 100ms"
checked: false
# === Changelog (automatic) ===
changelog:
- timestamp: "2024-11-01T09:00:00Z"
action: "created"
details: "Task created"
user: "@alice"
- timestamp: "2024-11-06T10:00:00Z"
action: "status_changed"
details: "status: To Do → In Progress"
user: "Claude"
# === AI Spaces ===
ai_plan: |
## Implementation Steps
1. Install Fuse.js...
ai_notes: |
**2024-11-06 10:30** - Started implementation...
ai_documentation: |
## Fuzzy Search
### Usage...
ai_review: |
## Self Review
✅ All tests passing...
---
# Implement fuzzy search
## Description
Add fuzzy search capability to task list using Fuse.js library.
Users should be able to search by title, description, labels, and assignees.
## Technical Details
- Library: Fuse.js v7.0.0
- Search threshold: 0.3 (configurable)
- Indexed fields: title, description, labels, assignees
## Expected Outcome
Users can quickly find tasks even with typos or partial matches.
Configuration File
config.yml Structure
project:
name: "My Project"
createdAt: "2024-11-01T09:00:00Z"
board:
columns:
- "To Do"
- "In Progress"
- "Review"
- "Done"
priorities:
- "low"
- "medium"
- "high"
- "critical"
completedStatuses:
- "Done"
- "Cancelled"
performance:
useIndex: true # Enable LokiJS indexing
rebuildIndexOnStart: false # Rebuild on every start
validations:
close:
check_subtasks: true
check_dependencies: true
check_blocked_by: true
check_acceptance_criteria: true
warn_missing_ai_review: true
warn_early_close: true
warn_late_close: true
warn_quick_close: 300 # Seconds
suggest_parent_close: true
notify_unblocked: true
allow_force: true
search:
threshold: 0.3 # Fuse.js threshold (0.0-1.0)
maxResults: 50 # Max search results
All settings are optional with sensible defaults.
Dual Repository System
Why Two Repositories?
BackMark uses a dual repository pattern to optimize for both simplicity and performance. The system automatically chooses the appropriate repository based on your configuration.
FileSystemRepository
Direct File Operations
How it works:
- Reads Markdown files directly
- Parses YAML frontmatter on demand
- No caching or indexing
- Simple and transparent
Best for:
- ✅ Small projects (<100 tasks)
- ✅ Development and testing
- ✅ Maximum transparency
- ✅ Zero overhead
Performance:
- List 100 tasks: ~100ms
- Search 100 tasks: ~150ms
LokiIndexedRepository
In-Memory Indexed Queries
How it works:
- Maintains in-memory LokiJS database
- Syncs with file mtime automatically
- Incremental updates only
- Transparent cache invalidation
Best for:
- ✅ Large projects (100+ tasks)
- ✅ Production use
- ✅ Frequent queries
- ✅ Maximum performance
Performance:
- List 1000 tasks: ~10ms
- Search 1000 tasks: ~20ms
- 50-250x faster!
Enabling Indexing
backmark config set performance.useIndex true
The cache is automatically managed - no manual intervention needed!
Tech Stack
Core Dependencies
- commander - CLI framework
- inquirer - Interactive prompts
- chalk - Terminal colors
- ora - Progress spinners
- cli-table3 - Formatted tables
File Processing
- gray-matter - YAML frontmatter parser
- js-yaml - YAML serialization
- date-fns - Date manipulation
Performance & Search
- lokijs - In-memory indexing
- fuse.js - Fuzzy search
Quality & Validation
- zod - Schema validation
- typescript - Type safety
- vitest - Testing (80%+ coverage)
Design Decisions
Why Markdown + YAML?
- ✅ Human-readable
- ✅ Git-friendly
- ✅ Editor-agnostic
- ✅ Future-proof
- ✅ No vendor lock-in
- ✅ Easy migration
Why Local Files?
- ✅ 100% offline
- ✅ Complete privacy
- ✅ No cloud dependencies
- ✅ Fast access
- ✅ Version control ready
- ✅ Backup with your files
Why TypeScript?
- ✅ Type safety
- ✅ Better IDE support
- ✅ Fewer runtime errors
- ✅ Self-documenting code
- ✅ Easier refactoring
Why CLI (not GUI)?
- ✅ Developer-friendly
- ✅ Scriptable/automatable
- ✅ SSH-friendly
- ✅ Low resource usage
- ✅ Fast and efficient
Data Flow
Task Creation Flow
User Command
↓
Commander Parser
↓
Create Task Command
↓
Generate Task ID (auto-increment)
↓
Build Task Object (with metadata)
↓
Validate with Zod Schema
↓
Serialize to Markdown + YAML
↓
Write to backlog/tasks/{id}.md
↓
Update Index (if enabled)
↓
Display Success Message
Task Query Flow
User Command (e.g., list --status "In Progress")
↓
Commander Parser
↓
List Tasks Command
↓
Choose Repository (FileSystem vs LokiIndexed)
↓
Query Tasks with Filters
├─ FileSystem: Scan all files, parse, filter
└─ LokiIndexed: Query in-memory DB (fast!)
↓
Apply Additional Filters (status, priority, etc.)
↓
Sort Results
↓
Format as Table (cli-table3)
↓
Colorize Output (chalk)
↓
Display to User
Performance Optimizations
LokiJS Indexing
In-memory database provides sub-10ms query times for 1000+ tasks.
Incremental Sync
Only changed files are re-indexed using mtime comparison.
Lazy Loading
Task content only loaded when viewing details.
Efficient Parsing
gray-matter optimized for YAML frontmatter parsing.
Fuzzy Search Cache
Fuse.js index cached for repeated searches.
Minimal Dependencies
Only 87 packages installed, most are lightweight.
Extensibility
Custom Task Templates
Create templates in backlog/templates/:
# backlog/templates/custom.md
---
priority: "medium"
labels: ["custom"]
---
# {{title}}
## Custom Section
Your template content here...
Use with:
backmark task create-from-template custom "My Task"
Configuration Customization
Modify config.yml to customize:
- Board columns and statuses
- Priority levels
- Validation rules
- Search thresholds
- Performance settings