Ticgit is a Git-native issue tracker. Tickets live in the repository as structured git-meta metadata.
The ti cli can create, read, update and sync ticket data.
Also ships with ti tui for a cool TUI version.
Everything has --json output for scripting and --markdown output for agentic use. You can also train your agent to use it by asking it to run ti agent.
You can also do specs and writeups and lots of fun stuff.
Download a pre-built binary:
curl -fsSL https://ticgit.dev/install | shOr install from source via Cargo:
cargo install ticgitThe binary is named ti.
git init
git config user.email you@example.com
git config user.name "Your Name"
ti init
ti new --title "fix the parser" --tags bug,parser --comment "fails on empty input"
ti list
ti show <ticket-id-or-prefix>Most commands accept a full UUID or any unique UUID prefix.
Create tickets:
ti new --title "add docs"
ti new --title "fix crash" --tags bug,cli --assigned you@example.com
ti new --title "investigate flaky test" --comment "seen on CI twice"List and filter:
ti list
ti list --status open
ti list --state blocked
ti list --tag bug
ti list --assigned you@example.com
ti list --order title.desc
ti list --json
ti list --markdownShow details:
ti show <id>
ti show <id> --json
ti show <id> --markdownCommands that support --json also support --markdown, which renders the same
ticket data as Markdown and includes suggested next commands for agent workflows.
TicGit publishes a stable JSON schema for agent and automation workflows at
docs/schema/v1.json. On the website, the same schema is
available at https://ticgit.dev/schema/v1.json.
--json is the stable machine interface:
- successful JSON commands write parseable JSON to stdout only
- diagnostic and error text goes to stderr
- JSON output does not include ANSI color escapes
- non-zero exit status means the command failed
- ticket ids may be full UUIDs or unique UUID prefixes
- ambiguous or missing prefixes fail with a non-zero exit status and stderr diagnostic
ti show <id> --json and JSON mutation commands emit a ticket object.
ti list --json emits an array of ticket objects. Ticket metadata appears under
.meta as an object whose values are strings.
--porcelain and --format json are not supported compatibility aliases today;
use --json for schema-stable output.
Agents can run ti help --agent for a Markdown guide, or read the website's
Markdown version at docs/index.md.
Select a current ticket:
ti checkout <id>
ti show
ti comment "follow-up note"
ti checkout --clearMutate tickets:
ti state blocked --ticket <id>
ti state closed --ticket <id>
ti state closed:wontfix --ticket <id>
ti status review --ticket <id>
ti assign you@example.com --ticket <id>
ti assign --clear --ticket <id>
ti points 3 --ticket <id>
ti milestone v1.0 --ticket <id>
ti tag --ticket <id> bug ui
ti tag --ticket <id> --remove ui
ti edit <id>
ti comment --ticket <id> "fixed in the latest patch"Lifecycle values are split into a broad status and a specific state.
Open tickets use new, assigned, in-progress, blocked, or review.
Closed tickets use resolved, wontfix, duplicate, or invalid.
New tickets start as open:new; ti state closed defaults to
closed:resolved.
Recent tickets:
ti recent
ti recent --limit 20Import open GitHub issues:
ti import gh
ti import gh --repo owner/repoSaved views are named snapshots of ticket UUIDs:
ti save-view bugs --tag bug
ti views
ti views bugs
ti list --view bugsTicGit delegates storage and transfer to git-meta-lib.
ti pull
ti push
ti syncti sync performs a pull followed by a push. If you pass --remote <name>, the
named git-meta remote is used; otherwise git-meta resolves the default metadata
remote from Git config.
All TicGit data is written on the git-meta project target under the
ticgit: namespace:
ticgit:schema-version string
ticgit:owners set
ticgit:views:<name> set of ticket UUIDs
ticgit:tickets:<uuid>:title string
ticgit:tickets:<uuid>:description string (optional)
ticgit:tickets:<uuid>:status string
ticgit:tickets:<uuid>:state string
ticgit:tickets:<uuid>:assigned string
ticgit:tickets:<uuid>:points string
ticgit:tickets:<uuid>:milestone string
ticgit:tickets:<uuid>:tags set
ticgit:tickets:<uuid>:comments list
ticgit:tickets:<uuid>:created-at string
ticgit:tickets:<uuid>:created-by string
Ticket existence is implied by the presence of fields under
ticgit:tickets:<uuid>:*; there is no separate ticket index.
The local query database is git-meta's .git/git-meta.sqlite. Exchange with
other clones happens through refs/meta/* using normal Git transfer.
The workspace has two crates:
ticgit-lib: domain model and git-meta-backedTicketStore.ticgit: theticommand-line application.
Example:
use ticgit_lib::{NewTicketOpts, TicketStore};
let store = TicketStore::discover()?;
let ticket = store.create("fix parser", NewTicketOpts::default())?;
println!("{}", ticket.id);
Ok::<(), ticgit_lib::Error>(())Run the full test suite:
cargo testRun just the library tests:
cargo test -p ticgit-libRun the CLI integration tests:
cargo test -p ticgit --test cliBuild the CLI:
cargo build -p ticgitPackage the crates before publishing:
cargo package -p ticgit-lib
cargo publish -p ticgit-lib
# After ticgit-lib 0.1.0 is available in the crates.io index:
cargo package -p ticgit
cargo publish -p ticgitThe CLI crate depends on ticgit-lib by both local path and published
version, so publish ticgit-lib first.