Persistent Workspaces for Long-Running AI-Assisted Feature Branches
GuideSeptember 29, 202610 min read

Persistent Workspaces for Long-Running AI-Assisted Feature Branches

The Short Version

A feature branch built over several days with an AI coding assistant in the loop doesn't fit neatly into either of the two environment patterns most teams already have. It isn't a short-lived PR preview, since the branch isn't ready for review yet and might change substantially session to session. It also isn't a shared long-lived staging environment, since it belongs to one developer's specific, in-progress work. What it actually needs is a persistent, single-owner workspace: a real environment that stays up (or can be cheaply stopped and restarted) across many separate working sessions, keeping its data and state intact between them, torn down deliberately once the branch merges rather than recreated fresh every time the developer picks the work back up.

Why Multi-Day AI-Assisted Work Changes the Shape of the Problem

A developer working with an AI coding assistant on a feature branch that spans several days accumulates real, meaningful state in their working environment as the branch progresses: database records created while testing a specific flow, a partially completed data migration, configuration tweaked to reproduce a specific edge case the assistant is helping debug. None of this is disposable in the way a fresh PR environment's throwaway seed data is. Recreating the environment from scratch at the start of each new session, the way an ephemeral PR environment would, means redoing setup work every single time the developer resumes, which adds friction disproportionate to what a short PR-review cycle would ever accumulate.

This is also, deliberately, a narrower and more specific case than "environment for AI agents" generally. The workspace described here supports a human developer's own iterative session, using their own editor and their own AI coding assistant, working against a real environment the same way they would against a local dev setup, just running remotely with proper resources and proper isolation. It is not an unattended agent execution sandbox running autonomous, long-lived AI-driven workflows, which is a different problem with different infrastructure requirements.

Configuring It as a Long-Lived, Single-Owner Environment

The environment itself is a standard type: primary (not ephemeral) definition, tied to the specific feature branch rather than to a PR number, and typically named in a way that makes its owner and purpose obvious to anyone else who might glance at the environment list:

YAML
1kind: Environment
2name: jsmith-checkout-redesign
3type: primary
4
5components:
6  - kind: Database
7    name: postgres
8    dockerCompose:
9      environment:
10        POSTGRES_PASSWORD: SECRET['workspace-db-pass']
11    volumes:
12      - name: db-data
13        size: 10Gi
14        type: disk
15
16  - kind: Application
17    name: api
18    gitBranch: 'jsmith/checkout-redesign'
19    dependsOn: [postgres]
20    hosts:
21      - hostname: 'jsmith-checkout-{{ env.base_domain }}'
22        servicePort: 8080

The type: primary setting matters directly: it signals this environment is meant to persist and be updated in place across many deploys, not recreated fresh each time, which is the same distinction a long-lived staging environment relies on, just scoped to one developer's branch instead of the whole team's shared staging.

Preserving State Across Stop and Start, Not Just While Running

The other half of making this practical, rather than just theoretically possible, is cost: a persistent environment running continuously around the clock for a branch under active development for two weeks, including nights and every hour the developer isn't actually working, adds up to real, largely wasted spend. Stopping the environment outside active working hours, and starting it back up at the beginning of the next session, keeps the cost proportional to actual use while preserving exactly the state that makes this pattern worthwhile in the first place:

Bash
$ bns environments stop --id <WORKSPACE_ENV_ID>   # End of the day
$ bns environments start --id <WORKSPACE_ENV_ID>  # Next morning

See Stop and Start Environments On-Demand for the underlying mechanism, which preserves volumes and their contents across the stop/start cycle, meaning the developer resumes exactly where they left off, database state and all, rather than starting from a clean slate each morning.

Connecting the Local Editor and AI Assistant to the Remote Workspace

The actual day-to-day workflow uses the same remote development configuration available to any component, syncing local file changes into the running remote container so the developer's local editor (and whatever AI coding assistant runs alongside it locally) is working against files that live, and execute, in the real remote environment:

YAML
1dev:
2  api:
3    - containers:
4        api:
5          command: ['npm', 'run', 'dev']
6          syncPaths:
7            - remotePath: /app
8              localPath: ~/projects/checkout-redesign
9          portForwards:
10            - "9229<9229"   # Node debugger port, reachable locally

This keeps the AI assistant's own working context (whatever conversation history or session state the assistant itself maintains) entirely local to the developer's machine, independent of the remote environment's own lifecycle. Stopping and restarting the remote workspace has no bearing on the assistant's own history; the two are separate concerns that happen to both matter for the same overall workflow.

Direct Access for Debugging Mid-Session

For the moments remote-dev file sync isn't the right tool, checking something directly inside the running environment, bns exec or SSH-based access into the workspace works the same way it would for any other environment, since a persistent workspace is still a completely standard environment underneath, just given a longer intended lifetime:

Bash
$ bns exec --component <API_COMPONENT_ID> -- bash

See SSH Into a Running Environment for the fuller set of direct-access patterns this supports, which apply identically here regardless of the environment's expected duration.

Where the Human Still Needs to Look

Multi-day AI-assisted work on a real, persistent environment doesn't reduce the need for a human to actually verify the resulting behavior against something real before the branch is considered done; if anything it makes that check more important, since a session spanning many days and many rounds of AI-assisted changes has more accumulated surface area for a subtle, compounding misunderstanding to slip through unnoticed. See Human-in-the-Loop Testing for AI-Generated Code for why a passing test suite, even one the same assistant helped write, doesn't substitute for that check.

Winding the Workspace Down

