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

@agentrouter/agentrouter

v0.1.12

Published

TypeScript SDK for AgentRouter.

Readme

AgentRouter SDK

TypeScript SDK for the AgentRouter.

AgentRouter supports both a structured capability-first flow and an intent-first entrypoint. The intent-first path is backed by AgentRouter's hosted intent resolver, so the SDK can start from a natural-language prompt, inspect the selected route context, and then execute explicitly through one client.

  • Package: @agentrouter/agentrouter
  • Docs: https://docs.agentrouter.to/integrations/sdk
  • Base URL: https://api.agentrouter.to/api/agentic-api

Install

npm install @agentrouter/agentrouter

Get an API Key

Hosted AgentRouter requests require an API key.

  1. Open https://www.agentrouter.to/agentic-api/install
  2. Sign in and copy your API key
  3. Export it in your shell
export AGENTIC_API_KEY=your_key_here

For local development against a local AgentRouter server, you can also use userId instead of an API key.

Quick Start

Intent-first:

import { AgentRouterClient } from "@agentrouter/agentrouter";

const client = new AgentRouterClient({
  apiKey: process.env.AGENTIC_API_KEY,
});

const recommendation = await client.recommend(
  "can you help me buy an email inbox?",
);

const routeContext = await client.catalog.routes.context(recommendation.recommendedRouteKey);

const result = await client.capabilities.execute({
  domain: recommendation.resolution.domainKey,
  capability: recommendation.resolution.capabilityId,
  routeKey: recommendation.recommendedRouteKey,
  input: {
    inbox_name: "launch-updates",
  },
  allowFallback: true,
});

If you want the hosted mapping step directly, call:

const resolution = await client.intent.resolve(
  "can you help me buy an email inbox?",
);

Structured:

import { AgentRouterClient } from "@agentrouter/agentrouter";

const client = new AgentRouterClient({
  apiKey: process.env.AGENTIC_API_KEY,
});

const domains = await client.catalog.domains.list();
const capabilities = await client.catalog.capabilities.list("email");

const recommendation = await client.capabilities.recommend({
  domain: "email",
  capability: "send",
  input: {
    optimizationPreferences: ["cost", "quality"],
  },
});

const result = await client.capabilities.execute({
  domain: "email",
  capability: "send",
  input: {
    to: "[email protected]",
    subject: "Hello from AgentRouter",
    html: "<p>Hello</p>",
  },
  provider: recommendation.recommendedProvider,
  allowFallback: true,
});

CLI

The package also ships a thin CLI wrapper over the same SDK semantics.

Create an API key at https://www.agentrouter.to/agentic-api/install and export it before hosted CLI requests:

export AGENTIC_API_KEY=your_key_here

Install locally:

npm install @agentrouter/agentrouter
npx agentrouter domains list

Or run it without adding the package to your app:

npx -p @agentrouter/agentrouter agentrouter domains list

Examples:

agentrouter wallet
agentrouter capabilities list email
agentrouter capabilities list models
agentrouter capabilities list text
agentrouter capabilities list translation
agentrouter capabilities list finance
agentrouter capabilities list tax
agentrouter capabilities list captcha
agentrouter capabilities list commerce
agentrouter capabilities list lottery
agentrouter capabilities list music
agentrouter capabilities list property
agentrouter capabilities list media
agentrouter capabilities list web
agentrouter routes context email.send.resend
agentrouter routes context models.chat.complete.deepseek.mpp
agentrouter routes context models.chat.complete.groq.mpp
agentrouter routes context text.analyze.diffbot-nl.mpp
agentrouter routes context translation.text.rephrase.deepl.mpp
agentrouter routes context web.extract.diffbot.mpp
agentrouter routes context web.publication.list.dripstack.mpp
agentrouter routes context web.publication.post.get.dripstack.mpp
agentrouter routes context enrichment.people.enrich.diffbot.mpp
agentrouter routes context finance.equity.quote.alphavantage.mpp
agentrouter routes context finance.fx.rate.abstract-exchange-rates.mpp
agentrouter routes context finance.fx.convert.abstract-exchange-rates.mpp
agentrouter routes context finance.fx.rate.historical.abstract-exchange-rates.mpp
agentrouter routes context tax.vat.validate.abstract-vat.mpp
agentrouter routes context tax.vat.calculate.abstract-vat.mpp
agentrouter routes context tax.vat.categories.list.abstract-vat.mpp
agentrouter routes context captcha.task.create.twocaptcha.mpp
agentrouter routes context commerce.product.search.kicksdb.stockx.mpp
agentrouter routes context lottery.round.active.megapot
agentrouter routes context music.song.generate.suno.mpp
agentrouter routes context property.records.search.rentcast.mpp
agentrouter routes context media.image.generate.fal.mpp
agentrouter routes context travel.airport.operations.flightapi.mpp
agentrouter recommend email send --input '{"optimizationPreferences":["cost"]}'
agentrouter recommend text analyze --input '{"provider":"diffbot-nl","fields":"entities,sentiment,language","optimizationPreferences":["quality"]}' --json
agentrouter execute models chat-complete --input '{"model":"deepseek-v4-flash","messages":[{"role":"user","content":"Say AgentRouter DeepSeek smoke OK."}]}' --route-key models.chat.complete.deepseek.mpp --json
agentrouter execute translation text-rephrase --input '{"text":"Please make this product update friendlier.","targetLanguage":"EN-US","tone":"prefer_friendly"}' --route-key translation.text.rephrase.deepl.mpp --json
agentrouter execute web extract --input '{"url":"https://www.example.com/article"}' --route-key web.extract.diffbot.mpp --json
agentrouter execute web publication-list --input '{"allowFallback":false}' --route-key web.publication.list.dripstack.mpp --json
agentrouter execute web publication-posts-list --input '{"publicationSlug":"newsletter.morning-brew.morningbrew.com","allowFallback":false}' --route-key web.publication.posts.list.dripstack.mpp --json
agentrouter execute web publication-post-get --input '{"publicationSlug":"newsletter.morning-brew.morningbrew.com","postSlug":"cheers-to-beer-20260506","allowFallback":false}' --route-key web.publication.post.get.dripstack.mpp --json
agentrouter execute enrichment people-enrich --input '{"fullName":"Sam Altman","companyName":"OpenAI"}' --route-key enrichment.people.enrich.diffbot.mpp --json
agentrouter recommend finance equity-quote --input '{"symbol":"MSFT","optimizationPreferences":["speed","quality"]}' --json
agentrouter recommend finance fx-convert --input '{"fromCurrency":"USD","toCurrency":"JPY","amount":25,"optimizationPreferences":["cost"]}' --json
agentrouter execute email send --input @send-email.json --route-key email.send.resend --allow-fallback
agentrouter execute finance equity-quote --input '{"symbol":"MSFT"}' --route-key finance.equity.quote.alphavantage.mpp --json
agentrouter execute finance fx-convert --input '{"fromCurrency":"USD","toCurrency":"JPY","amount":25}' --route-key finance.fx.convert.abstract-exchange-rates.mpp --json
agentrouter execute tax vat-validate --input '{"vatNumber":"DE123456789","countryCode":"DE","allowFallback":false}' --route-key tax.vat.validate.abstract-vat.mpp --provider abstract-vat --json
agentrouter execute tax vat-calculate --input '{"countryCode":"DE","amount":100,"calculationType":"add","allowFallback":false}' --route-key tax.vat.calculate.abstract-vat.mpp --provider abstract-vat --json
agentrouter execute media image-generate --input '{"prompt":"Create a clean launch hero image for an AI developer tool","aspectRatio":"16:9","allowFallback":false}' --route-key media.image.generate.fal.mpp --provider fal --json
agentrouter execute travel airport-operations --input '{"iataCode":"JFK","mode":"departures","limit":1}' --route-key travel.airport.operations.flightapi.mpp --provider flightapi --json
agentrouter route enrichment --input '{"intent":"Find the work email for the VP Engineering at Example Corp"}'

