A minimal MCP server that exposes a remote Claude Code agent over HTTP. Your laptop's Claude Code calls run_task to delegate a whole job to an agent running on Cloud Run โ block for the answer, detach and poll long jobs, or pass a session_id to keep the conversation going.
sk8 runs claude headless on a remote box and returns the final answer.
It's deliberately small, but no longer just fire-and-wait: block for the result,
detach long jobs and poll them, or resume a session so the agent
remembers the previous exchange.
The remote agent runs your prompt in its cwd and hands back the final text answer. Blocking by default, up to 600s.
run_task(detach=true) returns TASK_STARTED: <task_id> immediately and runs in the background โ poll get_task for status and the answer. Long jobs stop fighting your MCP client's timeout.
Every answer ends with a [session_id]. Pass it back to continue the same conversation in the same workspace โ follow-ups can be short instead of restating the brief.
Customize each agent per profile โ extra Python packages, bundled Claude Code skills, and a tool / MCP / system-prompt spec compiled into the image at build time.
server_sdk.py drives the agent loop through the Claude Agent SDK โ a typed async message stream with structured permission control.
Send small files inline with the files param โ no bucket needed โ or use GCS-backed signed URLs to move big inputs and artifacts without bloating the prompt.
Install the CLI, provision an agent on Cloud Run, and wire it into Claude Code.
# install the `sk8` command from this repo (uv / pipx / pip all work)
uv tool install .
# build the agent image (first time) + provision on Cloud Run
sk8 create iris --build
# custom deps / skills / tools via a profile
sk8 create iris --profile ./profiles/data-analyst --build
# `sk8 create` prints the exact `claude mcp add ...` line โ run it, then:
claude mcp list # sk8 should show as connected
Then, in a Claude Code session on your laptop:
Use the sk8 run_task tool with prompt:
"list the files in the current directory and summarize them"
Long jobs run detached in the background, and every task hands back a session id you can use to continue the conversation โ the remote agent keeps its memory and its workspace between calls.
# kick off a long job without blocking your session
run_task(prompt="profile the test suite and find the 5 slowest tests", detach=true)
โ TASK_STARTED: 3f2a91c0โฆ
# poll every 30-60s until it's done (polling also keeps the instance alive)
get_task("3f2a91c0โฆ")
โ {status: "done", result: "โฆ", session_id: "9b1c44d2โฆ"}
# every answer ends with a session id line
run_task(prompt="write a fibonacci module with a CLI")
โ โฆ final answer โฆ [session_id: 9b1c44d2โฆ]
# pass it back โ same conversation, same workspace, short follow-up
run_task(prompt="now also add tests", session_id="9b1c44d2โฆ")
On GCS-backed agents, transcripts are mirrored to the bucket, so sessions survive even when the scale-to-zero instance is recycled between calls.
Scriptable for humans and agents alike โ it emits JSON so a running agent can spawn and register its own sub-agents.
sk8 create iris --build # build image (first time) + provision
sk8 create iris # subsequent agents reuse the image
sk8 create iris --json # {url, token, mcp_add_command} for agents
sk8 create iris --dry-run # preview the gcloud commands offline
sk8 list # list deployed agents in the region
sk8 delete iris --yes # tear down service + token secret
sk8 suggest 5 # propose adjective-noun names
The GCP services (Cloud Build, Artifact Registry, Secret Manager, IAM, Cloud Run) and the
agent lifecycle โ image build โ token mint โ a run_task call triggering Cloud Run.
Every run โ blocking or detached โ is capped at a 600s timeout. No streaming; detached tasks report progress only as coarse get_task status.
Task records and sessions live on the instance. Without a GCS bucket they vanish when Cloud Run recycles it โ poll regularly to keep it warm, or configure a bucket.
Sessions remember prior exchanges, but a fresh task still starts from nothing โ write the first prompt as a standalone brief.
claude can do anything the host user can.
Treat reaching this endpoint as equivalent to a shell on the box โ secure it accordingly.