DEV Community

Edison Flores
Edison Flores

Posted on Edited on

UTA v1.0.0 — full status report: 96 articles, 2,276 NPM downloads, here's what's next

Correction (Aug 25): Earlier version of this article misnamed the project as "ATC/1.0 — Agent Trust Card Protocol." That was wrong. ATC is one of 8 adapter formats UTA supports — not the project name. This version corrects that throughout.

The project is Universal Trust Adapter (UTA) v1.0.0. ATC is one of 8 formats it translates between (the others: EAT-AI, ZTA, A2A, MCP Card, W3C VC, OAuth, SPIFFE). The canonical schema is Universal Trust Schema (UTS) v2.0.0.

Two months in. Here's the honest numbers, then what's next.

The numbers (as of Aug 25, 2026)

NPM packages

Package Version Description Monthly downloads
marketnow-mcp 1.10.0 MCP server (13 trust tools) 958
agent-trust-card 1.1.1 ATC adapter SDK (issue/verify/inspect) 518
marketnow-install-stack 1.1.0 Multi-source installer 345
@marketnow/uts 2.0.0 Universal Trust Schema (canonical) 125
@marketnow/trust-core 1.0.0 Trust Engine core 122
@marketnow/trust-adapters 1.0.0 8 format adapters 106
@marketnow/trust-gateway 1.0.0 Gateway + post-exec filter 102
TOTAL — — 2,276/mo

All packages mirrored automatically by jsDelivr CDN and unpkg CDN.

Dev.to

  • 96 articles published since July 2
  • 26 reactions accumulated
  • 44 comments received from 15 different developers
  • 5 batched response articles published (responding to all 32 actionable comments)
  • 258 minutes total reading time

Top commenters by engagement:

  • @anp2network (6 comments) — most technically rigorous, found the JCS bug
  • @mads_hansen (6 comments) — conexor.io, runtime policy angle
  • @wrencalloway (4 comments) — wcalloway.substack.com, tool-description-poisoning
  • @topstar_ai (3 comments) — production LLM systems, asked about collaboration
  • @neelagiri65 (2 comments) — pushed for honest per-layer catch counts

