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

@controlflow-ai/daemon

v0.1.8

Published

Small Bun demo for the Lock idea: a local message server, a daemon that connects a computer, and CLI surfaces for humans, agents, and Lark bots.

Readme

pal

Small Bun demo for the Lock idea: a local message server, a daemon that connects a computer, and CLI surfaces for humans, agents, and Lark bots.

Architecture

| Component | Script | Role | Default endpoint | |-----------|--------|------|------------------| | Server | bun run server | Message platform, control API, web workbench, Lark websocket host | http://127.0.0.1:4127 | | Daemon | bun run daemon | Connects one computer, claims deliveries for assigned agents, runs coding-agent CLIs | local API http://127.0.0.1:4137 | | Console | bun run console -- ... | Admin CLI that talks directly to the Server | Server API | | CLI | bun run cli -- ... | Agent/human CLI that talks through the local Daemon | Daemon local API |

The current preferred model is computer-first: provision a computer, start one daemon with the provisioned API key, then assign agents to that computer. The daemon can run with zero agents and periodically reconciles assignments from the server, so newly assigned agents start without a daemon restart and removed agents stop being registered for new work.

Quick Start

The commands below work on Linux/macOS shells. For native Windows daemon setup, PowerShell examples, and Windows path notes, see docs/windows-daemon.md.

1. Install Dependencies

bun install

For disposable local smoke tests, keep state isolated:

export PAL_HOME=/tmp/pal-demo

PowerShell equivalent:

$env:PAL_HOME = "$env:TEMP\pal-demo"

2. Start Server

bun run server

Server listens on http://127.0.0.1:4127/ by default. Change the bind address with PAL_HOST and the port with PAL_PORT:

PAL_HOST=0.0.0.0 PAL_PORT=4127 bun run server

PowerShell equivalent:

$env:PAL_HOST = "0.0.0.0"
$env:PAL_PORT = "4127"
bun run server

When clients or daemons connect through a non-default address, pass --server <url> or set PAL_SERVER / LOCK_SERVER_URL to the reachable URL.

3. Provision a Computer

curl -s -X POST http://127.0.0.1:4127/api/computers/provision \
  -H 'content-type: application/json' \
  -d '{"name":"Local Demo","server_url":"http://127.0.0.1:4127"}'

PowerShell equivalent:

$body = @{ name = "Local Demo"; server_url = "http://127.0.0.1:4127" } | ConvertTo-Json
Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:4127/api/computers/provision" -ContentType "application/json" -Body $body

The response includes a computer.id, an api_key, and a packaged daemon command. For a source checkout, start the local Bun daemon with the returned key:

bun run daemon -- --server http://127.0.0.1:4127 --api-key sk_machine_...

If no agents are assigned yet, the daemon stays connected, heartbeats the computer, and waits for assignments.

4. Create and Assign an Agent

Use agents onboard to create/update an agent and optionally assign it to the provisioned computer:

bun run console -- agents onboard \
  --key codex \
  --name "Codex Agent" \
  --runtime codex \
  --computer-id machine_...

If the daemon is already running with the same API key, it will discover the codex assignment on a later heartbeat and begin claiming deliveries for it. Restarting is not required.

You can also do the two steps separately:

bun run console -- agents create --key codex --name "Codex Agent" --runtime codex --desc "Main coding agent"
curl -s -X POST http://127.0.0.1:4127/api/agents/codex/assignment \
  -H 'content-type: application/json' \
  -d '{"computer_id":"machine_..."}'

5. Send a Message

# Through the local daemon
bun run cli -- send --room general --from alice --mention codex "hello"

# Directly to the server
bun run console -- send --chat general --from alice --mention codex "hello"

Console Commands

Console connects to the server directly and is intended for administration.

Agents

# List agents
bun run console -- agents list [--json]

# Create or update an agent record
bun run console -- agents create --key <agent-key> --name <display-name> [--runtime neeko|coco|codex] [--desc <description>]

# Create/update an agent, optionally assign it to a computer, and optionally set up Lark at the end
bun run console -- agents onboard --key <agent-key> --name <display-name> [--runtime codex] [--desc <description>] [--computer-id <machine-id>]
bun run console -- agents onboard --interactive

# Update runtime and/or manage the Lark bot bound to the agent
bun run console -- agents update --key <agent-key> [--runtime neeko|coco|codex]
bun run console -- agents update --key <agent-key> --lark-app-id <app-id> --lark-app-secret <app-secret> [--lark-label <name>] [--rebind-lark]
bun run console -- agents update --key <agent-key> --unbind-lark
bun run console -- agents update --interactive

# Delete an agent and clean up its assignment, room memberships, subscriptions, Lark binding, and active deliveries
bun run console -- agents delete --key <agent-key> --yes

codex is the validated runtime for the current demo environment. Do not use neeko or coco until their binaries and adapters are available on the runtime host.

agents onboard --interactive asks at the end whether to set up a Lark bot. Lark setup can create a Feishu app by QR scan/open-link, or accept a pasted App ID/App Secret. agents update --interactive manages Lark binding, rebind, and unbind for existing agents.

Lark Bots

# List configured bots; secrets are redacted
bun run console -- lark list

# View recent raw Lark events
bun run console -- lark events --limit 20

# Send a message through a configured bot
bun run console -- lark send --app-id <app-id> --to <receive_id> [--to-type chat_id|open_id|union_id|email|user_id] "Hello"

Lark bot binding is managed as part of agent settings. agents update --lark-app-id ... --lark-app-secret ... validates the credential, resolves bot open_id, writes ~/.pal/lark.json or PAL_LARK_CONFIG, and asks the running server to reload Lark integration. An agent may only be bound to one Lark bot at a time; use --rebind-lark to move that agent from its previous bot to the new bot, or --unbind-lark to clear the binding while keeping the credential.

The Lark config file is written with mode 0600. Use --no-reload when you want to edit or validate the file first, then trigger reload manually:

curl -s -X POST http://127.0.0.1:4127/api/lark/reload

Reload scans the config explicitly. If the file is invalid, the server keeps existing Lark websocket listeners running and returns an error instead of dropping them.

The older bun run console -- lark daemon ... command still exists for standalone Lark testing, but normal server operation now hosts Lark websocket clients inside bun run server.

Messages and Runs

# Health check
bun run console -- health

# List rooms/chats
bun run console -- chats [--json]

# View messages
bun run console -- messages [--chat general] [--parent 1] [--after 0] [--limit 50] [--q text] [--json]

# View an agent inbox
bun run console -- inbox --agent codex [--after 0] [--limit 50] [--json]

# List runs
bun run console -- runs [--json]

# Control a run
bun run console -- run-action <run-id> kill
bun run console -- run-action <run-id> restart

CLI Commands

CLI connects through the local daemon. It is the surface used by coding agents and local operators once the daemon is running.

Rooms, Topics, and Messages

# Send a message
bun run cli -- send --room general --from alice [--mention codex ...] "Task completed"

# Reply to an existing message
bun run cli -- send --room general --from codex --parent 1 "Reply content"

# Send file content as a message
bun run cli -- send --room general --from codex --file /path/to/message.txt

# List rooms and members
bun run cli -- rooms list [--json]
bun run cli -- rooms members --room general [--json]

# Invite an agent to a room with a delivery mode
bun run cli -- rooms invite --room general --agent codex [--mode mentions|all|periodic|muted|off]

# Restart the active runtime for an agent in a room
bun run cli -- rooms restart-agent --room general --agent codex [--json]

# Create a topic inside a room
bun run cli -- topics create --room general "Investigation"

# List or show messages
bun run cli -- messages list [--room general] [--topic 1] [--after 0] [--limit 50] [--q text] [--json]
bun run cli -- messages show <message-id> [--json]

# Start a simple agent-to-agent debate workflow
bun run cli -- debate start --chat general --a codex --b reviewer [--turns 6] "Topic"

Artifacts

# Upload an HTML file through the daemon to the server
bun run cli -- http file /path/to/report.html --mime text/html --title "Report"

# Upload with a TTL in seconds
bun run cli -- http file /path/to/data.json --mime application/json --ttl 3600

Query and Control

bun run cli -- health
bun run cli -- chats [--json]
bun run cli -- runs [--json]
bun run cli -- run-action <run-id> kill
bun run cli -- run-action <run-id> restart
bun run cli -- rooms restart-agent --room general --agent codex

Daemon Commands

# Preferred computer-first startup
bun run daemon -- --server http://127.0.0.1:4127 --api-key sk_machine_...

# Equivalent env-var startup
PAL_API_KEY=sk_machine_... bun run daemon -- --server http://127.0.0.1:4127

# Custom polling interval and daemon local API port
bun run daemon -- --server http://127.0.0.1:4127 --api-key sk_machine_... --interval 3000 --local-port 4137

# Dry run: claim and record runs without executing the agent runtime
bun run daemon -- --server http://127.0.0.1:4127 --api-key sk_machine_... --dry-run

# Legacy explicit-agent startup using a computer id/secret instead of an API key
bun run daemon -- --agent codex --computer-id hm-media-demo --computer-secret pal-demo-computer-secret --cwd /path/to/workspace

# One-shot processing for tests or scripts
bun run daemon -- --server http://127.0.0.1:4127 --api-key sk_machine_... --once

PowerShell equivalents:

# Preferred computer-first startup
bun run daemon -- --server http://127.0.0.1:4127 --api-key sk_machine_...

# Equivalent env-var startup
$env:PAL_API_KEY = "sk_machine_..."
bun run daemon -- --server http://127.0.0.1:4127

# Windows project checkout as runtime cwd
bun run daemon -- --server http://127.0.0.1:4127 --api-key sk_machine_... --cwd C:\Projects\pal

The daemon creates one local API for CLI calls, connects the computer to the server, opens a delivery WebSocket at /api/daemon/ws, heartbeats the connection, reconciles assigned agents, claims pending deliveries for currently assigned agents, and starts one runtime process per claimed delivery. The WebSocket is a wakeup path, not the reliability boundary: deliveries are still durably recorded as pending, so messages can be sent while the daemon is offline or the network is unhealthy, and the daemon drains pending work when the socket reconnects. If the WebSocket is unavailable, the daemon falls back to processing pending deliveries during its heartbeat loop. It can stay online with no assigned agents. Runs have no default timeout; use run actions to kill or restart them.

Environment Variables

| Variable | Default | Description | |----------|---------|-------------| | PAL_HOME | ~/.pal | Runtime home for DB, daemon state, Lark config, and agent homes | | PAL_DB | $PAL_HOME/lock.sqlite | SQLite database path | | PAL_HOST | 127.0.0.1 | Server bind host used by bun run server; set 0.0.0.0 to listen on all interfaces | | PAL_PORT | 4127 | Server bind port used by bun run server | | PAL_SERVER | http://127.0.0.1:4127 | Reachable server URL for console/daemon clients; update this when PAL_HOST/PAL_PORT change client access | | LOCK_SERVER_URL | - | Alternate server URL env read before PAL_SERVER | | PAL_API_KEY | - | Provisioned computer API key for daemon startup | | PAL_AGENT | - | Optional legacy explicit agent for daemon startup | | PAL_COMPUTER_ID | - | Legacy computer id when not using PAL_API_KEY | | PAL_COMPUTER_SECRET | - | Legacy computer secret when not using PAL_API_KEY | | LOCK_DAEMON_URL | http://127.0.0.1:4137 | Local daemon API URL used by bun run cli | | LOCK_DAEMON_TOKEN | token file fallback | Local daemon API bearer token | | PAL_LARK_CONFIG | $PAL_HOME/lark.json | Lark bot credential file | | PAL_LARK_ACTION_REACTION_EMOJI | Typing | Reaction added when Lark delivery is created |

Lark sender authorization is stored in Pal's database. Manage authorized Lark users from the Web Settings Access tab or with:

bun run console -- lark-users list
bun run console -- lark-users add --user-id <union-id> --name "Display Name"
bun run console -- lark-users delete --user-id <union-id>

Runtime Semantics

  • Rooms are the primary conversation container; chat remains as a compatibility alias in several APIs.
  • Agents receive deliveries through room subscriptions, direct mentions, or Lark bot bindings.
  • A daemon starts one agent run for each claimed delivery.
  • Runs do not have a default timeout. Agents can work as long as needed.
  • A visible chat reply is just a message, not run completion.
  • A run completes only when the agent exits normally, fails when it exits non-zero, or is explicitly killed/restarted.
  • Restart kills the current process and starts a fresh run for the same message.

HTTP API

Common read and room APIs:

  • GET /
  • GET /health
  • GET /api/chats
  • GET /api/rooms
  • POST /api/rooms
  • GET /api/rooms/<room-id-or-name>/members
  • GET /api/rooms/<room-id-or-name>/mentionables
  • POST /api/rooms/<room-id-or-name>/agents
  • POST /api/rooms/<room-id-or-name>/agents/<agent-key>/restart
  • POST /api/rooms/<room-id-or-name>/topics
  • GET /api/messages?chat=general&after=0&limit=50
  • GET /api/messages/<id>
  • POST /api/messages
  • GET /api/inbox?agent=codex&after=0&limit=50

Computer, daemon, and delivery APIs:

  • POST /api/computers/provision
  • POST /api/computers/connect
  • POST /api/computers/<computer-id>/heartbeat
  • GET /api/daemon/ws
  • POST /api/daemons
  • GET /api/deliveries?agent=codex&status=pending&limit=50
  • POST /api/deliveries
  • POST /api/deliveries/<delivery-id>/claim
  • POST /api/deliveries/<delivery-id>/ack
  • POST /api/deliveries/<delivery-id>/fail

Agent, session, run, artifact, and Lark APIs:

  • GET /api/agents
  • POST /api/agents
  • POST /api/agents/onboard
  • PATCH /api/agents/<key>
  • POST /api/agents/<key>/assignment
  • GET /api/sessions
  • POST /api/sessions
  • GET /api/sessions/<session-id>/runs
  • POST /api/sessions/<session-id>/runtime-session
  • GET /api/runs
  • POST /api/runs
  • GET /api/runs/<id>
  • POST /api/runs/<id>/pid
  • POST /api/runs/<id>/finish
  • POST /api/runs/<id>/kill
  • POST /api/runs/<id>/restart
  • GET /api/artifacts
  • POST /api/artifacts
  • POST /api/artifacts/cleanup
  • POST /api/artifacts/<artifact-id>/revoke
  • GET /api/workbench/artifacts
  • POST /api/lark/reload

Example message body:

{
  "room": "general",
  "sender": "alice",
  "mentions": ["codex"],
  "content": "hello"
}

Example agent onboarding body:

{
  "agent_key": "codex",
  "display_name": "Codex Agent",
  "runtime": "codex",
  "computer_id": "machine_..."
}

This is intentionally not a production architecture. It is a single-node demo to validate the workflow before adding richer routing, auth, WebSocket delivery, UI, or multi-agent adapters.