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

@ideaspaces/cli

v0.2.4

Published

IdeaSpaces CLI — capture durable agent knowledge from the command line

Readme

IdeaSpaces CLI

The command line for folders that agents inhabit.

An ideaspace is a folder of Markdown under git that holds your knowledge and how to work with it. Open an agent inside it and that's who you're talking to. The protocol defines the shape.

Most people use the shape through a plugin for Claude Code, Codex, or Cowork, or Pi. The plugins bundle this CLI. Install it yourself for scripts, automation, and other harnesses.

A space is a real git repository on your disk. Nothing leaves your machine until you publish or push.

Install

npm install -g @ideaspaces/cli

Node 20+ and git. ideaspaces doctor checks both.

Five minutes

ideaspaces create my-space --yes       # a folder with _agent/ in it, committed
cd my-space
ideaspaces navigate .                  # what is here, what changed since last time
ideaspaces look . --depth children       # one target at a chosen rung
ideaspaces write decisions/pricing.md --name "Pricing" --content "# Pricing

Per seat, billed yearly."
ideaspaces commit -m "Capture the pricing decision" decisions/pricing.md

create --home <dir> --yes makes a dedicated Home with an Agreement and an empty home.map.md; it refuses code repos and preserves an existing home.map.md. map <dir> opens that curated file even before it has roots, and navigate <dir> names it. Without a Map note (*.map.md or a README.md with a map block), map derives the local tree as before. create writes one contract file, _agent/agreement.md, under the knowledge kind — or the agent kind with --agent — and references that kind's public Agreement Space in its frontmatter (agreement: knowledge:repo:…). Its sections are prompts to replace in conversation; navigate --json reports the reference as agreementReference. Older Spaces on _agent/foundation.md still load; navigate prefers Agreement when both exist, and --contract foundation reads the older frame explicitly. create --foundation writes the older shape for one more release. Ambient navigation renders the protocol-owned stable head, then local working-set/catalog handles, then the volatile tail; activity belongs only to the tail. look <path> --depth name|summary|surface|children|full reads exactly one local Note or directory beneath a reference-only frame; the existing navigate --focus and inspect readers remain available during convergence. create --agent makes a folder that is an agent. Inside a code repo, create --yes keeps _agent/ local to your machine; --shared commits it.

Take one home, hand one over

git clone https://github.com/IdeaSpaces-xyz/hn-reader && cd hn-reader    # any git host
ideaspaces fork https://ideaspaces.xyz/repos/<repo-id> ./theirs         # public space, no account
ideaspaces update --yes                                                   # later: pull in source changes that don't conflict
ideaspaces login
ideaspaces publish --yes                                     # host it, private to you
ideaspaces share person [email protected] --grade explore
ideaspaces share visibility public --yes                     # anyone can view and fork
ideaspaces push
ideaspaces pull

Anything that leaves your machine prints its plan and runs only with --yes.

share stays recipient-shaped: person, team, list, remove, resend, history, and visibility. It does not expose repository memberships, internal Grant records, or organization administration.

Commands

ideaspaces <command> --help for usage. --json on reads and local writes.

| Job | Commands | |---|---| | Look around | navigate, look, status, inspect, ls, search, skills, map, times | | Write things down | write, commit, change, node | | Start, bring home | create, get (clone, fork, link), clones, forget | | Share and sync | login, status account (whoami), publish, share, push, integrate (pull, update), sync, repos, catalog | | Talk | conversation, conversations, threads (inbox legacy alias for one release), spaces, agents, agent list | | Run a local agent | agent run (--runtime=pi or --runtime=claude, --model, pinned local --thread), pi-status, pi-login, pi-logout, pi-models, claude-status, claude-models, conversation send --local (--runtime=pi, the default, or --runtime=claude for your own Claude Code), conversation compact --local | | Housekeeping | status doctor (doctor), credential, power logout |

