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

oppi-server

v0.44.0

Published

Self-hosted server for the Oppi mobile coding agent

Readme

oppi-server

Server for Oppi. Embeds the Pi SDK for server-owned sessions and supports terminal-owned mirror sessions through the oppi-mirror Pi extension.

Quickstart

npm global install

npm install -g oppi-server
oppi --version
oppi serve

On first serve, Oppi creates ~/.config/oppi/, generates owner credentials, bootstraps local HTTPS/WSS with tls.mode=self-signed, and prints a pairing QR plus invite link for the iPhone/iPad app. Use oppi pair later to generate a fresh single-use invite.

Upgrade or uninstall the global CLI with npm:

npm install -g oppi-server@latest
npm uninstall -g oppi-server

Source checkout install

Use a source checkout only for development or unreleased server changes. For regular use, prefer the npm global install above.

git clone https://github.com/duh17/oppi.git && cd oppi/server
npm install
npm run build
node dist/src/cli.js serve

If you prefer the repo bootstrapper from outside the repo, use:

curl -fsSL https://raw.githubusercontent.com/duh17/oppi/main/install.sh | bash

Equivalent explicit steps:

git clone https://github.com/duh17/oppi.git
cd oppi
bash install.sh

Use this command only if you need to switch back to self-signed later:

oppi config set tls '{"mode":"self-signed"}'

