Getting Started

From install to a fully populated workspace in about 10 minutes. Every command is copy-pasteable and shows the expected output.

Core concepts

A few terms show up in every command below. Here's the short version; the Core Concepts page covers each one in full.

TermWhat it is
WorkspaceA directory holding a backlog.db (and a config.toml). Every project, task, plan, and comment lives in that one SQLite file. Created by backlog init.
ProfileA named pointer to a workspace, registered in ~/.config/backlog/config.toml, so you can switch workspaces without typing paths.
ProjectA named group of tasks inside a workspace, identified by a short alias (e.g. api), the alias is what you pass to -p / --project.
TaskThe unit of work. Has a type, status, priority, and actor; addressed as TASK-N.
PlanA versioned markdown document attached to a task. Every edit creates a new immutable version.
CommentAn append-only, actor-attributed note on a task.
LabelA per-project tag for filtering tasks.
DocA versioned markdown document attached to a project (not a task): runbooks, ADRs, design notes.
MemoryA free-form, taggable, mutable note for cross-session agent context.
ActorThe human:name or ai:name attributed to every write.

Install

Requirements: Go 1.22+. No CGO. No external runtime dependencies.

Go install (recommended)
go install github.com/mazen160/backlog/cmd/backlog@latest

Or download a pre-built binary from GitHub Releases:

macOS (Apple Silicon)
curl -L https://github.com/mazen160/backlog/releases/latest/download/backlog_darwin_arm64.tar.gz | tar xz
sudo mv backlog /usr/local/bin/
Linux (amd64)
curl -L https://github.com/mazen160/backlog/releases/latest/download/backlog_linux_amd64.tar.gz | tar xz
sudo mv backlog /usr/local/bin/

Confirm the install:

backlog version
Output
backlog v1.0.3

Initialize a workspace

By default backlog init creates the workspace under ~/.backlog/<profile>. To keep it next to your code instead, pass --path:

backlog init --path ./my-project
cd my-project
Output
✓ workspace initialized: /Users/alice/my-project (profile: "default") [default]

This registers a profile named default and writes two files into the workspace:

FilePurpose
backlog.dbSQLite database: all tasks, projects, plans, comments, labels
config.tomlLocal workspace settings: default actor, project, and output format

init does not create a backlog.json. That file is an optional, hand-authored project manifest: you write it yourself (or commit it with your repo), and backlog sync reads it to create any listed projects that don't exist yet in the database. Sync is one-way (manifest → database) and never deletes.

Commit backlog.db to your repository so your team (and any AI agents working alongside you) share the same backlog. Add a backlog.json manifest too if you want project definitions tracked in plain text and reconciled with backlog sync.

To create a named workspace for use across directories, pass --profile:

backlog init --profile work          # creates ~/.backlog/work/backlog.db
backlog init --path ~/projects/api   # custom path

Create a project

A project groups tasks under a short alias, the identifier you type in every other command.

backlog project add "API Service" --alias api --repo-path /code/api
Output
ID:          01KR4H1TMRW3QAZ7D274SYCRJ1
Alias:       api
Name:        API Service
Repo:        /code/api
Created:     2026-05-08 12:29
backlog project add "Web Frontend" --alias web
backlog project list
Output
 ALIAS │ NAME         │ REPO      │ CREATED
───────┼──────────────┼───────────┼──────────────────
 api   │ API Service  │ /code/api │ 2026-05-08 12:29
 web   │ Web Frontend │           │ 2026-05-08 12:29

Set a default project so you can omit -p from most commands:

backlog project set-default api

Create tasks

backlog task add --project api --title "Fix login timeout" --type bug --priority P2
Output
ID:          01KR4H1ZYWGC3BQK01YBMM94P0
Project:     api
Title:       Fix login timeout
Type:        bug
Status:      todo
Priority:    P2
Actor:       human:alice
Created:     2026-05-08 12:29

The actor defaults to human:$USER. Pass --as to override:

backlog task add \
  --project api \
  --title "Reject unsigned JWTs in auth middleware" \
  --type vulnerability \
  --priority P1 \
  --source "security-review-2026-Q1" \
  --as human:alice

List open tasks:

backlog task list
Output
 ID       │ P  │ TYPE          │ STATUS │ TITLE                               │ PROJECT │ LABELS │ ACTOR
──────────┼────┼───────────────┼────────┼─────────────────────────────────────┼─────────┼────────┼───────
 01KR4H1Z │ P1 │ vulnerability │ todo   │ Reject unsigned JWTs in auth middl… │ api     │        │ alice
 01KR4H1Z │ P2 │ bug           │ todo   │ Fix login timeout                   │ api     │        │ alice

The ID column shows the first 8 characters of the ULID. You can use the prefix, the full ULID, or TASK-N interchangeably.

Move through the lifecycle

backlog task move TASK-1 --status doing
backlog task move TASK-1 --status done

All status transitions are valid in any direction:

todo  →  doing  →  done
  ↑___________|

Attach a plan

Plans are versioned markdown documents. Every edit creates an immutable new version, and old versions are always readable.

backlog plan add \
  --task TASK-1 \
  --title "Fix unsigned JWT rejection" \
  --content "## Steps
1. Extract JWT from Authorization header
2. Verify RS256 signature with JWKS endpoint
3. Return 401 on missing, malformed, or unsigned tokens
4. Add unit tests with forged tokens" \
  --as ai:claude-code

A human reviews and revises:

PLAN_ID="01KR4H25J062ANP3ZN6Z6GFDCM"

backlog plan update "$PLAN_ID" \
  --title "Fix unsigned JWT rejection (revised)" \
  --content "## Steps
1. Extract JWT from Authorization header
2. Verify RS256 signature with JWKS endpoint
3. Return 401 on missing, malformed, or unsigned tokens
4. Add unit tests with forged tokens
5. Rotate the signing key — current key may be compromised" \
  --change-note "added key rotation after security review" \
  --as human:alice

View version history:

backlog plan history "$PLAN_ID"
Output
 VER │ TITLE                                │ ACTOR          │ NOTE                                     │ CREATED
─────┼──────────────────────────────────────┼────────────────┼──────────────────────────────────────────┼──────────────────
 v1  │ Fix unsigned JWT rejection           │ ai:claude-code │                                          │ 2026-05-08 12:29
 v2  │ Fix unsigned JWT rejection (revised) │ human:alice    │ added key rotation after security review │ 2026-05-08 12:29

Add comments

backlog comment add --task TASK-1 \
  "JWKS endpoint is at /auth/.well-known/jwks.json — tested, returns correct keys."

backlog comment add --task TASK-1 \
  "Got it. Should we cache the keys?" \
  --as ai:claude-code

backlog comment add --task TASK-1 \
  "Yes — 1hr TTL, re-fetch on key-ID miss." \
  --as human:alice
backlog task show TASK-1 --with-plans --with-comments
Output
--- Comments (3) ---
2026-05-08 12:30 [human:alice]:    JWKS endpoint is at /auth/.well-known/jwks.json — tested.
2026-05-08 12:30 [ai:claude-code]: Got it. Should we cache the keys?
2026-05-08 12:30 [human:alice]:    Yes — 1hr TTL, re-fetch on key-ID miss.

Organize with labels

backlog label create --project api "security" --color "#e03e3e"
backlog label create --project api "auth"

backlog label attach --task TASK-1 security
backlog label attach --task TASK-1 auth

backlog task list --label auth

Bulk import from a scanner

Create a findings file, suitable for output from security scanners, AI triage agents, or any structured source:

findings.json
{
  "version": 1,
  "project": "api",
  "items": [
    {
      "title": "SQL injection in /users search endpoint",
      "type": "vulnerability",
      "priority": "P1",
      "source": "semgrep",
      "external_ref": "SEMGREP-001",
      "plans": [
        {
          "title": "Remediation",
          "body": "Replace string interpolation with parameterized queries."
        }
      ]
    },
    {
      "title": "Hardcoded credentials in config sample",
      "type": "vulnerability",
      "priority": "P2",
      "source": "semgrep",
      "external_ref": "SEMGREP-002"
    },
    {
      "title": "Outdated dependency: golang.org/x/net (CVE-2023-44487)",
      "type": "vulnerability",
      "priority": "P3",
      "source": "dependency-scan"
    }
  ]
}
# Dry run to preview
backlog import-findings findings.json --dry-run
Output
[dry-run] imported 3 tasks · 1 plans · 0 errors
backlog import-findings findings.json --as ai:semgrep
# Full-text search (FTS5)
backlog task list --search "injection"
backlog task list --search "sql*"            # prefix match
backlog task list --search "jwt OR csrf"     # boolean OR

# Combine filters
backlog task list --project api --type vulnerability --priority P1
backlog task list --actor-kind ai            # tasks created by AI agents
backlog task list --source semgrep           # tasks from a specific tool
backlog task list --status doing             # in-progress only

Export

backlog export --format json                     # machine-readable
backlog export --format csv --out tasks.csv      # spreadsheets
backlog export --format md                       # paste into PRs / reports

Open the web UI

The embedded web UI runs entirely from the binary, no additional setup:

backlog web                           # opens http://localhost:8080 in browser
backlog web --port 3000               # custom port
backlog web --port 3000 --no-browser  # don't auto-open

The web UI provides list, Kanban, and grid task views, versioned docs, memory entries, attachments, and an activity timeline. All API endpoints are also usable directly. See the API reference.

Connect an AI assistant

Start the MCP stdio server so an AI coding assistant can read and write your backlog directly, without CLI invocations:

backlog mcp serve --as ai:claude-code
For full configuration snippets for Claude Code, Cursor, Codex, and OpenCode (including how to set BACKLOG_DB so the server always finds the right workspace), see the MCP guide.