Issue trackers

Santree supports Linear, GitHub Issues, and a built-in Local (file-based) tracker behind a single interface. Each repo picks one.

  1. Choosing a tracker
  2. Linear
    1. Auth
    2. What gets fetched
    3. Triage inbox
    4. Branch naming
  3. GitHub Issues
    1. Auth
    2. What gets fetched
    3. Empty dashboard?
    4. Branch naming
  4. Cross-tracker resolution (Reviews tab)

Choosing a tracker

The active tracker is resolved in this order:

  1. SANTREE_TRACKER env var (one-off override — linear, github, or local)
  2. Per-repo _tracker.kind in .santree/metadata.json (linear / github / local)
  3. Legacy _linear.org (treated as Linear, for back-compat)
  4. Auto-detect — any Linear creds present → Linear, else GitHub

The easiest way to pick is the Issue tracker row under This repo in santree config:

santree config

Selecting that row drills into Local / Linear / GitHub, marks the one in use, and switches the moment you select. Picking Linear lets you choose an authenticated workspace or authenticate a new one inline; picking GitHub switches if gh is logged in, otherwise tells you to run gh auth login. The dashboard’s t key opens the same picker.

For one-off overrides (testing, scripting):

SANTREE_TRACKER=github santree dashboard

Linear

Santree fetches Linear ticket data via the GraphQL API (OAuth PKCE).

Auth

# Authenticate with Linear (opens browser for OAuth)
santree linear auth

# Check auth status
santree linear auth --status

# Verify a ticket fetches correctly
santree linear auth --test TEAM-123

# Log out
santree linear auth --logout

On first run, santree linear auth opens your browser to authorize the app with your Linear workspace. Tokens are stored in $XDG_CONFIG_HOME/santree/auth.json (defaults to ~/.config/santree/auth.json) and auto-refresh transparently.

To switch between authenticated workspaces for a repo, open the Issue tracker row in santree config and pick Linear — it lists every workspace you’ve authenticated (plus a row to authenticate a new one).

What gets fetched

  • Title, description, comments
  • State (name + type), priority, labels
  • Project name + ID
  • Triage SLA + snooze — the SLA breach time is surfaced as the urgency-coded SLA countdown badge on the Triage tab, and snoozed issues are greyed and sunk to the bottom there
  • Attached images — downloaded to /tmp/santree-images-<ticketId>/ and the URLs in the description are rewritten to local paths so Claude can read them. (Cleanup is handled by macOS clearing /tmp on reboot — no explicit cleanup runs.)

Triage inbox

Linear is the one tracker today with a native triage concept, so the dashboard grows a Triage tab when Linear is the active tracker. It lists the triage-state issues assigned to you that don’t have a worktree yet, ordered by SLA urgency, with the SLA countdown, the full comment thread, and an a key to ask Claude a read-only clarifying question about the issue before you commit to it. Snoozed issues are greyed and parked at the bottom so the active work stands out. Press s to see your team’s triage on-call rotation, pulled from Linear’s “Triage responsibility” schedule (current shift and your own shifts highlighted). See the Dashboard → Triage actions reference for the full keymap.

Branch naming

Linear’s parser is permissive: any uppercased letter prefix + dash + digits anywhere in the branch matches. See Branch naming.


GitHub Issues

Santree uses the existing gh CLI — no separate OAuth.

Auth

# Authenticate the gh CLI yourself (santree never does this for you):
gh auth login

# Then pick GitHub as this repo's tracker via the Issue tracker row:
santree config   # This repo → Issue tracker → GitHub

gh owns its own token; santree never writes a GitHub token of its own — that’s why you log in with gh auth login directly. Selecting GitHub in santree config only verifies the login and sets the tracker.

What gets fetched

Issues are listed via gh search issues --assignee=@me --state=open --repo <owner>/<name> — current repo only. Cross-repo issues aren’t surfaced today.

  • Title, body, comments
  • State (open / closed)
  • Labels — priority is derived from labels matching P0 / P1 / P2 / P3 / urgent / critical / high / medium / low, falling back to “No priority”
  • Project name = repository.nameWithOwner
  • Attached images on user-images.githubusercontent.com and github.com/.../assets/ are downloaded so Claude can read them when filling PR templates

Empty dashboard?

gh search issues --assignee=@me returns nothing if the issues you care about aren’t assigned to you. GitHub Projects affiliation doesn’t count — assignees do. If your team uses Projects without assignees, self-assign the issues you’re working on.

Branch naming

GitHub’s branch parser is strict to avoid false positives — a commit-style branch like fix-typo-1 would otherwise match issue 1. See Branch naming for the accepted patterns.


Cross-tracker resolution (Reviews tab)

When the Reviews tab encounters a PR whose branch was created using another tracker’s convention (e.g. a Linear-style TEAM-1234-… branch in a repo configured for GitHub Issues), santree’s getCandidateTrackers() falls back to other trackers with active credentials. If Linear is authed, the Linear ticket context shows up in the PR detail panel even though the repo’s active tracker is GitHub.

This is by design — your repo is configured one way, but contributors may use whatever convention they like.