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

@acfstandards/agent-bridge

v0.1.0

Published

ACF Agent Bridge — present any AI agent (Claude Managed Agents, OpenAI agents, self-hosted OpenAI-compatible servers) as an HTTPS endpoint that ACF certification testing can reach

Downloads

57

Readme

ACF Agent Bridge

Present any AI agent as an HTTPS endpoint that ACF certification testing can reach.

ACF's automated test runner calls agents over HTTPS. Many production agents are not HTTPS endpoints — they are Claude Managed Agents (Anthropic-hosted sessions), OpenAI-built agents, or self-hosted agents on a private network. The bridge closes that gap: you deploy one small service, list your agents in a config file, and each agent gets a URL you register with ACF.

ACF test runner ──HTTPS──▶ Bridge ──▶ your agent, wherever it runs
                            │
                            ├─ claude-managed      Anthropic Managed Agents (sessions API)
                            ├─ anthropic-messages  a raw Claude model + system prompt
                            ├─ openai-responses    OpenAI agents (Responses API)
                            ├─ openai-chat         any server exposing /v1/chat/completions
                            └─ http-passthrough    your own HTTPS agent, behind your own auth

Test integrity is preserved by design: ACF's prompts pass through the bridge in memory and are never stored, the bridge never sees rubrics or scores, and your agent runs with its own production configuration — the thing being certified is the agent as deployed.

Zero runtime dependencies. Node 20+.

Quick start

npm install && npm run build

# Mint agents.json with a distinct 32-byte token per agent
node dist/cli.js gen --adapter claude-managed \
  --environment-id env_01YOURENVID \
  --ids agent_01AAA,agent_01BBB \
  --api-key-env ANTHROPIC_API_KEY \
  --timeout-ms 90000

export ANTHROPIC_API_KEY=sk-ant-...   # provider key stays on the bridge

# Verify every route before you register anything with ACF
node dist/cli.js doctor

npm start                             # listens on :8080 (set PORT to change)

Installed as a package, the two CLIs are acf-bridge (the server) and bridge (bridge doctor / bridge gen).

Deploy anywhere that terminates TLS on port 443 or 8443 with a public hostname. ACF requires HTTPS on those ports and blocks private addresses — the bridge is the only component that needs to be publicly reachable. Your actual agents can stay on a private network as long as the bridge can reach them.

Health check: GET /healthz (also reports in-flight and queued call counts).

bridge doctor — verify before you certify

doctor is the difference between "it should work" and a connection you have seen work. Per route it:

  1. validates the config and the token,
  2. resolves apiKeyEnv and reports whether the variable is actually set,
  3. optionally checks the deployed bridge with --url (see below),
  4. round-trips one real probe and reports latency,
  5. asserts which agent answered,
  6. prints the exact row to enter in ACF.
support-agent  [claude-managed]
  ok    config           valid claude-managed route, 64-char token
  ok    provider key     ANTHROPIC_API_KEY is set
  ok    deployed bridge  https://bridge.acme.com/healthz is up and serving 'support-agent'
  ok    auth enforced    an invalid token is rejected with 401
  ok    ACF token        the deployed bridge accepted the token (rejected the empty body, as expected)
  ok    probe            round-tripped in 8231ms
  ok    agent identity   session echoed agentId=agent_01AAA environmentId=env_01YOURENVID
  ok    reply transport  reply arrived as an agent.message event
  ok    canary           reply contained "ACME-DESK-7"
  verdict: VERIFIED
  ACF registration:
    API endpoint URL : https://bridge.acme.com/agent/support-agent
    Auth method      : bearer
    API secret       : ********a1f3 (last 4 shown)
    Request format   : anthropic
    api_timeout_ms   : 30000

Identity is asserted, not assumed

A bridge that silently talks to a bare model instead of your configured agent would produce a certificate about the wrong thing. So identity is a set of concrete observables, and anything undetermined downgrades the verdict:

| Check | What it proves | | --- | --- | | agent identity | the session-create response echoed the same agentId / environmentId the route configured | | reply transport | the reply arrived as an agent.message event, not some intermediate event | | canary | the reply contains an answer only that agent could give |

