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

@cuylabs/cli

v0.2.0

Published

Cuylabs CLI for running and managing agents

Readme

@cuylabs/cli

A terminal-native AI coding agent with a full interactive TUI, built on @cuylabs/agent-code and @cuylabs/agent-core. Multi-provider (OpenAI, Anthropic, Google), slash commands, streaming, mid-turn intervention, tool approval, skill discovery, sub-agent delegation, persistent sessions, keyboard shortcuts, markdown rendering, and more.


Quick Start

1. Set an API key

You only need one provider key. The CLI loads a .env file from your current working directory — the project folder where you run cuylabs, not from inside packages/cli/.

Where does the .env go?

your-project/              ← cd here, then run `cuylabs`
  ├── .env                 ← put your API key here
  ├── src/
  ├── package.json
  └── ...

The CLI looks for .env in whatever directory you're in when you launch it (process.cwd()). You can also point to a specific file with --env-file.

Create your .env

An .env.example is included in apps/cli/. Copy it to your project:

# From your project directory
cp node_modules/@cuylabs/cli/.env.example .env

# Or just create one manually
cat > .env << 'EOF'
# Uncomment ONE provider key:

# OpenAI
OPENAI_API_KEY=sk-proj-xxxxxxxxxxxxxxxxxxxx

# Anthropic
# ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxxxxxxxxx

# Google (either variable works)
# GOOGLE_GENERATIVE_AI_API_KEY=AIzaxxxxxxxxxxxxxxxxxx
EOF

Or set the key as a shell environment variable (no .env needed):

export OPENAI_API_KEY=sk-proj-...
cuylabs

Important: The .env file is loaded from your current directory, not from packages/cli/. If you run cuylabs from /Users/you/my-project, it looks for /Users/you/my-project/.env.

Provider auto-detection

The CLI auto-detects which provider to use based on which key is present:

| Environment Variable | Provider | |----------------------|----------| | OPENAI_API_KEY | OpenAI | | ANTHROPIC_API_KEY | Anthropic | | GOOGLE_GENERATIVE_AI_API_KEY or GOOGLE_API_KEY | Google |

If multiple keys are set, the priority is: OpenAI > Anthropic > Google. Override with --provider.

2. Build

# From the agents-ts workspace root
pnpm build --filter @cuylabs/cli

3. Launch

# Launch the interactive TUI (default command)
npx cuylabs

# Or with an initial prompt
npx cuylabs "refactor the auth module"

# Specify a model
npx cuylabs --model anthropic:claude-sonnet-4-20250514

# Resume your last session
npx cuylabs --continue       # or -C

# Disable tool approval prompts
npx cuylabs --approval never

# Legacy plain-text chat mode
npx cuylabs chat

# One-shot prompt
npx cuylabs run "summarize this repo" --json

Running cuylabs with no subcommand launches the TUI — the full interactive terminal interface.

Install locally (from the monorepo)

If you're developing in the agents-ts repo, build and link the CLI so the cuylabs command uses your local code:

# From the agents-ts workspace root
pnpm install
pnpm build --filter @cuylabs/cli

# One-time: set up pnpm's global bin directory (if you haven't before)
pnpm setup
source ~/.zshrc   # or restart your terminal

# Link the CLI globally so `cuylabs` resolves to your local build
cd apps/cli && pnpm link --global
cd -

# Now `cuylabs` runs your local version from anywhere
cuylabs --help

Or run it directly without linking — using pnpm exec from the workspace root:

pnpm --filter @cuylabs/cli exec cuylabs

Or via the bin entry with Node:

node apps/cli/bin/cuylabs.js

Install from npm (published release)

npm install -g @cuylabs/cli
cuylabs

Note: This installs the latest published version from npm, not your local code. Use "Install locally" above if you're working on the CLI itself.


Choosing a Model

The CLI supports three providers and uses a provider:model syntax:

# Explicit provider:model
cuylabs --model openai:gpt-4o
cuylabs --model anthropic:claude-sonnet-4-20250514
cuylabs --model google:gemini-2.0-flash

