Skip to content

Commit e5ce285

Browse files
committed
feat(agent-designer): adopt uniform reusable agent template shape
1 parent a0357c0 commit e5ce285

11 files changed

Lines changed: 232 additions & 102 deletions

File tree

‎agents/designer/README.md‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# @corbits/code-agent-designer
2+
3+
## What this is
4+
5+
A ready-to-go Corbits agent for the **designer** role (`@corbits/code-agent-designer`)
6+
plus its named component parts so a consumer can recreate or remix it. Designer is
7+
the UI/UX design engineering specialist: it owns DESIGN.md creation and updates,
8+
impeccable.style design laws, design tokens, typography, spatial layout, and
9+
micro-interaction polish.
10+
11+
## Consume (runLocal)
12+
13+
```ts
14+
import { agent } from "@corbits/code-agent-designer";
15+
const run = runLocal(defining(agent), env);
16+
```
17+
18+
## Consume (deploy runWorkflow / hub / sidecar)
19+
20+
Hand the same `AgentDefinition` (`agent`) to a workflow, hub, or sidecar. The
21+
package never exports a workflow itself — a workflow _consumes_ `agent`.
22+
23+
## Remix components
24+
25+
```ts
26+
import {
27+
director,
28+
tools,
29+
systemPrompt,
30+
config,
31+
defineAgent,
32+
} from "@corbits/code-agent-designer";
33+
34+
// Swap components at the consumer side.
35+
defineAgent({ director, tools, systemPrompt, config }); // or spread overrides
36+
```
37+
38+
Each of `agent`, `defineAgent`, `director`, `tools`, `systemPrompt`, `config` is a
39+
named, independently importable part.
40+
41+
## Byte-stability & single authority
42+
43+
- `systemPrompt.build()` is pure and byte-stable — identical string every call.
44+
- `tools` is content-equal to the app's `REVIEW_TOOLS` surface constant
45+
(`src/agent/directors/tool-sets.ts`); the in-tree drift-guard
46+
(`src/agent/directors/designer/package.test.ts`) enforces they match.
47+
- This package is the single prompt authority for designer; the in-tree
48+
`src/agent/directors/designer/package.ts` is deleted.

‎agents/designer/src/agent.ts‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Designer assembled agent — ready unit + package defineAgent wrapper.
2+
// Calls `@intx/agent`'s `defineAgent` directly (no Corbits bridge/helper layer).
3+
// Tool mounting is consumer/app-side: `tools` here is [] (the allowlist surface
4+
// is exported from `./toolset.js` and wired by the app harness).
5+
6+
import {
7+
defineAgent as coreDefineAgent,
8+
type AgentDefinition,
9+
} from "@intx/agent";
10+
11+
import { systemPrompt } from "./prompt.js";
12+
13+
/** The assembled designer agent — ready to hand to `runLocal` / `runWorkflow`. */
14+
export const agent: AgentDefinition = defineAgent();
15+
16+
/** Package convenience wrapper → `AgentDefinition` for `runLocal` authoring. */
17+
export function defineAgent(): AgentDefinition {
18+
return coreDefineAgent({
19+
id: "designer",
20+
systemPrompt: systemPrompt.build(),
21+
tools: [],
22+
capabilities: [],
23+
inference: { sources: [] },
24+
tags: { fleet: "0.3.36", lane: "designer" },
25+
});
26+
}

‎agents/designer/src/config.ts‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Designer config — uniform `{ spawn, tier, modelRole }` shape (§5).
2+
// designer is a leaf worker: maySpawn false, no allowlist.
3+
// modelRole is "implement" (matches the in-tree card).
4+
export const config = {
5+
spawn: {
6+
maySpawn: false,
7+
},
8+
tier: "leaf",
9+
modelRole: "implement",
10+
} as const satisfies {
11+
spawn: { maySpawn: boolean; allowlist?: readonly string[] };
12+
tier: string;
13+
modelRole: string;
14+
};

