Skip to content

feat(stack): replace remote runtime protocol with Effect RPC - #6303

Open
jgoux wants to merge 20 commits into
developfrom
feat/remote-stack-control-plane
Open

feat(stack): replace remote runtime protocol with Effect RPC#6303
jgoux wants to merge 20 commits into
developfrom
feat/remote-stack-control-plane

Conversation

@jgoux

@jgoux jgoux commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace the runtime REST and SSE daemon protocol with a static control plane exposing owner discovery, session-fenced shutdown, and same-build Effect RPC over HTTP and NDJSON.
  • Centralize supervisor lifecycle and structured shutdown ownership across Node and Bun runtimes, with schema-validated parent and child IPC.
  • Allow only an explicit start command to replace an incompatible daemon while preserving managed data, launch metadata, runtime selection, pinned service versions, exclusions, and sticky ports.
  • Update CLI consumers, internal helpers, error reporting, and durable architecture documentation for the single-protocol cutover.

Linked issue

None.

Reviewer context

This intentionally has no legacy protocol window or compatibility adapter. Runtime RPC is a same-build boundary; owner discovery and session-fenced shutdown remain the stable cross-build protocol.

@jgoux
jgoux marked this pull request as ready for review August 23, 2026 16:35
@jgoux
jgoux requested a review from a team as a code owner August 23, 2026 16:35
@github-actions

github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Supabase CLI preview

npx --yes https://pkg.pr.new/supabase/cli/supabase@530175d9162781fc9ce64b50abc7b418413bada7

Preview package for commit 530175d.

Comment thread packages/stack/src/SupervisorControlServer.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2f99a0c82c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/stack/src/RemoteStack.ts
Comment thread packages/stack/src/layers.ts Outdated
Comment thread apps/cli/src/shared/cli/version.ts
Comment thread apps/cli/src/next/commands/start/start.command.ts
Comment thread apps/cli/src/next/commands/start/ui/dashboard-state.ts Outdated
@jgoux
jgoux marked this pull request as draft August 23, 2026 19:23
Comment thread packages/stack/src/managed/control.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2639cfb636

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/stack/src/platform-bun.ts
Comment thread apps/cli/src/shared/cli/version.ts Outdated
Comment thread packages/stack/src/DaemonProtocol.ts
Comment thread packages/stack/src/SupervisorReplacement.ts Outdated
Comment thread packages/stack/src/supervisor.ts
Comment thread packages/stack/src/supervisor.ts Outdated
@jgoux
jgoux marked this pull request as ready for review August 23, 2026 20:42

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 530175d916

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +114 to +116
return stats.size <= MAX_UNTRACKED_FILE_BYTES
? { path, content: readFileSync(absolutePath) }
: { path, size: stats.size, mtimeMs: stats.mtimeMs };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Hash large untracked files by content

When an untracked file exceeds 1 MiB, its build identity depends only on path, size, and mtime. Replacing that file's contents while preserving its size and timestamp—for example via a timestamp-preserving copy—therefore produces the same build ID even though the source checkout changed. A new CLI process can then attach to an older daemon as if it were the same build and issue RPCs across an incompatible runtime boundary; stream the file contents into the digest instead of substituting metadata.

Useful? React with 👍 / 👎.

Comment on lines +44 to +48
Effect.catchCause((cause) =>
Effect.all([
SubscriptionRef.set(errorRef, Cause.pretty(cause)),
SubscriptionRef.set(phaseRef, "failed"),
]).pipe(Effect.asVoid),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve interruption when the dashboard watcher shuts down

When the foreground scope closes normally, such as after the user exits or presses Ctrl-C, stack.dispose() closes the RPC scope and interrupts this forked watcher while the dashboard registry is still mounted. This unrestricted catchCause converts that expected interruption—and any defect—into a successful fiber that marks the dashboard failed, overwriting the normal stopping state and potentially rendering a spurious failure during teardown. Handle only expected stream failures and propagate interruption and defects unchanged.

AGENTS.md reference: AGENTS.md:L160-L165

Useful? React with 👍 / 👎.

Comment on lines +147 to +154
const existingLayer = yield* connectLayer({
buildIdentity,
cwd: runtimeInfo.cwd,
cacheRoot: cliConfig.supabaseHome,
projectDir: projectHome.projectRoot,
name: stackName,
});
yield* Effect.scoped(Effect.provide(Stack, existingLayer).pipe(Effect.asVoid));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Allow branch switching to recover a stale running document

When a supervisor crashes after leaving stack.json with lifecycle: "running", resolveManagedStack returns that stale document and this new connectLayer call fails with NoRunningStackError because no ready control owner can be probed. The command therefore never reaches stopDaemon, which previously acquired ownership, cleaned up the stale runtime, and allowed the stack to restart for the selected branch. Restrict the compatibility preflight to a live owner or let this specific no-owner result continue into stale-owner recovery.

Useful? React with 👍 / 👎.

Comment on lines +313 to +318
waitForControlSessionEnd(
endpoint,
ownershipId,
ownerSessionId,
readControlOwnerStatus(endpoint, ownershipId, transport.read),
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Recognize a foreign rebind as completion of the old session

After the verified owner accepts the stop and releases its listener, another stack whose deterministic candidates collide can bind this endpoint before the next poll. readControlOwnerStatus then fails with ControlAddressConflictError before waitForControlSessionEnd can observe that the captured session is gone, so supabase stop or an upgrade replacement reports a failure even though its targeted owner already stopped. Treat a valid different-ownership response as completion of this captured session and let identity-scoped callers rescan their own candidates.

Useful? React with 👍 / 👎.

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