# Provider/model also works
cuylabs --model anthropic/claude-sonnet-4-20250514

# Just the model name (provider inferred from your API key)
cuylabs --model gpt-4o

# Or set provider separately
cuylabs --provider anthropic --model claude-sonnet-4-20250514

Defaults when no model is specified:

| Provider | Default Model | |----------|---------------| | OpenAI | gpt-4o | | Anthropic | claude-sonnet-4-20250514 | | Google | gemini-2.0-flash |

Switch models mid-session inside the TUI:

❯ /model anthropic:claude-sonnet-4-20250514
⚙ Model switched to: anthropic:claude-sonnet-4-20250514

List all available models:

cuylabs models               # grouped by provider
cuylabs models --remote      # live fetch from models.dev
cuylabs models --json        # machine-readable
cuylabs models --provider anthropic

Provider Priority

  1. --provider / --model CLI flag (highest)
  2. Config file (~/.config/cuylabs/config.json)
  3. Environment variable auto-detect (OPENAI_API_KEY → openai, ANTHROPIC_API_KEY → anthropic, etc.)

The TUI

The TUI is an Ink-based (React for terminal) interactive interface. It's the default when you run cuylabs.

Layout

┌──────────────────────────────────────────┐
│  Cuylabs CLI                             │
│  Model: gpt-4o · Tools: 9 · cwd: /proj  │
│  Type /help for commands, or start.      │
│                                          │
│  ❯ refactor the auth module              │
│  ● Looking at the auth module...         │
│    ✓ 📖 read  src/auth.ts               │
│    ✓ ✏️  edit  src/auth.ts               │
│    Done. I've **refactored** the JWT...  │
│                                          │
│  ❯ _                                     │
├──────────────────────────────────────────┤
│ ● ready  gpt-4o  1.2k↑ 856↓  a3f8d2e1  │
└──────────────────────────────────────────┘

Components:

| Area | What it does | |------|-------------| | Welcome Banner | Model, tool count, working directory — shown until first message | | Message List | Scrolling conversation with role indicators ( user, assistant, system), per-tool icons (📂📖✏️📝🔍⚡), tree-branch result summaries | | Markdown Rendering | Completed messages render with full markdown: bold, italic, code, code blocks with language labels, headings, lists, blockquotes, links | | Prompt Input | Text input with slash-command autocomplete hints. During streaming, input redirects the agent (intervention) | | Status Bar | Agent state (ready/thinking/calling-tool), model name, token counters, session ID | | Approval Overlay | Pops up when a tool needs permission — [Y] allow, [N] deny, [A] always allow |

Intervention (Mid-Turn Redirect)

While the agent is streaming (calling tools, generating text), type anything and press Enter to redirect it in-flight:

❯ refactor the auth module
● Reading auth module...
  ✓ read  src/auth.ts
  The auth module has three main...     ← agent is streaming

⚡ fix only the JWT validation bug      ← you type this
⚙ ⚡ Redirected: fix only the JWT validation bug

● Understood, focusing on JWT...        ← agent adjusts

The intervention is injected at the next step boundary. The conversation stays coherent — interventions are persisted to session history.

Tool Approval

When the agent calls a tool classified as moderate or dangerous, an overlay appears:

╭──────────────────────────────────────────╮
│ ⚠ Approve tool: bash                    │
│   Run command: rm -rf dist/              │
│   {"command": "rm -rf dist/"}            │
│                                          │
│ [Y] allow  [N] deny  [A] always  [Esc]  │
╰──────────────────────────────────────────╯
  • Y / Enter — allow this one call
  • N / Esc — deny (the model sees the denial and can adjust)
  • A — allow this tool+pattern for the rest of the session

Approval modes

Control when approval prompts appear with --approval:

cuylabs --approval auto      # (default) ask for moderate + dangerous tools
cuylabs --approval always    # ask for every tool call
cuylabs --approval never     # skip all prompts (YOLO mode)

Risk classification:

| Risk | Tools | Behavior | |------|-------|----------| | safe | read, grep, glob | Auto-allowed in auto mode | | moderate | write, edit | Prompt in auto and always | | dangerous | bash | Always prompt (unless never) |