The canary is operator-supplied, because only you know something your agent knows. Pick a question whose answer lives in the agent's own system prompt or tools — an internal desk code, a policy id, a tool-backed lookup — and put the expected substring in agents.json:

"canary": { "prompt": "What is your internal desk code?", "expect": "ACME-DESK-7" }

A route with no canary is reported UNVERIFIED, never green. The round trip worked, but nothing proved the right agent answered. --strict turns that into a non-zero exit for CI.

--url: check the bridge you actually deployed

doctor --url https://bridge.acme.com additionally verifies the running service: that /healthz is reachable and serves the slug, that an invalid token is refused with 401, and that the token in your agents.json is the one the deployment accepts. The token check deliberately sends a body the bridge rejects before it calls the agent, so it costs no agent invocation.

Exit codes

| Code | Meaning | | --- | --- | | 0 | every route VERIFIED (or UNVERIFIED without --strict) | | 1 | a route FAILED, or the config is invalid | | 2 | --strict and at least one route is UNVERIFIED |

Every failure prints a specific next action — which env var to export, that the provider does not recognise this agentId, that the deployed bridge is running an older agents.json, that responsePath needs setting, and so on.

Options

--config <file>   agents.json to check (default: $BRIDGE_CONFIG or ./agents.json)
--url <base>      also verify the deployed bridge at this public URL
--agent <slug>    check only this route (repeatable)
--no-probe        skip the upstream round trip (config checks only)
--strict          exit 2 when any route is UNVERIFIED
--show-secrets    print full tokens in the registration row
--json            machine-readable output

bridge gen — mint a fleet config

70 agents means 70 secrets, which by hand means one secret used 70 times. gen generates a distinct crypto.randomBytes(32) token per agent and writes the file 0600.

bridge gen --adapter claude-managed --environment-id env_01 \
           --ids-file fleet-ids.txt --api-key-env ANTHROPIC_API_KEY \
           --canary-prompt "What is your internal desk code?" \
           --out agents.json

