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

@criticalbridge/conformance-sidecar

v1.3.2

Published

Language-agnostic conformance sidecar that makes an external A2A agent a fully governed CriticalBridge peer (registers, heartbeats, control-channel polls, proxies /tasks, emits per-task telemetry). Companion to the Brain's /api/brain/agents/v1 ingress (Ep

Readme

@criticalbridge/conformance-sidecar

Language-agnostic conformance sidecar that makes an external A2A agent a fully governed peer of the CriticalBridge Brain — handles registration, heartbeats, control-channel polling, the policy/HITL gate at /tasks, telemetry emission, and JWT lifecycle. Companion to the Brain's /api/brain/agents/v1 ingress.

If you're integrating a Python agent and want a higher-level API (@handler decorator, mint_credential(), etc.), use the criticalbridge Python SDK — it boots this sidecar for you. This package is the lower-level boundary for non-Python customers (Go, Java, Rust, …) or operators who want to manage the sidecar process independently.

Install

The Docker container is the recommended install path — it's language-agnostic, isolated from your agent runtime, and works identically on every host OS. npx and npm install -g are shortcuts for Node-native environments.

Docker (recommended)

docker run --rm -p 8080:8080 \
  -v cb-sidecar-sessions:/home/sidecar/.criticalbridge/sidecar/sessions \
  -e BRAIN_URL=https://api.criticalbridge.ai \
  -e ENTITY_ID=your-entity-id \
  -e ENROLLMENT_TOKEN=eyJhbGc.paste.your.token.here \
  -e AGENT_VENDOR=langchain \
  -e AGENT_BROKER_ID=your-agent-id \
  -e AGENT_UPSTREAM_URL=http://your-agent-host:8000 \
  -e SIDECAR_PUBLIC_URL=https://sidecar.your-domain.com \
  ghcr.io/fburkitt/conformance-sidecar:1.3.2

AGENT_UPSTREAM_URL DNS resolution. your-agent-host in the example is a placeholder. Replace with the hostname the sidecar container can reach:

  • host.docker.internal — if your agent runs on the host machine (Docker Desktop only)
  • A Docker Compose service name (e.g. my-agent) — if the sidecar and agent share a network
  • A fully-qualified DNS name — if the agent runs on a separate machine reachable from inside the container

http:// is fine here (the upstream is private to the sidecar); SIDECAR_PUBLIC_URL still must be HTTPS.

Volume mount matters. The -v flag persists the 30-day registration JWT to a Docker volume. Skip it and container restarts have to re-exchange the (single-use) enrollment token — which fails after the first boot with enrollment_token_already_consumed. The path /home/sidecar/.criticalbridge/sidecar/sessions matches the image's non-root user (sidecar, uid 1001) — that's $HOME/.criticalbridge/sidecar/sessions for the default user, which is where the sidecar's default session directory now resolves (#8665). If you rebuild the image with a different user, adjust the mount path to that user's $HOME/.criticalbridge/sidecar/sessions.

The same directory (or SIDECAR_STATE_DIR, when set) also holds the last-known tool-call screening state (<entity>--<agent>.screening.json). Without the mount, a restarted sidecar can only learn that state from the Brain, so a restart during a Brain outage starts fail-open. See Tool-call screening.

npm

# Run on demand
npx @criticalbridge/[email protected]

# Or install globally
npm install -g @criticalbridge/[email protected]
cb-conformance-sidecar

Configure

All env vars are required; missing ones fail loud at boot. The error message lists every missing var in a single message — no need to iterate.

Required

| Variable | Purpose | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | BRAIN_URL | CriticalBridge Brain Coordinator base URL (HTTPS, no trailing slash) | | ENTITY_ID | Entity ID the sidecar registers under | | ENROLLMENT_TOKEN | One-time enrollment token (mint via Portal /dashboard/managed-agents/enrollment-tokens). Single-use; persisted as a 30-day JWT after first boot | | AGENT_VENDOR | One of langchain, autogen, crewai, semantic-kernel, haystack, other | | AGENT_BROKER_ID | Durable per-agent ID within the entity — stable per-deployment; the resulting agent id is derived from (vendor, brokerId) | | AGENT_UPSTREAM_URL | Where your agent listens (private OK) — /tasks requests get forwarded here | | SIDECAR_PUBLIC_URL | Where the Brain dispatches to the sidecar (must be HTTPS). Point this at your tunnel / reverse-proxy hostname |

Optional