What the CLI promises

  • write touches only the file you name and keeps frontmatter you did not set. --map JSON|YAML|FILE writes a validated Map block to a Note. Pass the returned sha as --if-match for a safe second write; --force overwrites.
  • commit commits only the paths you name. Other staged work, yours or a teammate's, is left alone. The author is git's user.name and user.email, never a hidden credential.
  • A space has one id. Agreement is the preferred contract source; until it declares identity, a valid Foundation identity remains the compatibility evidence for that same Space. create mints identity into the Agreement it writes (or into Foundation under --foundation), publish adopts it, and conflicting declarations fail closed. clone keeps identity; fork remints it in every projected root entrypoint. Nothing rekeys a space silently.
  • get shows before it does. Given a Space URL it says what clone would do (same identity, fetch/push truth, full history) and what fork would do (new identity, no source history), and mutates nothing until --yes --as clone|fork names one; given a folder it offers link. It offers only a mode your account can reach; otherwise it says which access (Viewer, Allow copying, Editor) would open one. The choice between clone and fork is yours, never guessed. clone, fork, and link remain the explicit verbs.
  • integrate follows what the checkout is. A clone integrates its upstream; an unpublished fork integrates its maintained source; a published fork with source lineage defaults to its own remote and takes --from source for the other. Plan-first: --yes applies. pull and update remain as the underlying verbs.
  • status is the tail, and only the tail. It renders local State (branch, upstream, working tree, captures awaiting commit), the repo catalog when you pass --workspace, and what moved since last session — the same composition an agent runtime appends after its cached head, so the two never disagree. Nothing navigate already showed in the head. Login state and installation health are separate sections: status account and status doctor (whoami and doctor still work for one release).
  • look deepens one target without adopting its terms. The applicable Agreement or Foundation is reference context only. JSON adds a portable map only for a clean, pinned, identified root; dirty, unborn, ignored, local-only, or invalid roots remain honest local projections.
  • Read through a Map, not a folder. look @notes//ideas/first.md --map space.map.md reads a Map member by address — @<root name>//<position>, @<root_node_id>//<position>, or //<position> for your own root — with no filesystem path, from any working directory. navigate @notes//ideas --map space.map.md focuses on a member directory the same way. A Space's Map reads each root's checkout at HEAD and says when it has drifted from the pin; a Thread's Map (one under _threads/) reads the pin; --at pin|head overrides either. The bytes come from the commit, never the working tree, and the result names the root and carries its identity form, so what you keep resolves without the Map. A root with no local checkout fails with its name and the reason. look <path> --pin <sha> reads your own checkout at an authored commit.
  • A launch Map is read, not just listed. agent run and conversation send with --map <note> start the session with each member read at its declared depth, within 12,000 characters: over that, the last member is read at a lower depth first, then the one before it, and nothing is cut mid-member. The same Map at the same commits gives the same bytes. The launched session gets the Map as IDEASPACES_MAP, so an address read there needs no --map. It is a convenience, not a boundary: it grants and restricts nothing.
  • agent run <pov> --message <text> launches from an explicit local Agreement POV path under Pi or Claude and streams Keeper events. It passes that POV's own Agreement as child orientation; --model, --pi-thinking, and supported Claude --claude-effort are runtime choices, not task modes. Pi child runs require explicit --ext <paths> (and --skill <dirs> for selected package skills). They disable discovery of both Pi extensions and skills; only the forwarded paths load, not additional user or target-project skills. Relative paths resolve from the selected POV, not the caller's cwd. Installed packages or ambient IDEASPACES_PI_EXTENSIONS do not authorize a child launch. Missing selection refuses before spawning. A supplied --conversation <id> must already have a nonempty transcript under that exact POV and runtime; omit it for the first turn. Pi trust now defaults to saved on agent run; older scripts that relied on implicit project approval must explicitly pass --pi-trust explicit after a person approves that target. Direct conversation send --local retains its legacy explicit default for Desktop callers; pass --pi-trust saved there when appropriate. --read-only restricts Claude to Read/Grep/Glob without MCP tools (not a filesystem sandbox); --permission-mode bypassPermissions requires opting out of read-only. agent run bounds messages to 8 KiB and the combined contract/Thread orientation to 16 KiB before child spawn rather than silently truncating a contract.
  • agent run --thread <path> --thread-map <note> --thread-member <ordinal> launches from a selected authored Map member (zero-based ordinal), never from the Thread path alone or HEAD. --thread-map names a regular authored Map file (not inline YAML), and --thread-member is its zero-based member index. The member must name a post in that local Thread at an available commit; the Thread Agreement and selected post summary are read at the pin, separate from the user's message. A successful run appends its closing response as a snapshot under the POV Agreement's name, citing that pinned member in its Map; a failed run writes nothing. The post id and path appear in turn_complete.result.thread_snapshot in the Keeper JSONL stream (and on stderr in human mode); a failed append emits a terminal error instead of turn_complete. Hosted x_… Threads are not supported here.
  • threads is one family for local files and hosted x_ ids. threads list shows local and hosted rows together when logged in; threads open <slug|path> reads a local Thread at name, summary or full depth, while threads read <x_…>, send, reply, and expand keep the hosted wire unchanged. threads new, post, close (a closure post), and render work without a login. Posts are exclusive-create Markdown; commit and push their exact paths through the repo's usual Git flow for a second machine to see them. A successful local agent is_threads post is harvested from its returned file path as a write; list, open, close, and failed posts are not. --reply-to fills the ancestor chain, --map accepts a validated authored Map, and render derives the timeline without overwriting the curated README. open --new uses a private per-thread cursor; only --ack moves it. Same-Space open --pin <40-hex-sha> --position _threads/<thread>/<post>.md remains a low-level pinned read; an unavailable commit never falls back to HEAD.
  • Select a pinned local Thread across Spaces. Use open <slug> --map <file> --member <ordinal> to read only an authored pinned post, including one in another Space, without leaving the caller's Agreement; --depth full returns the pinned bytes, not the live Thread, and selected reads do not support live --new or --ack. A unique registered checkout resolves the Map root; for an unregistered or multiply checked-out Space, pass --checkout <absolute Space root> explicitly. A Map-selected read requires a verifiable root identity even when the Thread is in the caller's Space; that caller Space can serve as its own checkout without a registry entry, and same-Space paths still work once identity is established. Unlike earlier same-Space open --map --member, selected posts contains only the pinned post and thread.closed is not reported from the live tree; unselected same-Space open and explicit --pin/--position retain their live timeline. For an orphan _threads/ worktree, give the parent Space root as --checkout, not the orphan worktree directory. Symlinked _threads/ is refused; use the real orphan Git worktree instead. The checkout's root identity and any canonical origin or registry evidence must agree with the authored Map root.
  • Reply to the selected Thread. post <slug> --map <file> --member <ordinal> --reply-to <existing-pinned-post-id> --message <body> rechecks the live Thread before appending under the caller's Agent Agreement name; a newer post need not be the parent. A changed/closed Thread, missing parent, missing pin, symlink or arbitrary cross-Space path refuses. A changed Thread README or Agreement needs a re-authored Map at an updated commit. The late live-target recheck is best-effort against concurrent edits, not a cross-process lock; creation is exclusive. --map without --member on a same-Space post remains a citation, not target selection.
  • Private Threads stay off the default remote. For a private code repo, threads init mounts an orphan threads branch at ignored _threads/; threads push --remote <team-remote> explicitly names a non-origin destination on git.ideaspaces.xyz (or a local file remote for offline testing); unknown hosts, including GitHub Enterprise domains, are refused rather than guessed safe. Never publish that branch to GitHub. The inbox alias prints a deprecation notice for one release; the server's /inbox API stays unchanged.
  • search --json seals its hits as a Map under the same gate. Ranked results always come back; map_status is available with a parse-valid map only for a clean, pinned, identified root with every hit tracked at an unchanged HEAD, else projection_pending with map: null. Rank, score, and snippet stay in results; member order carries the rank.
  • map opens a curated *.map.md or a folder's README.md with a map block. Pass the file to select one lens explicitly; a folder prefers home.map.md, then a Map-bearing README.md, then another *.map.md. navigate <folder> names the chosen Map. map create team.map.md --name Team --summary 'Team work' creates an empty Space Map without overwriting an existing file. map add team.map.md thread:x_0123456789abcdef01234567 --depth summary adds an open address; map add team.map.md --root-node-id n_0123456789abcdef01234567 --sha <commit> --position . --depth summary adds a pinned root and position; use --root <index> for an existing root. map remove team.map.md <address> drops an unambiguous address; for an index, pass --if-match <file_sha> from map team.map.md --json, so a concurrent edit cannot change which member the index means. Roots remain (their indices are stable). Concurrent CLI edits serialize under <map-note>.lock; a busy/stale lock refuses after four seconds, and --if-match <sha> refuses a moved base. If a writer crashed, check no writer is running before removing its empty lock directory with rmdir <map-note>.lock; never delete a live lock. The lock and hidden temporary file are transient siblings: stage the exact Map file, not git add -A during an edit. YAML nodes and comments survive edits, but long scalar formatting may change; the source's LF/CRLF convention is kept. Removing a member keeps roots and their indices stable; a duplicate address must be removed by index. These file edits do not stage or commit. The reader shows each pinned root as pinned (checkout HEAD matches), moved (HEAD differs), or unresolved (no matching local checkout), and names other Maps in the same folder. Without one, it derives the local tree: JSON includes a portable map block only for a clean, exactly pinned root with stable identity that passes strict protocol validation. Dirty, unborn, unidentified, or invalid trees remain inspectable under projection without leaking their checkout path into a Map.
  • fork and update validate before touching your disk and never overwrite your work; conflicts are reported.
  • --json returns a status, the revision, and typed failure details. A partial write or commit exits non-zero.
  • conversation send --local --runtime=claude runs Claude Code — the copy you installed and signed in to, unmodified. Usage bills to your own Claude plan (or to your API key with --claude-auth=api-key — without it, a stray ANTHROPIC_API_KEY in your shell is kept away from the turn; provider routing you configured yourself, such as Bedrock or Vertex, stays in force); the CLI never sees your credentials and reads only the session transcripts Claude Code writes under ~/.claude/projects/. A turn streams the same events as a pi or hosted turn, so every client renders it the same way.