The other necessary discipline, easy to let slide precisely because this pattern is convenient, is actually tearing the workspace down once its branch merges or gets abandoned, rather than letting it linger as a forgotten, still-running environment nobody's actively using. Treating it as a specific named environment (rather than an anonymous one indistinguishable from a hundred others) makes it a natural candidate for the same stale-environment audit process that catches other kinds of abandoned infrastructure:

Bash
$ bns environments delete --id <WORKSPACE_ENV_ID> --force

A reasonable habit: tear it down as part of the same pull request that merges the feature branch itself, so the environment's lifecycle is visibly tied to the work it existed to support, rather than left as a loose end for a later cleanup audit to eventually catch.

Managing Several Concurrent Persistent Workspaces on a Team

Once more than one developer on a team adopts this pattern, a small amount of naming and visibility discipline keeps a handful of persistent workspaces from becoming as confusing as a pile of anonymous ephemeral environments would be. A consistent naming convention (<developer>-<short-feature-description>) makes ownership obvious at a glance in the environment list, and tagging each workspace explicitly (owner:jsmith, branch:checkout-redesign) makes it a clean, unambiguous input to the same stale-environment audit process described in Auditing and Cleaning Up Stale Non-Production Environments, rather than an ambiguous case the audit has to guess about.

Bash
1$ bns environments list --project <PROJECT_ID> -o json | \
2    python3 -c "
3import json, sys
4d = json.load(sys.stdin)
5workspaces = [e for e in d if e['type'] == 'primary' and 'owner:' in str(e.get('tags', []))]
6print(f'{len(workspaces)} active persistent workspaces')
7"

A team with several of these running at once benefits from treating them as a distinct, visible category rather than letting them blend into the general environment list, since a workspace's expected multi-week lifetime looks identical, from a bare activity timestamp, to an abandoned environment that should have been cleaned up weeks ago.

When a Persistent Workspace Is the Wrong Tool

This pattern earns its cost specifically for work that genuinely spans multiple sessions with state worth preserving between them. A feature that will realistically be done in a single sitting, or a branch being reviewed and merged within a day, gets no benefit from a persistent workspace over a standard ephemeral PR environment, and defaulting to persistent workspaces for every branch regardless of expected duration just accumulates more long-lived, higher-cost environments than the team's actual working patterns justify. The practical rule: reach for a persistent workspace when a branch is expected to span multiple days with meaningful state to preserve between sessions, and use the standard ephemeral PR flow for everything else, which is the large majority of day-to-day work for most teams.

For the stop/start mechanics that make running this cost-effective across many separate sessions, see Stop and Start Environments On-Demand. For direct debugging access into the running workspace, see SSH Into a Running Environment.

A Realistic Session Timeline

Concretely, a multi-day feature branch supported by a persistent workspace might look like: Monday, the workspace is created, migrations run, and a first working version of the change goes up, with a session ending mid-debug on a specific edge case; Tuesday, the developer starts the stopped workspace, resumes exactly where the previous session left off (the same database state, the same partially-reproduced bug), and works through it with their AI assistant open alongside the same synced local files; Wednesday and Thursday follow the same pattern; Friday, the branch is ready, opens as a PR (which triggers its own separate, standard ephemeral PR environment for review, independent of the workspace), and once that PR merges, the persistent workspace itself is torn down. The workspace and the PR's own preview environment coexist briefly during review, serving different purposes: one is the developer's ongoing working environment, the other is the reviewer-facing snapshot of what's actually being proposed.

Checklist

  • The workspace is a type: primary environment tied to a specific feature branch and owner, not an anonymous ephemeral one
  • Volumes preserve database and file state across stop/start cycles, so sessions genuinely resume rather than restart
  • The environment is stopped outside active working hours to control cost, not left running continuously by default
  • Remote development sync connects the developer's local editor and AI assistant to the real remote environment
  • The workspace is explicitly torn down when its branch merges or is abandoned, not left running indefinitely
✦✦

Give a multi-day AI-assisted branch a workspace that actually persists.

14-day full-feature trial. No credit card required. Pay-as-you-go from $0.007/min per environment.

Frequently Asked Questions

How is this different from an ephemeral PR environment?

An ephemeral PR environment is created fresh per pull request and destroyed on merge or close, usually living hours to a few days. A persistent workspace is created once for a specific long-running feature branch and stays up, with its state intact, across many separate working sessions over days or weeks, until the feature branch itself is done.

Why not just recreate the environment fresh every morning?

Recreating fresh means re-running every migration, re-seeding data, and losing any manually-set-up state (a specific record created mid-debugging, a partially completed data import) from the previous session. For a short-lived PR that's a fair tradeoff for guaranteed cleanliness. For a feature branch under active development over days, it becomes a real daily cost with no corresponding benefit.

Does this environment run any AI agent itself?

No. This is a development environment a human developer works in, using their own editor and their own AI coding assistant locally (or connected via remote development), the same way they'd work against a local dev environment. It is not an autonomous agent sandbox executing unattended; a human is driving the session.

How long should a persistent workspace stay alive?

For the life of the feature branch it supports, typically days to a couple of weeks, and no longer. Once the branch merges or is abandoned, the workspace should be torn down like any other environment, not kept running indefinitely as a matter of habit.

Does stopping the environment overnight lose the AI assistant's context or history?

No, stopping preserves the underlying environment's state (its volumes, its data) the same way it does for any other stopped environment. Whatever context or conversation history the AI coding assistant itself maintains lives in the assistant's own session state, typically on the developer's local machine or the assistant's own service, independent of whether the remote environment is running.