History

refactor(v2): rename PM runtime surface to runtime host

Align runtime naming with the current architecture by replacing PM-prefixed runtime services/env wiring with runtime-host terminology while keeping legacy PM env vars as fallbacks for compatibility.

Rhys Sullivan committed 8 months ago

Commit be4adee1 parent 7b46af718 files · +113 −312Browse files

Unified · Split

18 files
  1. PLAN.md +6 −6
  2. apps/cli/README.md +9 −3
  3. apps/cli/src/main.ts +5 −227
  4. apps/web/lib/control-plane/server.ts +27 −27
  5. apps/web/lib/env/server.ts +19 −6
  6. packages/control-plane-runtime/src/actor.ts +8 −5
  7. packages/control-plane-runtime/src/approvals-service.ts +4 −4
  8. packages/control-plane-runtime/src/credential-resolver.ts +1 −1
  9. packages/control-plane-runtime/src/credentials-service.ts +1 −1
  10. packages/control-plane-runtime/src/index.ts +12 −12
  11. packages/control-plane-runtime/src/mcp-handler.ts +4 −4
  12. packages/control-plane-runtime/src/organizations-service.ts +1 −1
  13. packages/control-plane-runtime/src/policies-service.ts +1 −1
  14. packages/control-plane-runtime/src/runtime-execution-port.ts +11 −11
  15. packages/control-plane-runtime/src/storage-service.ts +1 −1
  16. packages/control-plane-runtime/src/tools-service.ts +1 −1
  17. packages/control-plane-runtime/src/workspaces-service.ts +1 −1
  18. turbo.json +1 −0
