feat: claude-dispatch workflow (guiziwebbot) - #3
Merged
Conversation
Single reusable entrypoint called by a per-repo issue_comment stub. PR comments -> code-review; issue '@guiziwebbot fix' -> implement and open a PR. Guardrails live in the right layers (ruleset for merge, CLAUDE.md for conventions, CI for tests); the prompt only carries what no mechanism can: implement, open PR, and ping the author when ambiguous. Claude-Session: https://claude.ai/code/session_01UjSKLDquR9hJa3Dg6dJKxi
Scope the app token to the triggering repo only (blast radius = one repo) and grant the fix agent file-edit tools only (no arbitrary Bash). The action handles branch/PR creation. Guardrails stay layered: ruleset blocks merge, human approves. Claude-Session: https://claude.ai/code/session_01UjSKLDquR9hJa3Dg6dJKxi
…ssue and open the PR Claude-Session: https://claude.ai/code/session_01UjSKLDquR9hJa3Dg6dJKxi
Router v1 grammar: issue+fix -> implement+PR; PR+review/bare -> review; PR+fix -> revise (apply feedback, push to the PR branch). Per-issue concurrency group prevents concurrent runs on the same item. Claude-Session: https://claude.ai/code/session_01UjSKLDquR9hJa3Dg6dJKxi
Deterministic label state around the fix agent: add bot:working before, and after (always) remove it; set bot:stuck if the agent failed or no PR linking the issue was opened. Labels are created on the fly if missing. Claude-Session: https://claude.ai/code/session_01UjSKLDquR9hJa3Dg6dJKxi
… prompts The fix/revise logic and label handling move into the guiziweb-bot marketplace plugin. The workflow now only routes and passes parameters: fix-issue gets the issue number, revise-pr gets the PR number and the linked issue (resolved via GraphQL closingIssuesReferences). All inline github-script label management is gone. Claude-Session: https://claude.ai/code/session_01UjSKLDquR9hJa3Dg6dJKxi
Replace the classify/checkout/GraphQL/3-mode routing (~90 lines) with a single action step + a routing prompt. The action handles smart branch handling (PR comment -> push to PR branch, issue -> new branch) and context natively. Keep only our value-adds: camille guard, app token, skills, labels (in skills). Test before deleting the old approach. Claude-Session: https://claude.ai/code/session_01UjSKLDquR9hJa3Dg6dJKxi
The agent does the work (and may set 'blocked' when stuck); the workflow owns the label STATE so it never drifts: a pre-step marks 'in progress' + reacts immediately, a post-step (always) assigns the reviewer and sets 'needs review' unless the agent flagged 'blocked'. Claude-Session: https://claude.ai/code/session_01UjSKLDquR9hJa3Dg6dJKxi
…ure) Allow make/docker/composer/npx + mcp__playwright so the agent can bring the project's app up (make init/database-init/load-fixtures) on the runner, then capture a page with Playwright MCP and deliver it inline via the bot-screenshots branch. Claude-Session: https://claude.ai/code/session_01UjSKLDquR9hJa3Dg6dJKxi
… on intent Drop Docker/make-init. A classify step detects a screenshot request and only then boots the test app exactly like build.yaml: setup-php + mysql-action + composer/yarn + db/schema/fixtures + symfony server :8080. No image pulls -> fast. The agent navigates 127.0.0.1:8080 via Playwright MCP and delivers the PNG on the bot-screenshots branch. Claude-Session: https://claude.ai/code/session_01UjSKLDquR9hJa3Dg6dJKxi
…patch) The Guiziweb/bot VPS app is gone, so the repository_dispatch -> claude-review path is dead. Everything now goes through claude-dispatch (workflow_call, native context). Claude-Session: https://claude.ai/code/session_0198vwGe6fEi7HKW4w6NLo7K
…ion_file artifact for format check) Claude-Session: https://claude.ai/code/session_0198vwGe6fEi7HKW4w6NLo7K
…end to tracking comment - execution_file is a JSON array; the final result event holds Claude Code's own usage totals + total_cost_usd (per-message usage is streaming-stale) - append the token line to the track_progress comment, fallback to a standalone comment - continue-on-error so token reporting can never fail the bot run - drop the temporary execution_file artifact (format confirmed) Claude-Session: https://claude.ai/code/session_0198vwGe6fEi7HKW4w6NLo7K
…ction Replace the inline bash/jq blob with a reusable composite action (.github/actions/report-tokens) whose logic lives in a real JS file. Reads the authoritative usage from the execution file's final result event and appends a token/cost table to the run's tracking comment (fallback to a standalone comment). The workflow step is now a 4-line 'uses:' call. Claude-Session: https://claude.ai/code/session_0198vwGe6fEi7HKW4w6NLo7K
…cle, agent owns only 'blocked' The prompt no longer claims labels are handled entirely outside (it was contradicted by the skills). It now states the truth: the workflow sets 'in progress'/'needs review' on the triggering item; the agent may only set 'blocked' when it gives up. Claude-Session: https://claude.ai/code/session_0198vwGe6fEi7HKW4w6NLo7K
Extract the inline classify/setup/finalize logic into three composite actions whose code lives in real files (classify.js, mount.sh, finalize.js), mirroring report-tokens. The workflow resolves the PR head in classify and checks it out so the test app boots on the right branch, always mounts the app, and broadens allowedTools so the agent can run the test/build gate and drive the UI via Playwright. Claude-Session: https://claude.ai/code/session_017kew2Mb2ckZ6oB4hawfvtL
…--resume Restore ~/.claude/projects from the Actions cache (keyed per issue/PR), resolve the last transcript to a --resume <id>, and save it back after the run. On a follow-up comment the agent resumes its session instead of starting fresh. Includes temporary debug steps to inspect the session dir around the claude step. Claude-Session: https://claude.ai/code/session_017kew2Mb2ckZ6oB4hawfvtL
track_progress forces tag mode (detectMode), which restricts the agent to read/git/comment tools and makes it emit a "Create PR" link instead of a real PR. In tag mode the agent could not run the test/build gate at all — so it fabricated a passing result. Dropping track_progress selects agent mode, where claude_args --allowedTools is honored and the skill opens a real PR via gh. We lose the live checklist comment (cosmetic); report-tokens falls back fine. Claude-Session: https://claude.ai/code/session_017kew2Mb2ckZ6oB4hawfvtL
In agent mode the agent really has gh, so Bash(gh:*) would let it merge its own PR or hit the raw API. Restrict to the verbs the skills actually use (issue view/edit/comment, pr view/diff/create/comment/edit). Claude-Session: https://claude.ai/code/session_017kew2Mb2ckZ6oB4hawfvtL
After the agent fabricated a passing gate it never ran, the prompt now asks it to report the real result, say so plainly if a check fails or it cannot run it, and never claim untested passes. The PR's own CI remains the source of truth. Claude-Session: https://claude.ai/code/session_017kew2Mb2ckZ6oB4hawfvtL
Agent mode denied 15 tool calls with a narrow allowlist — compound commands (cd ... && ...) and common bash never match single-tool patterns — leaving the agent unable to run the gate or open a PR. The runner is ephemeral and the token is repo-scoped, so switch to bypassPermissions and rely on the branch-protection ruleset (PR + review, no bot bypass) as the real guard, not a fragile allowlist. Claude-Session: https://claude.ai/code/session_017kew2Mb2ckZ6oB4hawfvtL
…cache Since 2026-06-26 GitHub hands issue_comment runs a read-only cache token (untrusted trigger), so cache/save can never work here — every save failed with "token has no writable scopes". Artifacts are not restricted: save uploads ~/.claude/projects as claude-session-<issue> (30d retention), and a new restore-session composite action downloads the latest one and resolves the --resume flag (absorbing the inline resolve step). Claude-Session: https://claude.ai/code/session_017kew2Mb2ckZ6oB4hawfvtL
…up-test-app The dispatch runs on an untrusted trigger (issue_comment) so it may not write caches — but reading is allowed, and build.yaml already refreshes the composer and yarn caches on every push with lockfile-hashed keys. Restore them with the same keys before mounting: downloads are skipped and composer/yarn install only extracts. No save step: build.yaml owns the cache. Claude-Session: https://claude.ai/code/session_017kew2Mb2ckZ6oB4hawfvtL
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merges the claude-dispatch stack: the reusable workflow, its actions (classify, setup-runner with on-demand mount.sh, restore-session via artifacts, report-tokens, finalize), and the guiziweb-bot plugin (fix-issue / revise-pr skills) hosted next to the workflow as its own marketplace.
Note: dispatch stays broken until this merges, since the workflow now installs guiziweb-bot from this repo's default branch.