Lattice
A workspace for your research.
A unified CLI for project management tools and wikis. One interface for issues, documentation, and repeatable workflows — fetch every page, emit JSON, dry-run bulk plans, and resume long operations.
ProductivityRust · ShellGitHub @OrekGamesOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Project planning CLI for YouTrack, Jira, GitHub, GitLab, etc. easily wraps all commands into a singular AI agent friendly model to enable easy integrations and powerful workflows.
Loading the full README. The saved excerpt is shown below.
A command-line interface for issue tracking systems, built with Rust. Supports YouTrack, Jira, GitHub, GitLab, and Linear with a unified command interface.Read the full README ↗A command-line interface for issue tracking systems, built with Rust. Supports YouTrack, Jira, GitHub, GitLab, and Linear with a unified command interface.
--all flag auto-paginates to fetch every resultmacOS and Linux:
curl -fsSL https://raw.githubusercontent.com/OrekGames/track-cli/main/scripts/install.sh | bash
Windows PowerShell:
irm https://raw.githubusercontent.com/OrekGames/track-cli/main/scripts/install.ps1 | iex
The native installers download the latest GitHub release archive, verify it with
checksums-sha256.txt, install track into a user-owned directory, and install
shell completions where supported. Override the install directory with
TRACK_INSTALL_DIR, or set TRACK_SKIP_PATH=1 to skip shell startup file or
user PATH changes. Pin a release with TRACK_VERSION:
curl -fsSL https://raw.githubusercontent.com/OrekGames/track-cli/v1.15.1/scripts/install.sh | TRACK_VERSION=1.15.1 bash
$env:TRACK_VERSION = "1.15.1"; irm https://raw.githubusercontent.com/OrekGames/track-cli/v1.15.1/scripts/install.ps1 | iex
Agent skills are optional and installed explicitly after the CLI is available.
track init --skills installs the bundled track reference for Claude Code,
GitHub Copilot, Cursor, and Gemini CLI:
track init --skills
brew tap OrekGames/tap
brew install track
Shell completions for bash, zsh, and fish are installed automatically.
To install the agent skill for Claude Code, Copilot, Cursor, and Gemini CLI, run
track init --skills (Homebrew can't write into your home directory itself).
cargo install --path crates/track
Download prebuilt binaries from the latest release. Archives are available for macOS (arm64, x86_64), Linux (x86_64, arm64), and Windows (x86_64, arm64).
Create a .track.toml file in your project directory or ~/.tracker-cli/.track.toml for global configuration.
Project configs can contain API tokens. If a .gitignore exists in the current directory, local track init adds .track.toml and .tracker-cache/ automatically; otherwise add those entries before committing:
Create a GitHub personal access token
that can access issues in the target repository. Replace
YOUR_GITHUB_TOKEN and owner/repo below; owner/repo is the repository
path, for example OrekGames/track-cli.
track init \
--backend github \
--url https://api.github.com \
--token YOUR_GITHUB_TOKEN \
--project owner/repo
track i s "is:open"
track init validates the repository and writes a local .track.toml; the
next command searches open issues using that saved GitHub configuration. See
the GitHub backend notes
and configuration reference
for backend behavior and other configuration methods.
# Initialize with YouTrack (default)
track init --url https://youtrack.example.com --token YOUR_TOKEN
# Or initialize with Jira
track init --url https://your-domain.atlassian.net --token YOUR_TOKEN --backend jira --email [email protected]
# Or initialize with Linear (URL is the Linear workspace URL used by `track open`)
track init --url https://linear.app/your-workspace --token YOUR_LINEAR_API_KEY --backend linear --project PROJ
For AI-assisted workflows, install the agent skill reference once per user:
track init --skills
This installs guidance for Claude Code, GitHub Copilot, Cursor, and Gemini CLI.
track config project PROJ
track config test # Quick connectivity check (URL + token)
track doctor # Deeper capability audit (search, reads, fields, articles, ...)
# Get an issue
track PROJ-123
# Search issues
track issue search "project: PROJ #Unresolved" --limit 10
# Create an issue
track issue create -p PROJ -s "Fix bug" -d "Description"
Configuration priority order (highest to lowest):
--url, --token, --backend, etc..track.toml in current directory~/.config/track/config.tomlCreate .track.toml in your project directory or ~/.config/track/config.toml:
# .track.toml
backend = "youtrack"
url = "https://youtrack.example.com"
token = "perm:base64user.base64name.token"
default_project = "PROJ"
# .track.toml
backend = "jira"
[jira]
url = "https://your-domain.atlassian.net"
email = "[email protected]"
token = "your-api-token"
# .track.toml
backend = "linear"
default_project = "PROJ" # Linear team key/name/id
[linear]
token = "lin_api_xxxxxxxxxxxx"
url = "https://linear.app/your-workspace" # for `track open`
# api_url = "https://api.linear.app/graphql" # default
# default_team = "PROJ" # optional alias for default_project
# default_linear_project = "Track CLI" # optional issue Project association
You can configure multiple backends in a single config file and switch between them:
# .track.toml
# Set your default backend
backend = "youtrack"
# YouTrack configuration
url = "https://youtrack.example.com"
token = "perm:base64user.base64name.token"
default_project = "PROJ"
# Jira configuration
[jira]
url = "https://your-domain.atlassian.net"
email = "[email protected]"
token = "your-api-token"
# Optional: override link type name mappings per backend
# [jira.link_mappings]
# depends = "Requires"
With this setup, you can use the default backend (YouTrack) or switch to another backend:
track PROJ-123 # Uses YouTrack (default)
track -b jira PROJ-123 # Uses Jira
track -b lin ORE-123 # Uses Linear
# Or switch the default backend
track config backend jira # Set Jira as default
track config backend linear # Set Linear as default
Environment variables override config file settings:
# Generic (any backend)
export TRACKER_BACKEND=youtrack
export TRACKER_URL=https://youtrack.example.com
export TRACKER_TOKEN=YOUR_TOKEN
# YouTrack-specific
export YOUTRACK_URL=https://youtrack.example.com
export YOUTRACK_TOKEN=YOUR_TOKEN
# Jira-specific
export JIRA_URL=https://your-domain.atlassian.net
export [email protected]
export JIRA_TOKEN=your-api-token
# GitHub-specific
export GITHUB_TOKEN=ghp_xxx
export GITHUB_OWNER=your-org
export GITHUB_REPO=your-repo
# GitLab-specific
export GITLAB_TOKEN=glpat_xxx
export GITLAB_URL=https://gitlab.com/api/v4
export GITLAB_PROJECT_ID=12345
# Linear-specific
export LINEAR_TOKEN=lin_api_xxx
export LINEAR_URL=https://linear.app/your-workspace
export LINEAR_DEFAULT_TEAM=PROJ
# export LINEAR_API_URL=https://api.linear.app/graphql
# export LINEAR_DEFAULT_PROJECT="Track CLI"
# HTTPS behind a proxy that inspects it (see "HTTPS proxies and certificates")
export SSL_CERT_FILE=/path/to/proxy-ca.pem
export TRACKER_SYSTEM_CERTS=true
Default backend is YouTrack. You can specify which backend to use in three ways:
# .track.toml
backend = "youtrack" # or "jira", "github", "gitlab", "linear"
Or use the CLI to set it:
track config backend youtrack
track config backend jira
track config backend linear
export TRACKER_BACKEND=jira
track PROJ-123 # Uses Jira
track -b jira PROJ-123 # Use Jira for this command
track -b youtrack PROJ-123 # Use YouTrack
track -b linear PROJ-123 # Use Linear
# Short aliases
track -b j PROJ-123 # Jira
track -b yt PROJ-123 # YouTrack
track -b lin PROJ-123 # Linear
Priority: CLI flag > Environment variable > Config file > Default (YouTrack)
A .track.toml committed to a repository is read whenever you run track in
that directory. Because config layers merge key by key, such a file could set
only a URL and have track send the token from your global config,
environment or --token to a host the repository chose. track refuses that
before sending anything:
Error: Refusing to send your youtrack token to https://attacker.example.
The check only applies when the repository file sets a token destination
(url, [backend].url, github.api_url, linear.api_url) that differs from
your own configuration's and does not also supply the token. A repository
.track.toml holding both URL and token (what track init writes), or only
settings such as default_project, is unaffected. To allow a repository you
trust, or to bypass its config:
track config trust # Allow this directory's .track.toml to receive your token
track config untrust # Revoke it (changing the URL also requires trusting again)
track --config ~/.tracker-cli/.track.toml ... # Ignore the repository's .track.toml
track config show and track doctor report a redirected token as well.
track trusts the Mozilla root certificates built into it, the same set on
every machine. A corporate proxy that inspects HTTPS re-signs traffic with its
own certificate authority, so requests fail with invalid peer certificate: UnknownIssuer. Trust that authority in either of two ways:
export SSL_CERT_FILE=/path/to/proxy-ca.pem # PEM file(s), as OpenSSL-based tools read them
# (SSL_CERT_DIR works too)
track config set system_certs true # Or trust your operating system's certificates
# (TRACKER_SYSTEM_CERTS=true for one run)
Both add certificates to the built-in roots; nothing they trusted before is
dropped. SSL_CERT_FILE / SSL_CERT_DIR take precedence over the system
store when set. With neither, track uses exactly the built-in roots.
track PROJ-123 # Get issue (shortcut)
track PROJ-123 --full # With comments, links, subtasks
track open PROJ-123 # Open in browser
# Get
track issue get PROJ-123
track i g PROJ-123 --full
# Create (with validation)
track issue create -p PROJ -s "Summary" -d "Description"
track i new -s "Subtask" --parent PROJ-100 --priority "Major"
track i new -p PROJ -s "Title" --field "Priority=Major" --validate
# Update (single or batch)
track issue update PROJ-123 --summary "New title"
track i u PROJ-123 --field "Priority=Critical"
track i u PROJ-1,PROJ-2,PROJ-3 --field "Priority=Major" # Batch update
track i u PROJ-123 --assignee @username # GitLab: @-prefixed username (case-insensitive)
track i u PROJ-123 --assignee 7 # GitLab: numeric user id (verified server-side)
track i u PROJ-123 --assignee "" # Clear assignees (GitLab also accepts "0" or "@0")
# State transitions (single or batch)
track issue start PROJ-123 # In progress
track issue complete PROJ-123 # Done
track i start PROJ-1,PROJ-2,PROJ-3 # Batch start
track i done PROJ-1,PROJ-2 --state Done # Batch complete
# Search (with query or template)
track issue search "project: PROJ #Unresolved" --limit 20
track i s "project: PROJ State: Open"
track i s --template unresolved --project PROJ # Use query template
track i s "project: PROJ #Unresolved" --all # Fetch all pages
track i s "project: PROJ #Unresolved" -o json --select id_readable,summary # Projected JSON
track i s "project: PROJ #Unresolved" -o jsonl # JSON Lines: one issue per line
track i s "project: PROJ #Unresolved" -o jsonl --select id_readable,summary # Projected JSON Lines
`--select` (JSON/JSONL only) takes comma-separated dotted paths (e.g. `id_readable,project.short_name`)
and emits only those fields per issue; missing paths are omitted. It is rejected in text mode and
for any command other than `issue search`.
# Inspect many issues at once (per-issue success/failure, opt-in context)
track issue inspect PROJ-1,PROJ-2,PROJ-3 -o json
track i ix --ids ids.txt --include comments,links -o json # IDs from file ("-" for stdin)
track i ix --query "project: PROJ #Unresolved" --all --include all -o json
track i ix --template unresolved --project PROJ --limit 50 --jsonl # One JSON object per line
track i ix PROJ-1,PROJ-404 --strict # Exit non-zero if any issue fails (after full report)
# Delete (single or batch)
track issue delete PROJ-123
track i del PROJ-1,PROJ-2,PROJ-3 # Batch delete
track issue comment PROJ-123 -m "Comment text"
track issue comments PROJ-123 --limit 10
Show an issue's change history — the time-ordered timeline of field transitions (status changes, assignee changes, etc.) with timestamps and authors. Supported on all backends.
track issue history PROJ-123 # Full timeline, newest first
track i hist PROJ-123 --field status # Only status transitions
track i history PROJ-123 --since 7d # Last 7 days (s/m/h/d/w)
track -o json i history PROJ-123 # {"issue": id, "changes": [...]}
track -b gh i history 42 # GitHub (numeric id)
from/to coverage varies by backend: Jira, YouTrack, and Linear carry the
prior value for every field; the event-based backends (GitHub, GitLab) populate
from only for status and report from: null for other fields. (Linear
label-change history is not yet included.)
track issue link PROJ-1 PROJ-2 # Relates (default)
track issue link PROJ-1 PROJ-2 -t depends # Depends on
track issue link PROJ-1 PROJ-2 -t subtask # Subtask
track issue link PROJ-1 PROJ-2 -t clones # Custom/admin-defined type
# Unlink (remove a link by its ID — get link IDs from `track i g PROJ-1 --full`)
track issue unlink PROJ-1 "142-3t/PROJ-2" # YouTrack (composite ID)
track -b j issue unlink PROJ-1 12345 # Jira (numeric link ID)
track -b gl issue unlink 42 789 # GitLab (numeric link ID)
track -b lin issue unlink ORE-1 <link-id> # Linear (relation ID or linear-parent/child ID)
Built-in link types: relates, depends, required, duplicates, duplicated-by, subtask, parent
Unrecognized type names are passed through to the backend as-is, so admin-defined link types (e.g., clones, causes) work without CLI changes.
Each backend maps canonical link type names (like depends) to its native name (e.g., "Blocks" on Jira, "Depend" on YouTrack). You can override these mappings in your config file:
# Override Jira's default mapping for "depends" (default: "Blocks")
[jira.link_mappings]
depends = "Requires"
duplicates = "Cloners"
# Override YouTrack's default mapping
[youtrack.link_mappings]
depends = "Is required for"
# Override GitLab's default mapping
[gitlab.link_mappings]
depends = "is_blocked_by"
# Override Linear's default mapping
[linear.link_mappings]
relates = "similar"
This is useful when your instance has custom or renamed link types.
track project list
track project get PROJ
track project fields PROJ # Custom fields
track project create -n "Name" -s "KEY" # YouTrack only (defaults leader to authenticated user; --leader is ignored for non-YouTrack backends)
track project create -n "Name" -s "KEY" -l "username" # Specify explicit leader (YouTrack only)
track tags list # Lists tags/labels for the configured backend
Note: GitHub and GitLab use labels instead of tags. The CLI maps labels to the common IssueTag model.
# List all custom field definitions
track field list
# Create a field definition
track field create "Priority" -t enum
# Create field with values and attach to project (convenience command)
track field new "Sprint Phase" -t enum -p PROJ -v "Planning,Development,Testing,Done"
# For state fields with resolved markers
track field new "Bug Status" -t state -p PROJ -v "Open,In Progress,Fixed,Closed" --resolved "Fixed,Closed"
# List bundles by type
track bundle list -t enum
track bundle list -t state
# Create a bundle with values
track bundle create "Priority Levels" -t enum -v "Low,Medium,High,Critical"
# Add value to existing bundle
track bundle add-value <bundle-id> -t enum -v "Urgent"
# Attach a field to a project
track project attach-field PROJ -f <field-id> --bundle <bundle-id>
YouTrack uses its built-in Knowledge Base. Jira uses Confluence (automatically at same domain with /wiki path).
# YouTrack
track article get KB-A-1
track article list --project PROJ
track article search "query"
track article create --project PROJ --summary "Title" --content "Body"
track article update KB-A-1 --content-file ./doc.md
# Jira/Confluence (use numeric space ID for --project)
track -b j article get 123456
track -b j article list --project 65957 --limit 20
track -b j article search "query"
track -b j article create --project 65957 --summary "Title" --content "Body"
track -b j article update 123456 --summary "New Title"
track -b j article delete 123456
track config test # Test connection
track config show # Show current config
track config backend jira # Set default backend
track config project PROJ # Set default project
track config set <key> <value> # Set any config value
track config get <key> # Get a config value
track config keys # List all available config keys
track config clear # Clear default project and backend
track config path # Show config file path
track config trust # Allow this directory's .track.toml to receive your own token
track config untrust # Revoke config trust for this directory
track config set system_certs true # Also trust the OS certificate store (HTTPS proxies)
track doctor # Audit the configured backend
track doctor --all-backends # Audit every configured backend
track -b gitlab doctor # Audit a specific backend
track doctor --project PROJ # Use a specific project for scoped checks
track doctor --write-check # Also validate write payloads locally (no remote writes)
track doctor --all-backends --strict -o json # CI-friendly: non-zero exit if any check or backend failed
config test vs doctor: config test runs a single connectivity probe
(list_projects) and tells you whether the URL and token work at all.
doctor audits what the backend can actually do: it runs non-mutating checks
for config validity, auth/connectivity, project resolution, issue search/read,
comments, links, field schema, field admin, and articles, and reports each as
ok, degraded (e.g. valid token missing a scope), failed, or skipped
(capability not supported by the backend). A token can pass config test but
lack scopes for specific operations — or fail config test while search/read
still work; doctor distinguishes those cases and never mutates remote
trackers (--write-check only validates against the locally fetched field
schema). A backend rolls up failed only when nothing practical works — bad
credentials, or a broken read path (e.g. every call 404s under a wrong
project id). Exit code is 0 unless --strict is passed and a check or
backend failed (degraded stays 0).
track cache refresh # Refresh local cache (includes issue counts)
track cache refresh --if-stale 1h # Only refresh if older than 1 hour
track cache status # Check cache age and freshness
track cache show # Show cached data
track cache path # Show cache location
The cache stores comprehensive tracker context for fast lookups:
Cached built-in templates are backend-scoped: the cache records which backend wrote it, and
workflow list / template resolution only expose templates whose backend matches the selected
one. A repository workflow pack ([workflow_pack] in .track.toml) takes precedence over
cache-built-ins on name collision (shadowing); pack queries are never written into the cache.
Run track cache refresh after switching backends.
A [workflow_pack] in .track.toml defines project-local query templates:
[workflow_pack]
name = "Orek backlog"
default_project = "PROJ"
[[workflow_pack.queries]]
name = "ready"
description = "Issues ready for implementation."
query = "project: {PROJECT} #Unresolved State: {Ready}"
track workflow list # Pack queries first, then unshadowed cached built-ins (offline)
track workflow show # Selected pack, source, and queries
track workflow validate # Offline; shadows_builtin is a warning, semantic errors fail
track i s -T ready -p PROJ
--config/TRACKER_CONFIG, else ./.track.toml, else
~/.tracker-cli/.track.toml. Project config shadows the global config.^[a-z][a-z0-9_]*$), unique within the pack
(case-insensitive), with non-empty name/description/query. Only exact {PROJECT} is
substituted (--project, then pack default_project, then config default_project).validate warns shadows_builtin); pack
queries always win over cached built-ins. Packs are never written into the cache.-T search, workflow commands) instead
of silently falling back to built-ins; ordinary commands like issue get are unaffected.track context # Aggregated context for AI sessions
track context --project PROJ # Filter to specific project
track context --refresh # Force refresh from API
track context --include-issues # Include unresolved issues
track -o json context # JSON output for parsing
Single command to get all relevant data: projects, fields, users, query templates, workflow hints, issue counts, and recent issues.
| Full Command | Aliases |
|---|---|
track issue | track i |
track issue get | track i g |
track issue create | track i new, track i c |
track issue update | track i u |
track issue search | track i s, track i find |
track issue inspect | track i ix |
track issue delete | track i rm, track i del |
track issue comment | track i cmt |
track issue history | track i history, track i hist |
track issue complete | track i done, track i resolve |
track issue start | track i start |
track issue link | track i link |
track issue unlink | track i ul |
track project | track p |
track project list | track p ls |
track project fields | track p f |
track tags | track t |
track article | track a, track wiki |
track config | track cfg |
track context | track ctx |
track field list | track field ls |
track field create | track field c |
track i s "project: PROJ #Unresolved"
track i s "project: PROJ State: {In Progress}"
track i s "project: PROJ Assignee: me Priority: Major"
track -b jira i s "project = PROJ AND resolution IS EMPTY"
track -b jira i s "project = PROJ AND status = 'In Progress'"
track -b jira i s "assignee = currentUser() AND priority = Major"
track -b github i s "is:open label:bug"
track -b github i s "is:closed assignee:username"
track -b github i s "is:issue is:open"
GitHub uses GitHub's search query syntax (not traditional issue queries).
track -b gitlab i s "bug fix" --state opened
track -b gitlab i s "performance" --labels "priority::high"
GitLab uses project-scoped search with filter parameters.
track -b linear i s "project: ORE #Unresolved"
track -b linear i s "team: ORE state: {In Progress}"
track -b linear i s "project: ORE label: Bug assignee: me"
Linear exposes teams as track projects. The Project field on issues maps to Linear's native project association (--field "Project=Track CLI").
track PROJ-123 # Text (default)
track -o json PROJ-123 # JSON
track --format json p ls # JSON
track -o jsonl p ls # JSON Lines: one project per line
-o jsonl prints the same document as -o json, compacted for line-based tools: when the
document is an array (a list command such as p ls or i s), each element is one line, and an
empty list prints nothing; anything else (an object such as track PROJ-123 or a batch summary)
is a single line. Nested arrays stay inside their line. Every command that prints JSON accepts
it; completions rejects it. In both modes stdout holds only JSON; warnings, progress and
errors go to stderr.
/wiki path)--parent, or link existing issues with issue link -t subtaskissue get/issue search surface all populated fields Jira returns — standard system fields (fixVersions, reporter, environment, duedate, resolution, …) and every custom field — as custom_fields entries, not just a hardcoded subset. Single-issue reads (track <KEY>) fetch the full field set too. Anything that can't be mapped to a typed variant is preserved verbatim as Unknown { value }, so no data is lost. --field <name> write attempts flow straight to Jira; if a field isn't editable, Jira's error is surfaced.Components multi-value custom field. To filter by area, use server-side JQL such as component = "Rendering".42), not project-prefixed keys--parent, issue link -t subtask/parent)#number in comments)project_id configuration#42), not global IDs# prefix)--parent, issue link -t subtask/parent)-p ORE maps to a Linear team)Authorization: <API_KEY>)--field "Project=Track CLI" or linear.default_linear_projectparentId; relation links support related, blocks, duplicate, and similarcrates/
├── tracker-core/ # Core traits and models
├── youtrack-backend/ # YouTrack API client
├── jira-backend/ # Jira API client
├── github-backend/ # GitHub API client
├── gitlab-backend/ # GitLab API client
├── linear-backend/ # Linear GraphQL client
├── tracker-mock/ # Mock system for testing
├── agent-harness/ # AI agent evaluation harness
└── track/ # CLI binary
IssueTracker trait, common models, errors# Build
cargo build
# Test (unit + mock integration tests)
cargo test
# Test specific crate
cargo test --package youtrack-backend
cargo test --package jira-backend
cargo test --package github-backend
cargo test --package gitlab-backend
cargo test --package linear-backend
# Run live integration tests (requires .track.toml with valid credentials)
cargo test --package track --test youtrack_integration_tests -- --ignored
cargo test --package track --test jira_integration_tests -- --ignored
cargo test --package track --test github_integration_tests -- --ignored
cargo test --package track --test gitlab_integration_tests -- --ignored
cargo test --package track --test linear_integration_tests -- --ignored
# Run without installing
cargo run -- PROJ-123
crates/<backend>-backend/IssueTracker trait from tracker-coretracker-core typescrates/track/src/main.rs backend selectioncrates/track/src/config.rswiremock for HTTP mockingSee existing backend crates (jira-backend/, github-backend/, gitlab-backend/) for reference implementations.
See Agent Guide for:
MIT
track field new | track field setup |
track bundle list | track bundle ls |
track bundle create | track bundle c |