| Variable | Purpose | | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | | SIDECAR_PORT | Port the sidecar HTTP server listens on (default 8080) | | SIDECAR_HITL_HOLDS_ENABLED | true reports each task parked on hitlRequiredFor[] to the Brain as a hold an operator approves or rejects per task (default off). See Per-task approvals | | SIDECAR_HITL_SUMMARY_FIELDS | Comma-separated top-level request-body fields whose values may be shown to the approving operator, e.g. amount,payee. Unset: no field values leave the sidecar | | SIDECAR_AGENT_PROXY_TOKEN_ENABLED | true fetches a proxy session token from the Brain and attaches it to MCP calls sent through the loopback agent-proxy forwarder (default off). See Agent proxy token | | SIDECAR_AGENT_PROXY_URL | HTTPS base URL of the entity's agent proxy gateway. Required when SIDECAR_AGENT_PROXY_TOKEN_ENABLED=true | | SIDECAR_AGENT_PROXY_HEADERS_TIMEOUT_MS | How long a forwarded MCP call waits for the gateway's response headers before answering 504 agent_proxy_timeout (default 30000). Streamed bodies are not cut | | AGENT_DISPLAY_NAME | Label shown in the operator fleet view | | AGENT_CAPABILITY_TAGS | Comma-separated capability strings, e.g. expense.submit,expense.approve | | AGENT_CATALOG_IDENTIFIER | AI Catalog URN, e.g. urn:air:criticalbridge.ai:acme:support-agent | | AGENT_CATALOG_MEDIA_TYPE | AI Catalog media type, e.g. application/a2a+json | | AGENT_REPRESENTATIVE_QUERIES | Pipe-separated (\|) example queries the agent handles — up to 5, up to 256 chars each | | AGENT_PUBLISHABLE | true | false — whether the agent should appear in federated AI Catalog discovery. Defaults to server-side (typically off) | | AGENT_CARD_POLL_ENABLED | true | false — enable Agent Card drift detection (polls ${AGENT_UPSTREAM_URL}/.well-known/agent.json, ships hash + structural diff on the heartbeat). Default true | | AGENT_CARD_POLL_INTERVAL_MS | Poll interval for the Agent Card fetcher, in milliseconds. Clamped to [15_000, 600_000]. Default 60_000 |

What it does

  1. First boot: exchanges your one-time ENROLLMENT_TOKEN for a 30-day registration JWT, persists it at ~/.criticalbridge/sidecar/sessions/<entity>__<agent>.json (mode 0600), registers the agent with the Brain.
  2. Subsequent boots: reads the persisted JWT from the session file — no exchange needed. Volume-mount the session directory so the file survives container restarts (see the Docker example above).
  3. Steady state:
    • Heartbeats the Brain on a server-tuned cadence (5s–10min)
    • Polls the control channel for executionAllowed + hitlRequiredFor[] posture
    • Serves POST /tasks — gates by policy, forwards to AGENT_UPSTREAM_URL
    • Emits 60s rollups of latency p50/p99/avg + tasks_processed_total + tasks_failed_total
    • Polls ${AGENT_UPSTREAM_URL}/.well-known/agent.json on a 60s cadence, hashes the card, and piggybacks any structural diff (added/removed/changed skill paths) on the next heartbeat so the Brain surfaces silent card drift — new tools your agent started advertising without operator approval. Set AGENT_CARD_POLL_ENABLED=false to opt out
    • Refreshes the JWT inside the 7-day pre-expiry window
  4. Health: GET /healthz returns 200 for Kubernetes / Cloud Run liveness probes.

Per-task approvals

Off by default. With SIDECAR_HITL_HOLDS_ENABLED=true, a task whose skill is in hitlRequiredFor[] becomes an approval request in the operator's Approvals inbox instead of a silent park. It needs a Brain with BRAIN_MANAGED_AGENT_HITL_HOLDS_ENABLED=true and fleet auth in enforce mode; against any other Brain every HITL-required task simply stays parked.

What POST /tasks answers for a HITL-required skill:

| Situation | Response | | --- | --- | | Waiting for a decision | 200 {"status":"working","pendingDecisionId":…}. Re-send the same task to check again | | Approved | The task is forwarded to your agent, once | | Rejected | 403 hitl_rejected, with the operator's note. Permanent for that task | | Nobody decided in time | 403 hitl_expired. Re-send the task to ask again | | The approval was already used | 409 hitl_already_executed | | No approval request could be opened | 429 hitl_unavailable (the approval queue is full) or 422 hitl_unavailable (the Brain refused the request; retrying will not help) |

Three things to know before turning it on:

  • An approval covers one exact request body, once. The request is identified by its taskId plus a hash of the body. Changing any byte of the body asks for a new approval, so an agent that re-sends a task must re-send it byte for byte. After the task has been forwarded once, the same request is refused with 409; if your agent fails after that point, the task needs a new approval.
  • Send a taskId. Without one, two tasks with identical bodies cannot be told apart, and the second is refused with 409 rather than run on the first one's approval.
  • By default the operator does not see the request's contents. They see the skill, the body's size and hash, and the names of its top-level fields. List the fields that are safe and useful to show in SIDECAR_HITL_SUMMARY_FIELDS; only string, number and boolean values are sent, truncated to 256 characters. With nothing listed, approving means approving "this skill, this exact body" unread.

