Ticketr keeps your Jira backlog in Git. Author issues in Markdown, review changes like code, and synchronize with Jira whenever you're ready.
Ticketr understands only the
# TICKET:schema. If you still have# STORY:headings, rename them before running the CLI.
- Tickets as code β store Jira issues alongside source, protected by version control, reviews, and history.
- Bidirectional sync β push Markdown to Jira, pull Jira updates back to Markdown, resolve conflicts explicitly.
- Safe automation β deterministic runs, machine-friendly exit codes, and redacted logs for CI/CD.
- Human-readable state β
.ticketr.statetracks hashes so only changed tickets are touched. - Zero lock-in β plain Markdown files and YAML config keep your backlog portable.
# From source
git clone https://github.com/karolswdev/ticketr.git
cd ticketr
go build -o ticketr ./cmd/ticketr
# or
# go install github.com/karolswdev/ticketr/cmd/ticketr@latestTicketr uses the Atlassian Cloud REST API.
export JIRA_URL="https://yourcompany.atlassian.net"
export JIRA_EMAIL="[email protected]"
export JIRA_API_KEY="<api-token>" # Create at https://id.atlassian.com/manage-profile/security/api-tokens
export JIRA_PROJECT_KEY="PROJ"Tip: keep these in an
.envfile andsource .envlocally. In CI, store them as secrets.
# TICKET: New Authentication Flow
## Description
Ship the new login, registration, and session handling experience.
## Acceptance Criteria
- Users can sign up with email + password
- Passwords stored with bcrypt
- Sessions expire after 24 hours of inactivity
## Tasks
- Implement login and registration endpoints
- Add password reset flow
- Instrument audit loggingSave this as tickets/auth.md (or any filename you prefer).
ticketr push tickets/auth.mdTicketr validates your Markdown, creates missing issues, updates existing ones, and injects Jira keys back into the file.
ticketr pull --project PROJ --output tickets/pulled.mdPull merges Jira changes into a Markdown file, highlights conflicts, and respects .ticketr.state so only edited tickets are touched.
# Author or edit Markdown in git branches
vim tickets/sprint-24.md
# Preview issues without touching Jira
ticketr push tickets/sprint-24.md --force-partial-upload
# Synchronize (create/update) in Jira
ticketr push tickets/sprint-24.md
# Bring Jira edits back to Markdown
ticketr pull --project PROJ --jql "Sprint = 'Sprint 24'" --output tickets/sprint-24.md
# Resolve conflicts if both sides changed
vim tickets/sprint-24.mdAutomate the same flow from CI:
# .github/workflows/jira-sync.yml
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: go build -o ticketr ./cmd/ticketr
- run: ./ticketr push backlog.md --force-partial-upload
env:
JIRA_URL: ${{ secrets.JIRA_URL }}
JIRA_EMAIL: ${{ secrets.JIRA_EMAIL }}
JIRA_API_KEY: ${{ secrets.JIRA_API_KEY }}
JIRA_PROJECT_KEY: PROJEvery ticket starts with # TICKET: followed by sections (Description, Acceptance Criteria, Tasks, custom ## Fields, etc.). Tasks are Markdown list items that can hold their own detail blocks.
Tasks inherit any custom fields defined on their parent ticket, unless you override them explicitly.
# TICKET: [PROJ-100] Payment Gateway
## Fields
- Priority: High
- Sprint: Sprint 24
- Component: API
## Tasks
- ### Build adapter
#### Fields
- Priority: Critical # Overrides parent priority
- ### Document retry policy
#### Fields
- Component: Docs # Overrides parent componentTicketr will treat the second task as Priority=High, Sprint=Sprint 24, Component=Docs because only Component is overridden. See docs/WORKFLOW.md for a complete breakdown.
Ticketr keeps .ticketr.state (ignored by git) with hashes of the last successful push/pull. If you delete the file, the next run treats everything as changed.
ticketr pull compares the state file, your Markdown, and Jira. When all three diverge, the pull fails with a conflict. Fix the Markdown manually or accept remote changes with --force.
Each run writes a timestamped log in .ticketr/logs/ with credentials redacted. The last 10 logs are retained automatically.
# Push one or more files
ticketr push backlog.md
# Merge Jira changes back into Markdown
ticketr pull --project PROJ --output backlog.md
# Force remote version when resolving conflicts
ticketr pull --project PROJ --force
# Continue despite validation errors (records partial successes)
ticketr push backlog.md --force-partial-upload
# Discover Jira fields and generate .ticketr.yaml
ticketr schema > .ticketr.yamlRun ticketr --help or ticketr <command> --help for full flag descriptions.
- examples/ β ready-to-use Markdown templates for epics, bugs, sprints, inheritance patterns
- docs/WORKFLOW.md β end-to-end walkthroughs
- docs/ARCHITECTURE.md β ports & adapters design
- docs/state-management.md β hash algorithm and conflict model
- docs/TROUBLESHOOTING.md β common failures and fixes
- docs/release-process.md β release playbook
| Symptom | Quick check |
|---|---|
401 Unauthorized |
Ensure JIRA_URL includes https:// and the API token is fresh |
| Missing custom fields | Run ticketr schema > .ticketr.yaml and commit the config |
| Nothing pushes | Inspect .ticketr.state; delete it to force a full sync |
| Pull conflicts every time | Someone or automation is editing the Markdown + Jira simultaneously β reconcile, then push |
More detail lives in docs/TROUBLESHOOTING.md.
go test ./...
bash scripts/quality.sh
bash tests/smoke/smoke_test.shCI runs the same checks on every pull request. See docs/ci.md for workflow internals.
- π Docs & wiki: https://github.com/karolswdev/ticketr/wiki
- π Issues: https://github.com/karolswdev/ticketr/issues
- π¬ Discussions: https://github.com/karolswdev/ticketr/discussions
- π Security: SECURITY.md
- π€ Contributions: CONTRIBUTING.md
MIT β see LICENSE.
Built with β€οΈ in Go, backed by the Jira Cloud REST API, and ready for teams who treat planning like code.