npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@atcn/adapter-a2a

v1.5.1

Published

Record paid A2A (Agent2Agent) work in ATCN: signed task events, billing references, estimates, signed outcomes and sub-task lineage

Readme

@atcn/adapter-a2a

Connects A2A (Agent2Agent v1.0) agents to ATCN, so paid work handed from one agent to another ends up in a cost record that anyone can verify offline. ATCN only records: it never blocks, holds or releases money.

What it gives each side:

  • The agent doing the work signs its task events as it goes (started, evidence submitted, completed) and can sign its estimate and how the task ended.
  • The agent paying for it turns A2A tasks into delegations, matches the worker's bills to them through a declared billing reference, and records estimates, signed outcomes and sub-tasks handed further down the chain.
npm install @atcn/adapter-a2a

Signed task events

The working agent runs the bridge on its own task stream:

| A2A | ATCN | | --- | --- | | TASK_STATE_WORKING | obligation.started | | Artifact with metadata.atcn (evidence_type, verifier, deliverable_ids) | evidence.submitted | | TASK_STATE_COMPLETED | completion.proposed | | FAILED, CANCELED, REJECTED | Nothing signed on the obligation (only the issuer may cancel it); the bridge returns a terminal action naming the subledger claim to record (provider_failure or cancellation) |

Every event is signed with the working agent's key. Clearing, payment and the task closure follow from those events.

import { StreamResponse } from "@a2a-js/sdk";
import { A2AObligationBridge, localObligationClient, obligationIdFromMetadata } from "@atcn/adapter-a2a";

// In the working agent's AgentExecutor:
const obligationId = obligationIdFromMetadata(requestContext.userMessage.metadata);
const bridge = new A2AObligationBridge({ client: localObligationClient(network), worker: signer, obligationId });
await bridge.handle(StreamResponse.toJSON({ payload: { $case: "statusUpdate", value: statusUpdate } }));

client is either an AtcnClient from @atcn/sdk (hosted API) or localObligationClient(network) for the in-memory network from @atcn/local-runner, which needs no account. The bridge reads A2A wire JSON, so it works with any A2A SDK; with @a2a-js/sdk, StreamResponse.toJSON produces it.

The delegating agent puts obligationTaskMetadata(obligationId) on the A2A message so the worker knows which obligation the task is for. obligationTaskMetadata(obligationId, { skillId }) also names the AgentSkill it wants; the worker reads it with skillIdFromMetadata.

Pass execution to describe the run in obligation.started, so attestations can cite exactly which run, agent version and skill they judged:

import { AgentCard } from "@a2a-js/sdk";

const bridge = new A2AObligationBridge({
  client,
  worker: signer,
  obligationId,
  execution: { agentCard: AgentCard.toJSON(card), skillId: skillIdFromMetadata(metadata) ?? undefined },
});

The run's execution_id is a2a:<task id>. It records the A2A task and context ids, the card's version and digest, and the skill (namespace a2a). Optional model and configDigest are recorded as given; the agent declares them itself. When the obligation's terms name a skill, the network refuses a run of any other skill. After obligation.started, bridge.execution holds the descriptor; an attestation cites it as executionBinding(bridge.execution) from @atcn/schema.

Billing reference

An agent declares what its bills reference with the billing-reference extension: billingRefExtension({ billing_ref: "task_id", currency: "USD" }) goes in its Agent Card's capabilities.extensions. The buyer records the delegation with delegationFromA2A({ card, task, currency }), which takes provider_job_ref from that declaration, so the agent's charges match the delegation without a hand-written mapping. Pass parentDelegationId when an agent records a sub-task under its own delegation.

Estimates

An agent can sign its own estimate and send it in task or artifact metadata: signedEstimateMetadata(estimate, { keyId, privateKey }). The buyer reads it with estimateFromMetadata and records it with estimateEventFromA2A(estimate, { match, binding }). With a key binding for the agent's key_id it is provider_key_signed; without one it is relayed unsigned. Estimates are records only: nothing is reserved and they never count toward net cost. See ESTIMATES.md.

Signed outcomes

An agent signs how its task ended, over its A2A task id, its note and pointers to its evidence:

import { signedOutcomeMetadata, terminalClaimType } from "@atcn/adapter-a2a";

// Agent side, on a failed task (the same works for "completion" or "partial_completion"):
const metadata = signedOutcomeMetadata(
  { type: terminalClaimType("TASK_STATE_FAILED"), task_id: taskId, occurred_at: new Date().toISOString(), note: "index unavailable; charge refunded", evidence: [] },
  { keyId: "gamma-key", privateKey },
);

The buyer reads it from the status update with outcomeFromMetadata and records outcomeClaimFromA2A(outcome, { binding }) on the delegation whose provider_job_ref is the task id. The claim is provider_key_signed only when the buyer bound the agent's key; the closure verifier re-checks the signature offline (check signed_claims). A failed or cancelled delegation that is still billed raises charge_after_cancellation until a refund, credit or reversal nets it to zero. The A2A example publishes the signing key in a card extension (npm run demo:a2a -- --search-fails).

Multi-hop lineage

When an agent hands part of its task to another agent, lineageMetadata(parentTask, agentName) on the message that starts the sub-task carries the chain of tasks above it (metadata.atcn.lineage, root first; read it with lineageFromMetadata). The agent reports its sub-tasks back up with downstreamMetadata(edges), each with the sub-agent's own signed outcome relayed unchanged. The buyer records every edge from downstreamFromMetadata as a child delegation (childDelegationFromA2A(edge, { parentDelegationId, currency, providerId })) and its outcome with outcomeClaimFromA2A. A sub-agent's signed outcome verifies against its own key even though the buyer never dealt with it. An edge that arrives with no outcome is a broken edge: record brokenEdgeGap(edge, childDelegationId) as a capture gap, and the closure shows lineage as incomplete with an incomplete_lineage exception.

A runnable example with two A2A agents over HTTP is in examples/a2a-delegation.

Part of ATCN. Apache-2.0.