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

@forked-online/pod-runner

v0.9.0

Published

Self-hosted runner for forked.online pods — registers with the platform, clones a workspace's repos onto a persistent volume, injects env vars, keeps a tmux session, and heartbeats. Honors the platform's manual on/off.

Readme

@forked-online/pod-runner

Self-hosted runner for a forked.online Pod (Pods phase 2, WI-0066).

A Pod is a persistent, per-workspace controller environment for your agents (Hermes / Claude Code / OpenCode). You run this daemon on your own box; it:

  1. Registers with the platform using the pod's runner_token.
  2. Pulls the environment manifest (GET /api/v1/pod/runner/manifest).
  3. Clones/updates every workspace repo onto a persistent volume at the manifest's on-disk paths (idempotent: clone when absent, pull --ff-only when present). Uses a brokered GitHub token when a GitHub App is installed.
  4. Writes the env-var store to <working_root>/.pod.env.
  5. Keeps a tmux session (pod) alive so agent shells persist across runs.
  6. Heartbeats and honors the operator's manual on/off (desired_state).

The platform never exposes env values or the brokered token to agents — only the runner (authenticated by runner_token) receives them.

A freedom pod

The pod is a full, root Debian sandbox — not a scoped Node box. A curated baseline is baked into the image (git, tmux, build tools, mise, the agent CLIs, Hermes); beyond that you install whatever you want, however you want:

  • Languages via mise (Ruby, Node, Rust, Python, Go, Java, …) — installed on demand from a repo's .tool-versions, and they persist on the volume.
  • Tools via cargo / go install / npm -g / pip --user — these are relocated onto /workspace too, so they survive restarts and rebuilds.
  • System packages via apt install — you're root, so it just works in the session. (Those land in the image's root FS, so they reset on an image rebuild; prefer the user-space installers above for anything you want permanent.)

The rule of thumb: the /workspace volume is your machine. HOME, your dotfiles, shell history, SSH keys, toolchains, and per-tool installs all live there and persist; the image just provides the warm baseline.

