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

@botanary/agent

v0.1.0-alpha.12

Published

Botanary agent session and execution runtime with an injected signer

Readme

@botanary/agent

Version 0.1.0-alpha.12, canonical API contract 2026-09-12. MIT licensed. Node 22 or later.

The runtime is extracted from botanary-mcp. MCP keeps desktop keychain adapters, profile selection, owner sessions and approval handles. The CLI consumes that desktop adapter through MCP. The shared package has no dependency on desktop storage, the Botanary backend or frontend source.

// Node server only. The caller supplies an agent signer whose private key stays in its own storage.
import { AgentRuntime, registerAgent, type AgentSigner } from '@botanary/agent';
import { createBotanary } from '@botanary/sdk';

export async function registerAndRead(signer: AgentSigner) {
  const app = createBotanary({ apiKey: process.env.BOTANARY_SECRET_KEY! });
  const registration = await registerAgent(signer, app, 'Research agent');
  return { id: registration.id, access: registration.apiAccess, grant: registration.grantStatus };
}

export async function readConnectedAgent(signer: AgentSigner) {
  const agent = new AgentRuntime(signer);
  return agent.me();
}

Registration requires app:read and agents:write on the app key. It verifies an EIP-191 challenge bound to the application, environment, key ID, agent public key, one-use nonce and expiry. It creates neither an account connection nor an on-chain grant. Pass the returned registration ID to app.connections.begin({ agentRegistrationId: registration.id, redirectUri, scopes }), including accounts:read and agents:read in the requested scopes. That app key also needs connections:write and every requested scope. The owner reviews the public key and explicitly checks the agent API option for one account. me() then describes that exact binding; registration alone cannot make it succeed. The owner still signs any spending grant separately.

For app-key rotation, repeat registerAgent with an active same-app/environment key carrying every existing consent scope. This proves possession again, preserves the customer connection and invalidates old agent sessions. Revoked owner consent requires a new owner approval. Disabled registrations cannot be revived through registration proof.

AgentSigner supplies ensure() with public metadata, sign(message) for EIP-191 registration, and signHash(hash) for raw session and execution digests. createViemAgentSigner(account) adapts an existing viem-compatible account; it does not load, generate, export or back up a key. Each customer connection needs a distinct identity. Independent runtime instances have independent cached sessions.

Session creation coalesces concurrent calls, validates nonce and expiry, and refreshes rejected reads once. Mutations are not automatically retried. The default transport uses generated agent routes and openapi-fetch, refuses owner routes and app credentials, forbids redirects and cookies, and bounds response bodies and request time. The injected transport seam is for trusted host adapters such as MCP.

callApi preserves the provider/endpoint requirements, signature and relay protocol. A pending approval includes its requirementId; resumeApi(requirementId) reads durable payment status before continuing approval, without making another requirements request. A failed relay carries its original requirement ID. Do not treat an ambiguous relay failure as permission to create a new purchase. The owner must complete paid-API setup first; per-agent off-chain mandate checks and the on-chain payment authorization remain distinct.

status: 'submitted' with paymentStatus: 'pending' retains the same requirement while finalized chain evidence is unavailable. Resume it to read progress; the SDK never signs or forwards an already submitted payment again. status: 'settled' proves payment, while providerStatus separately records whether the provider served the request. A provider can fail after payment. Check both fields and the explicit simulated marker before presenting an outcome.

spendUnderGrant validates the v0.7 UserOp shape, signs once and preserves its hash on relay errors. awaitTerminal returns the actual last reported state, including a pending state when its budget ends. Submission is not confirmation. Existing low-level buildDelegatedAction and buildDelegatedSwap methods retain the legacy display-number wire inputs for CLI/MCP compatibility. New integrations use prepareExactAction below. Customer binding and real testnet settlement proof remain release work. No mainnet grant capability is added here.

Exact execution

For the developer-first mandate flow, configure one trusted native gas ceiling when constructing the runtime, then pass the confirmed mandate projection directly. The facade accepts transfer only and maps amountRaw without floating-point conversion:

const runtime = new AgentRuntime(agentSigner, { maxGasCostWei: '10000000000000000' });
const prepared = await runtime.prepareAction({
  mandate,
  action: { type: 'transfer', tokenAddress, recipient, amountRaw: '1000000' },
});
if (prepared.status === 'refused') {
  // No transaction was submitted. Render reason and remainingRaw as policy evidence.
  return prepared;
}
remember(prepared.userOpHash);
return prepared.submit();

The projection must report confirmed creation, active API access, observed active chain authority, the exact account, agent, permission, executor, policy, and remaining limit. The package rechecks the runtime agent identity. Over-limit, wrong-recipient, inactive, expired, and revoked requests return a typed refusal before build or signing. An allowed request continues through the same exact call, nonce-lane, gas-ceiling, hash, signature, one-shot submission, and reconciliation checks described below. OpenAI integration, key loading, persistence, and retries remain host responsibilities.

An already connected agent with an owner-signed grant can prepare an action. Obtain the delegation ID, permission ID and pinned executor address from that approved grant and its network deployment. The app key is never an execution credential. Amounts and the maximum native gas cost are integer strings.

import { AgentRuntime, type AgentSigner, type AgentActionBinding } from '@botanary/agent';

export async function sendUnderApprovedGrant(signer: AgentSigner, binding: AgentActionBinding) {
  const runtime = new AgentRuntime(signer);
  const prepared = await runtime.prepareExactAction({
    accountId: 'your-connected-account-id',
    accountAddress: '0x1111111111111111111111111111111111111111',
    chainId: 84532,
    action: 'transfer',
    tokenAddress: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
    recipient: '0x2222222222222222222222222222222222222222',
    amount: '1000000',
  }, binding);
  // Persist this hash with the application's logical operation before submitting.
  const hash = prepared.userOpHash;
  const receipt = await prepared.submit();
  return { hash, receipt };
}

Replace the example account and recipient with the owner-approved values. Preparation verifies the account, chain, permission, executor, exact calldata, Smart Sessions nonce lane, native gas ceiling and v0.7 EntryPoint hash. It refuses failed simulations, unexpected factories and paymasters. The on-chain grant remains the authority boundary; advisory simulation is not evidence of settlement.

submit() signs and sends at most once for a prepared handle, including concurrent calls and failures. It never builds a replacement automatically. Persist the hash before submission. After a timeout use prepared.reconcile() or, after restarting the client, runtime.getUserOpByHash(chainId, hash). A 404 means no submission is recorded; it does not prove the network rejected it. Keep the outcome unknown and reconcile before offering another spend. The prepared handle is process-local; durable application idempotency across process restarts is a separate platform delivery requirement.

For a swap, use action: 'swap', tokenOutAddress, integer amount, and optional maxSlippageBps. Pass an AgentSwapBinding that also pins routerAddress and integer minAmountOut. The default verifier decodes swapExactIn(tokenIn, tokenOut, amountIn, minOut, to) and checks both assets, input, minimum receive and receiving account. For another reviewed router ABI, supply verifyRoute(facts) and return true only after decoding and checking every supplied fact. Unknown router calldata is refused without that verifier. The outer grant call still pins the router, exact allowance and zero native value. A token address or slippage label in response metadata alone cannot authorize a swap.

API access disablement and on-chain permission revocation are separate. Disabling a registration does not revoke a previously signed grant. Never interpret grantStatus: unknown as revoked authority.

From this package directory: pnpm install --frozen-lockfile, pnpm check:generated, pnpm typecheck, pnpm test, pnpm build, pnpm check:inventory, pnpm run audit:artifact, and pnpm test:packed. Install the independent SDK package before the packed check. The CLI and MCP package integration checks live in their private repositories.

What ships in the npm tarball

Allowlisted declarations (no declaration maps), one bundled and minified dist/index.js (no source maps, no comments; viem, openapi-fetch and node: built-ins external), this README, the changelog and LICENSE. pnpm run audit:artifact verifies the exact tarball.

Every runtime export is classified in docs/specs/2026-09-10-protected-sdk-integration-boundary.inventory.md. AgentRuntime carries no planning, tool selection, compilation, or route/provider selection - the hosted platform re-resolves both swap legs from its own manifest. The only local trust logic is the exact challenge/digest verifier behind prepareExactAction and registerAgent plus one-shot signing and submission fencing, each with a written threat argument. No important logic is distributed; minification is not concealment.