cd /news/ai-agents/sch-an-affordable-sandbox-for-coding… · home topics ai-agents article
[ARTICLE · art-128541] src=c-daniele.github.io ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

SCH: An affordable sandbox for Coding Agents in your AWS account

A developer built SCH, a serverless coding harness on AWS AgentCore Runtime that lets coding agents run unattended in isolated cloud containers for a few cents of remote compute per session, excluding model inference costs. SCH addresses two problems the developer identified: keeping a laptop or rented server running for eight-hour agent loops, and the security risk of running long loops with auto-approval flags such as --dangerously-skip-permissions on a machine holding SSH keys and cloud credentials. The harness targets compatibility with at least OpenCode and Claude Code and relies on AWS's pay-as-you-go, session-isolated runtime that shuts down on idle timeout.

read24 min views3 publishedSep 13, 2026

Table of Contents #

Intro # #

One Friday morning, I closed my laptop lid while a coding agent kept working in a lightweight container in the cloud. When I opened it again a few hours later, the branch was ready for review, the runtime was already gone, and the remote compute alone had added only a few cents. That figure does not include model inference, which remains a separate line item.

Getting there forced me to answer two questions:

  1. do I really need to keep my PC, or a remote machine, running for an eight-hour loop?
  2. can I let an agent work unattended without also having to build my own sandboxing system?

This post is my answer: SCH, a serverless coding harness built on AWS AgentCore.

Over the past two years, quite a few labels ending in “engineering” have piled up. Context engineering shifted attention from the individual prompt to the information available for the next step. Geoffrey Huntley’s Ralph Wiggum loop, literally while :; do cat PROMPT.md | claude-code; done, showed how much a bash loop can achieve with a fresh context at each iteration and state stored on disk. Loop, graph, and harness engineering followed. The labels change quickly; I mainly needed three concepts to build SCH:

  • State. Where the work lives after the context window is gone: files, planning documents, git history, and checkpoints. Every loop technique must externalize enough state for the next iteration to pick up where the previous one left off.
  • Harness. Everything around the model call: tools, hooks, permissions, checks, and the outer loop that decides whether “done” really means done. As a rough approximation, “agent” = “model” + “harness”.
  • Runtime. The machine that runs the harness: filesystem, network, credentials, and lifetime. Very often, it is the developer’s laptop, with all the limitations that entails.

Newer models, combined with the work on these three elements, have also changed the unit of work. A task can run unattended for hours and, across multiple sessions and checkpoints, even for days. This creates two practical problems.

  1. Someone has to keep the machine running. An eight-hour loop means eight hours with the laptop on, or a remote server that I have to rent, update, and remember to shut down.
  2. Long loops encourage YOLO mode. Unattended work stops as soon as the harness asks for permission. With permission gates enabled, it is easy to come back and find the agent stalled after twelve minutes, waiting for an “okay, proceed.” Many people end up using options such as--dangerously-skip-permissions ,--auto , or--yolo .

A long session has more opportunities to take an unexpected turn. If it runs with auto-approval on a laptop, the same machine keeping the loop alive often holds SSH keys, cloud credentials, and personal data. The problem grows as soon as you go from one session to three across different branches and tasks: the laptop becomes a host shared by several agents with plenty of room to act.

Isolation reduces the blast radius of an error, but it only works if network access and permissions are tuned to the job. A sandbox that is too restrictive stops the agent at the first denied command; one that is too permissive merely moves the problem elsewhere.

Over the past few weeks, I looked for a setup that would let me isolate the runtime, run asynchronous, detached tasks, and work with at least OpenCode and Claude Code. I also wanted to avoid servers to administer and sandbox rules to maintain by hand.

Because I work extensively with AWS, I had already used Amazon Bedrock AgentCore Runtime. The closest analogy is a Lambda designed to host AI agents: a serverless runtime with pay-as-you-go pricing and isolated sessions. When the idle timeout kicks in, the runtime disappears and compute returns to zero. Later, I show the figures I collected over roughly ten days of intermittent use.

That is how SCH - Serverless Coding Harness came about. It is now public at c-daniele/sch. When I need it, AgentCore starts a remote harness that I can reach from the terminal. The runtime does the work and then terminates; SCH saves its state and brings the changes back to the local working copy or to a separate branch.

The architectural principle is that durability belongs in the checkpoints, not the runtime. If the repository, agent sessions, and git history can be restored, there is no reason to keep the microVM running. SCH is still a proof of concept, retains some early design decisions, and currently runs only on AWS. I discuss its limitations later.

Compared with Claude Code on the web, Codex cloud, or Copilot’s coding agent, SCH requires more setup. In return, repositories, sessions, checkpoints, and inference stay in my AWS account, under IAM policies I define, without locking me into a single harness or provider.

What changes in my workflow # #

SCH combines a local CLI with an ARM image that runs OpenCode, Claude Code, or Pi inside an AgentCore microVM. Workspace state is stored in S3, changes come back through Git, and the runtime is removed when it is no longer needed.

Feature What it lets me do
Session handoff Start work locally and continue in the cloud without rebuilding the context
Detached tasks Turn off the laptop without interrupting execution
State and checkpoints outside the runtime Check on a task and resume it even after the microVM has been deleted
Supervision from Telegram Receive updates, approve a tool, or send a follow-up away from the terminal
One workspace per branch Run several tasks in parallel without sharing writable state
Centralized image and policies Use a repeatable environment with harnesses, tools, models, and permissions defined in advance

Three SCH use cases: handoff, workbench, and batch # #

The following commands assume that SCH has already been deployed. The README quickstart covers the prerequisites and initial deployment.

1. Brainstorm locally, hand off, supervise from your phone #

This is the mode I use most often for non-trivial work. I brainstorm with OpenCode on my laptop until the objectives, files to change, tests, and definition of done are clear. Once the context is ready and the local state is suitable for launching the task, I send the entire conversation to a remote workspace and let the agent continue there:

sch task my-project --handoff --branch change/plan-a \
  "implement what we agreed, run the tests, fix what breaks"
#> a1b2c3...          # returns immediately; laptop can go offline

sch status my-project
#> state        : succeeded
#> continuation : resumed prior session
#> checkpoint   : confirmed

sch fetch my-project

From this point on, the laptop is optional. Each workspace has a topic in a Telegram group and a [workspace] prefix on its messages. I receive milestones, to-do list updates, a digest of tool activity, a warning if the heartbeat stops responding, and finally the task outcome with the checkpoint status.

Headless tasks run with auto-approval by design. Interactive sessions, however, also have an intermediate detached mode: after starting a session, I leave it running with Ctrl+], and when the agent asks for permission, I receive Approve/Deny buttons on my phone. The response goes back to the harness hook. If I do not respond within ten minutes (SCH_APPROVAL_TIMEOUT_S), SCH falls back to the policy configured in the harness. Free text entered in the topic becomes a follow-up prompt through task --continue. I can type “now update the README too” from my phone and let the harness continue.

2. An isolated AWS workbench #

Another use case is an isolated workbench for developers who work mainly with AWS services. By attaching an appropriate policy to the AgentCore Runtime IAM role, the remote harness can read a CloudWatch log group, check an IAM policy, prototype a Lambda, or access a DynamoDB table without inheriting the workstation’s credentials.

sch run aws-lab       # fresh remote workspace, straight into the OpenCode TUI
sch web aws-lab       # same backend, in a browser tab
sch acp aws-lab       # same backend, from Zed over ACP

The image contains the AWS CLI, the AWS MCP Server, the AWS Documentation MCP Server, and the standard development tools. Bedrock inference uses the same execution role. The default role combines ReadOnlyAccess with permission to invoke Bedrock: convenient for a POC, but too broad for production data, and it should be narrowed for each workspace. Once the session ends, the microVM is destroyed.

