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

@moor-sh/cli

v0.9.0

Published

Command-line interface for moor - manage your moor server's projects, logs, env vars, and container lifecycle.

Readme

@moor-sh/cli

Command-line interface for moor - manage your moor server's projects, logs, env vars, and container lifecycle from a terminal. Ships a moor binary.

Requires Bun on the machine running the CLI.

Install

One-shot (no install):

bunx @moor-sh/cli status

Global install (puts moor on PATH):

bun add -g @moor-sh/cli
moor status

Don't use bunx moor (without the scope) - moor on npm is an unrelated package.

Log in

moor login https://moor.example.com
moor status
moor logout

Enter your admin password at the hidden prompt. Moor saves a separate 30-day session for this machine in ~/.config/moor/config.json (or $XDG_CONFIG_HOME/moor/config.json), readable only by your user. The password is never saved. This credential grants full admin access to the Moor host; keep it outside synced folders.

For a server with private admin access (the default), open an SSH tunnel first:

ssh -L 8080:127.0.0.1:3000 your-server
# In another terminal:
moor login http://127.0.0.1:8080

Login requires HTTPS, except for loopback HTTP through a tunnel or on the server itself. For piped input, use moor login <server-url> --password-stdin; never put the password in arguments.

One server login is saved per machine. Run moor logout before logging in again or changing servers. Logout revokes that session and removes the local file; if the server is unreachable, it keeps the file so you can retry revocation. Resetting the server's admin password revokes all sessions, including CLI logins. There is no automatic session renewal.

Automation

Existing API keys still work. Set both variables to override the saved login:

export MOOR_URL=https://moor.example.com
export MOOR_API_KEY=your-api-key

Setting only one fails instead of combining it with saved credentials. Unset both to use the saved login. moor logout does not revoke environment API keys. See the self-hosting guide for key setup and rotation.

The MCP server and moor mcp config continue to use their existing API-key configuration; they do not read the saved CLI login.

Commands

moor status                          # list all projects (human-readable alias)
moor project list [--json]           # list projects
moor project get <name|id> [--json]  # get one project
moor logs <project> [-f] [-n 100] [--json] # view container logs
moor rebuild <project> [--no-cache] [--json] # rebuild from source
moor restart <project> [--json]      # stop + start
moor stop <project> [--json]         # stop without deleting the project
moor exec <project> [--json] -- <command> # run a shell command in the container
moor env list <project> [--json]     # list environment variables
moor env set <project> KEY=VALUE     # set environment variables (human mode)
moor env set <project> --env-file - --json # set environment variables (agent mode)
moor stats [--json]                  # server resource usage
moor history <project> [--hours N] [--json] # stored resource history and events
moor project deploy <name> [options] # create or update and optionally run a project
moor mcp config --client <name>      # generate MCP client config snippet

Project inspection

Use the project commands to verify a deploy or inspect current configuration:

moor project list --json
moor project get api --json
moor project get 7 --json

Both commands print one JSON document to stdout in --json mode. Failures print a JSON error to stderr and exit nonzero. Without --json, project list uses the same table as the existing moor status alias and project get prints readable, indented JSON.

Project selectors accept a name or numeric ID. If a numeric selector matches both, an exact project name takes precedence.

Logs

Use finite JSON mode when an agent needs recent container output and its state:

moor logs api -n 100 --json

Success prints the API response as one JSON document with logs, lastTimestamp, and state (ok, exited, no_container, or missing). Failures print structured JSON to stderr and exit nonzero. Exact project names take precedence over numeric IDs, matching moor project get.

--json cannot be combined with --follow yet. Use moor logs api --follow for the existing human-readable polling mode; a later streaming slice will define JSONL follow events.

Host stats

moor stats --json returns the server's stats response as one JSON document, including host CPU, memory, disk, and container totals. Without --json, it retains the human-readable summary. Errors go to stderr and exit 1; unknown options and extra arguments are rejected before any request.

Resource history

moor history api --hours 6 --json returns the full API history document, including stored samples, events, and summary. The default window is 24 hours; --hours=N and fractional hours also work. Windows extending before the Unix epoch start at zero. Human mode retains the summary and ten most recent events.

Errors go to stderr and exit 1. Unknown arguments, duplicate --hours, and invalid durations are rejected before requests. Exit 0 means history was retrieved, not that the workload is healthy.

Run inspection and cancellation

moor run list api --page 1 --json returns {runs,total} with 20 summaries per page and no stdout/stderr bodies. moor run get 11 --json returns the run metadata and the last 8192 bytes of each output stream. Use --tail-bytes 0 for metadata only, or up to 65536 bytes per stream.

Detail output includes stdout_truncated and stderr_truncated flags and preserves total byte counts. UTF-8 characters are not split. The CLI limits displayed output after fetching the stored run; it does not limit the API download. Server-side retention may already have removed older output.

For list/get, exit 0 means the read succeeded, even if the recorded run has a nonzero exit_code. Argument and request failures exit 1 and put errors on stderr. Without --json, list shows summary lines and get shows indented JSON.

moor run stop 11 --json attempts cron/build cancellation once. Use an ID from cron run or run list, never from job start. Build cancellation is available only during the build/pull phase. Successful cancellation outcomes go to stdout and exit 0; HTTP errors (including 409 outcomes such as cron_kill_incomplete) go to stderr and exit 1, preserving server details. An HTTP-success body with ok:false also exits 1, on stdout. Human mode prints indented outcome JSON.

Inspect result, message, and live_remaining when present. Incomplete cancellation can leave processes running, and the kill attempt can remove the tracking pidfile: do not retry blindly. There is no automatic retry or polling. Use run get to inspect the recorded outcome.

Exec

moor exec api --json -- 'printf hello' prints one JSON document with exitCode, stdout, and stderr. The CLI exits with the container command's exit code, including nonzero results. Request and argument failures instead print a JSON error to stderr and exit 1.

Put Moor options before --; everything after it belongs to the container command. Arguments are joined with spaces into a shell command, not passed as an argv array. Quote shell expressions to prevent your local shell from expanding them. Do not put secrets in command arguments.

Existing human calls such as moor exec api ls -la still work and print the container's stdout and stderr directly. One compatibility exception: a standalone --json token anywhere without a separator is rejected to avoid confusing Moor output options with remote options. For a remote JSON option, use moor exec api -- gh pr list --json state; Moor still prints human-mode output. This command runs synchronously; asynchronous exec is not included in this slice.

Restart

moor restart api --json returns the API response as one JSON document. Errors go to stderr with a non-zero exit code. Unknown options and extra arguments are rejected. Without --json, the existing progress messages are preserved.

Stop

moor stop api --json stops the project's container without deleting its configuration or volumes. Success prints the API response as one JSON document; human mode prints a confirmation. Request failures go to stderr and exit 1. Missing projects, unknown options, and extra arguments fail without a stop request.

The API treats already-stopped or absent containers as success. A Docker failure returns an error without marking the project stopped; a failed request does not prove the container's current state. Use project inspection to check its live state.

Rebuild

moor rebuild api --json emits one {event,data} JSON object per line as the API builds and starts the project. Use --no-cache to bypass the build cache. Human mode retains progress and log output.

Failures before streaming emit one JSON error document on stderr. Stream failures emit JSONL error events on stdout and exit nonzero. A stream ending without a completion or error event also fails. Unknown options and extra arguments are rejected.

Environment variables

moor env delete api OLD_KEY OTHER_KEY --json removes matching keys in one server operation. The response lists deleted_keys, missing_keys, and restarted. Missing keys are a no-op; stopped projects are not started. Running projects restart only after an actual deletion. Drain rejects restart-requiring deletion before changing values.

If restart fails after deletion, the command exits nonzero and reports the deleted keys with env_updated: true; it does not roll the deletion back. Keys are trimmed and deduplicated before matching, consistent with environment writes. The legacy single-key API deletion remains configuration-only.

List a project's environment values as one JSON document for agents:

moor env list api --json

Without --json, the command preserves the existing KEY=VALUE output. Unknown options and extra arguments are rejected.

The existing human syntax remains available:

moor env set api PORT=3000

For agents, pass a JSON object through a file or stdin so values do not appear in command arguments:

printf '%s' '{"DATABASE_URL":"..."}' | moor env set api --env-file - --json

The command merges the supplied keys and restarts the project only when it is running. JSON success is one document containing updated_keys and restarted. Failures are written as JSON to stderr with a non-zero exit status; if values were saved but restart failed, the error retains env_updated and updated_keys.

moor project deploy

Deploy from GitHub or a registry image through the same API operation used by MCP:

moor project deploy api --github-url https://github.com/example/api
moor project deploy web --docker-image nginx:alpine --domain web.example.com --domain-port 80
moor project deploy private --github-url https://github.com/example/private --source-credential-id 42
moor project deploy db --docker-image postgres:17 --volume data:/var/lib/postgresql/data

Repeat --volume <name>:<target> to add named persistent volumes. Targets are absolute container paths, not host paths. Mount modes such as :ro and colons in targets are not supported by this flag. With --update-existing, existing mounts are retained; an identical name and target is accepted, but changing a mount's target is rejected. Omitting --volume does not remove mounts. The server validates names, paths, and conflicts.

Pass --update-existing to update a project with the same name, or --no-run to save its configuration without rebuilding or starting it. Environment values are read from a JSON object so secrets do not appear in the command line:

printf '%s' '{"DATABASE_URL":"..."}' | \
  moor project deploy api --github-url https://github.com/example/api --env-file -

Set resource caps with --memory-limit-mb 256 --cpus 0.5. Memory uses integer MB and allows no extra swap; CPU counts may be fractional. The server enforces minimums (6 MB and 0.001 CPUs) and host capacity. Pass unlimited to either option to clear that cap; zero is not a clearing value. Omitted limits remain unchanged with --update-existing. With --no-run, new limits take effect on the next container recreation, such as a restart.

Use --files files.json to read a JSON array of injected files, or --files - for stdin:

[
  { "path": "/etc/app/config.json", "content": "{\"debug\":false}", "mode": "0644" },
  { "path": "/etc/app/token", "env_ref": "TOKEN", "mode": "0600" }
]

Each entry supplies exactly one of content or env_ref; the server validates paths and modes. Referenced env keys must exist when the container starts, either already stored or supplied with --env-file in this deploy. File contents stay out of command-line arguments. Only one of --files and --env-file can read stdin.

With --update-existing, entries replace file configuration at matching paths; omitted files are retained. --no-run saves configuration without injecting files until the next container creation, such as a restart.

Agents should pass --json. Each streamed API event is emitted as one JSON object per line:

{"event":"deploy","data":{"action":"created","project_id":1,"project_name":"api","env_keys":[],"run":true,"env_changes_pending_restart":false}}
{"event":"done","data":"Container started"}

Failures return a non-zero exit status. Pre-stream errors are written to stderr and, in JSON mode, preserve the API's structured fields plus the HTTP status. Errors received after streaming begins remain ordered with the other JSONL events on stdout.

Worker command and entrypoint

Use JSON argv arrays to override the image's command or entrypoint. This example assumes your image contains Node and /app/worker.js; replace the image reference with your own:

moor project deploy worker --docker-image ghcr.io/acme/worker:latest --entrypoint '["node"]' --command '["/app/worker.js"]' --json
moor project deploy worker --update-existing --command null --entrypoint null --json

Arguments are passed as array elements, not split or expanded by the CLI. Quote the JSON to prevent your local shell from expanding it. Use environment variables or injected files for secrets, not command arguments. These options configure container startup; they do not execute a command inside an existing container.

Omitted options preserve existing overrides on updates. null restores image defaults; the server treats [] the same way, not as “run nothing.” The API validates array entries. Overrides take effect on container recreation; --no-run saves them until a later restart or rebuild. --json controls output independently of the JSON input arrays.

Asynchronous shell jobs

moor job start worker --file job.json --json
moor job status 12 --json
moor job stop 12 --json

Start reads {"command":"node /app/task.js","timeout_ms":3600000} from a file or stdin (--file -). The API validates the shell command and timeout, which defaults to 24 hours and ranges from 60,000 to 86,400,000 milliseconds. Keep secrets in environment variables or injected files rather than command text, which the server stores and logs.

Start returns run_id when accepted, without waiting for completion. Use that ID only with job status/stop: async jobs have a separate ID space from build/cron run records. Existing moor exec remains the synchronous command. Status returns live output tails while running, final output afterward, byte totals, and execution state. Empty initial output is normal; status exit 0 means retrieval succeeded even if the job failed.

Stop attempts cancellation once. Inspect ok, state, live_remaining, and message: an error can mean processes are still running. Do not retry blindly; the server cannot reliably repeat a failed kill attempt. The CLI does not poll or retry start/stop. An HTTP-success stop outcome is printed to stdout and exits 1 if ok is false; HTTP request failures go to stderr and exit 1. A successful start or status request exits 0, not the command's eventual exit code. Human output is indented JSON; --json emits one compact document.