Finance commands require a deployment that actually exposes GET /domains/finance. If that domain returns DOMAIN_NOT_FOUND or the finance execute endpoints return 404, the rollout is not live on that environment yet.

Tax VAT commands require a deployment that exposes GET /domains/tax. The live Abstract VAT routes are tax.vat.validate.abstract-vat.mpp, tax.vat.calculate.abstract-vat.mpp, and tax.vat.categories.list.abstract-vat.mpp.

Text analysis is currently recommend/context only. text.analyze.diffbot-nl.mpp is mapped through Diffbot NL, but May 5, 2026 direct wrapper checks returned HTTP 429 before payment and no AgentRouter credits were charged, so do not execute it until the catalog reports it executable and paid smoke evidence exists.

Media image generation and edit are live through fal MPP image routes. media.video.generate.fal.mpp remains gated after upstream paymentauth 524 timeouts reproduced outside AgentRouter, so use recommend/context for video generation until the catalog reports it executable and paid smoke evidence exists.

Environment variables:

  • AGENTIC_API_BASE_URL
  • AGENTIC_API_KEY
  • AGENTIC_API_SESSION_TOKEN
  • AGENTIC_API_USER_ID
  • AGENTIC_API_TIMEOUT_MS

Recommended Flow

  1. List domains with client.catalog.domains.list()
  2. List capabilities with client.catalog.capabilities.list(domainKey)
  3. Inspect routes or contracts for a capability
  4. Ask for a recommendation
  5. Execute explicitly

This keeps your integration stable even when providers or routes change.

Catalog Discovery

const domain = await client.catalog.domains.get("enrichment");

const capability = await client.catalog.capabilities.get("email", "send");

const routes = await client.catalog.capabilities.routes("email", "send");

const contract = await client.catalog.capabilities.contract("email", "send");

const routeContext = await client.catalog.routes.context("email.send.resend");

Capability contracts describe the common input shape for a workflow. Route contexts describe the executable surface for one selected route, including route-specific fields and possible provider/wrapper values. Read each possible value's label and description to map natural language to the exact value.

When you want one concrete route, execute through the capability endpoint and pass routeKey; the SDK sends it in the request body.

const result = await client.capabilities.execute({
  domain: "travel",
  capability: "flight-search",
  routeKey: "travel.flight.search.stabletravel.googleflights.agentcash",
  input: {
    departure_id: "JFK",
    arrival_id: "LAX",
    outbound_date: "2026-05-01",
    type: "2",
    travel_class: "1",
    adults: 1,
  },
  allowFallback: false,
});

The same generic surface also works for physical-mail workflows:

const postcard = await client.capabilities.execute({
  domain: "post",
  capability: "postcard-send",
  routeKey: "post.postcard.send.papercut.mpp",
  input: {
    roast: "Launch follow-up postcard",
    github_username: "codepoet",
    type: "digital",
  },
  allowFallback: false,
});

It also works for public-broadcast price checks:

const broadcastQuote = await client.capabilities.execute({
  domain: "broadcast",
  capability: "message-quote",
  routeKey: "broadcast.message.quote.billboard.mpp",
  input: {},
  allowFallback: false,
});

As of May 1, 2026, broadcast.message.send.billboard.mpp is still intentionally gated because one live execute would create a real public post and the latest observed supplier challenge was about $40.96.

For text analysis, use the generic surface for recommendation and route context only until the Diffbot NL route clears its runtime gate:

const textRecommendation = await client.capabilities.recommend({
  domain: "text",
  capability: "analyze",
  input: {
    provider: "diffbot-nl",
    fields: "entities,sentiment,language",
    optimizationPreferences: ["quality"],
  },
});

const textContext = await client.catalog.routes.context(
  "text.analyze.diffbot-nl.mpp",
);

console.log(textRecommendation.recommendedRouteKey);
console.log(textContext.routeKey);

The current Diffbot NL route is not a live execute example. It returned HTTP 429 before payment during May 5, 2026 direct wrapper checks, so keep integrations to recommend/context until canExecuteNow is true and a paid route smoke succeeds.

It also works for route-pinned fal image generation through the media domain:

