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

rcman

v1.2.0

Published

Remote Control Manager — a PM2-style supervisor for AI coding-agent remote-control sessions (Claude Code, OpenAI Codex CLI).

Readme

Follow me on X @ybouane — I'm building in public.

rcman — Remote Control Manager

A PM2-style process manager for AI coding-agent remote-control sessions.

systemd manages rcman. rcman manages your agent sessions.

$ rcman list
┌────────────┬──────────┬────────┬───────┬────────────┬──────────────────────────┬────────┐
│ Name       │ Provider │ Status │ PID   │ Session ID │ Directory                │ Uptime │
├────────────┼──────────┼────────┼───────┼────────────┼──────────────────────────┼────────┤
│ storefront │ claude   │ online │ 16549 │ d7b1e2a4   │ /srv/projects/storefront │ 4h12m  │
│ api-server │ claude   │ online │ 16712 │ a1c9f082   │ /srv/projects/api-server │ 4h11m  │
└────────────┴──────────┴────────┴───────┴────────────┴──────────────────────────┴────────┘

No tmux. No git worktrees. rcman never touches your repository, your branches or your agent conversations.


Why

Remote control lets you drive a coding agent running on your server from your phone or a browser. Keeping a dozen of those alive by hand is the problem: they die on reboot, they stall on a startup modal, and a second attach to the same session forks its history.

rcman is the supervisor for that: one managed process per session, restarted when it crashes, restored after a reboot, with per-session logs and a registry of exactly which session id lives where.

Install

npm install -g rcman
rcman service install     # detects this machine's service manager and registers rcman

service install figures out how the machine starts things at boot — a systemd user service, a launchd agent, an OpenRC service, or a cron @reboot entry — writes the right unit with real resolved paths, enables it and starts it. On systemd it also turns on user lingering, without which nothing survives a logout. rcman service detect shows what it found and why.

Requires Node 18.17+, and at least one provider CLI on PATH (Claude Code or the Codex CLI).

Quick start

rcman setup      # guided: provider, boot service, first sessions

setup checks whether an agent CLI is installed and offers to run its own installer if not — showing you the exact command first, defaulting to no. It then checks you are signed in, and offers to run the provider's login flow. Then the boot service, the daemon, and your first sessions.

Or do it by hand:

rcman config set defaultProvider claude    # used when --provider is omitted

rcman start my-session ~/projects/foo   # create a new session in that directory
rcman start my-session                  # resume the one you already have
rcman ls                                # what is running
rcman logs my-session -f                # follow its output
rcman info my-session                   # session id, cwd, remote URL, limitations
rcman restart my-session
rcman stop my-session
rcman remove my-session                 # unregister; the conversation survives

How rcman start decides

rcman start <name> <path>     -> create and start a NEW session there
rcman start <name>            -> resume an EXISTING one:
                                   1. rcman's registry, by name
                                   2. otherwise ask the provider adapter to
                                      discover a local session with that name
                                   3. most recently active wins if several match
                                   4. register it, then resume that exact session

Discovery reads only the provider's own session metadata (~/.claude/projects, ~/.codex/sessions). It never walks your project directories.

If neither the registry nor discovery finds the name, rcman stops and says so. It will not quietly create a new session behind a resume request.

Commands

| Command | What it does | | --- | --- | | rcman setup | Guided first-run: install a CLI, sign in, register for boot, add sessions | | rcman start <name> [path] | Start a session (see the rules above) | | rcman start all | Start every enabled session | | rcman start <file.json> | Register and start everything in an ecosystem file | | rcman stop <name> / stop all | SIGTERM, then SIGKILL after a grace period | | rcman restart <name> / restart all | Stop, then start | | rcman remove <name> | Unregister from rcman only | | rcman enable <name> | Autostart on; start it now | | rcman disable <name> | Stop it and keep it stopped across restarts | | rcman list, rcman ls | Status table | | rcman status <name> | One-line status | | rcman info <name> | Everything rcman knows + provider limitations | | rcman logs [name] [-n N] [-f] | Per-session logs | | rcman discover [name] | Sessions the provider knows about locally | | rcman providers | Installed provider CLIs and their limitations | | rcman config get/set/unset/list | Settings | | rcman reload | Re-read config + registry; running sessions keep running | | rcman trust <path> / untrust | Let the provider act in a directory | | rcman service install | Auto-detect the service manager and register for boot | | rcman service status | Where rcman is registered, and whether it is running | | rcman service detect | Which managers exist here, and which one wins | | rcman service print | Show the generated unit without installing it | | rcman service uninstall | Deregister (sessions are not deleted) | | rcman daemon | Run the supervisor (what the service runs) | | rcman daemon --stop | Stop the supervisor; sessions keep running | | rcman upgrade | After an npm update: refresh the unit, restart the daemon |

Add --json to list, status, info, discover for machine-readable output.

Configuration

Global settings live in $RCMAN_HOME/config.json (~/.rcman by default):