You can also set this in your config file:

{
  "approval": "auto"
}

Keyboard Shortcuts

Global shortcuts that work alongside the text input:

| Shortcut | Action | |----------|--------| | Ctrl+L | Clear conversation | | Ctrl+K | Compact context (summarize older messages) | | Ctrl+N | Start a new session | | Esc | Deny approval / cancel |

Type /shortcuts in the TUI to see this list.

Note: Shortcuts are disabled during streaming and when the approval overlay is active.


Slash Commands

Type / in the TUI to see autocomplete suggestions. All commands:

| Command | Aliases | Description | |---------|---------|-------------| | /help | /h, /? | Show all available commands | | /quit | /q, /exit | Exit the CLI | | /clear | /c | Clear conversation history | | /status | /s | Session info, model, token usage, context utilization % | | /model [spec] | /m | Show or switch model (e.g. /model anthropic:claude-sonnet-4-20250514) | | /tools | /t | List active tools | | /compact | | Summarize older messages to free context window | | /undo | | Revert file changes from the last agent turn | | /diff | /d | Show file changes from the current turn | | /sessions | | List saved sessions | | /branch | /fork | Fork the current session into a new branch | | /resume [id] | /r | Resume a previous session by ID prefix | | /skills | /sk | List discovered skills | | /agents | /sa | Show sub-agent tools and profiles | | /shortcuts | /keys | Show keyboard shortcuts |


Skills

The CLI automatically discovers SKILL.md files from your project and loads them as tools the agent can use.

How it works

  1. On startup, the CLI scans for SKILL.md files in:
    • .agents/ directory (Cuylabs convention)
    • .claude/ directory (Claude Code convention)
    • Nested up to 4 levels deep
  2. Skills are summarized in the agent's context (L1 — titles and descriptions)
  3. The agent can call the skill tool to load full skill content on demand (L2 — body text)
  4. The agent can call skill_resource to read associated files (scripts, examples, references)

Creating a skill

mkdir -p .agents/my-skill
cat > .agents/my-skill/SKILL.md << 'EOF'
---
name: deploy
description: Deploy the application to production
tags: [devops, deploy]
---

# Deploy Skill

## Steps

1. Run `pnpm build` to create the production build
2. Run `pnpm test` to verify all tests pass
3. Run `./scripts/deploy.sh` to push to production

## Notes

- Always run from the project root
- Requires AWS credentials in environment
EOF

Managing skills

# List discovered skills in the TUI
/skills

# Disable skill discovery
cuylabs --skills false

Skills can also be set in your config:

{
  "skills": true
}

Sub-Agents

The agent can delegate tasks to specialized sub-agents — lightweight forks that run independently and return their results.

Built-in profiles

| Profile | Purpose | Max Steps | |---------|---------|-----------| | explorer | Fast read-only codebase search and exploration | 20 | | coder | Full-power implementation — write, edit, fix, refactor | 40 | | planner | Read-only analysis and step-by-step planning | 15 | | runner | Execute commands (tests, builds, lint) and report results | 10 |

The model decides when to delegate based on the task. You don't need to trigger sub-agents manually — just ask complex multi-part questions and the agent will use invoke_agent when it makes sense.

How it works

  1. The agent gets an invoke_agent tool that lists available profiles
  2. When the agent calls invoke_agent, a sub-agent is forked from the parent with the chosen profile
  3. The sub-agent runs in its own session with its own turn budget
  4. Results are returned to the parent agent as a tool result
  5. Sub-agents share the same tools, cwd, and file system as the parent

Managing sub-agents

# Show available sub-agent tools in the TUI
/agents

# Disable sub-agent tools
cuylabs --sub-agents false

Sessions

All sessions are automatically persisted to disk using JSONL file storage. Sessions are stored per-project in ~/.cuylabs/sessions/<project-hash>/.

Resume a session

# Resume the most recent session
cuylabs --continue
cuylabs -C

# Resume a specific session by ID
cuylabs --session <session-id>

