Operational DNA describes what an organization is and what it does, independent of UI, API, or deployment technology. It is split into three categories of primitives:
- People — Person, Role, Group, Membership
- Structures — Resource, Attribute, Relationship, Domain
- Activities — Operation, Action, Process, Task, Trigger, Rule
The four noun primitives (Resource, Person, Role, Group) share a common shape: name, optional attributes[], optional actions[], optional parent. They differ in which collection of a Domain they live in and in the extra fields specific to their type.
People
Who the organization deals with, in what capacities.
Person Stable
A Person is an individual template — the kind of human the organization deals with. Examples: Employee, Customer, Patient, Borrower, Contractor, Partner, Associate. A Person is a type, not a specific named individual; instance-level data (Joe, Jane, Dr. Adams) lives in Product/Technical layers.
Person is one of four noun primitives (alongside Resource, Role, Group). All four share the noun base shape: name, optional attributes[], optional actions[], optional parent. Person carries no people-specific fields beyond the shared base — its identity as a Person comes from being declared in the Domain's persons[] collection.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | The singular PascalCase name of the Person template. |
| description | string | — | Human-readable explanation of who this Person template represents. |
| domain | string | — | The dot-separated domain path this Person template belongs to. |
| attributes | attribute[] | — | Fields that describe this Person template. |
| actions | action[] | — | Verbs this Person template supports — the catalog of lifecycle actions on the Person itself (Patient.GetAdmitted, Customer.Onboard, Employee.Hire). Distinct from actions a Person performs in a Role context (those are Operations targeted at other nouns, assigned via Tasks). |
| parent | string | — | Optional parent Person name (e.g., for specialization hierarchies). |
| resource | string | — | Optional Resource template that backs this Person — used when a Person template is a façade over a Resource at another layer (e.g., Customer Person backed by Customer Resource). |
| examples | object[] | — | Representative example records for this Person template. |
Example
{
"name": "Patient",
"description": "A person receiving care from the organization.",
"attributes": [
{
"name": "dob",
"type": "date",
"required": true
},
{
"name": "allergies",
"type": "string"
}
],
"actions": [
{
"name": "GetAdmitted",
"type": "write"
},
{
"name": "GetDischarged",
"type": "write"
}
]
}
Related: Role · Group · Membership
Role Stable
A Role is a position/capacity template — the kind of organizational position Persons fill. Examples: Underwriter, Doctor, ChargeNurse, LeadCounsel, SuperAdmin. Roles are exercised within Groups (Underwriter operates within BankDepartment); the type-level Role-Group relationship is captured by `scope`.
Role is one of four noun primitives (alongside Resource, Person, Group). All four share the noun base shape: name, optional attributes[], optional actions[], optional parent. Role adds: scope, system, and resource-link fields. Actions on a Role cover org-admin lifecycle (Underwriter.Activate, Doctor.Certify) — not 'what an Underwriter does' (those are Operations on other nouns, assigned via Tasks).
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | The singular PascalCase name of the Role. |
| description | string | — | Human-readable explanation of this Role's authority and purpose. |
| domain | string | — | The dot-separated domain path this Role belongs to. |
| scope | string | string[] | — | The Group type(s) this Role is exercised within. Single Group name (Underwriter scope: BankDepartment) or array of Group names (SuperAdmin scope: [Workspace, Tenant]). Roles with no scope are global. The validator resolves each entry to a Group declaration. |
| parent | string | — | Optional parent Role for position hierarchy (SeniorUnderwriter.parent = Underwriter). A child with no `scope` inherits its parent's effective scope; a child that declares its own `scope` must be narrower-or-equal (sub-Group via Group.parent, equal Person, or array subset). Cycles are rejected. Action and Membership inheritance are intentionally NOT implied — children declare their own actions[] and Memberships reference Roles by exact name. |
| system | boolean | — | If true, this Role represents a non-human (system) actor — scheduled jobs, bots, integrations. System Roles are not eligible for Memberships (no Person fills them). |
| resource | string | — | Optional Resource template that backs this Role — used when a system Role is embodied by a Resource at another layer (e.g., NightlyDelinquencySweep backed by ScheduledJob, or ExternalCreditBureau backed by CreditBureau). |
| attributes | attribute[] | — | Fields that describe this Role template (rare — most Role detail lives in Memberships and authorities). |
| actions | action[] | — | Verbs supporting org-admin lifecycle on the Role itself (Underwriter.Activate, Doctor.Certify, Role.Retire). NOT what someone in this Role does — those are Operations on other nouns assigned via Tasks. |
| cardinality | "one" | "many" | — | Per-scope-instance Person count limit. "one" means at most one Person may hold this Role on any given scope instance at runtime; "many" (default) means unbounded. "one" requires a declared or inherited scope and is incompatible with system: true. The validator checks the declaration only — runtime systems enforce the count. |
| required | boolean | — | Whether at least one Person must hold this Role on every scope instance at runtime. Composes orthogonally with cardinality: { cardinality: 'one', required: true } means exactly one. Requires a declared or inherited scope and is incompatible with system: true. The validator checks the declaration only — runtime systems enforce presence. |
| excludes | string[] | — | Names of other Roles that the same Person SHALL NOT simultaneously hold on the same scope instance. Symmetric (one-sided declaration is enough). Both Roles must share at least one effective-scope entry. No self-reference. Incompatible with system: true. The validator checks well-formedness only — runtime systems enforce the constraint. |
Example
{
"name": "Underwriter",
"description": "Reviews and approves loan applications.",
"scope": "BankDepartment",
"actions": [
{
"name": "Activate",
"type": "write"
},
{
"name": "Retire",
"type": "destructive"
}
]
}
Related: Person · Group · Membership · Action
Group Stable
A Group is a work-unit / container template — the kind of organizational unit Roles are scoped within. Examples: BankDepartment, Hospital, Ward, Case, Workspace, Family, CourseOffering. Groups have attributes and lifecycle (a Case can be Opened, Settled, Closed); they're entity-like, but their organizational primary purpose is to be the container Roles are exercised in.
Group is one of four noun primitives (alongside Resource, Person, Role). All four share the noun base shape: name, optional attributes[], optional actions[], optional parent.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | The singular PascalCase name of the Group template. |
| description | string | — | Human-readable explanation of what this Group represents. |
| domain | string | — | The dot-separated domain path this Group belongs to. |
| attributes | attribute[] | — | Fields that describe this Group template. |
| actions | action[] | — | Verbs this Group supports — lifecycle actions on the Group itself (Case.Open, Case.Settle, BankDepartment.Merge). |
| parent | string | — | Optional parent Group name for organizational hierarchy (Department.parent = Division; Ward.parent = Hospital). |
| examples | object[] | — | Representative example records for this Group template. |
Example
{
"name": "Case",
"description": "A legal case grouping related parties, documents, and proceedings.",
"attributes": [
{
"name": "case_number",
"type": "string",
"required": true
},
{
"name": "filed_at",
"type": "date"
}
],
"actions": [
{
"name": "Open",
"type": "write"
},
{
"name": "Settle",
"type": "write"
},
{
"name": "Close",
"type": "destructive"
}
]
}
Membership Stable
A Membership is a template-level eligibility statement: 'Persons of type X may hold Roles of type Y, optionally in Groups of type Z.' It captures organizational RBAC at the template level — which kinds of people can fill which kinds of roles in which kinds of groups — without binding specific person-instances. Instance-level (Joe × Father × Family-4271) bindings live in Product/Technical layers.
Membership does not share the noun base shape (no attributes, no actions). It is purely a relationship template.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | The PascalCase name of this Membership template (e.g., EmployeeUnderwriter, PartnerLeadCounsel). |
| description | string | — | Human-readable explanation of who fills which role where. |
| person | string | yes | The Person template eligible to hold this Role. References a declared Person. |
| role | string | yes | The Role template the Person is eligible to hold. References a declared Role. |
| group | string | — | Optional Group template specifying where the Role is exercised. Required when the referenced Role has multi-scope (Role.scope is an array) and disambiguation is needed; optional when Role has a single scope or no scope. The validator resolves this against the Role's scope when both are present. |
| domain | string | — | The dot-separated domain path this Membership belongs to. |
Example
{
"name": "EmployeeUnderwriter",
"description": "Employees may hold the Underwriter role (in their BankDepartment, inferred from Underwriter.scope).",
"person": "Employee",
"role": "Underwriter"
}
Structures
The objects and connections your business manages.
Resource Stable
A Resource is an Entity the organization manages — a thing the system tracks, mutates, or operates on. Loans, Accounts, Products, Documents, Invoices.
Resources are one of four noun primitives (alongside Person, Role, and Group); all four share the noun base shape: name, optional attributes[], optional actions[], optional parent. People-specific concerns (scope, memberships, eligibility) live on Person/Role/Group/Membership, not on Resource.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | The singular PascalCase name of the Resource. |
| description | string | — | Human-readable explanation of what this Resource represents in the domain. |
| domain | string | — | The dot-separated domain path this Resource belongs to. |
| attributes | attribute[] | — | Fields that describe this Resource. |
| actions | action[] | — | Verbs this Resource supports — the catalog of what can be done to it. |
| parent | string | — | Optional parent Resource name for hierarchical relationships (e.g., LineItem.parent = Invoice). |
| examples | object[] | — | Representative example records for this Resource. Used as stub data when the API is unavailable. |
Example
{
"name": "Loan",
"description": "A financial loan issued to a borrower with repayment terms.",
"domain": "acme.finance.lending",
"attributes": [
{
"name": "amount",
"type": "number",
"required": true
},
{
"name": "interest_rate",
"type": "number",
"required": true
},
{
"name": "status",
"type": "enum",
"values": [
"pending",
"active",
"repaid",
"defaulted"
]
}
],
"actions": [
{
"name": "Apply",
"type": "write"
},
{
"name": "Approve",
"type": "write"
},
{
"name": "Reject",
"type": "write"
},
{
"name": "Disburse",
"type": "destructive"
}
]
}
Related: Attribute · Action · Operation · Relationship
Attribute Stable
An Attribute is a property that belongs to a Resource. Attributes describe the data shape of a Resource — its fields, their types, and any constraints.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | The snake_case name of the attribute. |
| description | string | — | A human-readable explanation of what this attribute represents. |
| required | boolean | — | Whether this attribute must be present on the resource. |
| values | string[] | — | The allowed values when type is 'enum'. |
| resource | string | — | The referenced Resource name when type is 'reference'. |
Example
{
"name": "amount",
"type": "number",
"required": true,
"description": "Principal amount of the loan in dollars."
}
Relationship Stable
A Relationship is a named, directed connection between two Resources. It formalizes the semantic link that a reference Attribute implies — adding cardinality and a human-readable name. Relationships are declared at the Operational layer so that Product and Technical cells can derive foreign keys, join tables, nested routes, and navigation links.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | A unique name for the relationship, typically From.to_resource (e.g. Loan.borrower). |
| from | string | yes | The Resource that holds the reference Attribute. |
| to | string | yes | The Resource being referenced. |
| cardinality | "one-to-one" | "many-to-one" | "one-to-many" | "many-to-many" | yes | The cardinality of the relationship from the 'from' Resource's perspective. |
| attribute | string | yes | The reference Attribute on the 'from' Resource that implements this relationship. |
| description | string | — | A human-readable explanation of what this relationship represents. |
| inverse | string | — | Optional name for the inverse direction (e.g. 'loans' on Borrower when Loan.borrower is the forward direction). |
Example
{
"name": "Loan.borrower",
"from": "Loan",
"to": "Borrower",
"cardinality": "many-to-one",
"attribute": "borrower_id",
"description": "Each loan belongs to one borrower; a borrower can have many loans.",
"inverse": "loans"
}
Domain Stable
A Domain is a bounded-context wrapper that organizes related noun primitives (Resources, Persons, Roles, Groups) into a logical boundary. Domains can be multiple levels deep — e.g. organization → domain → subdomain — with primitives at the leaves.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | The lowercase identifier for this domain segment. |
| description | string | — | A human-readable explanation of what this domain represents. |
| path | string | — | The fully qualified dot-separated path to this domain from the root. |
| domains | domain[] | — | Child domains nested within this domain. |
| resources | resource[] | — | The Resources (entity templates) that live directly within this domain. |
| persons | person[] | — | The Person templates (kinds of individuals) that live directly within this domain. |
| roles | role[] | — | The Role templates (positions/capacities) that live directly within this domain. |
| groups | group[] | — | The Group templates (work-units / containers) that live directly within this domain. |
Example
{
"name": "acme",
"path": "acme",
"domains": [
{
"name": "finance",
"path": "acme.finance",
"domains": [
{
"name": "lending",
"path": "acme.finance.lending",
"resources": [
{
"name": "Loan"
}
],
"persons": [
{
"name": "Borrower"
},
{
"name": "Employee"
}
],
"groups": [
{
"name": "BankDepartment"
}
],
"roles": [
{
"name": "Underwriter",
"scope": "BankDepartment"
}
]
}
]
}
]
}
Activities
What actually happens — atomic operations, orchestrated processes, and the rules that govern them.
Operation Stable
An Operation is a Subject.Action pair — the atomic unit of business activity. The Subject (target) can be any targetable primitive: Resource, Person, Role, Group, or Process. Examples: Loan.Approve (Resource), Patient.GetAdmitted (Person), Underwriter.Activate (Role, org-admin lifecycle), Case.Settle (Group), PublishFlow.Start (Process, lifecycle action on the SOP itself). The Actor that performs an Operation is expressed through Rules (access) and Tasks (assignment), not on the Operation itself.
The `target` field is a noun name that the validator resolves across resources[], persons[], roles[], groups[], and processes[] collections. The `action` field must match an entry in the target's actions[] catalog when one is declared.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| target | string | yes | The targetable primitive this operation acts on. Resolves across Resource, Person, Role, Group, and Process collections. |
| action | string | yes | The verb being performed. Must match a `name` in the target noun's actions[] catalog. |
| name | string | — | The operation expressed as Target.Action. |
| description | string | — | Human-readable explanation of what this operation represents. |
| changes | object[] | — | State mutations applied to the target Resource when this operation completes. Each entry names an attribute on the target and the value to assign (use 'now' for the current timestamp). |
Example
{
"target": "Loan",
"action": "Approve",
"name": "Loan.Approve",
"description": "Approves a pending loan application.",
"changes": [
{
"attribute": "status",
"set": "active"
}
]
}
Action Stable
An Action is a verb a noun primitive (Resource, Person, Role, or Group) supports. Actions are declared as entries in the noun's `actions[]` catalog using this uniform sub-schema. The Action entry is the catalog declaration; an Operation (top-level) is what binds a (noun, action-name) pair and carries orchestration metadata (Rules, state changes via `Operation.changes`).
There is no top-level Action collection. Actions are not reused across nouns — Loan.Approve and Document.Approve are independent declarations even when they share an English verb.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | The PascalCase verb (the action's name within its noun's catalog). |
| description | string | — | Human-readable explanation of what this action does. |
| idempotent | boolean | — | Whether repeating the action with the same input is safe (yields the same result without additional side effects). |
Example
{
"name": "Apply",
"description": "Submit a loan application.",
"type": "write",
"idempotent": false
}
Process Stable
A Process is a Standard Operating Procedure: a named, owned, ordered DAG of Steps that accomplishes a business goal. Each Step references exactly one Task. The DAG begins at the Step named by `startStep` (Amazon-States-Language `StartAt` convention).
Processes are purely descriptive in this version — they document the human playbook behind a set of Operation executions. A Process's `operator` is the Resource (acting as a Role) responsible for owning and supervising the workflow; the actual work is performed by whichever Actor each Task names. Runtime orchestration semantics (state tracking, timers, SLAs) are deferred to the planned workflow-cell.
Step-level gating uses `conditions` — a list of Rule names that must all evaluate true for the Step to execute. This composes existing condition Rules rather than re-declaring condition logic at the Step level.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | The PascalCase name of the process. |
| description | string | — | A human-readable explanation of what this process accomplishes. |
| domain | string | — | The dot-separated domain path this process is scoped to. |
| operator | string | yes | The Resource (acting as a Role) responsible for owning and supervising this process. |
| startStep | string | yes | The id of the Step that begins this process. Must reference a Step in the steps[] array. Mirrors Amazon States Language `StartAt`. |
| steps | object[] | yes | DAG of Steps. Step ids are referenced by `depends_on` to form the DAG. The Step named by `startStep` is the entry point. |
Example
{
"name": "LoanOrigination",
"description": "End-to-end loan origination from application to disbursement.",
"domain": "acme.finance.lending",
"operator": "LendingManager",
"startStep": "intake",
"steps": [
{
"id": "intake",
"task": "intake-loan-application"
},
{
"id": "underwrite",
"task": "underwrite-loan",
"depends_on": [
"intake"
]
},
{
"id": "close",
"task": "close-loan",
"depends_on": [
"underwrite"
],
"conditions": [
"LoanIsApproved"
],
"else": "abort"
},
{
"id": "disburse",
"task": "disburse-loan",
"depends_on": [
"close"
]
}
]
}
Task Stable
A Task is the atomic reusable unit of business activity: a Role performing exactly one Operation. A Task reads as '<Role> does <Operation>' (e.g. 'Underwriter does Loan.Approve'). Different Operation = different Task. Tasks are referenced by Steps inside a Process and are the primary unit of composition for SOPs.
The `actor` field references a Role (declared in the domain's roles[]). System actors are Roles with `system: true`.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | The kebab-case stable identifier for this task. |
| description | string | — | A human-readable explanation of what this task accomplishes and why. |
| actor | string | yes | The Role that performs this task. References a declared Role (human or system). |
| operation | string | yes | The Operation (Target.Action) this task invokes. Must reference a declared Operation. One Task = one Operation. |
| domain | string | — | The dot-separated domain path this task is scoped to. |
Example
{
"name": "close-loan",
"description": "Closing specialist closes an approved loan, preparing it for disbursement.",
"actor": "ClosingSpecialist",
"operation": "Loan.Close",
"domain": "acme.finance.lending"
}
Trigger Stable
A Trigger is what initiates an Operation or a Process — from a user, an external system, or the passage of time. Triggers are the entry point to all behavior.
A Trigger targets exactly one of: an Operation (ad-hoc invocation of a single Target.Action) or a Process (kick off the SOP from its startStep). The two are orthogonal — the same first-step Operation may have an Operation-level Trigger (standalone invocation) AND its containing Process may have a Process-level Trigger (full SOP kickoff).
Trigger replaces the prior 'Cause' primitive. Renamed for clarity and industry alignment (GitHub Actions, EventBridge, Zapier, n8n all use 'trigger').
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| operation | string | — | The Operation this trigger initiates, expressed as Target.Action (Target is any noun primitive). Mutually exclusive with `process`. |
| process | string | — | The Process this trigger initiates, by name. Process kickoff begins at the Process's startStep. Mutually exclusive with `operation`. |
| description | string | — | A human-readable explanation of what initiates this trigger. |
| source | "user" | "schedule" | "webhook" | "operation" | yes | The origin of the trigger. |
| schedule | string | — | A cron expression defining when the trigger fires. Required when source is 'schedule'. |
| event | string | — | The webhook event name that fires this trigger. Required when source is 'webhook'. |
| after | string | — | The Operation whose completion fires this trigger. Required when source is 'operation'. |
Example
{
"operation": "Loan.Apply",
"source": "user",
"description": "Borrower submits a loan application form."
}
Rule Stable
A Rule defines a constraint on an Operation — either who is permitted to perform it (type: access) or what conditions must be satisfied before it executes (type: condition). Rules are checked before execution.
Rules of type 'condition' are also referenced by Steps inside a Process via `step.conditions[]` to gate step execution compositionally.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | — | Optional PascalCase name for this rule. Required for condition rules that are referenced by Step.conditions[]. |
| operation | string | yes | The Operation this rule applies to, expressed as Target.Action (where Target is any noun primitive). |
| description | string | — | A human-readable explanation of what this rule enforces. |
| rule_type | "access" | "condition" | — | The kind of rule. 'access' controls who can perform the operation; 'condition' defines business conditions that must be satisfied. Named `rule_type` (not `type`) because every primitive carries `type` as the base-contract discriminator; this field is the per-primitive sub-classifier. |
| allow | object[] | — | The Actors permitted to perform this operation. Used when type is 'access'. An Actor matching any entry is allowed; all properties within a single entry must match together (AND). Cross-entry semantics is OR. |
| conditions | object[] | — | The conditions that must all be satisfied for the operation to proceed. Used when type is 'condition'. |
Example
{
"operation": "Loan.Approve",
"rule_type": "access",
"allow": [
{
"role": "Underwriter"
}
]
}