Turn a GitHub issue into a dedicated branch, git worktree, and coding-agent session.
start-issue turns issue context into a repeatable workflow:
- issue -> branch
- branch -> worktree
- worktree -> agent session
It fetches issue metadata with gh, creates a git worktree with a branch name based on the issue, optionally runs init.sh, optionally renames the current zellij tab, and starts a configurable coding agent session.
Install from source with Go:
go install github.com/dapi/start-issue/v2/cmd/start-issue@latestPublished releases contain platform-specific Go binaries and a checksums.txt
manifest. Download the asset matching your OS and architecture from the release
page and verify it against that manifest before adding it to PATH.
After bootstrapping the Go command, start-issue install performs the same
platform selection and SHA-256 verification before installing the latest POSIX
release binary into ~/.local/bin.
Build and install from source:
make installThis builds and installs the Go binary to ~/.local/bin/start-issue.
Make sure ~/.local/bin is in your PATH.
Update an existing installation to the latest published GitHub Release:
start-issue update
start-issue --updateThe update workflow resolves the latest GitHub Release for dapi/start-issue,
compares it with the running executable version, and updates the same
executable path when a newer release exists. If the installed version is
already current, the command exits successfully with a clear no-op message.
start-issue 123
start-issue https://github.com/owner/repo/issues/123
start-issue 123 --repo owner/repo --base develop
start-issue 123 --agent codex
start-issue 123 --agent codex --model gpt-5.2
start-issue 123 --agent codex --human-gate
start-issue 123 --agent kimi --prompt-file .start-issue/prompt.md
start-issue 123 --no-agent
start-issue 123 --dry-run
start-issue setup
start-issue --setup
start-issue init
start-issue init --project --agent codex --model gpt-5.2
start-issue update
start-issue --update
start-issue --human-gate-helpRunning start-issue without an issue prints the normal help plus the currently
selected agent, selected model, prompt source, and prompt location, then exits
without contacting GitHub.
flowchart TD
A["start-issue ISSUE [options]"] --> B["Resolve context<br/>repo, issue, base branch"]
B --> C["Load configuration<br/>agent, prompt, worktree dir"]
C --> D["Fetch GitHub issue metadata"]
D --> Z["Optional zellij tab rename<br/>with zellij-tab-status"]
Z --> E["Plan branch and worktree path"]
E --> F{"--dry-run?"}
F -- yes --> G["Print planned actions<br/>and exit"]
F -- no --> H["Create or reuse git worktree"]
H --> I["Run worktree init hook if enabled"]
I --> J["Render agent prompt"]
J --> K{"Agent selected?"}
K -- yes --> L["Launch selected coding agent<br/>inside worktree"]
K -- no --> M["Print manual next steps"]
L --> N["Work on issue"]
M --> N
The Go entrypoint is cmd/start-issue. It owns argument parsing, configuration
resolution, repository and worktree orchestration, self-install/update, output,
and adapter commands for supported agents. git, gh, and agent CLIs remain
explicit external process boundaries.
- Configuration and prompt helpers resolve CLI, environment, project, and user defaults.
- Repository/worktree helpers fetch issue metadata, plan reuse safely, and run
the optional
init.shhook found in a prepared worktree. - Agent helpers validate adapters, build launch commands, generate AI branch names, and run Codex human-gate mode.
- Release helpers select platform assets, verify checksums and staged
--versionoutput, and atomically install updates.
The internal pipeline is now:
- Parse input.
- Resolve config.
- Fetch issue.
- Plan branch and worktree.
- Execute the plan.
- Launch the selected agent.
The Go implementation keeps lifecycle commands, configuration shape, and output in one compiled CLI while retaining external-tool boundaries. Future additions should preserve the same focused helper boundaries rather than reintroducing a second runtime implementation.
| Argument | Description |
|---|---|
ISSUE | GitHub issue number or full GitHub issue URL. Required. |
init | Create default configuration files for either the current project or the current user. |
setup | Run first-run onboarding for user config in ~/.config/start-issue. |
update | Update the running start-issue executable from the latest published GitHub Release. |
--repo OWNER/REPO, -r OWNER/REPO | Repository to read the issue from when ISSUE is a number. If omitted, start-issue detects the repository from origin. |
--base BRANCH, -b BRANCH | Base branch for the new worktree branch. If omitted, start-issue uses the repository default when available, otherwise the current branch. |
--worktree-dir DIR, -w DIR | Parent directory for created worktrees. Overrides START_ISSUE_WORKTREE_DIR. |
--flat | Use a flat worktree path by replacing / in the branch name with -. |
--agent AGENT | Agent to launch after preparing the worktree. With init, the default agent to write. Supported: claude, codex, kimi, pi, none. |
--model MODEL | Explicit model for the selected agent. With init, the model config to write. If omitted, built-in behavior stays unset and the selected agent CLI decides. |
--no-agent | Prepare the worktree and print manual next steps without launching an agent. Alias for --agent none. |
--no-claude | Compatibility alias for --no-agent. |
--prompt TEXT | Inline prompt template for the selected agent. With init, the prompt template to write. Mutually exclusive with --prompt-file. |
--prompt-file PATH | Prompt template file for the selected agent. With init, the file content to write. Mutually exclusive with --prompt. |
--improve-prompt | Ask the selected agent to generate a reviewable improved prompt template proposal, then exit before creating a worktree. |
--human-gate | Codex-only batch mode for issue work. Runs codex exec, exits on STATUS: DONE, and resumes the same session on STATUS: HUMAN_GATE. |
--human-gate-help | Show dedicated help for the Codex human-gate workflow, including prompt contract, exit codes, and state files. |
--prompt-output-file PATH | Proposal output path for --improve-prompt. |
--no-init | Do not run init.sh even if it exists in the created worktree. |
--command COMMAND, -c COMMAND | Claude command prefix used by the default Claude prompt. Default: /task-router:route-task. |
--ai | Ask the selected agent to generate the branch name. Falls back to the local branch-name heuristic if generation fails. |
--project | With init, write project config under .start-issue in the git root. |
--user | With init, write user config under ~/.config/start-issue. |
--force | With init, overwrite existing agent and prompt.md files, and reset model to the selected value or to built-in unset when --model is omitted. Existing files are kept by default without --force. |
--dry-run | Print the selected configuration and launch command without creating a worktree, running init.sh, or launching an agent. With init, print planned config writes without creating files. |
--setup | Run the same user-config onboarding flow as start-issue setup. |
--update | Update the running start-issue executable from the latest published GitHub Release. Equivalent to start-issue update. |
--version, -v | Show version. |
--help, -h | Show help. |
Detailed per-agent examples are in docs/agent-examples.md.
Related Claude Code marketplace workflows:
| Variable | Description |
|---|---|
START_ISSUE_AGENT | Default agent when --agent is not provided and no config file sets an agent. Supported: claude, codex, kimi, pi, none. Built-in default: claude. |
START_ISSUE_MODEL | Default model when --model is not provided and no config file sets a model. Built-in default: unset, which lets the selected agent CLI decide. |
START_ISSUE_PROMPT | Inline prompt template used when no CLI prompt is provided. It overrides project and user prompt files. Mutually exclusive with START_ISSUE_PROMPT_FILE when no CLI prompt is provided. |
START_ISSUE_PROMPT_FILE | Prompt template file used when no CLI prompt is provided. It overrides project and user prompt files. Mutually exclusive with START_ISSUE_PROMPT when no CLI prompt is provided. |
START_ISSUE_WORKTREE_DIR | Default parent directory for created worktrees when --worktree-dir is not provided. Built-in default: ~/worktrees. |
START_ISSUE_DUMP_PROMPT | When set to 1, dry-run output includes the full rendered prompt instead of only summary information. |
| File | Description |
|---|---|
.start-issue/agent | Project default agent. Read from the git root. |
.start-issue/model | Project default model. Read from the git root when present. |
.start-issue/prompt.md | Project default prompt template. Read from the git root. |
~/.config/start-issue/agent | User default agent. |
~/.config/start-issue/model | User default model. Read when present. |
~/.config/start-issue/prompt.md | User default prompt template. |
Run start-issue setup or start-issue --setup for the friendly user-level onboarding flow. It works only with ~/.config/start-issue, asks for the default agent (claude, codex, kimi, pi, or skip), shows the derived default prompt, and writes prompt.md only when the user confirms.
Run start-issue init for the existing manual initializer. If neither --project nor --user is provided, the command asks which scope to initialize. It writes the built-in default agent and prompt unless --agent, --prompt, or --prompt-file is provided. --model writes a sibling model file; when --model is omitted, built-in behavior stays unset and no new model file is created. If an existing agent file is kept without --force, the generated default prompt is chosen for that kept agent.
On an ordinary non-setup launch, if ~/.config/start-issue does not exist yet, start-issue shows a compact first-run message and asks whether to run setup immediately. If the user declines, it still creates the empty ~/.config/start-issue directory so the onboarding prompt is not shown again automatically.
start-issue update and start-issue --update are equivalent entry points.
The workflow:
- Resolves the latest published GitHub Release for
dapi/start-issue. - Reads the version of the executable the user is currently running.
- Normalizes version strings so
1.11.1andv1.11.1compare as equal. - If the running version is current or newer than the latest published release, exits
0with a clear status message. - If a newer published release exists, downloads the matching platform binary and
checksums.txt, verifies the checksum, and installs the update into the resolved target of the executable the user invoked.
The update workflow works outside a git repository and requires only gh.
The Go binary parses release metadata, downloads assets, and verifies checksums
internally.
start-issue 123 --agent codex --human-gate keeps the normal issue-start workflow through worktree creation, optional init.sh, and prompt rendering, but replaces the final interactive Codex launch with a resumable batch run.
The batch flow:
- runs
codex execwith JSON event output and a saved last-message file; - captures
thread_idfrom thethread.startedevent; - exits
0onSTATUS: DONE; - opens
codex resume --include-non-interactive <thread_id>onSTATUS: HUMAN_GATE.
This mode is intentionally Codex-only. --human-gate with any other agent fails clearly instead of being ignored.
When the workflow is about to block for a branch/worktree decision, it prints
Waiting for input: .... Before handing control to an interactive agent or
Codex batch run, it prints Handing off to <agent> in <worktree>. A non-zero
exit from codex exec is reported as a failed human-gate run with exit code 1;
the captured events and thread id remain available for diagnosis.
Dedicated help:
start-issue --human-gate-helpPrompt contract:
- The final message must contain exactly one terminal status line:
STATUS: DONEorSTATUS: HUMAN_GATE. HUMAN_GATEis only for real user decisions such as destructive actions, missing credentials, incompatible product choices, or unresolved test failures that cannot be fixed safely inside scope.
Exit codes:
0: Codex returnedSTATUS: DONE.1: Codex failed, nothread_idwas captured, no recognized final status was found, or parsing failed.2: Codex returnedSTATUS: HUMAN_GATE, butstart-issuecould not open interactive resume. The resume command and thread id are printed for manual reuse.
State files:
<worktree>/.start-issue/runs/<timestamp>/events.jsonl
<worktree>/.start-issue/runs/<timestamp>/last-message.txt
<worktree>/.start-issue/runs/<timestamp>/thread-id
The normal Bats suite uses a fake Codex CLI. To exercise the real local Codex
CLI, run this opt-in test from a start-issue checkout:
START_ISSUE_E2E=1 make e2e-human-gateThe script uses the private dapi/start-issue-e2e-fixture repository and its
control issue, requires authenticated gh, rejects the fake Codex binary, and
creates an isolated temporary clone and worktree parent. It deletes those after
success; set START_ISSUE_E2E_KEEP=1 to retain them. It also rejects any
fixture worktree change other than its .start-issue state. To test interactive resume, run:
START_ISSUE_E2E=1 \
test/e2e/human-gate.sh --scenario human-gateExit the resumed Codex session to let the script verify the artifacts.
| Scenario | Command | What it verifies |
|---|---|---|
done | START_ISSUE_E2E=1 make e2e-human-gate | A real Codex batch run emits thread.started, saves thread-id, events.jsonl, and last-message.txt, ends with STATUS: DONE, and leaves no fixture change other than .start-issue state. |
human-gate | START_ISSUE_E2E=1 test/e2e/human-gate.sh --scenario human-gate | The same artifact and clean-worktree checks, plus the reported explicit codex resume --include-non-interactive <thread_id> handoff. The operator exits the resumed interactive session before the script can finish. |
Both scenarios verify authenticated gh, a real rather than fake Codex binary,
and the required codex exec help interface (--output-last-message, without
the obsolete --ask-for-approval flag). The selected Codex executable is
printed in the test output. They do not prove application behavior beyond this
human-gate protocol and are intentionally excluded from CI.
Run the deterministic built-binary E2E locally:
make e2e-sandboxIt uses a temporary local git repository plus fake gh and Kimi commands, but
real worktree creation, init.sh, prompt rendering, model/cwd forwarding, and
dry-run behavior. It needs no network, credentials, or external agent and runs
in the sandbox-e2e CI job.
Configuration precedence:
- Agent: CLI
--agent/--no-agent, then project config, user config,START_ISSUE_AGENT, then built-in defaultclaude - Model: CLI
--model, then project config, user config,START_ISSUE_MODEL, then built-in unset - Prompt: CLI, then project config, user config, environment prompt, then built-in default
Claude uses the plugin-native command by default:
/task-router:route-task {ISSUE_URL}
Other agents use a portable prompt by default. Kimi is launched from the
worktree directory because current Kimi Code CLI versions do not support the
legacy --work-dir option and reject --yolo together with --prompt.
To improve the prompt template used for future development starts, run:
start-issue 123 --agent codex --improve-promptThe command resolves the active prompt template with the normal precedence, fetches the issue as context, asks the selected agent for a complete improved prompt template, and writes a proposal file. It does not overwrite the active prompt. Markdown prompt files write next to the source as *.improved.md; other file names append .improved. Built-in and inline prompts write to .start-issue/prompt.improved.md. Use --prompt-output-file to choose another proposal path.
Prompt templates support:
{ISSUE_URL}
{ISSUE_NUMBER}
{ISSUE_TITLE}
{ISSUE_BODY}
{ISSUE_LABELS}
{REPO}
{BRANCH_NAME}
{WORKTREE_PATH}
{BASE_BRANCH}
Unknown placeholders are left unchanged.
If zellij-tab-status is available in PATH, start-issue renames the current Zellij tab to #ISSUE_NUMBER with zellij-tab-status --set-name after the issue is fetched.
This step is optional. Missing zellij-tab-status is ignored, and a rename failure is reported as a warning without stopping the workflow.
Optional dependency for Zellij support:
gitghCLI with authenticated GitHub session- selected agent CLI unless
--agent noneor--dry-runis used
Building from source additionally requires Go 1.24+. The optional Bash
installer and the manual-install snippet require bash, curl or wget, and
a SHA-256 tool; those tools are not used by start-issue update.
GitHub Releases are published automatically when a SemVer tag like v1.12.0 is pushed. The release workflow reruns the Go test suite and publishes platform-specific binaries with a checksum manifest:
start-issue-linux-amd64start-issue-linux-arm64start-issue-darwin-amd64start-issue-darwin-arm64start-issue-windows-amd64.exechecksums.txtstart-issueandstart-issue.sha256(temporary v1 update bridge)
To prepare a release locally:
make test
git tag v2.0.0
git push origin v2.0.0Before preparing a release, add user-facing changes under ## [Unreleased] in CHANGELOG.md.
Create releases from a clean worktree after make test and make build pass. The tag is the source of the published binary version.
Publish the prepared release with:
git push origin master --follow-tagsThe script specification is in doc/spec.md.
MIT