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

@dreamtree-org/dhruthi

v0.3.9

Published

CLI for DigitalOcean Serverless Inference and Inference Router

Readme

dhruthi (dhruthi)

A multi-provider AI CLI that works instantly with free models — no key, no setup, no friction.

npm install -g @dreamtree-org/dhruthi
dhruthi                                    # starts instantly, uses free Pollinations model
dhruthi "Explain closures in TypeScript"   # one-shot

dhruthi started as a DigitalOcean inference CLI and is now a provider-agnostic tool that talks to OpenAI, Anthropic, Google Gemini, Groq, DeepSeek, Ollama, OpenRouter, and 25+ more — with automatic wire-protocol translation so --format json and sessions behave the same regardless of which provider answered.


Why dhruthi?

| | dhruthi | opencode | aider | Claude Code | |---|---|---|---|---| | Zero-config start | ✅ free Pollinations | ✅ via Copilot | ❌ needs key | ❌ needs key | | Built-in providers | 33 + gateways | 75+ via models.dev | many via litellm | 1 (Anthropic) | | Wire translation | OpenAI / Anthropic / Gemini | OpenAI shape | via litellm | Anthropic | | Multi-model routing | 6 strategy kinds, fallback, round-robin | multi-session | ❌ | ❌ | | Parallel agents | ✅ /parallel | multi-session | ❌ | ❌ | | Goal & plan tracking | ✅ /goal + /plan | ❌ | ❌ | /todo | | Hybrid context recall | SQLite graph + vector | linear history | repomap | project context | | Hooks / plugins | JS/TS at 5 lifecycle pts | skills + MCP | ❌ | hooks | | Dev commands | 11 built-in (/exec, /grep, /diff, …) | via shell tool | via /run | via bash | | Image input | ✅ all 3 wire standards | ✅ | ✅ | ✅ | | Auto-slash | detects intent, injects context | ❌ | ❌ | auto-tools | | Dependencies | 2 (commander + better-sqlite3) | 100+ | 30+ | N/A (binary) |


Quick start

Zero configuration (free, no key)

npm install -g @dreamtree-org/dhruthi
dhruthi                           # interactive REPL, uses free Pollinations model
dhruthi "What is a monad?"        # one-shot

That's it. Pollinations' openai-fast model (GPT-OSS 20B) serves every prompt for free, rate-limited. No account, no key, no setup.

With a provider key

Already have a key in your environment? No configuration needed:

export OPENAI_API_KEY=sk-…
dhruthi --provider openai "explain closures"

export GROQ_API_KEY=gsk_…
dhruthi --provider groq "write a haiku about SQL"

Or add one interactively:

dhruthi provider add anthropic   # pastes key, auto-activates
dhruthi provider use groq        # switch between configured providers

No model configured?

The CLI picks one, tells you, and remembers it:

$ dhruthi "Bonjour, ça va?"
auto-selected model: openai-gpt-oss-20b  (tier gpt-oss, smallest ≥20B)
saved as default_model — change it with: dhruthi config set default_model <id>
Ça va bien, merci !

It chooses the cheapest capable model rather than the largest — this is spending money on a decision you did not make. The choice is deterministic, announced on stderr, and persisted. For CI: --no-auto-model or DHRUTHI_NO_AUTO_MODEL=1.


Interactive REPL

$ dhruthi
dhruthi 0.3.5 — interactive. /help for commands, /exit or Ctrl-D to leave.
provider pollinations · model (auto) · session repl · 0 turns
›

All slash commands

Session & model:

| command | | |---|---| | /model [id] | show or switch model (/model auto to clear) | | /router [name] | route through DO inference router | | /session [name] | show, switch, or start a conversation | | /sessions | list saved conversations | | /clear | forget conversation history | | /system <text> | set the system prompt | | /strategy [name] | route turns across several models | | /switch <model> | hand conversation to another model | | /compact [n] | compress older turns, keeping last n exchanges | | /retry | re-send the last message | | /parallel [on\|off] | query all strategy candidates simultaneously | | /goal [text] | set or show the high-level objective | | /plan [cmd] | step-by-step plan (generate|add|done|undo|edit|clear) | | /recall | search past context across all sessions |

Development:

| command | | |---|---| | /file <path> | read a file into the conversation context | | /dir [path] | list directory tree | | /grep <pattern> | search codebase (requires ripgrep) | | /exec <cmd> | run a shell command, capture output | | /diff [--staged] | show git diff | | /log [-n 5] | show recent git log | | /lint | run the project linter | | /test [name] | run tests (filters by test name) | | /review [file] | ask the model to review code | | /explain <code> | ask the model to explain code | | /undo | revert all unstaged file changes | | /save [file] | write transcript to a file |

Meta:

| command | | |---|---| | /help, /exit | |

Ctrl-C cancels the reply and returns to the prompt. Ctrl-D exits. All chrome goes to stderr.

Goal-driven execution

dhruthi supports structured, goal-oriented workflows — set an objective and let the model build a step-by-step plan:

› /goal Build a REST API for user management
  Goal set.

› /plan generate
  Generating plan…
  ⤷ openai-fast
  Plan generated (5 items):
    1. Set up Express project structure
    2. Define user model and database schema
    3. Implement CRUD endpoints
    4. Add input validation and error handling
    5. Write integration tests

  Mark complete with /plan done <n>

› /plan done 1
  ✓ 1. Set up Express project structure

The goal and plan are composed into the system prompt so the model always sees them. The status line updates: goal "Build a REST API" · plan 1/5.

Parallel agents

With an active strategy, /parallel on fires all candidates at once and displays every reply:

› /strategy code-review
› /parallel on
  Parallel mode on — all strategy candidates will be queried simultaneously.
› Review this diff for bugs.
  ⤷ groq/llama-3.3-70b …
  ⤷ cerebras/llama3.1-8b …
  ⤷ openai/gpt-4o-mini …
  … all three replies stream simultaneously …

Sequential fallback (/parallel off) is the default — one candidate at a time, falling back on failure.

Auto-slash

dhruthi detects intent from your prompt and automatically injects context before the model sees it:

| Prompt pattern | Auto-injected context | |---|---| | "the tests are failing" | npm test output | | "refactor the auth module" | project file listing | | "where is the login handler?" | ripgrep search results | | "commit and push" | git diff --stat | | "how does the token validation work?" | relevant source file contents | | long prompt referencing multiple files | auto-goal + plan suggestion |

Toggle: dhruthi config set auto_slash off


Providers

One profile is one connection — base URL, wire standard, credential, and defaults. 33 presets built in.

dhruthi provider catalog        # show all 33 built-in presets
dhruthi provider list           # what you have configured
dhruthi provider add openai     # paste key, auto-activates
dhruthi provider use groq       # switch active
dhruthi provider status         # active provider details
dhruthi provider test           # GET /models + 1-token smoke test
dhruthi provider remove groq

Three wire protocols

Translation is transparent — --format json, streaming, sessions, and AGENTS.md behave the same regardless of which standard answered:

| Standard | Endpoint | System prompt | Auth header | |---|---|---|---| | openai | /v1/chat/completions | system message role | Authorization: Bearer | | anthropic | /v1/messages | top-level system field | x-api-key + anthropic-version | | gemini | :generateContent | systemInstruction | x-goog-api-key |

Image input (multimodal)

--attach works across all three standards — base64 data URLs and HTTP URLs are auto-translated to each provider's native image format:

dhruthi --attach screenshot.png "describe this UI"
dhruthi --provider anthropic --attach photo.jpg "what's in this image?"
dhruthi --provider gemini --attach diagram.png "explain this architecture"

Environment keys

Each preset knows its provider's conventional variable, so an exported key needs no config:

export OPENAI_API_KEY=sk-…
export GROQ_API_KEY=gsk_…
export ANTHROPIC_API_KEY=sk-ant-…
dhruthi --provider openai "hello"   # picks up OPENAI_API_KEY automatically

Precedence: --api-keyDHRUTHI_API_KEY → provider's own env var → stored profile key.

Gateways

Three gateway presets reach hundreds of upstreams through one endpoint:

npx omniroute@latest              # local, 290+ providers
dhruthi provider add omniroute

dhruthi provider add openrouter   # 400+ models, :free suffix for free ones
dhruthi provider add litellm      # local proxy, any provider

Free models (zero cost)

dhruthi works with free models across multiple providers. Pick your level:

Zero configuration — start instantly

dhruthi                           # uses Pollinations' openai-fast (GPT-OSS 20B), no key

Free API key — no payment required

| Provider | Models | Key env var | Setup | |----------|--------|-------------|-------| | Groq | llama-3.3-70b, qwen-coder, gemma, deepseek, mixtral | GROQ_API_KEY | console.groq.com | | Cerebras | llama3.1-8b, llama-4, mixtral | CEREBRAS_API_KEY | cloud.cerebras.ai | | Google Gemini | gemini-2.0-flash, gemini-2.5-pro, gemini-3.5-flash | GEMINI_API_KEY | aistudio.google.com | | NVIDIA NIM | nemotron-3, llama variants | NVIDIA_API_KEY | build.nvidia.com | | DeepSeek | deepseek-chat, deepseek-reasoner, deepseek-v4 | DEEPSEEK_API_KEY | platform.deepseek.com | | DeepInfra | llama, qwen, mistral, gemma | DEEPINFRA_API_KEY | deepinfra.com | | OpenRouter | 400+ models, 30+ :free suffix (zero billing) | OPENROUTER_API_KEY | openrouter.ai | | IO.NET | 17 models, free tier | IONET_API_KEY | ai.io.net | | Cloudflare AI | llama, gemma, mistral on global edge | CLOUDFLARE_API_KEY | developers.cloudflare.com |

# One key, one provider — instant setup
export GROQ_API_KEY=gsk_…
dhruthi --provider groq "hello"

# OpenRouter :free models — zero billing
export OPENROUTER_API_KEY=sk-or-…
dhruthi --provider openrouter --model google/gemini-2.0-flash-001:free "explain TypeScript generics"
dhruthi --provider openrouter --model deepseek/deepseek-chat:free "write a haiku about Rust"

OpenCode Zen — subscription, 87 models, many free

OpenCode Zen exposes an OpenAI-compatible API at https://opencode.ai/zen/v1 with 87 models including Claude, GPT, Gemini, DeepSeek, Kimi, GLM, Qwen, and many with -free suffix:

dhruthi provider add opencode-zen
# Paste your OpenCode Zen API key from https://opencode.ai/auth

# Free suffix models — zero additional cost:
dhruthi --provider opencode-zen --model deepseek-v4-flash-free "hello"
dhruthi --provider opencode-zen --model glm-5-free "explain this"
dhruthi --provider opencode-zen --model qwen3.6-plus-free "write a function"
dhruthi --provider opencode-zen --model kimi-k2.5-free "review this code"
dhruthi --provider opencode-zen --model hy3-free "summarize this"
dhruthi --provider opencode-zen --model minimax-m3-free "translate"

All OpenCode Zen free models: deepseek-v4-flash-free, glm-5-free, glm-4.7-free, hy3-free, hy3-preview-free, kimi-k2.5-free, ling-2.6-flash-free, ling-3.0-flash-free, ling-3.0-tiny-free, longcat-2.0-free, mimo-v2-flash-free, mimo-v2-omni-free, mimo-v2-pro-free, mimo-v2.5-free, minimax-m2.1-free, minimax-m2.5-free, minimax-m3-free, nemotron-3-super-free, nemotron-3-ultra-free, north-mini-code-free, qwen3.6-plus-free, ring-2.6-1t-free, trinity-large-preview-free, laguna-s-2.1-free

OpenCode Go — subscription, 24 curated models

dhruthi provider add opencode-go
# Paste your OpenCode API key
dhruthi --provider opencode-go --model qwen3.7-max "explain this architecture"

Local models — always free

dhruthi provider add ollama       # Ollama: localhost:11434/v1
dhruthi provider add lmstudio     # LM Studio: localhost:1234/v1
dhruthi provider add vllm         # vLLM: localhost:8000/v1
dhruthi provider add llamacpp     # llama.cpp: localhost:8080/v1

Free model strategies — combine for resilience

# Fire-and-forget across 3 free providers
dhruthi strategy add resilient --preset resilient

# OpenRouter :free only — 100% free, zero billing
dhruthi strategy add oss --preset oss-champion

# OpenCode Zen free models only
dhruthi strategy add zen-free -k cost-optimized \
  -c opencode-zen/deepseek-v4-flash-free \
  -c opencode-zen/glm-5-free \
  -c opencode-zen/qwen3.6-plus-free

# Activate and use
dhruthi strategy use oss
dhruthi "refactor this function"
# Automatic fallback if any model rate-limits

Strategies — multi-model routing

A strategy is a named set of candidate models plus a rule for ordering them. It makes free tiers usable: try the free one, and when it rate-limits, continue elsewhere.

dhruthi strategy add resilient -c groq/llama-3.3-70b -c cerebras/llama3.1-8b
dhruthi strategy use resilient
dhruthi "explain closures"
⤷ groq/llama-3.3-70b failed (429); continuing on cerebras/llama3.1-8b
→ strategy "resilient" → cerebras/llama3.1-8b (attempt 2 of 2)

| kind | ordering | |---|---| | priority | as declared; fall back only on failure | | cost-optimized | free → free-tier → paid | | round-robin | rotate per turn — stretches several free tiers past rate limits | | least-used | fewest recent requests first | | weighted | proportional, -c groq/model:7 | | random | shuffled |

Two billing protections: fallback never re-issues a request that may already have run, and automatic fallback will not escalate to a paid provider unless --allow-paid is set.

Built-in strategy presets

Six presets ship with dhruthi, each optimized for a specific coding workflow with free models:

dhruthi strategy add review --preset redundant   # install a built-in preset
dhruthi strategy use review                       # activate it
# or in the REPL:
/strategies redundant                             # list, then activate

| Preset | Kind | Candidates | Use case | |--------|------|-----------|----------| | resilient | cost-optimized | groq/llama-3.3-70b → cerebras/llama3.1-8b → openrouter :free | Never fail — rotate through 3 free providers | | redundant | priority | groq/llama + cerebras/llama + gemini-flash | Code review: fire multiple models, compare results | | fast-first | least-used | groq/llama + cerebras/llama | Stretches two free tier quotas across turns | | heavy-code | priority | gemini-2.5-pro → groq/llama → cerebras/llama | Complex tasks: strongest free models first | | oss-champion | cost-optimized | openrouter :free models only | 100% free — no API key needed on any provider | | multi-review | priority | groq/llama + cerebras/llama + gemini-flash | /parallel on — all three models review simultaneously |

# Redundant code review workflow
dhruthi strategy add review --preset redundant
dhruthi strategy use review
/parallel on
/diff
"Review this diff for bugs, style, and security"
→ groq, cerebras, and gemini review simultaneously

# Zero-key development (just OpenRouter API key)
dhruthi strategy add oss --preset oss-champion
dhruthi strategy use oss
→ All models are :free — no billing on any provider

Hybrid context recall

dhruthi uses a SQLite database with entity graphs and vector embeddings to retrieve relevant context from all past sessions — not just the current one.

User: "fix the JWT expiry bug in auth.ts"
  → Entity extraction: "JWT", "auth.ts", "bug"
  → Graph traversal: find turns referencing "auth.ts" across sessions
  → Vector search: cosine similarity on prompt embedding
  → Hybrid score: 0.5×vector + 0.3×graph + 0.2×freshness
  → Inject "Relevant past context" into system prompt

Embeddings are generated via the active provider's embedding API (text-embedding-3-small) and stored in the SQLite DB at ~/.local/state/dhruthi/context.db. Entity extraction is regex-based (file paths, function names, error codes, URLs, tech terms). The DB survives across REPL sessions and grows automatically.

Manual recall: /recall "JWT authentication"


Hook injection system

Extend dhruthi with plugins at five lifecycle points. Create a file in ~/.config/dhruthi/hooks/ and enable it:

dhruthi config set hooks my-hook,slack-notify

Hook types:

  • .ts / .js — ESM modules exporting lifecycle handlers
  • .sh — spawned shell scripts (simpler, no JS needed)

Lifecycle events:

// ~/.config/dhruthi/hooks/my-hook.ts
export function onStartup(ctx: HookContext) { ctx.log("REPL started"); }
export function onPreTurn(ctx: HookContext) {
  // modify context, inject data, run external tools before model call
}
export function onPostTurn(ctx: HookContext) {
  // post-process reply, send notifications, log metrics
}
export function onSlashCommand(ctx: HookContext) {
  // intercept or extend any slash command
  if (ctx.slashCommand === "/review") { /* custom logic */ }
}
export function onShutdown(ctx: HookContext) { /* cleanup */ }

Hook failures never crash the REPL — each handler is wrapped in try/catch.


Switching models mid-conversation

When a conversation moves to a different model (by fallback or /switch), the new model would otherwise read the previous model's replies as its own. The handoff system prevents this:

› /switch claude-haiku-4
Switched to claude-haiku-4 (from llama-3.3-70b). 12 message(s) handed over.

The incoming model sees attributed history — previous assistant turns are marked [assistant · llama-3.3-70b] — and a handoff preamble that prevents claiming work it didn't do. User turns are never rewritten, code is never summarized.


Authentication (DigitalOcean)

DigitalOcean issues two credentials that are not interchangeable. Commands that only exist on DO (routers, auth, setup) gate on the active provider:

| Credential | Format | Works on | |---|---|---| | Model access key | doo_v1_… or sk-do-… | inference.do-ai.run | | Personal access token | dop_v1_… | api.digitalocean.com |

export MODEL_ACCESS_KEY=doo_v1_…
export DIGITALOCEAN_TOKEN=dop_v1_…
dhruthi auth login --type pat      # stores in config (mode 0600)

Credentials are never in argv, never in output — including under --debug-http.


Project awareness

AGENTS.md becomes the system prompt

Any AGENTS.md from the repo root down to your working directory is concatenated into the system prompt. The cross-tool convention — a repo with an AGENTS.md for another tool needs nothing new.

dhruthi context print      # exactly what would be sent
dhruthi context files      # which files were found
dhruthi --no-context "…"   # ignore for one call

Prompt templates

Markdown files in .dhruthi/prompts/ become commands:

---
description: Review code for bugs
model: openai-gpt-oss-20b
---
Review the following for correctness bugs. Focus areas: $ARGUMENTS
dhruthi review null checks
dhruthi template list
dhruthi template render review null checks

Project settings

.dhruthi/config.json (committed) and .dhruthi/config.local.json (personal) layer under your user profile. Only default_model, default_router, and format are allowed — endpoints, transport, and credentials are refused outright in shared files.


Commands

setup                          one-time onboarding (DigitalOcean)
repl (shell)                   interactive chat
doctor (check)                 diagnose configuration
context (ctx) show·files·print what applies here
template(s) list·show·render·trust·untrust
provider(s) catalog·add·list·use·status·test·remove
strategy(s) list·show·add·use·remove
auth login·logout·status·whoami (DigitalOcean only)
config get·set·unset·list·path·fix-permissions
models (m) list·get          GET /v1/models
chat (c) create              POST /v1/chat/completions
responses create             POST /v1/responses
messages create              POST /v1/messages
embeddings create            POST /v1/embeddings
images generate              POST /v1/images/generations
audio (tts) speech           POST /v1/audio/speech
async submit·status·get·wait
video create·get·wait·download (experimental)
batch files·create·list·get·results·cancel
routers list·get·create·update·delete·presets (DigitalOcean only)
session list·show·rm·path

Output

--format json|jsonl|table|text. --format json always emits exactly one valid JSON document. Streaming happens over the wire for fast first byte, but output is assembled before printing.

| Code | | Code | | |---|---|---|---| | 0 | success | 5 | rate limited | | 1 | unexpected | 6 | server error | | 2 | usage / validation | 7 | network / timeout | | 3 | auth | 8 | job failed | | 4 | not found | 130 | interrupted |


Reliability

  • Retries on transient errors with exponential backoff and jitter; Retry-After honored up to 60s.
  • Billable POSTs are not blindly retried. An inference request returning 500 may have executed and been charged — only retried when the server confirms it wasn't processed.
  • Config files written atomically, mode 0600. Credentials never in argv or output.
  • Session transcripts at ~/.local/state/dhruthi/sessions/, mode 0600, JSONL format.

Development

npm install
npm run build          # tsc → dist/
npm run typecheck      # src + test
npm run lint           # biome
npm test               # builds, then unit + e2e (549 + 210 tests)
npm run verify:providers  # sweep the catalog against live hosts

Requires Node ≥ 22.12. Two conventions: relative imports carry .js extensions (NodeNext module resolution), and unit tests import from dist/ (type-stripping doesn't map .js to .ts).

Architecture

src/core/context-store.ts     SQLite DB: turns, entities, embeddings, hybrid search
src/core/context-graph.ts     Entity extraction (regex) + graph edge insertion
src/core/context-retrieve.ts  Hybrid retrieval: graph + vector with combined scoring
src/core/hooks.ts             Plugin system: 5 lifecycle events, JS/TS/sh hooks
src/repl/auto-slash.ts        Intent detection: auto-runs context commands before turns
src/repl/commands.ts          All 30 slash commands: dev, goal/plan, session, recall
src/repl/engine.ts            Conversation loop with hooks, auto-slash, recall
src/repl/turn.ts              Turn dispatch: single, strategy-fallback, parallel agents
src/api/chat.ts               Standard-aware dispatch + image translation for 3 protocols
src/providers/catalog.ts      33 provider presets with base URLs, env vars, costs

License

MIT