const heroImage = await client.capabilities.execute({
  domain: "media",
  capability: "image-generate",
  routeKey: "media.image.generate.fal.mpp",
  input: {
    prompt: "Create a clean launch hero image for an AI developer tool",
    aspectRatio: "16:9",
  },
  provider: "fal",
  allowFallback: false,
});

console.log(heroImage.primaryImageUrl);

media.video.generate.fal.mpp remains gated after upstream paymentauth 524 timeouts reproduced outside AgentRouter, so do not execute video generation until route context reports canExecuteNow=true and paid smoke evidence exists.

It also works for DeepL Write rephrase through the translation domain:

const rewrite = await client.capabilities.execute({
  domain: "translation",
  capability: "text-rephrase",
  routeKey: "translation.text.rephrase.deepl.mpp",
  input: {
    text: "Please make this product update friendlier.",
    targetLanguage: "EN-US",
    tone: "prefer_friendly",
  },
  allowFallback: false,
});

console.log(rewrite.rewrittenText);

For DeepL rephrase, fetch route context before execution and use the exposed DeepL Write fields: text, targetLanguage, and optional tone.

It also works for route-pinned airport schedule operations on FlightAPI:

const airportOperations = await client.capabilities.execute({
  domain: "travel",
  capability: "airport-operations",
  routeKey: "travel.airport.operations.flightapi.mpp",
  input: {
    iataCode: "JFK",
    mode: "departures",
    limit: 1,
  },
  provider: "flightapi",
  allowFallback: false,
});

FlightAPI airport operations passed a May 8, 2026 production smoke through travel.airport.operations.flightapi.mpp. Fetch route context first and pin the route when you need that concrete provider.

If your deployment exposes the finance domain, it also works for finance market-data routes:

const marketStatus = await client.capabilities.execute({
  domain: "finance",
  capability: "market-status",
  routeKey: "finance.market.status.alphavantage.mpp",
  input: {},
  allowFallback: false,
});

const quote = await client.capabilities.execute({
  domain: "finance",
  capability: "equity-quote",
  routeKey: "finance.equity.quote.alphavantage.mpp",
  input: {
    symbol: "MSFT",
  },
  allowFallback: false,
});

const fxRate = await client.capabilities.execute({
  domain: "finance",
  capability: "fx-rate",
  routeKey: "finance.fx.rate.abstract-exchange-rates.mpp",
  input: {
    fromCurrency: "USD",
    toCurrency: "EUR",
  },
  allowFallback: false,
});

const fxConversion = await client.capabilities.execute({
  domain: "finance",
  capability: "fx-convert",
  routeKey: "finance.fx.convert.abstract-exchange-rates.mpp",
  input: {
    fromCurrency: "USD",
    toCurrency: "JPY",
    amount: 25,
  },
  allowFallback: false,
});

const historicalFxRate = await client.capabilities.execute({
  domain: "finance",
  capability: "fx-rate-historical",
  routeKey: "finance.fx.rate.historical.abstract-exchange-rates.mpp",
  input: {
    fromCurrency: "USD",
    toCurrency: "GBP",
    date: "2024-01-01",
  },
  allowFallback: false,
});

If your deployment exposes the tax domain, the same generic surface works for VAT validation, calculation, and category-rate lookup:

const vatValidation = await client.capabilities.execute({
  domain: "tax",
  capability: "vat-validate",
  routeKey: "tax.vat.validate.abstract-vat.mpp",
  input: {
    vatNumber: "DE123456789",
    countryCode: "DE",
  },
  allowFallback: false,
});

const vatCalculation = await client.capabilities.execute({
  domain: "tax",
  capability: "vat-calculate",
  routeKey: "tax.vat.calculate.abstract-vat.mpp",
  input: {
    countryCode: "DE",
    amount: 100,
    calculationType: "add",
  },
  allowFallback: false,
});

const vatCategories = await client.capabilities.execute({
  domain: "tax",
  capability: "vat-categories-list",
  routeKey: "tax.vat.categories.list.abstract-vat.mpp",
  input: {
    countryCode: "DE",
  },
  allowFallback: false,
});

