@nightowlsdev/agent-builder
Pre-built agentsThe meta-agent that knows the nightowls agent anatomy end to end: researches external skills, drafts + validates agents/bundles, and, behind a rule-enforced human-approval floor, imports skills and publishes definitions.
What it does
@nightowlsdev/agent-builder ships an agent whose persona encodes the framework's own internals (agent anatomy, the three skill kinds, bundles, the actor model, with a compile-time staleness guard that fails this package's CI if core's shape changes). With no options it is DRAFT-ONLY: it designs and validates agents/bundles through the real defineAgent/defineBundle and a human applies the JSON. Give it providers + repos + a service actor and it gains gated tools: search_skills/preview_skill (never raw provider I/O, the skills package's policy gates run before any fetch; everything third-party arrives fenced), list/get_agent, import_skill/publish_agent/publish_bundle. The mutating tools are hard-coded needsApproval + failClosed AND floored to `ask` by a package-attached enforce-level rule, engine-tested that a permissive host hook cannot downgrade the gate, with your policyGuard running fail-closed before every repo call. The storage actor bar (agents can never mutate definitions) stays fully intact underneath: publishes run with YOUR service actor, only after a human approves that specific call.
Install
pnpm add @nightowlsdev/agent-builderKey exports
- createBuilder (draft-only safe default; capability tools appear with their dependencies)
- builderApprovalRule (the enforce-level ask floor on the mutating tools)
- AGENT_DRAFT_SCHEMA / BUNDLE_DRAFT_SCHEMA / validateAgentDraft / validateBundleDraft
- manifest / BUILDER_CURATED_SKILLS (skill-creator, writing-skills, writing-great-skills, pinned)
Usage
import { createBuilder } from "@nightowlsdev/agent-builder";
import { skillsShProvider } from "@nightowlsdev/skills";
// DRAFT-ONLY by default: designs + validates agents/bundles; a human applies the JSON.
const builder = createBuilder();
// Full capability: gated skill research + human-approved publishing. Every mutating call suspends
// for approval (an enforce-level rule a permissive host hook cannot downgrade), then runs YOUR
// service actor through your policyGuard, the agents-can-never-mutate storage bar stays intact.
const fullBuilder = createBuilder({
providers: { "skills.sh": skillsShProvider() },
storage: {
skills: storage.skills, skillsWritable: storage.skillsWritable,
agents: storage.agents, agentsWritable: storage.agentsWritable,
bundles: storage.bundles, bundlesWritable: storage.bundlesWritable, // enables publish_bundle
},
actor: { type: "service", serviceId: "builder-host", tenantId },
policy: { allowAuthors: ["anthropics", "vercel-labs", "coreyhaines31"] },
policyGuard: (op) => assertOrgAllows(op), // throw to deny, fail-closed
});
// PREREQUISITE: your host handles suspend/resume (approvals render as question cards).
// The full journey: /docs/adopt-prebuilt-agentsWhat it provides
agent-builder is a meta-agent whose persona encodes the framework's own internals — agent anatomy, the three skill kinds, bundles, the actor model — with a compile-time staleness guard that fails this package's CI if core's shape changes. With no options it is DRAFT-ONLY: it designs and validates agents/bundles through the REAL defineAgent/defineBundle and a human applies the emitted JSON. Given providers + repos + a service actor it gains capability tools to research external skills and, behind a rule-enforced human-approval floor, import skills and publish definitions.
When to use it
- You want an in-product 'design me an agent / bundle' experience that produces framework-valid definitions, not free text.
- You want gated skill research (search_skills / preview_skill) and governed publishing behind human approval, under your own service actor and policy guard.
- You are building an authoring/workshop surface and need the mutating operations to be un-downgradeably gated.
When not to
- You author agents in code — defineAgent / defineBundle directly is simpler; the builder's value is the guided, validated, gated authoring loop.
- Your host can't handle suspend/resume — the mutating tools suspend for approval and simply park without an approval surface.
- You only need to import curated skills, not design new agents — agent-kit's importCuratedSkills is the narrower tool.
Alternatives
- defineAgent / defineBundle in coreYou author agents in code and review them in PRs — no conversational drafting agent, no in-product publishing, no approval surface needed.
- agent-kit lifecycle helpersYou want to seed/upgrade a known pre-built agent on a persisted store (ensurePrebuiltAgent / publishPrebuiltAgent), not design brand-new agents interactively.
Strengths
- Safe default: createBuilder() with no storage/actor/providers is DRAFT-ONLY — it designs and validates; a human applies. Capability tools appear only when their dependencies are supplied.
- The approval floor is rule-enforced, not flag-hoped: mutating tools are hard-coded needsApproval + failClosed AND floored to 'ask' by a package-attached enforce-level rule, engine-tested that a permissive host preToolCall hook cannot downgrade it.
- Drafts validate through the REAL framework — AGENT_DRAFT_SCHEMA / BUNDLE_DRAFT_SCHEMA + validateAgentDraft / validateBundleDraft run zod plus the actual defineAgent/defineBundle, so a draft that validates is a definition that will load.
- import_skill requires the previewed expectedName (+ optional expectedSourceVersion) — what's imported is exactly what was reviewed, and third-party text always arrives fenced.
- The storage actor bar stays intact: publishes run with YOUR service actor, only after a human approves that specific call — the agent can never mutate definitions on its own.
Limits & trade-offs
- The mutating tools suspend for approval (SP5) — a headless host must catch and resume the suspend, or publishing parks forever.
- Bundle drafts don't yet cover per-member rules/workflows — those handles are host-side, attached after the draft is applied.
- No hosted approve/publish UI ships — the OSS tools exist; the 'Agent Workshop' surface is host-built.
- It is only as safe as your configuration — policy.allowAuthors and a fail-closed policyGuard are yours to set before any fetch or repo mutation.
How it works
createBuilder assembles the framework-internals persona plus a tool set that grows with the dependencies you supply: providers enable search_skills / preview_skill, adding the writable skill store enables import_skill, adding agent/bundle repos enables publish_agent / publish_bundle. Every mutating tool is built needsApproval + failClosed, and the package attaches builderApprovalRule — an enforce-level rule forcing 'ask' on exactly the PRESENT mutating tools — so defineSwarm wires the composed mostRestrictiveTool path a permissive host hook can't downgrade. Third-party skill text arrives fenced through the skills package's policy gates; your policyGuard runs fail-closed before every repo mutation, and publishes execute under your service actor once the human approves.
Examples
Draft-only default
No storage/actor/providers — designs + validates only; a human applies the emitted JSON.
import { createBuilder } from "@nightowlsdev/agent-builder";
const builder = createBuilder();Validate a draft through the real framework
zod + the real defineAgent; returns publishable content or a legible error string.
import { validateAgentDraft } from "@nightowlsdev/agent-builder";
const result = validateAgentDraft({
slug: "triage",
role: "specialist",
personality: "Route inbound issues to the right owner.",
externalSkillNames: ["issue-triage"], // stored-skill grants; code skills are the developer's side
});
if ("error" in result) throw new Error(result.error);
// result.content is a publishable AgentVersionContentFull-capability builder: gated research + human-approved publishing
Tools appear with their dependencies; policyGuard throws to deny, fail-closed.
import { createBuilder } from "@nightowlsdev/agent-builder";
import { skillsShProvider } from "@nightowlsdev/skills";
const builder = createBuilder({
providers: { "skills.sh": skillsShProvider() },
storage: {
skills: storage.skills, skillsWritable: storage.skillsWritable,
agents: storage.agents, agentsWritable: storage.agentsWritable,
bundles: storage.bundles, bundlesWritable: storage.bundlesWritable, // enables publish_bundle
},
actor: { type: "service", serviceId: "builder-host", tenantId },
policy: { allowAuthors: ["anthropics", "vercel-labs"] },
policyGuard: (op) => assertOrgAllows(op), // throw to deny — fail-closed
});Doing the parts it doesn't support
- Publishing from a headless hostThe mutating tools suspend for approval. A headless host must catch the suspend (swarm.question) and drive a resume with the human's decision — @nightowlsdev/react hosts already render approvals as question cards.
- Per-member rules/workflows in a bundle draftBundle drafts cover members plus declared dependencies; attach per-member rules/workflows host-side with defineBundle after the draft is applied.
- Restricting which authors can be importedPass policy.allowAuthors (an allowlist) and a policyGuard that throws to deny — both run fail-closed before any fetch or repo mutation.
Related
- agent-kit — The shared foundation the builder builds on — the manifest shape, curated import, and the lifecycle a publish lands into.
- skills — The SkillProvider + import policy the builder's search_skills / preview_skill / import_skill run through, fenced and gated.
- core — defineAgent / defineBundle / defineRule — the real primitives the drafts validate against and the approval rule enforces on.
- approval-modes — How the enforce-level 'ask' floor folds with a host's approval modes so mutations can only tighten.
- capability-bundles — What publish_bundle emits — a reusable, closure-validated crew definition.