# Resume from within the TUI
/resume              # shows recent sessions
/resume a3f8d2e1     # switch to session matching prefix

Session commands

# List all sessions for the current project
/sessions

# Fork the current conversation into a new branch
/branch

# Start a fresh session mid-conversation
# (Ctrl+N shortcut also works)

How session persistence works

  • Each session is a .jsonl file with append-only entries
  • Messages, tool calls, compaction summaries, and branches are all persisted
  • Sessions are scoped to the project (identified by git root hash or directory path)
  • Sub-agent sessions are linked to their parent via parentSessionId
  • Session IDs are UUIDs — use /resume with a prefix to avoid typing the full ID

CLI Commands

The CLI also supports non-TUI modes for scripting and pipelines:

| Command | Description | |---------|-------------| | cuylabs [prompt] | Default — Launch interactive TUI | | cuylabs tui [prompt] | Same as above (explicit) | | cuylabs chat [prompt] | Legacy plain-text interactive mode (readline, no TUI) | | cuylabs run [prompt] | Single prompt, then exit. Supports --json and stdin pipe | | cuylabs models | List available models | | cuylabs tools | List available tools and groups | | cuylabs config <action> | path, show, or init for CLI configuration |

Examples

# TUI with a specific model and system prompt
cuylabs --model anthropic:claude-sonnet-4-20250514 --system @./AGENTS.md

# Resume last session with a follow-up
cuylabs -C "now add tests for that"

# Skip approval prompts (unattended mode)
cuylabs --approval never "fix all lint errors"

# One-shot with JSON output
cuylabs run "list the top 5 files by size" --json

# Pipe stdin
cat error.log | cuylabs run "explain this error"

# Read prompt from a file
cuylabs run @./prompt.md

# Disable tools (chat-only mode)
cuylabs --tools false

# Use specific tools only
cuylabs --tools read,grep,glob

# All tools except bash
cuylabs --tools all,-bash

# Use a tool group
cuylabs --tools read-only
cuylabs --tools safe

# Disable all agent features for a simple chat
cuylabs --tools false --skills false --sub-agents false --approval never

Configuration

Config file

Default location: ~/.config/cuylabs/config.json (XDG compliant)

# Create a config template
cuylabs config init

# Show current config
cuylabs config show

# Print config path
cuylabs config path

Config structure:

{
  "provider": "anthropic",
  "model": "claude-sonnet-4-20250514",
  "systemPrompt": "",
  "cwd": "/path/to/project",
  "tools": true,
  "maxSteps": 50,
  "temperature": 0.7,
  "reasoningLevel": "medium",
  "approval": "auto",
  "skills": true,
  "subAgents": true
}

| Field | Type | Default | Description | |-------|------|---------|-------------| | provider | "openai" \| "anthropic" \| "google" | auto-detect | AI provider | | model | string | provider default | Model ID | | systemPrompt | string | "" | System prompt text | | cwd | string | process.cwd() | Working directory | | tools | boolean \| string | true | Tool spec (see below) | | maxSteps | number | 50 | Max agent steps per turn | | temperature | number | — | LLM temperature | | reasoningLevel | string | — | Reasoning depth | | approval | "auto" \| "always" \| "never" | "auto" | Tool approval mode | | skills | boolean | true | Enable skill discovery | | subAgents | boolean | true | Enable sub-agent delegation |

Environment variables

| Variable | Purpose | |----------|---------| | OPENAI_API_KEY | OpenAI provider | | ANTHROPIC_API_KEY | Anthropic provider | | GOOGLE_GENERATIVE_AI_API_KEY | Google provider (or GOOGLE_API_KEY) | | CUYLABS_CONFIG / CUY_CONFIG | Custom config file path |

.env file resolution order

  1. --env-file ./path/to/.env (explicit flag — highest priority)
  2. --cwd /some/dir → looks for /some/dir/.env
  3. Config file cwd field → looks for .env there
  4. Current working directory → $(pwd)/.env (default)
# Use a specific .env file
cuylabs --env-file ~/secrets/cuylabs.env

