Skip to content
← All posts
EngineeringAugust 20, 2026

paper clearings: How We Develop a Hosted Platform with Disposable Local Clouds

Companion to Paper Forest.

During my time at Paper Compute we’ve expanded from offering tapes and stereOS to launching paper console, which hosts our agent telemetry offering in the cloud, turning tapes into a multiplayer experience. We recently rolled out a revised tapes open core with support for cassettes to extend the tapes experience. This significantly expanded the scope of our development environment. It’s become more important to have a local development environment that allows us to orchestrate all of our cloud services, our open source offerings, and test those changes before shipping them to staging and eventually to production.

We’re a small team and work on many projects at once. The approach in recent years to do multiple changes in parallel is to use things like git worktrees, branch checkouts, and monorepo tooling. But as our cloud offering grows, we found that we also needed to support parallel “platform instances” running locally for testing, verification, and validating that changes work across open core and platform.

In a previous post we described Paper Forest: a manifest, a CLI called forester, and groves — isolated working directories where all of our repositories appear as one navigable tree. Groves solved a real problem, but a specific one. A grove answers where does the code live. It provides a source tree, not a running system.

This post describes how we reworked our development environments around a clearing: a disposable, fully isolated paper console per grove, so multiple instances of our cloud platform run side by side on one laptop.

The Architecture: How a Request Travels from Agent to Capture

Let’s start with a brief overview of Paper Compute’s architecture. paper console is built around our open source project tapes, but we needed to make some changes in order to host tapes in the cloud and add support for multiple tenants.

Users create an account on console.papercompute.com and install paperctl. Both paperctl and tapesctl are able to talk to a tapes server, and share much of the same code in tapes-crates, but paperctl introduces identity and authorization to our cloud platform. Behind it sits paperd, a daemon on your machine. When you start an agent with paperctl start claude, your agents talk to a provider and that traffic flows through paperd first. From there it travels to a hosted gateway: Envoy, with an AI-aware routing layer in front of the model providers and an external processor watching the stream as it passes. That processor is tapes-extproc, and what it observes lands in tapes — the same capture engine you may already run locally — now ingesting behind the gateway, backed by Postgres. A control plane manages tenants, gateways, and the console you use to browse captured sessions.

The path a single request takes is the diagram for everything that follows:

[ Host Agent ]


 [ Host paperd ]


  [ Gateway ] ──────► [ AI Provider ]
      │ (Mirror Stream)

  [ extproc ]


   [ tapes ] ──────► [ Postgres ]

Suppose you want to change how tapes-extproc parses a provider’s streaming format and you want to make sure that it works for both open core and our platform. The code change takes thirty seconds but extproc no longer runs on your laptop — it runs behind a hosted gateway, with real authentication in front of it and a Kubernetes operator managing its lifecycle. There are subtle differences between how we run the tapes stack in open core vs in our platform that need to be tested simultaneously when a change affects both.

The Challenge: A Shared Staging Environment Isn’t Enough

The conventional answer is a staging environment, and we have one. It works, but it is a shared state: real DNS, real identity-provider configuration, real cloud resources, and everyone else’s experiments. It’s shared by our team and deploying to it, while easy, takes up valuable feedback cycles. We also try to reserve staging for more trivial frontend changes.

You could edit tapes-client and extproc in a grove immediately, then need to build new tapesctl and paperctl and deploy extproc to staging to find out whether the change achieved its desired outcome across the whole system.

Another wrinkle for us is that we’re in the business of agent telemetry, which means that running real agent traffic through our system is the highest confidence way to validate a change. We’ve set up a series of fixtures to help us keep parity between our open core and platform stack, but sometimes there is no substitute for running paperctl start claude against your in-flight changes. Fixtures only go so far when harnesses are shipping updates frequently and customers show us new ways that they’re using harnesses to get their work done. If agent traffic is our value proposition then we needed a way to route agent traffic easily through a local instance of the platform to test changes.

The Approach: A Disposable paper console Scoped to Each Grove

All this led us to build the concept of a clearing, named after the open space in a forest where you can see what is happening.

A grove is the source tree boundary.
A clearing is the runtime boundary.

A clearing is a disposable paper console in miniature, scoped to a single grove: its own Kubernetes cluster, its own kubeconfig, its own ports, its own paper configuration. Two groves could each have a clearing and both are completely isolated from each other.

Cluster and Environment Isolation

You create a fresh grove with forester grove create, and the grove’s environment puts a clearing command on your path — no extra setup, no separate checkout. The grove’s environment evaluates clearing env, which computes the runtime profile on demand: which ports the clearing owns, where its kubeconfig lives, where its isolated paper home goes. Nothing is persisted; the profile is derived from the grove itself. Then one command stands up the platform:

clearing ensure

This boots a local Kind-backed Kubernetes cluster, deploys the platform into it — the operator, tapes, extproc, and the Envoy gateways — then logs in, starts the port-forwards, and runs a smoke check end to end. Everything is namespaced to the grove. Host ports are offset by a hash of the clearing’s ID, so two clearings on one laptop do not contend for port bindings.

Staging-Backed Authentication

A clearing does not fake authentication, and it does not touch production authentication. The local platform validates real paper credentials against our identity provider’s staging environment, then maps a real organization onto a tenant that exists only inside the clearing. Real tokens and a real login flow, with a local blast radius. The entire setup is headless except for when the agent brings the login URL to you to authenticate.

Capturing Real Agent Traffic Locally

With the clearing up, you can direct an actual agent session through the grove’s local platform using clearing paperctl.

That routing is selective — a clearing is an additional destination, not a machine-wide replacement for paperctl. Other agents on the same machine keep talking to production:

paperctl          -> host paperd     -> production gateway -> production tapes
clearing paperctl -> clearing paperd -> clearing gateway   -> local tapes

This yields two development modes, chosen explicitly per agent rather than imposed on the workstation. For the tightest possible feedback loop, point the agent helping build paper console at its own clearing: its development traffic becomes the traffic exercising the platform. For a more controlled test, leave your development agent on production and send dedicated test agent traffic through the clearing. The development traffic and the test traffic can be the same traffic, but they do not have to be.

clearing verify claude-db confirms a clearing is healthy by ensuring a session landed in a Postgres you can drop without consequence. clearing console dev runs the real console against your local tapes API, rendering the sessions you just captured.

Operational Commands

We built a bunch of other commands to help ourselves and our agents use clearings effectively. clearing doctor preflights your workstation’s tools, paths, kube isolation, and routing health and reports what is missing. clearing status --json identifies the clearing, its current state, and where agent traffic is routed, in a form a script — or an agent — can interrogate. clearing image rebuilds components from your local checkouts and deploys them into the local cluster, so a runtime change can be tested without leaving the grove.

Design Trade-offs: Guarded Isolation, Proven-then-Ported Orchestration, and Prod-like Wherever Possible

We made a few design choices I want to talk about:

Explicit isolation on purpose. The paperctl a grove runs is a verified copy-shim, and clearing paperctl build is the only thing that installs it. We use direnv and Nix to keep clearing copies of our clients isolated and available only when working in the grove, and expose it only with clearing paperctl. Likewise, clearing kubectl overrides the clearing’s kubeconfig and refuses to run against any context that isn’t its own local cluster, even when invoked from a child repository directory.

We started in Bash before rewriting clearing in Go. The clearing command started life as experimental Bash orchestration because that was easiest to iterate on. We got to a point where it was a core part of our workflow, and once we were happy with how clearings worked, we were able to use a running clearing as input to an agent to rewrite it from scratch in Go and install it like the rest of our tooling. This meant that we could build a much cleaner Go implementation off a spec and do a lot of the messy iteration in Bash.

Production-like, wherever possible. We wanted our environments to be as close to production as possible. Some of those components (like our tenant-api that integrates with WorkOS) were harder to set up locally, so we did those after proving the concept. Before migrating to Go we beefed up our cloud repository, which uses Flux and Kustomize, so that it had a dedicated clearing overlay that tracked production. The result is that we can iterate on changes across the entire platform stack and be very confident that it will work in production.

The Result: Agents Work in Clearings by Default

We spent a lot of time iterating on the docs, the CLI surface, and our agent context so that we can start a session in a new grove, tell an agent to spin up a clearing, and it will return with a working, smoke-tested environment. A common workflow for me is to start a new task by directing an agent to spin up a clearing, and then we discuss the problem while the clearing is building. Once we’ve come up with an implementation I can direct the agent to test the changes in the clearing by starting codex/claude/pi sessions and inspecting the collected telemetry. It can spin up the console and click around to validate its changes.

It was especially helpful during our recent tapes open-core and cassettes refactoring to come up with a test matrix so that it could make a change to a shared component like tapes-harnesses, build a clearing tapesctl and paperctl, and run sessions to validate parity. Then of course if I want to test things myself I can easily send non-trivial agent traffic or inspect the cluster or database. I’ve been able to make sweeping changes with confidence because I and my agents can test them thoroughly locally.

The forest made our code navigable for agents. Groves made isolated multi-repo worktrees for our agents. The clearing makes our platform operable and testable by them. The feedback loop that required a shared staging environment now runs end-to-end on one laptop, against real traffic.

Looking Ahead: Humans out of the Loop?

stereOS is our open-source agent sandbox: a minimal NixOS-based VM image with a small daemon for configuration, secret injection, and shared mounts, built so agents run with real isolation instead of polite suggestions. So far we have described it as a place to run agents. The clearing work lets us make it mean more for ourselves: a place where agents build paper.

We’ve done a lot of experiments internally around running stereOS on micro-VMs or in containers for agent isolation. We envision an end state for ourselves where:

agent runs inside stereOS
agent edits platform code in the mounted grove
agent deploys into its own clearing
agent runs smoke checks
agent reports a patch with evidence

Since we love our Paper Forest concept, we’re calling this agent a Gardener. As we’re seeing more and more companies roll out agents as a service / managed agents, we’ve had a lot of fun seeing how we can build our own with deterministic tools, clearings and groves as isolated environments, and stereOS as our sandboxing layer. Stay tuned for another post as we get closer to that workflow.

Found this useful? Share it.
ShareY

Start with paper

Turn every session into knowledge at team scale.

Get started