rcman config set defaultProvider claude
rcman config get defaultProvider
rcman config list

Sessions are declared in a PM2-style ecosystem file kept outside the package:

{
  "sessions": [
    {
      "name": "my-session",
      "provider": "claude",
      "sessionId": "d7b1e2a4-9c3f-4f56-b0aa-6e1c2f3d4a5b",
      "cwd": "~/projects/foo",
      "enabled": true,
      "providerOptions": {"resumeMode": "summary"}
    }
  ]
}
rcman start ~/rcman.json

Edit config.json or registry.json directly and rcman picks the change up on its own — or rcman reload to apply it now. Either way running sessions keep running: supervision settings and notes are applied in place, and an edit that changes how a session launches is reported as pending rather than acted on, because saving a file is not permission to interrupt an agent mid-task.

Full field reference: docs/CONFIGURATION.md.

Updating

npm install -g rcman

npm replaces files; it does not restart processes. The daemon would otherwise keep executing the version it started with, while the CLI you just installed is the new one — talking to it over an IPC contract that may have moved. rcman handles that in three ways:

  • a post-install hook restarts the daemon when one is running and the version actually changed. It is inert for a non-global install, inert when no daemon is running (so image builds and CI do nothing), never fails the install, and RCMAN_NO_POSTINSTALL=1 turns it off.
  • every command notices the skew anyway, because the handshake it already makes now carries a version, and says so rather than letting you find out sideways.
  • rcman upgrade does it deliberately: refresh the boot unit if the install moved, restart the daemon, and confirm every session came across.
$ rcman upgrade
rcman 1.0.2  ·  daemon running 1.0.1
✔ daemon restarted on 1.0.2 (pid 129203)
✔ 8 session(s) carried across untouched

This is only safe to do automatically because a managed session outlives the supervisor — see Sessions outlive the supervisor.

rcman upgrade also catches a failure npm cannot: service install bakes absolute paths for node and rcman's entrypoint into the unit, and under a version manager both live under the node version. Installing rcman on a newer node leaves the unit pointing at the old copy, which nothing surfaces until the next boot.

Providers

rcman talks to agent CLIs through adapters. Two ship today; the contract is one file (src/providers/base.js) and adding one is an import plus a line in src/providers/index.js.

Claude Code

Fully supported: one managed process per session, bound to one exact session id.

  • claude remote-control is an environment, not a session. The subcommand starts a persistent server that hosts up to --capacity conversations created on demand, and publishes claude.ai/code?environment=env_…. The flag on the main command — claude --remote-control — is one session, publishing claude.ai/code/session_…. rcman supervises sessions, so it uses the flag. The environment is available as providerOptions.attach = "environment".
  • A new session gets its uuid from rcman up front (--session-id), so every later start resumes that same conversation instead of beginning a new one.
  • claude remote-control --session-id <id> only reattaches a bridge session (a cse_…/session_… id that already has an environment). Given a local transcript uuid it fails with "has no environment_id", so it is not the way to resume an ordinary local session. rcman exposes it as providerOptions.attach = "bridge".
  • Binding remote control to one exact local session therefore uses claude --resume <uuid> --remote-control, which is the interactive UI and refuses to run on a pipe. rcman allocates a pty with script(1) — no tmux, no native dependency.
  • Resuming a large session shows a blocking "resume from summary / full" modal. rcman answers it (summary by default; providerOptions.resumeMode).
  • The workspace must be trusted before a session can run there. claude remote-control hard-errors on an untrusted directory rather than prompting, and the resume path shows a modal that stalls forever — so rcman reads ~/.claude.json up front. In a terminal it offers to grant it there and then; otherwise it refuses with the fix, rcman trust <path>. Either way it is a decision you make — never a side effect of starting a session.
  • Reattaching mints a fresh bridge, so the claude.ai/code URL changes on every restart. rcman info <name> always has the current one.

OpenAI Codex CLI

Supported with a documented ceiling, because Codex's architecture differs.

  • Codex remote control is one machine-wide app-server daemon, not a per-session process. rcman supervises exactly one Codex session per machine and refuses a second.
  • There is no --session-id equivalent: remote control cannot be bound to a specific thread. Threads are created and attached from the Codex app.
  • codex resume <id|name> does resume a specific thread, but it is the interactive TUI and is not a remote-control surface.
  • The daemon self-backgrounds, so rcman's managed child is a small supervisor that keeps it alive and healthy and stops it on rcman stop.
  • Pair once, interactively: codex remote-control pair.

rcman providers prints the current list for the CLIs you actually have installed.