# Set working directory (also changes where .env is loaded from)
cuylabs --cwd /path/to/project

All CLI Options

cuylabs [prompt]

Options:
  --model            Model ID or provider:model (e.g. openai:gpt-4o)
  --provider         Force provider: openai, anthropic, google
  --system           System prompt string or @file path
  --session          Session ID for persistence
  --continue, -C     Resume the most recent session
  --cwd              Working directory for the agent
  --env-file         Path to .env file
  --config           Path to config JSON
  --tools            Tool spec (see below)
  --approval         Tool approval mode: auto, always, never (default: auto)
  --skills           Enable skill discovery (default: true)
  --sub-agents       Enable sub-agent delegation tools (default: true)
  --temperature      LLM temperature
  --topP             Top-P sampling
  --maxOutputTokens  Max output tokens
  --maxSteps         Max agent steps per turn
  --reasoningLevel   Reasoning depth (low, medium, high)
  --verbose          Show tool call details
  --show-reasoning   Stream reasoning/thinking text
  --json             (run only) JSON output instead of streaming

Tool specs

--tools true           All tools (default)
--tools false          No tools
--tools read-only      Group: read, grep, glob
--tools safe           Group: all except bash
--tools minimal        Group: read, grep
--tools read,grep      Specific tools by name
--tools all,-bash      All minus bash

Architecture

cuylabs (CLI binary)
  ├── TUI layer (Ink / React for terminal)
  │   ├── App              — root layout, input routing, keyboard shortcuts
  │   ├── MessageList      — streaming conversation with markdown rendering
  │   ├── MarkdownView     — zero-dep markdown parser + Ink renderer
  │   ├── PromptInput      — text input with /command autocomplete hints
  │   ├── StatusBar        — model, tokens, state, session ID
  │   ├── ApprovalOverlay  — tool permission prompts (Y/N/A)
  │   └── Commands         — 15 slash commands via registry pattern
  │
  ├── Hooks
  │   ├── useAgent         — bridges agent.chat() events → React state
  │   ├── useKeyboard      — Ctrl+L/K/N global shortcuts
  │   └── useTerminal      — terminal dimensions
  │
  ├── ApprovalGateway      — bridges middleware ↔ React state
  │
  ├── @cuylabs/agent-code
  │   ├── 6 coding tools: bash, read, edit, write, grep, glob
  │   └── ToolsetBuilder (fluent tool selection)
  │
  └── @cuylabs/agent-core
      ├── Agent            — streaming chat, sessions, forking
      ├── Middleware        — approval, lifecycle hooks
      ├── Skills           — SKILL.md discovery, registry, L1/L2 loading
      ├── Sub-Agents       — invoke_agent tool, profiles, tracker
      ├── SessionManager   — FileStorage (JSONL), branching, resume
      ├── Approval         — risk classification, rules, remember
      ├── Intervention     — mid-turn message injection
      ├── Context          — token estimation, pruning, summarization
      ├── MCP              — Model Context Protocol servers
      └── Prompt Pipeline  — model-aware system prompts

How the TUI works

  1. cuylabs boots Ink (React for terminal) and mounts <App>
  2. setupAgent() creates the agent with middleware (approval), skills, sub-agent tools, and file-based session storage
  3. User types a message → useAgent.send(message) is called
  4. send() calls agent.chat(sessionId, message) — an async generator
  5. Each AgentEvent from the generator updates React state:
    • text-delta → appends to the assistant message (raw during streaming, markdown on completion)
    • tool-start/tool-result → inline tool status with per-tool icons and result summaries
    • step-start/step-finish → updates the status bar
    • intervention-applied → adds a system note
  6. When the middleware triggers an approval request, the ApprovalGateway sets React state → the ApprovalOverlay renders → user presses Y/N/A → the Promise resolves → middleware continues
  7. When the user types while streaming, it calls agent.intervene() — injected at the next step boundary
  8. Slash commands are dispatched locally (never sent to the LLM)
  9. All messages are persisted to ~/.cuylabs/sessions/<project-hash>/ as JSONL