01
Qué es la Identidad Agéntica Verificable
Un agente de IA que escribe correos, prepara informes o contacta con clientes no puede ser anónimo. La IAV es el documento de identidad de ese agente: un fichero firmado criptográficamente que dice quién es, quién responde por él, qué puede hacer y qué no, y que cualquiera puede comprobar en el momento sin pedirnos permiso.
Llamamos Identidad Agéntica Verificable (IAV) —o, en lenguaje llano, DNI digital para agentes de IA— al conjunto formado por una credencial firmada, un identificador descentralizado publicado en este dominio, una lista de revocación firmada, un registro público y una página de verificación. El Sello CORTEX es su representación visual: un SVG generado a partir de la propia credencial, no un logotipo.
El emisor es Cosmolabs OÜ (Tallinn, Estonia, registro 17106582), que opera la marca CORTEX y responde de los agentes que identifica. Contacto: legal@digitalcortex.tech.
La política pública que rige la emisión está en /identidad-agentica y es la URL que las propias credenciales llevan dentro, en termsOfUse.id. Un ejemplo vivo: /verify/argos. Para una explicación divulgativa, sin código, está nextai.pro/dni-digital-agentes-ia.
Problema
Atribución
Quien recibe un mensaje de un agente no sabe de quién es el agente ni a quién reclamar. La credencial nombra a la sociedad responsable y su canal de contacto.
Problema
Alcance
Un agente puede decir que está autorizado a cualquier cosa. La credencial lista lo permitido y lo expresamente prohibido, firmado por quien lo delega.
Problema
Integridad
La credencial se vincula al hash del manifiesto registrado. Cambios en sistemas externos al registro requieren comprobaciones adicionales; el hash no observa por sí solo la ejecución.
Problema
Retirada
Revocar actualiza una lista firmada. La consulta debe obtener su versión vigente y los conectores deben aplicar el resultado para retirar acceso efectivo.
02
Arquitectura en cuatro bloques
Cuatro piezas, cada una con un único trabajo. La clave privada vive en un módulo de gestión de claves (KMS) externo y nunca en el servidor web; todo lo demás es público a propósito.
| Bloque | Qué hace | Dónde vive |
|---|---|---|
| Emisor en KMS | Custodia la clave ES256 y firma. La clave privada no sale nunca del KMS; el backend de firma se registra en cada credencial (KMS_GCP, KMS_AWS o DEV_LOCAL para pruebas). | KMS externo (GCP Cloud KMS o AWS KMS) + motor de emisión |
| Credencial W3C VC 2.0 | Construye la credencial y la firma como JWS compacto con typ vc+jwt, atándola al hash del manifiesto del agente y a un índice de la lista de revocación. | Función de emisión, restringida al titular del sistema |
| Publicación | Sirve el documento DID del emisor y de cada agente, el registro público, la credencial vigente, la lista de estado firmada y el sello. | digitalcortex.tech (ficheros estáticos + funciones públicas) |
| Verificación | Ejecuta las comprobaciones una por una y devuelve el detalle, en JSON y en una página pública. Sin login, sin clave de API. | /functions/credentialVerify y /verify/<agente> |
{
"@context": ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/jwk/v1"],
"id": "did:web:digitalcortex.tech",
"verificationMethod": [{
"id": "did:web:digitalcortex.tech#Cf3q-SmjX9b0cdB3PbbvnnvVudiVXiPkt-9guZgAIGY",
"type": "JsonWebKey",
"controller": "did:web:digitalcortex.tech",
"publicKeyJwk": { "kty": "EC", "crv": "P-256", "x": "SMkWL4v6…", "y": "7WzmL-2Z…",
"kid": "Cf3q-SmjX9b0cdB3PbbvnnvVudiVXiPkt-9guZgAIGY", "alg": "ES256", "use": "sig" }
}],
"assertionMethod": ["did:web:digitalcortex.tech#Cf3q-SmjX9b0cdB3PbbvnnvVudiVXiPkt-9guZgAIGY"],
"service": [
{ "id": "did:web:digitalcortex.tech#status-list", "type": "BitstringStatusList",
"serviceEndpoint": "https://digitalcortex.tech/functions/statusList" },
{ "id": "did:web:digitalcortex.tech#agent-registry", "type": "AgentRegistry",
"serviceEndpoint": "https://digitalcortex.tech/functions/agentRegistry" },
{ "id": "did:web:digitalcortex.tech#policy", "type": "IssuerPolicy",
"serviceEndpoint": "https://digitalcortex.tech/identidad-agentica" }
]
}03
Estándares utilizados
Nada propietario en el formato. Si mañana desapareciéramos, la credencial seguiría siendo verificable con herramientas de terceros.
| Estándar | Para qué | Detalle de implementación |
|---|---|---|
| W3C VC Data Model 2.0 | Estructura de la credencial | @context: ["https://www.w3.org/ns/credentials/v2"], type: ["VerifiableCredential", "AgentDelegationCredential"], validFrom/validUntil, termsOfUse, credentialStatus. |
| VC-JOSE-COSE | Cómo se asegura | JWS compacto con typ: "vc+jwt". El payload es la credencial completa, no un JWT con claims sueltos. |
| ES256 | Firma | ECDSA sobre P-256 con SHA-256. Es el único algoritmo aceptado por el verificador. |
| W3C DID Core · did:web | Identificadores | Emisor: did:web:digitalcortex.tech. Agentes: did:web:digitalcortex.tech:agents:<slug>, con controller = el emisor (un agente no controla su propia identidad). |
| RFC 7638 | Identificador de clave | El kid es la huella JWK (SHA-256 del JSON canónico {crv,kty,x,y}, base64url). Así el kid no se puede falsear: se deriva de la propia clave. |
| W3C Bitstring Status List v1.0 | Revocación | Un bit por credencial, GZIP, multibase base64url con prefijo u. La lista es a su vez una credencial firmada. |
| JSON-LD | Semántica | Los contextos son los oficiales del W3C; no publicamos vocabulario propio. |
04
Endpoints públicos
Todo lo necesario para verificar por tu cuenta, sin credenciales de acceso, con CORS abierto (Access-Control-Allow-Origin: *).
| Método y ruta | Content-Type | Respuesta (abreviada) |
|---|---|---|
| GET /.well-known/did.json | application/json | Documento DID del emisor: verificationMethod (JWK ES256), assertionMethod y service (status-list, agent-registry, policy). |
| GET /agents/<slug>/did.json | application/json | Documento DID del agente: controller = emisor y tres service (credential, seal, verify). |
| GET /.well-known/agents.json | application/json | Instantánea estática del registro; incluye el campo live apuntando al registro en vivo. |
| GET /functions/agentRegistry | application/json (cache 120 s) | |
| GET /functions/agentCredential?slug= | application/vc+jwt (cache 300 s) | El JWS compacto tal cual, en texto. Cabecera X-Credential con el identificador legible (p. ej. CRD-2026-0001). 404 si no hay credencial vigente. |
| GET /functions/credentialVerify?slug= | application/json (cache 30 s) | Resultado de las comprobaciones, una por una. Acepta ?did=, ?c=, ?skill= y POST { jwt }. Esquema completo en la sección 08. |
| GET /functions/statusList | application/vc+jwt (cache 60 s) | Lista de revocación vigente, firmada. Cabecera X-Status-List-Version. &format=json devuelve metadatos (versión, revoked_count, published_at, issuer_kid) en lugar del JWT. |
| GET /functions/agentSeal?slug= | image/svg+xml (cache 60 s) | El sello, regenerado en el momento desde la credencial. Cabeceras X-Credential y X-Credential-Status. &format=json devuelve metadatos; &c=CRD-… pide el sello de una credencial concreta. |
| Situación | HTTP | Cuerpo |
|---|---|---|
| Falta el parámetro obligatorio | 400 | { "error": "Indica ?slug=" } |
| Agente no público o inexistente | 404 | { "valid": false, "reason": "Agente desconocido para este emisor" } |
| Agente sin credencial vigente | 200 / 404 | El verificador responde 200 con valid: false y explica el estado; la credencial y el sello devuelven 404. |
| Fallo interno del verificador | 500 | { "valid": false, "error": "VERIFIER_ERROR" } |
| Otros fallos internos | 500 | REGISTRY_ERROR, SEAL_ERROR, CREDENTIAL_ERROR, STATUS_LIST_ERROR. |
05
El manifiesto del agente
Antes de emitir nada hay que declarar qué es el agente. El manifiesto es la instantánea versionada de los campos declarados en el registro; la credencial no delega en «un agente llamado Argos», delega en una versión concreta de esa configuración.
El manifiesto se publica como una versión inmutable (append-only): cada publicación crea un registro nuevo con su número de versión, su changelog y su hash, y marca la anterior como sustituida. Sin manifiesto publicado y vigente, la emisión de credencial se rechaza con el código NO_MANIFEST — a propósito.
Campos del manifiesto
| Campo | Tipo / valores | Qué significa |
|---|---|---|
| name | texto | Nombre público del agente. Aparece en la credencial y en el sello. |
| slug | texto, [a-z0-9_-]+ | Identificador en URLs y en el DID. Se valida al emitir: un slug inválido para un DID bloquea la emisión. |
| role | texto | Función declarada, p. ej. «Lead NextAI». |
| mission | texto | Objetivo permanente del agente, en una frase. |
| manifesto | texto | Principio operativo con el que se le juzga. |
| domain_scope | lista de personal · cosmo_labs · soulbyte · nextai | Dominios de la organización en los que opera. El primero se usa como domainCode de la credencial y determina la paleta del sello. |
| autonomy_max | A0 · A1 · A2 · A3 · A4 · A5 | Techo de autonomía. Ver la sección 06. |
| is_lead · is_overseer · is_independent | booleanos | Posición del agente en la jerarquía operativa. |
| health_status | healthy · degraded · offline | Estado operativo declarado. |
| public | booleano | Si el agente aparece en el registro público. Un agente no público no existe para el exterior: ni registro, ni credencial, ni sello. |
| current_version · manifest_hash | texto | Los escribe la publicación del manifiesto; son el puntero a la versión vigente. |
| did · credential_status · active_credential_id | texto · none|active|expired|revoked · texto | Los escribe la emisión o la revocación, no el autor del manifiesto. |
El alcance (scope), el riesgo máximo sin aprobación, el límite de importe y el TTL no viven en el manifiesto: son parámetros de la emisión, y por eso pueden endurecerse sin tocar la configuración del agente.
Parámetros de la emisión
| Parámetro | Valores | Qué hace |
|---|---|---|
| scope_skills | lista de skill_id, no vacía | Lo que el agente está autorizado a hacer. Una lista vacía se rechaza: una credencial sin alcance no delega nada. |
| scope_prohibited | lista de skill_id o acciones | Lo expresamente prohibido. Solaparse con scope_skills se rechaza. |
| max_risk_without_approval | LOW · MEDIUM · HIGH (por defecto LOW) | Riesgo máximo que puede ejecutar sin aprobación humana. Por encima, la comprobación de alcance devuelve REQUIRE_APPROVAL. |
| max_transaction_eur | número o null | Límite de importe. null significa que el agente no puede mover dinero. |
| ttl_days | número, máximo 365 (por defecto 90) | Vigencia de la credencial. Ver la sección 10. |
| public | booleano | Publica o retira al agente del registro público. |
Taxonomía de acciones
Las acciones se identifican con el skill_id del catálogo de skills del emisor, en notación dominio.verbo. No es una lista cerrada en el código: cada skill del catálogo declara su risk_level (LOW, MEDIUM, HIGH, PROHIBITED), su estado (DRAFT, ACTIVE, QUARANTINED, DEPRECATED), sus herramientas y conectores necesarios, si es idempotente y qué evidencia exige. Al emitir se avisa —sin bloquear— si una skill del alcance no existe o no está activa.
Las acciones documentadas hoy, tal y como aparecen en el alcance de referencia:
| skill_id | Uso típico en una credencial |
|---|---|
| lead.research | Permitida: investigar una cuenta o un contacto a partir de fuentes públicas. |
| outreach.draft | Permitida: redactar un borrador de mensaje, sin enviarlo. |
| outreach.send | Prohibida: enviar comunicación externa en nombre de la organización. |
| payment.execute | Prohibida: ejecutar un pago. |
| contract.sign | Prohibida: firmar o aceptar un contrato. |
El manifestHash: cómo se calcula y qué lo invalida
El hash es SHA-256 en hexadecimal sobre una serialización JSON canónica del manifiesto: claves ordenadas alfabéticamente en todos los niveles de anidamiento, sin espacios, con los valores undefined descartados. Antes de calcularlo se retiran los campos volátiles del almacenamiento (id, created_date, updated_date, created_by, is_sample), que cambiarían el hash sin que cambiase el agente.
function canonical(v) {
if (v === null || typeof v !== 'object') return JSON.stringify(v ?? null);
if (Array.isArray(v)) return '[' + v.map(canonical).join(',') + ']';
return '{' + Object.keys(v).sort()
.filter(k => v[k] !== undefined)
.map(k => JSON.stringify(k) + ':' + canonical(v[k])).join(',') + '}';
}
// manifest_hash = SHA-256(canonical(manifiesto)) en hexadecimal, 64 caracteresLa comprobación manifestBinding compara el hash firmado con el manifiesto registrado como vigente. Cambiar sus campos exige publicar una nueva versión y reemitir. Esta comprobación no inspecciona la configuración efectiva del sistema en ejecución: cambios externos en prompts, modelos, herramientas o permisos requieren controles adicionales. El alcance de la emisión se firma por separado y no forma parte de ese hash.
Ejemplo: el manifiesto de Argos
{
"human_id": "AGT-2026-0004",
"name": "Argos",
"slug": "argos",
"role": "Lead NextAI",
"mission": "Conducir NextAI entregando valor medible a cada cliente.",
"manifesto": "Vigilancia panorámica sobre cada compromiso con cliente.",
"autonomy_max": "A4",
"domain_scope": ["nextai"],
"is_lead": true,
"is_overseer": false,
"is_independent": false,
"health_status": "healthy",
"public": true
}
// manifest_hash = SHA-256(canonical(…)) → 64 caracteres hexadecimales
// Se publica con { subject_type: "AGENT", version: "1.0.0", changelog: "Primera versión" }La instantánea se toma del registro del agente antes de escribirle la nueva versión, de modo que el hash no dependa de sí mismo. Puedes comprobar el hash vigente de cualquier agente público en la respuesta del verificador, campo credential.manifestHash.
06
Niveles de autonomía A0–A5
La autonomía no es un adjetivo de marketing: es un techo declarado en el manifiesto, firmado en la credencial y pintado en el sello.
| Nivel | Nombre | Qué permite |
|---|---|---|
| A0 | Observar | Leer, buscar, recopilar, detectar y medir. No produce ningún cambio. |
| A1 | Analizar | Clasificar, resumir, estimar y detectar riesgos. |
| A2 | Preparar | Crear borradores, propuestas, opciones y planes, sin ejecutarlos. |
| A3 | Ejecutar interno | Cambios internos reversibles dentro de su dominio. |
| A4 | Ejecutar con aprobación | Acción persistente o externa, siempre con una aprobación humana válida. |
| A5 | Prohibido | Mover dinero de forma autónoma, borrar la auditoría o escalar privilegios. No es un nivel alcanzable: es la clase de acciones vedadas. |
07
Anatomía de la credencial
Un JWS compacto de tres partes separadas por puntos. La segunda parte no es un JWT con claims sueltos: es la credencial W3C completa.
Cabecera protegida
{
"alg": "ES256",
"typ": "vc+jwt",
"kid": "did:web:digitalcortex.tech#Cf3q-SmjX9b0cdB3PbbvnnvVudiVXiPkt-9guZgAIGY"
}El kid apunta a un verificationMethod del documento DID del emisor; el fragmento tras # es la huella JWK de la propia clave (RFC 7638). El verificador exige typ = "vc+jwt" y un kid que contenga #, y rechaza cualquier otra combinación antes incluso de mirar la firma.
Payload: la credencial
{
"@context": ["https://www.w3.org/ns/credentials/v2"],
"id": "urn:uuid:8f1c9a52-…",
"type": ["VerifiableCredential", "AgentDelegationCredential"],
"issuer": {
"id": "did:web:digitalcortex.tech",
"name": "Cosmolabs OÜ",
"registryCode": "17106582",
"jurisdiction": "EE",
"contact": "legal@digitalcortex.tech"
},
"validFrom": "2026-09-10T09:00:00.000Z",
"validUntil": "2026-12-09T09:00:00.000Z",
"termsOfUse": [{
"type": "IssuerPolicy",
"id": "https://digitalcortex.tech/identidad-agentica",
"policy": "Esta credencial acredita únicamente que el emisor autoriza al agente identificado a operar dentro
del alcance declarado, mientras esté vigente y no revocada. … Su validez debe comprobarse en tiempo
real en la URL de verificación incluida en la propia credencial. El sello visual derivado puede
reproducirse íntegro y sin alteraciones con fines informativos."
}],
"credentialStatus": {
"id": "https://digitalcortex.tech/functions/statusList#48213",
"type": "BitstringStatusListEntry",
"statusPurpose": "revocation",
"statusListIndex": "48213",
"statusListCredential": "https://digitalcortex.tech/functions/statusList"
},
"credentialSubject": {
"id": "did:web:digitalcortex.tech:agents:argos",
"type": "AIAgent",
"name": "Argos",
"slug": "argos",
"role": "Lead NextAI",
"domainCode": "nextai",
"autonomyLevel": "A4",
"manifestVersion": "1.0.0",
"manifestHash": "…64 caracteres hexadecimales…",
"scope": {
"skills": ["lead.research", "outreach.draft"],
"prohibited": ["outreach.send", "payment.execute", "contract.sign"],
"maxRiskWithoutApproval": "LOW",
"domains": ["nextai"],
"maxTransactionEur": null
},
"principal": {
"type": "Organization",
"legalName": "Cosmolabs OÜ",
"registryCode": "17106582",
"jurisdiction": "EE",
"address": "Ahtri tn 12, 15551 Tallinn, Estonia",
"contact": "legal@digitalcortex.tech",
"accountableRole": "Administrador"
},
"disclosure": {
"statement": "Argos es un sistema de inteligencia artificial operado por Cosmolabs OÜ. No es una persona.
De sus acciones dentro del alcance autorizado responde Cosmolabs OÜ.",
"regulation": "Reglamento (UE) 2024/1689 (AI Act), art. 50 — transparencia",
"dataProtection": "Esta credencial y su sello no contienen datos personales de personas físicas.
Contacto: legal@digitalcortex.tech",
"verifyUrl": "https://digitalcortex.tech/verify/argos",
"policyUrl": "https://digitalcortex.tech/identidad-agentica"
}
}
}
// Firma (tercer segmento del JWS), abreviada: MEUCIQD…| Campo | Papel |
|---|---|
| id | Identificador único de esta credencial concreta (urn:uuid). Se reemplaza en cada reemisión. |
| issuer | Datos registrales públicos del emisor. Si existe LEI, se añade el campo lei. |
| validFrom / validUntil | Ventana de vigencia. La diferencia es el TTL de emisión. |
| termsOfUse | Condiciones bajo las que el emisor publica la credencial, incluida la URL de la política (VC 2.0 §5.2). |
| credentialStatus | Entrada en la lista de revocación: índice del bit y URL canónica de la lista firmada. |
| credentialSubject.scope | Lo permitido, lo prohibido, el riesgo máximo y el límite de importe. |
| credentialSubject.principal | Quién responde: la sociedad, sus datos registrales y el rol responsable. Nunca una persona física. |
| credentialSubject.disclosure | El aviso de transparencia listo para copiar, con la referencia normativa y las URLs de verificación y política. |
Minimización de datos
La credencial y el sello no contienen datos personales de personas físicas: ni de quien opera el agente, ni de terceros. La rendición de cuentas pública se expresa como organización + rol + canal de contacto (accountableRole), porque la persona concreta consta en el registro mercantil, no en un documento que va a circular. El verificador filtra además cualquier campo de persona responsable aunque una credencial antigua lo llevara dentro.
08
Verificación: las ocho comprobaciones
El verificador no devuelve un semáforo. Devuelve qué comprobó, en qué orden y con qué resultado, porque enseñar el trabajo es la mitad del valor.
Siete comprobaciones las ejecuta el verificador del emisor sobre la credencial; la octava la añade la página pública resolviendo el documento DID en este dominio. La cadena se detiene en la primera que falla: si la firma no es válida, no tiene sentido mirar la vigencia.
| # | Comprobación | Qué comprueba | Cuándo falla |
|---|---|---|---|
| 1 | format | Que es un JWS compacto, con typ: "vc+jwt" y un kid que apunta a un verificationMethod (contiene #). | «No es un JWS compacto válido», «typ esperado vc+jwt, recibido …» o «Falta kid o no apunta a un verificationMethod». |
| 2 | keyDeclared | Que la clave que firmó es la que el emisor declara públicamente en assertionMethod de su documento DID. | «La credencial la firma otro DID, no did:web:digitalcortex.tech» o «La clave … no es la declarada en el documento DID». |
| 3 | signature | Que la firma ES256 es matemáticamente válida sobre cabecera y payload con esa clave pública. | «Firma inválida». Cualquier byte alterado en la credencial cae aquí. |
| 4 | issuerMatch | Que el emisor declarado dentro de la credencial coincide con el que efectivamente la firmó. | «La credencial declara emisor X pero la firmó Y». |
| 5 | validity | Que la fecha actual está entre validFrom y validUntil. | «Aún no válida (desde …)» o «Caducada el …». Si pasa, el detalle indica cuántos días quedan. |
| 6 | revocation | Que existe lista de revocación publicada, que está firmada por la misma clave, que es la que la credencial referencia y que el bit de esta credencial está a 0. | «No hay lista de revocación publicada», «La lista de revocación no está firmada por el emisor», «La lista publicada no es la que referencia la credencial» o «REVOCADA (índice N)». |
| 7 | manifestBinding | Que el hash del manifiesto que lleva dentro la credencial coincide con el del manifiesto que el emisor tiene registrado como vigente. | «El agente fue modificado: la credencial autoriza un hash y el emisor tiene registrado como vigente otro». |
| 8 | did_document | Que /.well-known/did.json está publicado en este dominio y declara exactamente la clave que firmó. | «Documento no publicado todavía» o «El documento publicado no declara la clave que firmó». |
La API del verificador
| Forma de llamada | Qué verifica |
|---|---|
| GET ?slug=argos | La credencial vigente de ese agente público. |
| GET ?did=did:web:digitalcortex.tech:agents:argos | Lo mismo, identificando por DID. |
| GET …&c=CRD-2026-0001 | Además dice si esa credencial concreta (la que codifica el QR de un sello) sigue siendo la vigente. |
| GET …&skill=outreach.send | Añade la comprobación de alcance. |
| POST { jwt } | Verifica cualquier credencial emitida por este emisor, la tengas de donde la tengas. |
{
"valid": true,
"checks": {
"format": { "ok": true, "detail": "JWS con typ=vc+jwt y kid presente" },
"keyDeclared": { "ok": true, "detail": "La clave está declarada en assertionMethod del emisor" },
"signature": { "ok": true, "detail": "Firma ES256 válida" },
"issuerMatch": { "ok": true, "detail": "Emitida por Cosmolabs OÜ (did:web:digitalcortex.tech)" },
"validity": { "ok": true, "detail": "En vigor, caduca en 83 días" },
"revocation": { "ok": true, "detail": "No revocada" },
"manifestBinding": { "ok": true, "detail": "Manifiesto 1.0.0 (a91c4f22e8…3b7d) sin cambios" }
},
"credential": { "humanId": "CRD-2026-0001", "id": "urn:uuid:8f1c9a52-…",
"issuedAt": "…", "expiresAt": "…",
"manifestVersion": "1.0.0", "manifestHash": "…", "signingBackend": "KMS_GCP" },
"reference": { "requested": "CRD-2026-0001", "isCurrent": true },
"didDocument": { "published": true, "matches": true,
"url": "https://digitalcortex.tech/.well-known/did.json" },
"agent": { "did": "did:web:digitalcortex.tech:agents:argos", "name": "Argos",
"slug": "argos", "role": "Lead NextAI", "domain": "nextai",
"autonomyLevel": "A4", "manifestVersion": "1.0.0",
"scope": { }, "disclosure": { } },
"principal": { "type": "Organization", "legalName": "Cosmolabs OÜ" },
"termsOfUse": [ ],
"issuer": { "id": "did:web:digitalcortex.tech", "name": "Cosmolabs OÜ" },
"validity": { "from": "…", "until": "…" }
}Cuando algo falla, valid es false, reason trae el motivo en texto legible y checks contiene solo las comprobaciones ejecutadas hasta la que falló, con esa última marcada ok: false. Si el sello escaneado apunta a una credencial que ya no es la vigente, reference.isCurrent es false y reference.note explica si fue revocada o sustituida y cuál es la vigente ahora.
| Estado | Qué significa | Dónde se ve |
|---|---|---|
| ACTIVE | Credencial vigente: firmada, en fecha y no revocada. | Sello (X-Credential-Status), registro (status: active), verificador (valid: true). |
| EXPIRED | Pasó validUntil sin reemisión. El sello se apaga y muestra el banner CADUCADA. | Sello y registro (status: expired). |
| REVOKED | El emisor puso su bit a 1 en la lista de estado. El sello muestra REVOCADA. | Sello, registro (status: revoked) y comprobación revocation. |
| SUPERSEDED | Sustituida por una reemisión. Su bit también se pone a 1: una credencial sustituida que siguiera verificando sería un agujero. | Registro (status: superseded) y reference.note del verificador. |
Verificar por tu cuenta en tres pasos
No hace falta confiar en nuestra página. Con curl y jose en Node (v18 o superior, sin más dependencias) tienes la verificación completa en unas veinte líneas.
# 1 · la credencial vigente del agente (JWS compacto, typ vc+jwt)
curl -s "https://digitalcortex.tech/functions/agentCredential?slug=argos" -o argos.jwt
# 2 · el documento DID del emisor, con su clave pública
curl -s "https://digitalcortex.tech/.well-known/did.json" -o did.jsonimport { readFileSync } from 'node:fs';
import { gunzipSync } from 'node:zlib';
import { importJWK, compactVerify, decodeProtectedHeader } from 'jose';
const jws = readFileSync('argos.jwt', 'utf8').trim();
const did = JSON.parse(readFileSync('did.json', 'utf8'));
// 1 · formato
const { alg, typ, kid } = decodeProtectedHeader(jws);
if (typ !== 'vc+jwt' || alg !== 'ES256') throw new Error('Formato inesperado');
// 2 · la clave está declarada por el emisor
const vm = did.verificationMethod.find((m) => m.id === kid);
if (!vm || !did.assertionMethod.includes(kid)) throw new Error('kid no declarado');
const key = await importJWK(vm.publicKeyJwk, 'ES256');
// 3 · firma — compactVerify lanza si no casa
const { payload } = await compactVerify(jws, key);
const vc = JSON.parse(new TextDecoder().decode(payload));
// 4 · emisor coherente 5 · vigencia
const now = new Date();
if (vc.issuer.id !== 'did:web:digitalcortex.tech') throw new Error('Emisor incoherente');
if (new Date(vc.validFrom) > now || new Date(vc.validUntil) < now) throw new Error('Fuera de vigencia');
// 6 · revocación — la lista va firmada por la MISMA clave
const res = await fetch(vc.credentialStatus.statusListCredential);
const { payload: lp } = await compactVerify(await res.text(), key);
const list = JSON.parse(new TextDecoder().decode(lp));
const bits = gunzipSync(Buffer.from(list.credentialSubject.encodedList.slice(1), 'base64url'));
const i = Number(vc.credentialStatus.statusListIndex);
if ((bits[i >> 3] & (128 >> (i % 8))) !== 0) throw new Error('REVOCADA');
console.log('OK', vc.credentialSubject.name, vc.credentialSubject.autonomyLevel, vc.validUntil);Falta la séptima comprobación —que el manifiesto del agente no haya cambiado— porque solo el emisor conoce el hash del manifiesto que el emisor tiene registrado como vigente. Se obtiene del verificador, en credential.manifestHash. Es, a propósito, la única pieza que no puedes reproducir por tu cuenta.
Qué NO prueba una verificación
- No acredita la calidad ni el resultado de ninguna tarea concreta que haya hecho el agente.
- No sustituye al contrato ni a las condiciones del servicio que rijan entre las partes.
- No convierte al agente en sujeto de derechos u obligaciones: de sus actuaciones dentro del alcance autorizado responde Cosmolabs OÜ conforme a la legislación aplicable.
- No prueba que el mensaje que has recibido lo enviara ese agente: prueba que existe un agente identificado con ese alcance. Atribuir un mensaje concreto exige firmar también el mensaje, y eso no forma parte de esta credencial.
- No es una auditoría externa ni la revisión de un tercero: es una declaración del emisor, verificable en su integridad y en su vigencia.
- No vale una captura. El resultado es válido en el instante de la consulta. Un sello impreso o una pantalla guardada no acreditan nada: hay que volver a comprobar.
09
El sello: nada es decorativo
El sello es una lectura gráfica de la credencial, generada de forma determinista a partir de ella. Mismo agente y mismo manifiesto, mismo sello; cambia el manifiesto, cambia el sello.
El arte se siembra con manifestHash|did, para diferenciar visualmente las identidades y las versiones del manifiesto. Esa representación no garantiza unicidad visual ni autentica al portador de una copia. No se almacena en ninguna parte: se regenera idéntico en cada petición a partir de la credencial.
| Elemento | Qué codifica |
|---|---|
| Anillo exterior de 256 marcas | Los 256 bits del manifestHash, literalmente: marca larga y clara = 1, marca corta y tenue = 0. |
| Anillo interior de 128 marcas | La huella del DID del agente. |
| Nebulosa central | Un campo de flujo de cientos de líneas de corriente sembrado con el hash y el DID. Es la huella del hash hecha imagen. |
| Rombos claros en órbita | Las acciones permitidas (scope.skills), cada una etiquetada con su skill_id en radial. |
| Rombos rojos tachados | Las acciones expresamente prohibidas (scope.prohibited). |
| Barra de cinco segmentos | El nivel de autonomía, de A1 a A5. El quinto segmento se pinta en rojo: es la frontera de lo prohibido. |
| Sigilo hexagonal central | Polígonos derivados del hash, más la inicial del nombre del agente sobre el núcleo luminoso. |
| Anillos tipográficos | Arriba, DID e identificador de credencial. Abajo, fecha de caducidad, emisor, versión del manifiesto y prefijo de su hash. |
| Código QR | La URL de verificación de esa credencial concreta: /verify/<slug>?c=<CRD-…>. No es un enlace genérico. |
| Animación | Solo si la credencial está vigente. Revocada o caducada: estático, atenuado al 42 % y con banner REVOCADA o CADUCADA. Respeta prefers-reduced-motion. |
| Paleta | La determina el domainCode del agente (nextai, cosmo_labs, soulbyte, personal). Identifica el dominio, no adorna. |
Formatos y cabeceras
| Petición | Devuelve |
|---|---|
| GET /functions/agentSeal?slug=argos | image/svg+xml; charset=utf-8 — el SVG completo, animado si la credencial está vigente. |
| GET /functions/agentSeal?slug=argos&c=CRD-2026-0001 | El sello de esa credencial concreta. Si ya no es la vigente, sale atenuado y con banner. |
| GET /functions/agentSeal?slug=argos&format=json | Metadatos estructurados (compatibles con ERC-721 y con el fichero de registro ERC-8004): name, description, image, animation_url, external_url y attributes con rol, dominio, autonomía, número de acciones permitidas y prohibidas, riesgo máximo sin aprobación, estado, versión y hash del manifiesto, emisor y fecha de caducidad. |
| Cabecera | Valor |
|---|---|
| X-Credential | Identificador legible de la credencial pintada, p. ej. CRD-2026-0001. |
| X-Credential-Status | ACTIVE, EXPIRED o REVOKED. Es el estado real en el momento de servir. |
| Cache-Control | public, max-age=60 si está vigente; 300 si no lo está (una credencial revocada ya no va a cambiar). |
| Access-Control-Allow-Origin | * — puedes incrustarlo desde cualquier dominio. |
Condiciones de uso del sello
- Puede reproducirse íntegro y sin alteraciones, con fines informativos.
- Siempre acompañado de su QR o con la URL de verificación visible. Recortar o sustituir el QR está prohibido.
- El sello que servimos se apaga solo cuando la credencial se revoca o caduca: nunca miente sobre el estado. Una copia antigua guardada como imagen no prueba nada.
- Está prohibido presentar como vigente una identidad revocada o caducada, o hacer pasar por agente de CORTEX a un sistema que no lo sea. Avisos a legal@digitalcortex.tech.
10
Ciclo de vida y revocación
Una autorización sin fecha de caducidad y sin forma de retirarla no es una autorización: es una declaración de intenciones.
| Momento | Qué ocurre |
|---|---|
| Emisión | Solo el titular del sistema puede emitir. Exige manifiesto publicado y vigente (si no, NO_MANIFEST) y que el hash del agente coincida con el de esa versión (si no, MANIFEST_MISMATCH). Se asigna un índice aleatorio —nunca secuencial, para que el índice no filtre la fecha de emisión— en la lista de estado y se firma en el KMS. |
| Renovación | El TTL por defecto es de 90 días (configurable, máximo 365). Renovar es reemitir: nueva credencial, nuevo urn:uuid, nuevo índice y nuevas fechas. |
| Reemisión por cambio de manifiesto | Cambiar el manifiesto registrado cambia su hash y requiere actualizar la vinculación manifestBinding. Hay que publicar la nueva versión del manifiesto y reemitir. |
| Sustitución | Al emitir, cualquier credencial anterior activa pasa a SUPERSEDED y su bit se pone a 1 en la lista. Solo hay una credencial vigente por agente. |
| Revocación | Exige un motivo —una revocación sin motivo no es auditable—, pone el bit a 1, firma y publica una versión nueva de la lista de estado, y marca al agente como credential_status: revoked. |
| Caducidad | Al pasar validUntil sin reemisión, la comprobación validity falla y el estado pasa a EXPIRED. No requiere ninguna acción del emisor. |
Cómo funciona la lista de revocación
Un bit por credencial, el más significativo primero dentro de cada byte, sobre una lista de 131.072 bits (16 KB). Se comprime con GZIP y se codifica en multibase base64url sin relleno, con prefijo u. La lista es a su vez una credencial firmada: si no lo fuera, cualquiera podría servir una lista vacía y «des-revocar» agentes.
Cada publicación crea una versión nueva y marca la anterior como sustituida; la vigente viaja en la cabecera X-Status-List-Version. La caché es de 60 segundos con revalidación en segundo plano: ese valor no es una garantía de propagación global ni de retirada efectiva de acceso. Los índices no se reutilizan jamás, aunque la credencial que los ocupaba haya caducado.
Qué ve un tercero tras una revocación
- El verificador devuelve
valid: falsecon la comprobaciónrevocationen rojo y el detalle «REVOCADA (índice N)». - La página /verify/<agente> muestra «Credencial revocada» y el sello atenuado.
- El sello servido desde este dominio deja de animarse, se atenúa y pinta el banner REVOCADA, con la cabecera
X-Credential-Status: REVOKED. - El registro sigue listando al agente con
status: "revoked"y su fecha de revocación: un registro que solo enseña lo vigente es un escaparate, no un registro. - La credencial en sí deja de servirse:
/functions/agentCredentialresponde 404. Quien conserve una copia del JWT podrá seguir comprobando la firma, y precisamente por eso la consulta de la lista de revocación es obligatoria en cualquier verificación seria.
11
Integración para terceros y clientes
Si trabajas con un agente identificado por CORTEX, o si quieres identificar los tuyos con el mismo enfoque, esto es lo que necesitas.
Mostrar el sello en una web
El sello es un SVG servido con CORS abierto: basta una etiqueta img envuelta en un enlace a la página de verificación. No lo copies a tu servidor: si lo sirves desde el nuestro, se apaga solo cuando la credencial deja de estar vigente.
<a href="https://digitalcortex.tech/verify/argos"
rel="noopener" target="_blank"
title="Verificar la identidad de este agente de IA">
<img src="https://digitalcortex.tech/functions/agentSeal?slug=argos"
alt="Sello de identidad del agente de IA Argos, emitido por Cosmolabs OU"
width="240" height="240" loading="lazy" />
</a>Si necesitas saber el estado sin renderizar la imagen, una petición HEAD al mismo endpoint devuelve X-Credential-Status. Para integraciones programáticas, usa el verificador y lee valid y checks.
Firma de correo
En la firma de los correos que envía un agente, tres líneas bastan y son verificables: qué es, quién responde y dónde comprobarlo. El texto exacto del aviso ya viene dentro de la credencial, en credentialSubject.disclosure.statement, y la URL en disclosure.verifyUrl.
Argos · Agente de IA de Cosmolabs OU (CORTEX)
Sistema de inteligencia artificial. No es una persona.
Identidad verificable: https://digitalcortex.tech/verify/argosAviso de transparencia en el primer mensaje
El art. 50 del Reglamento (UE) 2024/1689 exige que quien interactúa con un sistema de IA lo sepa. La práctica que seguimos: el aviso aparece en el primer mensaje de cada conversación, en lenguaje claro, con el nombre de la sociedad responsable y un enlace donde comprobarlo. En canales con cabeceras propias, además, un encabezado legible por máquinas.
Hola, soy Argos, un sistema de inteligencia artificial operado por Cosmolabs OU.
No soy una persona. Puedes comprobar mi identidad, quien responde por mi y que
tengo permitido hacer en https://digitalcortex.tech/verify/argos
X-AI-Agent: did:web:digitalcortex.tech:agents:argos
X-AI-Agent-Verify: https://digitalcortex.tech/verify/argosComprobar un agente desde tu sistema
| Quiero… | Llamada |
|---|---|
| Saber si un agente está autorizado ahora | GET /functions/credentialVerify?slug=<slug> |
| Saber si puede hacer una acción concreta | GET /functions/credentialVerify?slug=<slug>&skill=<skill_id> |
| Verificar una credencial que me han entregado | POST /functions/credentialVerify con { jwt } |
| Listar todos los agentes públicos y su estado | GET /functions/agentRegistry |
| Comprobar revocaciones por mi cuenta | GET /functions/statusList (y su versión en X-Status-List-Version) |
Cachea con cabeza: el verificador se sirve con max-age=30 y la lista de estado con max-age=60. No caches un resultado de verificación más allá de eso, porque una revocación debe verse en menos de un minuto.
Emitir con el mismo enfoque
Nada de esto es propietario. Si quieres identificar tus propios agentes con los mismos estándares, necesitas cuatro cosas:
- Una clave de firma ES256 en un KMS (o en un HSM). La clave privada no debe estar nunca en el servidor web ni en un equipo personal.
- Un documento DID publicado en tu dominio:
did:web:tudominio.tld→https://tudominio.tld/.well-known/did.json, con tu clave pública enverificationMethody referenciada enassertionMethod. Para los agentes, con path:did:web:tudominio.tld:agents:<slug>→https://tudominio.tld/agents/<slug>/did.json, sin.well-known. - Credenciales W3C VC 2.0 firmadas como JWS
typ: vc+jwt, concredentialStatusapuntando a tu propia Bitstring Status List firmada. - Un verificador público. Sin una URL donde un tercero compruebe en el momento, la credencial no sirve de nada.
Publicaremos la especificación completa de la credencial de delegación agéntica y del sello con licencia abierta. Mientras tanto, esta página documenta el formato con el detalle suficiente para reimplementarlo, y todos los artefactos de un agente real están accesibles para inspección. Si estás construyendo algo parecido y quieres que los formatos converjan, escribe a legal@digitalcortex.tech.
12
Anclaje en blockchain (hoja de ruta)
Nada de lo que sigue está desplegado hoy. Se documenta para que se vea hacia dónde va el diseño y, sobre todo, qué problema resolvería y cuál no.
Fase prevista 1 · Atestaciones EAS en Base
La idea: por cada emisión y cada revocación, escribir una atestación en el Ethereum Attestation Service desplegado en Base, con el hash del JWT de la credencial, el manifestHash, el DID del agente y las fechas. Una atestación cuesta céntimos y es pública.
| Campo previsto | Contenido |
|---|---|
| credentialHash | SHA-256 del JWS completo. No revela el contenido, permite probar identidad byte a byte. |
| manifestHash | El mismo hash que va dentro de la credencial. |
| agentDid | did:web:digitalcortex.tech:agents:<slug> |
| issuedAt / validUntil | Fechas de la ventana de vigencia. |
| revokedAt | En la atestación de revocación; también revoca la atestación original. |
Fase prevista 2 · Anclaje diario del ledger
El registro de auditoría ya está encadenado por hash, pero la base de datos la controla el operador. Un sello diario de la cabeza de cada partición, firmado con una clave que vive fuera del sistema, convierte «reescribí el ledger» en algo detectable: el sello de ayer deja de casar. Llevar ese sello a una cadena pública añade una marca de tiempo que el operador tampoco controla. El proceso es idempotente: si la cabeza no ha cambiado desde el último sello, no se escribe otro.
Fase prevista 3 · Registro ERC-8004
ERC-8004 propone un registro de identidad de agentes on-chain donde cada agente tiene un identificador y una agentURI que apunta a un fichero de registro con sus metadatos. Encaja de forma natural: esa agentURI sería el documento DID del agente publicado en este dominio, y el fichero de registro, los metadatos que ya devuelve hoy /functions/agentSeal?slug=<slug>&format=json.
Fase prevista 4 · Novena comprobación: «Anclado en Base»
Cuando lo anterior esté desplegado, la página de verificación mostrará una comprobación más junto a las ocho actuales: que existe una atestación on-chain para esta credencial, que no ha sido revocada en la cadena y en qué bloque y fecha se escribió. Hasta entonces no aparecerá: una comprobación que no se ejecuta no se pinta.
Qué resolvería el anclaje y qué no
Resolvería: marca de tiempo independiente del operador (no repudio), prueba de que una credencial existía en una fecha aunque el emisor desapareciera, y un punto de consulta que no depende de que nuestro dominio siga en pie. Refuerza, en una palabra, la atribución, el alcance y el no repudio.
No resolvería nada sobre el comportamiento del agente: no hace que esté mejor alineado, ni que sus resultados sean correctos, ni que cumpla lo que promete. Poner un hash en una cadena pública no mejora a un agente; solo hace más difícil mentir después sobre lo que se autorizó y cuándo. Cualquiera que venda lo contrario está vendiendo otra cosa.
13
Estado del sistema
El registro público de agentes, leído en vivo al abrir esta página. Es el mismo JSON que sirve /functions/agentRegistry y el mismo que declara el documento DID del emisor como servicio AgentRegistry.
Cosmolabs OÜ · did:web:digitalcortex.tech
1 agente · actualizado 2026-10-30
| Agente | DID | Autonomía | Estado | Credencial | Comprobar |
|---|---|---|---|---|---|
| ArgosLead NextAI | did:web:digitalcortex.tech:agents:argos | A4 | Vigente | CRD-2026-0001hasta 2026-12-07 | /verify/argos |
Se listan también los agentes con credencial revocada, caducada o sustituida: un registro que solo enseña lo vigente es un escaparate, no un registro. Los agentes no públicos no aparecen aquí ni en ningún otro sitio — para el exterior, sencillamente no existen.
14
Preguntas frecuentes
¿Lo valida algún organismo oficial?
No. Es una declaración de Cosmolabs OÜ con medios públicos para comprobar su firma, integridad y vigencia. No es una certificación oficial, una auditoría externa ni una garantía de cumplimiento del artículo 50 del AI Act.
¿Qué pasa si cambia la configuración del agente?
La vinculación compara el hash de la credencial con el manifiesto registrado como vigente. Un cambio en ese registro requiere publicar una nueva versión y reemitir. El verificador no inspecciona por sí solo cambios externos en prompts, modelo, herramientas o permisos efectivos.
¿Puedo verificar sin usar vuestra página?
Sí. La credencial usa un JWS ES256 y una clave pública en un documento DID. Puedes comprobar la firma, el emisor, las fechas y la lista de revocación. La vinculación con el manifiesto depende además del registro que publica el emisor. La sección de verificación explica el procedimiento.
¿Cuánto tarda en verse una revocación?
Depende del punto de consulta, las cachés y el comportamiento del cliente. Una cabecera max-age=60 no garantiza una propagación global en 60 segundos. Retirar acceso efectivo exige que cada conector consulte el estado actualizado o que se cancelen sus sesiones y permisos.
¿La credencial contiene datos personales?
El diseño público usa organización, rol y canal de contacto, evitando identificar a personas físicas. No debe incluirse información personal ni datos de clientes en los campos públicos del manifiesto o la credencial.
¿Qué ocurre cuando se rota la clave de firma?
La rotación planificada publica la nueva clave y conserva la anterior durante la transición que requieran las credenciales vigentes. La duración depende de sus fechas, no de un plazo universal de 90 días. Si hay compromiso de clave, se necesita un procedimiento de incidente y revocación específico.
¿Puedo copiar el sello o la credencial?
Son públicos y se pueden reproducir para consulta conforme a la política. Copiar una firma válida no permite modificar el contenido sin invalidarla, pero tampoco autentica a quien presenta esa copia. Verifica el dominio, la vigencia y el contexto de la interacción.
¿Por qué el DID del emisor vive en digitalcortex.tech?
Porque did:web:digitalcortex.tech se resuelve a https://digitalcortex.tech/.well-known/did.json. Los identificadores de agentes añaden su ruta. Este mecanismo vincula el identificador al dominio del emisor.
¿Sirve para agentes de otros proveedores?
Los estándares permiten otros emisores. Las credenciales de este registro las emite Cosmolabs OÜ para los agentes de los que declara responder; no acreditan automáticamente agentes de terceros.
¿Hay token, NFT o blockchain?
El sistema público de referencia funciona fuera de cadena. EAS en Base y ERC-8004 se describen como hoja de ruta. Un futuro anclaje aportaría evidencia de publicación y estado según su diseño; no comprobaría por sí solo la veracidad de la declaración ni la conducta del agente.
¿A4 permite cualquier acción si un humano la aprueba?
No. A0–A5 es una escala interna de autonomía. El nivel máximo no amplía la lista de acciones autorizadas ni anula las prohibiciones firmadas. Los conectores deben aplicar esas restricciones antes de ejecutar.
¿Qué hago si sospecho de un agente que dice ser de CORTEX?
Consulta digitalcortex.tech/verify/<agente> y confirma el canal por una vía independiente. Un QR válido puede haber sido copiado. Si faltan datos, la verificación falla o la interacción resulta sospechosa, contacta con legal@digitalcortex.tech sin enviar claves ni información confidencial.
Responsable de la emisión: Cosmolabs OÜ · código de registro 17106582 · Ahtri tn 12, 15551 Tallinn, Estonia · legal@digitalcortex.tech