Extract Runner provider launch preparation (#16977)

## Thinking Path

> - Paperclip manages work for AI agents.
> - Runner starts providers in local and remote environments.
> - Core selects the provider and task policy.
> - The execution environment supplies paths and installed files.
> - The transport currently combines these inputs in one large method.
> - This PR extracts provider descriptor construction before a separate
plugin preparation change.

## Linked Issues or Issue Description

**What existing behavior does this improve?**
Runner provider launch preparation.

**Current behavior**
The PRP transport constructs each provider descriptor inside startup.
This couples provider configuration to transport lifecycle code.

**Proposed behavior**
The transport calls one built-in descriptor builder. The builder takes
Core provider requirements and execution-environment locations as
separate inputs. File staging, provider validation logic, and session
rules keep their current behavior. The required Copilot source-identity
update changes profile admission metadata.

**Reason and benefit**
This gives launch preparation a separate unit of code. A later PR can
add plugin-owned preparation without adding ownership flags to each
provider backend.

Refs #15406, #16486. This replaces the earlier installed-home
implementation in this PR. #16978 remains a draft.

## What Changed

- Extract provider descriptor construction and its existing permission
helpers.
- Keep helper exports at their previous import path.
- Add focused tests for selection, permissions, locations, and managed
profile rejection.
- Update the Copilot source identity. Bind the extracted file and retain
the v49 history. The source attestation requires v50 after this move.
This changes the admitted profile identity even though no execution
behavior changes are intended.
- Document the boundary and its current limits.

## Verification

- 338 focused builder, transport, Codex security, and Copilot identity
tests passed on the rebased head.
- `pnpm -r typecheck` passed. `pnpm build` passed.
- The full root `pnpm test:run` on the pre-rebase head is still in
progress. It has reported five failures in unchanged server tests. One
isolated failure rejects the word `private` from this checkout's
`/private/tmp` stack path. The full root suite is not reported as
passing.
- All 56 CI checks passed on the rebased head. Four optional checks were
skipped. The branch is mergeable. Workspace typecheck and build passed
on this head.
- Standard Greptile and Apex each scored commit
`47f631883d8f417f6a818500ebe4e77e22cc70b8` 5/5. The rebase onto master
changed only Copilot identity metadata, history handling, and related
tests. `git range-diff` confirms that the launch-preparation
implementation is unchanged. The existing Apex result remains the review
evidence; it did not review the new commit hash.
- No live provider calls or Cloud deployment were run.

## Risks

- A moved field could change provider startup. Existing transport tests
and the new boundary tests check the projection.
- Copilot source binding requires a new identity after the move.
Existing artifacts and retained sessions must match the new admitted
profile. This PR does not claim fresh live qualification.
- This PR does not enable plugin-owned preparation. File materialization
remains in the existing SDK path.

## Model Used

- OpenAI Codex, GPT-6. Reasoning and repository tools. The exact serving
model identifier and context size are not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Nicky LeachandPaperclip authored and GitHub committed 2026-10-20 11:20:49 -07:00
1 parent 3bbc2104b6
commit 05f7079ecb
11 files changed
+503 -280

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
# Runner launch preparation
Core selects the provider, model, instructions, tools, and task permissions.
The execution environment supplies executable paths and filesystem locations.
The built-in TypeScript implementation constructs the provider descriptor in
`createRunnerProviderLaunch`. The transport sends this descriptor with
`run.prepare`. Provider backends keep their existing validation and session rules.
This separation does not change file preparation. The SDK still prepares local
files and stages remote files through the existing execution driver.
It does not enable plugin-owned launch preparation.
+2 -2
View File
@@ -32,12 +32,12 @@
"requiresProviderPolicy": true
},
"copilot": {
"agentProfileVersion": 49,
"agentProfileVersion": 50,
"agentServerPackage": "@github/copilot",
"agentServerVersion": "1.0.88",
"agentRuntimePackage": null,
"agentRuntimeVersion": null,
"commandDigest": "sha256:37a8f6a540a7417bb12becbf283158df8cca925c5136ecc0db14597441fff702",
"commandDigest": "sha256:d8f89c8e75883a793122ed908016b7730ededa6c3df741f23298c2445d7e6fc4",
"requiresProviderPolicy": true
},
"claude": {
@@ -47,7 +47,7 @@ pub(crate) fn acpx_release_profile(agent: &str) -> Option<AcpxReleaseProfile> {
agent_runtime_package: None,
agent_runtime_version: None,
command_digest:
"sha256:37a8f6a540a7417bb12becbf283158df8cca925c5136ecc0db14597441fff702",
"sha256:d8f89c8e75883a793122ed908016b7730ededa6c3df741f23298c2445d7e6fc4",
requires_provider_policy: true,
},
"claude" => AcpxReleaseProfile {
@@ -7,9 +7,9 @@ import { fileURLToPath } from "node:url";
import { resolve, dirname } from "node:path";
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const fixture = resolve(root, "test/fixtures/copilot-profile-v49-identity.json");
const fixture = resolve(root, "test/fixtures/copilot-profile-v50-identity.json");
const historical = JSON.parse(readFileSync(resolve(root, "test/fixtures/copilot-profile-v12-identity.json"), "utf8"));
const declaration = { ...historical.declaration, agentProfileVersion: 49 };
const declaration = { ...historical.declaration, agentProfileVersion: 50 };
delete declaration.permissionIdentitySourceSha256;
const sources = {
displayEventSourceSha256: "src/drivers/acpx/copilot-events.ts",
@@ -31,6 +31,7 @@ const sources = {
nativeBackendSourceSha256: "src/backends/codex-native-backend.ts",
nativeBackendFactorySourceSha256: "src/backends/native-backend-factory.ts",
nativeInstructionsSourceSha256: "src/backends/runtime-context.ts",
providerLaunchSourceSha256: "src/live/runner-provider-launch.ts",
runtimeRequestBridgeSourceSha256: "src/live/runnerd-codex-transport.ts",
runtimeRequestFacadeSourceSha256: "src/drivers/codex/codex-session-notifications.ts",
runtimeRequestNotificationSourceSha256: "src/drivers/codex/codex-thread-normalization.ts",
@@ -38,6 +38,7 @@ const SEMANTIC_RECEIPT_SOURCES = [
["../../contracts/completion-result.ts", "semanticCompletionContractSourceSha256"],
["../../contracts/native-execution.ts", "nativeExecutionSourceSha256"],
["installation-integrity.ts", "guardedInstallationSourceSha256"],
["../../live/runner-provider-launch.ts", "providerLaunchSourceSha256"],
["../../live/runnerd-codex-transport.ts", "runtimeRequestBridgeSourceSha256"],
["../codex/codex-session-notifications.ts", "runtimeRequestFacadeSourceSha256"],
["../codex/codex-thread-normalization.ts", "runtimeRequestNotificationSourceSha256"],
@@ -85,10 +86,20 @@ async function withCopilotTestPlatform<T>(arch: "x64" | "arm64", run: () => Prom
vi.mock("./installation-integrity.js", () => ({ verifyNativeAcpxInstallation: vi.fn() }));
describe("Copilot build-owned installation", () => {
it("admits profile49 after bounded completion-recovery compatibility revalidation", () => {
expect(QUALIFIED_ACPX_PROFILES.copilot.agentProfileVersion).toBe(49);
it("admits the current profile after launch preparation extraction", () => {
expect(QUALIFIED_ACPX_PROFILES.copilot.agentProfileVersion).toBe(50);
expect(QUALIFIED_ACPX_PROFILES.copilot.qualificationStatus).toBeUndefined();
expect(QUALIFIED_ACPX_PROFILES.copilot.commandDigest).toBe("sha256:37a8f6a540a7417bb12becbf283158df8cca925c5136ecc0db14597441fff702");
expect(QUALIFIED_ACPX_PROFILES.copilot.commandDigest).toBe("sha256:d8f89c8e75883a793122ed908016b7730ededa6c3df741f23298c2445d7e6fc4");
});
it("preserves v49 while binding the extracted provider launch builder", () => {
const prior = JSON.parse(readFileSync(new URL("../../../test/fixtures/copilot-profile-v49-identity.json", import.meta.url), "utf8"));
const current = JSON.parse(readFileSync(new URL("../../../test/fixtures/copilot-profile-v50-identity.json", import.meta.url), "utf8"));
expect(prior.commandDigest).toBe("sha256:37a8f6a540a7417bb12becbf283158df8cca925c5136ecc0db14597441fff702");
expect(Object.keys(current.declaration).filter(key => current.declaration[key] !== prior.declaration[key]).sort()).toEqual([
"agentProfileVersion", "profileCompatibilitySourceSha256", "providerLaunchSourceSha256", "runtimeRequestBridgeSourceSha256",
]);
expect(isSupportedAcpxProfileVersion("copilot", 49)).toBe(true);
});
it("preserves qualified v48 while binding completion-proposal recovery in v49", async () => {
@@ -48,12 +48,12 @@ export const QUALIFIED_ACPX_PROFILE_DATA = {
"protocolVersion": 1,
"acpxVersion": "0.13.1",
"agent": "copilot",
"agentProfileVersion": 49,
"agentProfileVersion": 50,
"agentServerPackage": "@github/copilot",
"agentServerVersion": "1.0.88",
"agentRuntimePackage": null,
"agentRuntimeVersion": null,
"commandDigest": "sha256:37a8f6a540a7417bb12becbf283158df8cca925c5136ecc0db14597441fff702",
"commandDigest": "sha256:d8f89c8e75883a793122ed908016b7730ededa6c3df741f23298c2445d7e6fc4",
"permissionPolicy": "interactive"
},
"claude": {
@@ -2,13 +2,13 @@ import { QUALIFIED_ACPX_PROFILE_DATA } from "./generated-profiles.js";
/** Decodable historical profile revisions, not permission to launch them.
* Exact current profile/package/digest admission is checked separately. */
type HistoricalAcpxProfileVersion = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48;
type HistoricalAcpxProfileVersion = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49;
type CurrentAcpxProfileVersion = typeof QUALIFIED_ACPX_PROFILE_DATA[keyof typeof QUALIFIED_ACPX_PROFILE_DATA]["agentProfileVersion"];
export type AcpxProfileVersion = HistoricalAcpxProfileVersion | CurrentAcpxProfileVersion;
const historicalVersions: Readonly<Record<string, readonly HistoricalAcpxProfileVersion[]>> = {
pi: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27], claude: [1, 2, 3, 4, 5], codex: [1, 2, 3, 4, 5],
grok: [1, 2, 3, 4, 5], copilot: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48],
grok: [1, 2, 3, 4, 5], copilot: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
cursor: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
};
@@ -0,0 +1,63 @@
import { describe, expect, it } from "vitest";
import { createRunnerProviderLaunch, type RunnerProviderLaunchEnvironment, type RunnerProviderLaunchRequirements } from "./runner-provider-launch.js";
const requirements: RunnerProviderLaunchRequirements = {
identity: { runnerInstanceId: "runner", environmentLeaseId: "lease", runId: "run",
normalizedSessionId: "session", turnId: "turn", itemId: "item" },
provider: "codex", model: "selected-model", approvalPolicy: "on-request",
instructions: "Follow the assigned instructions.", runtimeContext: null,
readOnly: true, preparedConversation: false, includeCollaborationModeInstructions: false,
settings: {},
};
const environment: RunnerProviderLaunchEnvironment = {
options: { codexArgs: ["app-server"] }, root: "/execution/state", cwd: "/execution/workspace",
codexHome: "/execution/home/.codex", providerNodeCommand: "/runtime/node",
codexCommand: "/runtime/codex", opencodeProxyPath: "/runtime/opencode-proxy.cjs",
acpxSidecarPath: "/runtime/acpx-sidecar.cjs",
};
describe("built-in provider launch preparation", () => {
it("keeps Core's selection and policy when the execution environment changes", () => {
const before = structuredClone(requirements);
const local = createRunnerProviderLaunch(requirements, environment);
const remote = createRunnerProviderLaunch(requirements, { ...environment,
cwd: "/guest/project", codexCommand: "/guest/bin/codex" });
expect(local).toMatchObject({ model: "selected-model", approvalPolicy: "on-request",
readOnly: true, collaborationMode: "plan", instructions: requirements.instructions });
expect(remote).toEqual({ ...local, cwd: "/guest/project", command: "/guest/bin/codex" });
expect(requirements).toEqual(before);
});
it("preserves the ACPX profile, run identity, and permission policy", () => {
const launch = createRunnerProviderLaunch({ ...requirements, provider: "acpx",
model: "claude-selected", settings: { acpxAgent: "claude", acpxPermissionMode: "deny-all" } }, environment);
expect(launch).toMatchObject({ kind: "acpx", agent: "claude", model: "claude-selected",
sidecarCommand: "/runtime/node", sidecarArgs: ["/runtime/acpx-sidecar.cjs"],
runId: "run", normalizedSessionId: "session", permissionMode: "deny-all",
permissionModePinned: true, providerPolicy: { readOnly: true },
instructions: requirements.instructions });
expect(launch.commandDigest).toMatch(/^sha256:[a-f0-9]{64}$/);
});
it("keeps the OpenCode facade shape and prepared conversation mode", () => {
expect(createRunnerProviderLaunch({ ...requirements, provider: "opencode", preparedConversation: true }, environment))
.toMatchObject({ kind: "opencode", driver: "opencode_server", command: "/runtime/node",
args: ["/runtime/opencode-proxy.cjs"], conversationMode: "prepared", collaborationMode: "plan" });
expect(createRunnerProviderLaunch({ ...requirements, provider: "opencode" }, environment))
.not.toHaveProperty("readOnly");
});
it("uses the existing permission builder when the environment supplies no argument override", () => {
const launch = createRunnerProviderLaunch(requirements, { ...environment,
options: { environment: { HOME: "/execution/home" } } });
expect(launch.args).toEqual(expect.arrayContaining(["app-server"]));
expect(JSON.stringify(launch.args)).toContain("paperclip-runner-workspace-read-only");
});
it("rejects missing managed profiles before provider launch", () => {
expect(() => createRunnerProviderLaunch({ ...requirements, provider: "claude_managed" }, environment))
.toThrow("requires a qualified managed profile");
expect(() => createRunnerProviderLaunch({ ...requirements, provider: "aws_agentcore" }, environment))
.toThrow("requires a qualified AgentCore profile");
});
});
@@ -0,0 +1,304 @@
import { resolve } from "node:path";
import { codexExecutableReadOnlyRoots } from "../drivers/codex/codex-security-config.js";
import { createIsolatedCodexAppServerArgs } from "../drivers/codex/codex-app-server-driver.js";
import { usesPreconfiguredHome } from "../drivers/preconfigured-home.js";
import { resolveQualifiedAcpxProfile } from "../drivers/acpx/qualified-profiles.js";
import { resolveAcpxProviderMode } from "../drivers/acpx/provider-mode.js";
import type { DurableRecoveryIdentity } from "../contracts/durable-recovery.js";
import type { NativeRuntimeContextSnapshot } from "../contracts/runtime-context.js";
import type { CapabilityRunnerdCodexTransportOptions } from "./runnerd-codex-transport.js";
/** Core's provider inputs. Executable paths and filesystem layout are supplied separately. */
export interface RunnerProviderLaunchRequirements {
identity: DurableRecoveryIdentity;
provider: NonNullable<CapabilityRunnerdCodexTransportOptions["provider"]>;
model: string | null;
approvalPolicy: "never" | "on-request" | "untrusted";
readOnly: boolean;
preparedConversation: boolean;
includeCollaborationModeInstructions: boolean;
settings: Pick<CapabilityRunnerdCodexTransportOptions,
"acpxAgent" | "acpxMode" | "acpxPermissionMode" | "acpxPermissionModePinned" |
"piThinkingLevel" | "claudeEffort" | "managedProfile" | "agentCoreProfile">;
instructions: string;
runtimeContext: NativeRuntimeContextSnapshot | null;
}
/** Locations and provider settings resolved by the built-in execution environment. */
export interface RunnerProviderLaunchEnvironment {
options: Pick<CapabilityRunnerdCodexTransportOptions,
"acpxRuntimeDirectory" | "homeMode" | "environment" | "codexArgs" |
"runnerFilesystemRoot" | "disableCodexProjectInstructions" | "externallySandboxed">;
root: string;
cwd: string;
codexHome: string;
providerNodeCommand: string;
codexCommand?: string;
opencodeProxyPath: string;
acpxSidecarPath: string;
}
export function createRunnerProviderLaunch(
requirements: RunnerProviderLaunchRequirements,
input: RunnerProviderLaunchEnvironment,
): Record<string, unknown> {
const { identity, instructions: baseInstructions, runtimeContext, settings, provider } = requirements;
const acpxAgent = provider === "acpx" ? settings.acpxAgent ?? "codex" : null;
const requestedModel = requirements.model ?? "";
const includeCodexCollaborationInstructions = provider === "codex" &&
requirements.includeCollaborationModeInstructions;
const { codexHome, providerNodeCommand, codexCommand: effectiveCodexCommand,
opencodeProxyPath, acpxSidecarPath } = input;
const acpxProfile =
provider === "acpx"
? resolveQualifiedAcpxProfile(acpxAgent!, requestedModel)
: null;
const managedProfile = settings.managedProfile;
const agentCoreProfile = settings.agentCoreProfile;
if (provider === "claude_managed") {
if (!managedProfile) {
throw new Error(
"Claude Managed runner transport requires a qualified managed profile",
);
}
if (requestedModel !== managedProfile.model) {
throw new Error(
"Claude Managed requested model does not match its qualified profile",
);
}
}
if (provider === "aws_agentcore") {
if (!agentCoreProfile) {
throw new Error(
"AWS AgentCore runner transport requires a qualified AgentCore profile",
);
}
if (requestedModel !== agentCoreProfile.model) {
throw new Error(
"AWS AgentCore requested model does not match its qualified profile",
);
}
}
const selectedAcpxMode = provider === "acpx"
? resolveAcpxProviderMode(acpxProfile!.agent, settings.acpxMode) : undefined;
return provider === "acpx"
? {
kind: "acpx",
provider: "acpx",
driver: "acpx_runtime",
providerVersion: acpxProfile!.acpxVersion,
agent: acpxProfile!.agent,
model: requestedModel,
acpxVersion: acpxProfile!.acpxVersion,
agentServerPackage: acpxProfile!.agentServerPackage,
agentServerVersion: acpxProfile!.agentServerVersion,
agentRuntimePackage: acpxProfile!.agentRuntimePackage,
agentRuntimeVersion: acpxProfile!.agentRuntimeVersion,
commandDigest: acpxProfile!.commandDigest,
sidecarCommand: providerNodeCommand,
sidecarArgs: [acpxSidecarPath],
runtimeDirectory:
input.options.acpxRuntimeDirectory ??
resolve(input.root, "acpx"),
normalizedSessionId: identity.normalizedSessionId,
runId: identity.runId,
cwd: input.cwd,
instructions: baseInstructions,
providerPolicy: { readOnly: requirements.readOnly },
...(selectedAcpxMode === undefined ? {} : { mode: selectedAcpxMode }),
...(acpxProfile!.agent === "pi" ? { piThinkingLevel: settings.piThinkingLevel } : {}),
...(acpxProfile!.agent === "claude" && settings.claudeEffort ? { claudeEffort: settings.claudeEffort } : {}),
permissionMode: resolveRunnerdAcpxPermissionMode(
settings.acpxPermissionMode,
),
permissionModePinned:
settings.acpxPermissionModePinned ?? true,
runtimeContext,
}
: provider === "claude_managed"
? {
kind: "claude_managed",
model: managedProfile!.model,
profileId: managedProfile!.profileId,
anthropicAgentId: managedProfile!.anthropicAgentId,
agentVersion: managedProfile!.agentVersion,
environmentId: managedProfile!.environmentId,
betaVersion: managedProfile!.betaVersion,
maxSessionListCostUsd: managedProfile!.maxSessionListCostUsd,
instructions: baseInstructions,
runtimeContext,
}
: provider === "aws_agentcore"
? {
kind: "aws_agentcore",
model: agentCoreProfile!.model,
profileId: agentCoreProfile!.profileId,
region: agentCoreProfile!.region,
accountId: agentCoreProfile!.accountId,
harnessArn: agentCoreProfile!.harnessArn,
harnessVersion: agentCoreProfile!.harnessVersion,
endpointArn: agentCoreProfile!.endpointArn,
endpointQualifier: agentCoreProfile!.endpointQualifier,
agentRuntimeArn: agentCoreProfile!.agentRuntimeArn,
memoryArn: agentCoreProfile!.memoryArn,
memoryId: agentCoreProfile!.memoryId,
invocationRoleArn: agentCoreProfile!.invocationRoleArn,
contextBucket: agentCoreProfile!.contextBucket,
contextPrefix: agentCoreProfile!.contextPrefix,
contextKmsKeyArn: agentCoreProfile!.contextKmsKeyArn,
qualificationRevision:
agentCoreProfile!.qualificationRevision,
eventExpiryDays: agentCoreProfile!.eventExpiryDays,
maxEstimatedSessionCostUsd:
agentCoreProfile!.maxEstimatedSessionCostUsd,
maxIterations: agentCoreProfile!.maxIterations,
maxOutputTokens: agentCoreProfile!.maxOutputTokens,
timeoutSeconds: agentCoreProfile!.timeoutSeconds,
instructions: baseInstructions,
runtimeContext,
}
: {
kind: provider,
provider,
...(input.options.homeMode === "preconfigured" ? { preconfiguredHome: { HOME: input.options.environment!.HOME, CODEX_HOME: codexHome } } : {}),
driver:
provider === "opencode"
? "opencode_server"
: "codex_app_server",
providerVersion:
provider === "opencode" ? "1.18.34" : "codex-app-server-v1",
command:
provider === "opencode"
? providerNodeCommand
: effectiveCodexCommand!,
args:
provider === "opencode"
? [opencodeProxyPath]
: (input.options.codexArgs ??
createRunnerdCodexAppServerArgs({
environment: input.options.environment,
codexHome,
workingDirectory: input.cwd,
runtimeStateRoot: input.options.runnerFilesystemRoot ?? input.root,
codexCommand: effectiveCodexCommand,
instructionWorkingCopyRoot: runtimeContext?.instructions.workingCopy?.rootPath,
disableProjectInstructions: input.options.disableCodexProjectInstructions,
readOnlyRoots: [
...trustedRuntimeReadOnlyRoots(
input.options.environment,
),
...(runtimeContext
? [
resolve(codexHome, "skills"),
runtimeContext.instructions.bundle.rootPath,
...runtimeContext.skills.map(
(skill) => skill.bundle.rootPath,
),
]
: []),
],
})),
cwd: input.cwd,
model: requirements.model,
approvalPolicy:
requirements.approvalPolicy,
externallySandboxed:
provider === "codex" &&
input.options.externallySandboxed === true,
...(provider === "codex" && requirements.readOnly ? { readOnly: true } : {}),
instructions:
provider === "codex"
? withCodexCollaborationRuntimeInstructions(
baseInstructions,
includeCodexCollaborationInstructions,
)
: baseInstructions,
collaborationMode:
requirements.readOnly
? "plan"
: "default",
...(requirements.preparedConversation
? { conversationMode: "prepared" }
: {}),
includeCollaborationModeInstructions:
includeCodexCollaborationInstructions,
...(provider === "codex"
? { includeSkillInstructions: runtimeContext !== null }
: {}),
runtimeContext,
};
}
const CODEX_COLLABORATION_RUNTIME_INSTRUCTIONS = `## Codex-style collaboration
- Before the first tool call in a turn, send a brief commentary update describing the immediate work you are starting.
- During tool-driven work, send concise commentary updates at meaningful transitions so the user can follow progress without opening raw logs.
- Reserve \`report_progress\` for meaningful durable milestones on longer work. Do not call it merely to create a completion comment on a short run; Paperclip materializes the final assistant response as the durable completion comment.
- Invoke the semantic completion tool exactly once before the final assistant response. After it succeeds, send one self-contained final response with the outcome and verification, then do not call another tool. The completion tool records task disposition; Paperclip keeps receiving your answer until the provider turn ends.`;
export function withCodexCollaborationRuntimeInstructions(
instructions: string,
enabled = true,
): string {
if (!enabled) return instructions;
const base = instructions.trimEnd();
return `${base}\n\n${CODEX_COLLABORATION_RUNTIME_INSTRUCTIONS}`;
}
export function resolveRunnerdAcpxPermissionMode(
configured: CapabilityRunnerdCodexTransportOptions["acpxPermissionMode"],
): NonNullable<CapabilityRunnerdCodexTransportOptions["acpxPermissionMode"]> {
return configured ?? "approve-all";
}
export function trustedRuntimeReadOnlyRoots(
environment: NodeJS.ProcessEnv | undefined,
): string[] {
const path = environment?.PATH ?? "";
const roots = new Set<string>();
for (const entry of path.split(process.platform === "win32" ? ";" : ":")) {
if (entry === "/opt/homebrew" || entry.startsWith("/opt/homebrew/")) {
roots.add("/opt/homebrew");
} else if (entry === "/usr/local" || entry.startsWith("/usr/local/")) {
roots.add("/usr/local");
} else if (entry === "/opt/local" || entry.startsWith("/opt/local/")) {
roots.add("/opt/local");
} else if (entry === "/nix/store" || entry.startsWith("/nix/store/")) {
roots.add("/nix/store");
}
}
return [...roots];
}
export function createRunnerdCodexAppServerArgs(input: {
environment: NodeJS.ProcessEnv | undefined;
codexHome: string;
codexCommand?: string;
workingDirectory?: string;
runtimeStateRoot?: string;
readOnlyRoots?: string[];
instructionWorkingCopyRoot?: string;
disableProjectInstructions?: boolean;
}): string[] {
// The filesystem policy denies HOME and CODEX_HOME to keep credentials and
// runner state outside provider reach. Always bind those names to the actual
// isolated runner home; a stale controller environment must never cause the
// execution workspace itself to become an explicit deny root.
const args = [
...(input.disableProjectInstructions ? ["-c", "project_doc_max_bytes=0"] : []),
...createIsolatedCodexAppServerArgs(
{
...input.environment,
HOME: usesPreconfiguredHome(input.environment) ? input.environment?.HOME : input.codexHome,
CODEX_HOME: input.codexHome,
},
[...(input.readOnlyRoots ?? []), ...codexExecutableReadOnlyRoots(input.environment ?? {}, input.codexCommand)],
input.instructionWorkingCopyRoot,
usesPreconfiguredHome(input.environment) && input.runtimeStateRoot ? [input.runtimeStateRoot] : [],
),
];
if (usesPreconfiguredHome(input.environment) && input.workingDirectory) {
args.unshift("-c", `projects={${JSON.stringify(input.workingDirectory)}={trust_level="trusted"}}`);
}
return args;
}
@@ -1,3 +1,5 @@
import { createRunnerProviderLaunch, createRunnerdCodexAppServerArgs, trustedRuntimeReadOnlyRoots } from "./runner-provider-launch.js";
export { createRunnerdCodexAppServerArgs, resolveRunnerdAcpxPermissionMode, trustedRuntimeReadOnlyRoots, withCodexCollaborationRuntimeInstructions } from "./runner-provider-launch.js";
import { applyProviderObservabilityEnvironment, redactObservabilityDiagnostic } from "../drivers/agent-observability.js";
import type { RunnerExecutionDriver } from "../control-plane/runner-execution-driver.js";
import { resolvePinnedOpenCodeCommand } from "../drivers/opencode/opencode-server-driver.js";
@@ -11,7 +13,6 @@ import { preconfiguredHomeEnvironment, preconfiguredCodexHome, usesPreconfigured
import { isAcpxCanonicalInputMethod } from "../drivers/acpx/profile-extensions.js";
import { RunnerdTraceFrameIndex } from "./runnerd-trace-frame-index.js";
import { waitForWarmAttachmentReadiness } from "./warm-attachment-readiness.js";
import { codexExecutableReadOnlyRoots } from "../drivers/codex/codex-security-config.js";
import { resolveCodexCommand } from "../drivers/codex/codex-command.js";
import { isCanonicalProviderEventType } from "../provider-events.js";
import { execFileSync } from "node:child_process";
@@ -46,7 +47,6 @@ import { createSanitizedCodexEnvironment } from "../drivers/codex/app-server-tra
import {
CodexAppServerDriver,
codexSemanticToolSpecs,
createIsolatedCodexAppServerArgs,
} from "../drivers/codex/codex-app-server-driver.js";
import type {
DurableRecoveryCommittedEvent,
@@ -72,7 +72,6 @@ import {
type DurablePrpControlPlaneOptions,
} from "../control-plane/durable-prp-control-plane.js";
import {
resolveQualifiedAcpxProfile,
type QualifiedAcpxAgent,
} from "../drivers/acpx/qualified-profiles.js";
import { ACPX_CREDENTIAL_BINDING_ENV, createAcpxCredentialBinding, createSanitizedAcpxSpawnInput } from "../drivers/acpx/environment.js";
@@ -149,22 +148,6 @@ function readLocalProcessStartedAt(pid: number): string | null {
return null;
}
const CODEX_COLLABORATION_RUNTIME_INSTRUCTIONS = `## Codex-style collaboration
- Before the first tool call in a turn, send a brief commentary update describing the immediate work you are starting.
- During tool-driven work, send concise commentary updates at meaningful transitions so the user can follow progress without opening raw logs.
- Reserve \`report_progress\` for meaningful durable milestones on longer work. Do not call it merely to create a completion comment on a short run; Paperclip materializes the final assistant response as the durable completion comment.
- Invoke the semantic completion tool exactly once before the final assistant response. After it succeeds, send one self-contained final response with the outcome and verification, then do not call another tool. The completion tool records task disposition; Paperclip keeps receiving your answer until the provider turn ends.`;
export function withCodexCollaborationRuntimeInstructions(
instructions: string,
enabled = true,
): string {
if (!enabled) return instructions;
const base = instructions.trimEnd();
return `${base}\n\n${CODEX_COLLABORATION_RUNTIME_INSTRUCTIONS}`;
}
const CONTROL_PLANE_STATE_MAX_BYTES = 256 * 1024 * 1024;
function readControlPlaneState(directory: string): Record<string, unknown> {
@@ -3408,12 +3391,6 @@ export function createCapabilityRunnerdProviderEnvironment(input: Parameters<typ
return applyProviderObservabilityEnvironment(createCapabilityRunnerdProviderEnvironmentBase(input), input.options.observability, input.provider === "acpx");
}
export function resolveRunnerdAcpxPermissionMode(
configured: CapabilityRunnerdCodexTransportOptions["acpxPermissionMode"],
): NonNullable<CapabilityRunnerdCodexTransportOptions["acpxPermissionMode"]> {
return configured ?? "approve-all";
}
const OPEN_CODE_RUNNER_ENVIRONMENT_KEYS = new Set([
"PAPERCLIP_AI_PROVIDER_KEY",
"PAPERCLIP_AI_PROVIDER_URL",
@@ -3475,58 +3452,6 @@ export function resolveSourceCodexHome(
return home ? resolve(home, ".codex") : null;
}
export function trustedRuntimeReadOnlyRoots(
environment: NodeJS.ProcessEnv | undefined,
): string[] {
const path = environment?.PATH ?? "";
const roots = new Set<string>();
for (const entry of path.split(process.platform === "win32" ? ";" : ":")) {
if (entry === "/opt/homebrew" || entry.startsWith("/opt/homebrew/")) {
roots.add("/opt/homebrew");
} else if (entry === "/usr/local" || entry.startsWith("/usr/local/")) {
roots.add("/usr/local");
} else if (entry === "/opt/local" || entry.startsWith("/opt/local/")) {
roots.add("/opt/local");
} else if (entry === "/nix/store" || entry.startsWith("/nix/store/")) {
roots.add("/nix/store");
}
}
return [...roots];
}
export function createRunnerdCodexAppServerArgs(input: {
environment: NodeJS.ProcessEnv | undefined;
codexHome: string;
codexCommand?: string;
workingDirectory?: string;
runtimeStateRoot?: string;
readOnlyRoots?: string[];
instructionWorkingCopyRoot?: string;
disableProjectInstructions?: boolean;
}): string[] {
// The filesystem policy denies HOME and CODEX_HOME to keep credentials and
// runner state outside provider reach. Always bind those names to the actual
// isolated runner home; a stale controller environment must never cause the
// execution workspace itself to become an explicit deny root.
const args = [
...(input.disableProjectInstructions ? ["-c", "project_doc_max_bytes=0"] : []),
...createIsolatedCodexAppServerArgs(
{
...input.environment,
HOME: usesPreconfiguredHome(input.environment) ? input.environment?.HOME : input.codexHome,
CODEX_HOME: input.codexHome,
},
[...(input.readOnlyRoots ?? []), ...codexExecutableReadOnlyRoots(input.environment ?? {}, input.codexCommand)],
input.instructionWorkingCopyRoot,
usesPreconfiguredHome(input.environment) && input.runtimeStateRoot ? [input.runtimeStateRoot] : [],
),
];
if (usesPreconfiguredHome(input.environment) && input.workingDirectory) {
args.unshift("-c", `projects={${JSON.stringify(input.workingDirectory)}={trust_level="trusted"}}`);
}
return args;
}
export function unwrapToolResponse(response: Record<string, unknown>, preserveEnvelope = false): {
readonly __paperclipSemanticToolOutcome: true;
readonly result: unknown;
@@ -4967,10 +4892,6 @@ class DurablePrpCodexTransport implements CodexAppServerTransport {
);
const acpxAgent =
provider === "acpx" ? (this.options.acpxAgent ?? "codex") : null;
const requestedModel = typeof params.model === "string" ? params.model : "";
const includeCodexCollaborationInstructions =
provider === "codex" &&
record(params.config).include_collaboration_mode_instructions !== false;
const unboundBaseInstructions = String(
params.developerInstructions ?? params.baseInstructions ?? "You are a Paperclip agent.",
);
@@ -4981,197 +4902,25 @@ class DurablePrpCodexTransport implements CodexAppServerTransport {
runtimeContext.instructions.bundle.rootPath,
)
: unboundBaseInstructions;
const acpxProfile =
provider === "acpx"
? resolveQualifiedAcpxProfile(acpxAgent!, requestedModel)
: null;
const managedProfile = this.options.managedProfile;
const agentCoreProfile = this.options.agentCoreProfile;
if (provider === "claude_managed") {
if (!managedProfile) {
throw new Error(
"Claude Managed runner transport requires a qualified managed profile",
);
}
if (requestedModel !== managedProfile.model) {
throw new Error(
"Claude Managed requested model does not match its qualified profile",
);
}
}
if (provider === "aws_agentcore") {
if (!agentCoreProfile) {
throw new Error(
"AWS AgentCore runner transport requires a qualified AgentCore profile",
);
}
if (requestedModel !== agentCoreProfile.model) {
throw new Error(
"AWS AgentCore requested model does not match its qualified profile",
);
}
}
const selectedAcpxMode = provider === "acpx"
? resolveAcpxProviderMode(acpxProfile!.agent, this.options.acpxMode) : undefined;
const completionContract = record(params.completionContract);
const runAttachTemplate = {
observeCredentials: this.options.observeCredentials !== false,
authorizedTools: this.#authorizedTools,
...(completionContract.revision &&
Array.isArray(completionContract.criterionIds)
? { completionContract }
: {}),
provider:
provider === "acpx"
? {
kind: "acpx",
provider: "acpx",
driver: "acpx_runtime",
providerVersion: acpxProfile!.acpxVersion,
agent: acpxProfile!.agent,
model: requestedModel,
acpxVersion: acpxProfile!.acpxVersion,
agentServerPackage: acpxProfile!.agentServerPackage,
agentServerVersion: acpxProfile!.agentServerVersion,
agentRuntimePackage: acpxProfile!.agentRuntimePackage,
agentRuntimeVersion: acpxProfile!.agentRuntimeVersion,
commandDigest: acpxProfile!.commandDigest,
sidecarCommand: providerNodeCommand,
sidecarArgs: [acpxSidecarPath],
runtimeDirectory:
this.options.acpxRuntimeDirectory ??
resolve(this.#root, "acpx"),
normalizedSessionId: identity.normalizedSessionId,
runId: identity.runId,
cwd: String(params.cwd ?? tmpdir()),
instructions: baseInstructions,
providerPolicy: { readOnly: params.permissions === "paperclip-runner-workspace-read-only" },
...(selectedAcpxMode === undefined ? {} : { mode: selectedAcpxMode }),
...(acpxProfile!.agent === "pi" ? { piThinkingLevel: this.options.piThinkingLevel } : {}),
...(acpxProfile!.agent === "claude" && this.options.claudeEffort ? { claudeEffort: this.options.claudeEffort } : {}),
permissionMode: resolveRunnerdAcpxPermissionMode(
this.options.acpxPermissionMode,
),
permissionModePinned:
this.options.acpxPermissionModePinned ?? true,
runtimeContext,
}
: provider === "claude_managed"
? {
kind: "claude_managed",
model: managedProfile!.model,
profileId: managedProfile!.profileId,
anthropicAgentId: managedProfile!.anthropicAgentId,
agentVersion: managedProfile!.agentVersion,
environmentId: managedProfile!.environmentId,
betaVersion: managedProfile!.betaVersion,
maxSessionListCostUsd: managedProfile!.maxSessionListCostUsd,
instructions: baseInstructions,
runtimeContext,
}
: provider === "aws_agentcore"
? {
kind: "aws_agentcore",
model: agentCoreProfile!.model,
profileId: agentCoreProfile!.profileId,
region: agentCoreProfile!.region,
accountId: agentCoreProfile!.accountId,
harnessArn: agentCoreProfile!.harnessArn,
harnessVersion: agentCoreProfile!.harnessVersion,
endpointArn: agentCoreProfile!.endpointArn,
endpointQualifier: agentCoreProfile!.endpointQualifier,
agentRuntimeArn: agentCoreProfile!.agentRuntimeArn,
memoryArn: agentCoreProfile!.memoryArn,
memoryId: agentCoreProfile!.memoryId,
invocationRoleArn: agentCoreProfile!.invocationRoleArn,
contextBucket: agentCoreProfile!.contextBucket,
contextPrefix: agentCoreProfile!.contextPrefix,
contextKmsKeyArn: agentCoreProfile!.contextKmsKeyArn,
qualificationRevision:
agentCoreProfile!.qualificationRevision,
eventExpiryDays: agentCoreProfile!.eventExpiryDays,
maxEstimatedSessionCostUsd:
agentCoreProfile!.maxEstimatedSessionCostUsd,
maxIterations: agentCoreProfile!.maxIterations,
maxOutputTokens: agentCoreProfile!.maxOutputTokens,
timeoutSeconds: agentCoreProfile!.timeoutSeconds,
instructions: baseInstructions,
runtimeContext,
}
: {
kind: provider,
provider,
...(this.options.homeMode === "preconfigured" ? { preconfiguredHome: { HOME: this.options.environment!.HOME, CODEX_HOME: codexHome } } : {}),
driver:
provider === "opencode"
? "opencode_server"
: "codex_app_server",
providerVersion:
provider === "opencode" ? "1.18.34" : "codex-app-server-v1",
command:
provider === "opencode"
? providerNodeCommand
: effectiveCodexCommand!,
args:
provider === "opencode"
? [opencodeProxyPath]
: (this.options.codexArgs ??
createRunnerdCodexAppServerArgs({
environment: this.options.environment,
codexHome,
workingDirectory: String(params.cwd ?? tmpdir()),
runtimeStateRoot: this.options.runnerFilesystemRoot ?? this.#root,
codexCommand: effectiveCodexCommand,
instructionWorkingCopyRoot: runtimeContext?.instructions.workingCopy?.rootPath,
disableProjectInstructions: this.options.disableCodexProjectInstructions,
readOnlyRoots: [
...trustedRuntimeReadOnlyRoots(
this.options.environment,
),
...(runtimeContext
? [
resolve(codexHome, "skills"),
runtimeContext.instructions.bundle.rootPath,
...runtimeContext.skills.map(
(skill) => skill.bundle.rootPath,
),
]
: []),
],
})),
cwd: String(params.cwd ?? tmpdir()),
model: typeof params.model === "string" ? params.model : null,
approvalPolicy:
params.approvalPolicy === "on-request" ||
params.approvalPolicy === "untrusted"
? params.approvalPolicy
: "never",
externallySandboxed:
provider === "codex" &&
this.options.externallySandboxed === true,
...(provider === "codex" && params.permissions === "paperclip-runner-workspace-read-only" ? { readOnly: true } : {}),
instructions:
provider === "codex"
? withCodexCollaborationRuntimeInstructions(
baseInstructions,
includeCodexCollaborationInstructions,
)
: baseInstructions,
collaborationMode:
params.permissions ===
"paperclip-runner-workspace-read-only"
? "plan"
: "default",
...(params.conversationMode === "prepared"
? { conversationMode: "prepared" }
: {}),
includeCollaborationModeInstructions:
includeCodexCollaborationInstructions,
...(provider === "codex"
? { includeSkillInstructions: runtimeContext !== null }
: {}),
runtimeContext,
},
...(completionContract.revision && Array.isArray(completionContract.criterionIds)
? { completionContract } : {}),
provider: createRunnerProviderLaunch({
identity, provider, model: typeof params.model === "string" ? params.model : null,
instructions: baseInstructions, runtimeContext, settings: this.options,
approvalPolicy: params.approvalPolicy === "on-request" || params.approvalPolicy === "untrusted"
? params.approvalPolicy : "never",
readOnly: params.permissions === "paperclip-runner-workspace-read-only",
preparedConversation: params.conversationMode === "prepared",
includeCollaborationModeInstructions: record(params.config).include_collaboration_mode_instructions !== false,
}, {
options: this.options, root: this.#root, cwd: String(params.cwd ?? tmpdir()),
codexHome, providerNodeCommand, codexCommand: effectiveCodexCommand,
opencodeProxyPath, acpxSidecarPath,
}),
};
// Preserve the first generation's provider attachment seed independently
// of bounded command history. The in-memory copy serves a live warm
@@ -0,0 +1,83 @@
{
"commandDigest": "sha256:d8f89c8e75883a793122ed908016b7730ededa6c3df741f23298c2445d7e6fc4",
"declaration": {
"schema": "paperclip.acpx_profile_declaration.v1",
"agent": "copilot",
"agentProfileVersion": 50,
"acpxVersion": "0.13.1",
"agentServerVersion": "1.0.88",
"protocolPolicyRevision": "copilot-agent-manual-v1",
"acpxPatchSha256": "00d6af17216cb0cad902b48633eb19bf0ec6b05837a984cb24661fca593f09c1",
"policySha256": "a4be69be43db84052560420a3ca546a665c9165573c24d543eb33d144ba138a3",
"distributionSourceSha256": "c0a65e247fc47b263bd369a3d5ab505c4b323d4e6493be8a9ecbeb0e9dbb9107",
"agentFilesBinding": "registered-runtime-context-v1",
"systemInstructionDelivery": "COPILOT_HOME/copilot-instructions.md:replace-under-lifetime-lease-before-launch:v1",
"sharedRuntimeContract": "paperclip.acpx-runtime-contract.v1",
"innerDistributionSourceSha256": "9bb08347eed01f1ab44e065c8b06ead9be3a25973d6e6329dc4c0a099096279a",
"upstreamAppSha256": "7b48282a19b5b0814a0c96ad5e3a125173d792cc55f9525b2effea962f6063c0",
"patchedAppSha256": "61f8eebe0c30cc03b311c6818b2acb158a6d16ca58c8bfac5ebd42db095c2679",
"messageIdentityContract": "copilot-native-message-id-v1",
"ownedDistributionDelivery": "COPILOT_CLI_DIST_DIR:lease-owned-guarded-inner-distribution:v1",
"permissionContextContract": "copilot-edit-permission-context-v1",
"permissionContextSourceSha256": "de2d38d702b3c574161af0c0c04790fb6f6347916eb3916ce7a131a8c229121b",
"permissionAdapterSourceSha256": "ee5929ed2ee647ad0369465dee9d51a00b2dd28e1ff735b43e969ddc9c164668",
"permissionLocationsSourceSha256": "f39a81da395b6e23aa2a1a45572a28846e5e81bfd3d764d9a456f74a79c752e9",
"permissionRedactionSourceSha256": "ad6770c69269087951790e2e87e22ac088e3d432769adf17ebc865ed512e6c4f",
"permissionClassifierSourceSha256": "1161eabd82e26133e3b3db3ab567f65d52808b03f176e93497e02c8330349fb4",
"semanticToolReceiptContract": "paperclip.semantic_tool_receipt.v2",
"semanticReceiptSourceSha256": "b2795726b2234a663fec1a6ca11f0551ae69882fe9e82aa39686e952d036e791",
"semanticBridgeSourceSha256": "89e3dde25ff35bfd4d7f520fd9d14af3cb9027f182a2d51431d298f1015be580",
"toolEvidenceSourceSha256": "6eef5039afc75bb851eaf9cd82a6f099e4bd398ca2deb59dd66f5b2a81a7a706",
"semanticNormalizedInputContract": "validated-forwarded-input-commit-v1",
"semanticSidecarSourceSha256": "cc90b59bdfe6a82f7fa3e819e8671f71f7b14047e68942e8086618ffbaacf59f",
"semanticDirectDriverSourceSha256": "ff572638f2cb5d9f8249ff8e2f412311c1e3af209ef0bf7e5ea9f10a21d91103",
"semanticValidationSourceSha256": "02fbb92681c78c5de5d2f1aae25aabc25a0e5df6b0ff4baccac652192a8da975",
"semanticNormalizationSourceSha256": "8b628b82e8eacc91cdcc6fdca2210ba4cf282f01e9c6f74e95ff271655b5047e",
"semanticCompletionContractSourceSha256": "f8b381e1ac2a880558f3e81968f0f8f05de3ded573d044fafc89f198f2ec0433",
"semanticValidatorsSourceSha256": "f22d9caf2035b600abc1a6625ae23ca97f1409d7e29ed5b7264bb8f9784c7dc9",
"semanticSchemaBundleSourceSha256": "016391a087cc217aafed4ba1f4efafc6e4881a7525952dce824b7f4d24530603",
"semanticSidecarProtocolSourceSha256": "03c0c95b900f9dc18f29f6be27b8c79bc0bcab29780190d46a74e95328081236",
"semanticSidecarReceiptCommitContract": "correlated-tool-resolve-v1",
"displayEventSourceSha256": "d72f9a6035c247bc6a42c067c05753076c54322c4b58984e93922f3325dc6877",
"displayProjectionSourceSha256": "75952606b26dd93bbc582c1f0a4424487377272ea745fb3a27ceae031fd5dc7e",
"configuredEnvironmentSourceSha256": "5c9008d121979a3a8987e6b8a5752172eafdc4a2b5d725a73f3bbb8fb83be8ff",
"configuredEnvironmentRustSourceSha256": "85c87fae62b8a9377e4f0a4c00302c7519fae4397b1c48253f8f2b7ba7faf994",
"profileActivitySourceSha256": "4fdb6b0f9125fd8372ba6f27945fa5c8a3d3b2ec891df544092e3dc7a75d5282",
"profileExtensionsSourceSha256": "a80ddc95eb4505095bfdbbf85c758199949ab20be9c84b34c77f762eb7180571",
"profileInstallationSourceSha256": "e4aacb08015fa9104dce2b0c7d150cc432231c8a3e07d2cec2a325b388f7f382",
"attachmentPolicySourceSha256": "4f7638b7cc64e18f6a4ba33fd46de2b3d49225e32aeab41f5c695b268fa4f8e2",
"singleReadEvidenceSourceSha256": "4069393405089bde613cecec04f5123c426594811da4c668bd96f0e7e283550f",
"nativeSessionRuntimeSourceSha256": "e8a3bee66a1ff1c6f251b5ae57453ffb908336da9c4a6d98f41f94f7ee94a8e8",
"nativeRuntimeContextSourceSha256": "28c28c850bceade8c72b3ea246485d2bc77bd6e1dab95b43e3b319e27ca944bf",
"nativeSessionContractSourceSha256": "22a8c96ce41ba4f03e976fc37f0cc7c5d05cee99fa789941da31ee1dab440b90",
"harnessSessionContractSourceSha256": "03f4cd7f76f34f6d82e009b66aa51f18f6e23dc235b660778060e35b6ea07412",
"harnessBackendSourceSha256": "dc827e281ae6731545b166ee4d709a4f67f594a556dcbe63c70fe8f1aca26249",
"harnessSessionSourceSha256": "81361733e86b56dd5a66415aefc6f72e69be24acc8d3417370154ebb7fef6e94",
"transportContractSourceSha256": "4fa9593226ff3280bc12140bfcbc2c0986e4cc8d4733381c334138dd03b08f46",
"nativeBackendSourceSha256": "2406483fd35a564971c22e10fc2bad26bae16ff5a3fb6c65690fcf156522ab6d",
"nativeBackendFactorySourceSha256": "7e431c926b76d53c4c08e3a4105353dcd34bd940f6588a1a68f79631f6feeb44",
"nativeInstructionsSourceSha256": "ee8df5d85b263d5d2d0dc9ede8602cb7daf6388687108fe05e2371f5f56c3492",
"providerLaunchSourceSha256": "2bd265438b88897ab57c73a180009d9f78c382c1576b8d9c16e4bae3dd01c45a",
"runtimeRequestBridgeSourceSha256": "ba198ea55c177906d1de215d119466805452b87abefa1db47a1ffabc205d7a73",
"runtimeRequestFacadeSourceSha256": "d0ed28e0c5ddad34db8f437e704c8a755eb0b47f27e08e44185f66d1d2205295",
"runtimeRequestNotificationSourceSha256": "6196c6175f11c69295dc00fc773201f4fdeca26c500653870253c43b81e65211",
"guardedInstallationSourceSha256": "f6d0c33de38259efefa0f4e0f9737cd30cfd3996a8e875e3fbdb8c72dc133dca",
"nativeExecutionSourceSha256": "fc7c6568feb0d8d709e9baa51839420c9b90336b4865a9b8405aba06e4d1e9c4",
"profileCompatibilitySourceSha256": "afbc27f9dcd824d14fc71552f0244614aaa7260a5b9b2cb9d148974c68a42ce6",
"installationSourceSha256": "a1c7c6f103b898216973e77ffbac0ef7572e250aa574d1a4065270e9dfa0dc2d",
"assetOwnershipSourceSha256": "1785e3f31e5dad5a13b53e25d8cf9482a9bd89a27b6c127830aed6b81acc605c",
"assetInstallerSourceSha256": "d3bd9514e5920d0cc3567aa50487fb534c57a6f66b8da0d3f22c5f6e499c841f",
"credentialBindingSourceSha256": "54fd09ad430dac04df98d829061f6701e73b5bf2a0f4de836d2ac36ee511009f",
"sidecarErrorSourceSha256": "b09af4577f8bf42eee7036b2ad9842202cfc763e72b53c3287f82c6090cdad80",
"profileSourceSha256": "f5538b3dbefa7634a332b87d5ededcefb56aa7e5790cede1c7a0d948a548a456",
"metadataProbeSourceSha256": "be4c8416edd27061109bc1f33d0c26071b4facbb3f651beaae6b3c0275cce727",
"permissionToolIdentitySourceSha256": "770b47305e571a81f344883057d0e4a482a1cd59ac77d045836593a8e739deb1",
"semanticContinuationSourceSha256": "eb877719ef32a935afa4ec93f0f1c43d58d55bc4e1042965febcac4c45ed851c",
"runtimeHostSourceSha256": "60e5454f030e87f2afa8b1fb120b26adb126b6b17d0e5e82f49c77f76f466cbb",
"runtimeAdapterSourceSha256": "e4c764c2c3c7dd655a965b39472bd1ad8d577d1e7258b25594b171c9429752b8",
"runtimeSandboxSourceSha256": "92dfa53f5a3ed0062913ae417eeccec243b430d444495efde2a8e9c4c02e78ea",
"cancellationSourceSha256": "a07d1a9e982dec0ae130c1ad1efa5bc75c6a39e013b730ba3ee45256f09ceeca",
"agentFilesSourceSha256": "fb32f6badc13dfa22f231479509b631b2f0eba0c99b1ab9f3cd5c0c601aa03ba",
"nativeDistributionSourceSha256": "aed327c389e957483a503cb1bb8b247ee7cd7ff4b528fb4567c39bcb4577690b"
}
}