‎agents/designer/src/director.ts‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Designer director card — the `DirectorPackage` data, extracted byte-for-byte
2+
// from the in-tree `src/agent/directors/designer/package.ts` (now deleted).
3+
// Structurally satisfies the app's `DirectorPackage` (asserted in-tree by
4+
// `src/agent/directors/designer/package.test.ts`); it imports @intx/* only.
5+
6+
import { tools } from "./toolset.js";
7+
import { systemPrompt } from "./prompt.js";
8+
import { config } from "./config.js";
9+
10+
/** The assembled designer director card. */
11+
export const director = {
12+
id: "designer",
13+
primaryIntent:
14+
"Own DESIGN.md create/use, design tokens, UI styling, and impeccable.style design engineering",
15+
outOfLane: [
16+
"backend architecture and database schema design",
17+
"general backend code defect review",
18+
"marketing publish campaigns",
19+
"orchestrating or spawning other agents",
20+
],
21+
description:
22+
"UI/UX designer — owns DESIGN.md, impeccable style design laws, tokens, and interface polish",
23+
systemPrompt: systemPrompt.build(),
24+
tools: { allow: tools },
25+
spawn: config.spawn,
26+
modelRole: config.modelRole,
27+
tier: config.tier,
28+
} as const;

‎agents/designer/src/index.ts‎

Lines changed: 9 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,9 @@
1-
/**
2-
* Designer worker: UI/UX design engineering specialist.
3-
* Owns DESIGN.md creation and updates, impeccable.style design laws,
4-
* design tokens, typography, spatial layout, and micro-interaction polish.
5-
*
6-
* Ships as the @corbits/code-agent-designer workspace package: the tool allowlist
7-
* lives here so the package stays importable without the app. Drift against
8-
* the app build surface fails src/agent/directors/designer/package.test.ts.
9-
*/
10-
export type AgentPackage = {
11-
readonly id: "designer";
12-
readonly primaryIntent: string;
13-
readonly outOfLane: readonly string[];
14-
readonly description: string;
15-
readonly systemPrompt: string;
16-
/** Unset — designer never attaches skill bodies at spawn. */
17-
readonly attachedSkills?: readonly string[];
18-
/** Unset — designer declares no skill scope. */
19-
readonly optionalSkills?: readonly string[];
20-
readonly tools: {
21-
readonly allow: readonly string[];
22-
};
23-
readonly spawn: {
24-
readonly maySpawn: false;
25-
};
26-
readonly modelRole: "implement";
27-
readonly tier: "leaf";
28-
};
29-
30-
const DESIGNER_TOOLS = [
31-
"read_file",
32-
"grep",
33-
"search_files",
34-
"list_dir",
35-
"lsp",
36-
"run_shell",
37-
"web_fetch",
38-
"web_search",
39-
"skill_search",
40-
"use_skill",
41-
"write_file",
42-
"edit_file",
43-
"delete_file",
44-
] as const;
45-
46-
export const designerPackage: AgentPackage = {
47-
id: "designer",
48-
primaryIntent:
49-
"Own DESIGN.md create/use, design tokens, UI styling, and impeccable.style design engineering",
50-
outOfLane: [
51-
"backend architecture and database schema design",
52-
"general backend code defect review",
53-
"marketing publish campaigns",
54-
"orchestrating or spawning other agents",
55-
],
56-
description:
57-
"UI/UX designer — owns DESIGN.md, impeccable style design laws, tokens, and interface polish",
58-
systemPrompt: `You are DesignerDirector (Designer), a specialist in Corbits Code.
59-
60-
PRIMARY INTENT: own interface design, design tokens, styling, and DESIGN.md. You bring design engineering excellence to UI surfaces — layout rhythm, typography, purposeful motion, responsive states, and cohesive design systems.
61-
62-
DESIGN.md ownership:
63-
- Own the living design contract: DESIGN.md. Create it when missing, keep it up to date, and adhere to its token system.
64-
- DESIGN.md specifies: color palettes and semantic tokens, typography scales, spacing and elevation systems, interaction states, motion curves, and UI voice guidelines.
65-
66-
Impeccable style & design engineering laws:
67-
1. Purposeful motion: animation must clarify spatial relationships, indicate state changes, or provide direct physical feedback. Never animate merely for decoration.
68-
2. Frequency-aware motion: high-frequency interactions (command palettes, quick shortcuts, list navigation) must feel instant (<100ms) with zero sluggish transitions.
69-
3. Spatial discipline & layout rhythm: establish consistent 4px/8px grid spacing, optical alignment, and balanced negative space.
70-
4. Calm hierarchy: interfaces should visually direct attention to primary actions without competing noise, unnecessary borders, or clashing colors.
71-
5. Accessible defaults: ensure strong contrast ratios, visible keyboard focus indicators, touch targets >= 44x44px, and semantic markup. Never rely on color alone to convey meaning.
72-
6. Surface & token discipline: use centralized semantic tokens rather than magic hex colors or arbitrary pixel values.
73-
74-
Workflow:
75-
1. Load DESIGN.md and existing UI component tokens. If DESIGN.md is absent and in scope, draft a concise, actionable version.
76-
2. Implement or update UI styling, design tokens, or component structure according to the brief and design principles.
77-
3. Verify visual hierarchy, component responsiveness, and state handling (hover, focus, disabled, active, error).
78-
4. Report changes with Summary / Findings / Blockers / Paths.
79-
80-
OUT OF LANE: backend business logic or database migrations, general backend defect review, marketing content pipelines, fleet orchestration.`,
81-
tools: { allow: [...DESIGNER_TOOLS] },
82-
spawn: { maySpawn: false },
83-
tier: "leaf",
84-
modelRole: "implement",
85-
};
1+
// Public surface — re-exports only (no logic). Exports exactly
2+
// `agent, defineAgent, director, tools, systemPrompt, config`. No `workflow`
3+
// export. No Corbits shared package is re-exported; the package's `director`
4+
// structurally satisfies the app's `DirectorPackage` (app-side drift-guard).
5+
export { agent, defineAgent } from "./agent.js";
6+
export { director } from "./director.js";
7+
export { tools } from "./toolset.js";
8+
export { systemPrompt } from "./prompt.js";
9+
export { config } from "./config.js";

