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: SpaceBridge-MCP

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.

A
license - permissive license
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/tya5/issuehub.cli'

If you have feedback or need assistance with the MCP directory API, please join our Discord server