Process management

  • One managed child process per session, tracked by PID, status and start time.
  • Crashed sessions restart with a delay and a crash-loop budget; a session that ran happily for hours always gets a fresh allowance.
  • Graceful stop: SIGTERM to the process group, SIGKILL after stopTimeoutMs.
  • rcman never signals a process it did not start. Every kill is gated on the live /proc/<pid>/cmdline still matching the command rcman recorded, and leftovers are only swept if they were both descendants of that process and still a signature match.
  • online means reachable, not merely alive. A provider declares whether a healthy session publishes a remote-control URL; when one that should has not after 90s, rcman says so rather than implying all is well. (A session stalled on an unanswered startup prompt keeps its process and passes every other check, while never appearing in the app.)
  • Startup modals that would stall an unattended session are answered from a list the provider declares — the resume prompt, Enable Remote Control?. Security decisions are never among them: those are reported, or asked about.
  • Duplicate protection: rcman refuses to attach to a session another process (a terminal, an IDE, another supervisor) is already driving, because two writers fork a conversation's history.
  • Session-scoped environment markers from a parent agent process are scrubbed — inheriting CLAUDE_CODE_CHILD_SESSION silently disables transcript saving.
  • Per-session logs, ANSI-stripped, spinner-frame-filtered and size-rotated.

Sessions outlive the supervisor

Restarting rcman must not cost you an agent's train of thought. Upgrading the package, editing the config, a daemon crash — none of them touch a running session. Three things make that true, and each one is load-bearing on its own:

  • No pipes. A child whose stdout is a pipe to the daemon is killed by SIGPIPE the moment the daemon exits. Sessions write to plain files instead, and the daemon tails them — so a successor resumes capture mid-stream, at the exact byte the last one reached, rather than replaying or losing output.
  • A fifo for stdin, opened O_RDWR. The child inherits a descriptor that is also a writer, so its stdin never reaches EOF even with no daemon alive to hold it. A new daemon reopens the write end and can answer a prompt again.
  • Its own cgroup. systemctl stop kills a cgroup, not a process, so a session spawned inside rcman.service dies with it whatever the daemon does. rcman launches each session in its own transient scope via systemd-run, and the generated unit sets KillMode=process as a second line of defence.

So SIGTERM to the daemon means detach, not stop: it persists each pid, signature and capture offset, lets go, and the next daemon adopts them. Ending a session stays an explicit act — rcman stop, or rcman daemon --stop --with-sessions.

systemctl --user restart rcman   # sessions never notice
rcman daemon --stop              # supervisor goes, sessions stay
rcman stop all                   # this is how you actually stop them

Starting at boot

rcman service install            # auto-detect and register
rcman service status             # where it is registered
rcman service detect             # what is available on this machine
rcman service print              # the generated unit, on stdout
rcman service uninstall          # deregister
rcman service install --manager cron   # override the auto choice

Managers are tried in this order, and the first usable one wins:

| Manager | Used when | Restarts on crash | | --- | --- | --- | | systemd-user | Linux with a systemd user manager | yes | | launchd | macOS | yes | | systemd-system | Linux, running as root or with passwordless sudo | yes | | openrc | Alpine and friends, with root | yes | | cron | anything else with crontab | no — boot only |

The generated unit hardcodes nothing about your machine: node's path, the rcman entrypoint, RCMAN_HOME and a minimal PATH containing the provider binaries are all resolved at install time. Adding a manager is one file in src/service/ plus a line in src/service/index.js, exactly like a provider.

Runtime layout

Nothing is written inside the installed package. What you edit and what rcman maintains are deliberately separate files:

$RCMAN_HOME/                 # ~/.rcman by default
├── config.json              # global settings          — watched for edits
├── registry.json            # registered sessions      — watched for edits
├── state.json               # pid, signature and capture offset, for adoption
├── daemon.sock              # CLI <-> daemon
├── daemon.pid
├── daemon.log
├── logs/
│   ├── <name>-out.log       # readable: ANSI-stripped, denoised, rotated
│   └── <name>-err.log
└── run/
    ├── <name>.in            # stdin fifo, outlives the daemon
    └── <name>.out.raw       # what the child writes; the daemon tails this

RCMAN_HOME moves all of it. RCMAN_CLAUDE_BIN / RCMAN_CODEX_BIN point at a specific CLI binary.

Architecture

systemd --user
   └── rcman daemon              one supervisor process — disposable
        ├── unix socket          newline-delimited JSON, CLI <-> daemon
        ├── registry.json        which sessions exist; watched for edits
        └── ManagedSession × N   one child process each, in its own cgroup scope
             ├── stdio           files + a fifo, so the child outlives the daemon
             └── provider adapter   builds the command, discovers sessions,
                                    answers startup modals, reports limits
  • src/core/ — daemon, IPC, registry, config, process control, logging.
  • src/providers/ — one file per agent CLI, plus the adapter contract.
  • src/service/ — one file per boot-time service manager, plus its contract.
  • src/commands/ — one function per CLI verb.

The CLI is a thin client: it auto-starts the daemon if it is not listening, then sends a single request.

Development

npm test          # node:test, no dependencies
node bin/rcman.js help

rcman has zero runtime dependencies.

License

MIT