From f467f3d826a3d3fa137393cd7fd0d8f567dedb3c Mon Sep 17 00:00:00 2001 From: plind-dm <59729252+plind-dm@users.noreply.github.com> Date: Fri, 3 Apr 2026 23:04:44 +0900 Subject: [PATCH 1/2] fix(import): read agent role from frontmatter before defaulting to "agent" Package imports defaulted every agent's role to "agent" when the extension block omitted the role field, even when the YAML frontmatter contained the correct role (e.g. "ceo"). Read from frontmatter as a fallback before the "agent" default so imported CEOs retain their role. Closes #1990 --- server/src/services/company-portability.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/services/company-portability.ts b/server/src/services/company-portability.ts index c73d9eaa..097e62fc 100644 --- a/server/src/services/company-portability.ts +++ b/server/src/services/company-portability.ts @@ -2393,7 +2393,7 @@ function buildManifestFromPackageFiles( name: asString(frontmatter.name) ?? title ?? slug, path: agentPath, skills: readAgentSkillRefs(frontmatter), - role: asString(extension.role) ?? "agent", + role: asString(extension.role) ?? asString(frontmatter.role) ?? "agent", title, icon: asString(extension.icon), capabilities: asString(extension.capabilities), From 6d73a8a1cb95a547ed2a15b29bc4c4622c8c0708 Mon Sep 17 00:00:00 2001 From: plind-dm <59729252+plind-dm@users.noreply.github.com> Date: Fri, 3 Apr 2026 23:24:24 +0900 Subject: [PATCH 2/2] test(import): verify frontmatter role fallback preserves CEO role Add test confirming that when a package's .paperclip.yaml extension block omits the role field, the agent role is read from AGENTS.md frontmatter instead of defaulting to "agent". --- .../src/__tests__/company-portability.test.ts | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/server/src/__tests__/company-portability.test.ts b/server/src/__tests__/company-portability.test.ts index 7a9ff812..d14ae8c0 100644 --- a/server/src/__tests__/company-portability.test.ts +++ b/server/src/__tests__/company-portability.test.ts @@ -1638,6 +1638,50 @@ describe("company portability", () => { })); }); + it("preserves agent role from frontmatter when extension block omits it", async () => { + const portability = companyPortabilityService({} as any); + + const preview = await portability.previewImport({ + source: { + type: "inline", + rootPath: "ceo-package", + files: { + "COMPANY.md": [ + "---", + 'schema: "agentcompanies/v1"', + 'name: "CEO Role Test"', + "---", + "", + ].join("\n"), + "agents/ceo/AGENTS.md": [ + "---", + 'name: "CEO"', + 'role: "ceo"', + "---", + "", + "# CEO", + "", + "You run the company.", + "", + ].join("\n"), + }, + }, + include: { company: true, agents: true, projects: false, issues: false }, + target: { mode: "new_company", newCompanyName: "CEO Role Test" }, + agents: "all", + collisionStrategy: "rename", + }); + + expect(preview.errors).toEqual([]); + expect(preview.manifest.agents).toEqual([ + expect.objectContaining({ + slug: "ceo", + name: "CEO", + role: "ceo", + }), + ]); + }); + it("treats no-separator auth and api key env names as secrets during export", async () => { const portability = companyPortabilityService({} as any);