Skip to main content
Glama

issuehub

issuehub is a standalone, provider-agnostic issue-tracker CLI. It caches, indexes, syncs, searches, and exports issues from Jira, Redmine, GitHub, and GitLab into a plain-file workspace that any tool can read. Attachment metadata travels with each issue; bytes download only on explicit request (issuehub attachments --fetch/--all), and always land under .state/, never the workspace — see docs/FORMATS.md §Attachments.

The workspace also carries a per-issue memo, metadata, and (produced by an AI backend on the other side of this CLI, never by this CLI itself) translations/<lang>.md files — this CLI reads and full-text-indexes those, and validates a language tag before it ever becomes a filename, but does not generate them (see docs/FORMATS.md §Translations).

If you keep your workspace in a shared or public repository: translated issue titles/descriptions, and analysis responses, are Git-tracked by design (so a translation can be hand-corrected and an analysis kept for reference) — so issue content you translate or analyze ends up in that repository's history, not only in the local, git-ignored cache. Optionally including comments in a translation also carries commenter names into the tracked file. None of this is a bug; it just means "private tracker" and "public repository" are two different choices, and it is worth picking the one you mean. See docs/FORMATS.md §What lands in Git, and what leaves the machine for the full picture.

Design stance

  • One invocation per command. No daemon, no persistent process. issuehub reads its inputs, does the work, prints a result, and exits.

  • Zero required external binaries. HTTP is in-process (httpx) and the index uses the stdlib sqlite3 module, not a sqlite3 CLI. git is purely informational (the workspace is designed to be git-managed, not required to be) and rg is optional — without it, search falls back to a pure-Python scan, so its absence is a warning, never an error.

  • Machine-readable by default when asked. Every verb has a --json mode producing stable, documented output, so issuehub composes into scripts, CI, and other tools without scraping human-oriented text.

  • The on-disk workspace is a published interface, not an implementation detail — other tools may read and write the same files, so its format is a compatibility contract (see docs/FORMATS.md).

  • Credentials never reach argv, logs, or disk.

Related MCP server: Jira Cloud MCP Server

Install

pip install issuehub-cli

The PyPI distribution is named issuehub-cli, but the import package and the console script are both still issuehub — that split is intentional and common (the package you pip install need not match the name you import or run), so after installing you still import issuehub and run issuehub <verb>.

or, from a checkout:

pip install -e .

Requires Python 3.10+. See pyproject.toml for the optional analysis extra (pandas-backed export aggregates), the optional mcp extra (fastmcp-backed MCP server, issuehub mcp serve — see docs/MCP.md), and the dev extra (test tooling).

Verification status

This CLI has been run against a live GitHub instance, which surfaced four real bugs (now fixed — see docs/CORRECTNESS.md). The Jira, Redmine, and GitLab providers, by contrast, have only been exercised against recorded payloads in the shared conformance corpus (corpus/) — they have not been run against a live Jira, Redmine, or GitLab instance. If you're picking this tool for one of those three providers, treat it as conformance-tested but not yet field-tested, and please report anything that doesn't match a live server's behavior.

Usage

Point issuehub at a workspace directory (--workspace <path> or $ISSUEHUB_WORKSPACE) and, if you have provider credentials, a config file (--config <path>, $ISSUEHUB_CONFIG, or <workspace>/.issuehub/config.yaml — see docs/CONTRACT.md §Config for the full shape):

# ~/notes/issuehub/.issuehub/config.yaml
workspace: ~/notes/issuehub

providers:
  jira:
    type: jira
    url: https://your-org.atlassian.net
    user: you@example.com
    token_env: JIRA_TOKEN
export ISSUEHUB_WORKSPACE=~/notes/issuehub

issuehub health --json                 # readiness, no network I/O
issuehub reindex --json                # rebuild the search index from the cache
issuehub list --provider jira --json   # query the provider (one page by default)
issuehub get jira://PROJ-123 --json    # one complete issue, cached unless --refresh
issuehub sync --json                   # re-fetch known issues, report what changed
issuehub fetch --provider jira --json  # page a whole query into the cache, resumably
issuehub search "login bug" --json     # local full-text search (cache + notes)
issuehub search 認証 --json             # non-ASCII queries route around FTS5's tokeniser gap
issuehub changed --json                # issues that moved since you last opened them
issuehub collection add sprint1 jira://PROJ-1 jira://PROJ-2
issuehub collection show sprint1 --json
issuehub export --source all --format csv -o issues.csv
issuehub import issues.csv --dry-run --json  # merge edits back after spreadsheet triage
issuehub summarize --source all --by status --json
issuehub attachments jira://PROJ-123 --json        # list attachment metadata (no network)
issuehub attachments jira://PROJ-123 --fetch 10001  # download one attachment's bytes
issuehub attachments jira://PROJ-123 --all --json  # download every not-yet-downloaded attachment