PLAN.md+6−6
@@ -104,7 +104,7 @@ Important boundary: · 103 unmodified lines
104104
105105 ### Modes
106106
107−- local-lite: PM daemon + in-memory hot state + file durability
107+- local-lite: Runtime Host daemon + in-memory hot state + file durability
108108 - remote: SQL-backed target (Postgres remote, SQLite local)
109109
110110 ### Runtime targets
@@ -265,7 +265,7 @@ Secrets/credentials: · 154 unmodified lines
265265 ---
266266
267267 ## 12) Security posture
268−- PM binds to loopback by default.
268+- Runtime Host binds to loopback by default.
269269 - Runtime callbacks require internal token validation.
270270 - Secrets do not pass through model args/transcripts.
271271 - Credential refs in state; secret values in secure stores.
@@ -279,7 +279,7 @@ Secrets/credentials: · 7 unmodified lines
279279 v2/
280280 apps/
281281 cli/
282− pm/
282+ runtime-host/
283283 web/
284284 packages/
285285 schema/
@@ -340,7 +340,7 @@ Rules: · 54 unmodified lines
340340
341341 ### Phase 1: local-lite execute vertical slice
342342
343−- PM execute path with persisted run lifecycle
343+- Runtime Host execute path with persisted run lifecycle
344344 - runtime callback path wired through shared invocation service
345345 - openapi + in_memory providers
346346
@@ -403,7 +403,7 @@ Implemented in `v2` so far: · 56 unmodified lines
403403 - local in-process JS runner with `tools.*` proxy
404404 - Deno subprocess runtime path with IPC tool-call proxying and tests
405405 - runtime adapter contract + registry scaffold
406−- PM execute lifecycle scaffold via MCP execute path
406+- Runtime Host execute lifecycle scaffold via MCP execute path
407407
408408 Still missing:
409409
@@ -417,7 +417,7 @@ Still missing: · 7 unmodified lines
417417
418418 ## 19) Immediate next steps
419419
420−1. Land shared `ToolInvocationService` contract in v2 and wire PM execute callback path through it.
420+1. Land shared `ToolInvocationService` contract in v2 and wire Runtime Host execute callback path through it.
421421 2. Add `CredentialResolver` interfaces and local/remote implementations; integrate at invocation-time only.
422422 3. Implement control handlers for sources (`add/list/remove`) and route both host API and `tools.executor.*` through same code path.
423423 4. Implement cloudflare-worker-loader runtime dispatch adapter in v2 and wire callback endpoints.
apps/cli/README.md+9−3
@@ -26,13 +26,19 @@ Supported commands: · 25 unmodified lines
2626 - `executor workspace use <workspace-id>`
2727 - `executor run execute --code ...`
2828 - `executor run execute --file ...`
29−- `executor run bootstrap openapi --spec-url ... --source-base-url ...`
30−- `executor run bootstrap github`
29+
30+Control-plane management from CLI should happen through `run execute` and discovered
31+source tool paths (for example, add Executor's own OpenAPI source, then call its
32+tool paths to manage other sources).
3133
3234 Run locally:
3335
3436 - `bun run --cwd apps/cli start -- target show`
3537 - `bun run --cwd apps/cli start -- run execute --target local --code "return 1"`
36−- `bun run --cwd apps/cli start -- run bootstrap github --target local`
3738 - `bun run --cwd apps/cli start -- --help`
3839 - `bun run --cwd apps/cli start -- server start --port 8788`
40+
41+Seed Executor's own OpenAPI source (example):
42+
43+- `bun run --cwd apps/cli start -- run execute --target local --workspace ws_local --code "const workspaceId='ws_local'; const res=await fetch('http://127.0.0.1:8788/v1/workspaces/'+workspaceId+'/sources',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({id:'src_executor_openapi',name:'executor:openapi',kind:'openapi',endpoint:'http://127.0.0.1:8788/v1/openapi.json',enabled:true,configJson:JSON.stringify({baseUrl:'http://127.0.0.1:8788'})})}); return await res.json();"`
44+- Then use `tools.discover(...)` in `run execute` to locate and call source tool paths.
apps/cli/src/main.ts+5−227
@@ -36,20 +36,6 @@ type WorkspaceRecord = { · 35 unmodified lines
3636 id: string;
3737 };
3838
39−type SourceRecord = {
40− id: string;
41− name: string;
42− endpoint: string;
43− configJson: string;
44−};
45−
46−type SourceToolSummaryRecord = {
47− toolId: string;
48− method: string;
49− path: string;
50− name: string;
51−};
52−
5339 type DeviceAuthorizationResponse = {
5440 device_code: string;
5541 user_code: string;
@@ -78,10 +64,6 @@ type CommonTargetOptions = { · 22 unmodified lines
7864
7965 const DEFAULT_LOCAL_BASE_URL = "http://127.0.0.1:8788";
8066 const DEFAULT_WORKOS_AUTH_BASE_URL = "https://api.workos.com";
81−const DEFAULT_GITHUB_OPENAPI_SPEC_URL =
82− "https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json";
83−const DEFAULT_GITHUB_API_BASE_URL = "https://api.github.com";
84−const DEFAULT_GITHUB_OPENAPI_SOURCE_ID = "src_github_openapi";
8567 const CONFIG_PATH = join(homedir(), ".config", "executor", "cli.json");
8668
8769 const toErrorMessage = (cause: unknown): string =>
@@ -518,6 +500,8 @@ class ExecutorServerClient { · 430 unmodified lines
518500 const childEnv = {
519501 ...cleanEnv(),
520502 PORT: localPort,
503+ EXECUTOR_RUNTIME_KIND:
504+ process.env.EXECUTOR_LOCAL_RUNTIME_KIND?.trim() || "local-inproc",
521505 PM_RUNTIME_KIND:
522506 process.env.EXECUTOR_LOCAL_RUNTIME_KIND?.trim() || "local-inproc",
523507 };
@@ -597,87 +581,6 @@ const ensureWorkspaceId = async ( · 73 unmodified lines
597581 return workspaceId;
598582 };
599583
600−const deriveSourceName = (kind: string, endpoint: string): string => {
601− try {
602− const url = new URL(endpoint);
603− const host = url.hostname.replace(/^api\./, "");
604− return `${kind}:${host}`;
605− } catch {
606− return `${kind}:source`;
607− }
608−};
609−
610−const bootstrapOpenApiSource = async (input: {
611− client: ExecutorServerClient;
612− config: ExecutorCliConfig;
613− workspaceOverride?: string;
614− specUrl: string;
615− baseUrl: string;
616− name?: string;
617− sourceId?: string;
618−}): Promise<{
619− workspaceId: string;
620− source: SourceRecord;
621− tools: Array<SourceToolSummaryRecord>;
622− sampleToolPath: string | null;
623−}> => {
624− const workspaceId = await ensureWorkspaceId(
625− input.client,
626− input.config,
627− input.workspaceOverride,
628− );
629− const normalizedSpecUrl = input.specUrl.trim();
630− const normalizedBaseUrl = input.baseUrl.trim();
631−
632− if (normalizedSpecUrl.length === 0) {
633− throw new Error("OpenAPI bootstrap requires --spec-url.");
634− }
635−
636− if (normalizedBaseUrl.length === 0) {
637− throw new Error("OpenAPI bootstrap requires --source-base-url.");
638− }
639−
640− const source = await input.client.runControlPlane((api) =>
641− api.sources.upsert({
642− path: { workspaceId },
643− payload: {
644− ...(input.sourceId && input.sourceId.trim().length > 0
645− ? { id: input.sourceId.trim() }
646− : {}),
647− name:
648− input.name && input.name.trim().length > 0
649− ? input.name.trim()
650− : deriveSourceName("openapi", normalizedBaseUrl),
651− kind: "openapi",
652− endpoint: normalizedSpecUrl,
653− status: "connected",
654− enabled: true,
655− configJson: JSON.stringify({ baseUrl: normalizedBaseUrl }),
656− },
657− }),
658− ) as SourceRecord;
659−
660− const tools = await input.client.runControlPlane((api) =>
661− api.tools.listSourceTools({
662− path: {
663− workspaceId,
664− sourceId: source.id,
665− },
666− }),
667− ) as Array<SourceToolSummaryRecord>;
668−
669− const sampleToolPath = tools[0]?.toolId
670− ? `source.${source.id}.${tools[0].toolId}`
671− : null;
672−
673− return {
674− workspaceId,
675− source,
676− tools,
677− sampleToolPath,
678− };
679−};
680−
681584 const postForm = async (
682585 url: string,
683586 params: Record<string, string>,
@@ -859,8 +762,9 @@ const commonTargetOptions = () => ({ · 175 unmodified lines
859762 });
860763
861764 const startEmbeddedLocalServer = async (port: number): Promise<void> => {
862− process.env.PM_RUNTIME_KIND =
765+ process.env.EXECUTOR_RUNTIME_KIND =
863766 process.env.EXECUTOR_LOCAL_RUNTIME_KIND?.trim() || "local-inproc";
767+ process.env.PM_RUNTIME_KIND = process.env.EXECUTOR_RUNTIME_KIND;
864768
865769 const {
866770 createLocalPrincipal,
@@ -1254,134 +1158,8 @@ const runExecuteCommand = Command.make( · 387 unmodified lines
12541158 Command.withDescription("Execute TypeScript code through Executor runtime"),
12551159 );
12561160
1257−const runBootstrapOpenApiCommand = Command.make(
1258− "openapi",
1259− {
1260− ...commonTargetOptions(),
1261− specUrl: Options.text("spec-url"),
1262− sourceBaseUrl: Options.text("source-base-url"),
1263− name: Options.text("name").pipe(Options.optional),
1264− sourceId: Options.text("source-id").pipe(Options.optional),
1265− },
1266− (input) =>
1267− Effect.tryPromise({
1268− try: async () => {
1269− const common: CommonTargetOptions = {
1270− target: input.target,
1271− workspace: input.workspace,
1272− baseUrl: input.baseUrl,
1273− json: input.json,
1274− };
1275−
1276− await withClient(common, async ({ client, config, workspaceOverride, asJson }) => {
1277− const setup = await bootstrapOpenApiSource({
1278− client,
1279− config,
1280− workspaceOverride,
1281− specUrl: input.specUrl,
1282− baseUrl: input.sourceBaseUrl,
1283− name: optionToUndefined(input.name),
1284− sourceId: optionToUndefined(input.sourceId),
1285− });
1286−
1287− printOutput(
1288− {
1289− ok: true,
1290− workspaceId: setup.workspaceId,
1291− source: {
1292− id: setup.source.id,
1293− name: setup.source.name,
1294− endpoint: setup.source.endpoint,
1295− configJson: setup.source.configJson,
1296− },
1297− toolCount: setup.tools.length,
1298− sampleToolPath: setup.sampleToolPath,
1299− },
1300− asJson,
1301− );
1302− });
1303− },
1304− catch: toErrorMessage,
1305− }),
1306−).pipe(
1307− Command.withDescription("Bootstrap an OpenAPI source with runtime base URL"),
1308−);
1309−
1310−const runBootstrapGithubCommand = Command.make(
1311− "github",
1312− {
1313− ...commonTargetOptions(),
1314− name: Options.text("name").pipe(Options.optional),
1315− sourceId: Options.text("source-id").pipe(Options.optional),
1316− specUrl: Options.text("spec-url").pipe(Options.withDefault(DEFAULT_GITHUB_OPENAPI_SPEC_URL)),
1317− sourceBaseUrl: Options.text("source-base-url").pipe(Options.withDefault(DEFAULT_GITHUB_API_BASE_URL)),
1318− },
1319− (input) =>
1320− Effect.tryPromise({
1321− try: async () => {
1322− const common: CommonTargetOptions = {
1323− target: input.target,
1324− workspace: input.workspace,
1325− baseUrl: input.baseUrl,
1326− json: input.json,
1327− };
1328−
1329− await withClient(common, async ({ client, config, workspaceOverride, asJson }) => {
1330− const setup = await bootstrapOpenApiSource({
1331− client,
1332− config,
1333− workspaceOverride,
1334− specUrl: input.specUrl,
1335− baseUrl: input.sourceBaseUrl,
1336− name: optionToUndefined(input.name) ?? "github:openapi",
1337− sourceId: optionToUndefined(input.sourceId) ?? DEFAULT_GITHUB_OPENAPI_SOURCE_ID,
1338− });
1339−
1340− const suggestedTool =
1341− setup.tools.find((tool) =>
1342− tool.toolId.includes("issues-and-pull-requests"),
1343− )
1344− ?? setup.tools[0]
1345− ?? null;
1346−
1347− printOutput(
1348− {
1349− ok: true,
1350− workspaceId: setup.workspaceId,
1351− source: {
1352− id: setup.source.id,
1353− name: setup.source.name,
1354− endpoint: setup.source.endpoint,
1355− configJson: setup.source.configJson,
1356− },
1357− toolCount: setup.tools.length,
1358− suggestedToolPath: suggestedTool
1359− ? `source.${setup.source.id}.${suggestedTool.toolId}`
1360− : null,
1361− executeHint: suggestedTool
1362− ? `executor run execute --code \"return await tools['source.${setup.source.id}.${suggestedTool.toolId}']({ q: 'repo:owner/repo is:issue state:open', per_page: 5 });\"`
1363− : null,
1364− },
1365− asJson,
1366− );
1367− });
1368− },
1369− catch: toErrorMessage,
1370− }),
1371−).pipe(
1372− Command.withDescription("Bootstrap GitHub OpenAPI source for public issue queries"),
1373−);
1374−
1375−const runBootstrapCommand = Command.make("bootstrap").pipe(
1376− Command.withSubcommands([
1377− runBootstrapOpenApiCommand,
1378− runBootstrapGithubCommand,
1379− ] as any),
1380− Command.withDescription("Bootstrap source setup shortcuts for execution workflows"),
1381−);
1382−
13831161 const runCommand = Command.make("run").pipe(
1384− Command.withSubcommands([runExecuteCommand, runBootstrapCommand] as any),
1162+ Command.withSubcommands([runExecuteCommand] as any),
13851163 Command.withDescription("Code execution commands"),
13861164 );
13871165
apps/web/lib/control-plane/server.ts+27−27
@@ -30,19 +30,19 @@ import { · 29 unmodified lines
3030 type ToolRegistryDiscoverOutput,
3131 } from "@executor-v2/engine";
3232 import {
33− PmActorLive,
33+ RuntimeHostActorLive,
3434 createKeychainSecretMaterialStore,
35− createPmApprovalsService,
36− createPmCredentialsService,
37− createPmExecuteRuntimeRun,
38− createPmMcpHandler,
39− createPmOrganizationsService,
40− createPmPersistentToolApprovalPolicy,
41− createPmPoliciesService,
42− createPmResolveToolCredentials,
43− createPmStorageService,
44− createPmToolsService,
45− createPmWorkspacesService,
35+ createRuntimeHostApprovalsService,
36+ createRuntimeHostCredentialsService,
37+ createRuntimeHostExecuteRuntimeRun,
38+ createRuntimeHostMcpHandler,
39+ createRuntimeHostOrganizationsService,
40+ createRuntimeHostPersistentToolApprovalPolicy,
41+ createRuntimeHostPoliciesService,
42+ createRuntimeHostResolveToolCredentials,
43+ createRuntimeHostStorageService,
44+ createRuntimeHostToolsService,
45+ createRuntimeHostWorkspacesService,
4646 createSqlSecretMaterialStore,
4747 parseSecretMaterialBackendKind,
4848 } from "@executor-v2/control-plane-runtime";
@@ -585,25 +585,25 @@ const createControlPlaneRuntime = async (): Promise<ControlPlaneRuntime> => { · 536 unmodified lines
585585 ];
586586 const runtimeAdapters = makeRuntimeAdapterRegistry(runtimeAdapterList);
587587 const defaultRuntimeKind =
588− webServerEnvironment.pmRuntimeKind
588+ webServerEnvironment.executorRuntimeKind
589589 ?? runtimeAdapterList[0]?.kind
590590 ?? "local-inproc";
591− const requireToolApprovals = webServerEnvironment.pmRequireToolApprovals;
591+ const requireToolApprovals = webServerEnvironment.executorRuntimeRequireToolApprovals;
592592 const defaultToolExposureMode =
593− parseExecuteToolExposureMode(webServerEnvironment.pmToolExposureMode)
593+ parseExecuteToolExposureMode(webServerEnvironment.executorRuntimeToolExposureMode)
594594 ?? defaultExecuteToolExposureMode;
595595 const toolProviderRegistry = makeToolProviderRegistry([
596596 makeOpenApiToolProvider(),
597597 makeMcpToolProvider(),
598598 makeGraphqlToolProvider(),
599599 ]);
600− const persistentApprovalPolicy = createPmPersistentToolApprovalPolicy(
600+ const persistentApprovalPolicy = createRuntimeHostPersistentToolApprovalPolicy(
601601 persistence.rows,
602602 {
603603 requireApprovals: requireToolApprovals,
604604 },
605605 );
606− const resolveCredentials = createPmResolveToolCredentials(
606+ const resolveCredentials = createRuntimeHostResolveToolCredentials(
607607 persistence.rows,
608608 secretMaterialStore,
609609 );
@@ -722,20 +722,20 @@ const createControlPlaneRuntime = async (): Promise<ControlPlaneRuntime> => { · 112 unmodified lines
722722
723723 const controlPlaneService = makeControlPlaneService({
724724 sources: sourcesService,
725− credentials: createPmCredentialsService(persistence.rows, secretMaterialStore),
726− policies: createPmPoliciesService(persistence.rows),
727− organizations: createPmOrganizationsService(persistence.rows),
728− workspaces: createPmWorkspacesService(persistence.rows),
729− tools: createPmToolsService(sourceStore, toolArtifactStore),
730− storage: createPmStorageService(persistence.rows, {
725+ credentials: createRuntimeHostCredentialsService(persistence.rows, secretMaterialStore),
726+ policies: createRuntimeHostPoliciesService(persistence.rows),
727+ organizations: createRuntimeHostOrganizationsService(persistence.rows),
728+ workspaces: createRuntimeHostWorkspacesService(persistence.rows),
729+ tools: createRuntimeHostToolsService(sourceStore, toolArtifactStore),
730+ storage: createRuntimeHostStorageService(persistence.rows, {
731731 stateRootDir,
732732 }),
733− approvals: createPmApprovalsService(persistence.rows),
733+ approvals: createRuntimeHostApprovalsService(persistence.rows),
734734 });
735735
736736 const controlPlaneWebHandler = makeControlPlaneWebHandler(
737737 Layer.succeed(ControlPlaneService, controlPlaneService),
738− PmActorLive(persistence.rows),
738+ RuntimeHostActorLive(persistence.rows),
739739 );
740740
741741 const rememberRunWorkspace = (runId: string, workspaceId: string): void => {
@@ -772,7 +772,7 @@ const createControlPlaneRuntime = async (): Promise<ControlPlaneRuntime> => { · 30 unmodified lines
772772 toolProviderRegistry,
773773 approvalPolicy: persistentApprovalPolicy,
774774 });
775− const executeRuntimeRun = createPmExecuteRuntimeRun({
775+ const executeRuntimeRun = createRuntimeHostExecuteRuntimeRun({
776776 defaultRuntimeKind,
777777 runtimeAdapters,
778778 toolRegistry,
@@ -784,7 +784,7 @@ const createControlPlaneRuntime = async (): Promise<ControlPlaneRuntime> => { · 5 unmodified lines
784784 return runId;
785785 },
786786 });
787− const next = createPmMcpHandler(runExecutor.executeRun, {
787+ const next = createRuntimeHostMcpHandler(runExecutor.executeRun, {
788788 toolRegistry,
789789 defaultToolExposureMode,
790790 });
apps/web/lib/env/server.ts+19−6
@@ -8,9 +8,18 @@ const webServerEnvConfig = configSchema("WebServerEnvironment", { · 7 unmodified lines
88 env: "CONTROL_PLANE_POSTGRES_CONNECTION_TARGET",
99 optional: true,
1010 }),
11− pmRuntimeKind: server({ env: "PM_RUNTIME_KIND", optional: true }),
12− pmRequireToolApprovals: server({ env: "PM_REQUIRE_TOOL_APPROVALS", optional: true }),
13− pmToolExposureMode: server({ env: "PM_TOOL_EXPOSURE_MODE", optional: true }),
11+ executorRuntimeKind: server({ env: "EXECUTOR_RUNTIME_KIND", optional: true }),
12+ legacyPmRuntimeKind: server({ env: "PM_RUNTIME_KIND", optional: true }),
13+ executorRuntimeRequireToolApprovals: server({
14+ env: "EXECUTOR_RUNTIME_REQUIRE_TOOL_APPROVALS",
15+ optional: true,
16+ }),
17+ legacyPmRequireToolApprovals: server({ env: "PM_REQUIRE_TOOL_APPROVALS", optional: true }),
18+ executorRuntimeToolExposureMode: server({
19+ env: "EXECUTOR_RUNTIME_TOOL_EXPOSURE_MODE",
20+ optional: true,
21+ }),
22+ legacyPmToolExposureMode: server({ env: "PM_TOOL_EXPOSURE_MODE", optional: true }),
1423 cloudflareSandboxCallbackSecret: server({
1524 env: "CLOUDFLARE_SANDBOX_CALLBACK_SECRET",
1625 optional: true,
@@ -36,14 +45,18 @@ const webServerEnvConfig = configSchema("WebServerEnvironment", { · 19 unmodified lines
3645 });
3746
3847 const env = webServerEnvConfig.server;
48+const executorRuntimeRequireToolApprovalsRaw =
49+ trim(env.executorRuntimeRequireToolApprovals)
50+ ?? trim(env.legacyPmRequireToolApprovals);
3951
4052 export const webServerEnvironment = {
4153 nodeEnv: trim(env.nodeEnv) ?? "development",
4254 databaseUrl: trim(env.databaseUrl),
4355 controlPlanePostgresConnectionTarget: trim(env.controlPlanePostgresConnectionTarget)?.toLowerCase(),
44− pmRuntimeKind: trim(env.pmRuntimeKind),
45− pmRequireToolApprovals: isTruthy(env.pmRequireToolApprovals),
46− pmToolExposureMode: trim(env.pmToolExposureMode),
56+ executorRuntimeKind: trim(env.executorRuntimeKind) ?? trim(env.legacyPmRuntimeKind),
57+ executorRuntimeRequireToolApprovals: isTruthy(executorRuntimeRequireToolApprovalsRaw),
58+ executorRuntimeToolExposureMode:
59+ trim(env.executorRuntimeToolExposureMode) ?? trim(env.legacyPmToolExposureMode),
4760 cloudflareSandboxCallbackSecret: trim(env.cloudflareSandboxCallbackSecret),
4861 executorPublicOrigin: trim(env.executorPublicOrigin),
4962 vercelProjectProductionUrl: trim(env.vercelProjectProductionUrl),
packages/control-plane-runtime/src/actor.ts+8−5
@@ -84,14 +84,17 @@ const resolveActorFromSnapshot = ( · 83 unmodified lines
8484 });
8585 });
8686
87−export const PmActorLive = (rows: ActorRows) =>
87+export const RuntimeHostActorLive = (rows: ActorRows) =>
8888 {
89+ const localAdminFallbackValue =
90+ process.env.EXECUTOR_RUNTIME_ALLOW_LOCAL_ADMIN?.trim().toLowerCase()
91+ ?? process.env.PM_ALLOW_LOCAL_ADMIN?.trim().toLowerCase()
92+ ?? "";
93+
8994 const localAdminFallbackEnabled =
90− (process.env.PM_ALLOW_LOCAL_ADMIN?.trim().toLowerCase() ?? "") === ""
95+ localAdminFallbackValue === ""
9196 ? process.env.NODE_ENV !== "production"
92− : ["1", "true", "yes"].includes(
93− process.env.PM_ALLOW_LOCAL_ADMIN?.trim().toLowerCase() ?? "",
94− );
97+ : ["1", "true", "yes"].includes(localAdminFallbackValue);
9598
9699 return ControlPlaneActorResolverLive({
97100 resolveActor: (input) => resolveActorFromSnapshot(rows, input.headers, localAdminFallbackEnabled),
packages/control-plane-runtime/src/approvals-service.ts+4−4
@@ -47,14 +47,14 @@ const toPersistentApprovalRecord = (approval: Approval): PersistentToolApprovalR · 46 unmodified lines
4747 reason: approval.reason,
4848 });
4949
50−export type PmPersistentToolApprovalPolicyOptions = {
50+export type RuntimeHostPersistentToolApprovalPolicyOptions = {
5151 requireApprovals?: boolean;
5252 retryAfterMs?: number;
5353 };
5454
55−export const createPmPersistentToolApprovalPolicy = (
55+export const createRuntimeHostPersistentToolApprovalPolicy = (
5656 rows: ApprovalRows,
57− options: PmPersistentToolApprovalPolicyOptions = {},
57+ options: RuntimeHostPersistentToolApprovalPolicyOptions = {},
5858 ): ToolApprovalPolicy => {
5959 const store: PersistentToolApprovalStore = {
6060 findByRunAndCall: (input) =>
@@ -106,7 +106,7 @@ export const createPmPersistentToolApprovalPolicy = ( · 45 unmodified lines
106106 });
107107 };
108108
109−export const createPmApprovalsService = (
109+export const createRuntimeHostApprovalsService = (
110110 rows: ApprovalRows,
111111 ): ControlPlaneApprovalsServiceShape =>
112112 makeControlPlaneApprovalsService({
packages/control-plane-runtime/src/credential-resolver.ts+1−1
@@ -163,7 +163,7 @@ const buildSecretHeaders = ( · 162 unmodified lines
163163 return {};
164164 };
165165
166−export const createPmResolveToolCredentials = (
166+export const createRuntimeHostResolveToolCredentials = (
167167 rows: CredentialResolverRows,
168168 secretMaterialStore: SecretMaterialStore,
169169 ): ResolveToolCredentials =>
packages/control-plane-runtime/src/credentials-service.ts+1−1
@@ -73,7 +73,7 @@ const uniqueHandles = (handles: ReadonlyArray<string | null | undefined>): Array · 72 unmodified lines
7373 return next;
7474 };
7575
76−export const createPmCredentialsService = (
76+export const createRuntimeHostCredentialsService = (
7777 rows: CredentialRows,
7878 secretMaterialStore: SecretMaterialStore,
7979 ): ControlPlaneCredentialsServiceShape =>
packages/control-plane-runtime/src/index.ts+12−12
@@ -1,14 +1,14 @@
1−export { PmActorLive } from "./actor";
1+export { RuntimeHostActorLive } from "./actor";
22 export {
3− createPmApprovalsService,
4− createPmPersistentToolApprovalPolicy,
3+ createRuntimeHostApprovalsService,
4+ createRuntimeHostPersistentToolApprovalPolicy,
55 } from "./approvals-service";
6−export { createPmResolveToolCredentials } from "./credential-resolver";
7−export { createPmCredentialsService } from "./credentials-service";
8−export { createPmMcpHandler } from "./mcp-handler";
9−export { createPmOrganizationsService } from "./organizations-service";
10−export { createPmPoliciesService } from "./policies-service";
11−export { createPmExecuteRuntimeRun } from "./runtime-execution-port";
6+export { createRuntimeHostResolveToolCredentials } from "./credential-resolver";
7+export { createRuntimeHostCredentialsService } from "./credentials-service";
8+export { createRuntimeHostMcpHandler } from "./mcp-handler";
9+export { createRuntimeHostOrganizationsService } from "./organizations-service";
10+export { createRuntimeHostPoliciesService } from "./policies-service";
11+export { createRuntimeHostExecuteRuntimeRun } from "./runtime-execution-port";
1212 export {
1313 createKeychainSecretMaterialStore,
1414 createSqlSecretMaterialStore,
@@ -19,6 +19,6 @@ export { · 4 unmodified lines
1919 type SecretMaterialScope,
2020 type SecretMaterialStore,
2121 } from "./secret-material-store";
22−export { createPmStorageService } from "./storage-service";
23−export { createPmToolsService } from "./tools-service";
24−export { createPmWorkspacesService } from "./workspaces-service";
22+export { createRuntimeHostStorageService } from "./storage-service";
23+export { createRuntimeHostToolsService } from "./tools-service";
24+export { createRuntimeHostWorkspacesService } from "./workspaces-service";
packages/control-plane-runtime/src/mcp-handler.ts+4−4
@@ -14,7 +14,7 @@ import { · 13 unmodified lines
1414 import { handleMcpHttpRequest } from "@executor-v2/mcp-gateway";
1515 import * as Effect from "effect/Effect";
1616
17−export type PmMcpHandlerOptions = {
17+export type RuntimeHostMcpHandlerOptions = {
1818 toolRegistry: ToolRegistry;
1919 defaultToolExposureMode?: ExecuteToolExposureMode;
2020 };
@@ -48,9 +48,9 @@ const resolveExecuteToolDescription = async ( · 27 unmodified lines
4848 }
4949 };
5050
51−export const createPmMcpHandler = (
51+export const createRuntimeHostMcpHandler = (
5252 executeRun: (input: ExecuteRunInput) => Effect.Effect<ExecuteRunResult>,
53− options: PmMcpHandlerOptions,
53+ options: RuntimeHostMcpHandlerOptions,
5454 ): ((request: Request) => Promise<Response>) => {
5555 const runClient = createExecutorRunClient((input) =>
5656 Effect.runPromise(executeRun(input)),
@@ -67,7 +67,7 @@ export const createPmMcpHandler = ( · 10 unmodified lines
6767 );
6868
6969 return handleMcpHttpRequest(request, {
70− serverName: "executor-v2-pm",
70+ serverName: "executor-v2-runtime-host",
7171 serverVersion: "0.0.0",
7272 runClient,
7373 executeToolDescription,
packages/control-plane-runtime/src/organizations-service.ts+1−1
@@ -33,7 +33,7 @@ const sortOrganizations = ( · 32 unmodified lines
3333 return leftName.localeCompare(rightName);
3434 });
3535
36−export const createPmOrganizationsService = (
36+export const createRuntimeHostOrganizationsService = (
3737 rows: OrganizationRows,
3838 ): ControlPlaneOrganizationsServiceShape =>
3939 makeControlPlaneOrganizationsService({
packages/control-plane-runtime/src/policies-service.ts+1−1
@@ -24,7 +24,7 @@ const sortPolicies = (policies: ReadonlyArray<Policy>): Array<Policy> => · 23 unmodified lines
2424 return leftPattern.localeCompare(rightPattern);
2525 });
2626
27−export const createPmPoliciesService = (
27+export const createRuntimeHostPoliciesService = (
2828 rows: PolicyRows,
2929 ): ControlPlanePoliciesServiceShape =>
3030 makeControlPlanePoliciesService({
packages/control-plane-runtime/src/runtime-execution-port.ts+11−11
@@ -9,14 +9,14 @@ import { · 8 unmodified lines
99 } from "@executor-v2/engine";
1010 import * as Effect from "effect/Effect";
1111
12−export type PmRuntimeExecutionPortOptions = {
12+export type RuntimeHostExecutionPortOptions = {
1313 defaultRuntimeKind: string;
1414 runtimeAdapters: RuntimeAdapterRegistry;
1515 toolRegistry: ToolRegistry;
1616 };
1717
18−export const createPmExecuteRuntimeRun = (
19− options: PmRuntimeExecutionPortOptions,
18+export const createRuntimeHostExecuteRuntimeRun = (
19+ options: RuntimeHostExecutionPortOptions,
2020 ): ExecuteRuntimeRun => {
2121 const runtimeToolCallService = createRuntimeToolCallService(options.toolRegistry);
2222
@@ -35,14 +35,14 @@ export const createPmExecuteRuntimeRun = ( · 12 unmodified lines
3535 ),
3636 );
3737
38− const isAvailable = yield* runtimeAdapter.isAvailable();
39− if (!isAvailable) {
40− return yield* new RuntimeExecutionPortError({
41− operation: "runtime_available",
42− message: `Runtime '${options.defaultRuntimeKind}' is not available in this pm process.`,
43− details: null,
44− });
45− }
38+ const isAvailable = yield* runtimeAdapter.isAvailable();
39+ if (!isAvailable) {
40+ return yield* new RuntimeExecutionPortError({
41+ operation: "runtime_available",
42+ message: `Runtime '${options.defaultRuntimeKind}' is not available in this runtime host process.`,
43+ details: null,
44+ });
45+ }
4646
4747 return yield* runtimeAdapter
4848 .execute({
packages/control-plane-runtime/src/storage-service.ts+1−1
@@ -136,7 +136,7 @@ const loadStorageScope = ( · 135 unmodified lines
136136 }),
137137 );
138138
139−export const createPmStorageService = (
139+export const createRuntimeHostStorageService = (
140140 rows: StorageRows,
141141 options: {
142142 stateRootDir: string;
packages/control-plane-runtime/src/tools-service.ts+1−1
@@ -141,7 +141,7 @@ const listSourceTools = ( · 140 unmodified lines
141141 return yield* parseArtifactManifest(source, artifact);
142142 });
143143
144−export const createPmToolsService = (
144+export const createRuntimeHostToolsService = (
145145 sourceStore: SourceStore,
146146 toolArtifactStore: ToolArtifactStore,
147147 ): ControlPlaneToolsServiceShape =>
packages/control-plane-runtime/src/workspaces-service.ts+1−1
@@ -25,7 +25,7 @@ const sortWorkspaces = (workspaces: ReadonlyArray<Workspace>): Array<Workspace> · 24 unmodified lines
2525 return leftName.localeCompare(rightName);
2626 });
2727
28−export const createPmWorkspacesService = (
28+export const createRuntimeHostWorkspacesService = (
2929 rows: WorkspaceRows,
3030 ): ControlPlaneWorkspacesServiceShape =>
3131 makeControlPlaneWorkspacesService({
turbo.json+1−0
@@ -19,6 +19,7 @@ · 18 unmodified lines
1919 "CONTROL_PLANE_POSTGRES_MAX_CONNECTIONS",
2020 "DATABASE_URL",
2121 "MCP_AUTHORIZATION_SERVER",
22+ "EXECUTOR_RUNTIME_KIND",
2223 "PM_RUNTIME_KIND",
2324 "VITE_CONVEX_URL",
2425 "WORKOS_API_KEY",