Agent lease record

One line of the lease journal: what the issuer decided about a lease, and when. Schema set 1.2. Nine events. granted carries the signed lease (and, from a 1.2 writer, the declared manifest and granted_hash, the SHA-256 of the canonical bytes of the GRANTED manifest, so a reader can tie the record to the exact bytes decided); refused carries no lease but a fresh id that names the refusal, the reserved reason codes, and declared_hash, so a refusal weighs the same as a grant (SPEC §5.2); narrowed carries the narrowing summary; attached says how the governor contained the process; revoked names who revoked (by: an ancestor lease or the issuer) and from the record's at the lease opens nothing; stopped, completed (with usage) and expired close it; heartbeat records liveness and never extends expiry. The journal is append-only and every status is folded from these lines. A record MAY carry the same declared_hash and granted_hash as the audit journal's lease.* events, which are the durable copy.

Schema
lease-record.schema.json, served as JSON at its $id: https://cognitive-delivery.github.io/contract/1.x/lease-record.schema.json
Dialect
http://json-schema.org/draft-07/schema#
Root
object, open (additional properties are carried)
required: schema_version, at, event, lease_id
conditional requirements (below)
Stability
none stated at the root; every declared property carries its own
Properties
106 declared: 16 under the root, 90 in definitions

Properties

Every declared property under the root, in the schema's own order. [] is an array's items, .* the shape of every unnamed member, #name a definition. Objects carry additional properties unless a row says otherwise.

PathTypeRequiredDescriptionConstraintsStability
schema_versionstringyesContract version this record was written against, major.minor. A reader compares the major only.pattern ^\d+\.\d+$stable
atstringyesWhen the issuer decided, UTC with milliseconds and Z: the same single form as the lease's own timestamps, because a granted record's at is the lease's issued_at.pattern ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$stable
eventstringyesWhat happened. Closed: a reader folds status from these and an unknown event would have no fold.one of "granted", "refused", "narrowed", "heartbeat", "attached", "revoked", "stopped", "completed", "expired"stable
lease_idstring #uuidyesThe lease this record is about. For refused, a fresh id that names the refusal; there is no lease.stable
parent_lease_idstring #uuidThe parent the lease was narrowed against, when it has one.stable
leaseobject #leasewhen event is "granted"The signed lease a granted record carries. Inlined from agent-lease.schema.json and held identical to it.stable
declaredobject #manifestThe declared manifest, when a granted record carries it: the same shape as the lease's granted manifest, so the narrowing diff is a plain comparison. Inlined from agent-lease-manifest.schema.json and held identical to it.stable
declared_hashstring #sha256when event is "refused"SHA-256 of the canonical bytes of the manifest as DECLARED: the input identity. Required on refused, where there is no lease to carry it.stable
granted_hashstring #sha256SHA-256 of the canonical bytes of the GRANTED manifest (lease.manifest): the enforced identity. A 1.2 writer records it on granted; a reader meeting a granted record without it MAY compute it from lease.manifest.stable
reasonsarraywhen event is "refused"Why a refused record refused: one or more reserved codes.min items 1stable
reasons[]string #reasonCodeA refusal reason in one of three reserved forms (SPEC §5.2). R<n>: the specification's own conditions, R1 to R6 today; R7 and above are reserved for the specification to assign, and an issuer MUST NOT mint one, although the pattern admits R7 to R99. runtime_error:<name>: the issuer could not decide (no signing key, parent unknown, schema invalid), named by the issuer. vendor:<vendor>:<code>: anything else, namespaced by whoever defines it. Prose goes in reason, never here, so two implementations can compare refusals by code.
reasonstringwhen event is "narrowed", "revoked" or "stopped"Prose: the narrowing summary on narrowed, why on revoked and stopped, and the human reading of the codes on refused. Never prompt text.max length 500stable
bystringwhen event is "revoked"Who revoked: the lease_id of an ancestor of the revoked lease, or issuer. A reader meeting a by that is neither MUST treat the record as invalid (SPEC §6, rule L3).any of: (1) #uuid; (2) string, one of "issuer"stable
signaturestring #sha256Optional on revoked: the issuer's HMAC-SHA256 over the record's canonical bytes without signature, under the same key as the lease.stable
usageobject #usageWhat a completed lease consumed, as far as the issuer could measure. Absent fields are unmeasured, not zero.stable
containmentstringwhen event is "attached"On attached: enforced when an OS sandbox confined the process, advisory when only the environment reached it. Never implied: no attached record means no governor attached.one of "enforced", "advisory"stable
platformstringwhen event is "attached"On attached: the platform the process ran on, as the runtime names it (darwin, linux, win32).max length 32stable

