
AI coding assistants are rapidly transitioning to the cloud. Platforms like Cursor Cloud Agents and Claude Code let developers offload programming tasks to AI agents running on remote servers. This eliminates the need for local setup and enables multiple agents to run in parallel, streamlining workflows and scaling development capacity.
For full‑stack development, however, raw compute power isn’t enough. Tasks such as updating database schemas, running migrations, or testing API routes require access to a database environment that mirrors production. Typically, developers configure cloud agents by setting environment variables in dashboards or project settings. The drawback is that these variables are defined at the workspace or environment level, meaning every agent instance inherits the same credentials (for example, a single DATABASE_URL).
When all agents connect to one shared staging database, isolation is lost. This shared setup introduces risk: a buggy migration from one agent could corrupt the database and block all others. If another agent is simultaneously running tests, cascading failures can occur. Because of these limitations, most cloud agents today remain confined to stateless or front‑end tasks. The limitation arises from state management. Cloud agents have access to ephemeral compute, but not ephemeral data.
This guide explains how to address that gap by building a custom Full-Stack Cloud Agent runner. By combining Cloudflare Sandboxes (for compute) with Neon Database Branching (for data), you can create isolated, production‑like environments for each agent task, provisioned safely and on demand.
Each time you issue a prompt, the runner forks a copy‑on‑write branch of your database, launches a secure Cloudflare Sandbox, and runs the agent (Codex, Claude code, GitHub Copilot, etc.) of your choice in this controlled environment. The agent can then perform migrations, implement backend logic, and test its work without risk to staging or production systems. Once complete, you can review and merge its output with confidence.
Prerequisites
Before you begin, ensure you have the following:
- Cloudflare account: A Cloudflare account on a Workers Paid Plan or higher, which is required to use Cloudflare Sandboxes.
- Claude API key: An Anthropic API key to run Claude Code in the sandbox. Create an API key in the Anthropic Developer Console.
- Development environment: Node.js and Docker installed locally.
- Install Node.js from nodejs.org.
- Install Docker from docker.com.
- Neon account and project: A Neon account with at least one active project. Sign up for a free account at console.neon.tech.
Step 1: Initialize the Cloudflare Sandbox project
Cloudflare provides a template for setting up a Worker configured with the Claude Code using Sandbox SDK. Open your terminal and run the following command to create a new project:
npm create cloudflare@latest -- cloudflare-sandbox-neon-branching --template=cloudflare/sandbox-sdk/examples/claude-code cd cloudflare-sandbox-neon-branchingThis creates a standard Cloudflare Workers project. If you examine the
wrangler.jsoncfile, you'll see it is already configured with the Containers and Durable Objects bindings required to use Cloudflare Sandboxes.If you inspect the
Dockerfile, you'll see it includes the necessary setup to run Claude Code within the sandbox environment. Similarly, thesrc/index.tsfile contains boilerplate code to demonstrate how to use the Sandbox SDK to run Claude Code.Learn more about the project structure and configuration in Cloudflare Docs: Run Claude Code on a Sandbox.
Step 2: Generate a Neon API key and get your project id
To allow programmatic access to Neon for branch creation, you need a Neon API key and your Neon project id. The Cloudflare Worker uses these values to call the Neon API and create branches on demand.
- In Neon Console, open your organization settings and select API Keys.
- Click Create new API Key and give it a name (for example, "Cloudflare sandbox").
Choose a project-scoped API key to restrict the agent's access to this specific project.
- Copy the generated API key.
- Open the Neon project you use for your application. The AI agent will create branches in this project to run tasks against for development and testing.
- Go to Settings > General, then copy the Project ID.