Run issuehub --help (or see docs/CONTRACT.md) for the full verb list, arguments, and exit-code conventions.

MCP server

issuehub mcp serve runs an MCP (Model Context Protocol) server over stdio — the same verbs above, reached as tools/resources by an agent or any MCP-aware host instead of shelling out to argv. Needs the optional mcp extra:

pip install "issuehub-cli[mcp]"
issuehub mcp serve --workspace ~/notes/issuehub

Full design (stateless-by-construction, import's consent guardrails, why fetch's progress becomes MCP notifications instead of stdout JSONL) is in docs/MCP.md.

Corporate networks (proxy / TLS / client certs)

The full field list lives in docs/CONTRACT.md §Config; these are the three situations people actually hit on their first run.

Behind an authenticating proxy:

http:
  proxy: http://proxy.corp.example:8080
  proxy_user: "DOMAIN\\you"
  proxy_password_env: PROXY_PASSWORD   # or proxy_password_cmd / proxy_password
  proxy_auth: basic                    # the only scheme this CLI supports — see below
  no_proxy: "localhost,.internal"      # or "*" to bypass the proxy entirely for one provider

proxy_auth only accepts "basic" — this CLI talks HTTP in-process (httpx) rather than shelling out to curl, so it never inherited curl's NTLM/negotiate/digest support. Any other value is a loud validation error at config load, never a silent fallthrough to a scheme it can't actually perform. no_proxy also honours $NO_PROXY from the environment, and can be set per-provider (providers.<name>.http.no_proxy) to override the global value for just that one.

Behind an internal CA:

http:
  cacert: ~/certs/root.pem   # one CA bundle file
  # or, if your CA is distributed as a hashed directory (e.g. /etc/ssl/certs):
  capath: /etc/ssl/certs

Use cacert when you have a single root/intermediate bundle file; use capath when your CA is distributed as a hashed certificate directory instead — the shape corporate CA distribution often takes. ssl_verify: false also exists as an escape hatch, but it is deliberately noisy (it prints a stderr warning on every use) and points you back at cacert/ capath as the real fix — reach for it only to unblock yourself temporarily, not as the answer.

Needing a client certificate:

http:
  client_cert: ~/certs/client.pem
  client_key: ~/certs/client.key
  client_key_password_env: CLIENT_KEY_PASSWORD  # or client_key_password_cmd / client_key_password

For any of these, a literal value, a *_cmd (an argv list, stdout trimmed), and a *_env (an environment variable name) are all accepted for the password/secret fields, resolved in that order — literal wins if present.

Check it actually took effect: issuehub health --json reports a network section (proxy/ssl_verify/cacert in effect) and, per provider, whether its credential resolves — never the value itself. That turns "did my proxy config work?" into one command instead of a failed request.

Documentation

The full spec of record lives in docs/:

Development

The shared conformance corpus under corpus/ (golden fixtures and recorded provider payloads) is committed, so pytest runs standalone without any external tooling. See tools/README.md if you need to regenerate the harvested fixtures from the reference implementation — that path is dev-only and not required to run the test suite.

Maintenance

ActivityStale
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    F
    maintenance
    A Model Context Protocol (MCP) server that integrates with the SpaceBridge REST API to automate issue management across connected issue trackers, allowing developers to manage issues directly from their AI-assisted coding environment.
    6
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    MCP server for interacting with Jira Cloud instances. Enables issue management, JQL queries, project and sprint management, and batch operations via natural language interfaces.
    206 npm
    4
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    A clean, reliable Model Context Protocol server for Jira integration, enabling issue management, search, and more via natural language.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    A Model Context Protocol (MCP) server that integrates with Atlassian Jira to search issues, retrieve details, access comments, create new issues, and update issues.
    528 npm
    MIT