GitHub

  • alicelabs-llc org: 21 repos, 6 stars, 1 fork
  • Most starred: sam-gov-types (3 stars), samgov-sdk (2 stars), Scraper (1 star)
  • Personal account: flagged by abuse-detection (ticket #4658791 open 2 weeks — still unresolved, SMS verification completed)
  • UTA canonical repo: https://github.com/alicelabs-llc/universal-trust-adapter (publicly accessible)

marketnow.site (AliceLabs-owned)

  • HTTP 200 active
  • Serving tarballs directly: /uta-packages/marketnow-uts-2.0.0.tgz etc.
  • Multi-source installer: /install.sh (tries NPM → jsDelivr → unpkg → marketnow.site → GitHub)
  • Resilience manifest: /resilience.json

What UTA actually is

Universal Trust Adapter (UTA) is the project. It's the USB-C of agent trust — translates between 8 trust credential formats via a canonical Universal Trust Schema (UTS).

The 8 formats UTA translates between:

  1. ATC (Agent Trust Card — AliceLabs)
  2. EAT-AI (IETF RFC 9421)
  3. ZTA (Anthropic Zero-Trust Agent)
  4. A2A Agent Card (Google/AAIF)
  5. MCP Server Card (Anthropic)
  6. W3C Verifiable Credentials
  7. OAuth/OIDC
  8. SPIFFE SVID

The 12-stage verification pipeline uses Ed25519 (RFC 8032) signatures over RFC 8785 JCS canonicalization, with domain separation across 7 distinct signature domains to prevent cross-context reuse.

What worked

  1. Writing in public. 96 articles in 8 weeks. The 44 comments pushed the spec harder than 6 months of private iteration would have. @anp2network's first comment (the JCS replacer bug) caught a real cryptographic flaw I'd shipped to production.

  2. Multi-channel distribution. When GitHub flagged my account two weeks ago, the 5-channel setup meant the project kept working. NPM downloads continued at the same rate. No user-visible disruption.

  3. Responding to every technical comment. Even when the comment was sharp (anp2network called the spec "a private result that weighs about as much as any other assertion nobody can re-derive"), engaging with the substance produced the highest-value feedback. The test vectors only exist because anp2network publicly shamed me into publishing the bytes.

  4. Publishing the test CA private key. Sounds counterintuitive but it's the only way to make a crypto spec truly verifiable across languages. Anyone can re-derive the signatures in Python, Go, or Rust.

What didn't work

  1. Relying on a single GitHub account. When the personal account got flagged, 55 public repos instantly returned HTTP 404. Should have moved to the org earlier.

  2. NPM package metadata still points to the flagged account. Without an NPM publish token in the build environment, I couldn't republish packages with updated repository.url. The tarballs are byte-identical and downloadable, but the "Repository" link on npmjs.com is broken.

  3. "8 layers of security" framing. The honest version is "8 layers, 2 of which actually caught things." The article should have led with per-layer catch counts, not layer count.

  4. Naming confusion between ATC and UTA. ATC is one of 8 adapters in UTA, but my early articles presented ATC as if it were the project. The repo name (universal-trust-adapter) was always right; the article framing was wrong. Fixed in this article.

  5. Not having a Hacker News / Reddit presence. Dev.to reaches the Dev.to audience, but the broader security / AI / cryptography communities don't read Dev.to. Should have cross-posted from day 1.

Where I'm publishing next

Based on the gap analysis, the project needs presence on platforms where the security / AI / MCP communities actually hang out:

  • Reddit: r/MCP, r/LocalLLaMA, r/cybersecurity, r/webdev
  • Hacker News: Show HN submission for UTA v1.0.0
  • Hashnode: cross-posting articles
  • LinkedIn: B2B audience for enterprise security
  • Twitter/X: threads for developer discovery
  • Discord communities: Anthropic, MCP, Cursor, Cline, Continue, Aider servers
  • MCP marketplaces: Smithery.ai, Glama.ai, PulseMCP, mcp.so

If you're in any of those communities and want to vouch for the project, that's the highest-value thing anyone can do right now.

What's next on the technical side

  1. Multi-sig for high-value agents — attestation.signature becomes an array, verifier requires N-of-M. Spec'd but not implemented.

  2. Runtime tool-catalog pinning — the fix for the tool-description-poisoning attack @wrencalloway flagged. Pin catalog at approval, block at runtime if catalog changes.

  3. Behavior-based detection layer — post-exec filter that inspects actual tool results, not just pre-call signatures.

  4. More test vectors — the 5 current vectors cover the obvious failure classes (expired, tampered, wrong-ca-key, minimal-valid, capability-samples). Need edge cases: nested objects deeper than 2 levels, unicode payloads, large card sizes, multi-sig.

  5. NPM republish with correct repository.url — once I have an NPM publish token, republish all 7 packages with repository.url pointing to alicelabs-llc instead of the flagged personal account.

  6. Cross-language SDKs — currently Node.js only. Python, Go, Rust SDKs to be published from the same source tree.

The honest ask

The project is at the inflection point where it needs more reviewers, not more features. If you're a security researcher, a cryptography implementer, or an MCP server author:

Repo: https://github.com/alicelabs-llc/universal-trust-adapter
NPM: marketnow-mcp@1.10.0 (958/mo) and agent-trust-card@1.1.1 (518/mo)
Install: curl -fsSL https://marketnow.site/install.sh | bash

— Edison Flores, AliceLabs LLC

Top comments (2)

Collapse
 
anp2network profile image
ANP2 Network •

Ran them, same day as promised. The re-derivation claim holds.

We wrote an RFC 8785 JCS implementation in Python straight from the spec and did the Ed25519 in Node 20, following your how_to_use: take the ATC payload, empty attestation.signature and attestation.signed_payload_hash, canonicalize, SHA-256, verify.

All four signed vectors canonicalize byte-identically to your published bytes_utf8, and bytes_hex and bytes_base64 decode to those same bytes. SHA-256 matches on 4 of 4. Both keypairs are internally consistent: deriving the public key from the published CA private key reproduces ca_public_key_spki_base64, and the agent pair does the same. Ed25519 is deterministic, so we re-signed the canonical bytes with your published CA private key and got byte-for-byte the published signature_base64 on minimal-valid, expired and wrong-ca-key. tampered-payload fails to verify under every key we tried. That part is real. Publishing the private key was the right call.

Now the disagreements.

byte_length is wrong on every vector, and it's wrong in the way that matters for a byte-level spec. You publish 1881 for minimal-valid, tampered-payload and wrong-ca-key, and 1877 for expired. The actual UTF-8 lengths are 1887 and 1883. The delta is exactly 6, every time. It comes from evidence.audit_pipeline, which carries three arrow characters that take 3 bytes each in UTF-8 and count as one unit each under a JS string .length. So a field called byte_length, living inside a block called canonical whose entire job is byte exactness, is a UTF-16 code-unit count. It contradicts its own neighbour too: bytes_hex is 3774 hex characters, which is 1887 bytes, in the same object that declares 1881. A verifier that length-checks before hashing rejects all four.

wrong-ca-key is a must-fail vector that passes. Its canonical bytes are byte-identical to minimal-valid, its SHA-256 is the same bf6738b3..., and it carries the same signature. The only field that changed is the file-level ca_public_key, which sits outside the signed payload. Inside the payload, issuer.ca_public_key still names the real CA, and verifying with the key the card itself carries returns true. It fails only for a verifier that gets the CA key out of band, and nothing in the vector set pins where that key comes from. The vector tests your harness convention rather than the card.

Your harness scores it green anyway, for a reason it never declared. _index.json says expected.errors_contain: "CA public key mismatch". The recorded SDK output for the same vector says errors: ["ATC-006: Ed25519 signature verification failed"], with matches_expected: true. So matches_expected is computed from valid == false, and the field holding the reason is stored but never checked. A must-fail vector failing for a different reason than the one you declared scores as a pass.

One small correction to the article itself: the code block shows ca_private_key_pkcs8_base64 starting MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg under ca_algorithm: Ed25519, and those DER bytes are an EC P-256 PKCS8. The file in the repo is correct and starts MC4CAQAwBQYDK2VwBCIEIA. Anyone lifting the key from the article gets one that can't produce these signatures.

Collapse
 
topstar_ai profile image
Luis Cruz •

Great progress, Edison. I especially like the focus on independent verification, test vectors, and getting more reviewers involved rather than simply adding features.

I’m a senior AI/Python developer working with production LLM systems, AI agents, automation, and security-focused architectures. I’d be interested in contributing to UTA and exploring whether there’s an opportunity to collaborate on the technical side.

If you’re looking for someone to help with implementation, testing, integrations, or future Python/AI tooling, I’d be happy to contribute and deliver high-quality, reliable results.

If there’s a paid project or ongoing opportunity around UTA, I’d also be glad to discuss it.