Skip to content
Night Owls.dev
Jump to a page

@nightowlsdev/agent-designer

Pre-built agents

Design directions you choose from: proposes 2-3 named approaches via the ask tool, then applies the chosen one from an 18-skill curated design library read on demand, impeccable, ui-ux-pro-max, the taste-skill family.

What it does

@nightowlsdev/agent-designer solves 'give the design agent ALL the skills' without prompt explosion: a small taste core (design-taste-frontend, Vercel web-design-guidelines) is always granted, and the full curated library, Anthropic frontend-design/canvas-design/brand-guidelines, ui-ux-pro-max, the taste-skill family (high-end, minimalist, brutalist, brandkit, redesign), the impeccable family (impeccable, critique, audit, typeset, layout), extract-design-system, design-an-interface, rides the kit's skill_library_list/read tools: held at ~zero prompt cost, read on demand as fenced third-party reference, scoped to the curated names (never whole-tenant). The flow is human-in-the-loop by design: interrogate the project's goal, survey the library, propose 2-3 NAMED approaches with trade-offs via the built-in ask tool, and only after the human picks, read that approach's skills and deliver a complete design direction, typography, color, spacing, per-section wireframes, component inventory, and the five don'ts that would break it. Structured text out; no image generation, no code emission.

Install

pnpm add @nightowlsdev/agent-designer

Key exports

  • createDesigner ({ skillLibrary?: SkillRepo, libraryNames? })
  • manifest / DESIGNER_CURATED_SKILLS (18 pinned refs: taste core + approach library)
  • DESIGNER_PERSONA (interrogate → propose via ask → read on demand → layout spec)

Usage

agent-designer.ts
import { createDesigner, manifest } from "@nightowlsdev/agent-designer";
import { importCuratedSkills, PREBUILT_READONLY_TOOL_NAMES } from "@nightowlsdev/agent-kit";
import { materializeSkillStore, skillsShProvider } from "@nightowlsdev/skills";
import { defineSwarm, DEFAULT_READ_ONLY_TOOLS } from "@nightowlsdev/core";

// 1. Import the 18-skill design library once per tenant (impeccable, ui-ux-pro-max, taste-skill…).
await importCuratedSkills({ sets: manifest.curatedSkills, providers: { "skills.sh": skillsShProvider() }, storage, tenantId, actor });

// 2. The designer holds the library at ~zero prompt cost (skill_library_list/read, fenced,
//    curated-scoped), proposes 2-3 named approaches via the ask tool, and applies the pick.
const designer = createDesigner({ skillLibrary: storage.skills });

const swarm = defineSwarm({
  storage,
  agents: [designer],
  dynamicSkills: materializeSkillStore(storage.skills),   // the always-on taste core injects via grants
  models: { allow: ["openai/gpt-5.5-mini"], tier: { tiers: { swift: "openai/gpt-5.5-mini" } } },
  modelFactory,
  cost: { maxSteps: 30, maxCostUsd: 0.5 },
  // strict hosts: allowlist the read-only library tools so reads don't suspend
  toolApproval: { mode: "all-side-effecting", readOnly: [...DEFAULT_READ_ONLY_TOOLS, ...PREBUILT_READONLY_TOOL_NAMES] },
});
// The full journey: /docs/adopt-prebuilt-agents

What it provides

agent-designer is a pre-built design agent that proposes 2–3 NAMED directions (with trade-offs) you choose from, then delivers a complete layout spec — typography, color, spacing, per-section wireframes, component inventory, and the don'ts that would break it. It solves 'give the design agent ALL the skills' without prompt explosion: a small taste core is always granted, and the full 18-skill curated library (impeccable, ui-ux-pro-max, the taste-skill family, Anthropic + Vercel design skills) is read on demand through the kit's progressive-disclosure tools.

When to use it

  • You want structured design direction and layout specs, human-in-the-loop — the agent proposes named approaches and waits for a pick.
  • You want a large curated design library available without paying its full prompt cost on every turn.
  • You want usable taste even without a store — the always-granted taste core runs standalone.

When not to

  • You want generated images or emitted code — the designer outputs structured text only.
  • You want a one-shot answer with no approach-selection step — the flow is deliberately human-in-the-loop.
  • You haven't imported the library and expect all 18 skills — without a SkillRepo it runs on the taste core only (and says so).