If your deployment exposes the agents domain, the same generic surface also works for hosted-agent discovery and stateless paid execution:

const agentSearch = await client.capabilities.recommend({
  domain: "agents",
  capability: "search",
  input: {
    query: "privy",
    optimizationPreferences: ["quality"],
  },
});

const agentRun = await client.capabilities.execute({
  domain: "agents",
  capability: "run",
  routeKey: "agents.run.autoexchange.mpp",
  input: {
    id: "ab7527c0-6099-4145-9d8b-47f09dab9390",
    prompt: "Say hello in one short sentence.",
    stateless: true,
  },
  allowFallback: false,
});

The generic surface also works for model inference through the models domain. The current live routes cover DeepSeek chat completion, code completion, and model listing, plus Groq chat completion and model listing through models.chat.complete.groq.mpp and models.list.groq.mpp:

const modelChat = await client.capabilities.execute({
  domain: "models",
  capability: "chat-complete",
  routeKey: "models.chat.complete.deepseek.mpp",
  input: {
    model: "deepseek-v4-flash",
    messages: [
      {
        role: "user",
        content: "Say AgentRouter DeepSeek smoke OK.",
      },
    ],
  },
  allowFallback: false,
});

const modelList = await client.capabilities.execute({
  domain: "models",
  capability: "list",
  routeKey: "models.list.deepseek.mpp",
  input: {},
  allowFallback: false,
});

console.log(modelChat.completionText);
console.log(modelList.models);

Fetch route context before execution to choose a supported model id. The May 5, 2026 live DeepSeek list route returned deepseek-v4-flash and deepseek-v4-pro, and the May 10, 2026 Groq chat smoke returned AgentRouter Groq smoke OK from llama-3.1-8b-instant.

Domain Helpers

The generic capability methods are the main contract. The SDK also includes helper namespaces where they improve ergonomics:

  • client.email
  • client.enrichment
  • client.social
  • client.web
  • client.post
  • client.broadcast

Finance and hosted agents are currently best accessed through the generic capability methods rather than a dedicated helper namespace:

const fxRate = await client.capabilities.execute({
  domain: "finance",
  capability: "fx-rate",
  routeKey: "finance.fx.rate.abstract-exchange-rates.mpp",
  input: {
    fromCurrency: "USD",
    toCurrency: "EUR",
  },
  allowFallback: false,
});

const fxConversion = await client.capabilities.execute({
  domain: "finance",
  capability: "fx-convert",
  routeKey: "finance.fx.convert.abstract-exchange-rates.mpp",
  input: {
    fromCurrency: "USD",
    toCurrency: "JPY",
    amount: 25,
  },
  allowFallback: false,
});

const historicalFxRate = await client.capabilities.execute({
  domain: "finance",
  capability: "fx-rate-historical",
  routeKey: "finance.fx.rate.historical.abstract-exchange-rates.mpp",
  input: {
    fromCurrency: "USD",
    toCurrency: "GBP",
    date: "2024-01-01",
  },
  allowFallback: false,
});

const hostedAgent = await client.capabilities.execute({
  domain: "agents",
  capability: "run",
  routeKey: "agents.run.autoexchange.mpp",
  input: {
    id: "ab7527c0-6099-4145-9d8b-47f09dab9390",
    prompt: "Say hello in one short sentence.",
    stateless: true,
  },
  allowFallback: false,
});

Example:

const routed = await client.enrichment.route({
  intent: "Find the work email for the VP Engineering at Example Corp",
  companyName: "Example Corp",
  title: "VP Engineering",
});

const contact = await client.enrichment.contactEnrich.execute(
  {
    linkedinUrl: "https://www.linkedin.com/in/example",
  },
  {
    allowFallback: true,
  },
);

const graphPerson = await client.capabilities.execute({
  domain: "enrichment",
  capability: "people-enrich",
  routeKey: "enrichment.people.enrich.diffbot.mpp",
  input: {
    fullName: "Sam Altman",
    companyName: "OpenAI",
  },
  allowFallback: false,
});

