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

@hitheo/agent-link

v0.3.0

Published

Agent Link Bridge — run Codex or Claude Code as the brain behind your Theo Personas. Pairs with your OpenCharts account, listens for hand-offs, does the work locally, and speaks the answer back through the persona.

Readme

Agent Link Bridge — @hitheo/agent-link

Run Codex or Claude Code as the brain behind your Theo Personas.

A persona is the face and voice your people talk to. When it is asked for something that needs your files, codebases, terminal or systems, it hands the task to your agent. The bridge is the small program on your computer that makes that reliable: it pairs with your OpenCharts account, listens for hand-offs, drives the runner you chose, reports what it is doing, and sends the answer back so the persona can speak it.

Nothing connects into your machine. The bridge polls OpenCharts over the same MCP server every install recipe uses, with a key that lives only on this computer.

The one paste. In the app (Personas → Start agent, or a persona's Your agent step) click Connect this computer: it shows one command with a five-minute, single-use pairing code. Paste it into a terminal and you are done:

npx -y @hitheo/agent-link@latest connect --code <code> --runner codex
# no Node.js?  curl -fsSL https://www.opencharts.com/agent-link/install.sh | sh -s -- --code <code> --runner codex

connect collects the key the click parked (named after this computer), checks your plan, installs the background service with the agent working in ~/OpenCharts (created if missing; --cwd <folder> to choose a project), and stops — the page that issued the code reads connected on its own and offers Talk to your persona. There is no link to open and nothing to confirm: the click in your signed-in browser was the authorization.

The longer form, step by step:

npx -y @hitheo/agent-link@latest login          # pair this computer (opens the dashboard; click "Link this computer")
npx -y @hitheo/agent-link@latest install --runner codex --cwd ~/path/to/your/project   # background service, starts with your computer,
                                                                                        # then opens your persona in the browser
npx -y @hitheo/agent-link@latest doctor         # why would a link fail?

install ends in the browser: it opens /personas/launch, which runs as you (the signed-in owner), waits for the fresh service's first heartbeat, picks the persona that hands work to your agent — or creates one if you have none — and lands on it with the call ready to start. open does the same later, on demand (--persona <id> to pick one). Before it touches the machine, install checks the paired account's plan: Theo Personas are Pro + Teams, and on a plan without them it refuses with the upgrade link instead of installing a service that would only meet a lock.

start runs the same loop in the foreground (it lives as long as the terminal; --open opens the page once connected). The dashboard at https://www.opencharts.com/developers/agent-link shows the exact commands for your setup and reads connected within a few seconds. Easier still: in the Personas tab, Start agent → Open in Codex hands Codex a prompt that runs these steps for you.

No Node.js? One line installs the bridge as a single binary (no Node.js needed) and prints the same steps:

curl -fsSL https://www.opencharts.com/agent-link/install.sh | sh
# then: ~/.opencharts/agent-link/bin/opencharts-agent-link login   (and install / doctor)

Why a bridge (and not a pasted prompt)

The first Agent Link asked you to paste a "keep polling forever" prompt into your agent. Agents do not do that reliably: turn limits, approval prompts and context compaction end the loop, and nothing tells you it stopped. The bridge is a process, so:

  • the persona reads connected only while the bridge is actually polling (a 45-second heartbeat);
  • every hand-off gets an answer — a runner failure is reported honestly instead of leaving the persona waiting;
  • one runner thread is kept per persona, so the persona remembers earlier hand-offs;
  • a rejected key stops the loop with the reason, and the dashboard names the same key.

Runners

| --runner | Drives | Needs | | -------------- | ------------------------------------------------------------- | ---------------------------------------------------------------- | | codex | codex exec --json (one thread per persona via exec resume) | Codex CLI on PATH, or the Codex / ChatGPT desktop app (macOS) | | claude-code | claude -p --output-format stream-json (--resume per persona) | Claude Code on PATH, signed in (claude login) | | custom | Any command: task on stdin, answer on stdout | --command "<your command>" |

Codex and Claude Code use whatever sign-in they already have. The bridge never handles those credentials.

Sandbox

--sandbox read-only | workspace-write | danger-full-access (default workspace-write).

  • Codex: passed straight through (-s). Approvals are never — a daemon cannot answer a prompt.
  • Claude Code: read-only → --permission-mode default with read tools; workspace-write → acceptEdits plus a Bash allow-list (git, npm, npx, node, python, …); danger-full-access → bypassPermissions. Override with --claude-permission-mode / --claude-allowed-tools a,b,c.

Commands and flags

connect    --code <code> --runner <id> [--cwd <folder>] [--open] [--url <deployment>]  (+ every start flag)
           the one paste: collect the key the app's click parked, install the service (folder default ~/OpenCharts)
login      [--runner codex] [--no-open] [--key oc_…] [--url <deployment>]
           [--print-link]            register a pairing code, print the link + code, exit (for an agent driving the setup)
           [--wait <code>]           collect the key for a code printed by --print-link
start      --runner <id> [--cwd <dir>] [--persona <id>] [--name <text>] [--sandbox <mode>]
           [--timeout <sec>] [--command <cmd>] [--codex-bin <p>] [--claude-bin <p>]
           [--claude-permission-mode <m>] [--claude-allowed-tools <a,b>] [--once] [--quiet] [--open] [--url <deployment>]
install    same flags as start — runs the loop as a background service that starts with your computer, then opens
           your persona in the browser ([--no-open] to skip that)
open       [--persona <id>] [--runner <id>] [--no-open]   open your persona in the browser (or print the URL)
uninstall  stop and remove the service (the paired key stays; `logout` forgets it)
status     is the service installed and running? (+ the last log lines)
restart    restart the service
doctor     [--url <deployment>] [--command <cmd>] [--codex-bin <p>] [--claude-bin <p>]
logout
  • --persona <id> restricts the bridge to one persona's hand-offs (default: any of yours). On open it names the persona to land on; without it the page uses your one delegating persona, the persona you started last, or a chooser.
  • --name is how the persona credits the agent ("Here's what Codex came back with…").
  • --timeout caps one hand-off (default 300 s). Past it the runner is stopped and the persona gets what it had.
  • --once answers a single request and exits (smoke checks, CI).
  • --url targets another deployment (local dev: --url http://localhost:3025). The apex opencharts.com is rewritten to www. — the apex redirects and drops the Authorization header.

The background service (install)

A pasted start lives as long as the terminal; install makes the bridge a service that starts with your computer and restarts itself:

  • macOS — ~/Library/LaunchAgents/com.opencharts.agent-link.plist (launchd, RunAtLoad + KeepAlive).
  • Linux — ~/.config/systemd/user/opencharts-agent-link.service (systemctl --user, Restart=always).
  • Windows — not yet; keep a terminal running start, or add it to Task Scheduler at logon.

The service never runs out of the npx cache (npm prunes it). install copies the program it is running to ~/.opencharts/agent-link/bin/<version>/ — the self-contained cli.js (run by the node that ran install) or, when you installed the single binary, the binary itself — and hands the service an explicit PATH (~/.local/bin, ~/.npm-global/bin, ~/.bun/bin, Homebrew, then yours), because launchd's own PATH would find neither codex nor claude. Everything it wrote is recorded in service.json; logs go to bridge.log.

The launch page (/personas/launch)

The terminal can pair a key and start a service; it cannot know which browser you are signed into, which persona you meant, or whether your plan includes Personas. So install (and open) hand the last mile to a page that runs as you:

https://www.opencharts.com/personas/launch?from=install&owner=<your user id>&runner=codex&host=<this computer>

Nothing in that URL is secret. owner is the paired account's id, so the page can tell you when the browser is signed into a different account than the bridge; runner and host only shape the copy ("Connecting Codex on Ari's Mac…"); persona (from --persona) names the persona to open. The page waits up to 20 s for the fresh service's heartbeat, checks the plan, picks or creates the persona (a new one is <first name>'s agent, delegation on, published), and lands on /personas/<id>?talk=1 — one tap on Start joins the call (browsers block audio without a click).

The bridge learns your account id on login (and backfills it on the first start / install for pairings made before it did), so open needs no network call.

Files

~/.opencharts/agent-link/credentials.json   the paired key + your account id (mode 0600) — never printed, never in argv or a shell profile
~/.opencharts/agent-link/state.json         runner thread per persona
~/.opencharts/agent-link/service.json       what `install` wrote (so status / restart / uninstall need no flags)
~/.opencharts/agent-link/bridge.log         the service's output
~/.opencharts/agent-link/bin/               the installed program: <version>/cli.js or the binary; install.sh puts
                                            `opencharts-agent-link` (or its symlink) here too

Override the folder with OPENCHARTS_AGENT_LINK_HOME. logout deletes the credentials file; revoke the key too under Settings → Integrations → MCP & API Keys if you no longer want it valid.

Other environment variables (all optional): OPENCHARTS_URL (the deployment; --url wins, then this, then the paired credentials, then production), CODEX_BIN and CLAUDE_BIN (same as --codex-bin / --claude-bin), and OPENCHARTS_AGENT_LINK_COMMAND (the custom runner's command when --command is not passed). A custom command receives OPENCHARTS_PERSONA_ID and OPENCHARTS_PERSONA_NAME in its environment; its stderr lines become progress notes.

Pairing, precisely

  1. login generates a UUID code, registers it with your computer's name and runner (POST /api/personas/agent-link/pair/start), and opens /developers/agent-link?pair=<code>.
  2. You sign in and click Link this computer. That click mints an API key named Agent Link · <your computer> and parks it under the code for five minutes.
  3. login polls GET /api/personas/agent-link/pair/poll?code= every two seconds and receives the key exactly once; the server deletes it in the same call.

The code is the only thing that crosses the wire before the key exists. It is 122 bits, single-use and time-boxed.

An agent driving the setup (Codex, through the OpenCharts plugin or the "Open in Codex" prompt) cannot hold a command open for minutes, so login splits in two: login --print-link --runner codex registers the code and prints the link and the code, then login --wait <code> waits for your click and stores the key. Nothing in between ever sees it.

Troubleshooting

  • doctor says the server refused the key (401). It was revoked, expired, or minted for another deployment. Run login again. The dashboard shows the same rejected key and why.
  • install says your plan does not include Theo Personas. Personas are on Pro and Teams; the message carries the upgrade link. doctor's plan line reads the same signal.
  • install finished but no browser opened. Run opencharts-agent-link open (or open --no-open to print the URL and paste it into the browser you are signed into).
  • start says Codex was not found. Install the CLI (npm i -g @openai/codex) or the Codex desktop app, or pass --codex-bin /path/to/codex.
  • The persona says "my agent isn't connected". The bridge is not running, or it is paired to a different account. doctor shows who the key signs in as.
  • Claude Code answers "Failed to authenticate". Run claude login on this computer.
  • The answer sounds like "I'll check that now." The runner announced instead of answering. The bridge detects this for Codex and asks the same thread for the real answer; for Claude Code the appended system prompt forbids it.

Development

From the OpenCharts repo (no install needed inside apps/agent-link):

npx tsx apps/agent-link/src/cli.ts doctor --url http://localhost:3025
npx tsc --noEmit -p apps/agent-link/tsconfig.json
npx vitest run __tests__/agent-link

src/shared.ts re-exports src/lib/personaAgentLink.ts from the web app — the pure rules module — and tsup inlines it at build time (along with @modelcontextprotocol/sdk, so the package has zero runtime dependencies and install can copy one file), so the bridge and the server can never disagree on the spoken-answer rules or the runner ids. The version is stamped into the bundle (__BRIDGE_VERSION__) because the compiled binary has no package.json beside it.

Release

npm run build              # dist/cli.js — what `npm publish` ships (prepublishOnly runs it)
npm run build:binaries     # dist-bin/opencharts-agent-link-<os>-<arch> for every target + SHA256SUMS (bun build --compile)
npm run build:binaries -- host   # just this computer's target, to smoke-test: dist-bin/opencharts-agent-link-darwin-arm64 doctor

Upload every dist-bin/ file, under exactly those names, to a release of hitheoai/agent-link-releases. The web's /download/agent-link/<os>-<arch> paths (and therefore install.sh) always point at the newest release's assets, so a new bridge version needs no web deploy. bun is used from PATH when present, else through npx -y bun@latest.