Alternatives

  • A hand-authored agent granted one design skillYou want a single fixed design skill inline, with no approach-proposal flow and no on-demand library.
  • agent-writerYou need the words for the approved direction, not the visual design — the designer produces layout, the writer produces copy.

Strengths

  • Progressive disclosure: the 18-skill library is held at ~zero prompt cost via skill_library_list / skill_library_read and read on demand as fenced third-party reference, scoped to the curated names (never whole-tenant).
  • Human-in-the-loop by design: interrogate the goal → survey the library → propose 2–3 NAMED approaches with trade-offs via the built-in ask tool → read only the picked approach's skills (2–3 reads) → deliver the direction.
  • Degrades honestly: without a SkillRepo it runs on the always-granted taste core and says so; an empty library yields a legible message naming importCuratedSkills, never silent pretending.
  • Curated-scoped by default: the library tools attach only with a SkillRepo and default to this package's curated names.

Limits & trade-offs

  • Structured text only — no image generation, no code emission. It specifies; it doesn't render.
  • The full library needs the per-tenant import (importCuratedSkills) PLUS a SkillRepo passed as skillLibrary — without it you get the taste core, not the 18 skills.
  • Tag-driven approach sets aren't in v1 — the refs carry approach:* / craft:* tags but the library tools filter by name only.
  • Strict-approval hosts must allowlist the read-only library tools (toolApproval.readOnly) or on-demand reads suspend.

How it works

createDesigner({ skillLibrary?, libraryNames? }) attaches skillLibraryTools only when you pass a SkillRepo, scoped to libraryNames (default: this package's curated names). The persona always carries the taste core as default grants, so the agent has taste even with no library. In a run it interrogates the goal, lists the library (skill_library_list), proposes named approaches via the built-in ask tool, and after the human picks reads just that approach's skills (skill_library_read, fenced) before emitting the layout spec. You import the curated library once per tenant with importCuratedSkills.

Examples

Designer over the imported library

Import the 18-skill library once per tenant; then hold it at ~zero prompt cost.

agent-designer-example-1.ts
import { createDesigner, manifest } from "@nightowlsdev/agent-designer";
import { importCuratedSkills } from "@nightowlsdev/agent-kit";
import { skillsShProvider } from "@nightowlsdev/skills";

await importCuratedSkills({ sets: manifest.curatedSkills, providers: { "skills.sh": skillsShProvider() }, storage, tenantId, actor });

const designer = createDesigner({ skillLibrary: storage.skills });

Standalone taste core (no store)

Without skillLibrary it runs on the always-granted taste core and its persona says so.

agent-designer-example-2.ts
import { createDesigner } from "@nightowlsdev/agent-designer";

const designer = createDesigner();

Strict-host approval wiring

Allowlist the read-only library tools so on-demand reads don't suspend.

agent-designer-example-3.ts
import { createDesigner } from "@nightowlsdev/agent-designer";
import { PREBUILT_READONLY_TOOL_NAMES } from "@nightowlsdev/agent-kit";
import { defineSwarm, DEFAULT_READ_ONLY_TOOLS } from "@nightowlsdev/core";

const swarm = defineSwarm({
  storage,
  agents: [createDesigner({ skillLibrary: storage.skills })],
  toolApproval: { mode: "all-side-effecting", readOnly: [...DEFAULT_READ_ONLY_TOOLS, ...PREBUILT_READONLY_TOOL_NAMES] },
  // …models, modelFactory, dynamicSkills
});

Doing the parts it doesn't support

  • Generating images or codeThe designer emits structured text (specs). Wire your own image/codegen tool as an extra skill via extraSkills, or hand the spec to a separate codegen agent.
  • Scoping the library by tag/approachv1 filters by name. Pass libraryNames with the subset you want in scope, or build the name list from the manifest's refs.
  • Skipping the approach-selection stepThe flow is human-in-the-loop by design. If you want a direct answer, prompt the agent to pick and proceed — but the value is in the named-approach trade-off it surfaces first.

Related

  • agent-kitskillLibraryTools + importCuratedSkills — the progressive-disclosure machinery the designer rides.
  • skillsThe SkillRepo the library is read from and the materializeSkillStore that injects the taste core.
  • approval-modesWhy the read-only library tools go on toolApproval.readOnly so reads don't suspend.
  • agent-writerCopy for the approved design direction.
  • adopt-prebuilt-agentsThe full four-step host-wiring journey.