forked from farhoodlabs/paperclip
641eb44949
## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies > - Hiring agents is a governance-sensitive workflow because it grants roles, adapter config, skills, and execution capability > - The create-agent skill needs explicit templates and review guidance so hires are auditable and not over-permissioned > - Skill sync also needs to recognize bundled Paperclip skills consistently for Codex local agents > - This pull request expands create-agent role templates, adds a security-engineer template, and documents capability/secret-handling review requirements > - The benefit is safer, more repeatable agent creation with clearer approval payloads and less permission sprawl ## What Changed - Expanded `paperclip-create-agent` guidance for template selection, adjacent-template drafting, and role-specific review bars. - Added a Security Engineer agent template and collaboration/safety sections for Coder, QA, and UX Designer templates. - Hardened draft-review guidance around desired skills, external-system access, secrets, and confidential advisory handling. - Updated LLM agent-configuration guidance to point hiring workflows at the create-agent skill. - Added tests for bundled skill sync, create-agent skill injection, hire approval payloads, and LLM route guidance. ## Verification - `pnpm exec vitest run server/src/__tests__/agent-skills-routes.test.ts server/src/__tests__/codex-local-skill-injection.test.ts server/src/__tests__/codex-local-skill-sync.test.ts server/src/__tests__/llms-routes.test.ts server/src/__tests__/paperclip-skill-utils.test.ts --config server/vitest.config.ts` passed: 5 files, 23 tests. - `git diff --check public-gh/master..pap-2228-create-agent-governance -- . ':(exclude)ui/storybook-static'` passed. - Confirmed this PR does not include `pnpm-lock.yaml`. ## Risks - Low-to-medium risk: this primarily changes skills/docs and tests, but it affects future hiring guidance and approval expectations. - Reviewers should check whether the new Security Engineer template is too broad for default company installs. - No database migrations. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex coding agent based on GPT-5, with shell, git, Paperclip API, and GitHub CLI tool use in the local Paperclip workspace. ## 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 run tests locally and they pass - [x] I have added or updated tests where applicable - [x] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge Note: screenshot checklist item is not applicable; this PR changes skills, docs, and server tests. --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
import express from "express";
|
|
import request from "supertest";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const mockAgentService = vi.hoisted(() => ({
|
|
getById: vi.fn(),
|
|
}));
|
|
|
|
const mockListServerAdapters = vi.hoisted(() => vi.fn());
|
|
|
|
vi.mock("../services/agents.js", () => ({
|
|
agentService: () => mockAgentService,
|
|
}));
|
|
|
|
vi.mock("../adapters/index.js", () => ({
|
|
listServerAdapters: mockListServerAdapters,
|
|
}));
|
|
|
|
function registerModuleMocks() {
|
|
vi.doMock("../services/agents.js", () => ({
|
|
agentService: () => mockAgentService,
|
|
}));
|
|
|
|
vi.doMock("../adapters/index.js", () => ({
|
|
listServerAdapters: mockListServerAdapters,
|
|
}));
|
|
}
|
|
|
|
async function createApp(actor: Record<string, unknown>) {
|
|
const [{ llmRoutes }, { errorHandler }] = await Promise.all([
|
|
vi.importActual<typeof import("../routes/llms.js")>("../routes/llms.js"),
|
|
vi.importActual<typeof import("../middleware/index.js")>("../middleware/index.js"),
|
|
]);
|
|
const app = express();
|
|
app.use(express.json());
|
|
app.use((req, _res, next) => {
|
|
(req as any).actor = actor;
|
|
next();
|
|
});
|
|
app.use("/api", llmRoutes({} as never));
|
|
app.use(errorHandler);
|
|
return app;
|
|
}
|
|
|
|
describe("llm routes", () => {
|
|
beforeEach(() => {
|
|
vi.resetModules();
|
|
vi.doUnmock("../routes/llms.js");
|
|
vi.doUnmock("../middleware/index.js");
|
|
registerModuleMocks();
|
|
vi.resetAllMocks();
|
|
mockListServerAdapters.mockReturnValue([
|
|
{ type: "codex_local", agentConfigurationDoc: "# codex_local agent configuration" },
|
|
]);
|
|
});
|
|
|
|
it("documents timer heartbeats as opt-in for new hires", async () => {
|
|
const app = await createApp({
|
|
type: "board",
|
|
userId: "board-user",
|
|
companyIds: ["company-1"],
|
|
source: "local_implicit",
|
|
isInstanceAdmin: true,
|
|
});
|
|
|
|
const res = await request(app).get("/api/llms/agent-configuration.txt");
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(res.text).toContain("Use the paperclip-create-agent skill for end-to-end hiring");
|
|
expect(res.text).toContain("desiredSkills");
|
|
expect(res.text).toContain("sourceIssueId/sourceIssueIds");
|
|
expect(res.text).toContain("Timer heartbeats are opt-in for new hires.");
|
|
expect(res.text).toContain("Leave runtimeConfig.heartbeat.enabled false");
|
|
});
|
|
});
|