diff --git a/server/src/modules/agent-lifecycle/__tests__/lifecycle.test.ts b/server/src/modules/agent-lifecycle/__tests__/lifecycle.test.ts
index 047c50a872a..48dd67cf95b 100644
--- a/server/src/modules/agent-lifecycle/__tests__/lifecycle.test.ts
+++ b/server/src/modules/agent-lifecycle/__tests__/lifecycle.test.ts
@@ -171,8 +171,8 @@ const support = await getEmbeddedPostgresTestSupport();
expect(await current(id)).toMatchObject({ lifecycleState: "paused", lifecycleHolds: ["setup", "budget"] });
await lifecycle.updateConfiguration(id, { adapterConfig: { provider: "codex", model: "changed" } });
expect((await current(id)).lifecycleState).toBe("paused");
- // Restore only the setup hold to exercise environment changes under the wizard's authority.
- await db.update(agents).set({ lifecycleHolds: ["setup"], pauseReason: "setup" }).where(eq(agents.id, id));
+ await store.change(id, "reconcile"); await work.process(id);
+ expect(await current(id)).toMatchObject({ lifecycleState: "verifying", lifecycleHolds: ["setup"] });
await lifecycle.updateConfiguration(id, { adapterConfig: { provider: "codex", model: "prepared" } });
await work.process(id);
expect((await current(id)).lifecycleState).toBe("verifying");
@@ -181,6 +181,11 @@ const support = await getEmbeddedPostgresTestSupport();
expect((await current(id)).lifecycleState).toBe("paused");
await lifecycle.updateConfiguration(id, { defaultEnvironmentId: environmentId }); await work.process(id);
expect((await current(id)).lifecycleState).toBe("verifying");
+ await lifecycle.updateConfiguration(id, { defaultEnvironmentId: local.id });
+ expect((await current(id)).lifecycleState).toBe("pausing");
+ await lifecycle.updateConfiguration(id, { defaultEnvironmentId: environmentId });
+ await work.process(id);
+ expect((await current(id)).lifecycleState).toBe("verifying");
const finished = await lifecycle.requestHire(companyId, input, { setupAgentId: id, runnerResolved: true });
expect(finished.id).toBe(id);
await work.process(id);
diff --git a/server/src/modules/agent-lifecycle/adapters/postgres.ts b/server/src/modules/agent-lifecycle/adapters/postgres.ts
index 3e9a50a3c45..4179fa923aa 100644
--- a/server/src/modules/agent-lifecycle/adapters/postgres.ts
+++ b/server/src/modules/agent-lifecycle/adapters/postgres.ts
@@ -62,6 +62,8 @@ async function changeLockedAgent(tx: Db, effects: LifecycleEffects, agent: Lifec
if (restartPause && next === "paused") next = "pausing";
if (command === "complete" && next === "ready" && holds.length) next = "pausing";
if (command === "complete" && next === "paused" && !holds.length) next = "resuming";
+ if (["complete", "reconcile"].includes(command) && next === "paused" && holds.length === 1 && holds[0] === "setup"
+ && await effects.setupRequiresPreparation(tx, agent.companyId, agent.defaultEnvironmentId)) next = "preparing";
if (next === agent.lifecycleState) {
if (JSON.stringify(holds) !== JSON.stringify(agent.lifecycleHolds) || agent.pauseReason !== (holds[0] ?? null)) {
const [updated] = await tx.update(agents).set({ lifecycleHolds: holds, pauseReason: holds[0] ?? null }).where(eq(agents.id, agent.id)).returning();
diff --git a/ui/src/components/new-agent/NewAgentSetup.tsx b/ui/src/components/new-agent/NewAgentSetup.tsx
index 9bb13435f46..429c7c59730 100644
--- a/ui/src/components/new-agent/NewAgentSetup.tsx
+++ b/ui/src/components/new-agent/NewAgentSetup.tsx
@@ -413,7 +413,9 @@ function Setup({
);
const needsCurrentSetup = ["codex_local", "claude_local", "opencode_local", "pi_local"].includes(adapterType);
const preparingComputer = created?.pauseReason === "setup" && ["preparing", "pausing"].includes(created.lifecycleState ?? "");
- const ready = Boolean(created) && !environmentSaving && !preparingComputer && connectionSettingsReady && (!needsCurrentSetup || (
+ const environmentSelectionSaved = (created?.defaultEnvironmentId ?? null)
+ === (environmentOverride || (forced.forced || managedOnly ? environmentId : null));
+ const ready = Boolean(created) && environmentSelectionSaved && !environmentSaving && !preparingComputer && connectionSettingsReady && (!needsCurrentSetup || (
envs.isSuccess && !envs.isFetching
&& settings.isSuccess && !settings.isFetching
&& experimental.isSuccess && !experimental.isFetching
@@ -657,6 +659,15 @@ function Setup({
finally { savingRef.current = false; setSaving(false); }
}
+ async function changeEnvironment(selected = environmentOverride) {
+ setEnvironmentOverride(selected);
+ resetTest();
+ setEnvironmentSaving(true);
+ try { await saveDraft(connection, false, undefined, selected); }
+ catch (cause) { setError(cause instanceof Error ? cause.message : "Could not save the environment."); }
+ finally { setEnvironmentSaving(false); }
+ }
+
async function runTest(nextConnection = connection): Promise