Action Type DSL
The Action Type DSL defines action types declaratively. Each type configures field constraints, content validation, processing behavior, lifecycle hooks, and permissions without touching the core processing pipeline. All built-in definitions live in cloudillo-action (dsl/definitions.rs) and are validated at compile time.
ActionDefinition Structure
Each action type is an ActionDefinition:
struct ActionDefinition {
r#type: String, // e.g., "POST", "CMNT", "REACT"
version: String, // Semantic version, e.g., "1.0"
description: String,
metadata: Option<ActionMetadata>, // category, tags, deprecated/experimental
subtypes: Option<HashMap<String, String>>, // subtype code → description
fields: FieldConstraints, // required/forbidden per field
schema: Option<ContentSchemaWrapper>, // validation for the content field
behavior: BehaviorFlags, // processing behavior
key_pattern: Option<String>, // dedup/override key template
hooks: ActionHooks, // lifecycle hooks
permissions: Option<PermissionRules>,
search: Option<serde_json::Value>, // search-index manifest
}search is an opaque JSON manifest telling cloudillo-search which parts of the action to index. Its absence is the only allowlist there is — a type with no search block is not indexed. Every block is validated at server startup. CONV’s, for example:
{
"v": 1,
"title": ["content.name"],
"body": [{ "field": "content", "extract": "text" }]
}The action type code in the JWT t claim combines type and subtype as TYPE:SUBTYPE (e.g., POST:IMG, REACT:LIKE, CONN:DEL). The DEL subtype is the conventional delete/revoke marker.
Field Constraints
Only five fields are configurable, and only their optionality — the field types are fixed:
struct FieldConstraints {
content: Option<FieldConstraint>, // JWT claim `c` (json)
audience: Option<FieldConstraint>, // JWT claim `aud` (idTag)
parent: Option<FieldConstraint>, // JWT claim `p` (actionId)
subject: Option<FieldConstraint>, // JWT claim `sub` (actionId/string)
attachments: Option<FieldConstraint>, // JWT claim `a` (fileId[])
}Each field is Required, Forbidden, or — when omitted — optional:
| Constraint | Meaning |
|---|---|
Required |
Field must be present and valid |
Forbidden |
Field must be absent |
| (omitted) | Field is optional |
The content field is additionally validated against the optional schema (string length, enum, or object properties).
Behavior Flags
Behavior flags control how an action is processed and delivered. The implemented flags:
| Flag | Description |
|---|---|
broadcast |
Send to all followers when posting to own wall (no audience) |
allow_unknown |
Accept actions from non-connected/non-following senders |
ephemeral |
Don’t persist; forward to WebSocket only (e.g. PRES) |
approvable |
Can receive an APRV approval; enables auto-approve for trusted sources |
requires_subscription |
Child actions require a valid SUBS subscription |
subscribable |
This action can have SUBS pointing to it (CONV) |
deliver_subject |
Deliver the subject action alongside this one |
deliver_to_subject_owner |
Also deliver to the subject’s owner (INVT, REPOST) |
relay_children |
The container’s owner vouches every accepted child with an owner-signed APRV, so it federates to all subscribers pre-approved (CONV; set together with subscribable) |
local_only |
Never federate: delivery is skipped and the type is excluded from broadcast recipients |
default_flags |
Default capability flags applied at creation (e.g. rco) |
default_visibility |
Visibility char (P/V/2/F/C/S) applied at creation when neither an explicit value nor parent/subject inheritance resolves one (e.g. S for CONV) |
gated_by_parent_flag |
Reject if the parent’s flags disable this action (e.g. C for CMNT) |
gated_by_subject_flag |
Reject if the subject’s flags disable this action (e.g. R for REACT) |
Note
requires_acceptance, ttl, sync, and federated exist in the struct but are reserved and not yet implemented. (local_only is documented as reserved in the source comments, but is implemented — see the table above.)
Hooks
Hooks run native Rust logic at four lifecycle points. In the DSL definitions they are declared as HookImplementation::None; the actual native implementations are wired up through a registry (native_hooks/).
struct ActionHooks {
on_create, // local user creates the action
on_receive, // federated action arrives at /api/inbox
on_accept, // user accepts a confirmation action
on_reject, // user rejects a confirmation action
}Permissions
struct PermissionRules {
can_create: Option<String>, // e.g. "authenticated"
can_receive: Option<String>, // e.g. "any", "followers", "authenticated"
requires_following: Option<bool>,
requires_connected: Option<bool>,
}can_create / can_receive hold named rule strings ("authenticated", "any", "followers"). The requires_* booleans add relationship gates.
Key Pattern
key_pattern is a template that produces the database key used to deduplicate and override actions. A new action with the same key supersedes the previous one. Templates interpolate {type}, {issuer}, {audience}, {subject}, {parent}, and content fields like {content.name}.
| Type | key_pattern |
Effect |
|---|---|---|
| POST, CMNT, CONV | None |
Every action is unique (action ID is the identity) |
| REACT, SUBS | {type}:{subject}:{issuer} |
One per user per subject |
| CONN, FLLW | {type}:{issuer}:{audience} |
One per user per target |
| REPOST | {type}:{subject}:{issuer}:{audience} |
One per subject per target wall |
| STAT | {type}:{parent} |
One stat row per action |
Override example: Alice LIKEs a post, then changes to LOVE. Both REACT tokens share the key REACT:{subject}:alice.example.com, so the LOVE token supersedes the LIKE.
Validation Flow
When an action is created or received, it is validated against its definition:
- Check field constraints (
Requiredpresent,Forbiddenabsent) - Validate the
contentfield againstschema - Apply behavior gates (
gated_by_parent_flag,gated_by_subject_flag,requires_subscription) - Enforce permissions (
allow_unknown,requires_following/requires_connected)
See Also
- Actions & Action Tokens - Overview of the action system
- Action Delivery - How actions are distributed
- ABAC Permissions - Permission system
- Trust & Content Distribution - What
relay_childrendoes at runtime