Ai-Mee Help Centre
Home
Features
How-To Guides
FAQ
Need Help?
Home
Features
How-To Guides
FAQ
Need Help?

Cloud agent — autonomous issue → PR

Run Claude on a GitHub issue unattended and remotely, iterating until done, using Claude Code on the web (Anthropic-managed cloud sessions) instead of GitHub Actions.

Why this over GitHub Actions: the agent loop runs on Anthropic's VM and bills to the Max subscription's rate limits — 0 GitHub Actions minutes. Since 1 March 2026 self-hosted runners are metered on private repos, so the old @claude workflow (.github/workflows/claude.yml) is no longer free. That workflow is kept as a fallback but should be retired once this is trusted.

Flow

issue labelled `claude`
  → Routine fires a cloud session
  → session clones the repo (.claude/skills/start, CLAUDE.md, hooks all load)
  → setup script (cached, repo-independent): supabase CLI + Playwright browser
  → SessionStart hook (scripts/cloud-session-start.sh):
        pnpm install → start dockerd (vfs, iptables off) → supabase start
        (all best-effort; writes /tmp/cloud-supabase-status = ready|failed)
  → prompt: /start <issue>   → implements; verifies with live /verify-fe if
                               Supabase is `ready`, else the mock-mode suite;
                               opens a PR via the GitHub MCP tools (Closes #<n>)
  → Auto-fix watches ci.yml and pushes fixes until green — no human @claude

Sandbox reality (verified in a live session + community reports):

  • No gh CLI — GitHub goes through the built-in mcp__github__* tools + the git push proxy (scoped to the current branch).
  • Docker daemon isn't running by default but can be started with constrained-kernel flags (--storage-driver=vfs --iptables=false --ip6tables=false; see anthropics/claude-code#29515). The SessionStart hook does this.
  • Bridge networking is unavailable, so a multi-container stack like supabase start may not fully come up. The hook attempts it and records the outcome in /tmp/cloud-supabase-status. When it fails, verification falls back to ci.yml's mock-mode suite (unit + route + Playwright e2e with fake VITE_SUPABASE_*), which needs no backend. If reliable local Supabase is a hard requirement, run the Routine against your own VPS environment instead (bridge networking works there).

One-time setup

1. Install the Claude GitHub App (required for Auto-fix)

Onboard at claude.ai/code using the GitHub App method (not just /web-setup). The App delivers the PR webhooks that Auto-fix needs. Install it on the ai-marketing repo. This also provides the built-in mcp__github__* tools and the git push proxy the session uses — no gh CLI or GH_TOKEN required.

2. Create a cloud environment + setup script

In the claude.ai web UI, add an environment (cloud icon → Add environment). The setup script runs once and its filesystem is cached (snapshotted), so keep it under ~5 minutes.

The setup script does NOT run inside your repo. Its working directory is /home/user and the clone isn't available at that phase, so anything with cd front-end, git, or pnpm install fails the setup (exit 1 → session won't start). Only do repo-independent global installs here; repo-relative work goes in the SessionStart hook (which runs later with the repo at $CLAUDE_PROJECT_DIR).

Node, pnpm, Postgres, Docker binaries and ripgrep are pre-installed. The script adds the Supabase CLI and the Playwright browser (globally, so no repo needed):

#!/bin/bash
npm install -g supabase
npm install -g [email protected]   # keep in sync with front-end's @playwright/test
playwright install chromium        # downloads to ~/.cache/ms-playwright — cached in the snapshot
  • Do NOT install gh, do NOT start dockerd, and do NOT touch the repo here.gh isn't in Ubuntu's repos (GitHub is handled by the MCP tools + git proxy). Starting dockerd in the setup script is reported to crash the environment — the SessionStart hook starts it per session. pnpm install also lives in the hook, since the repo isn't present during setup.

  • Keep the pinned Playwright version in sync with front-end's @playwright/test (same version → the global-install browser matches what the repo's tests expect). It currently tracks ci.yml's mcr.microsoft.com/playwright:v1.58.2-noble.

  • Network access: the default Trusted list does not include cdn.playwright.dev, which Playwright 1.58 uses to download Chrome-for-Testing — so playwright install 403s on Trusted. Switch to Custom, tick "Also include default list of common package managers", and add:

    cdn.playwright.dev
    

    (If a later run 403s on a different host — Playwright sometimes redirects to a storage CDN — add that host too.) npm, Docker Hub (Supabase images), and GitHub are already covered by the default list.

  • Environment variables (.env format, no quotes — visible to anyone who can edit the environment, so local/test values only, never production). Use the same VITE_SUPABASE_URL and VITE_SUPABASE_API_KEY your local front-end/.env.local uses — these point at the local Supabase (this project runs it on port 5411, not the default 54321) so the live /verify-fe path works when Supabase boots, and they're harmless in mock mode (the value is ignored there). The VITE_SUPABASE_API_KEY is a client publishable key, safe to place here.

    No GH_TOKEN, no production secrets (there is no secrets store yet).

