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

c9ai

v4.0.2

Published

Local-first AI CLI — TUI shell, autonomous agent, autoresearch, Small Language Foundry, multi-provider (Claude / Gemini / Ollama / OpenAI-compatible)

Readme

c9ai v4

Local-first AI CLI built as an Ink-powered TUI in TypeScript.

This is a clean restoration of c9ai v1 (the original 51 KB CLI from 2024 — a thin shell over Claude CLI + Gemini CLI with GitHub Issues as the backlog), rewritten in TypeScript with Ink for live streaming output, and scaffolded for future growth (skills, artifacts, Matsya registry).

v2 (sigils, JIT, BASIC, executive forms) and v3 (Electron desktop app) are archived and serve as a reference catalog of ideas to port back as skills later — not as the next codebase.

Install

npm install -g c9ai
c9ai

Requires Node 18+.

Quickstart

c9ai talks to whichever AI backends you have. Pick at least one:

Local model — no API key needed

  1. Install Ollama and pull a model:
    ollama pull llama3.2
  2. Start c9ai and type:
    switch ollama
    With exactly one model installed it's auto-detected. Otherwise switch ollama list to see what's installed, then switch ollama <name>.

Other local OpenAI-compatible servers (LM Studio, llama.cpp server, vLLM) work too — point the base URL at them and no API key is required:

OPENAI_BASE_URL=http://localhost:1234/v1   # e.g. LM Studio

then switch openai inside c9ai.

Hosted providers

  • Claude — set ANTHROPIC_API_KEY (in your shell, a .env file in the directory you run c9ai from, or ~/.c9ai/.env), then switch claude. Or inside c9ai: config claude <api-key>.
  • OpenAI / Kimi / DeepSeek / OpenRouter — inside c9ai: config openai <api-key> (same for kimi, deepseek, openrouter), then switch <provider>.
  • Gemini — install the Gemini CLI so gemini is on your PATH, then switch gemini.
  • Lab — a self-hosted GPU node exposing an OpenAI-compatible endpoint, gated by a Matsya API key (it reuses MATSYA_API_KEY — no separate credential). switch lab. Override the node with LAB_BASE_URL and pin a model with LAB_MODEL (default auto).

The default provider is claude; whatever you switch to persists in ~/.c9ai/config.json. Providers fall into three tiers: local (ollama), lab (a self-hosted GPU node), and cloud (claude, gemini, openai, gpt, kimi, deepseek, openrouter).

Status

Stable. The v1 CLI shape is restored and extended; published to the latest npm tag. New here? Type help for a short task-grouped summary, or help html to open a visual cheat-sheet in your browser.