Scheduled jobs

moor cron list worker --json
moor cron create worker --file job.json --json
moor cron update 12 --file patch.json --json
moor cron run 12 --json

Create reads a JSON object with name, schedule, and command; timeout_ms and enabled are optional. For example, job.json can contain:

{ "name": "daily", "schedule": "0 3 * * *", "command": "node /app/job.js", "enabled": false }

Jobs are enabled by default; enabled: false stages a disabled job without an active scheduling window. Update accepts a patch of the same fields, so {"enabled":false} disables an existing job. Both commands accept stdin with --file -; keep shell commands in the JSON input rather than expanding them in your local shell. The container interprets command through sh -c when the job runs.

Schedules use five numeric cron fields in the API process's local timezone, with Sunday numbered 0. The API validates schedule and timeout values. Creating or updating configuration does not manually trigger a run, but an enabled job is eligible at its scheduled time. This requires a running project container.

cron run triggers one execution immediately, even for a disabled schedule. It returns {ok:true,run_id} without waiting; exit 0 means acceptance, not workload success. Inspect the returned ID with moor run get <run_id> --json, not job status. No automatic retries or polling occur. A failed request or unusable response may leave the outcome uncertain; do not blindly repeat a trigger.

--json returns one document; human mode prints indented JSON. Exit 0 reports a successful request, not a successful job execution. Inspect results with moor run list <project> --json and moor run get <id> --json. Deletion is not exposed by these commands.

Private-image registry credentials

Store credentials from a protected JSON file, or pipe the object through stdin with --file -. Never put secrets in command-line arguments.

moor credential registry list --json
moor credential registry create --file registry.json --json
moor credential registry update --registry-credential-id 9 --file rotation.json --json

Create accepts hostname, username, and secret. Update accepts only username and/or secret; omitted fields stay unchanged. The API validates fields and returns metadata, not the stored secret. Hostnames cannot be patched, and deletion is not exposed in the CLI.

Use a bare hostname such as ghcr.io or registry.example.com:5000, with no scheme or path. For Docker Hub images such as user/image, use docker.io. The server selects credentials automatically by the image's registry hostname; there is no registry credential ID to pass when deploying.

Create and update only store credentials: they do not test authentication or pull an image. There is no registry check command. Authentication is exercised on the next image pull. When diagnosing a failed pull, the API server's logs report auth=anonymous if no matching credential was found, or auth=host=<hostname> when one was selected. These credentials cover docker_image pulls, not private FROM images inside Dockerfile builds.

Private-source credentials

Use moor credential source list --json to discover stored credential IDs. Create one from a protected JSON file, or pipe the object through stdin with --file -; do not put its secret in command-line arguments.

moor credential source create --file credential.json --json
moor credential source check --github-url https://github.com/acme/app --source-credential-id 8 --json
moor project deploy app --github-url https://github.com/acme/app --source-credential-id 8 --json

The creation object has hostname, label, username, secret, and optional expires_at fields. Responses contain metadata, not the stored secret. The server validates credential fields. Deletion is not exposed in the CLI.

To rotate a secret or edit metadata, put only the changed fields in a protected JSON file (or use stdin with --file -):

moor credential source update --source-credential-id 8 --file rotation.json --json
moor credential source check --github-url https://github.com/acme/app --source-credential-id 8 --json

The update object accepts username, secret, label, and expires_at. Omitted fields stay unchanged; expires_at: null clears the expiry. Hostname and state cannot be patched. Update makes one storage request: it does not verify access, restart projects, or restore a failed credential to active. Run an explicit check afterward; a successful check restores active state.

check contacts the repository and may update the credential's stored state and last-check result. It is not a read-only operation. Add --branch to check a specific branch. Without an explicit ID, a successful check may return auto_selected_credential_id; pass that ID explicitly when deploying. Deploy does not automatically select a credential. If selection is ambiguous, JSON stderr preserves the server's candidates list and exits 1.

These commands emit one JSON document with --json. Failures use stderr and exit 1. Human list/create output shows ID, hostname, label, and state; human check output shows the response as formatted JSON.

Server update inspection

moor server update status --json
moor server update audit --limit 20 --json