‎agents/designer/src/prompt.ts‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Designer card — the single prompt authority, extracted byte-for-byte from the
2+
// in-tree `src/agent/directors/designer/package.ts` (now deleted). `build()` is
3+
// pure and byte-stable: it returns an identical string on every call.
4+
const CARD = `You are DesignerDirector (Designer), a specialist in Corbits Code.
5+
6+
PRIMARY INTENT: own interface design, design tokens, styling, and DESIGN.md. You bring design engineering excellence to UI surfaces — layout rhythm, typography, purposeful motion, responsive states, and cohesive design systems.
7+
8+
DESIGN.md ownership:
9+
- Own the living design contract: DESIGN.md. Create it when missing, keep it up to date, and adhere to its token system.
10+
- DESIGN.md specifies: color palettes and semantic tokens, typography scales, spacing and elevation systems, interaction states, motion curves, and UI voice guidelines.
11+
12+
Impeccable style & design engineering laws:
13+
1. Purposeful motion: animation must clarify spatial relationships, indicate state changes, or provide direct physical feedback. Never animate merely for decoration.
14+
2. Frequency-aware motion: high-frequency interactions (command palettes, quick shortcuts, list navigation) must feel instant (<100ms) with zero sluggish transitions.
15+
3. Spatial discipline & layout rhythm: establish consistent 4px/8px grid spacing, optical alignment, and balanced negative space.
16+
4. Calm hierarchy: interfaces should visually direct attention to primary actions without competing noise, unnecessary borders, or clashing colors.
17+
5. Accessible defaults: ensure strong contrast ratios, visible keyboard focus indicators, touch targets >= 44x44px, and semantic markup. Never rely on color alone to convey meaning.
18+
6. Surface & token discipline: use centralized semantic tokens rather than magic hex colors or arbitrary pixel values.
19+
20+
Workflow:
21+
1. Load DESIGN.md and existing UI component tokens. If DESIGN.md is absent and in scope, draft a concise, actionable version.
22+
2. Implement or update UI styling, design tokens, or component structure according to the brief and design principles.
23+
3. Verify visual hierarchy, component responsiveness, and state handling (hover, focus, disabled, active, error).
24+
4. Report changes with Summary / Findings / Blockers / Paths.
25+
26+
OUT OF LANE: backend business logic or database migrations, general backend defect review, marketing content pipelines, fleet orchestration.`;
27+
28+
/** Stable identifier of the package's voice. */
29+
export const theme = "designer";
30+
31+
/** Byte-stable builder: returns the raw designer card, identical every call. */
32+
export const systemPrompt = {
33+
theme,
34+
build: (): string => CARD,
35+
};

‎agents/designer/src/toolset.ts‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Designer UI/UX: build surface (read + product writes) — content-equal to the
2+
// `REVIEW_TOOLS` constant in `src/agent/directors/tool-sets.ts` (the single
3+
// tool authority; BUILD_TOOLS = REVIEW_TOOLS = READ_TOOLS + PRODUCT_WRITE_TOOLS).
4+
// Drift is enforced by the in-tree `src/agent/directors/designer/package.test.ts`
5+
// against `REVIEW_TOOLS`.
6+
const BUILD_TOOLS = [
7+
"read_file",
8+
"grep",
9+
"search_files",
10+
"list_dir",
11+
"lsp",
12+
"run_shell",
13+
"web_fetch",
14+
"web_search",
15+
"skill_search",
16+
"use_skill",
17+
"write_file",
18+
"edit_file",
19+
"delete_file",
20+
] as const;
21+
22+
/** The designer tool allowlist — literal equal to the in-tree review/build surface. */
23+
export const tools: readonly string[] = [...BUILD_TOOLS];

