@pentoshi/clai
v1.2.9
Published
A fast, cross-platform AI CLI assistant with ask and agent modes for shell tasks, file operations, and cybersecurity workflows.
Maintainers
Readme
clai
A fast, cross-platform AI CLI assistant with
/askand/agentmodes for general shell tasks, file operations, and cybersecurity / pentesting workflows. Free to build, free to run.
Installation
macOS
# Homebrew (recommended)
brew tap pentoshi007/clai
brew install clai
# or via curl
curl -fsSL https://raw.githubusercontent.com/pentoshi007/clai/main/install/install.sh | shLinux
curl -fsSL https://raw.githubusercontent.com/pentoshi007/clai/main/install/install.sh | shWindows
# PowerShell (recommended)
irm https://raw.githubusercontent.com/pentoshi007/clai/main/install/install.ps1 | iex
# or Scoop
scoop bucket add clai https://github.com/pentoshi007/clai
scoop install claiAny OS (via npm)
npm i -g @pentoshi/claiFrom Source
git clone https://github.com/pentoshi007/clai.git
cd clai && npm install && npm run devAfter installing, type clai in any terminal to start.
Quick Start
# Open interactive REPL
clai
# One-shot ask mode (explains but doesn't execute)
clai --mode ask "create a python venv and install requests"
# One-shot agent mode (executes)
clai --mode agent "find all PDFs larger than 10MB in ~/Documents"
# Auto-confirm tool execution
clai -y "list the 10 largest files in my home directory"Features
/askmode — Read-only. AI explains, gives commands & step-by-step guidance, but does NOT execute anything./agentmode — Agentic. AI plans, waits for approval, then executes shell commands, edits files, installs missing tools, parses output, and continues until the goal is met. Tasks run on an approve/refine/discard plan workflow (/implement, free-text to refine,/discardto cancel).- 9 LLM providers — Groq, Google Gemini, OpenRouter, OpenAI, Anthropic, NVIDIA NIM, AgentRouter, Kimchi, AWS Mantle, and Ollama (local). All with streaming.
- 10 built-in tools —
shell.exec,fs.read,fs.write,fs.list,fs.search,pkg.install,net.scan,http.fetch,sysinfo,pentest.recon. - Smart safety gate — Read-only commands auto-execute; mutating commands require confirmation; destructive patterns are blocked.
- OS-aware & tool-frugal — Picks the best approach for your OS, prefers tools already installed (installs only when nothing suitable exists), broadens its approach and escalates privileges as needed to finish the task.
- Cross-platform — macOS, Linux, and Windows. Detects OS-native package managers (brew, apt, dnf, pacman, winget, choco).
- Pentest-aware — nmap, nikto, sqlmap, gobuster, ffuf, hydra, masscan, whois, dig, netcat, tshark.
- Auto-update — Checks for new versions on startup; run
/updateorclai updateto upgrade. - Persistent history — Session history with automatic key redaction in logs.
Provider Setup
clai supports 10 LLM providers (8 with free tiers):
| Provider | Default Model | Free? | API Key Prefix |
|-------------|----------------------------------------------|-------|----------------|
| Groq | llama-3.3-70b-versatile | ✓ | gsk_ |
| Gemini | gemini-2.0-flash | ✓ | AIza |
| OpenRouter | meta-llama/llama-3.3-70b-instruct:free | ✓ | sk-or- |
| OpenAI | gpt-4o-mini | — | sk- |
| Anthropic | claude-3-5-haiku-latest | — | sk-ant- |
| NVIDIA NIM | openai/gpt-oss-20b | ✓ | nvapi- |
| AgentRouter | gpt-5 | — | sk- |
| Kimchi | kimi-k2.6 | ✓ | (any) |
| AWS Mantle | anthropic.claude-haiku-4-5 | — | sk-ant- |
| Ollama | llama3.1:8b | ✓ | (local URL) |
# Store an API key
clai set groq gsk_xxxxxxxxxxxxxxxx
# Import from environment variable
clai set gemini --from-env GEMINI_API_KEY
# Read from stdin (safer — avoids shell history)
echo "gsk_xxx" | clai set groq --stdin
# Set Ollama endpoint
clai set ollama --url http://localhost:11434
# List configured providers (keys masked)
clai keys
# Switch active provider
clai use groq
# Interactive provider picker
clai provider
# Remove a key
clai unset groqEnvironment Variable Overrides
Runtime env vars override stored keys:
export GROQ_API_KEY=gsk_...
export GEMINI_API_KEY=AIza...
export OPENROUTER_API_KEY=sk-or-...
export OPENAI_API_KEY=sk-...
export ANTHROPIC_API_KEY=sk-ant-...
export NVIDIA_API_KEY=nvapi-...
export CASTAI_API_KEY=...
export ANTHROPIC_WORKSPACE_ID=default # optional, for AWS Mantle
export OLLAMA_HOST=http://localhost:11434REPL Commands
| Command | Action |
|-------------------------|-------------------------------------------------- |
| /ask | Switch to ask mode |
| /agent | Switch to agent mode |
| /model | Open interactive model picker (type/↑/↓, Tab fills, Enter selects) |
| /model <name\|#> | Switch model by name or number (e.g. /model 2) |
| /provider [name] | Switch provider or open interactive picker |
| /use <provider> | Alias for /provider <name> |
| /set <provider> [key] | Store API key (masked input if key omitted) |
| /unset <provider> | Remove stored key |
| /keys | List configured providers, masked |
| /variants [on|off|low|medium|high] | Toggle model thinking/reasoning variants |
| /think | Show hidden thinking from last response |
| /output [last|id|list]| Toggle full saved tool output |
| /clear | Clear conversation context |
| /new | Save current session & start fresh |
| /history | Browse & resume past sessions (interactive picker) |
| /save <name> | Save current session |
| /reset | Clear all saved history |
| /cwd <path> | Change working directory |
| /allow <tool> | Whitelist a tool for the session |
| /plan | View the current session plan (also Ctrl+P) |
| /implement | Approve the current plan and have clai execute it |
| /discard | Discard the current plan so later messages ignore it |
| /scope add <targets> | Add authorized pentest targets |
| /fallback [on|off] | Try other configured providers after a failure |
| /update | Check for updates |
| /exit | Quit |
| /help | List commands |
| Ctrl+C | Abort current response (second Ctrl+C exits) |
| Ctrl+O | Toggle full tool output (same keys on all OSes) |
| Ctrl+P | View the current session plan |
Plan → Implement workflow
For multi-step coding or pentest tasks, clai first proposes a plan (a goal, an approach, and an ordered task checklist) and then waits. Nothing runs until you approve it.
- Approve — type
/implementto execute the plan task by task. - Refine — type any normal message (e.g. "use only installed tools", "skip task 2", "also enumerate subdomains") and clai produces a revised plan, then waits again. While a plan is awaiting approval, free-text is treated as plan feedback, not as a signal to start running.
- Cancel — type
/discardto drop the plan. After discarding, later messages are independent of it.
Built-in Tools (Agent Mode)
| Tool | Description | Risk Level |
|------------------|--------------------------------------------------------------------|------------|
| shell.exec | Run shell commands via execa (120s timeout, streams output) | smart* |
| fs.read | Read files (sandboxed to approved roots) | safe |
| fs.write | Write files (sandboxed) | confirm |
| fs.list | List directory contents | safe |
| fs.search | Search files with ripgrep (falls back to grep) | safe |
| pkg.install | Install packages via detected OS package manager | confirm |
| net.scan | Nmap wrapper. Defaults to a stealth SYN scan, auto-elevates (sudo/doas/gsudo) and falls back to an unprivileged TCP connect scan | confirm |
| http.fetch | HTTP GET/POST with response size limits | safe |
| sysinfo | OS, architecture, shell, and working directory info | safe |
| pentest.recon | Composite: whois + dig + stealth nmap top-100 ports | confirm |
* smart = read-only commands (
curl,ls,whoami,gobuster,dirb, etc.) auto-execute; mutating commands require confirmation.
Web tools
Two higher-level tools sit alongside http.fetch for agent-driven web reading:
web.search— query the public web through a configurable search provider and return structured{title, url, snippet}hits. Default provider is DuckDuckGo (keyless, works out of the box). Brave Search and Tavily are supported when an API key is configured. Use this for current-events or post-cutoff information; the agent prompt steersweb.searchtoward time-sensitive questions andweb.fetchtoward reading a known URL.web.fetch— fetch a URL and return readable prose (HTML stripped of<script>/<style>/chrome) plus rich metadata: response headers, TLS session details (cipher, peer cert SAN list, fingerprint), redirect chain, fine-grained timing, resolved IP. Sensitive headers and cookie values are redacted by default; passredactSensitive=falseto expose them in the output (the audit log never carries them). Loopback / RFC1918 / link-local / cloud-metadata addresses are blocked by SSRF checks at every redirect hop, with DNS rebinding defeated by IP-pinning the connection to the resolved address.
Search provider configuration
# Set a key for Brave or Tavily (DuckDuckGo is keyless and is a no-op).
clai set brave bsx-xxxxxxxxxxxxxxxx
clai set tavily tvly-xxxxxxxxxxxxxxxx
# Remove a stored key.
clai unset brave
# Switch the active search provider used by web.search.
clai search-provider tavily
# List configured keys (LLM and search) with the same masking rule.
clai keysEnvironment variables override stored keys at call time:
| Provider | Env var |
|--------------|--------------------------|
| Brave Search | BRAVE_SEARCH_API_KEY |
| Tavily | TAVILY_API_KEY |
| DuckDuckGo | (none, keyless) |
Safety Gate
Every tool call passes through a 3-tier classifier:
safe— Auto-run: read-only fs, sysinfo, http.fetch, read-only shell commands (curl,ls,whoami,ifconfig,gobuster,dirb,ffuf,nikto, etc.)confirm— User prompt: mutating shell commands, fs.write, pkg.install, net.scanblock— Refuse with explanation:rm -rf /, fork bombs, public IP scans without authorization, exfiltration patterns
Pentest Authorization
Security tools require a one-time acknowledgment:
clai authorize-pentest AGREEPublic targets do not require a stored scope, but keeping one helps clai remember what you are authorized to test. Add targets with:
clai scope add --targets example.com,10.0.0.0/24Inside the REPL, use /scope add example.com. If the agent proposes a public recon target that is not covered, clai shows a scope suggestion and still lets you continue through the normal confirmation flow.
Updates
clai checks for updates automatically on startup (every 4 hours, non-blocking). You can also check manually:
# CLI command
clai update
# Inside the REPL
/updateDiagnostics
clai doctorOutputs: OS, shell, architecture, config paths, provider key status, available pentest tools with install commands for missing ones.
Per-Project Context
Create a .clai/context.md file in your project root to automatically inject project context into every prompt:
This is a Node.js project using Express and PostgreSQL.
The API server runs on port 3000.Configuration
Configuration is stored at ~/.config/clai/config.json (varies by OS):
clai config # Print config path and settings
clai mode agent # Set default mode
clai model llama-3.3-70b-versatile # Set modelDevelopment
npm install # Install dependencies
npm run dev # Run in development mode
npm run typecheck # Type check
npm run build # Build TypeScript
npm test # Run tests (39 tests)
npm run compile # Build native binaries (requires Bun)Releasing
Releases are fully automated by .github/workflows/release.yml, triggered when
you push a v*.*.* tag. To cut a release:
npm version 1.0.6 --no-git-tag-version # bump package.json + lockfile
# also bump: src/commands/update.ts (FALLBACK_VERSION),
# manifests/homebrew/clai.rb, manifests/scoop/clai.json
git commit -am "v1.0.6"
git push origin main
git tag -a v1.0.6 -m "clai v1.0.6"
git push origin v1.0.6 # this triggers the workflowOn the tag push the workflow:
- build — runs typecheck + tests and compiles native binaries for all platforms.
- publish — creates the GitHub Release with the binaries and SHA256 sidecars.
- publish-npm — publishes
@pentoshi/claito npm. - sync-tap — regenerates the Homebrew formula in
pentoshi007/homebrew-clai.
Reruns don't pick up newer workflow code. Re-running a workflow runs it against the commit the tag points to. If you change
release.ymlafter tagging, you must move/recreate the tag (or cut a new version) for the change to take effect.
Required repository secrets (Settings → Secrets and variables → Actions). Each job skips gracefully if its secret is absent:
| Secret | Used by | How to create |
|--------------------|---------------|-------------------------------------------------------------------------------|
| NPM_TOKEN | publish-npm | npm → Access Tokens → Granular (Read and write on @pentoshi/clai) or classic Automation token. These bypass the interactive OTP prompt that blocks CI. |
| TAP_GITHUB_TOKEN | sync-tap | A GitHub PAT with contents:write on the pentoshi007/homebrew-clai repo |
Optional repository variable (not a secret):
| Variable | Effect |
|------------------|---------------------------------------------------------------------------------|
| NPM_PROVENANCE | Set to true to publish with --provenance. Only works if the npm account's 2FA is set to "authorization only". Leave unset otherwise — the job publishes without provenance. |
The publish-npm job verifies the tag matches package.json version and skips
if that version is already on npm, so re-running a tag is safe.
A normal account with 2FA set to "auth and writes" prompts for a one-time password on every publish, which fails in CI. Use a Granular/Automation
NPM_TOKEN(token-level auth) so CI can publish without an OTP — you can keep 2FA enabled on the account.
Architecture
clai/
├─ src/
│ ├─ index.ts # CLI entry, argv parsing via commander
│ ├─ repl.ts # Interactive REPL with readline
│ ├─ modes/
│ │ ├─ ask.ts # Read-only mode (no tool execution)
│ │ └─ agent.ts # Agentic mode (tool execution)
│ ├─ agent/
│ │ └─ runner.ts # Agent loop: LLM → parse → classify → execute → loop
│ ├─ llm/
│ │ ├─ provider.ts # Provider interface & utilities
│ │ ├─ router.ts # Provider selection & fallback chain
│ │ ├─ http.ts # OpenAI-compatible HTTP client
│ │ ├─ groq.ts # Groq provider (streaming)
│ │ ├─ gemini.ts # Gemini provider (streaming)
│ │ ├─ ollama.ts # Ollama provider (streaming)
│ │ ├─ openai.ts # OpenAI provider (streaming)
│ │ ├─ anthropic.ts # Anthropic provider (streaming)
│ │ ├─ nvidia.ts # NVIDIA NIM provider (streaming)
│ │ └─ openrouter.ts # OpenRouter provider (streaming)
│ ├─ tools/
│ │ ├─ registry.ts # Tool dispatch table
│ │ ├─ shell.ts # shell.exec via execa
│ │ ├─ fs.ts # Sandboxed file operations
│ │ └─ http.ts # HTTP fetch tool
│ ├─ safety/
│ │ ├─ classifier.ts # 3-tier risk classification
│ │ └─ patterns.ts # Destructive & exfiltration regexes
│ ├─ os/
│ │ ├─ detect.ts # OS/arch/shell detection
│ │ └─ pkgmgr.ts # Package manager detection
│ ├─ store/
│ │ ├─ config.ts # Persistent config via `conf`
│ │ ├─ history.ts # Session history
│ │ ├─ keys.ts # Keychain + fallback key storage
│ │ ├─ logs.ts # Audit log with rotation
│ │ └─ project.ts # Per-project context loader
│ ├─ commands/
│ │ ├─ doctor.ts # System diagnostics
│ │ ├─ update.ts # Auto-update checker
│ │ └─ providers.ts # Provider management commands
│ └─ prompts/
│ └─ index.ts # Prompt template renderer
├─ bin/clai.mjs # ESM shebang launcher
├─ scripts/build.ts # Bun compile per target
├─ .github/workflows/
│ └─ release.yml # CI: build + publish binaries on tag
├─ manifests/
│ ├─ homebrew/clai.rb # Homebrew formula
│ └─ scoop/clai.json # Scoop manifest
├─ install/
│ ├─ install.sh # macOS/Linux curl installer
│ └─ install.ps1 # Windows PowerShell installer
├─ package.json
├─ tsconfig.json
└─ README.mdLicense
MIT