Production quickstart (forked.online)

  1. Deploy the app and run bin/rails db:migrate.
  2. In the app: sidebar → PodCreate pod → bind your GitHub provider → add env vars (e.g. GITHUB_TOKEN if you're not on a GitHub App) → SaveTurn on → copy the Runner token.
  3. Make sure the workspace's projects have repos linked (the manifest clones them). For in-pod agent runs, install the agent CLI (claude / opencode / hermes) on this host.
  4. On the runner host (with a persistent volume mounted at the working root):
POD_RUNNER_TOKEN=pod_xxx FORKED_BASE_URL=https://forked.online npx @forked-online/pod-runner

It registers → clones repos → writes .pod.env → starts a pod tmux session → heartbeats. The /pod page shows the heartbeat + recent in-pod runs. Then on any work item, hit ▶ Run in pod to launch the chosen agent in its own worktree.

Deploy on Dokploy (or any host, anywhere)

The runner only ever makes outbound connections to the platform — heartbeat, manifest, dispatches, and (since WI-0279) the browser terminal, which tunnels out over the same channel. So it runs on any box, anywhere — a separate VPS behind NAT/Docker is fine, with no inbound ports and no POD_RUNNER_HOST on the app side.

  1. New Dokploy Application → build from this repo, build context pod-runner/ (uses the included Dockerfile: Debian + git + tmux + node-pty + mise + the agent CLIs).
  2. Env on the runner service — just two:
    • POD_RUNNER_TOKEN=pod_… (Settings → Pod → Runner token)
    • FORKED_BASE_URL=https://forked.online
  3. Mount a persistent volume at /workspace (the image's default POD_WORK_DIR). Repos, tmux, your HOME, and everything you install live there.

Then: pod shows a heartbeat → sidebar → Terminal attaches.

Self-hosting Hermes inside the pod (WI-0100)

Enable Pod → Hermes → Host Hermes and the runner will, on each reconcile:

  1. Install the Nous Hermes agent — baked into the Docker image, so a rebuild already has the binary; the runtime only (re)installs it if it's missing (e.g. running from bare source).
  2. Point HERMES_HOME at <working_root>/.hermes on the persistent volume, so Hermes' memory, skills, sessions, and config survive runner restarts.
  3. Render its config — model + agent.reasoning_effort via hermes config set, and into HERMES_HOME/.env: the LLM provider keys plus the API-server platform (API_SERVER_ENABLED=true, API_SERVER_HOST, API_SERVER_PORT, API_SERVER_KEY). Only keys the runner manages are touched; your SOUL.md/skills are left alone.
  4. Supervise the gateway (hermes gateway run), which serves the agent HTTP API (/v1/runs, /v1/runs/:id/events, /api/sessions, /v1/models) only because API_SERVER_ENABLED=true. Restarts it if it exits; reports status via heartbeat.

The API server binds 127.0.0.1 by default on port 8642. Exposing it publicly — and the TLS for that URL — is your responsibility; set POD_HERMES_BIND=0.0.0.0 and put it behind your reverse proxy (target port 8642). Then copy the URL + token from the Hermes tab into a new agent Collaborator (Collaborators → Add → Hermes agent) — from there it's a normal remote Hermes: dispatch, stream, and steer all work unchanged. The token travels in the clear over plain HTTP, so use HTTPS.

Provider keys (e.g. ANTHROPIC_API_KEY) come from the Pod → Environment editor — the runner copies the allow-listed subset into Hermes' .env. Nothing Hermes-related (token or keys) is ever exposed to agents via the manifest.

Auto-wiring the forked.online MCP into Hermes: add HERMES_FORKED_API_KEY=<the agent collaborator's fkd_… key> in Pod → Environment. The runner writes the forked-online MCP server into Hermes' config.yaml (merging, so the rest is preserved) so the agent can read/write work items with zero setup. Use the collaborator's own key (from Collaborators → your agent → Agent), not the workspace key — its actions are then attributed to that agent and scoped to its projects. (API_SERVER_KEY = inbound auth; this fkd_… key = Hermes → forked MCP.)

Setting Hermes up by hand? If you configure Hermes yourself in a pod terminal instead of the UI, enable the API-server platform with the token from the Hermes tab as API_SERVER_KEY:

cat >> "$HERMES_HOME/.env" <<EOF
API_SERVER_ENABLED=true
API_SERVER_HOST=0.0.0.0
API_SERVER_PORT=8642
API_SERVER_KEY=<token from the Pod → Hermes tab>
EOF
hermes gateway restart

Use the token shown on the Hermes tab — that's the one to paste into the Collaborator. (The runner applies these same settings automatically when you use the UI.)

Serve command / port are configurable from the Hermes tab; defaults are hermes gateway run on port 8642 with the API-server platform enabled (API_SERVER_ENABLED / API_SERVER_KEY). A Python + Node agent runs alongside the rest of the pod — size the host accordingly.

Working in the pod (polyglot dev + Rails TDD)

The image ships mise (on-demand toolchains), the native build libs, psql, and the Claude Code / OpenCode CLIs. Per-project toolchains are installed on demand from the repo's .ruby-version / .tool-versions.

Put your dev/test creds in the Pod → Environment variables editor (they're injected into every terminal shell + agent): e.g. DB_HOST / DB_USER / DB_PASSWORD (or DATABASE_URL) pointing at Supabase, plus ANTHROPIC_API_KEY for Claude, etc. The brokered GitHub token is exported as GITHUB_TOKEN/GH_TOKEN automatically.

In a pod terminal:

cd forked-online
mise install            # installs Ruby 3.4.5 / Node / … from the repo's version files
bundle install
RAILS_ENV=test bin/rails db:test:prepare && bin/rails test

DB caveat: tests run against the Supabase connection you supply, and db:test:prepare drops/recreates the test database — use a separate Supabase project/database for tests, not the one holding production data. The no-SUPERUSER convention (create test data directly, no fixtures) still applies on Supabase.

Run from source (any host)

npm install && npm run build

export FORKED_BASE_URL=https://forked.online      # optional
export POD_RUNNER_TOKEN=pod_xxx                    # Settings → Pod → Runner token
export POD_WORK_DIR=/workspace                      # optional; else the manifest's
node dist/index.js

Or with Docker (mount a volume at the working root so repos + tmux persist):

docker run -d --name forked-pod \
  -e POD_RUNNER_TOKEN=pod_xxx \
  -v forked-pod-data:/workspace \
  node:20 sh -c "npx @forked-online/pod-runner"

Env

| var | default | meaning | |-----|---------|---------| | FORKED_BASE_URL | https://forked.online | platform base url | | POD_RUNNER_TOKEN | — (required) | the pod's runner token | | POD_WORK_DIR | manifest working_root | where repos are cloned | | POLL_INTERVAL_MS | 30000 | reconcile + heartbeat interval | | POD_HERMES_BIND | 127.0.0.1 | bind addr for the self-hosted Hermes server |

Status

Phase 2 ships the daemon + the platform's runner-auth endpoints (register / manifest / heartbeat, authenticated by the pod runner_token, with secrets and a brokered GitHub token served only to the runner). Phase 3 (WI-0067) adds launching the chosen agent inside the pod against an on-disk repo; phase 4 (WI-0068) adds per-WI git worktrees + short-lived token hardening.

The platform side is covered by test/controllers/api/v1/pod_runner_controller_test.rb and test/models/pod_test.rb. The daemon's clone/tmux behavior must be validated on a real host (git + tmux + a persistent volume).