3. Repo-side wiring (already committed)

  • scripts/cloud-session-start.sh — SessionStart hook. No-op locally (CLAUDE_CODE_REMOTE != true); in the cloud it runs pnpm install, starts the Docker daemon (constrained-kernel flags), and attempts supabase start. All best-effort and non-fatal; the outcome is written to /tmp/cloud-supabase-status (ready|failed) for /start to branch on.
  • .claude/settings.json — registers the hook (see Apply the settings hook below if not yet present).
  • .claude/skills/start/SKILL.md — when CLAUDE_CODE_REMOTE=true, /start skips the ~/.worktrees worktree and checks out in place, uses the GitHub MCP tools + git proxy instead of gh, and verifies with live /verify-fe when Supabase booted (/tmp/cloud-supabase-status = ready) or the mock-mode suite otherwise.

Apply the settings hook

Ensure .claude/settings.json contains:

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup|resume",
        "hooks": [
          { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/scripts/cloud-session-start.sh" }
        ]
      }
    ]
  }
}

4. Create the trigger Routine

Create a Routine pinned to the environment from step 2, prompt:

/start <issue number>
After opening the PR, enable auto-fix on it (or run /autofix-pr on the branch).

Trigger: a GitHub event filtered to issues labelled claude.

If issue-label events aren't a supported Routine trigger yet, use one of:

  • a scheduled Routine that runs /start on the newest open claude-labelled issue (managed polling), or
  • manual kickoff from a terminal: claude --remote "/start 612".

Confirm the currently supported trigger types when you build this.

Daily use

  1. Open an issue (or label an existing one) with claude.
  2. The Routine spins up a cloud session; watch it at claude.ai/code or on mobile.
  3. /start opens a PR; Auto-fix drives ci.yml to green automatically.
  4. Review and merge the PR like any other.

Caveats (research preview)

  • Docker + local Supabase are best-effort. The daemon starts with constrained flags, but bridge networking is unavailable, so supabase start may fail. When it does, verification falls back to the mock-mode suite (unit + route + Playwright e2e with fake VITE_SUPABASE_*) — the same checks ci.yml runs, needing no backend. For guaranteed local Supabase, use a VPS environment instead. First-session supabase start is slow (pulls ~10 images); they cache to disk for subsequent sessions.
  • No gh CLI — GitHub is reached via the built-in mcp__github__* tools and the git push proxy (scoped to the current branch).
  • Shared rate limits with all interactive Claude usage — parallel runs eat into your own quota.
  • No secrets store — env vars are visible to environment editors; test/mock keys only.
  • GitHub-only for pushing PRs.
  • Auto-fix does not resolve merge conflicts (GitHub emits no webhook for them). If the base branch advances into a conflict, open the session and ask Claude to rebase.
  • Resource ceiling: 4 vCPU / 16 GB RAM / 30 GB disk per session.

Verification checklist

  1. Start a session in the environment; run check-tools — confirm Playwright chromium is present. (gh will be absent — expected; GitHub is via MCP.)
  2. Confirm the SessionStart hook ran: node_modules/ exists at the repo root and under front-end/ (proves pnpm install executed). If it's missing, the .claude/settings.json hook isn't wired — see Apply the settings hook. Then check cat /tmp/cloud-supabase-status:
    • ready → Docker + local Supabase came up; supabase status should work.
    • failed → inspect /tmp/dockerd.log; verification will use mock-mode. This is the expected outcome if the sandbox lacks bridge networking.
  3. Label a throwaway issue claude; confirm the session checks out a branch without a ~/.worktrees worktree, verifies (live /verify-fe if Supabase is ready, else the mock-mode suite), and opens a PR via the GitHub MCP tools.
  4. Seed a failing check so ci.yml goes red once; confirm Auto-fix pushes a fix and CI goes green with no human @claude.
  5. Confirm .github/workflows/claude.yml and ci.yml are unchanged and the cloud run shows no compute charge (subscription usage only).

Fallbacks

  • .github/workflows/claude.yml — the metered self-hosted @claude path.
  • A self-hosted Docker poller (own VPS) — only if preview limits prove blocking.