Step 3: Generate a GitHub Personal Access Token
To allow the Sandbox to clone repositories, create git branches, commit changes, and open Pull Requests on your behalf, you need a GitHub Personal Access Token.
- Navigate to your GitHub Settings, then go to Developer settings > Personal access tokens > Tokens (classic).
- Click Generate new token (classic).
- Give the token a descriptive name (e.g., "Full-Stack Cloud Agent Runner") and select the
reposcope to allow full control of your repositories.If you are accessing an organization repository, you may also grant the admin:org scope to allow the token to access organization resources.
- Click Generate token and copy it to your clipboard.
Step 4: Set environment variables and install dependencies
Create a
.dev.varsfile in the root of your Cloudflare project to store your API keys and project configuration locally.ANTHROPIC_API_KEY=your_anthropic_key NEON_API_KEY=your_neon_api_key NEON_PROJECT_ID=your_project_id GITHUB_TOKEN=your_github_tokenReplace the placeholder values with your actual Anthropic API key, Neon API key, Neon project ID, and GitHub token.
Generate wrangler types Regenerate the Wrangler types to include the new environment variables:
npx wrangler typesTo interact with the Neon API from the Worker, install the Neon Typescript SDK:
npm install @neondatabase/api-clientStep 5: Update the Dockerfile to install GitHub CLI
The default template Dockerfile does not include the GitHub CLI, which is necessary for the agent to create Pull Requests. Update the Dockerfile to install the GitHub CLI in the sandbox environment.
Replace the contents of
Dockerfilewith:FROM docker.io/cloudflare/sandbox:0.7.17 # Install GitHub CLI RUN mkdir -p -m 755 /etc/apt/keyrings \ && curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \ -o /etc/apt/keyrings/githubcli-archive-keyring.gpg \ && chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \ > /etc/apt/sources.list.d/github-cli.list \ && apt-get update \ && apt-get install -y gh \ && rm -rf /var/lib/apt/lists/* RUN npm install -g @anthropic-ai/claude-code ENV COMMAND_TIMEOUT_MS=300000 EXPOSE 3000Step 6: Implement the cloud agent runner logic
The core of this runner is a Cloudflare Worker that listens for incoming HTTP requests containing a GitHub repository URL and a task description. When it receives an HTTP
POSTrequest, it provisions the ephemeral database (a Neon branch), provisions the compute (a Cloudflare Sandbox), and connects them together.Replace the contents of
src/index.tswith the following code:import { getSandbox } from '@cloudflare/sandbox' import { createApiClient, EndpointType } from '@neondatabase/api-client' const EXTRA_SYSTEM = ` You are a **senior full-stack developer** working in an **isolated development environment**. You will receive a **task** that may require changes to both the **application codebase** and the **database schema**. ### Environment * The environment is a **safe clone of the production codebase and database**. * You may freely modify the code and database without risk to the real production system. * The environment variable **DATABASE_URL** contains the database connection string. ### Capabilities You are allowed to: * Modify the **database schema** * Generate and apply **database migrations** * Update the **codebase** to support schema changes * Run **tests and validations** * Execute commands necessary to complete the task ### Guidelines * Always keep the **assigned task as the primary objective**. * Ensure that **schema changes and code updates remain consistent**. * Maintain **code quality, correctness, and stability**. * Prefer **minimal, targeted changes** over large refactors unless the task requires it. * Verify your work by **running tests or validating behavior** when possible. ### Restrictions * **Do not commit or push changes** to version control. It will be automatically done after you complete the task. * Do not modify unrelated parts of the codebase unless required for the task. ### Goal Complete the assigned task successfully by making the necessary **database and/or code changes**, ensuring the system functions correctly with the updates. ` function escapeShell(str: string) { return str.replaceAll('"', '\\"').replaceAll('`', '\\`') } async function createNeonBranch( projectId: string, branchName: string, env: Env ): Promise<string> { const api = createApiClient({ apiKey: env.NEON_API_KEY! }) const res = await api.createProjectBranch(projectId, { branch: { name: branchName }, endpoints: [{ type: EndpointType.ReadWrite }] }) const uri = res.data.connection_uris?.[0]?.connection_uri if (!uri) throw new Error('No DB connection URI returned') return uri } async function run(sandbox: ReturnType<typeof getSandbox>, cmd: string) { const result = await sandbox.exec(cmd) if (!result.success) throw new Error(result.stderr) return result } async function cloneRepo( sandbox: ReturnType<typeof getSandbox>, repoUrl: string, token: string ) { const url = `https://x-access-token:${token}@${repoUrl.replace('https://', '')}` await run(sandbox, `git clone ${url} /home/app`) } async function createGitBranch( sandbox: ReturnType<typeof getSandbox>, branch: string ) { await run(sandbox, `cd /home/app && git checkout -b ${branch}`) } async function runClaude( sandbox: ReturnType<typeof getSandbox>, task: string ) { const cmd = ` cd /home/app && claude --dangerously-skip-permissions \ --model haiku \ --append-system-prompt "${escapeShell(EXTRA_SYSTEM)}" \ -p "${escapeShell(task)}" ` return run(sandbox, cmd) } async function commitChanges( sandbox: ReturnType<typeof getSandbox>, agentId: string, task: string ) { // Use standard GitHub Actions bot credentials for commit attribution await sandbox.exec(` cd /home/app git config --global user.name "github-actions[bot]" git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" git add . git commit -m "AI agent ${agentId}: ${escapeShell(task)}" || echo "No changes" `) } async function pushBranch( sandbox: ReturnType<typeof getSandbox>, branch: string ) { await run(sandbox, `cd /home/app && git push origin ${branch}`) } async function createPR( sandbox: ReturnType<typeof getSandbox>, agentId: string, task: string, token: string ) { const res = await run( sandbox, ` cd /home/app gh auth login --with-token <<< "${token}" gh pr create --title "AI Agent: ${agentId}" \ --body "Automated PR for task: ${escapeShell(task)}" ` ) const match = res.stdout.match(/https:\/\/github\.com\/\S+\/pull\/\d+/) return match?.[0] } export default { async fetch(request: Request, env: Env): Promise<Response> { if (request.method !== 'POST') { return new Response('Method Not Allowed', { status: 405 }) } try { const { repoUrl, task } = await request.json<{ repoUrl?: string task?: string }>() if (!repoUrl || !task) { return new Response('repoUrl and task required', { status: 400 }) } const agentId = `agent-${Date.now()}` const sandbox = getSandbox(env.Sandbox, crypto.randomUUID().slice(0, 8)) const dbUrl = await createNeonBranch(env.NEON_PROJECT_ID, agentId, env) await cloneRepo(sandbox, repoUrl, env.GITHUB_TOKEN) await createGitBranch(sandbox, agentId) await sandbox.setEnvVars({ ANTHROPIC_API_KEY: env.ANTHROPIC_API_KEY, DATABASE_URL: dbUrl, IS_SANDBOX: "1" }) const agentResult = await runClaude(sandbox, task) await commitChanges(sandbox, agentId, task) await pushBranch(sandbox, agentId) const prUrl = await createPR( sandbox, agentId, task, env.GITHUB_TOKEN ) return Response.json({ success: agentResult.success, agentId, databaseUrl: dbUrl, agentOutput: agentResult.stdout, agentErrors: agentResult.stderr, prUrl }) } catch (err) { console.error(err) return new Response('Request failed', { status: 400 }) } } } export { Sandbox } from '@cloudflare/sandbox'This code implements the full workflow of the cloud agent runner. The main components are:
fetch(request, env): Main controller. It validates input, creates IDs, and runs the full workflow.createNeonBranch(...): Provisions an isolated Neon branch and returns a branch-specificDATABASE_URL.runClaude(...): Executes Claude Code inside the sandbox with your task and guardrail system prompt. In this example,haikuis used as the model, but you can choose any supported model likesonnetoropusdepending on your needs. Change the--modelflag accordingly.IS_SANDBOXenvironment variable: SettingIS_SANDBOXto"1"grants Claude Code permission to execute commands that are normally restricted. Because the sandbox and database branch are entirely isolated, the agent can safely perform destructive actions with full autonomy, posing zero risk to your production environment.createPR(...): Uses GitHub CLI to open a PR and returns the PR URL.
End-to-end flow (HTTP request -> PR):
- Receive a
POSTrequest withrepoUrlandtask. - Create a unique
agentId, sandbox instance, and Neon branch. - Clone the repository and create a git branch named after
agentId. - Inject environment variables (
ANTHROPIC_API_KEY, branchDATABASE_URL) and run Claude. - Commit and push the agent's changes.
- Create a Pull Request and return a JSON response with logs plus the PR link.
Step 7: Deploy the cloud agent runner to Cloudflare
Deploy your Worker to Cloudflare by running the following command in your terminal:
npx wrangler deployWrangler will prompt you to log in to your Cloudflare account. Follow the instructions for authentication.
Set your production secrets so the Worker can securely access the Anthropic, Neon, and GitHub APIs. Run the following commands and input the corresponding values when prompted:
npx wrangler secret put ANTHROPIC_API_KEY npx wrangler secret put NEON_API_KEY npx wrangler secret put NEON_PROJECT_ID npx wrangler secret put GITHUB_TOKENYou now have your own Full-Stack Cloud Agent runner deployed on Cloudflare! You can send
POSTrequests to the Worker URL with a JSON body containing arepoUrland ataskto see it in action.Step 8: Test the full workflow end-to-end
Now that your runner is deployed, test it with a real task and confirm that it creates an isolated database branch, pushes code to a new Git branch, and opens a Pull Request.
- Copy your Worker URL from the Wrangler deploy output (for example,
https://cloudflare-sandbox-neon-branching.<subdomain>.workers.dev). - Send a test request using
curl:
curl -X POST "https://cloudflare-sandbox-neon-branching.<subdomain>.workers.dev" \ -H "Content-Type: application/json" \ -d '{ "repoUrl": "https://github.com/<your-org>/<your-repo>", "task": "Add a /health endpoint and update tests." }'Testing the runner
You can send any repository URL that you have write access to. The agent will clone the repo, create a new branch, and open a PR with the changes.
- Inspect the JSON response. You should see the following fields:
agentId(unique run identifier)databaseUrl(branch-specific Neon connection string)prUrl(URL of the generated Pull Request)
- Open the Pull Request and verify:
- The changes match the requested task.
- CI and tests pass.
- In Neon Console, confirm a new branch was created for that run.
For example, here is an example request and response:

The JSON response provides the newly provisioned Neon branch URL and a direct link to the resulting Pull Request, giving you everything needed to review the agent's changes. The
agentOutputandagentErrorsfields contain the raw logs from the agent's execution, which can be helpful for debugging or auditing its behavior.For local testing during development, you can run the Worker with
npm run devand send requests tohttp://localhost:8787instead of the deployed URL.- Copy your Worker URL from the Wrangler deploy output (for example,
Benefits of this architecture
Building your own AI agent runner pairs ephemeral compute with ephemeral data, solving the state management limitations of standard cloud agents:
- True full-stack autonomy: Agents can safely test schema migrations and backend logic against a real Postgres branch prior to submitting a PR.
- Infinite parallelization: Spin up multiple sandboxes and branches instantly to run concurrent agent tasks without state collisions.
- Zero risk: A destructive agent action only affects its disposable branch, keeping staging and production databases entirely safe.
- Programmatic environment control: Inject runtime configuration (like a dynamic
DATABASE_URL) directly into each sandbox. - No vendor lock-in: Swap out Claude Code for any other CLI-based agent (e.g., Codex, OpenCode, GitHub Copilot CLI) while retaining the same execution architecture.
Extending this workflow
Because the runner is a standard Cloudflare Worker, you can easily extend it to build more robust internal automation:
- Custom triggers: Launch agents asynchronously via Slack commands, MS Teams, or GitHub Issue webhooks.
- Resource cleanup: Automatically delete branches when a PR merges using webhooks, or configure auto-expiring branches.
- Fallback and recovery: If an agent breaks its environment, reset the branch or use Time Travel before instructing the agent to retry.
For more details on programmatic database management, explore the Neon API Reference and the Neon TypeScript SDK.
Conclusion
Standard cloud AI agents are often limited by a lack of ephemeral state. By pairing Cloudflare sandboxes with Neon's instant database branching, you bridge this gap - providing agents with the disposable, production-like environments they need to function as true full-stack developers.
You have successfully built a custom execution layer that empowers AI agents to write, test, and validate complex codebase and schema changes autonomously. With this architecture, you can scale your AI-driven development workflows with confidence and zero risk to production.
Resources
- Neon Database Branching
- Neon for AI Agent Platforms
- Cloudflare Sandbox SDK Documentation
- Anthropic Claude Code
- Neon API Reference
Need help?
Join our Discord Server to ask questions or see what others are doing with Neon. For paid plan support options, see Support.








