{"record":{"id":"0d3f625f708922c0","repo":"paperclipai/paperclip","slug":"local-filesystem-network-confinement-requires-the","errorCode":null,"errorMessage":"Local filesystem/network confinement requires the Claude CLI engine; ACP confinement is not supported.","messagePattern":"Local filesystem/network confinement requires the Claude CLI engine; ACP confinement is not supported\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/adapters/claude-local/src/server/acp.ts","lineNumber":84,"sourceCode":"  const raw = typeof value === \"string\" ? value.trim().toLowerCase() : \"\";\n  if (raw === \"acp\") return { engine: \"acp\", explicit: true };\n  if (raw === \"cli\") return { engine: \"cli\", explicit: true };\n  return { engine: \"acp\", explicit: false };\n}\n\nexport function resolveClaudeExecutionEngine(config: Record<string, unknown>): ClaudeEngineSelection {\n  return normalizeEngine(config.engine);\n}\n\nexport async function resolveClaudeExecutionEngineForRun(\n  input: ClaudeEngineResolutionInput,\n): Promise<ClaudeEngineSelection> {\n  const selection = normalizeEngine(input.config.engine);\n  const filesystemScope = parseLocalProcessFilesystemScope(input.config.filesystemScope);\n  const networkScope = parseLocalProcessNetworkScope(input.config.networkScope);\n  if (filesystemScope || networkScope) {\n    if (selection.explicit && selection.engine === \"acp\") {\n      throw new Error(\"Local filesystem/network confinement requires the Claude CLI engine; ACP confinement is not supported.\");\n    }\n    return {\n      engine: \"cli\",\n      explicit: selection.explicit,\n      ...(!selection.explicit\n        ? { fallbackReason: \"Local filesystem/network scope requires spawn-level confinement in the CLI lane.\" }\n        : {}),\n    };\n  }\n  if (selection.explicit || selection.engine !== \"acp\") return selection;\n\n  const fallbackReason = await defaultClaudeAcpFallbackReason(input);\n  if (!fallbackReason) return selection;\n  return { engine: \"cli\", explicit: false, fallbackReason };\n}\n\nexport function formatClaudeAcpFallbackMessage(reason: string): string {\n  return `[paperclip] Claude ACP default unavailable; falling back to Claude CLI. ${reason} Set engine=acp to require ACP or engine=cli to silence this fallback.\\n`;","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/adapters/claude-local/src/server/acp.ts#L66-L102","documentation":"Thrown by resolveClaudeExecutionEngineForRun when the adapter config explicitly sets engine='acp' AND a local filesystemScope or networkScope confinement is also configured. ACP (the agent client protocol lane) cannot enforce spawn-level sandboxing, so requesting confinement under an explicitly-chosen ACP engine is an unsatisfiable combination; the function refuses instead of silently ignoring the confinement request.","triggerScenarios":"Adapter config with { engine: 'acp', filesystemScope: 'workspace' } or { engine: 'acp', networkScope: <scope> }. normalizeEngine marks engine explicit=true, parseLocalProcessFilesystemScope/NetworkScope return non-null, and the explicit-acp branch throws.","commonSituations":"An operator hardening a Claude run with network/filesystem confinement while also pinning engine=acp for performance; a config template that sets both without realizing ACP can't sandbox; upgrading a config that previously relied on implicit fallback.","solutions":["Drop engine='acp' (leave unset) so the resolver auto-falls back to CLI with a fallbackReason, preserving confinement.","Or set engine='cli' explicitly to use the CLI lane that supports spawn-level confinement.","If ACP is required, remove filesystemScope and networkScope from the config (accept no local confinement)."],"exampleFix":"// before\nconfig = { engine: \"acp\", filesystemScope: \"workspace\" };\n// after\nconfig = { engine: \"cli\", filesystemScope: \"workspace\" };","handlingStrategy":"validation","validationCode":"const hasConfinement =\n  parseLocalProcessFilesystemScope(config.filesystemScope) ||\n  parseLocalProcessNetworkScope(config.networkScope);\nif (config.engine === \"acp\" && hasConfinement) {\n  // pick one: confinement -> use cli; or acp -> drop confinement\n  config.engine = \"cli\";\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat engine=acp and filesystemScope/networkScope as mutually exclusive in config validation.","Validate adapter config at load time, surfacing the conflict before run start.","Prefer leaving engine unset so the resolver can auto-fallback with a logged reason."],"tags":["claude","acp","engine-selection","confinement","configuration"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}