3. A backlog of tasks across multiple harnesses and providers #

For the third workflow, I start with a backlog of tasks that already have specifications, tests, and completion criteria. I can run them unattended, each on its own branch and even with different coding agents:

sch task svc-a --branch change/a --harness opencode "implement change A per docs/specs/a.md"
sch task svc-b --branch change/b --harness claude   "implement change B per docs/specs/b.md"
sch task svc-c --branch change/c --harness pi --model <bedrock-model-id> "port module C as planned"

sch dashboard         # every workspace on one screen: task state, heartbeat age, checkpoint
sch fetch svc-a && sch fetch svc-b && sch fetch svc-c

The harness is bound to the workspace when it is created. The default provider is Bedrock through the execution role, but I can configure others without putting keys in the image or the checkpoints. Each parallel session lives on its own branch, and sch fetch accepts fast-forwards only. Any conflicts surface during the local git merge.

Run vs Task #

Interactive and headless commands provide different guarantees.

Mode Purpose Guarantee
run /shell /web /attach /acp Interactive, human-in-the-loop Best-effort checkpoints (~60 s). Disconnecting does not guarantee durable completion of the turn.
task Reliable autonomous work Heartbeat, terminal outcome, enforced timeout, forced checkpoint. checkpoint: confirmed means files and history are durable.
status /dashboard Observe one workspace / all of them Offline-first reads from S3. They do not wake a microVM unless explicitly requested with --live or from the dashboard.

I usually use the interactive commands for brainstorming and exploring possible solutions. Once I have defined a sufficiently complex task or set of tasks, I leave the interactive session and switch to task, so I can focus on something else and, if needed, shut down the laptop. The full command map is in the README.

Why AgentCore fits this workflow # #

SCH relies on four properties of AgentCore Runtime.

Isolation per session. AgentCore runs each session in a dedicated Firecracker microVM with its own kernel, CPU, memory, and filesystem. When the session ends, the microVM is destroyed and its memory is sanitized. This gives a coding harness a disposable machine that starts from a known image and shares no state with other sessions.

Permissions through IAM. Inside the VM, the CLI, SDKs, and MCP servers receive temporary credentials for the runtime’s execution role. I can grant permission to invoke Bedrock, read selected AWS APIs, and write to a specific S3 prefix without copying keys from the laptop. A microVM does not make an oversized role safe: the effective security boundary also depends on IAM policies and network configuration.

Managed lifecycle. AgentCore terminates idle sessions. The default idleRuntimeSessionTimeout is 15 minutes and can be reduced to 60 seconds; maxLifetime caps sessions at eight hours. A busy session returns HealthyBusy to the health check, preventing the timer from interrupting an agent while it works. The eight-hour limit forces SCH to support checkpoints and restarts.

Resources and startup suitable for a harness. Each session has 2 vCPUs and 8 GB of memory; the image must be linux/arm64 and cannot exceed 2 GB. That is enough for the coding harnesses and test suites I use regularly, while a very heavy build calls for a different runtime. In my measurements, a cold workspace is ready within a few seconds, including restoring from S3 and bootstrapping the harness.

CPU is billed only while it is working, while memory continues to incur charges for as long as the session is alive. This model suits a process that spends much of its time waiting for the LLM, although the wait is not entirely free. The actual figures are in the cost section.

How SCH separates runtime and state # #

The architecture is divided into three layers:

  • Operator. Thesch CLI runs on macOS, Linux, and Windows and delegates AWS calls to theaws CLI, retaining compatibility with the AWS profiles and authentication systems already configured on the workstation, including SSO and external credential providers.
  • Runtime. Each workspace runs one harness in alinux/arm64 microVM. A Python shim handles headless tasks, readiness, and checkpoints; the versioned image contains OpenCode, Claude Code, Pi, and the development tools.
  • Durability. SCH uses two distinct layers.L1 , AgentCore session storage, makes stopping and resuming fast, but resets when the runtime version changes and expires after 14 days of inactivity.L2 uses a versioned S3 bucket and survives even if the runtime is deleted. If L1 is empty, the shim downloads and validates the L2 checkpoint before declaring the workspace ready. An unreadable manifest blocks the restore, preventing SCH from initializing an empty workspace over existing data.

The lifecycle of a session is: sch shell → SigV4 invocation → microVM startup → L2 restore → harness bootstrap → work → checkpoint from L1 to L2 on stop or idle. The next command can restart from L2 in a new microVM.

Models and providers #

Every harness in the image is preconfigured for Amazon Bedrock through the execution role, so the default use case requires no external provider keys.

To use other providers, SCH forwards only an explicit list of variables defined in ~/.sch/env to the runtime. The shim stores them in a temporary area excluded from checkpoints: the keys reach the harness but never end up in the image or S3. The same mechanism can forward GITHUB_TOKEN when the workspace needs to interact directly with GitHub.

Why OpenCode is the default #

The three harnesses share the same basic state management, but SCH was built around OpenCode, and some features reflect its architecture. The same backend can be reached from a local TUI with sch attach, from a browser with sch web, or from an editor over ACP with sch acp. Claude Code works with run, task, and ACP through an adapter. Pi is best suited to headless tasks and currently does not support remote approvals, alternative interfaces, or handoff in SCH.

How headless tasks work #

Submission returns a task_id in less than a second, and the client closes the connection. The shim starts the harness in headless mode and tells AgentCore that the session is busy, so the idle timer does not interrupt it while it works. The seven-hour application timeout stays below the AgentCore limit and leaves the shim enough time to record the outcome and complete the checkpoint. The --model option changes the model for a single invocation, and the choice is recorded in the status.

Moving code: sync for exploration, git for delegation #

I use file synchronization for interactive sessions; for autonomous tasks, git-native mode is preferable.

  • --sync . synchronizes files between local and remote, excluding.git by default. I use this mode while brainstorming with the agent.
  • --branch <name> initializes the workspace from the localHEAD and creates a remote branch. When the work is done,sch fetch imports the changes back only as a fast-forward. This lets parallel sessions work on independent branches, while any conflicts surface during the localgit merge , where they remain under my control.

The workstation’s git credentials are not copied in either mode. Bundles travel over the tunnel’s file channel, and the remote agent does not push unless direct GitHub access is explicitly enabled with GITHUB_TOKEN. I had not originally planned to allow any direct access to GitHub. That prevented interaction with GitHub Actions and other remote pipelines, so I made access opt-in: anyone who needs it can explicitly provide GITHUB_TOKEN; otherwise, the runtime continues to work only with Git bundles.

What roughly ten days of intermittent use cost # #

I had started testing SCH in early August, but until August 28 my use had been too sporadic to represent my usual workflow. I therefore narrowed the analysis to the period from August 29 to September 9, 2026: twelve calendar days, with actual activity on nine of them.

AgentCore does not publish an equivalent of “minutes used,” so I reconstructed consumption from CloudWatch in the AWS/Bedrock-AgentCore namespace in eu-west-1. I used ActiveSessionCount for wall-clock minutes and CPUUsed-vCPUHours and MemoryUsed-GBHours for the billable quantities. The data comes from daily GetMetricData queries and was extracted on September 12, so every included day is complete.

The prices used in the calculation are $0.0895 per vCPU-hour, applied only to CPU actually used, and $0.00945 per GB-hour of memory. Memory is billed every second based on the session’s peak memory usage up to that point, with a minimum billable amount of 128 MB. If the process reaches 7 GB and then releases memory, the billable value remains 7 GB until the session terminates.