‎agents/designer/tsconfig.json‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"extends": "../../tsconfig.base.json",
3+
"compilerOptions": {
4+
"noEmit": true
5+
},
6+
"include": ["src/**/*.ts"]
7+
}

‎package.json‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@
8686
"tar": "^7.5.1"
8787
},
8888
"dependencies": {
89-
"@corbits/code-agent-designer": "workspace:*",
9089
"@corbits/codex-provider": "0.1.1",
9190
"@corbits/oauth-core": "0.2.0",
9291
"@corbits/openai-responses": "0.2.1",
Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,52 @@
11
import { describe, expect, test } from "bun:test";
22

3-
import { designerPackage } from "@corbits/code-agent-designer";
4-
import { BUILD_TOOLS } from "../tool-sets.js";
3+
import {
4+
director,
5+
tools,
6+
config,
7+
systemPrompt,
8+
} from "@corbits/code-agent-designer";
9+
import { REVIEW_TOOLS } from "../tool-sets.js";
510
import { DIRECTOR_REGISTRY } from "../registry.js";
611
import type { DirectorPackage } from "../types.js";
712

813
describe("designerPackage", () => {
914
test("workspace package satisfies the director contract and feeds the registry", () => {
10-
const asDirector: DirectorPackage = designerPackage;
15+
const asDirector: DirectorPackage = director;
1116
expect(asDirector.id).toBe("designer");
12-
expect(DIRECTOR_REGISTRY.designer).toBe(designerPackage);
13-
expect([...designerPackage.tools.allow]).toEqual([...BUILD_TOOLS]);
17+
expect(DIRECTOR_REGISTRY.designer).toBe(director);
18+
// In-tree card used BUILD_TOOLS; BUILD_TOOLS === REVIEW_TOOLS content, so
19+
// the drift-guard asserts against REVIEW_TOOLS (the brief's surface rule).
20+
expect([...director.tools.allow]).toEqual([...REVIEW_TOOLS]);
21+
expect(new Set(director.tools.allow).size).toBe(
22+
director.tools.allow.length,
23+
);
1424
});
1525

16-
test("extracted copy stays build-scoped and non-spawning", () => {
17-
expect(designerPackage.tools.allow).toContain("write_file");
18-
expect(designerPackage.tools.allow).toContain("edit_file");
19-
expect(designerPackage.tools.allow).toContain("delete_file");
20-
expect(designerPackage.tools.allow).not.toContain("spawn_agent");
21-
expect(designerPackage.tools.allow).not.toContain("ask_operator");
22-
expect(designerPackage.spawn.maySpawn).toBe(false);
23-
expect(designerPackage.tier).toBe("leaf");
24-
expect(designerPackage.modelRole).toBe("implement");
26+
test("spawn/tier/modelRole match config", () => {
27+
expect(director.spawn).toEqual(config.spawn);
28+
expect(director.tier).toBe(config.tier);
29+
expect(director.modelRole).toBe(config.modelRole);
30+
expect(director.spawn.maySpawn).toBe(false);
31+
expect(director.tier).toBe("leaf");
32+
// modelRole preserved from the in-tree card (implement, not §5 docs).
33+
expect(director.modelRole).toBe("implement");
34+
});
35+
36+
test("prompt authority is byte-stable", () => {
37+
expect(director.systemPrompt).toBe(systemPrompt.build());
38+
expect(systemPrompt.build()).toBe(systemPrompt.build());
39+
});
40+
41+
test("tools surface matches REVIEW_TOOLS and is leaf-scoped", () => {
42+
expect([...tools]).toEqual([...REVIEW_TOOLS]);
43+
expect(tools).not.toContain("spawn_agent");
44+
expect(tools).not.toContain("ask_operator");
45+
expect(tools).not.toContain("wait_agents");
46+
expect(tools).not.toContain("search_agents");
47+
});
48+
49+
test("tools allowlist has no duplicates", () => {
50+
expect(new Set([...tools]).size).toBe(tools.length);
2551
});
2652
});

0 commit comments

Comments
 (0)