| Layer | Status | |---|---| | Ink TUI shell | ✅ | | Built-in commands (help, switch, todos, resume, save, clear, exit, tools, config) | ✅ | | Cross-session conversation memory (~/.c9ai/sessions/*.jsonl + resume/clear) | ✅ | | Prompt history (↑/↓ arrows, persisted in ~/.c9ai/history.json) | ✅ | | Personal AI: profile.md, current-directory scope-aware agent prompt | ✅ | | Scope-content awareness (agent @scope lists current-directory files with snippets) | ✅ | | Autoresearch (research <topic-or-file> → memo in outputs/ + ledger) | ✅ | | Claude provider (Anthropic SDK, streaming + cache) | ✅ | | Gemini provider (CLI subprocess) | ✅ | | Ollama provider (HTTP, streaming, friendly 404 with installed-models list) | ✅ | | OpenAI-compatible providers (openai, gpt, kimi, deepseek, openrouter) | ✅ | | Lab provider (self-hosted GPU node, OpenAI-compatible, Matsya-key gated) | ✅ | | First-run onboarding wizard (Matsya → Claude → optional providers) | ✅ | | skill command — author/validate Bru skills for the Matsya marketplace | ✅ | | tunnels command — preview-share tunnel worker (frpc-driven) | ✅ | | Small Language Foundry model workflow (models init/list/inspect/status/doctor/corpus/pairs/build/eval/review/compare/export/switch) | ✅ | | Small Language Foundry LoRA training recipe (models train + GGUF/Ollama packaging path) | ✅ | | !shell runner | ✅ | | GitHub Issues backlog via gh CLI (todos list/add) | ✅ | | Tools: fs.*, date.now, env.{cwd,platform}, shell.run (with destructive-pattern blocklist) + ~/.c9ai/tools-registry.json | ✅ | | Sigil dispatch (@<tool>) | ✅ | | Aliases (~/.c9ai/aliases.json) | ✅ | | Autonomous loop guards (max-iter, wall-clock, stall) | ✅ | | Autonomous loop wired to TUI (agent <goal>) | ✅ | | Skills authoring (skill new/validate/list) | ✅ | | Skills publish/install (marketplace round-trip) | deferred (awaits Matsya bru-store endpoint) | | Artifacts ledger | deferred | | Matsya queue worker (on-demand runner + paging-confirm) | ✅ |

Develop

npm install
npm run dev          # tsx src/index.tsx
npm run typecheck
npm run build && npm start

Architecture

src/
├── index.tsx              ← entry: parses argv, picks interactive vs one-shot
├── App.tsx                ← Ink root component
├── core/
│   ├── types.ts           ← shared types
│   ├── config.ts          ← ~/.c9ai/config.json
│   ├── logger.ts          ← ~/.c9ai/logs/
│   └── router.ts          ← input → action classification
├── tui/                   ← Ink components (MessageView, Prompt, printBanner)
├── commands/              ← pluggable command registry
│   ├── registry.ts        (help · switch · todos · config · analytics · tools)
│   └── *.ts
├── providers/             ← LLM backends
│   ├── claude.ts          (Anthropic SDK, streaming, prompt caching)
│   ├── gemini.ts          (CLI subprocess)
│   ├── ollama.ts          (HTTP streaming, configurable model + URL)
│   ├── openai-compatible.ts (OpenAI / Kimi / DeepSeek / OpenRouter HTTP streaming)
│   └── registry.ts
├── tools/                 ← @sigil-dispatched tools
│   ├── fs.ts              (fs.read/write/list, path-sandboxed to cwd)
│   ├── parse.ts           (sigil arg parser: key=val + positional)
│   ├── registry.ts        (builtins + ~/.c9ai/tools-registry.json)
│   └── types.ts
├── agent/
│   ├── guards.ts          (max-iter, wall-clock, stall detection)
│   ├── prompt.ts          (system-prompt builder + scope-content listing)
│   ├── extract.ts         (parse @tool sigil calls from model output)
│   └── loop.ts            (autonomous chat+tool loop, emits AgentEvent stream)
├── research.ts            ← autoresearch: program → bounded run → memo + ledger
├── aliases.ts             ← ~/.c9ai/aliases.json → tool dispatch
├── shell.ts               ← ! handler, cd
└── autonomous.ts          ← agent loop scaffold (uses guards)

User config (~/.c9ai/)

config.json            { defaultModel, ollamaModel?, ollamaUrl? }
aliases.json           { "<sigil>": { "tool": "<name>", "positional": "<key>", "extra": {...} } }
tools-registry.json    { "tools": { "<name>": { "command": "<shell>", "positional": "<key>" } } }
agent-prompt.md        custom system prompt for `agent` (use {{tools}} and {{goal}})
logs/                  one JSONL file per session

Env knobs (every external dep is overridable)

ANTHROPIC_API_KEY        Claude credential
CLAUDE_MODEL             Claude model ID (default claude-opus-4-7)
OPENAI_API_KEY           OpenAI credential
OPENAI_MODEL             OpenAI model ID (default gpt-4o)
OPENAI_BASE_URL          OpenAI-compatible base URL override
KIMI_API_KEY             Kimi credential
KIMI_MODEL               Kimi model ID (default moonshot-v1-128k)
KIMI_BASE_URL            Kimi-compatible base URL override
DEEPSEEK_API_KEY         DeepSeek credential
DEEPSEEK_MODEL           DeepSeek model ID (default deepseek-chat)
DEEPSEEK_BASE_URL        DeepSeek-compatible base URL override
OPENROUTER_API_KEY       OpenRouter credential
OPENROUTER_MODEL         OpenRouter model ID (default openai/gpt-4o)
OPENROUTER_BASE_URL      OpenRouter-compatible base URL override
OLLAMA_URL               Ollama server (default http://localhost:11434)
OLLAMA_MODEL             Ollama model; if unset, c9ai auto-detects from /api/tags

# When a *_BASE_URL points at a local OpenAI-compatible server (LM Studio,
# llama.cpp, vLLM), the matching *_API_KEY becomes optional.
GEMINI_BIN               Gemini CLI binary (default 'gemini' on PATH)
C9AI_LLAMA_CPP           llama.cpp checkout (or converter script path) for `models package`
                         (default ./external/llama.cpp relative to cwd)
C9AI_MAX_ITER            Agent max iterations (default 25)
C9AI_MAX_WALL_SEC        Agent wall-clock cap in seconds (default 600)
C9AI_STALL_REPEATS       Same-action repeats before agent stops (default 3)
C9AI_SCOPE_LIST_MAX_FILES  Current-directory files listed in system prompt (default 100)
C9AI_SCOPE_LIST_MAX_DEPTH  Max depth when walking current directory (default 3)

Inside c9ai, hosted-provider keys can be saved without editing environment files:

config openai <api-key>
config kimi <api-key>
config deepseek <api-key>
config openrouter <api-key>
config openai model gpt-4o
config kimi model moonshot-v1-128k
config deepseek model deepseek-chat
config openrouter model openai/gpt-4o

Small Language Foundry

Guide: docs/create-your-models.md

models samples
models init tiny-dickinson
models status tiny-dickinson
models doctor tiny-dickinson
models corpus tiny-dickinson add ./my-public-domain-poems
models corpus tiny-dickinson list

# Generate (prompt, completion) training pairs from corpus
models pairs tiny-dickinson generate
models pairs tiny-dickinson audit
models pairs tiny-dickinson list

# Bake system prompt + pairs into a runnable Ollama tag (few-shot)
models build tiny-dickinson --create

# Optional: train a LoRA adapter, then package it for Ollama
models train tiny-dickinson
models package tiny-dickinson
models package tiny-dickinson --versioned --test "Who are you?"
models package tiny-dickinson --promote

models eval tiny-dickinson
models evals-list tiny-dickinson
models review tiny-dickinson
models compare tiny-dickinson
models export tiny-dickinson
models inspect tiny-dickinson
switch tiny-dickinson

Model projects live under ~/.c9ai/models/<name>/ with model.json, prompts/, corpus/, pairs/, build/Modelfile, train/ (scaffolded recipe), eval/, and notes. The first bundled sample is tiny-dickinson — it ships the project shape (system prompt, eval questions, corpus guidelines) but no corpus text; add 20–50 public-domain poems per corpus/README.md, then models pairs ... generate and models build ... --create complete the few-shot loop. The train recipe (real LoRA fine-tuning) writes the dataset, Python trainer, and requirements; after training, convert the PEFT adapter to GGUF with llama.cpp and register it with Ollama using ADAPTER. The full packaging walkthrough is in docs/create-your-models.md.

For Ollama specifically: c9ai never assumes a particular model is installed. With no OLLAMA_MODEL env or ollamaModel in config, it lists /api/tags and either uses the only installed model or asks you to pick (switch ollama list, then switch ollama <name>).

Autoresearch

research <topic-or-file>

If the argument is an existing markdown file, it's read as the program (brief / bounds / evaluator). Otherwise a brief is synthesized from the topic string. The agent runs one bounded iteration, writes the memo to outputs/autoresearch-<slug>-<runId>.md, and appends a record to ~/.c9ai/brain/autoresearch/runs.jsonl with verdict (keep / discard / needs-review / crash).

agent, research, and fs.* tools are bounded to the current working directory. Use !cd <dir> before a run to change that boundary. Add @scope to an agent goal when you want the prompt to list current-directory files with size + first heading, capped via C9AI_SCOPE_LIST_MAX_*.

Extension points (wired now, implemented later)

  • Skills — load from ~/.c9ai/skills/*/skill.json, register sigils into the router (will subsume tools-registry.json)
  • Artifacts — every interaction logged in ~/.c9ai/logs/ becomes an artifact entry
  • Registryc9ai skills install <id> pulls from the Matsya skill registry
  • Matsya queue worker — on matsya-integration branch (HTTP client + manual queue commands + polling lifecycle); merges back when Matsya UI surfaces local-targeted items