Agents should behave. Let them follow the issue flow.
issue-flow scaffolds a lightweight issue-tracking workflow into your project so that Cursor AI agents can pick up GitHub issues, plan work, and land PRs in a consistent way.
Running issue-flow init in your project root creates:
your-project/
.issueflows/
00-tools/ # Helper scripts for agents
01-current-issues/ # Active issue markdown files
02-partly-solved-issues/ # Parked / in-progress issues
03-solved-issues/ # Completed issues archive
.cursor/
commands/
iflow.md # /iflow — smart dispatcher (quick start)
issue-init.md # /issue-init — fetch a GitHub issue locally
issue-plan.md # /issue-plan — write issue<N>_plan.md and confirm
issue-start.md # /issue-start — implement the plan
issue-pause.md # /issue-pause — park work in 02-partly-solved-issues/
issue-close.md # /issue-close — test, commit, push, PR
issue-cleanup.md # /issue-cleanup — post-merge branch hygiene
issue-yolo.md # /issue-yolo — all-in-one for small, low-risk issues
build.md # /build — rebuild the graphify knowledge graph (optional)
skills/ # Optional Agent Skills (explicit / @ invoke)
issueflow-iflow/SKILL.md
issueflow-issue-init/SKILL.md
issueflow-issue-plan/SKILL.md
issueflow-issue-start/SKILL.md
issueflow-issue-pause/SKILL.md
issueflow-issue-close/SKILL.md
issueflow-issue-cleanup/SKILL.md
issueflow-issue-yolo/SKILL.md
issueflow-version-bump/SKILL.md
issueflow-history-update/SKILL.md
issueflow-build/SKILL.md
rules/
issueflow-rules.mdc # Always-on Cursor rule for the workflow
docs/
cursor-issue-workflow.md # Human-readable overview of the workflow
The Cursor slash commands give agents a repeatable flow. The linear path is:
/issue-init 42— pulls GitHub issue #42 into.issueflows/01-current-issues/and archives older issues./issue-plan— draftsissue<N>_plan.md(Goal / Constraints / Approach / Files to touch / Test strategy / Open questions) and stops for your confirmation./issue-start— reads the confirmed plan and implements it. If no plan file exists, it offers to run/issue-planfirst, proceed without a plan, or abort./issue-close— runs tests, optionally bumps version withuv version --bump, appends aHISTORY.mdentry (or promotes[Unreleased]to a new release section on a bump), updates status files, commits, pushes, and opens a PR./issue-cleanup— after the PR merges, switches to the default branch, fast-forwards, prunes, and deletes the merged local branch.
Plus a few off-path commands:
/iflow— quick start: inspects the current issue's state and dispatches to the right linear step automatically. A branch-derived number (42-fix-login→N=42) is authoritative, so/iflowworks from a fresh branch too./issue-pause— park the current issue in02-partly-solved-issues/with a Remaining work note; optional WIP commit + switch back to the default branch./issue-yolo— all-in-one chain (init → plan → start → close) for small, low-risk issues, with up-front safeguards (refuses on the default branch, refuses with dirty unrelated changes, requires passing tests, single consolidated confirm).
The matching Agent Skills (under .cursor/skills/) carry the same workflows for on-demand use with /issueflow-iflow, /issueflow-issue-init, /issueflow-issue-plan, /issueflow-issue-start, /issueflow-issue-pause, /issueflow-issue-close, /issueflow-issue-cleanup, /issueflow-issue-yolo, @issueflow-version-bump when you need only the bump steps, or @issueflow-history-update when you need only the changelog update (see Cursor Agent Skills).
issue-flow itself is a small Python CLI, but the scaffolded slash commands
it writes into your project shell out to a few external tools. If they are
missing, the slash commands will fail at runtime — so issue-flow init now
checks for them up front and prints install hints before it does anything.
Required:
- Git — used by every slash command for branch, fetch, status, commit, and push operations. Almost certainly already installed if you're here, but the check covers it for completeness.
- GitHub CLI (
gh) — used by/issue-initto fetch issues, by/issue-closeto open PRs, and by/issue-cleanupto check PR merge status. After installing, rungh auth loginonce to authenticate.
Recommended:
- uv — how issue-flow itself is meant to be installed, and how this repo manages its own Python environment.
Quick install pointers for gh:
| Platform | Command |
|---|---|
| macOS (Homebrew) | brew install gh |
| Windows (winget) | winget install --id GitHub.cli -e |
| Linux (Debian/Ubuntu) | sudo apt install gh (or see cli.github.com for the official repo) |
If a dependency is missing, issue-flow init prints the installation hints
and asks whether to continue anyway. You can bypass the prompt in automation
with issue-flow init --skip-dep-check (the same flag is available on
issue-flow update), and the prompt is also auto-skipped when stdin is not
a TTY (e.g. CI pipelines).
issue-flow has a lightweight integration with graphify
(PyPI: graphifyy, CLI: graphify) — a tool that turns the project into a
queryable knowledge graph that AI assistants can read instead of grepping
through files. The integration is opt-in by installing graphifyy as its
own tool (the same way you installed issue-flow): there is no flag, no
.env switch, no extras to remember. Detection is purely PATH-based.
What issue-flow does when graphify is on PATH:
issue-flow initandissue-flow updaterungraphify cursor installso the graphify Cursor skill is registered alongside the issue-flow scaffold. If graphify is not installed, both commands just print install hints and continue — they never block.- A new slash command
/build(and matching/issueflow-buildskill) wrapsissue-flow build. With no extra args it runsgraphify update <project>— AST-only, no LLM API key required, so the no-arg case "just works". For richer semantic relationships addextract(issue-flow build extract) and configure a backend (GEMINI_API_KEY,ANTHROPIC_API_KEY,OPENAI_API_KEY,MOONSHOT_API_KEY, or--backend ollamafor a local LLM). Cursor's own LLM is not available to subprocesses, so graphify needs its own backend. Other subcommands (watch,cluster-only, …) pass through too; trailing flags forward verbatim. - The scaffolded rules and
/issue-startmentiongraphify-out/GRAPH_REPORT.mdas a recommended pre-read when the file exists./buildis off-path —/iflownever auto-dispatches to it.
To enable, install graphify as its own standalone tool:
uv tool install graphifyy # recommended
# or
pipx install graphifyy
# or
pip install graphifyyWhy not an
issue-flow[graphify]extra (oruv tool install issue-flow --with graphifyy)?uv tool installonly puts the host package's entry-point scripts on PATH. An extra (or--with graphifyy) pulls graphifyy into issue-flow's venv but leaves thegraphifyCLI invisible to the shell, so/buildandgraphify cursor installwould still fail. Installing graphify as its own tool puts a realgraphifyshim on PATH and matches how we treatgit/gh.
Just installed graphifyy and
issue-flow initsays it's still missing? uv prints~/.local/bin is not on your PATHafter the firstuv tool install. Runuv tool update-shell(refreshes shell rc files), then restart your shell and Cursor so the new PATH takes effect. issue-flow's missing-CLI hint also detects this case and tells you the exact directory to add.
After installing, run issue-flow update once so the graphify Cursor skill
gets registered.
Requires Python 3.13+ and uv.
uv tool install issue-flowOr add it as a dev dependency to your project:
uv add --dev issue-flowcd your-project
issue-flow initThat's it. Open the project in Cursor and start with /iflow (or step through /issue-init, /issue-plan, /issue-start, /issue-close, /issue-cleanup explicitly).
issue-flow init [PROJECT_DIR] [--force] [--skip-dep-check]
issue-flow update [PROJECT_DIR] [--skip-dep-check]
issue-flow build [-C PROJECT_DIR] [...graphify subcommand + args]
| Argument / Option | Description |
|---|---|
PROJECT_DIR |
Project root directory. Defaults to . (current directory). |
--force, -f |
Overwrite generated Cursor commands, rules, and workflow doc instead of skipping them. |
--skip-dep-check |
Skip the external-CLI dependency check (git, gh) and the confirmation prompt that follows if anything is missing. Useful in automation. |
Running init again without --force is safe: generated scaffold files that already exist are skipped, and issue markdown under .issueflows/ is never touched by init or update. When the CLI detects an existing scaffold, it reminds you about update and --force.
| Argument / Option | Description |
|---|---|
PROJECT_DIR |
Project root directory. Defaults to . (current directory). |
--skip-dep-check |
Skip the external-CLI dependency check (git, gh) and the confirmation prompt that follows if anything is missing. |
Use update after upgrading the issue-flow package to refresh the packaged slash commands, Cursor rule, and docs/cursor-issue-workflow.md from the version you have installed. This overwrites those generated files (unlike a plain second init). It still does not modify arbitrary files under .issueflows/ (for example your issue*_original.md / issue*_status.md files), and it creates any new .issueflows/ subdirectories required by the current package.
| Argument / Option | Description |
|---|---|
-C, --project-dir |
Project root directory to scan with graphify. Defaults to . (current directory). Modeled on git -C so positional args can flow into graphify untouched. |
...graphify subcommand + args |
Optional graphify subcommand + flags. With no extras runs graphify update <PROJECT_DIR> — AST-only, no LLM API key required. The first extra arg, if it is a recognized build subcommand (update, extract, watch, cluster-only, check-update), picks the action; trailing tokens forward verbatim. Examples: issue-flow build extract (semantic LLM pass; needs GEMINI_API_KEY / ANTHROPIC_API_KEY / OPENAI_API_KEY / MOONSHOT_API_KEY or --backend ollama), issue-flow build cluster-only --no-viz, issue-flow build ./subdir. |
build requires graphifyy to be installed (uv tool install graphifyy). When the graphify CLI is missing, the command prints install hints and exits with code 2. Outputs land in graphify-out/ (graph.html, GRAPH_REPORT.md, graph.json).
| Goal | Command |
|---|---|
| First-time setup, or add missing files only | issue-flow init |
Pull newer templates after uv tool upgrade issue-flow (or similar) |
issue-flow update |
| Replace generated scaffolds without upgrading logic | issue-flow init --force |
| Rebuild the graphify knowledge graph | issue-flow build |
issue-flow reads a .env file from the project root (via python-dotenv). The following environment variables are supported:
| Variable | Default | Description |
|---|---|---|
ISSUEFLOW_DIR |
.issueflows |
Name of the issue-tracking directory. |
ISSUEFLOW_AGENT_DIR |
.cursor |
Name of the agent/IDE config directory (currently .cursor). |
ISSUEFLOW_DOCS_DIR |
docs |
Where to write the workflow documentation file. |
ISSUEFLOW_HISTORY_FILE |
HISTORY.md |
Changelog file that /issue-close updates (set to e.g. CHANGELOG.md for different conventions). |
git clone https://github.com/jepegit/issue-flow.git
cd issue-flow
uv sync
# Run tests
uv run pytest
# Lint
uv run ruff check src/ tests/See HISTORY.md for release notes.
- Multi-tool support — generate config for other AI coding tools (Claude Code, Windsurf, etc.) in addition to Cursor.
issue-flow status— show a dashboard of current, partly-solved, and solved issues.- Custom templates — let users supply their own Jinja2 templates to tailor slash commands and rules to their team's conventions.
- Git hook integration — optionally move issue files on commit based on status markers.
- GitHub Actions workflow — ship a reusable action that syncs issue state between
.issueflows/and GitHub issue labels/milestones.
This project is released under the MIT License. See the full text in the repository: LICENSE.