Issue Backends

Purpose

The Issue Backend system provides a pluggable abstraction for issue tracking, allowing fab to work with multiple issue tracking systems (tk, GitHub Issues, Linear) through a unified interface.

Non-goals:

Interface

The system defines several interfaces in internal/issue/backend.go:

Interface Description
IssueReader Read-only access: Get, List, Ready
IssueWriter Write access: Create, CreateSubIssue, Update, Close, Commit
Backend Combines IssueReader and IssueWriter
IssueCollaborator Collaboration features: AddComment, UpsertPlanSection, CreateSubIssue
CollaborativeBackend Combines Backend and IssueCollaborator

Core Types

type Issue struct {
    ID           string
    Title        string
    Description  string
    Status       Status      // open, closed, blocked
    Priority     int         // 0=low, 1=medium, 2=high
    Type         string      // task, bug, feature, chore
    Dependencies []string    // IDs of blocking issues
    Labels       []string
}

Configuration

Issue backends are configured per-project in ~/.config/fab/config.toml:

Project Configuration Keys

Key Type Description
issue-backend string Backend type: tk, github, gh, or linear
allowed-authors []string Usernames allowed to create issues (GitHub or Linear)
linear-team string Linear team ID (required for Linear backend)
linear-project string Linear project ID (optional, scopes issues)

Provider API Keys

API keys are configured globally under [providers.<name>]:

Provider Config Key Environment Variable
GitHub [providers.github] with api-key GITHUB_TOKEN or GH_TOKEN
Linear [providers.linear] with api-key LINEAR_API_KEY

Paths

Verification

Run the unit tests for the issue package:

$ go test ./internal/issue/... -v -count=1 2>&1 | head -30
=== RUN

Run the tk backend parser tests:

$ go test ./internal/issue/tk -run TestParse -v
=== RUN   TestParseIssue

Examples

tk Backend Configuration

The tk backend stores issues as markdown files in .tickets/:

[[projects]]
name = "myproject"
remote-url = "git@github.com:user/repo.git"
issue-backend = "tk"

Issues are stored as .tickets/<id>.md with YAML frontmatter:

---
id: fa-123
title: Fix the bug
status: open
priority: 1
type: bug
deps: [fa-100]
---

Description of the issue here.

GitHub Backend Configuration

# Global provider config
[providers.github]
api-key = "ghp_xxxxx"  # or use GITHUB_TOKEN env

# Project config
[[projects]]
name = "myproject"
remote-url = "git@github.com:user/repo.git"
issue-backend = "github"  # or "gh"
allowed-authors = ["owner", "contributor"]

Linear Backend Configuration

# Global provider config
[providers.linear]
api-key = "lin_api_xxxxx"  # or use LINEAR_API_KEY env

# Project config
[[projects]]
name = "myproject"
remote-url = "git@github.com:user/repo.git"
issue-backend = "linear"
linear-team = "TEAM-UUID"
linear-project = "PROJECT-UUID"  # optional
allowed-authors = ["user@example.com"]  # optional

Gotchas

Decisions

Interface split: The read/write/collaborator split allows backends to implement only what they support. A backend can satisfy Backend without implementing IssueCollaborator if it doesn't support comments or plans.

tk as default: The tk backend is the primary backend, storing issues in-repo as markdown files. This enables offline work and keeps issues versioned with code.

GraphQL for GitHub/Linear: Both external backends use GraphQL APIs for richer query capabilities and to support features like blockedBy relationships and sub-issues.

Priority normalization: Each backend maps its native priority system to fab's 0-2 scale, ensuring consistent behavior across backends while preserving backend-specific semantics.