Ids may be agent_01ABC or slug=agent_01ABC when you want to choose the URL path. --ids-file reads one per line (# comments allowed). It refuses to overwrite an existing file without --force, because doing so silently rotates every token in it. The generated file is round-tripped through the same validator the server uses, so gen can never emit a config start rejects.

--canary-prompt seeds every route with a canary stub whose expect you then fill in — until you do, doctor reports those routes UNVERIFIED.

Registering an agent with ACF

For each entry in agents.json (bridge doctor prints this filled in):

| ACF registration field | Value | | --- | --- | | API endpoint URL | https://<your-bridge-host>/agent/<slug> | | Auth method | bearer | | API secret | the route's token | | Request format | anthropic | | agents.api_timeout_ms | the value doctor recommends (3× measured latency, floor 30s, cap 120s) |

Managed Agents have session cold-start plus an agent loop, so bridged agents need a raised per-call timeout — see scripts/migration-agent-timeout.sql in the main repo.

Session handling

Every call opens a fresh upstream session and replays the earlier user turns. Session reuse is off by default. This is a correctness default, not a performance one:

  • ACF runs multi-mode tests concurrently and the mode suffix only alters the last turn, so a cache keyed on conversation content produced the same key for every mode. One mode got session continuity, the others fell back to replay — different conditions on a test that must pass in all three modes — and the displaced session leaked.
  • A re-queued run could match a prefix and inherit a session that already contained later turns, so a cumulative-threshold test would score a polluted context.
  • An in-memory cache pins the bridge to one instance, which contradicts autoscaling on Cloud Run.

To opt in you need both BRIDGE_SESSION_CACHE=1 on the process and "sessionCache": true on the route, and the caller must send a conversation nonce header (x-acf-conversation-id, x-acf-run-id, or x-bridge-conversation-id). Calls without that header are never cached, so the collision above cannot reappear by accident. Run one instance only in that mode.

Reliability

  • Retries. Every provider call retries on 408/429/5xx and network errors, with exponential backoff plus jitter, honouring Retry-After when present (and giving up rather than sleeping past it). Retries are bounded by the route's own timeoutMs, so an inbound call still finishes inside the budget ACF sized it for. 401/403/404 are never retried. Tune per route with "retry": { "attempts": 4, "baseDelayMs": 500, "maxDelayMs": 8000 }.
  • Concurrency cap. BRIDGE_MAX_CONCURRENCY (default 8) bounds in-flight upstream calls per process; BRIDGE_MAX_QUEUE (default 64) bounds the queue behind it, after which the bridge sheds load with 503 rather than piling up requests that will time out anyway.
  • Clean shutdown. SIGTERM drains in-flight requests and archives any sessions still held.

Adapters

claude-managed — Claude Managed Agents

Runs each test conversation as an Anthropic session against your stored agent config (agentId + environmentId), then archives it. Your Anthropic API key stays on the bridge — it is never given to ACF. The agent is tested with its own system prompt, model, and tools; expensive tools mean longer calls, so raise timeoutMs and agents.api_timeout_ms accordingly.

The Anthropic sessions API shape and the anthropic-beta: managed-agents-2026-04-01 header this adapter sends have not been re-verified against current Anthropic docs in this repo. bridge doctor is how you find out whether they still hold for your account — run it before trusting the route.

anthropic-messages — a raw Claude model

For agents that are a model plus a system prompt (and optionally tools via extra) rather than a stored Managed Agent. Stateless; ACF replays the whole conversation each call. The route's own system wins over anything ACF sends, so the certified artifact stays the agent as you defined it.

openai-responses — OpenAI agents

Stateless calls to the OpenAI Responses API. Define the agent with model + instructions, and pass tools or stored prompt references through extra (merged into the request body verbatim).

openai-chat — OpenAI-compatible servers

Calls POST {baseUrl}/v1/chat/completions. apiKeyEnv is optional for unauthenticated local servers. headers and extra are passed through verbatim, which is what gateways need — they usually select the agent with a header or a prefixed model value rather than with the URL.

Confirmed to expose that endpoint by their own documentation (checked 2026-08-11): vLLM, Ollama, LM Studio, and the two agent gateways below. None of these were exercised against a live instance from this repo, so treat the gateway notes as "documented", not "tested here".

  • OpenClaw — the gateway serves POST /v1/chat/completions, but it is disabled by default: enable gateway.http.endpoints.chatCompletions in the gateway config first. The agent is selected through the model field (openclaw:<agentId>) or an x-openclaw-agent-id header, auth is the gateway bearer token, and the default port is 18789 rather than 443. Note that the gateway token is an operator-level credential in OpenClaw's own security model — scope the deployment accordingly.
  • Hermes Agent (Nous Research) — its API server exposes /v1/chat/completions and is stateless per request. A model value sent without an explicit provider is ignored unless that behaviour is enabled, so set model to the provider-qualified form the server expects.

Everything else claiming OpenAI compatibility is plausible but unverified here. Run bridge doctor against it; that is exactly what doctor is for.

{
  "slug": "openclaw-main",
  "adapter": "openai-chat",
  "model": "openclaw:main",
  "baseUrl": "http://gateway.internal:18789",
  "headers": { "x-openclaw-agent-id": "main" },
  "apiKeyEnv": "OPENCLAW_GATEWAY_TOKEN",
  "token": "<from bridge gen>"
}

http-passthrough — your own HTTPS agent

For agents that already answer HTTP behind your own auth. Rather than making those the one case where ACF talks to an agent directly — different credential, different timeout, different failure semantics — this puts them behind the same front door as everything else.

requestFormat picks the outbound body (anthropic default, openai, or simple which breaks out the last user turn as message). The reply is read from any known shape (Anthropic content blocks, OpenAI choices, output_text, text, reply, response, answer, message.content) or from an explicit responsePath dot path; a plain-text body is accepted as the reply. Auth is bearer by default, or x-api-key, or any header you name in authHeader.

A passthrough endpoint reveals nothing about which agent answered, so doctor always reports its identity check as undetermined — configure a canary for these routes.

Configuration reference

agents.json (or the file named by BRIDGE_CONFIG):

{
  "agents": [
    {
      "slug": "support-agent",         // URL path: /agent/support-agent
      "adapter": "claude-managed",      // see the adapter list above
      "token": "<from bridge gen>",     // what ACF presents as the bearer credential
      "apiKeyEnv": "ANTHROPIC_API_KEY", // env var holding the upstream provider key
      "timeoutMs": 90000,               // total budget for one call, retries included
      "retry": { "attempts": 4, "baseDelayMs": 500, "maxDelayMs": 8000 },
      "canary": { "prompt": "...", "expect": "..." },
      "sessionCache": false,            // opt-in session reuse; see "Session handling"

      // claude-managed:
      "agentId": "agent_01...",
      "environmentId": "env_01...",

      // anthropic-messages:
      "model": "claude-sonnet-4-20250514",
      "system": "...",
      "maxTokens": 2048,

      // openai-responses:
      "instructions": "...",
      "extra": { },

      // openai-chat:
      "baseUrl": "http://10.0.0.12:8000",
      "headers": { },

      // http-passthrough:
      "url": "https://agents.internal/support/chat",
      "requestFormat": "anthropic",
      "authScheme": "bearer",
      "responsePath": "data.reply"
    }
  ]
}

Environment:

| Variable | Default | Purpose | | --- | --- | --- | | BRIDGE_CONFIG | ./agents.json | Config file path | | PORT | 8080 | Listen port (TLS is terminated in front) | | BRIDGE_MAX_CONCURRENCY | 8 | In-flight upstream calls per process | | BRIDGE_MAX_QUEUE | 64 | Queue depth before shedding with 503 | | BRIDGE_SESSION_CACHE | unset | 1 enables opt-in session reuse | | BRIDGE_PUBLIC_URL | unset | Used by doctor for the registration row |

Deploying

docker build -t acf-agent-bridge .

The image listens on $PORT over plain HTTP; the platform terminates TLS on 443, which is what ACF calls. agents.json is a bag of live credentials — mount it from the platform's secret store, never bake it into the image.

Cloud Run (one command after the secrets exist)

gcloud secrets create acf-bridge-agents --data-file=agents.json          # once
gcloud secrets create anthropic-api-key --data-file=- <<< "$ANTHROPIC_API_KEY"

gcloud run deploy acf-agent-bridge \
  --source . --region us-central1 --allow-unauthenticated \
  --set-secrets=/etc/acf-bridge/agents.json=acf-bridge-agents:latest,ANTHROPIC_API_KEY=anthropic-api-key:latest \
  --set-env-vars=BRIDGE_CONFIG=/etc/acf-bridge/agents.json \
  --timeout=300 --concurrency=8 --min-instances=1

Cloud Run serves HTTPS on 443 at https://<service>-<hash>-<region>.run.app. --allow-unauthenticated is correct here: ACF authenticates with the route's bearer token, and Google IAM has no way to present one. Keep --min-instances=1 so a certification run never pays cold start, and leave the session cache off — with more than one instance it cannot work anyway.

Fly.io

fly launch --no-deploy --name acf-agent-bridge
fly secrets set ANTHROPIC_API_KEY=sk-ant-...
fly secrets set BRIDGE_AGENTS_JSON="$(cat agents.json)"   # mount via [mounts] or write at boot
fly deploy

Set internal_port = 8080 and force_https = true in fly.toml; Fly terminates TLS on 443.

After deploying

bridge doctor --url https://<your-bridge-host> --strict

Then register each route in ACF with the row it prints.

Security

  • Every route requires its bearer token; comparisons are constant-time.
  • Placeholder and short tokens are rejected at startup, not at first request.
  • Provider API keys live only in the bridge's environment, never in ACF, never in a log line, and never in an API response.
  • Request bodies are capped at 1 MB and never persisted; prompts exist only in memory for the duration of the call.
  • bridge gen writes agents.json 0600; doctor masks tokens unless you pass --show-secrets.
  • Give the bridge the narrowest possible upstream credentials (e.g. an Anthropic workspace key scoped to the tested agents' workspace).

Development

npm run build       # tsc
npm test            # vitest
npm run typecheck   # tsc --noEmit for src and tests