Agent Lease

The grant envelope the kernel returns for an accepted Agent Lease Manifest. The lease id is the only key that opens anything: the tool gate, the dispatcher, and later the egress proxy and process supervisor all key off it. manifest is the GRANTED manifest after narrowing; declared_hash is the SHA-256 of the declared manifest's canonical bytes, so the narrowing diff can be reconstructed from the two. signature is HMAC-SHA256, lower-case hex, over the canonical bytes of every field except signature; key_fingerprint names the key without revealing it. A lease with a parent is a child whose grant is a subset of the parent's; that containment is the registry's rule, not this schema's, because a schema cannot see the parent.

Schema
agent-lease.schema.json, served as JSON at its $id: https://cognitive-delivery.github.io/contract/1.x/agent-lease.schema.json
Dialect
http://json-schema.org/draft-07/schema#
Root
object, open (additional properties are carried)
required: schema_version, lease_id, manifest, declared_hash, issued_at, expires_at, issuer_session_id, key_fingerprint, signature
Stability
none stated at the root; every declared property carries its own
Properties
49 declared: 10 under the root, 39 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, 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_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
manifestobject #grantedManifestyesThe 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
declared_hashstringyesSHA-256, lower-case hex, of the canonical bytes of the manifest as DECLARED, before narrowing.pattern ^[0-9a-f]{64}$stable
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
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
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
issuer_session_idstringyesThe kernel session that issued the lease.min length 1stable
key_fingerprintstringyesFingerprint of the signing key. Never the key.min length 1stable
signaturestringyesHMAC-SHA256, lower-case hex, over the canonical bytes of every field except this one.pattern ^[0-9a-f]{64}$stable

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.

#grantedManifest

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
#grantedManifest
an inlined copy of agent-lease-manifest.schema.json, held identical to its source
objectThe 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.
#grantedManifest.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
#grantedManifest.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
#grantedManifest.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
#grantedManifest.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
#grantedManifest.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
#grantedManifest.agent.providerstringThe organisation or product providing the agent, when it differs from the runtime.stable
#grantedManifest.agent.modelobjectThe model behind the agent, for attribution. Never a prompt, never a key.stable
#grantedManifest.agent.model.vendorstringyesmin length 1stable
#grantedManifest.agent.model.familystringyesmin length 1stable
#grantedManifest.agent.model.versionstringstable
#grantedManifest.agent.harness_versionstringVersion of the harness that generated or presented this manifest.stable
#grantedManifest.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
#grantedManifest.intentobjectyesWhy the agent is running. purpose is required and non-empty: a manifest with no stated purpose is refused.stable
#grantedManifest.intent.spec_slugstringThe governed spec this run serves, when there is one.stable
#grantedManifest.intent.task_idstringThe task within that spec, when there is one.stable
#grantedManifest.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
#grantedManifest.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
#grantedManifest.allow.toolsarrayyesGoverned tool names the agent may call. An empty list in a GRANTED manifest is refused (SPEC §5.2 R2).stable
#grantedManifest.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
#grantedManifest.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
#grantedManifest.allow.read_paths[]stringmin length 1
must not match ^/, (^|/)\.\.(/|$), ^~, ^[A-Za-z]:, \\
#grantedManifest.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
#grantedManifest.allow.write_paths[]stringmin length 1
must not match ^/, (^|/)\.\.(/|$), ^~, ^[A-Za-z]:, \\
#grantedManifest.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
#grantedManifest.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
#grantedManifest.allow.commandsarrayyesExecutables the agent may run, by basename.stable
#grantedManifest.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
#grantedManifest.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 #grantedManifest.allow.tool_args.*
development
a declaration an issuer MAY omit from the grant (SPEC 4.4); becomes a rule when a gate enforces it
#grantedManifest.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.
#grantedManifest.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
#grantedManifest.deny.commandsarrayyesExecutable names refused outright, for example sudo, su, docker, ssh, curl, wget, launchctl, systemctl.stable
#grantedManifest.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
#grantedManifest.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
#grantedManifest.deny.paths[]stringmin length 1
must not match ^/, (^|/)\.\.(/|$), \\
#grantedManifest.deny.hostsarrayyesHostnames refused outright.stable
#grantedManifest.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
#grantedManifest.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
#grantedManifest.budget.stepsintegerMaximum tool calls or turns.min 0
max 9007199254740991
stable
#grantedManifest.budget.wall_clock_msintegerMaximum lifetime in milliseconds; the lease expires when it is spent.min 0
max 9007199254740991
stable
#grantedManifest.budget.tokensintegerMaximum model tokens, input plus output.min 0
max 9007199254740991
stable
#grantedManifest.budget.cost_usdnumberMaximum spend in US dollars.min 0stable
#grantedManifest.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
#grantedManifest.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
#grantedManifest.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
#grantedManifest.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
#grantedManifest.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
#grantedManifest.attestation.issuerstringyesWhich party produced the declaration.one of "agent", "bridge", "harness", "plugin"stable
#grantedManifest.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
#grantedManifest.attestation.key_fingerprintstringFingerprint of the key that produced signature. Never the key.min length 1stable