Which local runtime

Both stream the same transcript; they differ in whose agent runs and how it is paid for.

| | --runtime=pi (default) | --runtime=claude | |---|---|---| | What runs | pi, bundled with the desktop or pi on your PATH | the Claude Code you installed and signed in to | | Who pays | your API key for the provider you chose (pi-login) | your Claude plan, or your API key with --claude-auth=api-key | | Models | any provider pi supports | Anthropic | | Agent context | our extensions and skills, passed with --ext and --skill | whatever your Claude Code already carries — plugin, skills, _agent/, memory | | Where sessions live | <context>/.pi/sessions/, inside the space | ~/.claude/projects/, outside the space | | Reasoning in the transcript | shown | not shown — Claude Code redacts it when run headless | | Needs a Claude account | no | yes | | Is it ready? | pi-status | claude-status — asks the binary (claude --version, claude auth status); never reads ~/.claude | | Models | pi-models — any provider pi supports | claude-models — Anthropic (1M context for Opus/Sonnet/Fable, 200k for Haiku) | | Compaction | context skills (context_cleanup) | conversation compact --local and --autocompact (100k–1M tokens) |

Pick claude to continue a session you started in Claude Code; the same session id resumes it. Close it there first — one session should have one writer at a time. Pick pi for another provider, an API-key setup, or a machine without Claude Code.

Configuration

| Path | What | |---|---| | ~/.ideaspaces/credentials.json | API credentials | | ~/.ideaspaces/spaces.json | Known spaces and remotes | | ~/.ideaspaces/cursors/ | Private per-reader local Thread acknowledgements | | ~/.pi/agent/auth.json | Local-agent model credentials |

IS_API_KEY overrides stored credentials. IS_API_URL points at another host. IDEASPACES_PI_EXTENSIONS lists extension paths for direct conversation send --local (not agent run child authority). CLAUDE_CONFIG_DIR relocates the Claude Code sessions --runtime=claude reads, as it does for Claude Code itself.

Contributing

Every server operation the CLI performs is listed in contract/api-calls.json, generated from src/auth/api.ts by npm run api:inventory; a test fails when the source changes without it. npm run check:api -- <openapi.json> holds that inventory against a server's OpenAPI document and fails on any operation the server does not serve or marks deprecated. The document is an input — set IDEASPACES_OPENAPI=<path> to run the same check inside npm test.

License

MIT