Quantity (Aug 29 - Sep 9, 12 calendar days, single dev) Value
Sessions 86
Minutes with ≥1 active microVM 1,856 (30.9 h)
Session-minutes (overlaps counted) 2,251 (37.5 session-hours)
Peak concurrent sessions 4
Average session length ~26 min
Active CPU 8.57 vCPU-h (an average of 0.23 vCPUs per running session; 0.39 on the most CPU-intensive day)
Memory 284 GB-h (average footprint ~7.6 GB)
Line item Amount
CPU (8.57 × $0.0895) $0.77
Memory (284 × $0.00945) $2.68
Total for the period $3.45
Per session-hour ~$0.092
Per session ~$0.040
Busiest day (Sep 6: 22 sessions, 7.7 h with at least one microVM active, 9.6 session-hours) $0.92

These figures made me reconsider SCH’s optimization priorities:

  1. Memory is ~78% of the cost, CPU ~22%. A coding agent spends most of its time waiting for the model. The wait is free on the CPU side, but memory is billed for every second the session is alive.
  2. Idle time is the main lever. SCH stops a session after 15 minutes of inactivity, configurable from 60 seconds to 8 hours. With roughly 7.5 GB of memory, the 15-minute tail costs about $0.018 for each session terminated by timeout;sch stop avoids it. Reducing the idle timeout and the memory footprint therefore makes more sense than optimizing CPU use.

I compared these figures with a t4g.large, the closest EC2 size with 2 vCPUs and 8 GB. In eu-west-1, it costs about $0.074/h, to which I added roughly $8.8 per month for 100 GB of gp3 storage. Over the same period, the comparison is:

Scenario over the same 12 days (37.5 session-hours) Cost
AgentCore, compute at zero between sessions $3.45
EC2 always on (288 h + prorated storage) ~$25
EC2 diligently stopped (37.5 h + prorated storage) ~$6.3

For each hour actually used, AgentCore costs about 24% more, $0.092 compared with $0.074. With my intermittent usage pattern, however, having no compute between sessions makes it about seven times cheaper than an always-on VM. Projecting the same rates over a month, the break-even point against an always-on t4g.large is around 680-700 session-hours per month. Even compared with a VM that is carefully stopped, the fixed EBS cost keeps AgentCore ahead below roughly 490 session-hours per month. The calculation excludes time spent patching and the inevitable occasions when someone forgets to shut the VM down. A developer or small team using agents for a few hours a day remains well below these thresholds.

These figures, reconstructed from CloudWatch metrics, are consistent with the aggregate Cost Explorer view. In my usage, the ancillary S3, logging, and Lambda costs were negligible. Inference is excluded and often dominates the total spend, so the overall cost depends mainly on the provider and model selected, not just the runtime.

This is not an exhaustive benchmark: the window is short, usage is intermittent, and it covers a single developer. A larger team would scale mainly with the number of session-hours. AgentCore managed session storage is also in public preview, and AWS has announced that its price will change before GA. It does not currently appear as a cost line item and is not included in the $3.45.

Why I chose AgentCore over the alternatives #

EC2 is not the only alternative. Fargate, AgentCore Instances, and hosted agents solve different parts of the same problem.

ECS Fargate. Fargate also scales to zero, and for this workload its price is in the same range: applying the eu-west-1 ARM rates to my 37.5 session-hours, the estimated cost would be about $2.3 with 1 vCPU and $3.5 with 2 vCPUs, compared with $3.45 for AgentCore. Price was therefore not the deciding factor for SCH. With Fargate, I would have to build per-session addressing, an idle timeout, a busy signal, workspace storage, and authenticated invocation. AgentCore already provides these primitives and, thanks to pre-initialized microVMs, restored a workspace within a few seconds in my tests. I did not run a side-by-side benchmark: this comparison combines service documentation with an AgentCore measurement.

AgentCore Instances. The service also provides agents on AWS-managed EC2 instances in your account. You pay for the instance, a management fee, and EBS storage even while the machine is stopped; in return, sessions can last up to 14 days. This option is better suited to workloads that exceed eight hours or keep a large amount of local state. For SCH, I prefer the eight-hour limit because it enforces frequent checkpoints.

