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

@akshitcodes/remote-agents

v0.4.11

Published

Self-hosted mobile web UI for your Codex, Claude Code, and Grok CLI sessions.

Downloads

845

Readme

remote-agents

remote-agents is a self-hosted phone UI for the Codex, Claude Code, and Grok sessions already on your computer. It reads each CLI's session files, lets you continue a thread, streams changes over Server-Sent Events, and can notify an installed PWA when a turn driven through the bridge finishes.

The bridge runs on your computer and uses your already logged-in agent CLIs. It does not provide a hosted relay or a shared account.

macOS setup

You need Node.js 22.18 or newer (the bridge uses Node's built-in SQLite module) and at least one supported CLI installed and logged in. You do not need to prepare Tailscale first: setup can download its current official signed macOS installer, open it, and wait while you approve installation and sign in. The recommended Funnel connection works from anywhere without installing Tailscale—or anything else—on the phone.

Install the package, then run one setup command:

npm install -g @akshitcodes/remote-agents
remote-agents setup

setup asks one plain question: who should be able to reach this Mac? Press Enter for the recommended “phone anywhere with the private pairing link” option; the choice is remembered, so later runs do not ask again. It generates a private per-install token, chooses and remembers a free port, checks all three provider CLIs, installs a per-user macOS LaunchAgent, configures Tailscale Funnel, and verifies that the authenticated app answers through the stable HTTPS name. On a tailnet that has never used Funnel, Tailscale opens a browser approval page; approve enabling Funnel in that tab while setup keeps waiting. Funnel is available on every Tailscale plan, including free. Setup also verifies that MagicDNS is enabled and names that setting specifically if it is not. After approval, the first HTTPS request can take about 28 seconds while Tailscale issues the certificate, so the verifier waits up to 75 seconds. Only then does it print the phone pairing QR.

Running setup again while the supervised bridge is already healthy does not restart it. Active agent turns keep running, and setup safely updates the saved service definition to the current package path. When the turns are idle, run remote-agents stop and then remote-agents start to load updated package code or newly installed providers; setup prints this reminder rather than claiming that the live process changed.

If Tailscale is missing, setup offers to download and signature-check the official installer (or open the official download page), then stays active while you install and sign in. If Tailscale or its HTTPS URL still cannot be verified, setup prints the exact recovery steps and no phone QR. It never substitutes a LAN HTTP link that looks successful but cannot install the PWA or receive push.

  • iPhone/iPad: open in Safari, then Share -> Add to Home Screen.
  • Android Chrome: tap Install app to use Chrome's native install prompt.
  • Open the installed app and tap Enable notifications when offered.

iPhone and iPad Web Push requires an installed Home Screen web app and iOS or iPadOS 16.4 or newer. A normal Safari tab cannot opt in.

Try it without installing a service

This foreground command uses the same Tailscale-first flow and persistent config, but the local bridge stops when the terminal closes:

npx @akshitcodes/remote-agents

Who can reach the Mac?

  1. A phone anywhere with the private pairing link — recommended. Tailscale Funnel provides stable public HTTPS. Only the Mac needs Tailscale; the bridge's long random token is still required for every app/API response.
  2. Only devices in your Tailscale account. Tailscale Serve keeps the HTTPS address private, but every phone must install Tailscale and join the same account.
  3. People allowed by your Cloudflare policy — advanced. A stable hostname on your own domain with an identity sign-in policy; the cost is Cloudflare account, domain/DNS, tunnel, and Access setup.

There is intentionally no LAN HTTP mode. Plain LAN HTTP cannot provide the secure context needed for PWA installation or Web Push. Cloudflare Quick Tunnels are also excluded: their hostname changes on restart and Cloudflare documents that Quick Tunnels do not support Server-Sent Events, which is this app's live transport.

For the advanced option, first create a named tunnel, route its public hostname to the bridge, and create a Cloudflare Access self-hosted application with an Allow policy for that hostname. Then run:

remote-agents setup --transport cloudflare
remote-agents tunnel --name my-agents --hostname agents.example.com --access-protected

The Cloudflare command refuses anonymous Quick Tunnels and withholds its QR until the stable hostname returns the authenticated app. A Cloudflare Access login page alone is deliberately not enough: it proves the policy exists, but not that the app and token work behind it. The URL still contains the bridge pairing token; treat it like a password.

Commands

remote-agents                         foreground server + QR
remote-agents setup                   install/start service; Funnel by default
remote-agents setup --transport serve private Tailscale-only access
remote-agents setup --transport cloudflare
remote-agents tailscale               configure/retry saved Tailscale mode
remote-agents tailscale --transport funnel|serve
remote-agents tunnel --name NAME --hostname HOST --access-protected
remote-agents url                     print pairing QR again
remote-agents status                  show service status and pairing URLs
remote-agents terminal enable         create a 5-minute device enrollment QR/code
remote-agents terminal devices        list trusted terminal devices
remote-agents terminal revoke ID      revoke one device and stop its shell sessions
remote-agents terminal disable        revoke every device and disable shell access
remote-agents start|stop              control the installed service
remote-agents uninstall               remove only the remote-agents service

Useful foreground overrides:

remote-agents serve --host 127.0.0.1 --port 9317
remote-agents serve --token 'at-least-32-random-characters'

Values supplied with --host, --port, or --token are persisted. A new public origin is persisted only after it returns the authenticated app, so a typo cannot strand an existing installed PWA. Later setup, start, status, and url commands reuse the saved transport, origin, port, and token. If Tailscale re-registers the Mac under a different public name, the CLI refuses the change and explains why installed phones would look broken. --replace-origin is the explicit recovery path; after using it, reinstall the phone PWA and enable notifications again.

status and url report the service manager, saved port and transport, Tailscale connection state, saved/verified public address, and readiness of Codex, Claude, and Grok. A missing provider does not block setup when another is ready. If none is installed and signed in, setup stops before installing a background service. Missing or signed-out providers are never installed or authenticated automatically; the CLI prints both commands for each one:

Codex  install: curl -fsSL https://chatgpt.com/codex/install.sh | sh
       sign in: codex login
Claude install: curl -fsSL https://claude.ai/install.sh | bash
       sign in: claude auth login
Grok   install: curl -fsSL https://x.ai/cli/install.sh | bash
       sign in: grok login

The web app exposes only providers that passed both checks when the bridge started. After installing or signing in to another CLI, restart Remote Agents to add it to the provider picker.

Configuration and files

The existing configuration home is reused:

~/.codex-phone/config.json       token, port, public URL, VAPID keypair, options
~/.codex-phone/push.json         browser Web Push subscriptions
~/.codex-phone/usage-retry-policy.json  global/per-task auto-resume choices
~/.codex-phone/usage-retries.json       durable pending usage-limit resumes
~/.codex-phone/terminal-security.json   public passkey credentials and trusted devices
~/.codex-phone/logs/             background-service logs

The directory is written with mode 0700 and secret-bearing JSON with 0600. Set REMOTE_AGENTS_HOME to relocate it (also useful for isolated testing).

Supported optional config fields include:

{
  "codexBinary": "/path/to/codex",
  "claudeBinary": "/path/to/claude",
  "grokBinary": "/path/to/grok",
  "fileAccess": "anywhere",
  "pushSubject": "mailto:[email protected]"
}

fileAccess defaults to anywhere: paired clients can preview and download files anywhere on the bridge computer, subject to the bridge process's OS permissions. Absolute paths may point outside the project; relative paths still resolve against the thread's working directory. Set fileAccess to project to retain project/worktree-only access and individual outside-file approvals. Existing explicit settings are preserved. Authentication, image validation and isolated HTML previews remain required in either mode.

Continue after a usage limit

Auto-resume is off by default. Open a task, tap the settings gear, and enable Auto-continue after usage resets for that task, or enable it for all tasks. After a provider reports a terminal usage-limit failure, the bridge durably queues one Continue. message. It refreshes the currently signed-in account's usage every minute, waits for the task to be idle, and revalidates the exact model, effort, and permission settings before sending. Switching provider accounts is picked up by the next check.

The queued status, provider reset hint, next check, Check now, and Cancel remain available after closing the PWA or restarting the bridge. A bridge restart during the actual send is marked uncertain and is never retried automatically, because sending twice is worse than requiring a manual check.

Project terminal security

Shell access is disabled by default and is deliberately stronger than ordinary app pairing. On the bridge computer, run remote-agents terminal enable, scan the five-minute QR (or enter its one-time code), and create a passkey using Face ID, Touch ID, Windows Hello, or the device PIN. Each browser is enrolled separately. Opening a terminal later requires a fresh passkey assertion; the short unlock expires after inactivity.

The terminal starts in the selected task's provider-reported project folder, which the server resolves again before every new session. That folder is a starting directory, not a filesystem sandbox: the shell has the same OS access as the bridge user. Interactive PTYs run in a separate worker so a native terminal-addon failure cannot stop the bridge or provider agents. If the native PTY is unavailable, the page offers passkey-protected one-shot command mode and never automatically repeats a command whose result is uncertain.

Revoking a device or disabling terminal access invalidates its unlocks and tickets and stops both its interactive and one-shot shell processes. Terminal administration is accepted only from the bridge machine through an authenticated loopback control endpoint; it is not exposed in the web app.

When a provider is not detected

Setup lists each provider CLI as one of four states, and only two of them stop it:

| State | Meaning | Does it block setup? | | --- | --- | --- | | installed and signed in | a signed-in account was confirmed | no | | sign-in unverified | the CLI is there, but nothing proved either way | no — it stays enabled | | installed, but not signed in | the CLI itself said nobody is signed in | only if every provider says this | | not installed | no binary found | only if no provider is installed |

sign-in unverified is normal on a fresh machine: the first run of a provider CLI can take a while, and its answer is not always machine-readable. The provider stays selectable, because trying to send is a better test than a guess made during setup — and the failure it reports is far more specific.

Binaries are looked for on PATH and in the places the official installers use (~/.local/bin, Homebrew, npm/bun/volta/asdf prefixes, and the codex bundled inside ChatGPT.app). Credentials are looked for in ~/.codex/auth.json, ~/.grok/auth.json, ~/.claude/.credentials.json, the macOS Keychain item Claude Code-credentials, and the usual API-key environment variables.

If your setup is unusual, these override the defaults:

| Variable | Purpose | | --- | --- | | REMOTE_AGENTS_BIN_DIRS | colon-separated directories to search instead of the built-in list (PATH is still used) | | REMOTE_AGENTS_CODEX_APP | path to the codex binary inside a ChatGPT desktop app that is not in /Applications | | REMOTE_AGENTS_AUTH_TIMEOUT_MS | how long to wait for a provider's auth check (default 20000) |

You can also pin a binary permanently in ~/.codex-phone/config.json via codexBinary, claudeBinary or grokBinary; setup records the absolute paths it found there, so the background service resolves the same binaries your shell does even though launchd gives services a minimal PATH.

Provider CLI versions

Provider CLIs add, rename and retire capabilities between releases. The bridge therefore uses the strongest provider-owned surface available: Codex app-server model/list; Grok ACP initialization metadata; and, where no structured API exists, the installed CLI's own --help. Claude model aliases come from help, while full model IDs are learned from successful provider transcripts. Every provider also offers an explicit Provider default choice rather than making the bridge guess a value.

Known equivalent names such as Claude's default/manual are mapped to the same Manual contract. If a build cannot prove it can apply the model, effort, or permission setting shown in the UI, the send is refused with an upgrade/reload instruction instead of silently running with different settings.

For example, Claude Code 2.1.0 has no --effort and does not accept --permission-mode auto, while 2.1.238 has both and calls manual approval manual instead of default. On 2.1.0 a Manual send uses the equivalent --permission-mode default; a send asking for Auto or explicit reasoning effort returns a clear instruction to update Claude Code.

This keeps the status bar truthful: choosing High can never secretly run the provider's default effort, and a restrictive permission mode can never be widened. If a CLI's help cannot be read, explicit help-derived settings fail closed and the probe is retried later. Provider-default model/effort remains discoverable, but a send waits until its permission contract can also be proven. This avoids both freezing the bridge during discovery and guessing from the version installed on the package author's machine.

Notifications

On first server start, a VAPID keypair is generated into the same config. After the installed PWA opts in, its Push subscription is stored in push.json. Completed turns are encrypted and signed with web-push; expired subscriptions are pruned when a push service returns 404 or 410. The service worker displays the notification and opens the matching provider/thread when tapped.

Notifications currently cover turns driven through this bridge. The filesystem watcher follows an external terminal/IDE thread only while a client is viewing it; remote-agents does not globally monitor every external session while the PWA is closed.

Connected agents: CLI, MCP and UI

The Linked sessions panel shows bridge-connected agents separately from native provider subagents. You can create a connected agent, connect an existing session, and navigate between creators, children and collaborators. A connection does not copy a conversation or change who owns a turn.

The CLI and MCP tools use the same bridge operations and durable request receipts.

Sessions this bridge starts or resumes (Codex, Claude and Grok) are given their own Remote Agents MCP server, bound to that one session. Their calls are identified by that connection: an agent can spawn, send, queue, steer, reply or wait directly, without whoami, attach or as. A different as (or a different spawn parent) on such a connection is refused, never honoured. The binding passes only the path of a private credential file to the provider; the credential ends when the session's process ends, and a resumed session gets a new one.

From the CLI, or from an MCP server configured globally in a session this bridge did not start (an IDE or terminal session), name the caller explicitly:

remote-agents agent providers
remote-agents agent attach --provider codex --thread YOUR_THREAD_ID
remote-agents agent whoami --as YOUR_AGENT_HANDLE
remote-agents agent spawn --as YOUR_AGENT_HANDLE --provider claude \
  --model MODEL_FROM_CATALOG --effort low --mode auto --cwd /absolute/project/path \
  --role reviewer --request-id review-001 --prompt 'Review the proposed changes.'
remote-agents agent status CHILD_AGENT_HANDLE
remote-agents agent messages CHILD_AGENT_HANDLE

Model, effort and mode may be given directly when you know valid values; they are used exactly as given and an invalid one is refused with the catalog's own error. providers lists the catalog when you need it. Every mutation requires a stable request ID. After a lost response, inspect its receipt with the same ID; do not create another session or resend with a new ID. Send to an idle agent, queue behind a busy turn, or steer where supported. Grok does not support steering. Stopping one agent never stops its children.

remote-agents agent mcp-config
remote-agents mcp

mcp-config prints the literal stdio server configuration for the installed package. Register it in each provider's MCP settings, then reconnect that provider process to discover the tools. mcp runs the stdio server; it is not an interactive shell command. A global MCP server serves many sessions, so its calls explicitly name the caller's handle rather than guessing from a working directory; sessions already open when you first register it may need to be reopened. npm installation does not silently alter provider configuration or authentication. The saved bridge pairing grants full owner access, not restricted agent permissions.

For the complete operation and identity contract, see the Connected agents guide.

Task progress above the composer

Connected agents can record task milestones using task_update and read them with task_list. The coordinator creates a stable task ID for each requested outcome, gives it a title and a plain-English progress summary, and links a worker through assignee plus the exact workRequestId it sent. Assigned workers pass the coordinator's handle as owner and report active or blocked; only the coordinator marks tasks done or cancelled after checking the outcome. Use a new update request ID for each milestone, and replay the same ID/payload after a lost response.

After confirming a fix is resolved and deployed, the coordinator can set archived: true (CLI: --archived true) on its done task to remove it from the current board. Cancelled tasks can also be archived when no longer needed. Done-but-not-deployed tasks stay visible. task_list retains archived history; archived: false or reopening a task restores it to the board.

remote-agents agent task_update --as COORDINATOR --task-id composer-dictation \
  --request-id dictation-plan-1 --title 'Composer dictation' --status planned \
  --summary 'Not started; implementation is next.'

These are reported milestones, not automatic test verification or provider liveness. A task does not become done merely because a worker's turn ends. The panel updates live across devices and recovers after restart, with clickable reporter names and the age of each report. Collapse leaves a small task-count header; that local preference survives reload and updates never force it open. Saved drafts/scheduled messages open from the composer toolbar; queued messages remain above the composer. Completion Snooze/Done controls live in the sidebar.

Status metadata does not start a paid turn, send notifications or replace result delivery and async waits. Agents must use the reporting tools; older conversations are not parsed or backfilled into tasks. Existing MCP processes need reconnecting to discover newly added tools. This is an additive progress surface, not an autonomous scheduler.

Service behavior

On macOS, setup creates ~/Library/LaunchAgents/com.remoteagents.bridge.plist with RunAtLoad and KeepAlive. It records absolute Node/package paths and writes logs below the config directory. Nothing is installed from npm's postinstall; machine changes happen only after the explicit setup command. The supervised process starts only the local bridge; setup remains the single owner of Funnel/Serve changes, public verification, and QR output.

Linux retains a best-effort user systemd service. It has not received the same platform verification as macOS.

On native Windows, setup registers a task for the current user's interactive login, without a password or administrator privilege. The task starts after login, runs on battery, and its launcher retries a failed bridge at most three times, one minute apart. A second start request does not create a parallel task instance. Its name includes a hash of the configuration directory, so relocated scratch installs control their own task. uninstall removes autostart and retains configuration, pairing, and logs. Run setup from an ordinary terminal while logged in; unattended SSH cannot prove interactive login behavior. Node/package paths are recorded, so run setup again after moving or upgrading the global installation, then restart when turns are idle.

Windows provider .cmd shims use the existing explicit quoting boundary. Arguments containing %NAME% remain refused because cmd would expand them. Line breaks, NUL and unpassable variable references are refused before launch. Native discovery includes npm and user-installed executables, and Tailscale's Program Files location. Provider authentication remains with each user's CLI; setup never copies credentials. Native package, provider, terminal and task checks are distinct from the coordinated reboot/login and sleep/resume checks; a manual start does not certify automatic login. WSL is Linux and does not establish native Windows support. Consult the release handoff for the exact artifact's verification and any remaining limitations.

For private access use Tailscale Serve; Funnel provides a public HTTPS address protected by the app's pairing/authentication. Keep the local bridge on loopback (--host 127.0.0.1) when only a local Tailscale or Access-protected Cloudflare proxy needs it. Do not open a public router port or blanket firewall exception. If direct LAN access is deliberate, limit the inbound rule to the chosen port, private profile, and intended clients. The bridge does not create firewall rules or change transport on supervised restart.

Security notes

  • Pairing through ?t=... immediately redirects to a clean URL and stores an HttpOnly, SameSite cookie. HTTPS pairings also receive the Secure flag.
  • Fresh installs generate a 256-bit random pairing token. Repeated bad token attempts receive per-client exponential backoff and rate limiting.
  • App, API, manifest, service-worker, icon, and vendor responses all require the pairing cookie or Bearer token. Unauthenticated responses contain only a generic error and no bridge marker, thread data, local paths, or version.
  • Responses set clickjacking, MIME-sniffing, referrer, permissions, CSP, and same-origin isolation headers; HTTPS responses also set HSTS.
  • Anyone with the pairing URL can drive agents with the permissions selected in the UI. Rotate the token in config if it leaks, then restart the service.
  • Funnel is internet-reachable and the pairing URL is a password. Choose private Serve or Cloudflare Access if the token boundary does not fit your threat model.
  • Agent Markdown is sanitized before rendering. The file viewer is a convenience boundary, not a substitute for authentication.

How it works

A high-level walkthrough of the pieces, provider connections, and multi-device sync is in docs/architecture.html.

  • Codex sessions: ~/.codex/sessions, with codex app-server for active RPC.
  • Claude Code sessions: ~/.claude/projects, using Claude's streaming JSON mode.
  • Grok sessions: ~/.grok/sessions, using its streaming messages protocol.
  • Browser transport: authenticated HTTP APIs plus SSE from /api/events.
  • PWA: one hand-written public/index.html, a manifest, and public/sw.js; no framework or build step.

Development checks

Agent-created visualizations

Codex, Claude and Grok can call the Remote Agents preview_check tool with an existing HTML path, or html for new self-contained content. It checks the actual sandbox in a temporary headless Chrome and returns an image plus blocked resources and script errors. Chrome must be installed on the bridge host (CHROME_PATH may select another Chromium). Missing Chrome or failed checks are reported as not verified; nothing is installed automatically.

The session determines the project folder; agents cannot substitute another chat or cwd. Existing file approvals still apply. CDNs remain blocked even when their origin is on the allowed list. Prefer inline CSS/JS or pre-rendered SVG. A screenshot is bounded visual evidence, not proof of every interaction or later callback.

After checking, reuse the returned reference in the final reply:

{"path":"/absolute/project/chart.html"}

Keep the fence; bare visualize{...} is plain text. For inline source use a fenced html-preview block. These display formats do not require a tool call; the tool is for verification. Previews remain inside the app. Agents using the CLI can run remote-agents agent preview_check --path chart.html --as <own-id>; JSON includes a private temporary screenshot path to inspect and remove when done.

Focused tests

For a small change, run the affected end-to-end journey and the critical boundary checks, not every unrelated provider, retry and recovery scenario:

npm run test:focus -- test/visualization-reference-browser.test.mjs test/html-preview.test.mjs

The selection is explicit and runs with isolated state, one file at a time. An empty or invalid selection fails instead of accidentally running everything. Prefer tests of real user outcomes; retain smaller checks for brittle algorithms, security, ownership, cancellation and no-duplicate-send boundaries. Avoid tests that only pin incidental source spelling or duplicate an already-covered outcome.

npm run test:full (also npm test) retains the complete four-way suite for CI, whole-app releases and changes with a demonstrated broad dependency. Do not run it automatically for a narrow UI change or repeat it because an unrelated test failed. Choose checks before editing, preserve failures and investigate the smallest affected path. Packaging changes still need an installed-artifact check.

Package verification

Version 0.4.11 is intended for the normal latest install under the owner's explicit small self/friend rollout approval. It includes agent preview checks, in-app HTML expansion, compact queued controls, device-local Queue/Steer defaults, wait recovery, folder browsing and the Node 24 compressed-history fix. Scoped Mac and exact installed-package evidence accompany the release; this is not a new whole-app/full/serial or exact Windows certification. Broader historical CI limitations remain open. Native Windows 0.4.9 reboot/sign-in evidence confirmed bridge startup after login; external connectivity required Tailscale activation. Pre-login operation, sleep/wake and very-large-thread latency remain uncertified. Use Node 22.18 or newer. Installation does not restart an existing bridge; restart when idle and reconnect agent tool sessions for newly available tools.

Before publishing a release:

npm pack --dry-run
node --check server.mjs
node --check bin/codex-phone.mjs

The package allowlist explicitly includes every top-level runtime module, including config.mjs and onboarding.mjs, plus providers, the PWA, and public docs. The internal portability audit is intentionally not published because it records details of the owner's previous installation. Do not add a service-installing postinstall.

License

MIT