Agent proxy token

Off by default. With SIDECAR_AGENT_PROXY_TOKEN_ENABLED=true and SIDECAR_AGENT_PROXY_URL set, the sidecar asks the Brain for a proxy session token (POST /api/brain/agents/v1/entities/:entityId/agents/:agentId/proxy-token, authenticated with the agent's registration JWT) and keeps it fresh: tokens last at most 15 minutes and are refreshed at 80% of their lifetime or 60 s before expiry, whichever comes first. The Brain needs AGENT_PROXY_TOKEN_ISSUER_ENABLED=true and fleet auth in enforce mode.

Point your agent's MCP client at the sidecar instead of the gateway:

POST http://127.0.0.1:8080/agent-proxy/servers/<serverId>/mcp

The sidecar forwards the call to <SIDECAR_AGENT_PROXY_URL>/v1/entities/<ENTITY_ID>/servers/<serverId>/mcp with x-cb-agent-did and x-cb-agent-token set (any x-cb-* headers your agent sends are dropped; its Authorization for the MCP server passes through). The route is loopback-only. When no token is available it answers 503 agent_proxy_token_unavailable (with Retry-After while backing off). If the Brain refuses the agent (403 agent_not_approved or agent_id_mismatch), the sidecar stops asking, logs an error, and answers 403 agent_proxy_token_refused with the reason until it is restarted. While the cached control-channel posture says the agent is not active or execution is disabled, the forwarder refuses with 403 agent_lifecycle_refusal / 403 execution_disabled, the same codes as /tasks. If the agent disconnects, the upstream call is aborted.

Tool-call screening

Your agent's MCP traffic does not pass through the sidecar, so the agent (or the SDK) asks the sidecar before and after each tool call. Both routes are loopback-only.

POST http://127.0.0.1:8080/mcp/authorize
{ "serverId": "github", "toolName": "search", "toolCallId": "tc-1", "arguments": { "q": "…" } }
→ 200 { "allowed": true, "reason": "unlisted_allowed", "policyVersion": "…", "screening": { … } }

POST http://127.0.0.1:8080/mcp/screen-result
{ "serverId": "github", "toolName": "search", "toolCallId": "tc-1", "result": { … } }
→ 200 { "allowed": true, "reason": "content_allowed", "sanitizedContent": "…" }

/mcp/authorize applies the entity's MCP access policy first. When the call is allowed and carries arguments, the Brain then screens them against the entity's guardrail policy. Use sanitizedContent from /mcp/screen-result in place of the raw result when it is present. Screening is controlled per entity by the Brain's sidecar-guardrails capability; while it is off, nothing is screened and calls are allowed.

Once the Brain has said screening is on, the sidecar fails closed: a tool call without arguments is refused (screening_required), a Brain outage is refused (screening_unavailable), and so is a request over 156 KiB (content_too_large). After a restart the sidecar restores that state from the session directory and asks the Brain before the first call. Always send arguments.

What your agent must provide

  • An HTTP /tasks endpoint that accepts the A2A task envelope { skill, taskId, ... } and returns the result. The sidecar forwards verbatim.

That's the bare minimum. For richer governance (decision lineage, audit events, just-in-time credentials, HITL gating), see the External Agent Integration Guide.

Troubleshooting

[sidecar] Missing required env vars: … — batch fail-loud at boot. The message lists every unset required var. Fix them all at once and retry.

enrollment_token_already_consumed at boot — the enrollment token is single-use, and either (a) you're restarting the container without a volume mount for the session file, or (b) you copy-pasted the token to a second sidecar. Fix (a) with -v cb-sidecar-sessions:/home/sidecar/.criticalbridge/sidecar/sessions; fix (b) by re-minting a fresh token for each sidecar.

401 unauthorized on register — your registration JWT's entity or broker doesn't match the URL/body. Re-mint the enrollment token, making sure the AGENT_BROKER_ID on your sidecar matches the broker registration id in the Portal form.

503 Managed agent registration requires a seat license — the enrollment token you minted didn't carry a seatLicenseId claim (pre-1d token) or your entity has no available seats. Re-mint a fresh token via the Portal after your entity has at least one seat licensed.

Brain never sees the sidecar despite the local log saying register OK — your SIDECAR_PUBLIC_URL isn't reachable from the Brain. Test it: curl https://your-sidecar-public-url/healthz from a machine outside your network should return 200. If it fails, fix your tunnel / ingress before restarting the sidecar.

Enrollment token expired before boot — enrollment tokens are 1h TTL. Mint a fresh one via the Portal.

License

Apache-2.0 © Frank Burkitt and CriticalBridge.AI contributors.