Skip to content

Add standalone, reusable Environments - #932

Merged
SaladDay merged 27 commits into
mainfrom
feat/standalone-environments
Nov 6, 2026
Merged

SaladDay merged 27 commits into
mainfrom
feat/standalone-environments

Conversation

@SaladDay

@SaladDay SaladDay commented Nov 5, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Standalone, reusable Environments in the public Agents API. One Session attaches at a time, in sequence.

  • Create POST /agents/environments:
    • Idempotency-Key takes 1–256 bytes; an empty key returns 400. A retry with the same key and body returns the same Environment, even after its named Template was deleted. A different body returns 409.
    • A non-empty vault_ids returns 400.
    • The Environment steps are shared with inline Session creation, so there is one preparation path.
  • List GET /agents/environments returns the Project's standalone Environments with the official pagination.
  • Retrieve: a prepared Environment with no attached Session reads ready.
  • Attach is POST /agents/sessions with environment.environment_id:
    • The official not constraint applies, and so does the x_agents_core.environment rejection.
    • Status codes: 404 for a missing, foreign or reclaimed Environment; 409 when it is attached, failed or expired; attaching to a pending Environment is allowed.
    • If the Environment cannot reach the Session's model provider, the request returns 400 model_provider_unreachable (a recorded gap).
    • Two concurrent attaches produce exactly one winner.
  • Detach: deleting the Session detaches it. The standalone Environment keeps its compute, workspace and preparation.
  • Files on an unattached Environment return 409.
  • Lifecycle model, one rule for every path:
    • one definition of ended and active, the environment_liveness view, read by every query that reclaims or admits;
    • one cleanup path: compute through the lifecycle reconcile on Allocation.Ended, placements through one sweep before reservation, workspaces through the deletion sweep;
    • one end rule: an unattached standalone Environment ends when it fails, a reset expires it, or its compute is released while no Session is attached.
  • Idle timeout: idle_seconds is one top-level /core/v1 deployment setting for every Provider. With checkpoints an unattached Environment suspends after it and expires at the end of retention; without checkpoints it expires after it.
  • Sealed preparation input is bound to the Environment.
  • Automations: a target projects the stored environment_id.

Docs are in EN and zh: environments.md (new section "Standalone Environments"), index.md ledger, wire-semantics.md, environment-files.md, sandbox-deployment.md and public-agent-api.md, which gains a prewarm example.

Checks

  • go vet ./..., scripts/check-sqlc.py, make openapi (no diff), pnpm --dir website check-translations and pnpm --dir website test pass.
  • Tests pass with a database for api, sessions, deployment, deploymentpg, sessionpg, execution and tests/integration, including the official-SDK scenario (official_environments.py), concurrent attaches and creates, and the reset of an unattached Environment. The lifecycle tests fail when their rule is removed.
  • Blind review: the final round, against the lifecycle model, found no lifecycle defect; its smaller findings are fixed.

Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.

A pending reset lists hosted Environments with no attached Session after the
Sessions page and expires them through the cleanup path, so the reset
completes. Document the unattached lifetime with and without checkpoints, and
drop the ledger lines for the key limit, Template retry and reset gap.
Re-read the attachment after the Environment lock, start the idle clock at
detach, release failed unattached compute, reject unknown members beside
environment_id, scope creation keys to the Project and creator (migration
000015), admit attach against the deployment state, list reset Environments
with a cursor, fail retained-history mismatches fast, keep a standalone
placement on Session deletion, validate Automation targets for existence only,
and share one public-address classifier.
@blacksmith-sh

This comment has been minimized.

…label and name the idle setter after its field
…lock at readiness and list reset candidates in one order
…creation only for the lease owner, scope the list cursor to its creator and check the attach exclusions against the pin
…he cleanup request

Replace about twenty per-path predicates with the environment_liveness view (ended, active), rename Allocation.Reclaimed to Ended, and drop the per-trigger releases the model makes redundant.
The placement reservation step releases every placement held without compute by an Environment that can no longer run work. Detach, archive and reset no longer release placements themselves, and a failure before allocation is covered.
@SaladDay
SaladDay marked this pull request as ready for review November 6, 2026 10:15
@SaladDay
SaladDay merged commit 66c9998 into main Nov 6, 2026
25 checks passed
@SaladDay
SaladDay deleted the feat/standalone-environments branch November 6, 2026 10:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant