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

@scrylog/cli

v0.1.4

Published

Terminal dashboard for monitoring tmux sessions running AI coding agents

Downloads

479

Readme

scrylog

scrylog is a Bun-based terminal dashboard and daemon for monitoring AI coding sessions in tmux and as standalone processes.

It ships four commands:

| Command | Purpose | | --- | --- | | scrylog | TUI dashboard and operator CLI | | scrylogd | Foreground daemon process | | scrylog-mcp | stdio MCP server that proxies daemon data | | oc | OpenCode launcher and attach helper |

Features

  • tmux monitoring for OpenCode, Codex, Copilot, and shell panes
  • OpenCode integration in hooks or sse mode
  • Claude transcript collection
  • Codex transcript collection and hook-based state tracking
  • Local daemon with Unix socket IPC on macOS and Linux, TCP fallback on Windows
  • Optional TCP REST API exposure (enabled by default on Windows)
  • Optional MCP HTTP exposure with bearer token support
  • User-service installation on macOS and Linux
  • Interactive setup wizard and diagnostics

Requirements

  • Bun >= 1.3.0
  • tmux if you want tmux monitoring
  • OpenCode if you want OpenCode monitoring
  • ps on Unix or wmic on Windows for process auto-discovery

Platform Support

| Tier | Platform | Status | Notes | | --- | --- | --- | --- | | Tier 1 | macOS | Tested daily | Full feature set including Keychain OAuth and Safari cookies | | Tier 2 | Linux / WSL 2 | Compatible | Claude OAuth via ~/.claude/.credentials.json, Chrome/Chromium cookies, systemd service when available | | Tier 3 | Windows (native) | Experimental / not recommended | TCP IPC, wmic process scan, degraded service status. Chrome cookie decryption not available (DPAPI not implemented). Primary use is ad-hoc debugging, not daily monitoring. |

WSL 2 Notes

  • The daemon runs as a Linux process and uses the same paths as native Linux.
  • Service installation requires systemd. If systemctl --user is not available, scrylog daemon status reports platform: wsl (WSL) or platform: linux-no-systemd (native Linux) with guidance.
  • tmux monitoring works inside WSL but cannot see Windows-native processes.
  • Browser cookie extraction works for Chrome/Chromium running inside WSL, not for the Windows host browser.

Linux Notes

  • Linux without systemd (containers, minimal distros) reports platform: linux-no-systemd — the daemon runs but service management commands throw descriptive errors.
  • OpenCode port discovery falls back to /proc/<pid>/net/tcp when lsof is unavailable.

Install

Main package

bun install -g @scrylog/cli

This installs the user-facing commands scrylog, scrylogd, scrylog-mcp, scrylog-claude-hook, scrylog-codex-hook, and oc.

OpenCode plugin for hooks mode

Install this only if you want opencode.mode: "hooks":

bun install -g @scrylog/opencode-plugin

From source

git clone https://github.com/scrylog/scrylog.git
cd scrylog
bun install

Quick Start

Simplest setup

Run the setup wizard:

scrylog setup

The wizard can:

  • create the config file
  • optionally configure OpenCode
  • enable or disable the TCP API
  • enable or disable CORS for browser access
  • enable or disable MCP HTTP
  • generate an MCP bearer token
  • install the daemon as a user service

Validated wizard paths:

  • skip OpenCode entirely and keep defaults
  • configure OpenCode hooks mode
  • configure OpenCode sse mode with explicit instance URLs

Launch the dashboard

scrylog

If the daemon is not running, scrylog prints an error with the commands to start it.

Recommended local setup

For most users on macOS or Linux:

  1. Install @scrylog/cli.
  2. Run scrylog setup.
  3. Keep the TCP API disabled unless you explicitly want HTTP access from outside local IPC.
  4. Keep MCP HTTP disabled unless you explicitly need remote MCP over HTTP.
  5. Install the daemon as a user service from the wizard.
  6. Launch the dashboard with scrylog.

Operator CLI

scrylog is both the TUI entrypoint and the operator CLI.

TUI

scrylog
scrylog --config ~/.config/scrylog/config.json

Keyboard shortcuts:

| Key | Action | | --- | --- | | / k | Move selection up | | / j | Move selection down | | Enter | Open session detail | | t | Attach to selected tmux session | | / | Search | | f | Cycle filters | | a | Show actionable sessions only | | r | Refresh now | | Esc | Close detail | | q / Ctrl+C | Quit |

Setup

scrylog setup

Daemon service management

scrylog daemon install
scrylog daemon uninstall
scrylog daemon start
scrylog daemon stop
scrylog daemon restart
scrylog daemon status

Supported service managers:

  • macOS: launchd user agent
  • Linux: systemd --user
  • WSL without systemd: reported as platform: wsl with guidance
  • Windows: reported as platform: unsupported — run scrylogd manually or use Task Scheduler

Typical service workflow:

scrylog daemon install
scrylog daemon start
scrylog daemon status

To stop automatic startup later:

scrylog daemon stop
scrylog daemon uninstall

Config commands

scrylog config path
scrylog config show

Token commands

scrylog token generate
scrylog token rotate
scrylog token clear

Diagnostics and logs

scrylog doctor
scrylog logs

Foreground Daemon

Use scrylogd when you want to run the daemon manually in the foreground:

scrylogd
scrylogd --config ~/.config/scrylog/config.json
scrylogd --log-level debug
scrylogd --log-format json
scrylogd --no-log-file

Use the foreground daemon mainly for:

  • debugging startup issues
  • verifying listener behavior manually
  • local development

Logging options:

| Flag | Purpose | | --- | --- | | --log-level debug|info|warn|error | Override the configured minimum log level | | --log-format pretty|json | Override stderr output format for this process | | --no-log-file | Disable daemon JSONL file logging for this process |

For normal daily use on macOS and Linux, prefer scrylog daemon install so the daemon starts automatically with your user session.

Configuration

Config is loaded from the first path that exists:

  1. --config <path>
  2. SCRYLOG_CONFIG
  3. ~/.config/scrylog/config.json
  4. ~/.scrylog.json
  5. built-in defaults

Example config:

{
  "daemon": {
    "pollIntervalMs": 10000,
    "socketPath": null,
    "commandTimeoutMs": 5000,
    "networkTimeoutMs": 10000,
    "logLevel": "info",
    "logFormat": "auto",
    "logFileEnabled": true,
    "logFilePath": "~/.scrylog/logs/scrylogd.log",
    "logFileMaxBytes": 5242880,
    "logFileMaxFiles": 3
  },
  "api": {
    "tcpEnabled": false,
    "host": "127.0.0.1",
    "port": 7788
  },
  "cors": {
    "enabled": false,
    "origins": [],
    "methods": ["GET", "POST", "OPTIONS"],
    "allowedHeaders": ["Content-Type", "Authorization"],
    "exposedHeaders": [],
    "credentials": false,
    "maxAge": 600
  },
  "opencode": {
    "mode": "hooks",
    "instances": [],
    "autoDiscover": true
  },
  "claude": {
    "claudeDir": "/Users/you/.claude",
    "hooksEnabled": false,
    "hooksDir": "/tmp/scrylog-claude-hooks"
  },
  "codex": {
    "codexDir": "/Users/you/.codex",
    "hooksEnabled": false,
    "hooksDir": "/tmp/scrylog-codex-hooks"
  },
  "tmux": {
    "previewLines": 50,
    "detailLines": 200
  },
  "tui": {
    "refreshMs": 5000,
    "showStandalone": true,
    "usePushUpdates": true,
    "standaloneMaxAgeHours": 6
  },
  "mcp": {
    "stdioEnabled": true,
    "httpEnabled": false,
    "host": "127.0.0.1",
    "port": 7789,
    "bearerToken": null
  },
  "usage": {
    "enabled": true,
    "pollIntervalMs": 300000,
    "providers": ["claude", "opencode-go", "codex"]
  },
  "retention": {
    "maxSessions": 500,
    "standaloneMaxAgeHours": 168,
    "localCommandTtlHours": 72,
    "cacheMaxEntries": 1000,
    "transcriptMaxBytes": 10485760
  }
}

Notes:

  • On macOS and Linux, local clients use the Unix socket even when api.tcpEnabled is false.
  • api.tcpEnabled controls TCP exposure of the REST API, not local daemon IPC.
  • mcp.httpEnabled controls the HTTP MCP listener.
  • scrylog-mcp uses local daemon access and is separate from MCP HTTP.
  • cors.enabled controls whether the API and MCP HTTP handlers include CORS headers. Enable it when consuming the API from a browser (e.g. a web dashboard).
  • cors.origins accepts an array of allowed origins. Use ["*"] to allow any origin.
  • daemon.logFormat: "auto" uses pretty stderr output in a terminal and JSONL when stderr is not a TTY.
  • daemon.socketPath overrides the local Unix socket on macOS/Linux. Leave it unset for the per-user default /tmp/scrylog-<uid>.sock.
  • daemon.commandTimeoutMs bounds daemon-owned commands such as ps, tmux, git, lsof, and pgrep.
  • daemon.networkTimeoutMs bounds daemon-owned usage/integration network requests.
  • usage.enabled: false disables periodic Claude/OpenCode usage probes without disabling session monitoring.
  • retention limits in-memory state. Active working and waiting-input sessions are preserved even when old.
  • The daemon log file is always JSONL and rotates by size: scrylogd.log, scrylogd.1.log, scrylogd.2.log by default.
  • The current CLI preserves an existing legacy config path when updating config, so older ~/.scrylog.json users are not forced onto a new file immediately.

Long-Running Operation

scrylogd is a monitor for active and recent sessions, not a permanent historical archive. Defaults are tuned for unattended daemon usage:

| Setting | Default | Effect | | --- | ---: | --- | | retention.maxSessions | 500 | Prunes oldest inactive sessions above this count | | retention.standaloneMaxAgeHours | 168 | Prunes inactive standalone sessions older than 7 days | | retention.cacheMaxEntries | 1000 | Bounds internal path/project caches | | retention.transcriptMaxBytes | 10485760 | Parses only a bounded tail for very large Claude transcripts | | daemon.commandTimeoutMs | 5000 | Prevents external commands from blocking indefinitely |

Expected daemon RSS depends on active sessions and transcript size:

| Scenario | Expected RSS | | --- | ---: | | No active sessions | 35-70 MB | | Normal local usage | 50-120 MB | | Heavy tmux/Claude/OpenCode usage | 100-250 MB |

If you want longer history, increase retention.maxSessions or retention.standaloneMaxAgeHours. Setting age to 0 disables age-based pruning, but count-based pruning can still apply.

Run diagnostics after changing operational settings:

scrylog doctor

Doctor reports the effective socket path, log path, retention limits, timeout values, and whether usage collection is enabled.

Daemon Logs

scrylogd writes structured logs to stderr and, by default, to:

~/.scrylog/logs/scrylogd.log

The file format is JSONL for bug reports and tooling. Terminal stderr output defaults to pretty formatting when interactive.

Default file rotation keeps three files total:

| File | Purpose | | --- | --- | | scrylogd.log | Active log file | | scrylogd.1.log | Previous active file | | scrylogd.2.log | Oldest retained file |

Example JSONL entry:

{"ts":"2026-05-05T18:42:31.123Z","level":"info","source":"daemon","event":"daemon.started","msg":"Started"}

Logs sanitize home-directory paths, bearer tokens, authorization values, and URL query strings before writing.

The daemon's own file logs are capped by daemon.logFileMaxBytes * daemon.logFileMaxFiles (15 MB by default). Stderr logs written by systemd --user or launchd are retained according to the operating system's service logging policy.

Exposure Recommendations

Recommended defaults for a local machine:

{
  "api": {
    "tcpEnabled": false
  },
  "cors": {
    "enabled": false
  },
  "mcp": {
    "httpEnabled": false
  }
}

Enable api.tcpEnabled only when you want TCP access to the REST API.

Enable cors.enabled when a browser-based client needs to consume the API directly.

Enable mcp.httpEnabled only when you want MCP over HTTP. If you enable it, also set or generate mcp.bearerToken.

OpenCode Integration

OpenCode setup is optional. If you skip it in scrylog setup, defaults remain unchanged until you configure it later.

scrylog supports two mutually exclusive OpenCode modes.

hooks mode

Recommended mode when you run OpenCode inside tmux.

Use it when you want:

  • immediate session updates from OpenCode events
  • permission prompt visibility
  • the best available pane correlation in tmux

Requirements:

  • scrylog
  • @scrylog/opencode-plugin
  • OpenCode config with the plugin enabled

Setup:

  1. Install the plugin.
bun install -g @scrylog/opencode-plugin
  1. Set opencode.mode to hooks and register the plugin.
scrylog setup
scrylog opencode hooks install

Alternatively, add the plugin to ~/.config/opencode/opencode.json manually:

{
  "plugin": ["@scrylog/opencode-plugin"]
}
  1. Start scrylogd or install the service.

Recommended command flow:

scrylog setup
scrylog daemon install
scrylog daemon status

What it allows:

  • webhook-driven OpenCode updates
  • better tmux correlation when the plugin writes @opencode-session
  • child session visibility when OpenCode emits parent IDs

What it does not allow:

  • heuristic opencode attach correlation inside tmux
  • complete exact-session tracking without an upstream OpenCode signal

sse mode

Use this when OpenCode exposes an HTTP endpoint, such as:

  • opencode --port 4096
  • opencode serve
  • oc

Setup:

  1. Set opencode.mode to sse.
  2. Optionally configure opencode.instances.
  3. Leave opencode.autoDiscover enabled if you want local process discovery.
  4. Start OpenCode with opencode --port 4096, opencode serve, or oc.

What it allows:

  • standalone OpenCode monitoring through the SDK
  • explicit instance URLs
  • oc launch and attach workflows

What it does not allow:

  • OpenCode tmux rows
  • plugin-driven updates

Important behavior:

  • in sse mode, OpenCode is shown as standalone only
  • the daemon ignores webhook payloads from the plugin in sse mode

oc

oc is the OpenCode helper included in scrylog. It is mainly intended for sse mode.

oc
oc --continue
OPENCODE_LOCAL_PORT=4097 oc
OPENCODE_HOST=mac-mini.my-tailnet.ts.net OPENCODE_LOCAL_PORT=4096 oc

How it works:

  1. scans running processes for OpenCode instances exposing a port
  2. probes each candidate with GET /global/health
  3. does one of the following:
    • no live instance: launches opencode --port 4096
    • one live instance: runs opencode attach <url>
    • multiple live instances: prompts you to choose one

Environment variables:

| Variable | Default | Purpose | | --- | --- | --- | | OPENCODE_LOCAL_PORT | 4096 | Force a specific port | | OPENCODE_HOST | 127.0.0.1 | Force a specific host |

HTTP API

The daemon always exposes local IPC on Unix socket on macOS and Linux. The TCP HTTP API is optional.

Enable it with:

{
  "api": {
    "tcpEnabled": true,
    "host": "127.0.0.1",
    "port": 7788
  }
}

Endpoints:

| Method | Path | Returns | | --- | --- | --- | | GET | /api/health | daemon health, timestamps, collector status | | GET | /api/status | visible counts, collector status, generated timestamp | | GET | /api/sessions | visible session tree plus counts | | GET | /api/sessions/:id | full session detail | | GET | /api/sessions/:id/children | visible child sessions | | GET | /api/sessions/:id/messages | recent messages when available | | GET | /api/config | active config with sensitive fields redacted | | GET | /api/events | SSE stream of store events | | POST | /api/webhook/opencode | OpenCode plugin webhook |

All error responses follow a consistent format:

{ "error": "Session 'abc' not found", "code": "NOT_FOUND" }

Known codes: NOT_FOUND, UNAUTHORIZED, VALIDATION_ERROR, INTERNAL_ERROR.

Example:

curl http://127.0.0.1:7788/api/health
curl http://127.0.0.1:7788/api/sessions

MCP

stdio MCP

Use scrylog-mcp for local MCP clients:

scrylog-mcp

Example MCP client config:

{
  "mcpServers": {
    "scrylog": {
      "command": "scrylog-mcp"
    }
  }
}

Available tools:

  • list_sessions
  • get_active_sessions
  • get_session
  • get_session_messages
  • get_session_children

Available resources:

  • sessions://all
  • sessions://active
  • config://current

MCP HTTP

MCP HTTP is disabled by default.

Enable it with:

{
  "mcp": {
    "httpEnabled": true,
    "host": "127.0.0.1",
    "port": 7789,
    "bearerToken": "your-secret-token"
  }
}

If bearerToken is set, clients must send:

  • Authorization: Bearer <token>

For streamable HTTP clients, include:

  • Accept: application/json, text/event-stream

The server uses stateful MCP HTTP sessions:

  1. send initialize
  2. read the mcp-session-id response header
  3. send notifications/initialized with the same mcp-session-id
  4. send later MCP requests with the same mcp-session-id

MCP HTTP Security

Generate a token from the operator CLI:

scrylog token generate

Rotate it later with:

scrylog token rotate

Clear it with:

scrylog token clear

Service Installation

You can keep the daemon running automatically with the operator CLI:

scrylog daemon install
scrylog daemon start
scrylog daemon status

macOS uses a LaunchAgent under ~/Library/LaunchAgents/.

Linux uses systemd --user under ~/.config/systemd/user/.

The service lifecycle was validated with:

  • install
  • start
  • restart
  • stop
  • uninstall

If you want to inspect the current service state or listener reachability, run:

scrylog daemon status
scrylog doctor

Troubleshooting

scrylog cannot connect to the daemon

Start it manually:

scrylogd --log-level debug

Or inspect the service:

scrylog daemon status
scrylog logs

If you normally use the user service, also try:

scrylog daemon restart

OpenCode is missing in hooks mode

Check:

  1. opencode.mode is hooks
  2. @scrylog/opencode-plugin is installed
  3. OpenCode config includes "plugin": ["@scrylog/opencode-plugin"]
  4. the daemon is running

OpenCode is missing in sse mode

Check:

  1. opencode.mode is sse
  2. OpenCode is exposing a reachable HTTP endpoint
  3. opencode.instances is correct or autoDiscover is enabled
  4. GET /global/health succeeds on the OpenCode endpoint

MCP HTTP returns 401 Unauthorized

Send the configured bearer token.

MCP HTTP returns No valid session ID provided

Start with initialize, then reuse the returned mcp-session-id.

I want a guided setup again

Run:

scrylog setup

Validated User Flows

These user-facing flows were exercised after implementation:

  • operator CLI help and subcommands
  • daemon foreground startup
  • daemon user-service install, start, restart, stop, uninstall on macOS
  • scrylog TUI launch and quit
  • setup wizard skip, hooks, and sse flows
  • MCP token generate, rotate, and clear
  • TCP API enable and disable behavior
  • MCP HTTP enable, disable, and bearer-token enforcement
  • scrylog-mcp stdio startup and tool discovery

Development And Release

Development Hooks

When developing from this checkout, use local hook paths instead of the published package. This is only for local development and manual testing; normal users should follow the published package setup above.

Claude Code hook commands should point to this checkout:

bun run /Volumes/Files/Workspace/Projects/other/scrylog/src/hooks/claude.ts

Use that command for every Claude hook event that scrylog tracks.

Codex hook commands should point to this checkout:

bun run /Volumes/Files/Workspace/Projects/other/scrylog/src/hooks/codex.ts

Use that command for every Codex hook event that scrylog tracks.

For OpenCode local plugin testing, create or update:

~/.config/opencode/plugins/scrylog.ts

with:

export { server } from "file:///Volumes/Files/Workspace/Projects/other/scrylog/packages/opencode-plugin/src/index.ts"

For package usage, prefer the published plugin configuration:

{
  "plugin": ["@scrylog/opencode-plugin"]
}

Validation:

bun run check-types
bun run test

Publish-readiness checks:

bun run release:check

Public packages are versioned with Changesets and validated through Turborepo. The release workflow creates a version PR on main; merging that PR publishes @scrylog/cli and @scrylog/opencode-plugin to npm.

OpenSpec

Design and behavior artifacts live in openspec/.