| name | designing-entities |
| description | Use when an app developer wants to build an entity (a.k.a. an agent) for their Electric Agents app — designing a single entity type, picking a coordination pattern when needed (single-agent, manager-worker, pipeline, map-reduce, dispatcher, blackboard, reactive-observer), defining state, handler, schemas, and implementing it in one entity file. Applies to any use of `registry.define(...)` / `defineEntity(...)` in a `@electric-ax/agents-runtime` app. |
Designing entities
Guided, 5-phase workflow for designing and implementing one Electric Agents entity. Infers the coordination pattern from the user's description, reviews the design against universal and pattern-specific checks, and writes a single entity file once approved.
When to use
- User is starting a new entity in their app (
registry.define(...) / registerXxx(registry)).
- User asks "how do I build an agent that..." / "I want an entity that...".
Do not use when editing an existing entity, querying entity streams (see the entity-stream-queries skill), or changing the runtime itself.
Workflow
The five phases are strict — do not skip, merge, or reorder. Reference files are loaded on demand only when the phase below says so.
1. Elicit
Ask the developer one open question:
Describe the entity you want to build. What should it do? Who/what does it interact with? What triggers it?
Skip this prompt if the opening message already contains a clear description.
2. Clarify
Load references/pattern-triggers.md. Match the description against the trigger table. If one pattern fits clearly, skip ahead. Otherwise, ask one disambiguation question per message — focused on narrowing the coordination shape (spawns / parallel vs sequential / fixed vs dynamic specialists / shared state / observes / LLM vs orchestration-only). Stop as soon as the pattern and shape are unambiguous. Typical count: 2–4 questions. Never ask a canned full list.
3. Propose pattern and design
State the inferred pattern and the reasoning:
Inferred pattern: <name>
Why: <trigger phrases> + <structural signals>
Load references/patterns/<selected>.md. If runtime details are needed, read the authoritative docs on demand (see "Canonical material" below). Then present the design outline in chat:
- Entity type name +
description
- Coordination pattern (or "single-agent — no coordination")
creationSchema (if spawn args are expected) — field names + types
state collections — names, primary keys, row shape
inboxSchemas (if messages are typed)
stateSchemas (if the entity produces typed state events)
- Handler outline —
firstWake init, wake-type branches, agent config, spawn/observe calls
- Key
ctx properties: ctx.db.actions.* (insert/update/delete), ctx.db.collections.* (get/toArray), ctx.tags / ctx.setTag(key, value) / ctx.deleteTag(key), ctx.events (Array of ChangeEvent from observed sources)
- Observation sources:
entity(url), cron(expression), entities({ tags: ... }) — import from @electric-ax/agents-runtime
ctx.send(url, payload, { type?, afterMs? }) — afterMs delays delivery
- Built-in agents referenced (e.g.
worker), if any
registerXxx(registry) factory wrapping it
Ask: "Design look right? Any changes before we run the review checks?" Wait for the answer. Revise if requested, then re-present the outline.
4. Review (loop until approved)
Load references/review-checklist.md. The pattern file from step 3 is already loaded. Apply both checklists mechanically against the design. Report:
Universal checks:
✓ Handler signature correct
✓ ...ctx.electricTools spread into tools array
✗ Spawn-once guard missing — child IDs collide on re-wake
N/A creationSchema — no spawn args
Pattern-specific (<name>):
✗ State machine transitions not defined
✓ Parallel spawn loop uses deterministic IDs
Proposed fixes:
- Add state.children collection + spawn-once guard
- Add state.status with transitions idle → mapping → reducing → idle
Apply these fixes? Anything to override?
Iterate: developer requests changes → revise design → re-run both checklists → report again. Loop until the developer explicitly approves ("looks good, write the file" or equivalent).
5. Implement
Confirm the output path — default entities/<type-name>.ts, or whatever the developer specifies. Write exactly one file using this shape:
import type { EntityRegistry } from "@electric-ax/agents-runtime"
import { z } from "zod/v4"
export function register<Name>(registry: EntityRegistry) {
registry.define("<type>", {
description: "...",
creationSchema,
inboxSchemas,
state: { ... },
async handler(ctx, wake) { ... },
})
}
After writing, tell the developer:
Wire it in by adding register<Name>(registry) to your registry composition file (typically entities/registry.ts or server.ts).
Do not patch the developer's registry file automatically. Stop — skill is done.
Invariants
- One question per message in phase 2.
- No files written before phase 5.
- Phase 4 loops until the developer explicitly approves.
- Reference files are loaded on demand, never upfront.
- The skill writes exactly one entity file. Multi-entity systems are designed by running the skill once per entity.
Canonical material (read on demand, do not preload)
How to access docs: paths below are relative routes (e.g. /docs/reference/handler-context).
If the file is available locally at electric-agents-docs/docs/, read it from disk.
Otherwise fetch from https://durable-agents-docs.netlify.app/ + the route
(e.g. https://durable-agents-docs.netlify.app/docs/reference/handler-context).
Runtime API reference:
/docs/reference/handler-context — the ctx API (db, state, spawn, observe, send, agent, electricTools, firstWake, sleep, tags, setTag, deleteTag, events).
/docs/reference/wake-event — wake event types and the Wake configuration object.
/docs/reference/entity-definition — full EntityDefinition interface.
/docs/reference/built-in-collections — the 17 built-in collections on db.collections.*.
/docs/reference/state-collection-proxy — ctx.db.actions.* (insert/update/delete) and ctx.db.collections.* (get/toArray) API.
/docs/reference/shared-state-handle — mkdb / observe(db(...)).
/docs/reference/agent-config — useAgent, AgentHandle.run(), testResponses.
/docs/reference/agent-tool — custom tool interface.
/docs/reference/entity-handle — what ctx.spawn / ctx.observe return.
Usage guides:
/docs/usage/writing-handlers — handler lifecycle and re-entrancy.
/docs/usage/waking-entities — how wakes are produced and consumed; authoritative mental model for wake.type (only "inbox" and "wake").
/docs/usage/defining-entities — registry and collection declaration patterns.
Built-in agent types:
/docs/entities/agents/horton — the dev-server's built-in assistant (chat, research, code, dispatch). Useful as a reference for custom single-agent entities.
/docs/entities/agents/worker — the built-in sandboxed subagent. Required spawn args: { systemPrompt, tools } where tools is a non-empty subset of WorkerToolName. Workers do not receive ctx.electricTools (least-privilege).
Pattern descriptions:
/docs/entities/patterns/<name> — one per pattern.
Canonical example implementations:
examples/durable-agents-playground/src/coordination/{manager-worker,pipeline,map-reduce,dispatcher}.ts
examples/durable-agents-playground/src/blackboard/{debate,wiki,peer-review,trading-floor}.ts
examples/durable-agents-playground/src/reactive/{monitor,summarizer,guardian}.ts
examples/durable-agents-playground/src/standalone/assistant.ts
examples/durable-agents-playground/src/workers/worker.ts — the playground registers its own worker type that accepts sharedState / builtinTools. When a real app spawns "worker" it gets the server's built-in least-privilege worker instead; adjust pattern examples accordingly.
Each references/patterns/<name>.md points at the specific canonical example for that pattern.