Skip to main content
This document is the canonical specification for the Cowboy Entitlements system. It defines the data model, lifecycle, enforcement rules, and the normative entitlement registry.

1. Scope and Goals

Goals
  • Least privilege by default.
  • Deterministic enforcement.
  • Declarative and composable permissions.
  • Auditable on-chain state and history.
Non-goals
  • UX design for entitlement configuration.
  • Runner market mechanisms and pricing.
  • Non-canonical, custom entitlement namespaces (reserved for a future release).

2. Terminology

  • Entitlement: A permission granting access to a capability or resource.
  • Actor entitlements: The set of entitlements an actor requires to execute correctly.
  • Runner entitlements: The set of entitlements a runner provides to off-chain jobs.
  • Attested entitlement: A runner entitlement that requires verifiable evidence (e.g., TEE, region).
  • Inheritable entitlement: An entitlement that may be passed to child actors on spawn.
  • Quota-bearing entitlement: An entitlement that supports parameterized limits or allowlists.

3. Canonical Data Model

Entitlements are represented as grants with a canonical structure.

3.1 Entitlement ID

An entitlement ID is a dotted string:
http.fetch
storage.kv
econ.transfer
sec.tee_required

3.2 Entitlement Grant

An entitlement grant has the following fields:
EntitlementGrant {
  id: string
  params?: map<string, value>
}
params MAY be omitted if the entitlement has no parameters. Parameter schemas are defined in the registry in Section 9.

3.3 Actor Manifest (Requires)

Actor deployment manifests MUST declare entitlements as a list of EntitlementGrant:
{
  "entitlements": [
    {"id": "econ.transfer", "params": {"max_amount": 1000}},
    {"id": "http.fetch", "params": {"allowlist_domains": ["api.coingecko.com"]}}
  ]
}

3.4 Runner Attestation (Provides)

Runner capability attestations MUST declare entitlements as a list of EntitlementGrant:
{
  "capabilities": [
    {"id": "http.fetch", "params": {"allowlist_domains": ["*"]}},
    {"id": "sec.tee_required"}
  ]
}

4. Serialization and Signing

Runner attestations are signed payloads to provide on-chain auditability. Canonical serialization: CBOR (RFC 8949 canonical CBOR) is used to serialize the attestation payload prior to signing. Signature: Runner EOA signs the CBOR-encoded payload using secp256k1. Deterministic ordering: Maps MUST be encoded with lexicographic key ordering as specified by canonical CBOR. Arrays MUST be sorted lexicographically by entitlement id prior to signing.

5. On-chain Storage

  • Actors: required entitlements are stored in the actor deployment manifest (on-chain).
  • Runners: provided entitlements are stored in an on-chain RunnerAttestation record.

5.1 RunnerAttestation Record

RunnerAttestation {
  runner_id: Address
  capabilities: [EntitlementGrant]
  valid_from: u64
  valid_until: u64
  evidence_hash?: Hash
  signature: Signature
}
evidence_hash MAY commit to off-chain evidence (e.g., a TEE quote bundle). The canonical attestation record is the single source of truth for scheduler matching. Time base: valid_from and valid_until are block heights (u64), not timestamps. An attestation is valid when valid_from <= current_block_height <= valid_until.

6. Enforcement Lifecycle

  1. Deployment-Time Check (MUST)
    The actor deployment transaction MUST be rejected if it declares unknown or invalid entitlements (see Section 10).
  2. Scheduler Match (MUST)
    A runner may be assigned to a job only if:
    Actor.requires ⊆ Runner.provides
    
    with parameter compatibility as defined in Section 8.
  3. VM Syscall Gate (MUST)
    Sensitive syscalls MUST fail deterministically if the corresponding entitlement is missing or its quota is exceeded.
  4. Attestation Validity (MUST)
    The scheduler MUST ignore runner attestations that are expired or invalidly signed.

7. Inheritance Rules

  • Only entitlements explicitly marked inheritable in the registry MAY be inherited by child actors.
  • Inheritance is a strict subset: child entitlements MUST be within the parent’s inheritable entitlements.

7.1 Actor Immutability

  • Actor code is immutable after deployment. Regular actors cannot upgrade their code.
  • Entitlements are immutable after deployment. Any change to entitlements requires redeployment.
  • To “upgrade” a regular actor, deploy a new actor at a new address. The old actor MAY implement a migration pattern (e.g., forwarding calls to the new address).
  • System actors (e.g., governance, bridge, blob storage) MAY be upgraded in-place if they hold the sys.upgrade entitlement. See Section 9.2.

8. Parameter Compatibility

When an entitlement has parameters, a runner provides a superset of an actor’s requirements. Examples:
  • allowlist_domains: actor set must be a subset of runner’s allowlist, or runner uses *.
  • max_* quotas: runner’s quota must be greater than or equal to actor’s requirement.

8.1 Parameter Types and Units

Unless otherwise specified in the registry:
  • All max_* and min_* parameters are unsigned integers.
  • max_amount is measured in base CBY units (integer).
  • max_bytes is measured in bytes (integer).
  • max_tokens counts model tokens (integer).
  • min_vram_gb is measured in GiB (integer).

8.2 Domain Matching

  • Domains are case-insensitive and MUST be normalized to ASCII punycode.
  • * denotes all domains.
  • *.example.com matches any subdomain of example.com but not the apex domain unless explicitly listed.
  • Exact matches (api.example.com) MUST match the normalized host.

8.3 Set and Range Matching

  • For set parameters (e.g., allowlist_domains, allowlist_assets, allowlist_contracts), the actor’s set MUST be a subset of the runner’s set, or the runner MUST provide *.
  • For range parameters (e.g., max_requests, max_tokens, max_bytes), the runner’s value MUST be greater than or equal to the actor’s value.
  • For equality parameters (e.g., region, tee_type), the values MUST be equal.

8.4 Domain Sets

  • domain_set references a curated set of domains defined by governance.
  • If both domain_set and allowlist_domains are provided, the effective allowlist is their union.
  • Runner matching MUST be performed against the effective allowlist.
  • A runner providing allowlist_domains: ["*"] is a superset of all domain sets and explicit allowlists. Wildcard always satisfies any actor domain requirement.

9. Normative Entitlement Registry

The following registry is canonical for v1. Any entitlement not listed here is invalid.

9.1 Execution & Lifecycle

IDDescriptionInheritableAttestedQuotaParams
exec.spawnAllow spawning child actors.max_children

9.2 System (Governance-Controlled)

IDDescriptionInheritableAttestedQuotaParams
sys.upgradeActor may upgrade its own code hash in-place.
The sys.upgrade entitlement is reserved for system actors. Only addresses in the System Deployer Allowlist (defined in the genesis config at genesis.system_deployers) may deploy actors with this entitlement. Deployments from other addresses MUST be rejected. This entitlement cannot be revoked once granted.

9.3 Networking (HTTP Egress)

IDDescriptionInheritableAttestedQuotaParams
http.fetchHTTP(S) egress via runner.allowlist_domains, domain_set, max_requests

9.4 Storage & State

IDDescriptionInheritableAttestedQuotaParams
storage.kvAccess to actor KV store.max_bytes
storage.blobBlob I/O via system blob actor.max_bytes

9.5 Off-chain Compute

IDDescriptionInheritableAttestedQuotaParams
oracle.llmRequest LLM inference.max_tokens, max_requests
accel.gpuRequire GPU for execution.min_vram_gb

9.6 Security & Privacy

IDDescriptionInheritableAttestedQuotaParams
sec.tee_requiredRequire execution in TEE.tee_type
sec.data_residencyRequire data to remain in a region.region

9.7 Economics & Funds

IDDescriptionInheritableAttestedQuotaParams
econ.hold_balanceActor may hold a persistent CBY balance across executions. Without this, actors can only pass through funds within a single transaction.
econ.transferActor may transfer CBY.max_amount, max_per_block

9.8 Timers & Scheduling

IDDescriptionInheritableAttestedQuotaParams
timer.scheduleActor may schedule timers.max_timers

9.9 Interoperability (Ethereum)

IDDescriptionInheritableAttestedQuotaParams
bridge.assetBridge assets to/from Ethereum.allowlist_assets
bridge.subscribe_eventSubscribe to Ethereum events.allowlist_contracts

9.10 Registry Governance and Versioning

  • The entitlement registry is defined by the protocol specification for a given protocol version.
  • Changes to the registry require governance approval and a protocol version update.
  • Nodes MUST reject any entitlement ID not present in the registry for their protocol version.

9.11 Entitlement Deprecation and Removal

When an entitlement is scheduled for removal, the following deprecation process applies:
  1. Deprecation announcement: A governance proposal marks the entitlement as deprecated starting at block height H.
  2. Deprecation window: For blocks H to H + DEPRECATION_WINDOW, the entitlement remains functional but:
    • New actor deployments using the deprecated entitlement emit a warning event.
    • The entitlement is flagged in on-chain queries and explorer UIs.
  3. Removal: At block H + DEPRECATION_WINDOW + 1:
    • The entitlement is removed from the registry.
    • Actors still holding the entitlement become non-executable until redeployed with a valid entitlement set.
    • Scheduler MUST NOT assign jobs to non-executable actors.
DEPRECATION_WINDOW: The minimum deprecation window is defined by governance, with a recommended default of 604,800 blocks (~7 days at 1s block time). Non-executable state: An actor in non-executable state:
  • Retains its on-chain state and balance.
  • Cannot process messages or be scheduled.
  • Can be redeployed by its owner with an updated manifest.
  • Emits ActorNonExecutable event at the block of removal.

9.12 Parameter Schemas

ParamTypeDescription
max_childrenu64Max child actors that may be spawned.
allowlist_domainsarray<string>Hostnames or * wildcard.
domain_setstringName of curated domain set.
max_requestsu64Max HTTP or LLM requests per execution.
max_bytesu64Byte limit for storage or blob I/O.
max_tokensu64Max tokens per LLM request within a single execution.
min_vram_gbu64Minimum GPU VRAM in GiB.
tee_typestringTEE type identifier (see Section 9.13).
regionstringRegion identifier (see Section 9.14).
max_amountu64Max CBY amount per transfer (base units).
max_per_blocku64Max CBY total per block (base units).
max_timersu64Max active timers per actor.
allowlist_assetsarray<string>Asset identifiers (e.g., token addresses).
allowlist_contractsarray<Address>Contract addresses permitted for subscriptions.

9.13 Canonical TEE Types

Valid tee_type values are:
  • sgx
  • sev
  • tdx

9.14 Canonical Regions

Valid region values are:
  • us
  • eu
  • uk
  • cn
  • apac

10. Validation Rules

  • Unknown entitlements are invalid (custom entitlements are not allowed in v1).
  • Parameter schemas are mandatory when the registry lists params.
  • Duplicate entitlements MUST be rejected (only one grant per ID).
  • Invalid parameter types or units MUST be rejected.
  • Non-canonical domain formats MUST be rejected.
  • Entitlement lists MUST be sorted lexicographically by id.
  • sys.upgrade is restricted: Deployments including sys.upgrade from addresses not in genesis.system_deployers MUST be rejected with ERR_SYSTEM_ENTITLEMENT_UNAUTHORIZED.

11. Errors and Determinism

Missing entitlements and quota violations MUST result in deterministic VM traps:
  • ERR_MISSING_ENTITLEMENT
  • ERR_ENTITLEMENT_QUOTA_EXCEEDED
  • ERR_ENTITLEMENT_PARAM_INVALID
  • ERR_ACTOR_NON_EXECUTABLE (actor holds deprecated/removed entitlement)
  • ERR_SYSTEM_ENTITLEMENT_UNAUTHORIZED (non-system deployer requested sys.upgrade)

12. Examples

12.1 Trading Bot (Actor Manifest)

{
  "entitlements": [
    {"id": "econ.transfer", "params": {"max_amount": 1000}},
    {"id": "http.fetch", "params": {"allowlist_domains": ["api.coingecko.com"]}},
    {"id": "oracle.llm", "params": {"max_tokens": 2000}},
    {"id": "storage.kv", "params": {"max_bytes": 1048576}},
    {"id": "timer.schedule", "params": {"max_timers": 10}}
  ]
}

12.2 Runner Attestation

{
  "runner_id": "0x...",
  "capabilities": [
    {"id": "http.fetch", "params": {"allowlist_domains": ["*"]}},
    {"id": "oracle.llm", "params": {"max_tokens": 100000}},
    {"id": "sec.tee_required", "params": {"tee_type": "sgx"}}
  ],
  "valid_from": 1700000000,
  "valid_until": 1710000000,
  "evidence_hash": "0x...",
  "signature": "0x..."
}

Appendix A: CDDL Schema

The following CDDL (RFC 8610) schema defines the canonical wire format for entitlements.
; Entitlement grant
entitlement-grant = {
  id: tstr,
  ? params: param-map
}

; Parameter map (keys and values depend on entitlement)
param-map = {
  * tstr => param-value
}

param-value = uint / tstr / [* tstr] / [* address]

; Address is a 20-byte value
address = bstr .size 20

; Hash is a 32-byte value
hash = bstr .size 32

; Signature is a 65-byte secp256k1 recoverable signature
signature = bstr .size 65

; Actor manifest entitlements array (sorted by id)
actor-entitlements = [* entitlement-grant]

; Runner attestation record
runner-attestation = {
  runner_id: address,
  capabilities: [* entitlement-grant],
  valid_from: uint,
  valid_until: uint,
  ? evidence_hash: hash,
  signature: signature
}

; Signing preimage (excludes signature field)
runner-attestation-preimage = {
  capabilities: [* entitlement-grant],
  ? evidence_hash: hash,
  runner_id: address,
  valid_from: uint,
  valid_until: uint
}

Appendix B: CBOR Signing Preimage

The runner attestation is signed over the CBOR-encoded payload below. Keys are sorted lexicographically, and arrays are sorted by entitlement id:
{
  "capabilities": [
    {"id": "http.fetch", "params": {"allowlist_domains": ["*"]}},
    {"id": "oracle.llm", "params": {"max_tokens": 100000}},
    {"id": "sec.tee_required", "params": {"tee_type": "sgx"}}
  ],
  "evidence_hash": "0x...",
  "runner_id": "0x...",
  "valid_from": 1700000000,
  "valid_until": 1710000000
}