issue-kit
Opinionated backlog-standards toolkit: a single spec file (issue-standard.yml)
declares your issue standard — label taxonomy with colors, the required
.github/ISSUE_TEMPLATE set, lint rules — and issue-kit checks any number of
repositories against it. MCP server and CLI over one engine.
Phase M0 is strictly read-only: it lints and reports, it never mutates a
repository. The only write is standard_init, which puts the default spec on
your local disk.
Design docs live in ARCHITECTURE.md, ROADMAP.md, and adr/.
Install
pip install issue-kit-mcp
# or from a checkout:
pip install -e '.[dev]'
Requires Python 3.10+.
CLI
# Write the default spec (standard 2026-07-14) to ./issue-standard.yml
issue-kit init [--path PATH] [--force]
# Lint one or more repos against the spec
issue-kit lint OWNER/REPO [OWNER/REPO ...] [--repo OWNER/REPO] [--repos-file FILE]
[--spec PATH] [--provider github|snapshot] [--snapshots DIR]
[--format json|text|markdown] [--ci]
# Aggregate conformance dashboard
issue-kit report OWNER/REPO ... [--repos-file FILE] [--spec PATH]
[--provider github|snapshot] [--snapshots DIR]
[--format json|text|markdown]
# Capture a repo's issues/labels/templates into a snapshot bundle (GET-only)
issue-kit snapshot OWNER/REPO --out DIR [--format json|text|markdown]
standard-init / standard-lint / standard-report / standard-snapshot
are accepted aliases — the same naming the MCP tools use (snapshot is
CLI-only in M0; it has no MCP double yet).
Exit codes
Shared CI contract (never masked):
| code | meaning |
|---|---|
| 0 | conformant, or advisory-only findings |
| 1 | error-severity findings present |
| 2 | config error: invalid spec, provider/auth failure, invalid arguments |
stdout carries the report in the chosen format (parseable even at exit 1);
stderr carries diagnostics. Default format is text on a TTY, json otherwise.
Spec resolution
--spec PATH > ISSUE_KIT_SPEC env > ./issue-standard.yml > built-in
default spec. An explicit path that does not exist is a config error (exit 2).
GitHub token
The GitHub provider is read-only (issues, labels, contents) and takes its
token from the same env chain MCP clients use:
GITHUB_PERSONAL_ACCESS_TOKEN > GITHUB_TOKEN > GH_TOKEN. A fine-grained
PAT with Issues:read, Contents:read, Metadata:read is enough. Without a token
the provider runs anonymously (60 req/h, public repos only); an auth failure
on a private repo is a config error, never a silent pass.
Snapshots (offline runs)
--provider snapshot --snapshots DIR reads repo state from bundle JSONs
instead of the network. Bundle format (fixed contract):
{
"repo": "owner/name",
"fetched_at": "2026-07-14T12:00:00Z",
"issues": [
{"number": 1, "title": "...", "state": "open",
"labels": [{"name": "bug", "color": "d73a4a", "description": ""}],
"body": "..."}
],
"labels": [{"name": "bug", "color": "d73a4a", "description": ""}],
"templates": {"bug.md": "---\nname: ...\n---\n..."}
}
labels may be null — the label inventory was unavailable at capture time;
label lint then covers only labels that appear on issues. templates may be
null, which is treated as "no templates". Keep local snapshot captures in
.snapshots/ (gitignored).
Produce a bundle with the toolkit itself instead of hand-assembling one:
issue-kit snapshot OWNER/REPO --out .snapshots
issue-kit lint OWNER/REPO --provider snapshot --snapshots .snapshots
snapshot is strictly read-only (GET issues, labels, contents), writes one
<owner>__<repo>.json under --out, and serializes deterministically (sorted
keys, ensure_ascii=False, indent 2) so re-captures diff cleanly. The label
inventory is captured in full (not null), so an offline --provider snapshot
run reproduces the live findings at capture time.
MCP server
{
"mcpServers": {
"issue-kit": {
"command": "python",
"args": ["-m", "issue_kit"]
}
}
}
Tools (names are a public contract): standard_init, standard_lint,
standard_report. Each returns the same JSON object the CLI prints with
--format json.
Lint rules (M0)
| rule | severity | meaning |
|---|---|---|
missing_type |
error | OPEN issue without a type label |
multiple_type |
error | more than one type label |
missing_priority |
error | no P1/P2/P3 label |
multiple_priority |
error | more than one priority label |
nonstandard_label |
advisory | repo label outside the spec (may be a legitimate domain label) |
missing_template |
error | no template whose labels contains the type — matched by content, not filename: .md front matter or a GitHub Issue Forms *.yml/*.yaml top-level labels (config.yml excluded) |
missing_template_config |
advisory | no config.yml in .github/ISSUE_TEMPLATE/ |
missing_body_section |
advisory | soft body-structure check (problem, todo) |
Title prefixes like [P1] are intentionally not mapped to priority
labels in M0 — recognizing them as relabel hints is M2 material
(issues_relabel). Issues by dependabot and pull requests are excluded
from checks and from the conformance denominator.
Reports contain issue numbers, titles, labels, and rule details — never issue bodies.
Development
pip install -e '.[dev]'
ruff check src tests
pytest -q
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file issue_kit_mcp-0.1.0.tar.gz.
File metadata
- Download URL: issue_kit_mcp-0.1.0.tar.gz
- Upload date:
- Size: 43.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d5c9b8d3ac241ddfe0006385b1882f9237332e5e4e500edef7e8852e26979f7
|
|
| MD5 |
d8052769fd188992f081d9c3c8372444
|
|
| BLAKE2b-256 |
9c5d75a2061885d94670a10735821f3a1beb337d099157d9373223334c4fd14c
|
Provenance
The following attestation bundles were made for issue_kit_mcp-0.1.0.tar.gz:
Publisher:
release.yml on ignatenkofi/issue-kit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
issue_kit_mcp-0.1.0.tar.gz -
Subject digest:
4d5c9b8d3ac241ddfe0006385b1882f9237332e5e4e500edef7e8852e26979f7 - Sigstore transparency entry: 2299296817
- Sigstore integration time:
-
Permalink:
ignatenkofi/issue-kit@2a3eaf948be54c455cbaec338b9581aec55bb52d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/ignatenkofi
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2a3eaf948be54c455cbaec338b9581aec55bb52d -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file issue_kit_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: issue_kit_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 37.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
db198c02bfbd7a3bbf453e72481cc7dbcf648fdb878cebf011bb576ee6c0501d
|
|
| MD5 |
70c38ddca3e592ccdb5b47b653fa468e
|
|
| BLAKE2b-256 |
aa032703af197639e542845c6483f47e70561841b82a34cd3679ae62c52a3300
|
Provenance
The following attestation bundles were made for issue_kit_mcp-0.1.0-py3-none-any.whl:
Publisher:
release.yml on ignatenkofi/issue-kit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
issue_kit_mcp-0.1.0-py3-none-any.whl -
Subject digest:
db198c02bfbd7a3bbf453e72481cc7dbcf648fdb878cebf011bb576ee6c0501d - Sigstore transparency entry: 2299296826
- Sigstore integration time:
-
Permalink:
ignatenkofi/issue-kit@2a3eaf948be54c455cbaec338b9581aec55bb52d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/ignatenkofi
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2a3eaf948be54c455cbaec338b9581aec55bb52d -
Trigger Event:
workflow_dispatch
-
Statement type: