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

@dinesh-gamage/pulse

v0.10.0

Published

PULSE — Persistent Unified Layer for Software Engineering. Shared context and control for AI coding agents.

Readme

PULSE

Persistent Unified Layer for Software Engineering
Shared context and control for AI coding agents.

Pulse is a local CLI that maintains engineering knowledge across repositories and supplies relevant context to coding agents. The current MVP integrates with Claude Code. Desktop work follows the completed CLI product.

Run from this repository

Requires Node.js 18.20+ and Git. Claude Code is needed only for runtime integration.

npm install
npm run build
node bin/pulse.mjs --help

For the examples below, make the executable available as pulse. You can use npm link, or define a shell alias to node /absolute/path/to/pulse/bin/pulse.mjs. Development commands also work through npm run dev -- <command>.

The CLI uses @dinesh-gamage/cli-kit for tables, colors, progress feedback, and logging, with Commander for argument parsing. Use --json for machine-readable output. Logs and progress go to stderr; hooks and MCP emit only their protocol on stdout.

New to it? Using Pulse is the whole workflow in order, in plain language.

Register your software system

pulse init
pulse project create acme --name "Acme Platform"
pulse repo add ~/code/acme/backend --project acme --name backend --purpose "HTTP API"
pulse repo add ~/code/acme/auth --project acme --name auth --purpose "Authentication and sessions"
pulse repo add ~/code/acme/frontend --project acme --name frontend --purpose "Browser application"
pulse component add token-service --project acme --repo auth --purpose "Token generation and refresh"
pulse relationship add repo:backend calls component:token-service --project acme
pulse repo list --project acme

Repositories stay where they are. Register their Git roots; nested or overlapping registrations are rejected. Once inside a registered repository, Pulse infers its project and repository. Explicit --project and --repo flags override that inference.

Project creation accepts --directory /path/to/canonical-context for knowledge you want to version yourself. Existing Pulse manifests can be registered through the same command, then their repository IDs rebound with repo add or repo edit --path. Pulse never commits these files.

Capture durable knowledge

pulse knowledge add --project acme --scope project --type rule --title "API compatibility" \
  --body "All API changes must remain backward compatible."
pulse knowledge add --project acme --repo auth --type architecture \
  --title "Token refresh" --file ./auth-architecture.md
pulse knowledge list --project acme
pulse knowledge show <id>
pulse knowledge edit <id>

Supported types: fact, rule, decision, architecture, finding, and diagram. A diagram is a description and one mermaid block. Findings begin as provisional. Other manually authored records default to confirmed; use --status to choose explicitly. knowledge edit <id> --status confirmed promotes a reviewed finding.

Without --body or --file, add/edit opens $VISUAL or $EDITOR, falling back to vi. Editor commands require an interactive terminal. knowledge import <file> --type architecture --title "..." imports Markdown as a new record with provenance. A repository flag scopes knowledge to that repository; --scope project creates project-wide knowledge even when your terminal is inside a repository.

Canonical knowledge is Markdown with YAML frontmatter. External edits are incorporated by the next pulse index. Agent MCP tools are read-only in this MVP; saving discoveries is a CLI operation.

Index and inspect context

pulse index --project acme
pulse context search "token refresh" --project acme
pulse context resolve "Fix the login timeout" --project acme --repo backend --explain
pulse context get <id> --project acme

