From 41399e317a855af80375ea5780125bb37b3fd9de Mon Sep 17 00:00:00 2001 From: Dotta Date: Sun, 8 Nov 2026 20:36:13 -0600 Subject: [PATCH] fix(agents): say who sets up a Claude Managed Agent profile An agent asked to set up an Anthropic managed agent read the Paperclip Runner configuration doc, which named Claude Managed but not who creates its profile, and spent its reply window exploring hiring and adapter configuration. The doc and the profile-creation catalog entry now say that a board operator creates and qualifies the profile and that agents cannot. Co-Authored-By: Claude Opus 5.5 --- server/src/__tests__/board-access-denial.test.ts | 8 ++++++++ server/src/adapters/registry.ts | 2 +- server/src/routes/openapi.ts | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/server/src/__tests__/board-access-denial.test.ts b/server/src/__tests__/board-access-denial.test.ts index 98b20c19e37..e217af86064 100644 --- a/server/src/__tests__/board-access-denial.test.ts +++ b/server/src/__tests__/board-access-denial.test.ts @@ -5,6 +5,7 @@ import { describe, expect, it } from "vitest"; import { errorHandler } from "../middleware/index.js"; import { assertBoard, assertBoardOrgAccess, BOARD_ACCESS_REQUIRED_CODE } from "../routes/authz.js"; import { AGENT_CHAT_DIRECTIVE } from "../services/agent-conversations.js"; +import { buildOpenApiDocument } from "../routes/openapi.js"; const COMPANY_ID = "10000000-0000-4000-8000-000000000001"; const AGENT_ID = "20000000-0000-4000-8000-000000000002"; @@ -71,4 +72,11 @@ describe("board-only denial", () => { expect(AGENT_CHAT_DIRECTIVE).toContain("tell the person which control in the Paperclip web app to use, link its page when you know the route"); expect(AGENT_CHAT_DIRECTIVE).not.toContain("use permitted discovery to identify the supported operator path"); }); + + it("says in the API catalog who sets up a Claude Managed Agent profile", () => { + const post = buildOpenApiDocument().paths["/api/companies/{companyId}/managed-agent-profiles"].post; + expect(post["x-paperclip-authorization"]).toEqual({ actor: "board" }); + expect(post.description).toContain("Board only: agent credentials get 403"); + expect(post.description).toContain("explicitly acknowledges stateful retention"); + }); }); diff --git a/server/src/adapters/registry.ts b/server/src/adapters/registry.ts index d5b38bea0b7..a6f822946fc 100644 --- a/server/src/adapters/registry.ts +++ b/server/src/adapters/registry.ts @@ -644,7 +644,7 @@ const paperclipRunnerAdapter: ServerAdapterModule = { ) : buildNpmRuntimeCommandSpec(config, "codex", "@openai/codex@0.160.0"), agentConfigurationDoc: - "# Paperclip Runner\n\nAdapter: paperclip_runner\n\nRuns Codex, OpenCode, Claude Managed, AWS AgentCore, or ACPX Claude/Grok Build/Cursor/Pi through the Rust Paperclip runner and authenticated PRP transport. Pi accepts an explicit provider/model ID and uses the company credentials bound to the agent environment. GitHub Copilot requires a saved GitHub token and an explicitly selected available model. Managed providers use company-scoped qualified profiles, explicit retention acknowledgement, and spend limits.\n", + "# Paperclip Runner\n\nAdapter: paperclip_runner\n\nRuns Codex, OpenCode, Claude Managed, AWS AgentCore, or ACPX Claude/Grok Build/Cursor/Pi through the Rust Paperclip runner and authenticated PRP transport. Pi accepts an explicit provider/model ID and uses the company credentials bound to the agent environment. GitHub Copilot requires a saved GitHub token and an explicitly selected available model. Managed providers use company-scoped qualified profiles, explicit retention acknowledgement, and spend limits. A board operator creates each Claude Managed (Anthropic managed agent) profile through POST /api/companies/{companyId}/managed-agent-profiles; agent credentials cannot create, qualify or list one.\n", getConfigSchema: () => ({ fields: [ { diff --git a/server/src/routes/openapi.ts b/server/src/routes/openapi.ts index e4c2f54bb37..068495bba5e 100644 --- a/server/src/routes/openapi.ts +++ b/server/src/routes/openapi.ts @@ -7570,6 +7570,7 @@ registry.registerPath({ path: "/api/companies/{companyId}/managed-agent-profiles", tags: ["agents"], summary: "Create or operator-attest a Claude Managed Agent profile", + description: "Board only: agent credentials get 403. A Claude Managed Agent runs on Anthropic's managed-agents beta. A board operator creates the company profile with an Anthropic API-key secret and a limited environment (no hosts, no packages), attests its qualification and explicitly acknowledges stateful retention before it can be enabled.", request: { params: z.object({ companyId: z.string() }), body: jsonBody(