const graphCompany = await client.capabilities.execute({
  domain: "enrichment",
  capability: "company-enrich",
  routeKey: "enrichment.company.enrich.diffbot.mpp",
  input: {
    companyName: "OpenAI",
    domain: "openai.com",
  },
  allowFallback: false,
});

const letterRecommendation = await client.post.letter.send.recommend({
  to: {
    name: "Jianyu Li",
    address_line1: "11030 SE 2nd St",
    city: "Bellevue",
    state: "WA",
    zip: "98004",
    country: "US",
  },
  from: {
    name: "AgentRouter",
    address_line1: "2261 Market St",
    city: "San Francisco",
    state: "CA",
    zip: "94114",
    country: "US",
  },
  pdf: {
    url: "https://example.com/letter.pdf",
  },
});

const postcard = await client.post.postcard.send.execute(
  {
    roast: "Launch follow-up postcard",
    github_username: "codepoet",
    type: "digital",
  },
  {
    routeKey: "post.postcard.send.papercut.mpp",
    allowFallback: false,
  },
);

const broadcastQuote = await client.broadcast.message.quote.execute(
  {},
  {
    routeKey: "broadcast.message.quote.billboard.mpp",
    allowFallback: false,
  },
);

const broadcastSendRecommendation =
  await client.broadcast.message.send.recommend({
    text: "Launch update goes here.",
    optimizationPreferences: ["quality"],
  });

const publications = await client.web.publications.list.execute(
  {},
  {
    routeKey: "web.publication.list.dripstack.mpp",
    allowFallback: false,
  },
);

const publicationPosts = await client.web.publications.posts.list.execute(
  {
    publicationSlug: "newsletter.morning-brew.morningbrew.com",
  },
  {
    routeKey: "web.publication.posts.list.dripstack.mpp",
    allowFallback: false,
  },
);

const publicationPost = await client.web.publications.post.get.execute(
  {
    publicationSlug: "newsletter.morning-brew.morningbrew.com",
    postSlug: "cheers-to-beer-20260506",
  },
  {
    routeKey: "web.publication.post.get.dripstack.mpp",
    allowFallback: false,
  },
);

const publicationPostGeneric = await client.capabilities.execute({
  domain: "web",
  capability: "publication-post-get",
  routeKey: "web.publication.post.get.dripstack.mpp",
  input: {
    publicationSlug: "newsletter.morning-brew.morningbrew.com",
    postSlug: "cheers-to-beer-20260506",
  },
  allowFallback: false,
});

Treat broadcast.message.send as a recommend-or-review step until a human explicitly approves the exact public message body and spend.

DripStack publication discovery is exposed through web.publication.list.dripstack.mpp and web.publication.posts.list.dripstack.mpp as free reads. web.publication.post.get.dripstack.mpp retrieves one selected article and is a paid route that starts at 50 credits, so inspect route context and make an explicit article choice before execution.

Auth

Hosted usage:

const client = new AgentRouterClient({
  apiKey: process.env.AGENTIC_API_KEY,
  baseUrl: "https://api.agentrouter.to/api/agentic-api",
});

Local development also supports user-scoped fallback against local AgentRouter servers:

const wallet = await client.wallet.get({
  userId: "agentrouter-sdk-smoke-user",
});

Security Note

Do not expose AGENTIC_API_KEY in browser client code. Use this SDK from server-side environments such as:

  • Node.js services
  • Next.js server routes and server actions
  • CLI tools
  • agent runtimes

API Surface

Top-level modules:

  • client.catalog
  • client.capabilities
  • client.wallet
  • client.usage
  • client.auth
  • client.raw

Notes

  • Canonical capability IDs come from the catalog.
  • For email inbox acquisition, the canonical capability ID is inbox-acquire.
  • The backend may still accept legacy aliases such as inbox-buy, but the SDK normalizes to canonical capability IDs.
  • Recommend, route, and execute responses preserve the raw backend payload on raw.

Resources

  • SDK docs: https://docs.agentrouter.to/integrations/sdk
  • Install flow: https://www.agentrouter.to/agentic-api/install
  • skill.md: https://www.agentrouter.to/SKILL.md