The index includes documentation, selected configuration, source chunks, and declaration names extracted per language (JavaScript/TypeScript, Python, Go, Rust, C#, Java, Kotlin, Ruby, PHP, C/C++, Elixir, SQL, Terraform, shell and more, with a keyword fallback elsewhere). It excludes ignored files, common secret files, generated/dependency directories, binaries, files over 256 KiB, and external symlinks. Add patterns to a repository's .pulseignore, with pulse settings add exclusions <pattern> for one project, or with pulse config set exclusions <patterns...> for every project. Language detection counts tracked files rather than reading one ecosystem's manifest, so a repository with no manifest is still classified.

Indexing refreshes changed/deleted chunks and preserves unchanged embeddings. Run it after switching branches or editing relevant source files. Changed source content is flagged during retrieval and omitted from automatic task context until refreshed. There is no background file watcher yet.

Context packets carry relevant knowledge and source pointers. Rules are not among them — see below. --explain reports selection reasons, omissions, index timestamps, and estimated cost. Default prompt ceiling: 1,000 estimated tokens, enforced as 3,000 UTF-8 bytes; change it with pulse config set contextTokens <n>, override it per project with pulse settings set contextTokens <n>, or use context resolve --budget. These counts are estimates, not provider tokenizer measurements.

Rules are retrieved, never injected. Re-sending them on every prompt spent 82% of a measured packet on bytes the conversation already held, so packets and session maps now carry the obligation and the count, and the agent calls context_rules — narrowed by tag — before it plans or edits. Rules provide guidance; Pulse does not enforce source-edit policies in this MVP.

At session start Pulse delivers a project map instead of a bare identity line: every repository with its language, the purpose of the ones marked mandatory, the confirmed relationships between them, and the rule and index state. This is the context you would otherwise retype at the start of every session. It is budgeted separately from prompt packets by sessionTokens (global default 1,000 estimated tokens, per-project override under settings.sessionTokens). Set it to 0 to fall back to the identity line.

A repository's purpose reaches the model one of two ways. Marked --mandatory it is stated in full in every map and is never trimmed. Otherwise the map lists the repository by name, and its purpose arrives on a prompt that names one of its --tags. On a project of twenty repositories, most purposes are never relevant to the prompt at hand, and sending them all forced every one of them down to a truncated clause.

The map degrades by shortening and then dropping non-mandatory purposes, then collapsing relationships to a pointer. If the roster plus the mandatory purposes still do not fit, it is sent over budget rather than losing repositories, and the overshoot is recorded in the session log.

Tune one project without affecting the others

Anything that differs between projects belongs in that project's manifest, not in global configuration. All fields are optional:

pulse settings                                      # current values and what they resolve to
pulse settings add exclusions "build/generated/"    # gitignore syntax, this project only
pulse settings add stopwords widget                 # extends the built-in query stopwords
pulse settings add extensions .liquid               # extra indexable file types
pulse settings add deprioritise "**/vendor-ui/**"   # searchable, ranked below first-party code
pulse settings set contextTokens 1500               # overrides the global default
pulse settings set sessionTokens 1500               # overrides the session-start map budget
pulse settings set transcript full                  # off | basic | full
pulse settings unset contextTokens                  # fall back to the global default

Every value is validated on write, so the manifest cannot be left invalid. pulse config does the same for the global defaults, and pulse config price <model> sets the rates used for cost reporting. Nothing here requires editing a file by hand.

Built-in defaults are extended, never replaced. The global exclusions array stays for patterns that genuinely apply to every project you register.

Enable local semantic search

pulse semantic setup
pulse index --project acme
pulse semantic status

Setup explicitly downloads a pinned quantized Xenova/all-MiniLM-L6-v2 model. Inference then runs locally; normal retrieval never downloads weights or sends source text to an embedding service. The Transformers.js dependency is optional so lexical operation remains available if its native runtime cannot be installed.

CLI search and MCP use hybrid retrieval when the model and indexed vectors are available. Hooks use lexical retrieval to keep fresh-process latency bounded; they never initialize the model. --no-semantic selects lexical-only indexing/search. If semantic retrieval fails, search reports a warning and returns lexical results.

Connect Claude Code

cd ~/code/acme/backend
pulse integration install claude --dry-run
pulse integration install claude
pulse doctor
claude
# Or: pulse run claude -- --model <model>

Installation merges three hooks into .claude/settings.local.json: SessionStart, UserPromptSubmit, and SessionEnd. The MCP server is registered at local scope in ~/.claude.json, under the repository path; CLAUDE_CONFIG_DIR is respected. Existing hooks, unrelated servers, and permissions are preserved. Setup does not grant workspace trust or bypass runtime permissions.

Repeat installation safely. pulse integration uninstall claude removes Pulse-owned entries while retaining other configuration. If the MCP entry was independently changed, Pulse asks you to resolve the conflict instead of overwriting it. Configuration backups and installation records are kept in Pulse's home; an interrupted installation is reported by doctor and can be retried.

After setup, ordinary claude sessions receive context. Session start/recovery supplies identity; prompt submission supplies bounded relevant context. Nothing is injected twice in a session — knowledge, repository purposes and relationships all pass through the same delivery ledger — and everything becomes eligible again after session restart, clear, or compaction. Applicable rules are counted and named, and retrieved with context_rules. Hook failures time out and allow the coding session to continue.

Agent tools:

| Tool | Purpose | | --- | --- | | context_search | Search the current project's indexed context | | context_get | Retrieve a source by stable ID, with pagination | | context_relationships | Inspect confirmed component/repository relationships | | context_rules | Retrieve applicable confirmed rules in full, narrowed by tag |

Runtime references: Claude hook lifecycle, Claude MCP configuration scopes.

Scripting Pulse

Every command takes --json. The contract is small and worth stating exactly, because other tools depend on it.

One document on stdout, per process. No streaming, no envelope around a successful result — the command's value is the payload. pulse project list --json returns the array it always did.

A failure is a document too. It is the only output with an ok key:

{"ok": false, "error": {"code": "unknown_project", "message": "Unknown project \"x\". Use pulse project list.", "details": null}}

Codes: invalid_input (with details carrying the failing fields), unknown_project, no_project, database_newer, busy, live_sessions, usage, error. The human-readable line still goes to stderr, so a terminal session is unchanged.

Parse stdout first; the exit code is advisory. doctor exits 1 with a complete, valid report when it finds issues, and policy test exits 2 on a deny. Neither is a failure. If stdout parses, the command produced a result.

Progress goes to stderr. Under --json, long commands emit one JSON object per line as they work, so a caller is not blind while an index runs:

{"v":1,"at":"…","event":"progress","command":"Indexing acme","step":"indexing backend","done":2,"total":4}

Any stderr line that parses as JSON with "event":"progress" is progress; everything else is diagnostics.

Start with pulse overview --json. One call returning the whole installation: home, config, every project with its repositories, their local paths and index state, components, relationships, resolved effective settings, observed sessions, and logging and embedding state. It deliberately skips the runtime version check and the database checksum that make doctor slow, so it answers in about 200 milliseconds. Use doctor when you want health, where that cost belongs.

Reading a session log. pulse transcript show <session> --resolve --json adds a documents map turning every document id in the log into a title, repository and kind, in one query. An id whose document has since been re-indexed comes back as {"missing": true} rather than failing the whole read.

Indexing refuses to run under a live coding session. The hook waits only 100 ms for the database; indexing holds a write lock for much longer, so an index started mid-session would make that session silently lose its context. pulse index reports code live_sessions and names them. --force overrides.

Storage and maintenance

By default, Pulse stores data in ~/.pulse; set PULSE_HOME for an isolated workspace.

config.json                  Global defaults: context budget, exclusions, logging, prices
state.sqlite                 Registration, index, embeddings, sessions, delivery state
logs/<project>/<session>.jsonl  Optional per-session log (off by default)
projects/<id>/project.yaml   Portable project/repository/component metadata and per-project settings
projects/<id>/relationships.yaml
projects/<id>/layout.yaml    Where the relationship graph puts things
projects/<id>/knowledge/*.md Durable knowledge
cache/                       Downloaded embedding model
integrations/                Configuration ownership and recovery records
backups/                     Original runtime configuration backups

project remove unregisters a project and retains canonical files. repo remove removes its association and indexed source, preserving the source tree; dependent components, relationships, and scoped knowledge must be removed or reassigned first. knowledge remove deletes that knowledge file. Full database deletion also loses local bindings and session state; it is not an index-reset command.

Pulse records no prompts and no transcripts by default. Session logging is opt-in: pulse config set transcript basic|full, or per project with pulse settings set transcript. basic records what was retrieved and why — document IDs, delivery mode, omission reasons, counts and timings — and nothing derived from the words of your prompt. full additionally records each prompt and the injected packet verbatim, so a session can be read back exactly as the model received it. Logs are plain JSONL under ~/.pulse/logs/, pruned after transcriptDays (default 30), and never leave the machine. pulse status shows the active level at a glance.

Logging never changes what is injected. The packet is byte-identical with it on or off, and a test enforces that.

pulse transcript list                      # logged sessions, what was injected, what they billed
pulse transcript audit <session>           # what was injected, and what the model then did with it
pulse transcript show <session> --context  # the injected text, exactly as delivered
pulse transcript summary                   # injected context measured against actual usage
pulse transcript prune                     # apply the retention window now

Token usage is read from the coding runtime's own session file, on demand, never inside a hook — those files reach hundreds of megabytes. Dollar figures need rates you set with pulse config price <model> (the model id is matched by substring, rates are per million tokens); Pulse ships none of its own, because rates change. Any figure shown is a list-price estimate over per-request usage, not an invoice.

Sessions show last observed activity; sessions without a reliable end signal become stale/unknown rather than appearing permanently active.

Validation and current boundary

Experimental local rule checks are available with pulse run claude --policy <file>. They check package dependencies and task-specific write paths before edits. This opt-in mode blocks shell and unsupported tools; builds/tests run in a separate terminal. See policy hooks, editable examples, and trial results.

npm test
npm run check
npm run benchmark
# Optional, after downloading into an isolated validation home:
PULSE_HOME="$PWD/.pulse/validation" node bin/pulse.mjs semantic setup
npm run benchmark -- --semantic
node --import tsx scripts/live-smoke.ts

Tests cover persistence, scoping, exclusions, invalidation, packet budgets, recovery, configuration preservation, MCP, and concurrent writers. The 20-prompt synthetic benchmark reports retrieval recall/precision and hook latency in eval/results/synthetic/benchmark-*.json. The live smoke uses the installed Claude runtime's initialization lifecycle without making a provider request.

See current state for measured results and remaining real-project validation. Synthetic relevance and latency results do not establish token savings on real work. Agents that own repositories, with per-stage models, are in 0.9.0 (see Using Pulse). Task orchestration beyond one lead, file claims and other runtimes are later phases in the MVP plan.