A Hermes gateway plugin for running GitHub sub-issues through auditable agent implementation workflows from Discord.
This repository contains the issue #2 technical spike artifact and an incremental issue-runner prototype: Discord command handling, GitHub child discovery/selection, operational label state, branch preparation, child-session launch prompts, and parent-run resume/continuation behavior.
See docs/spike-002-gateway-native-discord-child-sessions.md.
Short version:
- Hermes already has gateway-native Discord streaming for normal sessions via
GatewayStreamConsumer. - Hermes already has a Discord adapter-private
/threadflow that can create a Discord thread and dispatch a Hermes session into it. - A repository/user plugin can catch a test trigger through
pre_gateway_dispatch, but it does not have a stable public gateway API for “create thread, then start a gateway-origin streamed child session in that thread”. - The smallest core extension should expose that existing adapter/gateway behavior as a supported service method while keeping the user-facing artifact a plugin.
plugins/issue_runner/— minimal Discord start command plugin entrypoint.src/issue_runner/start.py— parser/handler for slash and mention start commands with injected auth/GitHub seams.src/issue_runner/selection.py— pure GitHub child discovery,ready-for-agentfiltering, blocker parsing, and deterministic next-child selection.plugins/issue_runner_spike/— minimal plugin prototype for a/issue-runner-spiketext trigger.src/issue_runner_spike/seam.py— source-inspection/seam model and CLI smoke-check helper.tests/test_start_command.py— unit tests for issue #3 start command behavior.tests/test_seam.py— lightweight semantic checks for the proposed seam.
The issue-runner plugin recognizes slash-style commands such as:
/issue-runner start owner/repo#1
/issue-runner start https://github.com/owner/repo/issues/1
It also recognizes mention-oriented natural language, for example:
@Hermes start issue runner for owner/repo#1
A started parent run re-selects children from current GitHub state. It starts the
next unblocked child labeled ready-for-agent, reserves that child with
agent:in-progress before branch/session setup, then launches one gateway child
session. If a controlled child-session adapter explicitly reports completion
(agent:done, completed_child_issue, or equivalent), the parent loop marks that
child agent:done, removes agent:in-progress, re-fetches GitHub state, and
advances to the next runnable child. Normal gateway scheduling acknowledgements do
not auto-advance; the operator should resume after the child finishes.
Resume/continue commands are live Discord continuations that use the same handler path and reply formatting as start:
/issue-runner resume owner/repo#1
/issue-runner continue owner/repo#1
@Hermes continue issue runner for owner/repo#1
Operational labels:
ready-for-agent— child issue is eligible for selection.agent:in-progress— child issue is reserved/running; duplicate parent starts are refused while any child has this label. The handler preserves this label on branch preparation, child-session startup, or review/child-session failure so operators can inspect and recover the attempt. It is cleared only when the child is markedagent:doneor by explicit operator cleanup.agent:done— child issue is complete; blockers referencing it are satisfied.
The handler reuses Hermes Discord authorization through the injected gateway
authorization predicate (for example _is_user_authorized) and requires an
injected GitHub client with get_issue(owner, repo, number) plus one child
discovery method: list_child_issues(owner, repo, parent_number),
list_sub_issues(...), or get_child_issues(...). Child issues are eligible
only when labeled ready-for-agent; blockers are parsed from each child issue's
## Blocked by section as #N references or GitHub issue links. A blocker is
satisfied when the referenced issue is closed or labeled agent:done. The plugin
imports the handler as issue_runner.start; for direct local imports from a
checkout, put src/ on PYTHONPATH (the plugin does this for its repository
layout during registration/tests).
python3 -m src.issue_runner_spike.seam --hermes-source "${HERMES_SOURCE:-$HOME/.hermes/hermes-agent}" --json
python3 -m unittest discover -s teststests/test_seam.py uses HERMES_SOURCE when set, defaults to
~/.hermes/hermes-agent, and skips the local source-inspection assertion when
that checkout is absent.
The plugin API shape in this spike is illustrative: the prototype may need small adaptations once Hermes core lands a supported child-session seam.
For a throwaway local check, copy or symlink plugins/issue_runner_spike/ into
the active Hermes profile plugin directory, enable it in the profile config, and
restart the gateway with Discord configured. Then run this from an authorized
Discord channel:
/issue-runner-spike inspect the current repository, run a harmless command, and summarize
Until gateway.start_child_session(...) exists, the prototype only consumes the
trigger when it can send a visible Discord diagnostic/ack through the Discord
adapter; it does not claim live child-session proof or emit invisible diagnostics
for other platforms.