feat: add agent blueprints — instance-scoped reusable agent config presets#4451
feat: add agent blueprints — instance-scoped reusable agent config presets#4451chewieglass-labs wants to merge 8 commits intopaperclipai:masterfrom
Conversation
Greptile SummaryThis PR adds instance-scoped Agent Blueprints — a well-structured feature covering DB migrations, a CRUD backend service, Zod validators, typed API client, and a full frontend (browse, create, edit, export/import, "Save as Blueprint", and a revamped Confidence Score: 5/5Safe to merge; both findings are P2 quality gaps, not blocking bugs Only P2 findings — no P0/P1 issues remain after verifying the previously flagged fixes are in place. Migrations are additive, routes are correctly auth-gated, and the core hire/blueprint flows work end-to-end. ui/src/pages/Blueprints.tsx (import drops lineage), ui/src/pages/AgentDetail.tsx and ui/src/pages/NewAgent.tsx (instructionsContent gap) Important Files Changed
Prompt To Fix All With AIThis is a comment left during a code review.
Path: ui/src/pages/Blueprints.tsx
Line: 560-575
Comment:
**Import silently drops `sourceAgentId` and `sourceBlueprintId`**
`handleImport` destructures only `id`, `createdAt`, and `updatedAt` before passing `payload` to `blueprintsApi.create`, but the explicit property list never includes `sourceAgentId` or `sourceBlueprintId`. The PR description says "strips `id`/`createdAt`/`updatedAt` on import", implying all other fields are preserved — but after an export → import round-trip the **Derived** badge will disappear and the lineage chain is permanently broken.
If dropping lineage on import is intentional (e.g. lineage UUIDs are meaningless on a different instance), document it explicitly; otherwise add the two fields to the `blueprintsApi.create` call:
```typescript
sourceAgentId: payload.sourceAgentId ?? null,
sourceBlueprintId: payload.sourceBlueprintId ?? null,
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: ui/src/pages/AgentDetail.tsx
Line: 1259-1278
Comment:
**`instructionsContent` not captured in "Save as Blueprint"**
`SaveAsBlueprintDialog.handleSave` omits `instructionsContent` from the `createMutation` payload, so the agent's prompt/instructions are never written to the blueprint. The `agent_blueprints` schema and the export output both carry this field, but it can never be populated through the UI: `BlueprintFormDialog` also exposes no instructions input, and `NewAgent.tsx` doesn't apply `blueprintData.instructionsContent` when pre-filling the hire form.
As a result `instructionsContent` is effectively write-only via the raw API — the most important part of an agent's configuration is silently absent from every blueprint created through the UI.
How can I resolve this? If you propose a fix, please make it concise.Reviews (5): Last reviewed commit: "fix: blueprint edit/search/import polish" | Re-trigger Greptile |
@greptileai re-review |
Export serializes the full blueprint including instructionsContent, but the import payload passed to blueprintsApi.create was missing the field, silently dropping agent instructions on every export→import round trip. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
handleSave was hardcoding runtimeConfig: {} and permissions: {} for
both create and edit paths. In edit mode this silently wiped any values
originally set when saving an agent as a blueprint. Now edit mode falls
back to the existing blueprint's values so they are preserved across
updates.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- preserve runtimeConfig and permissions on edit by omitting them from
the PATCH payload (only sent on create where they default to {})
- debounce blueprint search via useDeferredValue to avoid a fetch on
every keystroke
- add success toast after a successful blueprint import
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Fixed in d6dfbf7 — added instructionsContent: payload.instructionsContent ?? null to the blueprintsApi.create call inside handleImport. The field was present in payload after stripping id/createdAt/updatedAt, but was never forwarded, causing agent instructions to be silently dropped on every export → import round trip. It's my first PR, so I'm hoping I did okay. |
Thinking Path
What Changed
Database
agent_blueprints(migration0071_agent_blueprints.sql) — stores name, description, role, title, icon, capabilities, tags, adapter config, runtime config, budget, permissions, instructions, and metadata as an instance-scoped record with nocompany_id0072_blueprint_lineage.sql— adds nullablesource_agent_idandsource_blueprint_idtoagent_blueprints, andsource_blueprint_id(FK→ agent_blueprints.id ON DELETE SET NULL) toagents; also addstags: text[]toagents; both migrations are additive and safe to run against production datapackages/db/src/schema/agent_blueprints.ts— new Drizzle schema file for theagent_blueprintstable; exported frompackages/db/src/schema/index.tspackages/db/src/schema/agents.ts— extended Agent schema withtags: text[]andsourceBlueprintIdFK referencingagent_blueprintsBackend
server/src/services/agent-blueprints.ts— CRUD service withilikesearch across name, description, and capabilitiesserver/src/routes/agent-blueprints.ts— REST routes under/api/blueprints; read endpoints requireassertAuthenticated(agents can discover blueprints), write endpoints requireassertBoardpackages/shared/src/validators/agent-blueprint.ts— Zod validators for create and partial-update shapes, including lineage fieldspackages/shared/src/validators/index.ts— re-exportscreateAgentBlueprintSchema,updateAgentBlueprintSchema,CreateAgentBlueprint,UpdateAgentBlueprintpackages/shared/src/index.ts— added explicit named exports for all four blueprint validator symbols so they are available as@paperclipai/sharedtop-level importspackages/shared/src/types/agent.ts—Agentinterface extended withtags: string[]andsourceBlueprintId: string | nullFrontend
ui/src/api/blueprints.ts— typed API client withlist,get,create,update,delete;listaccepts optionalsearchandrolequery paramsui/src/lib/queryKeys.ts— addedblueprints.all,blueprints.list(search?, role?),blueprints.detail(id)ui/src/components/TagsInput.tsx— shared tag chip input (Enter/comma to add, Backspace to remove last, deduplication); used byBlueprintFormDialogandSaveAsBlueprintDialogui/src/components/SkillsMultiSelect.tsx— shared searchable skills multi-select with All/Clear bulk actions and footer count; used byBlueprintFormDialog,SaveAsBlueprintDialog, andNewAgentui/src/pages/Blueprints.tsx— new/instance/blueprintspage:BlueprintCard: icon slot shows the agent's icon when the blueprint was derived from an agent, falls back to the Layers glyph for manually created ones; name, role badge, and Derived badge (whensourceAgentIdis set); capabilities text expandable inline via a more/less toggle; skills chips with +N more collapseBlueprintFormDialog: create/edit form with description, adapter config viaAgentConfigForm, tags viaTagsInput, desired skills viaSkillsMultiSelect, and monthly budgetExport (
.blueprint.json) and Import actions — stripsid/createdAt/updatedAton importCreate, edit, and delete mutations fire a
pushToastsuccess notification viauseToastActionson completionui/src/pages/AgentDetail.tsx:TagsInput, adapter config viaAgentConfigForm, desired skills viaSkillsMultiSelect(non-required, filtered from agent's liveAgentSkillSnapshot), and monthly budget; setsicon,sourceAgentId, and preservessourceBlueprintIdfor full lineage; fires a success toast on saveagent.sourceBlueprintIdis set:Hired from blueprint: <linked name>— links to/instance/blueprintsui/src/pages/NewAgent.tsx— detects?blueprintId=query param; pre-fills name, title, role, adapter config, and desired skill keys from the blueprint; passessourceBlueprintIdin the hire payload; tags removed (blueprint-only concept); skills section usesSkillsMultiSelectfor consistency with blueprint formsui/src/components/NewAgentDialog.tsx— new 4-step onboarding flow replacing the previous single-step adapter picker:paperclip-blueprintsskill) or "Configure manually" (navigates to the hire form with?blueprintId=pre-filled)ui/src/components/InstanceSidebar.tsx— addedBlueprintsnav item withLayersicon, positioned below Heartbeats in the instance settings navui/src/App.tsx— registeredinstance/blueprintsrouteTests & Fixtures
ui/src/components/CommentThread.test.tsx— addedtags: []andsourceBlueprintId: nullto two inlineAgentmock objectsui/src/components/RoutineRunVariablesDialog.test.tsx— same fix to the agent fixture used by the dialog testui/src/fixtures/issueChatUxFixtures.ts— added missing fields to the shared agent fixture used across issue chat testsui/src/lib/agent-config-patch.test.ts— updatedmakeAgent()factory to include both new required fieldsui/src/lib/company-portability-sidebar.test.ts— updatedmakeAgent()helper to include both new required fieldsui/src/pages/IssueDetail.test.tsx— added fields to thecreateAgent()factory before the...overridesspread to ensure the base object satisfies the updatedAgentinterfaceui/storybook/fixtures/paperclipData.ts— addedtags: []andsourceBlueprintId: nullto all three agent entries in the shared storybook datasetCEO Skill
skills/paperclip-blueprints/— new CEO skill with six documented workflows: list, get, adapt, hire (passessourceBlueprintIdin the hire payload), reference in approval comment, and save-agent-as-blueprint; includes field-by-field adaptation guidelines and cleanup rules for stripping org-specific details before savingskills/paperclip-blueprints/references/api-reference.md— full endpoint reference with payload shapes and query param docsVerification
BETTER_AUTH_SECRET=<secret> docker compose -f docker/docker-compose.quickstart.yml up --build— migrations run automatically on startuppnpm db:migrate— both migrations are additive, no data lossInstance → Blueprintsin the sidebar.blueprint.json, then import it — verify the imported record has a newidand correct fieldscurl "$PAPERCLIP_API_URL/api/blueprints" -H "Authorization: Bearer $PAPERCLIP_API_KEY"should return the blueprint listRisks
ON DELETE SET NULLonagents.source_blueprint_idmeans deleting a blueprint does not cascade-delete agents.sourceBlueprintIdfield is optional)company_id— they are visible to all authenticated agents on the instance. This is intentional (templates are shared infrastructure) but means any board-role user can write blueprints. If multi-tenant isolation is a concern, acompany_idor visibility flag can be added later without changing the schema's additive nature.NewAgentDialogrefactor: the existing adapter picker is preserved as the "Advanced" path; the new onboarding steps wrap it, so no existing hire flow is removedModel Used
claude-sonnet-4-6) via Claude Code CLIChecklist