Hosted agents. Claude Code on the web, Codex cloud, and Copilot’s coding agent already let you close the laptop and require less setup. SCH addresses a different requirement for me: keeping repositories, sessions, checkpoints, and inference in my AWS account, under IAM policies I define, while choosing the harness and provider. SCH currently uses a network with public egress. AgentCore also supports VPCs, security groups, private endpoints, and ingress through PrivateLink, but I have not yet validated this configuration with SCH.

Who may find it useful today # #

  • Developers working on AWS who want to use Bedrock through an execution role, retain theaws CLI credential chain, and restrict which models and APIs the deployment can access.
  • People running long, intermittent tasks who prefer checkpoints and branches to a server running 24/7.Ctrl+] ,sch status , one session per branch, andsch fetch cover this workflow.
  • Development teams with standardization requirements that want to avoid a different configuration for every developer. A shared image can include approved harnesses, models, MCP servers, skills, and plugins.

The team use case still needs validation; this is not a recommendation for enterprise adoption. SCH centralizes the agent environment, but it does not determine whether the agent’s actions are correct. An oversized execution role remains dangerous even inside a microVM. Telegram is also a practical adapter for my personal workflow, not the control plane I would propose as a company standard.

Limitations # #

  • Proof-of-concept constraints. SCH assumes a single-account trust model, and the default role is broad. Some AgentCore APIs are still in preview; session storage has its own limits, each runtime accepts at most 10 concurrent interactive shells, and the WebSocket channel imposes frame and rate quotas. These constraints are documented in the repository as security notes or specification invariants.
  • Excluded costs. ECR, buckets, and registries can incur costs between sessions. Inference, excluded from the $3.45, is often the largest line item. Session storage is free only during the preview. A runtime version change or expiry after 14 days recreates the microVM; L2 restores the checkpoint, but the final unsaved seconds are lost.
  • Differences between harnesses. In SCH, Pi does not have the approval channel, theweb ,attach ,acp , andhandoff modes, or MCP integration. Claude’s JSONL transcripts grow cumulatively, so the seven-hour timeout also caps transcript growth. OpenCode remains the harness with the most complete support.
  • AWS dependency. SCH uses AWS services and APIs directly through theaws CLI. The project explicitly states that multi-cloud abstraction is not a goal. The architectural pattern can be ported elsewhere, but the current implementation creates AWS lock-in.
  • One maintainer. The project currently depends on one person, so its continuity and maintenance cadence are not those of a supported product. Specifications and end-to-end checks in the repository reduce the risk but do not eliminate it.

What comes next: a slimmer image, guardrails, VPC, and identity # #

The next steps, in approximate priority order, are:

  • A trial with a larger team. I want to validate the registry, workspace separation by owner, and real SSO to understand whether a shared image works with several developers.
  • A slimmer image. Memory accounts for roughly 80% of the cost, so reducing the memory footprint is the first cost optimization.
  • Cost guardrails per workspace. Today I use task timeouts, model allow-lists, andsch stop ; budgets and alarms per workspace are still missing.
  • A private deployment. I need to validate VPC network mode and PrivateLink for the invocation path.
  • Identity passthrough. Today, every session acts under a single execution role. I would like sessions to assume the identity of the developer invoking them and retain that developer’s permissions. AgentCore Identity and STS session tags are possible parts of a solution that I have not yet designed.

The pattern itself is not exclusive to AWS: one sandbox per session, checkpoints in object storage, and cloud identity as the permission boundary. Porting it to another cloud would require rewriting the shim and infrastructure, however, and that is not a goal of the current roadmap.

The complete source code, specifications, architecture diagram, and verification scripts are available at c-daniele/sch.

To try it, I would start with sch run aws-lab, which creates a disposable workbench, and then use sch task --branch on a branch you can throw away. The most useful issue reports include the output of sch status, especially for races during restore and approval timeouts.

References # #

── more in #ai-agents 4 stories · sorted by recency
── more on @sch 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/sch-an-affordable-sa…] indexed:0 read:24min 2026-09-13 ·