01
What this defines, and what it does not
Four things: the manifest, the A0–A5 scale, the credential and verification. Plus an explicit list of what a conforming credential does not attest.
- The manifest — the declared document and its canonical hash.
- The A0–A5 scale — graded, so that two operators mean the same thing by A3.
- The credential — how the manifest travels inside a W3C Verifiable Credential 2.0, with the
boundResourcesandkillSwitchclaims. - Verification — the eight checks, in order, and what each one proves.
It deliberately does not define how credentials are issued operationally, how a revocation cascade is executed, or what a particular implementation charges. Those belong to an implementation, and CORTEX Seal’s own answers are published separately in its trust framework.
02
The manifest
A JSON object describing exactly one agent. It is the exact object the hash is computed over.
| Field | Type | Required | Meaning |
|---|---|---|---|
| schema | string | no | Identifier of this schema version. Enters the hash. |
| name | string | yes | The agent’s public name. |
| role | string | yes | What the agent does, in one line. |
| mission | string | no | The agent’s objective, in prose. |
| operator | object | yes | Organisation answering for it: legalName, registryCode, jurisdiction. |
| autonomyMax | enum | yes | One of A0…A5. Section 03. |
| skills | string[] | yes | Actions the agent is authorised to perform. |
| prohibited | string[] | yes | Expressly forbidden actions. May be empty; may not be omitted. |
| tools | string[] | no | Tools and scopes, for example crm:write. |
| dataScope | string[] | no | Data sets it may reach. |
| channels | string[] | no | Channels it operates on. |
| limits | object | no | maxRiskWithoutApproval, maxTransactionEur, humanEscalation. |
| bindingsHash | string | no | Hash over the linked resources. Section 05. |
{
"schema": "https://digitalcortex.tech/schemas/agent-manifest/1.0",
"name": "Soporte",
"role": "First-line customer support",
"operator": { "legalName": "ACME Robotics S.L.", "registryCode": "B12345678", "jurisdiction": "ES" },
"autonomyMax": "A2",
"skills": ["ticket.read", "ticket.reply"],
"prohibited": ["payment.execute", "data.delete"]
}Three checks a JSON Schema validator cannot express on its own: a skill present in both skills and prohibited is a contradiction and must be rejected; autonomyMax must be consistent with the declared skills, because an agent declaring A0 cannot list a skill that writes; and operator.jurisdiction must be an ISO 3166-1 alpha-2 code.
03
Canonical form and the hash
manifestHash = sha256(canonicalJson(manifest)), lowercase hexadecimal.
canonicalJson is a recursive serialisation with each object’s keys sorted by code point, no insignificant whitespace, and keys whose value is undefined removed. It is not a plain JSON.stringify: two semantically identical manifests must produce the same bytes, or the hash stops being a useful binding.
function canonical(value) {
if (Array.isArray(value)) return '[' + value.map(canonical).join(',') + ']';
if (value && typeof value === 'object') {
const keys = Object.keys(value).filter((k) => value[k] !== undefined).sort();
return '{' + keys.map((k) => JSON.stringify(k) + ':' + canonical(value[k])).join(',') + '}';
}
return JSON.stringify(value === undefined ? null : value);
}04
The A0–A5 autonomy scale
A graded scale, not a boolean. The point of publishing it is that two operators mean the same thing by A3.
| Level | Name | Definition |
|---|---|---|
| A0 | Observe | Reads and records. Produces no output directed at third parties. |
| A1 | Analyse | Produces analysis and recommendations for people to act on. Takes no action itself. |
| A2 | Prepare | Drafts and stages work — messages, documents, changes — without sending or executing it. |
| A3 | Execute internally | Acts on the operator’s own systems, with no effect outside them. |
| A4 | Execute with human approval | Acts outside the perimeter, with a named human approving each action of that class. The highest level attainable. |
| A5 | Forbidden | A class of vetoed actions: autonomous movement of money, deleting audit records, escalating privileges. |
autonomyMax declares the ceiling, not the usual operating level: an agent declared A4 may spend most of its life doing A1 work. What the declaration says is that it will not go above A4 without a new manifest. A5 is never a valid value for `autonomyMax` in an implementation following this specification: it names the class of actions no agent may take, and it belongs in prohibited.
05
The credential and its claims
A W3C Verifiable Credential 2.0 secured with VC-JOSE-COSE: a compact JWS with typ vc+jwt and algorithm ES256, whose payload is the credential itself.
Both the VC 2.0 data model and the Bitstring Status List v1.0 have been W3C Recommendations since 15 May 2025. The JWS header carries a kid pointing at a verification method in the issuer’s DID document; a verifier that does not recognise that kid’s DID must fail at step 2 and go no further.
| credentialSubject claim | Meaning |
|---|---|
| id | The agent’s DID. |
| autonomyLevel | The level granted by this credential, at or below the manifest’s autonomyMax. |
| manifestHash | The binding. Section 03. |
| manifestVersion | The manifest version it was issued against. |
| scope | { skills[], prohibited[], maxRiskWithoutApproval, domains[], maxTransactionEur }. |
| boundResources | The resources the agent carries, as hashed references only. Below. |
| mcpServers | Tool servers the agent declares it uses, where applicable. |
| killSwitch | Stop coverage and its limits. Below. |
| principal | The legal person answering for it: organisation and role, never a natural person. |
| disclosure | Plain-language statement that this is an AI system and not a person, with the verification URL. |
"boundResources": [
{ "ref": "sha256:1a7b…", "provider": "openai", "type": "API_KEY",
"revocationMethod": "WEBHOOK", "irreversible": false, "failOpen": false }
],
"killSwitch": {
"coverage": { "total": 4, "revocable": 3, "irreversible": 1 },
"methods": ["STOP_ISSUANCE", "WEBHOOK", "PROVIDER_API"],
"graceSecondsMax": 900,
"dualApprovalRequired": true,
"bestEffort": true
}- Only hashed references travel.
ref = sha256(salt ‖ provider ‖ externalId), with the salt per workspace. Never the secret, never the hash of the secret alone — with a small key space that would be an oracle — and never the provider’s identifier. - `bindingsHash` enters the manifest. Adding or removing a linked resource therefore changes
manifestHashand invalidates the live credential. That is correct: if the agent’s hands change, its identity document changes. - `failOpen` is declared, not hidden. Its state lives inside the signed credential precisely so a third party can check it without asking anyone.
- `bestEffort: true` is mandatory whenever any method beyond
STOP_ISSUANCEappears. An implementation may stop issuing its own tokens and publish a revoked status; what it cannot do is promise that a third party’s system executes anything.
Revocation is published with a W3C Bitstring Status List v1.0, itself served as a JWS signed with the same issuer key. A verifier must fetch the list referenced by credentialStatus.statusListCredential, verify its signature, confirm its id matches what the credential references, and read the bit at statusListIndex.
06
Verification, in eight steps
In order. Each step assumes the previous one passed.
| # | Check | What it proves | What it does not prove |
|---|---|---|---|
| 1 | format | The token is a compact JWS with typ=vc+jwt and a kid pointing at a verification method. | Nothing about who signed it. |
| 2 | keyDeclared | The kid resolves to a key the issuer declares in assertionMethod of its published DID document. | That the key is uncompromised. |
| 3 | signature | The ES256 signature over the token verifies against that public key. | That the content is true. |
| 4 | issuerMatch | The issuer.id inside the credential is the same DID that signed it. | That the issuer is trustworthy — that is the verifier’s decision. |
| 5 | validity | validFrom ≤ now ≤ validUntil. | That the credential was not revoked. |
| 6 | revocation | The signed list is the one the credential names and the bit at its index is zero. | That the list is fresh beyond its stated cache window. |
| 7 | manifestBinding | The credential’s manifestHash equals the hash of the manifest the agent publishes now. | That the manifest describes the agent honestly. |
| 8 | scope | A specific action is in skills, is not in prohibited, and its risk is at or below maxRiskWithoutApproval. | That the action will be carried out as declared. |
An implementation may add checks; a DID-document resolution check on the subject is common. A subject DID document served live is a discovery resource, not a trust one: cryptographic verification resolves the issuer’s document.
07
Lifecycle
From declaration to end of service, with what happens to already-issued credentials written down in advance.
| Stage | Rule |
|---|---|
| Declaration | The operator writes the manifest and publishes a version. The hash is computed on publication. |
| Issuance | The credential is issued against one manifest version. Issuance is idempotent per operation key: a retry must not consume a second revocation index. |
| Validity | 90 days in the reference implementation. Rotation re-issues against the same manifest and produces a new credential with a new status index. |
| Change of scope | Publishing a new version changes the hash. The live credential stops matching at step 7 and must be re-issued. The implementation must warn at publication time rather than letting it be discovered in the verifier. |
| Revocation | Sets the bit in the status list. The reason is mandatory: a revocation with no reason is not auditable. Publicly visible within 60 s in the reference implementation. |
| Expiry | An expired credential fails at step 5. Expiry is not revocation and must be reported differently. |
| Superseded | A credential replaced by a newer one for the same agent. It stays cryptographically valid until it expires or is revoked; a verifier should indicate which one is current. |
| End of service | Issued credentials are not retroactively revoked merely because a commercial relationship ended, because third parties rely on them. The status of every credential ever issued stays in the list, for the historical integrity of the verification system. |
08
Conformance
Five conditions, and a warning about what conformance is not.
- It accepts and produces manifests valid against
agent-manifest-1.0.json. - It computes
manifestHashas defined in section 03, byte for byte. - It uses the A0–A5 scale with the definitions of section 04, and never issues
autonomyMax: "A5". - It issues credentials in the format of section 05, with
bestEffort: truewhenever a kill switch claim names any method beyondSTOP_ISSUANCE. - It performs the checks of section 06 in order, reports the third outcome of step 8 distinctly, and states plainly what it does not attest, per section 01.
09
Licences and trade marks
The specification is free to use. The brand is not part of it, and that separation is deliberate.
- This text and the JSON Schema: Creative Commons Attribution 4.0 International. Attribution: “Agent Manifest 1.0, Cosmolabs OÜ, CC BY 4.0”.
- The reference code, including the official SDKs: Apache License 2.0.
- Trade marks: CORTEX Seal, the logo and the seal artwork are trade marks of Cosmolabs OÜ, trade mark application pending, and are expressly excluded from both licences.
10
Versioning
Semantic, and slow on purpose.
- A change that would invalidate an existing manifest is a major version.
- Adding an optional field is a minor version.
- Clarifying prose is a patch.
Because the schema identifier enters the hash, a new major version means new hashes. Implementations should keep validating old versions rather than migrating credentials that were correct when they were issued.