These read-only commands make one request without polling, retries, drain changes, or starting an update. Status reports current and available versions, active work, backup recency, safe_to_update, and unsafe_reasons. Unknown registry comparisons remain null. The server's recommended_command is informational; the CLI does not execute it.

Audit returns {rows: [...]} with recent update attempts (default 20; --limit accepts integers 1–200). Inspect each row's state and error fields. crashed means an old in-progress record had no completion marker, not necessarily an observed process crash. Full records are downloaded and displayed.

Exit 0 means retrieval succeeded, including unsafe readiness or failed updates in audit history. Request or invalid-response failures use stderr and exit 1. Success prints one JSON document with --json, or formatted JSON otherwise. These commands do not apply updates.

Request a server update

moor server update apply --json
moor server update apply --target-digest 'sha256:<64-lowercase-hex-characters>' --json

Apply makes one request to replace the server, using the registry's latest digest unless one is supplied. The server performs preflight, drain, a database backup, and launch. The CLI exposes no bypass flags and does not poll or retry.

Exit 0 and { "audit_id": N } mean HTTP 202 acceptance, not completion. The server may disconnect. After reconnecting, use moor server update audit --json and inspect that audit ID's state and errors. Human mode prints formatted JSON.

Failures use stderr and exit 1. Transport failures or unusable replies leave the outcome unverified; inspect audit before retrying. HTTP errors can follow side effects such as an audit record or backup and do not imply rollback. Structured API errors are retained in error_details, alongside the CLI's string error and HTTP status.

Guarded server cleanup

moor server cleanup plan --json > cleanup-plan.json
# Review the file and keep only candidates you intend to remove.
moor server cleanup execute --file cleanup-plan.json --json

Plan inspects build cache and dangling images without deleting anything. Execute requires a JSON object with a nonempty candidates array; you can use the saved plan or an edited selection. --file - reads stdin. The server validates candidate categories and identifiers and ignores descriptive metadata. The file is not an immutable or authorized plan token.

Execution is irreversible. Dangling images are rechecked by ID without force or parent-image pruning. A build_cache candidate prunes currently unused cache, not a fixed set or a byte cap from the plan. These commands do not remove volumes or containers. No automatic planning, retries, or polling occurs.

JSON results go to stdout (formatted JSON without --json). Execute exits 1 if any candidate reports an error, preserving the full partial-result document and audit ID on stdout. Request and invalid-response errors go to stderr and exit 1. A failed request can occur after partial deletion, including an audit-write failure: inspect the server before retrying. Re-executing a saved file can report images as no longer dangling; it does not prove the first execution failed.

Server database backup

moor server backup --json creates a SQLite snapshot next to the database on the server. The server prunes older snapshots, keeping the seven most recent. This is not a volume or full-server backup, an offsite copy, or a download to your computer.

The command makes one request without retries, drain changes, or updates. Success returns path (on the server), sizeBytes, and durationMs as one JSON document; without --json, it prints formatted JSON. Errors use stderr and exit 1. A lost or invalid response does not prove that no snapshot was created: inspect the server before retrying, because another backup also applies retention.

Server drain

moor server drain status --json
moor server drain enable --reason "maintenance" --ttl-minutes 30 --json
moor server drain disable --json

Drain refuses new work without killing work already running. Status returns the server's state and active_work counts; enable and disable return state. These commands make one request and do not wait, poll, or retry. Reads remain available during drain.

TTL must be finite and positive. Omit it for the server's 30-minute default; the server clamps supplied values to 0.05–10080 minutes. Enabling again replaces the reason and resets expiry from now. Disabling does not restart or resume work. Scheduled cron executions during drain are recorded as skipped.

Success emits one JSON document with --json, or formatted JSON for humans. Request failures use stderr and exit 1. The updater-specific clear_after_version option is not exposed.

moor mcp config

Generates a ready-to-paste config snippet for an MCP-compatible AI client. Removes the "open a doc, copy a JSON block, fill in the blanks" step from MCP setup.

moor mcp config --client claude        # or --client claude-code (alias)
moor mcp config --client codex

Output is JSON for claude / claude-code and TOML for codex. Prints to stdout - redirect or paste into ~/.claude.json or ~/.codex/config.toml. Optional flags: --url <url> (default http://127.0.0.1:8080), --api-key <key> (else read from MOOR_API_KEY env, then cwd .env, then a placeholder).

See @moor-sh/mcp for the MCP server itself.

Links

License

MIT.