Definitions

The named shapes this schema refers to as #name. A row above that links here is not expanded in place; its constraints are the definition's.

#manifest

An inlined copy of agent-lease-manifest.schema.json (its reference), carried so the schema is self-contained and held identical to its source by npm test.

PathTypeRequiredDescriptionConstraintsStability
#manifest
an inlined copy of agent-lease-manifest.schema.json, held identical to its source
objectThe declared manifest, when a granted record carries it: the same shape as the lease's granted manifest, so the narrowing diff is a plain comparison. Inlined from agent-lease-manifest.schema.json and held identical to it.
#manifest.schema_versionstringyesContract version this record was written against, as major.minor. One rule across every schema (schema set 1.2): a reader compares the major only, and a minor it has not met is additive by the contract's own rule.pattern ^\d+\.\d+$stable
#manifest.agentobjectyesWho is asking. name is a label for the cockpit; kind says how the harness runs it; runtime_agent is the existing closed agent vocabulary so a lease keys to the same identity every audit event already carries.stable
#manifest.agent.namestringyesDisplay label for the cockpit, at most 120 characters: the worker role, the session, the plugin. Not an identity, and never a person's name, email address or git identity; this value is recorded in an audit journal that is retained indefinitely.min length 1
max length 120
stable
#manifest.agent.kindstringyesHow the harness runs this agent. native: inside the kernel's own process. delegated-cli: a spawned coding CLI. plugin: loaded into the host. external: presented over a bridge from outside the harness.one of "native", "delegated-cli", "plugin", "external"stable
#manifest.agent.runtime_agentstringyesThe closed agent identity vocabulary. unknown is a first-class value, never an error: the kernel looked and could not tell. cdf-native (schema set 1.0, additive) is the harness's own native turn loop: the kernel drives a model provider directly, with no vendor CLI or SDK.one of "codex-cli", "claude-code", "gemini-code-assist", "github-copilot", "cdf-native", "unknown"stable
#manifest.agent.providerstringThe organisation or product providing the agent, when it differs from the runtime.stable
#manifest.agent.modelobjectThe model behind the agent, for attribution. Never a prompt, never a key.stable
#manifest.agent.model.vendorstringyesmin length 1stable
#manifest.agent.model.familystringyesmin length 1stable
#manifest.agent.model.versionstringstable
#manifest.agent.harness_versionstringVersion of the harness that generated or presented this manifest.stable
#manifest.parent_lease_idstringThe lease this manifest is presented under, when it is a child. A root manifest has none and is narrowed against the workspace policy instead.pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$stable
#manifest.intentobjectyesWhy the agent is running. purpose is required and non-empty: a manifest with no stated purpose is refused.stable
#manifest.intent.spec_slugstringThe governed spec this run serves, when there is one.stable
#manifest.intent.task_idstringThe task within that spec, when there is one.stable
#manifest.intent.purposestringyesOne sentence of intent, at most 500 characters. Recorded in the audit journal, so no prompt and no content.min length 1
max length 500
stable
#manifest.allowobjectyesWhat the agent asks to be allowed. Every list is required and may be empty; an empty tools list in a GRANTED manifest is a lease that opens nothing, which is why the kernel refuses rather than grants it. Granted lists are always a subset of the parent's.stable
#manifest.allow.toolsarrayyesGoverned tool names the agent may call. An empty list in a GRANTED manifest is refused (SPEC §5.2 R2).stable
#manifest.allow.tools[]stringA governed tool name the agent may call. At most 128 characters of letters, digits, _, ., :, / and -, so a governed cdf_ name and a <server>/<tool> pair both fit. * is refused: a lease that names every tool has not named one, and SPEC §5.2 R2 exists because a grant must say what it opens. Whitespace is refused.pattern ^[A-Za-z0-9_][A-Za-z0-9_.:/-]{0,127}$
min length 1
#manifest.allow.read_pathsarrayyesWorkspace-relative POSIX globs the agent may read. Refused here, without lookahead so any RE2-based validator can load the rule: a leading /, any .. segment, a leading ~, a drive-letter prefix and any backslash. The registry re-checks the resolved path against the workspace root.stable
#manifest.allow.read_paths[]stringmin length 1
must not match ^/, (^|/)\.\.(/|$), ^~, ^[A-Za-z]:, \\
#manifest.allow.write_pathsarrayyesWorkspace-relative POSIX globs the agent may change. Refused here, without lookahead: a leading /, any .. segment, a leading ~, a drive-letter prefix and any backslash. The registry re-checks the resolved path against the workspace root, and a change outside the granted set is a scope violation that revokes the lease.stable
#manifest.allow.write_paths[]stringmin length 1
must not match ^/, (^|/)\.\.(/|$), ^~, ^[A-Za-z]:, \\
#manifest.allow.hostsarrayyesHosts the agent may reach. *.example.com matches api.example.com and not example.com; matching a bare parent domain requires listing it. Enforced by the egress proxy once it keys off the lease.stable
#manifest.allow.hosts[]stringA host the agent may reach. A lower-case DNS name of one or more labels, an IPv4 literal or localhost (both are DNS-name shaped), with an optional single leading *. label, or the bare *. Refused by the pattern, which uses no lookahead or backreference and compiles under RE2: a scheme, a port, a path, whitespace, upper case, a trailing dot and a wildcard anywhere but the first label. A port is not a host: the egress proxy matches hostnames, and a rule nothing enforces is a claim. IP literals are admitted because a local model provider (Ollama, LM Studio) lives at 127.0.0.1 and the root policy derives its hosts from provider URLs.pattern ^(\*|(\*\.)?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*)$
min length 1
max length 253
#manifest.allow.commandsarrayyesExecutables the agent may run, by basename.stable
#manifest.allow.commands[]stringAn executable the agent may run. The basename of the executable, at most 128 characters: letters, digits, ., _, +, -. No path separator (identity is the resolved executable's basename, not where it was found), no whitespace (an argument is not part of the name) and no shell operator.pattern ^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$
min length 1
#manifest.allow.tool_argsobjectDECLARED argument constraints per tool (schema set 1.2, development stability): tool name to a JSON Schema the agent proposes for its own calls to that tool, after Progent's argument-schema policies. A declaration, not a grant: in 1.x an issuer MAY omit it from the granted manifest and MUST NOT treat it as granted authority, because the reference gate does not yet evaluate argument schemas and a narrowing rule without an enforcing gate is a claim the corpus cannot test. The vector tool-args-dropped shows the reference dropping it. It becomes a rule when a gate enforces it.keys must match ^[A-Za-z0-9_][A-Za-z0-9_.:/-]{0,127}$
additional properties: see #manifest.allow.tool_args.*
development
a declaration an issuer MAY omit from the grant (SPEC 4.4); becomes a rule when a gate enforces it
#manifest.allow.tool_args.*objectA JSON Schema. Not validated as one here: draft-07 cannot validate a schema as data without a meta-schema $ref, which the self-contained rule forbids.
#manifest.denyobjectyesWhat the agent must not do even if allow would otherwise permit it. Granted deny lists are the UNION of the declared and the parent's, so a child can never shed a parent's refusal.stable
#manifest.deny.commandsarrayyesExecutable names refused outright, for example sudo, su, docker, ssh, curl, wget, launchctl, systemctl.stable
#manifest.deny.commands[]stringAn executable refused outright. The basename of the executable, at most 128 characters: letters, digits, ., _, +, -. No path separator (identity is the resolved executable's basename, not where it was found), no whitespace (an argument is not part of the name) and no shell operator.pattern ^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$
min length 1
#manifest.deny.pathsarrayyesPOSIX globs the agent must not touch: credentials, governance evidence, the lease journal itself. A denial MAY be home-relative (~/.ssh/**), because refusing a path outside the workspace is meaningful even though no allow could grant it; a leading /, any .. segment and any backslash are refused.stable
#manifest.deny.paths[]stringmin length 1
must not match ^/, (^|/)\.\.(/|$), \\
#manifest.deny.hostsarrayyesHostnames refused outright.stable
#manifest.deny.hosts[]stringA host refused outright. A lower-case DNS name of one or more labels, an IPv4 literal or localhost (both are DNS-name shaped), with an optional single leading *. label, or the bare *. Refused by the pattern, which uses no lookahead or backreference and compiles under RE2: a scheme, a port, a path, whitespace, upper case, a trailing dot and a wildcard anywhere but the first label. A port is not a host: the egress proxy matches hostnames, and a rule nothing enforces is a claim. IP literals are admitted because a local model provider (Ollama, LM Studio) lives at 127.0.0.1 and the root policy derives its hosts from provider URLs.pattern ^(\*|(\*\.)?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*)$
min length 1
max length 253
#manifest.budgetobjectyesCeilings. Every field is optional and non-negative; an absent field means the parent's remaining budget applies. A child's granted budget is clamped to its parent's remaining, depth is decremented per generation and fan_out is decremented on the parent as each child is issued.stable
#manifest.budget.stepsintegerMaximum tool calls or turns.min 0
max 9007199254740991
stable
#manifest.budget.wall_clock_msintegerMaximum lifetime in milliseconds; the lease expires when it is spent.min 0
max 9007199254740991
stable
#manifest.budget.tokensintegerMaximum model tokens, input plus output.min 0
max 9007199254740991
stable
#manifest.budget.cost_usdnumberMaximum spend in US dollars.min 0stable
#manifest.budget.depthintegerHow many generations of child lease may be issued beneath this one. Zero means no children. At most 16: the reference root policy allows 4, and a declaration above the ceiling is nonsense rather than something to clamp.min 0
max 16
stable
#manifest.budget.fan_outintegerHow many child leases may be live under this one at once. At most 256: the reference root policy allows 8.min 0
max 256
stable
#manifest.approvalsarrayyesAction names that need a human before the agent may perform them, under the same identifier rule as tool names. Required and may be empty.stable
#manifest.approvals[]stringAn action that needs a human first; the same identifier rule as a tool name. At most 128 characters of letters, digits, _, ., :, / and -, so a governed cdf_ name and a <server>/<tool> pair both fit. * is refused: a lease that names every tool has not named one, and SPEC §5.2 R2 exists because a grant must say what it opens. Whitespace is refused.pattern ^[A-Za-z0-9_][A-Za-z0-9_.:/-]{0,127}$
min length 1
#manifest.attestationobjectWho vouches for the declaration. Optional: an agent presenting its own manifest has nothing to sign with, and the bridge or harness signs on its behalf.stable
#manifest.attestation.issuerstringyesWhich party produced the declaration.one of "agent", "bridge", "harness", "plugin"stable
#manifest.attestation.signaturestringLower-case hex signature over the canonical bytes of the manifest, when the issuer can sign: 64 hex characters, which is HMAC-SHA256 like the lease's own signature. An odd-length or longer value is not a signature this contract defines.pattern ^[0-9a-f]{64}$stable
#manifest.attestation.key_fingerprintstringFingerprint of the key that produced signature. Never the key.min length 1stable

