Skip to content

feat: claude-dispatch workflow (guiziwebbot) - #3

Merged
camilleislasse merged 28 commits into
mainfrom
feat/claude-dispatch
Jul 31, 2026
Merged

feat: claude-dispatch workflow (guiziwebbot)#3
camilleislasse merged 28 commits into
mainfrom
feat/claude-dispatch

Conversation

@camilleislasse

Copy link
Copy Markdown
Contributor

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.

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
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
…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
@camilleislasse
camilleislasse merged commit 9a2b29f into main Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant