# CORTEX Seal — Open Specification 1.0

**Agent Manifest 1.0, the A0–A5 autonomy scale, the credential format and the eight verification
steps.**

Version 1.0 · Published 19 September 2026 · Cosmolabs OÜ, Ahtri tn 12, 15551 Tallinn, Estonia,
registry code 17106582.

Specification text: **CC BY 4.0**. JSON Schema: **CC BY 4.0**. Reference code: **Apache-2.0**.
The CORTEX Seal name, logo and seal artwork are **trade marks of Cosmolabs OÜ** and are expressly
excluded from those licences. See `TRADEMARK.md`.

---

## 0. Scope of this document

This specification defines an interoperable way for the operator of an AI agent to declare, in a
machine-readable and signable document, what that agent is authorised to do, what it is explicitly
forbidden to do, and at which autonomy level it runs — and a way for anyone to verify that
declaration without holding an account anywhere.

It defines four things:

1. **The manifest** — the declared document and its canonical hash.
2. **The autonomy scale A0–A5** — graded, so that two operators can mean the same thing by A3.
3. **The credential** — how the manifest is carried inside a W3C Verifiable Credential 2.0,
   including the `boundResources` and `killSwitch` claims.
4. **Verification** — the eight checks, in order, and what each one does and does not prove.

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 to them are published separately in its Trust Framework.

### What a conforming credential does and does not attest

A credential conforming to this specification attests that:

1. an identified legal person declared the content of the manifest;
2. the declaration was signed by an identified issuer at a given time;
3. the manifest has not changed since (`manifestHash`);
4. the credential had not been revoked as of the moment of verification.

It does **not** attest that the declaration is true, that the agent behaves as declared, that the
agent is safe, or that anyone complies with any law. Any implementation that claims otherwise is
not following this specification.

---

## 1. The manifest

A JSON object describing exactly one agent. It is the exact object over which the hash is computed.

### 1.1 Fields

| 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 the agent: `legalName`, `registryCode`, `jurisdiction`. |
| `autonomyMax` | enum | **yes** | One of `A0`…`A5`. See section 2. |
| `skills` | string[] | **yes** | Actions the agent is authorised to perform. |
| `prohibited` | string[] | **yes** | Actions expressly forbidden. May be empty; may not be omitted. |
| `tools` | string[] | no | Tools and scopes, for example `crm:write`. |
| `dataScope` | string[] | no | Data sets the agent may reach. |
| `channels` | string[] | no | Channels the agent operates on. |
| `limits` | object | no | `maxRiskWithoutApproval`, `maxTransactionEur`, `humanEscalation`. |
| `bindingsHash` | string | no | Hash over the agent's linked resources. See section 3.3. |

Machine-readable schema: `agent-manifest-1.0.json` (JSON Schema 2020-12).

### 1.2 Two rules that are easy to miss

1. **`prohibited` is required, even when empty.** Declaring what an agent may not do is half the
   value of the document. Making the field optional would make it disappear.
2. **No personal data of natural persons.** The publicly accountable party is the organisation and
   the role, never a named individual.

### 1.3 Validation beyond the schema

Three checks a JSON Schema validator cannot express on its own:

1. **Scope conflict.** A skill present in both `skills` and `prohibited` is a contradiction, not a
   preference, and must be rejected.
2. **Autonomy ceiling.** `autonomyMax` must be consistent with the declared skills: an agent
   declaring `A0` cannot list a skill that writes.
3. **Operator identity.** `operator.legalName` must name a legal person and
   `operator.jurisdiction` must be an ISO 3166-1 alpha-2 code.

### 1.4 Canonical form and the hash

```
manifestHash = sha256(canonicalJson(manifest))
```

Lowercase hexadecimal. `canonicalJson` is a recursive serialisation with object 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.

```js
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);
}
```

### 1.5 A minimal valid manifest

```json
{
  "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"]
}
```

---

## 2. The A0–A5 autonomy scale

A graded scale, not a boolean. `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.

| 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 operator's 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, deletion of audit records, escalation of privileges. |

**`A5` is never a valid value for `autonomyMax`** in a manifest issued by an implementation
following this specification. It names the class of actions no agent may take, and it belongs in
`prohibited`.

---

## 3. The credential

### 3.1 Format

A W3C Verifiable Credential 2.0 secured with VC-JOSE-COSE: a compact JWS with
`typ: "vc+jwt"`, algorithm `ES256`, whose payload **is** the credential. Both the VC Data Model 2.0
and the Bitstring Status List v1.0 have been W3C Recommendations since 15 May 2025.

```
@context          ["https://www.w3.org/ns/credentials/v2"]
id                urn:uuid:<uuid4>
type              ["VerifiableCredential", "AgentDelegationCredential"]
issuer            { id: <issuer DID>, name, registryCode, jurisdiction, contact }
validFrom         ISO 8601
validUntil        ISO 8601 — 90 days after validFrom in the reference implementation
termsOfUse        [{ type: "IssuerPolicy", id: <policy URL>, policy: <text> }]
credentialStatus  BitstringStatusListEntry { statusPurpose, statusListIndex, statusListCredential }
credentialSubject see 3.2
environment       "SANDBOX" — present only in non-production credentials
```

The JWS header carries `kid` pointing at a `verificationMethod` in the issuer's DID document. A
verifier that does not recognise the `kid`'s DID must fail at step 2 and go no further.

### 3.2 `credentialSubject`

| Claim | Meaning |
|---|---|
| `id` | The agent's DID. |
| `type` | `"AIAgent"`. |
| `name`, `slug`, `role`, `domainCode` | Identity of the agent. |
| `autonomyLevel` | The level granted by this credential, at or below the manifest's `autonomyMax`. |
| `manifestHash` | The binding. See 1.4. |
| `manifestVersion` | The manifest version this credential was issued against. |
| `scope` | `{ skills[], prohibited[], maxRiskWithoutApproval, domains[], maxTransactionEur }`. |
| `boundResources` | See 3.3. |
| `mcpServers` | Tool servers the agent is declared to use, when applicable. |
| `killSwitch` | See 3.4. |
| `principal` | The legal person answering for the agent: organisation and accountable **role**, never a natural person's name. |
| `disclosure` | Plain-language statement that this is an AI system and not a person, the verification URL, the policy URL and the data-protection note. |

### 3.3 `boundResources`

An array describing the resources the agent actually holds — a provider key, a tool server, an
endpoint — so that a third party can see **how much of the agent can actually be stopped**.

```json
"boundResources": [
  { "ref": "sha256:1a7b…", "provider": "openai", "type": "API_KEY",
    "revocationMethod": "WEBHOOK", "irreversible": false, "failOpen": false }
]
```

Three rules are normative:

1. **Only hashed references travel.** `ref = sha256(salt ‖ provider ‖ externalId)`, where the salt is
   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 for the key.
2. **`bindingsHash` enters the manifest.** Adding or removing a bound resource therefore changes
   `manifestHash` and invalidates the live credential. This is intended: if the agent's hands change,
   its identity document changes.
3. **`failOpen` is declared, not hidden.** Its state is inside the signed credential precisely so a
   third party can check it without asking anyone.

### 3.4 `killSwitch`

```json
"killSwitch": {
  "coverage": { "total": 4, "revocable": 3, "irreversible": 1 },
  "methods": ["STOP_ISSUANCE", "WEBHOOK", "PROVIDER_API"],
  "graceSecondsMax": 900,
  "dualApprovalRequired": true,
  "bestEffort": true
}
```

`bestEffort: true` is **mandatory** whenever any method other than `STOP_ISSUANCE` is present. An
implementation may stop issuing its own tokens and may publish a revoked status; it cannot promise
that a third-party system executes anything. Declaring the limitation inside the signed credential,
rather than in an annex, is the point: whoever verifies the credential reads it.

### 3.5 Revocation status

Revocation is published with a W3C Bitstring Status List v1.0, itself served as a JWS signed by 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`.

---

## 4. 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` that points 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 a decision the verifier makes. |
| 5 | **validity** | `validFrom ≤ now ≤ validUntil`. | That the credential was not revoked. |
| 6 | **revocation** | The signed status list references the same list the credential names, and the bit at `statusListIndex` is 0. | That the list is fresh beyond its stated cache window. |
| 7 | **manifestBinding** | The `manifestHash` in the credential equals the hash of the manifest the agent publishes **now**. | That the manifest describes the agent honestly. |
| 8 | **scope** | A specific action is inside `skills` and not inside `prohibited`, and its risk is at or below `maxRiskWithoutApproval`. | That the action will be carried out as declared. |

Step 8 has a third outcome besides pass and fail: **the action is in scope but its risk exceeds the
maximum authorised without approval**. A conforming verifier must report that distinctly — CORTEX
Seal returns `valid: true` together with `requires_approval: true` — because collapsing it into
"valid" is how a supervision requirement quietly disappears.

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.

---

## 5. Lifecycle

| 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 manifest version changes the hash. The live credential stops matching at step 7 and must be re-issued. An implementation must warn at publication time, not leave it to 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. Public visibility within 60 seconds 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 remains cryptographically valid until it expires or is revoked; a verifier should show 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 status list, for the historical integrity of the verification system. |

---

## 6. Conformance

An implementation conforms to CORTEX Seal Open Specification 1.0 if it:

1. accepts and produces manifests valid against `agent-manifest-1.0.json`;
2. computes `manifestHash` as defined in 1.4, byte for byte;
3. uses the A0–A5 scale with the definitions in section 2, and never issues `autonomyMax: "A5"`;
4. issues credentials in the format of section 3, with `bestEffort: true` whenever a kill switch
   claim names any method beyond `STOP_ISSUANCE`;
5. performs the checks of section 4 in order, reports the third outcome of step 8 distinctly, and
   states plainly what it does not attest, per section 0.

Conformance is a **self-declaration**. Nobody certifies it, including us. An implementation may say
that it is *compatible with Agent Manifest 1.0*; it may not call itself CORTEX Seal.

---

## 7. 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.

---

## 8. Licences and trade marks

- **This document and the JSON Schema:** Creative Commons Attribution 4.0 International (CC BY 4.0).
  Attribution string: *"Agent Manifest 1.0, Cosmolabs OÜ, CC BY 4.0"*.
- **Reference code, including the official SDKs:** Apache License 2.0.
- **Trade marks:** CORTEX Seal, the CORTEX Seal logo and the seal artwork are trade marks of
  Cosmolabs OÜ, **trade mark application pending**, and are expressly excluded from both licences.
  Full policy in `TRADEMARK.md`.

---

## 9. Contact

Cosmolabs OÜ · registry code 17106582 · Ahtri tn 12, 15551 Tallinn, Estonia
legal@digitalcortex.tech · security@digitalcortex.tech · abuse@digitalcortex.tech

CORTEX Seal is a trade mark of Cosmolabs OÜ. It is not a qualified electronic seal, a qualified
certificate or a qualified trust service within the meaning of Regulation (EU) No 910/2014.