#lease

An inlined copy of agent-lease.schema.json (its reference), carried so the schema is self-contained and held identical to its source by npm test.

PathTypeRequiredDescriptionConstraintsStability
#lease
an inlined copy of agent-lease.schema.json, held identical to its source
objectThe signed lease a granted record carries. Inlined from agent-lease.schema.json and held identical to it.
#lease.schema_versionstringyesContract version this record was written against, as major.minor. One rule across every schema (schema set 1.2): a reader compares the major only, and a minor it has not met is additive by the contract's own rule.pattern ^\d+\.\d+$stable
#lease.lease_idstringyesThe grant's identity. Lower-case UUID, the same shape as a capability token id.pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$stable
#lease.manifestobjectyesThe GRANTED manifest: the same shape as the Agent Lease Manifest the agent declared, after narrowing. This is a dereferenced copy of agent-lease-manifest.schema.json, inlined because the contract keeps every schema self-contained (a reader compiles each file on its own, with no cross-file references). A test in the consumer asserts the copy is identical to the source.stable
#lease.manifest.schema_versionstringyesContract version this record was written against, as major.minor. One rule across every schema (schema set 1.2): a reader compares the major only, and a minor it has not met is additive by the contract's own rule.pattern ^\d+\.\d+$stable
#lease.manifest.agentobjectyesWho is asking. name is a label for the cockpit; kind says how the harness runs it; runtime_agent is the existing closed agent vocabulary so a lease keys to the same identity every audit event already carries.stable
#lease.manifest.agent.namestringyesDisplay label for the cockpit, at most 120 characters: the worker role, the session, the plugin. Not an identity, and never a person's name, email address or git identity; this value is recorded in an audit journal that is retained indefinitely.min length 1
max length 120
stable
#lease.manifest.agent.kindstringyesHow the harness runs this agent. native: inside the kernel's own process. delegated-cli: a spawned coding CLI. plugin: loaded into the host. external: presented over a bridge from outside the harness.one of "native", "delegated-cli", "plugin", "external"stable
#lease.manifest.agent.runtime_agentstringyesThe closed agent identity vocabulary. unknown is a first-class value, never an error: the kernel looked and could not tell. cdf-native (schema set 1.0, additive) is the harness's own native turn loop: the kernel drives a model provider directly, with no vendor CLI or SDK.one of "codex-cli", "claude-code", "gemini-code-assist", "github-copilot", "cdf-native", "unknown"stable
#lease.manifest.agent.providerstringThe organisation or product providing the agent, when it differs from the runtime.stable
#lease.manifest.agent.modelobjectThe model behind the agent, for attribution. Never a prompt, never a key.stable
#lease.manifest.agent.model.vendorstringyesmin length 1stable
#lease.manifest.agent.model.familystringyesmin length 1stable
#lease.manifest.agent.model.versionstringstable
#lease.manifest.agent.harness_versionstringVersion of the harness that generated or presented this manifest.stable
#lease.manifest.parent_lease_idstringThe lease this manifest is presented under, when it is a child. A root manifest has none and is narrowed against the workspace policy instead.pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$stable
#lease.manifest.intentobjectyesWhy the agent is running. purpose is required and non-empty: a manifest with no stated purpose is refused.stable
#lease.manifest.intent.spec_slugstringThe governed spec this run serves, when there is one.stable
#lease.manifest.intent.task_idstringThe task within that spec, when there is one.stable
#lease.manifest.intent.purposestringyesOne sentence of intent, at most 500 characters. Recorded in the audit journal, so no prompt and no content.min length 1
max length 500
stable
#lease.manifest.allowobjectyesWhat the agent asks to be allowed. Every list is required and may be empty; an empty tools list in a GRANTED manifest is a lease that opens nothing, which is why the kernel refuses rather than grants it. Granted lists are always a subset of the parent's.stable
#lease.manifest.allow.toolsarrayyesGoverned tool names the agent may call. An empty list in a GRANTED manifest is refused (SPEC §5.2 R2).stable
#lease.manifest.allow.tools[]stringA governed tool name the agent may call. At most 128 characters of letters, digits, _, ., :, / and -, so a governed cdf_ name and a <server>/<tool> pair both fit. * is refused: a lease that names every tool has not named one, and SPEC §5.2 R2 exists because a grant must say what it opens. Whitespace is refused.pattern ^[A-Za-z0-9_][A-Za-z0-9_.:/-]{0,127}$
min length 1
#lease.manifest.allow.read_pathsarrayyesWorkspace-relative POSIX globs the agent may read. Refused here, without lookahead so any RE2-based validator can load the rule: a leading /, any .. segment, a leading ~, a drive-letter prefix and any backslash. The registry re-checks the resolved path against the workspace root.stable
#lease.manifest.allow.read_paths[]stringmin length 1
must not match ^/, (^|/)\.\.(/|$), ^~, ^[A-Za-z]:, \\
#lease.manifest.allow.write_pathsarrayyesWorkspace-relative POSIX globs the agent may change. Refused here, without lookahead: a leading /, any .. segment, a leading ~, a drive-letter prefix and any backslash. The registry re-checks the resolved path against the workspace root, and a change outside the granted set is a scope violation that revokes the lease.stable
#lease.manifest.allow.write_paths[]stringmin length 1
must not match ^/, (^|/)\.\.(/|$), ^~, ^[A-Za-z]:, \\
#lease.manifest.allow.hostsarrayyesHosts the agent may reach. *.example.com matches api.example.com and not example.com; matching a bare parent domain requires listing it. Enforced by the egress proxy once it keys off the lease.stable
#lease.manifest.allow.hosts[]stringA host the agent may reach. A lower-case DNS name of one or more labels, an IPv4 literal or localhost (both are DNS-name shaped), with an optional single leading *. label, or the bare *. Refused by the pattern, which uses no lookahead or backreference and compiles under RE2: a scheme, a port, a path, whitespace, upper case, a trailing dot and a wildcard anywhere but the first label. A port is not a host: the egress proxy matches hostnames, and a rule nothing enforces is a claim. IP literals are admitted because a local model provider (Ollama, LM Studio) lives at 127.0.0.1 and the root policy derives its hosts from provider URLs.pattern ^(\*|(\*\.)?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*)$
min length 1
max length 253
#lease.manifest.allow.commandsarrayyesExecutables the agent may run, by basename.stable
#lease.manifest.allow.commands[]stringAn executable the agent may run. The basename of the executable, at most 128 characters: letters, digits, ., _, +, -. No path separator (identity is the resolved executable's basename, not where it was found), no whitespace (an argument is not part of the name) and no shell operator.pattern ^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$
min length 1
#lease.manifest.allow.tool_argsobjectDECLARED argument constraints per tool (schema set 1.2, development stability): tool name to a JSON Schema the agent proposes for its own calls to that tool, after Progent's argument-schema policies. A declaration, not a grant: in 1.x an issuer MAY omit it from the granted manifest and MUST NOT treat it as granted authority, because the reference gate does not yet evaluate argument schemas and a narrowing rule without an enforcing gate is a claim the corpus cannot test. The vector tool-args-dropped shows the reference dropping it. It becomes a rule when a gate enforces it.keys must match ^[A-Za-z0-9_][A-Za-z0-9_.:/-]{0,127}$
additional properties: see #lease.manifest.allow.tool_args.*
development
a declaration an issuer MAY omit from the grant (SPEC 4.4); becomes a rule when a gate enforces it
#lease.manifest.allow.tool_args.*objectA JSON Schema. Not validated as one here: draft-07 cannot validate a schema as data without a meta-schema $ref, which the self-contained rule forbids.
#lease.manifest.denyobjectyesWhat the agent must not do even if allow would otherwise permit it. Granted deny lists are the UNION of the declared and the parent's, so a child can never shed a parent's refusal.stable
#lease.manifest.deny.commandsarrayyesExecutable names refused outright, for example sudo, su, docker, ssh, curl, wget, launchctl, systemctl.stable
#lease.manifest.deny.commands[]stringAn executable refused outright. The basename of the executable, at most 128 characters: letters, digits, ., _, +, -. No path separator (identity is the resolved executable's basename, not where it was found), no whitespace (an argument is not part of the name) and no shell operator.pattern ^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$
min length 1
#lease.manifest.deny.pathsarrayyesPOSIX globs the agent must not touch: credentials, governance evidence, the lease journal itself. A denial MAY be home-relative (~/.ssh/**), because refusing a path outside the workspace is meaningful even though no allow could grant it; a leading /, any .. segment and any backslash are refused.stable
#lease.manifest.deny.paths[]stringmin length 1
must not match ^/, (^|/)\.\.(/|$), \\
#lease.manifest.deny.hostsarrayyesHostnames refused outright.stable
#lease.manifest.deny.hosts[]stringA host refused outright. A lower-case DNS name of one or more labels, an IPv4 literal or localhost (both are DNS-name shaped), with an optional single leading *. label, or the bare *. Refused by the pattern, which uses no lookahead or backreference and compiles under RE2: a scheme, a port, a path, whitespace, upper case, a trailing dot and a wildcard anywhere but the first label. A port is not a host: the egress proxy matches hostnames, and a rule nothing enforces is a claim. IP literals are admitted because a local model provider (Ollama, LM Studio) lives at 127.0.0.1 and the root policy derives its hosts from provider URLs.pattern ^(\*|(\*\.)?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*)$
min length 1
max length 253
#lease.manifest.budgetobjectyesCeilings. Every field is optional and non-negative; an absent field means the parent's remaining budget applies. A child's granted budget is clamped to its parent's remaining, depth is decremented per generation and fan_out is decremented on the parent as each child is issued.stable
#lease.manifest.budget.stepsintegerMaximum tool calls or turns.min 0
max 9007199254740991
stable
#lease.manifest.budget.wall_clock_msintegerMaximum lifetime in milliseconds; the lease expires when it is spent.min 0
max 9007199254740991
stable
#lease.manifest.budget.tokensintegerMaximum model tokens, input plus output.min 0
max 9007199254740991
stable
#lease.manifest.budget.cost_usdnumberMaximum spend in US dollars.min 0stable
#lease.manifest.budget.depthintegerHow many generations of child lease may be issued beneath this one. Zero means no children. At most 16: the reference root policy allows 4, and a declaration above the ceiling is nonsense rather than something to clamp.min 0
max 16
stable
#lease.manifest.budget.fan_outintegerHow many child leases may be live under this one at once. At most 256: the reference root policy allows 8.min 0
max 256
stable
#lease.manifest.approvalsarrayyesAction names that need a human before the agent may perform them, under the same identifier rule as tool names. Required and may be empty.stable
#lease.manifest.approvals[]stringAn action that needs a human first; the same identifier rule as a tool name. At most 128 characters of letters, digits, _, ., :, / and -, so a governed cdf_ name and a <server>/<tool> pair both fit. * is refused: a lease that names every tool has not named one, and SPEC §5.2 R2 exists because a grant must say what it opens. Whitespace is refused.pattern ^[A-Za-z0-9_][A-Za-z0-9_.:/-]{0,127}$
min length 1
#lease.manifest.attestationobjectWho vouches for the declaration. Optional: an agent presenting its own manifest has nothing to sign with, and the bridge or harness signs on its behalf.stable
#lease.manifest.attestation.issuerstringyesWhich party produced the declaration.one of "agent", "bridge", "harness", "plugin"stable
#lease.manifest.attestation.signaturestringLower-case hex signature over the canonical bytes of the manifest, when the issuer can sign: 64 hex characters, which is HMAC-SHA256 like the lease's own signature. An odd-length or longer value is not a signature this contract defines.pattern ^[0-9a-f]{64}$stable
#lease.manifest.attestation.key_fingerprintstringFingerprint of the key that produced signature. Never the key.min length 1stable
#lease.declared_hashstringyesSHA-256, lower-case hex, of the canonical bytes of the manifest as DECLARED, before narrowing.pattern ^[0-9a-f]{64}$stable
#lease.parent_lease_idstringThe lease this one was issued under. Absent for a root lease.pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$stable
#lease.issued_atstringyesWhen the lease was issued. One form only, because this field is inside the signed bytes: UTC with millisecond precision and a Z suffix (2026-10-05T06:00:00.000Z), which is what Date.prototype.toISOString() writes. An offset form would hash differently for the same instant, so two implementations could disagree about one signature. SPEC §6 rule L1: expires_at is after issued_at, checked by the runner because a schema cannot compare two fields.pattern ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$stable
#lease.expires_atstringyesWhen the lease stops opening anything, whatever its recorded status; fixed at issue. One form only, because this field is inside the signed bytes: UTC with millisecond precision and a Z suffix (2026-10-05T06:00:00.000Z), which is what Date.prototype.toISOString() writes. An offset form would hash differently for the same instant, so two implementations could disagree about one signature. SPEC §6 rule L1: expires_at is after issued_at, checked by the runner because a schema cannot compare two fields.pattern ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$stable
#lease.issuer_session_idstringyesThe kernel session that issued the lease.min length 1stable
#lease.key_fingerprintstringyesFingerprint of the signing key. Never the key.min length 1stable
#lease.signaturestringyesHMAC-SHA256, lower-case hex, over the canonical bytes of every field except this one.pattern ^[0-9a-f]{64}$stable

#uuid

PathTypeRequiredDescriptionConstraintsStability
#uuidstringpattern ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$

#sha256

PathTypeRequiredDescriptionConstraintsStability
#sha256stringpattern ^[0-9a-f]{64}$

#reasonCode

PathTypeRequiredDescriptionConstraintsStability
#reasonCodestringA refusal reason in one of three reserved forms (SPEC §5.2). R<n>: the specification's own conditions, R1 to R6 today; R7 and above are reserved for the specification to assign, and an issuer MUST NOT mint one, although the pattern admits R7 to R99. runtime_error:<name>: the issuer could not decide (no signing key, parent unknown, schema invalid), named by the issuer. vendor:<vendor>:<code>: anything else, namespaced by whoever defines it. Prose goes in reason, never here, so two implementations can compare refusals by code.any of: (1) pattern ^R[1-9][0-9]?$; (2) pattern ^runtime_error:[a-z0-9_]{1,64}$; (3) pattern ^vendor:[a-z0-9-]{1,32}:[A-Za-z0-9_.-]{1,64}$

#usage

PathTypeRequiredDescriptionConstraintsStability
#usageobjectWhat a completed lease consumed, as far as the issuer could measure. Absent fields are unmeasured, not zero.
#usage.tokensintegermin 0
max 9007199254740991
stable
#usage.cost_usdnumbermin 0stable

Conditional requirements

What an if/then clause makes required, one line per property and condition value; the same text appears in the Required column above.

PropertyRequiredWhere
reasonswhen event is "refused"the root
declared_hashwhen event is "refused"the root
leasewhen event is "granted"the root
reasonwhen event is "narrowed"the root
reasonwhen event is "revoked"the root
reasonwhen event is "stopped"the root
bywhen event is "revoked"the root
containmentwhen event is "attached"the root
platformwhen event is "attached"the root