Optional: enable Tailscale HTTPS/WSS (Let's Encrypt cert via tailscale cert):

oppi config set tls '{"mode":"tailscale"}'

Create a workspace in the app and start a session.

Requirements

  • Node.js 23.6+
  • Pi runtime dependency, installed automatically with the npm package
  • At least one Pi provider configured with pi auth or an API key such as ANTHROPIC_API_KEY
  • macOS or Linux
  • OpenSSL on PATH for tls.mode=self-signed certificate generation

Docker (skills-ready compose setup)

A containerized setup is included in this directory:

  • Dockerfile
  • docker-compose.yml
  • docker/entrypoint.sh

The container runs oppi serve, persists state in Docker volumes, and seeds Pi auth and skills from your host on first start. Mounting the Docker socket is optional and only needed for Docker-backed skill wrappers.

Quick start:

cd server

# Optional: host/ip or tailnet host encoded into pairing links
export OPPI_PAIR_HOST=$(ipconfig getifaddr en0 || ipconfig getifaddr en1)
# export OPPI_PAIR_HOST=<machine>.<tailnet>.ts.net

# Optional: choose container/server port (default 7750 to avoid host conflicts)
export OPPI_PORT=7750

# Optional: host-side SearXNG endpoint for search skill
export SEARXNG_URL=http://host.docker.internal:8888

# Optional: override host paths
# export PI_AGENT_DIR="$HOME/.pi/agent"
# export DOTFILES_DIR="$HOME/.config/dotfiles"

docker compose up -d --build

What it does:

  • runs node dist/src/cli.js serve as PID 1 in container
  • auto-restarts via restart: unless-stopped
  • binds host ${OPPI_PORT:-7750} to the same in-container port
  • persists server state in Docker volume oppi-data (/data/oppi)
  • persists runtime Pi state in Docker volume pi-agent-data (/data/pi-agent)
  • seeds Pi auth/skills/extensions from host ${PI_AGENT_DIR} into container (copy-once by default)
  • exposes host-side SearXNG via SEARXNG_URL (default: http://host.docker.internal:8888)
  • mounts Docker socket so in-session wrappers can reach sibling containers (e.g. web-toolkit)

Important security note:

  • Mounting /var/run/docker.sock gives the container root-equivalent host control.
  • Keep this only if you need Docker-backed skill wrappers (web-nav, web-eval, web-screenshot, etc.).

Useful commands:

# Logs (watch startup + pairing hints)
docker compose logs -f oppi-server

# Health
curl -sk "https://127.0.0.1:${OPPI_PORT:-7750}/health"

# Verify SearXNG reachability from inside container
docker compose exec oppi-server curl -sS "$SEARXNG_URL/healthz"

# Generate pairing QR/deep link explicitly
docker compose exec oppi-server node dist/src/cli.js pair --host <your-lan-host-or-ip>

# Force resync Pi seed from host on next start
PI_AGENT_SYNC_MODE=always docker compose up -d

# Stop / start
docker compose stop
docker compose start

Commands

Use oppi ... for npm/global installs. In a source checkout before linking, use node dist/src/cli.js ... from the server/ directory.

oppi serve [--host <h>]      # start server
oppi init                    # interactive first-time setup
oppi pair [--host <h>]       # regenerate pairing QR + invite link
oppi status                  # server, network, and pairing status
oppi doctor                  # security and environment diagnostics
oppi workspace ...           # list/inspect/create/update/delete workspaces
oppi worktree ...            # list/create/open/preview/remove worktrees
oppi session ...             # create/send/watch/wait/inspect/resume/fork/delete sessions
oppi agent ...               # manage saved Agents
oppi schedule ...            # manage schedules and run history
oppi server ...              # install/status/restart/stop/uninstall launchd service
oppi config ...              # show/get/set/validate config
oppi token rotate            # rotate owner bearer token
oppi update                  # update mutable runtime dependencies only
oppi update --self           # show how to update the server install

Session history reads are consolidated under oppi session inspect. Start with its default turn outline, use --view summary for counts, and request --turns <spec> --view messages|tools only for the smallest relevant turn set.

Saved Agents and schedules

Saved Agents store reusable Agent definitions. Launch inputs such as workspace, worktree, prompt, and session name stay on oppi session create, so the same Agent definition can run in different workspaces.

Schedules store a trigger plus an action. oppi schedule create accepts --at, --every, or --cron; actions can start a new session in a workspace or send input to an existing session. The background schedule runner materializes due runs, dispatches active schedules, and records run history. Pause or archive a schedule to stop future automatic runs.

Install and update modes

  • App-managed runtime: Oppi.app owns server code and seeds ~/.config/oppi/server-runtime. oppi update updates mutable runtime dependencies only; update Oppi.app to update server code.
  • npm global install: npm owns server code. Use oppi update --self for upgrade instructions, npm install -g oppi-server@latest to upgrade, and npm uninstall -g oppi-server to remove. oppi update updates mutable runtime dependencies only.
  • Git/bootstrap install: git owns server code. Use git pull && npm install && npm run build to upgrade a checkout.

Extensions

Oppi uses Pi's extension system and adds mobile rendering for standard extension UI requests. Extension approval behavior lives in Pi extensions, not in server config.

See Oppi extension behavior for workspace allowlists and mobile rendering. Use Oppi Mirror mode for terminal-owned sessions.

Server stats API

GET /server/stats?range=7|30|90&tz=<offset> returns aggregate session counts, cost, token usage, model breakdown, workspace breakdown, and daily trends. GET /server/stats/daily/YYYY-MM-DD?tz=<offset> returns an hourly breakdown and session list for a single day. Both the iOS and Mac apps consume these endpoints for the stats dashboard.

Workspace files API

GET /workspaces/:id/files/<path> serves directory listings and file content over HTTP. GET /workspaces/:id/file-index returns a flat path index for client-side filename search in the iOS file browser.

Configuration

  • Config file: ~/.config/oppi/config.json
  • Data directory: ~/.config/oppi/
  • Override both with OPPI_DATA_DIR or --data-dir

Key config sections:

| Section | What it controls | | -------- | --------------------------------------------------------------------------- | | tls | HTTPS mode: self-signed, tailscale, manual, or explicit insecure HTTP | | asr | Dictation pipeline: STT backend endpoint | | images | Image attachment preprocessing before upload |

Model routing and API keys are managed by pi (pi auth), not the oppi config. Unknown config keys are ignored on startup and reported by oppi config validate.

Quick inspection:

cat ~/.config/oppi/config.json | jq .          # raw config
cat ~/.config/oppi/config.json | jq '.asr'     # single section
node dist/src/cli.js config show                # formatted overview
node dist/src/cli.js config get asr             # top-level key
node dist/src/cli.js config set images.autoResize false
node dist/src/cli.js config set tls '{"mode":"self-signed"}'

For unsupported nested keys, edit config.json directly and restart the server.

See config-schema.md for full reference.

Development

Dependency installation and script runtimes

CI, Docker builds, and the development checks use npm; package-lock.json is the authoritative dependency lockfile for those flows. Use npm ci when you need the same dependency tree as CI. Bun is otherwise used only to execute the TypeScript repository scripts referenced by package.json.

The source-checkout bootstrapper is currently an exception: root install.sh delegates to server/setup.sh, which prefers Bun when it is installed and runs bun install --ignore-scripts. That documented flow consumes bun.lock, so the Bun lockfile cannot be removed until the bootstrapper installs dependencies with npm. Its dependency tree can diverge from the npm/CI tree in the meantime.

npm test                            # vitest unit tests
npm run test:coverage               # coverage gate
npm run check                       # typecheck + lint + dead-code + format check
npm run dev                         # watch mode
npm run test:e2e                    # Docker E2E harness
npm run test:e2e:pairing            # pairing flow only
npm run test:e2e:session            # paired session flow only
E2E_NATIVE=1 npm run test:e2e       # native E2E harness without Docker
npm run bench:correctness           # check + test before perf measurements
npm run bench                       # correctness + perf regression gate
npm run telemetry:review            # telemetry summary
npm run diagnostics:review          # diagnostics summary

Benchmark conventions, baselines, and comparison workflow live in bench/README.md.

Local release telemetry dashboard (SQLite + Grafana)

This stack builds directly on telemetry JSONL files written by oppi-server at:

  • ${OPPI_DATA_DIR:-~/.config/oppi}/diagnostics/telemetry/*.jsonl

1) Start telemetry stack (auto-import + Grafana)

cd server
npm run telemetry:grafana:up

This starts two services:

  • telemetry-importer: watches telemetry JSONL and keeps SQLite in sync.
  • grafana-telemetry: serves the dashboard.

Importer behavior:

  • reads telemetry JSONL from ${OPPI_DATA_DIR:-~/.config/oppi}/diagnostics/telemetry/*.jsonl
  • writes SQLite into a Docker-managed volume mounted at /var/lib/oppi-telemetry-db/telemetry.db
  • runs one import immediately on startup
  • runs SQLite integrity checks on startup/recovery only by default, not on every watch tick
  • continues in watch mode (poll interval: OPPI_TELEMETRY_IMPORT_INTERVAL_MS, default 15000)
  • ingests incrementally for append-only daily JSONL files instead of reimporting the whole hot file each cycle
  • normalizes source file keys so Docker and host imports target the same rows
  • flattens common server-ops tags (path, type, level, lane, ring, code, outcome) for split-stream Grafana panels
  • keeps at most OPPI_TELEMETRY_BROKEN_DB_KEEP_COUNT malformed-db backups (default 1)
  • uses a short-lived lock file so overlapping importer runs skip instead of clobbering each other

Open:

  • http://localhost:13001
  • default login: admin / admin

The datasource and dashboard are provisioned automatically:

  • datasource: Oppi Telemetry SQLite
  • dashboards: Oppi Release Preflight and Oppi Server Health (folder: Oppi)

2) Stop telemetry stack

cd server
npm run telemetry:grafana:down

Optional manual import commands

Use these if you want to import without Docker:

cd server
npm run telemetry:import
npm run telemetry:import:watch

Notes:

  • Services are defined in server/docker-compose.telemetry.yml.
  • The Docker stack keeps SQLite inside a named volume instead of the host-mounted telemetry directory. This avoids SQLite corruption on macOS bind mounts while still reading host JSONL input files. Grafana opens this database read-write because SQLite WAL-mode readers may need sidecar shared-memory files even for read queries.
  • Manual telemetry:import runs still write ${OPPI_DATA_DIR:-~/.config/oppi}/diagnostics/telemetry/telemetry.db on the host, share the same normalized file keys as the Docker watcher, and skip if another importer run currently holds the lock.
  • Importer integrity-check mode is startup by default; use --integrity-check always for old every-run checking or --integrity-check never for trusted throwaway databases.
  • If you use a non-default data dir, export OPPI_DATA_DIR before running commands.

License

MIT