Reference¶
The commands of issue_assistant.py, the inputs and outputs of the action that runs them, the AI engines that it supports, and how to try a prompt on your own computer.
Commands¶
The action runs issue_assistant.py with one command:
| Command | Job | What |
|---|---|---|
event |
event | handles the event and the slash command of a comment, sets labels and names the AI's next task, within the limits of the AI runs |
engine |
analyze | names the engine of config.toml and whether its secret exists, and the model, turns, dollars and effort of the task |
context |
analyze | writes what the task reads into .issue-assistant/: the issue; for an analysis or a follow-up the other issues, the discussions and the labels; for a reply or a question the comment of its event; then the rules, the task and the schema |
usage |
analyze | writes the turns, time, cost and tokens of the engine's run into the summary of the job, numbers only, and a warning when the run stopped at its turns or its dollars |
apply |
apply | checks the AI's answer and posts it |
sweep |
lifecycle | reminds, closes unanswered issues and duplicates, marks fixed issues and closes them with the release |
sync-labels |
labels | creates and updates the labels, and renames those that the repository has in another case |
findings |
findings | dismisses the accepted findings of code scanning and fails while others are open; needs no other settings |
check |
your CI | checks labels, issue forms, workflows, firewall, settings, the description of the project and the notice to reporters, and names every key it doesn't know |
install runs from a git checkout of a release, as Set up a repository shows, and pins its commit and tag; --ref and --version name them for another checkout. install --setup also creates the environment issue-assistant for the default branch and has the GitHub CLI ask for the engine's secret. install, check, engine and usage read only the checkout, and install --setup the environment too; the other commands call GitHub, for the repository that GH_REPO names as owner/name, or else the workflow's GITHUB_REPOSITORY. Every command but install and check takes dry-run: true to only report what it would write; runs by hand under Actions → Issue assistant → Run workflow start as dry runs, and their summary shows the comment, as the last step of the set-up shows.
Inputs and outputs of the action¶
The workflows of the templates set the inputs of the action; a workflow of your own, such as the check in the CI, sets command, and for a command that writes maybe dry-run. The tables come from action.yml of this version.
Inputs¶
| Input | Required | Default | What it is |
|---|---|---|---|
command |
yes | none | event, engine, context, apply, usage, sweep, sync-labels, findings or check |
issue |
no | none | Number of the issue, for context, apply and usage |
mode |
no | none | Task of the engine (triage, follow-up, maintainer-reply, release-reply or maintainer-question), for engine, context, apply and usage |
answer |
no | none | The engine's JSON answer, for apply |
engine |
no | none | The engine that wrote the answer, for apply |
ready-engines |
no | none | Engines whose secret exists, separated by commas, for engine |
execution-file |
no | none | The execution file of the engine's action, whose numbers usage reports |
dry-run |
no | false |
Only report what would be written |
github-token |
no | ${{ github.token }} |
Token for the GitHub API; the job's permissions limit it |
Outputs¶
The commands event, engine and context set the outputs for the steps and jobs after them.
| Output | What it is |
|---|---|
issue |
The issue of the event |
mode |
The engine's next task, or none |
engine |
The engine of the repository's config.toml |
ready |
Whether the engine's secret exists |
model |
The engine's model for the task |
turns |
The most turns of the engine for the task |
budget |
The most dollars that the engine's run may cost |
effort |
The engine's effort, or empty for its default |
task |
The task for the engine, which the rules in .issue-assistant/rules.md precede as its system prompt |
prompt |
The rules and the task in one prompt, for templates before the rules became a system prompt |
schema |
The JSON schema of the engine's answer |
Engines¶
Everything except one step of the analyze job is independent of the AI: the context, the prompts in prompts/, the checks and every write. An engine gets the read-only checkout with the context in .issue-assistant/, the rules as its system prompt, the task and the JSON schema of its answer (as files and as outputs of the context step), and the model, turns, dollars and effort of the task from the step engine, and returns the JSON answer. apply validates it whether or not the engine could enforce the schema, and also accepts it in a code fence.
| Engine | Step | Secret | Restrictions |
|---|---|---|---|
claude (default) |
anthropics/claude-code-action |
CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY |
--restricted --tools "Read,Grep,Glob", the rules with --append-system-prompt-file, --max-turns and --max-budget-usd, schema with --json-schema |
To add one, for example OpenAI Codex with openai/codex-action (prompt-file, output-schema-file and a read-only sandbox) or the GitHub Copilot CLI in programmatic mode (only reading tools, the JSON asked for in the prompt): add it to ENGINES in issue_assistant.py with its secrets, the one that install --setup asks for first, give it a step with its key as id in templates/.github/workflows/issue-assistant.yml with the same condition as the Claude step, add its secret to ready-engines and its answer to the job output answer, pass it the rules, the turns and the dollars of the task, give usage the numbers of its run, add its hosts to templates/.github/egress-firewall.yaml in a block of its own, and its rules to ENGINE_RULES in tests/test_templates.py, which keeps it read-only.
Try a prompt locally¶
export GH_REPO=OWNER/REPO DRY_RUN=true
python3 issue_assistant.py context --issue 12 --mode triage # in the repository's checkout
claude -p "$(cat .issue-assistant/prompt.md)" --restricted --tools "Read,Grep,Glob" \
--append-system-prompt-file .issue-assistant/rules.md --max-turns 40 --max-budget-usd 1 \
--json-schema "$(cat .issue-assistant/schema.json)" --output-format json > answer.json
RESULT="$(jq -c .structured_output answer.json)" python3 issue_assistant.py apply --issue 12 --mode triage
To try it on an issue that exists nowhere, write the issue and its comments into a JSON file, as GitHub's REST API gives them, and name the file in ISSUE_ASSISTANT_FIXTURE, relative to the checkout. context and apply then read that issue instead of one on GitHub, take its number, and write nothing, as in a dry run; the other issues, the discussions and the labels still come from GitHub. The issue of the project's own canary, tests/fixtures/canary-issue.json, is an example:
gh api repos/OWNER/REPO/issues/12 | jq '{issue: ., comments: []}' > issue.json # then change it
export ISSUE_ASSISTANT_FIXTURE=issue.json
python3 issue_assistant.py context --mode triage