Creating Holons
The definitive guide to building a holon - whether you're adding a Capability or defining a brand-new holon type. Everything here follows from one idea: every holon is whole and part, so it shares one contract and one shape.
Holon taxonomy - what should I build?
Three categories, by primary role:
- Behavioral (Agent, Capability, Governance, Workflow) - own their execution.
Each has its own Runner and extends
InvokableEntityBase. - Execution context (Steward) - hosts behavioral entities and dispatches via
.Run(); owns its own builder. - Strategy (Operation) - composes behavioral holons; no Runner, no Governance of its own.
A special case: orchestrating holons are behavioral holons that also own an
inner Steward (with clone-on-write + Configure/Start) - that's how vaults and
workbenches in @fathym/power-ai are built. See
Advanced Patterns.
The universal contract
Every holon shares a six-method contract - the expression of Self-Assertion and Integration in the API:
| Method | Tendency | Purpose |
|---|---|---|
.Execute(fn) | S-A | The holon owns how it runs |
.Governance(policy) | INT | Participation in oversight |
.Services(factory) | INT | IoC dependency resolution |
.Build() | INT | Module production (Engine calls only) |
.Input(schema) | — | Input contract (or a domain-named alias) |
.Output(schema) | — | Output contract (or a domain-named alias) |
Both S-A and INT are always required - a holon that only asserts can't compose; a holon that only integrates has no identity.
Builder / Runner / Engine
The same pattern across every holon type - only the names differ:
| Holon | Factory | Runner | Verb |
|---|---|---|---|
| Capability | Capability() | CapabilityRunner() | .Execute() |
| Agent | Agent() | AgentRunner() | .Setup() |
| Governance | GovernancePolicy() | GovernancePolicyRunner() | .Evaluate() |
| Workflow | Workflow() | WorkflowRunner() | .Run() |
Golden rule: .Build() is called ONLY by the Engine, never externally. Always
pass the builder (a Buildable) to the Runner. See
Builder, Runner, Engine.
Code style
- Public methods: TitleCase (
Execute,Build). - Private/protected: camelCase (
executeFn,stepBuilders). - Prefer
protectedoverprivate; always write the explicitpublicmodifier; never use a_prefix.
Carry-forward generics
Builder methods return the concrete subclass type with updated generics (via
as unknown as SubclassBuilder<Updated>), and accumulate types by intersection
(TServices & S) - never replacing. New composition methods store builders
directly, not invokers. This is the type system encoding holonic participation.
The four sub-holon composability types
Every holon that can be composed publishes four types (named from the CHILD
holon), all declared in its *Module.ts:
*Invoker- the callable shape a caller holds at runtime.*InvokerMap- a map of name → Invoker.*BuilderMap- a structural map of name →Buildable.*TypeMap<T>- the mapping function (builders → invokers), applied in context only.
Services - accumulation and mocking
.Services() calls merge (spread-on-write) onto the previous - so services
accumulate across calls. At test time, real services + a mock override layer let
you swap dependencies. Operations receive (ctx, ioc) - not just ioc - so
resolution can be context-scoped.
Testing with intents
Declare intent as the natural completion of building a holon - see
Testing with Intents for the full IDD pattern
(CapabilityIntentSuite, mocked services, compile-time contract guards).
Creating a new holon type - the 8-component template
When you define a brand-new holon type, you write eight pieces: (1) a factory
function, (2) a Builder class extending InvokableEntityBase with carry-forward
generics, (3) a Module interface extending InvokableEntityModule, (4) a Context
interface (readonly, domain vocabulary), (5) an Engine (lazy build → validate I/O
→ resolve services → govern → execute), (6) a Runner (domain verb), (7) an
IntentRuntime, and (8) Intent + Suite. Field names match across all four layers
(builder method, module field, context field, intent method).
Anti-pattern checklist
Before you ship a holon, audit: code style (TitleCase/camelCase, explicit
public, no _); generics carry forward by intersection, no explicit generics at
call sites; .Build() only in the Engine; Module extends InvokableEntityModule;
Context fields readonly; composition keys TitleCase with all four sub-holon types
declared; no aggregation across boundaries (Operations have no Governance of
their own); IntentSuite present.
Canonical file/folder structure
{holontypes}/
├── .exports.ts (root barrel - re-exports the 4 sub-barrels)
├── types/ (*Module.ts with the 4 composability types; *TypeMaps.ts helpers)
├── fluent/ (factory, *Builder, *Runner, *RunnerBuilder, built-ins)
├── services/ (*Engine.ts)
└── intents/ (*Intent, *IntentRuntime, *IntentSuite, expectations/)
Each .exports.ts re-exports only its immediate siblings; the root re-exports the
four sub-barrels. The package entry maps ./{holontypes} → ./src/{holontypes}/.exports.ts.
- Testing with Intents → - declare what your holon intends to do
On this page
- Creating Holons
- ╰─▶Holon taxonomy - what should I build?
- ╰─▶The universal contract
- ╰─▶Builder / Runner / Engine
- ╰─▶Code style
- ╰─▶Carry-forward generics
- ╰─▶The four sub-holon composability types
- ╰─▶Services - accumulation and mocking
- ╰─▶Testing with intents
- ╰─▶Creating a new holon type - the 8-component template
- ╰─▶Anti-pattern checklist
- ╰─▶Canonical file/folder structure