@pentoshi/clai 3.8.44 → 3.8.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +249 -251
  2. package/dist/attachments/clipboard-image.d.ts +10 -0
  3. package/dist/attachments/clipboard-image.js +188 -0
  4. package/dist/attachments/clipboard-image.js.map +1 -0
  5. package/dist/attachments/image-content.d.ts +3 -0
  6. package/dist/attachments/image-content.js +51 -0
  7. package/dist/attachments/image-content.js.map +1 -0
  8. package/dist/attachments/service.js +6 -2
  9. package/dist/attachments/service.js.map +1 -1
  10. package/dist/commands/providers.js +4 -2
  11. package/dist/commands/providers.js.map +1 -1
  12. package/dist/commands/search-providers.d.ts +1 -0
  13. package/dist/commands/search-providers.js +4 -2
  14. package/dist/commands/search-providers.js.map +1 -1
  15. package/dist/llm/capabilities.js +17 -4
  16. package/dist/llm/capabilities.js.map +1 -1
  17. package/dist/prompts/embedded.js +2 -2
  18. package/dist/prompts/embedded.js.map +1 -1
  19. package/dist/prompts/index.js +1 -1
  20. package/dist/prompts/system.agent.md +5 -3
  21. package/dist/prompts/system.ask.md +1 -1
  22. package/dist/repl/prompt-line.js +39 -6
  23. package/dist/repl/prompt-line.js.map +1 -1
  24. package/dist/repl.js +1 -1
  25. package/dist/repl.js.map +1 -1
  26. package/dist/store/config.d.ts +5 -1
  27. package/dist/store/config.js +8 -0
  28. package/dist/store/config.js.map +1 -1
  29. package/dist/store/history.js +43 -5
  30. package/dist/store/history.js.map +1 -1
  31. package/dist/store/keys.js +1 -0
  32. package/dist/store/keys.js.map +1 -1
  33. package/dist/tools/definitions.js +13 -7
  34. package/dist/tools/definitions.js.map +1 -1
  35. package/dist/tools/http.d.ts +6 -1
  36. package/dist/tools/http.js +247 -68
  37. package/dist/tools/http.js.map +1 -1
  38. package/dist/tools/registry.js +2 -1
  39. package/dist/tools/registry.js.map +1 -1
  40. package/dist/tools/web/decode.d.ts +17 -0
  41. package/dist/tools/web/decode.js +65 -0
  42. package/dist/tools/web/decode.js.map +1 -0
  43. package/dist/tools/web/fetch-core.js +14 -20
  44. package/dist/tools/web/fetch-core.js.map +1 -1
  45. package/dist/tools/web/providers/exa.d.ts +51 -0
  46. package/dist/tools/web/providers/exa.js +303 -0
  47. package/dist/tools/web/providers/exa.js.map +1 -0
  48. package/dist/tools/web/readable.d.ts +5 -5
  49. package/dist/tools/web/readable.js +34 -12
  50. package/dist/tools/web/readable.js.map +1 -1
  51. package/dist/tools/web/search.d.ts +3 -1
  52. package/dist/tools/web/search.js +6 -4
  53. package/dist/tools/web/search.js.map +1 -1
  54. package/dist/tools/web/types.d.ts +25 -2
  55. package/dist/tools/web/types.js +32 -0
  56. package/dist/tools/web/types.js.map +1 -1
  57. package/dist/tui-v2/app/commands/key-commands.js +1 -1
  58. package/dist/tui-v2/app/commands/key-commands.js.map +1 -1
  59. package/dist/tui-v2/app/commands/picker-commands.js +59 -8
  60. package/dist/tui-v2/app/commands/picker-commands.js.map +1 -1
  61. package/dist/tui-v2/components/transcript/intro-card.js +11 -5
  62. package/dist/tui-v2/components/transcript/intro-card.js.map +1 -1
  63. package/dist/tui-v2/composer/composer-editor.js +11 -9
  64. package/dist/tui-v2/composer/composer-editor.js.map +1 -1
  65. package/dist/tui-v2/composer/composer-image-paste.d.ts +19 -0
  66. package/dist/tui-v2/composer/composer-image-paste.js +56 -0
  67. package/dist/tui-v2/composer/composer-image-paste.js.map +1 -0
  68. package/dist/ui/keys.d.ts +1 -0
  69. package/dist/ui/keys.js +4 -0
  70. package/dist/ui/keys.js.map +1 -1
  71. package/dist/ui/mentions.d.ts +2 -16
  72. package/dist/ui/mentions.js +132 -102
  73. package/dist/ui/mentions.js.map +1 -1
  74. package/dist/version.generated.d.ts +2 -2
  75. package/dist/version.generated.js +2 -2
  76. package/package.json +1 -1
package/README.md CHANGED
@@ -1,48 +1,31 @@
1
1
  # clai
2
2
 
3
- > **Offensive-security agent in your terminal**recon, enumerate, exploit, and report with an approve-before-run plan workflow. Also a strong coding/sysadmin agent for shell and files. Free to build, free to run.
3
+ > A fast, terminal-native AI agent that runs real tools built to run on **free API tiers**, stay alive across rate limits with **multi-key + multi-provider switching**, and do serious work: **building, debugging, and scope-based pentesting / bug bounty**.
4
4
 
5
- clai is an AI **agent CLI** built for people who break (and fix) systems: authorized pentests, red-team style workflows, CTFs, report verification, and day-to-day security engineering. It runs real tools (`nmap`, `ffuf`, `sqlmap`, `http` evidence capture, …), keeps a **durable engagement plan**, and never pretends a finding is real without tool output to back it up. Providers that support it use **native function/tool calling** (config `toolCalling: auto|native|text`); text-fence tools remain as fallback.
5
+ `clai` is an agentic CLI. It doesn't just describe what to do it edits files, runs shell commands, scans hosts, fetches HTTP evidence, keeps a durable task plan, and verifies its own work before claiming success. It runs entirely in your terminal with a full-screen console UI (and a classic line REPL fallback).
6
6
 
7
- It also builds software and runs shell/file workflows when that is the job — same agent, same safety gate, same UI.
7
+ Two things make it practical for everyday use:
8
8
 
9
- ---
10
-
11
- ## Why clai for pentesting?
12
-
13
- | Pain | What clai does |
14
- |------|----------------|
15
- | Chatbots that only *describe* scans | **Runs** recon, fuzzers, and PoCs via shell + dedicated tools |
16
- | Long engagements lose the thread | **Session plan** + task checklist survives compaction and reloads from history |
17
- | Spray-and-pray tooling | **Stack fingerprint first**, then stack-matched wordlists and vectors |
18
- | Noisy full dumps fill context | **High-signal tool use**, artifacts for long output, expandable cards |
19
- | Unscoped scanning | **Authorize once**, optional **engagement scope**, confirm on mutating work |
20
- | “AI said vulnerable” without evidence | Findings require **command + real output**; report-style structure encouraged |
9
+ - **It's cheap-to-free to run.** Point it at Groq, Google Gemini, NVIDIA NIM, OpenRouter, Bynara, Kimchi, or a local Ollama — all have free access — and clai stacks them. Add several keys per provider; when one hits a rate limit, it rotates to the next automatically.
10
+ - **It's honest.** Findings need real tool output. Builds get typechecked/run before "done." Compaction and history keep long sessions coherent instead of hallucinating progress.
21
11
 
22
- ### Engagement shape (built into the agent)
23
-
24
- ```
25
- recon / discovery → fingerprint stack → plan.create (kind=pentest)
26
- ↑ │
27
- │ /implement (approve)
28
- │ ↓
29
- └──── enumerate → exploit → post-ex → report
30
- (revise plan as surface grows; keep completed tasks)
31
- ```
12
+ ---
32
13
 
33
- 1. **Recon first** (whois, DNS, `net.context`, `net.scan`, `http.fetch`, `pentest.recon`, …) — read-only discovery does **not** need a plan yet.
34
- 2. **Analyze evidence**, then **`plan.create`** with `kind=pentest` from real ports/services/endpoints/weaknesses — then **stop**.
35
- 3. You **`/implement`**, refine in chat, or **`/discard`**.
36
- 4. Execute task-by-task with **`task.update`**; expand the plan when new surface appears without wiping done work.
14
+ ## Highlights
37
15
 
38
- Non-destructive by default: prove issues with the least invasive evidence (reflected values, auth bypass PoCs, `whoami` after a shell). Destructive impact only when you explicitly ask.
16
+ - **Free-tier first.** 12 providers wired in, 6 cloud free tiers + local Ollama. Default provider is NVIDIA NIM (`openai/gpt-oss-20b`) so a fresh install can run at no cost.
17
+ - **Multi-key smart switching.** Up to 10 keys per provider with a *sticky* active key and circular rotation on rate-limit / auth / quota / transient / 5xx / empty-response errors. Optional cross-provider fallback and a free-only filter.
18
+ - **Scope-based pentesting.** Opt-in engagement scope with authorized/excluded targets, allowed phases, rate and concurrency ceilings, redirect and DNS-rebinding escape detection, and out-of-scope flagging — designed for authorized pentests and bug-bounty programs.
19
+ - **Real building & debugging.** Scaffolds apps, edits code surgically, installs packages, runs builds/tests, starts dev servers as background jobs, and probes them before reporting success.
20
+ - **Durable plans.** `plan.create` / `task.update` drive a live checklist that survives context compaction and reloads with `/history` — the agent works task-by-task and won't fake completion.
21
+ - **Native + text tool calling.** Uses provider-native function calling where available, with a text-fence fallback (`toolCalling: auto|native|text`).
22
+ - **Safety gate you control.** Every action is classified safe / confirm / block; deletes always confirm with a preview; destructive patterns are blocked.
39
23
 
40
24
  ---
41
25
 
42
- ## Installation
26
+ ## Install
43
27
 
44
28
  ### macOS
45
-
46
29
  ```sh
47
30
  brew tap pentoshi007/clai && brew install clai
48
31
  # or
@@ -50,248 +33,280 @@ curl -fsSL https://raw.githubusercontent.com/pentoshi007/clai/main/install/insta
50
33
  ```
51
34
 
52
35
  ### Linux
53
-
54
36
  ```sh
55
37
  curl -fsSL https://raw.githubusercontent.com/pentoshi007/clai/main/install/install.sh | sh
56
38
  ```
57
39
 
58
40
  ### Windows
59
-
60
41
  ```powershell
61
42
  irm https://raw.githubusercontent.com/pentoshi007/clai/main/install/install.ps1 | iex
62
- # or: scoop bucket add clai https://github.com/pentoshi007/clai && scoop install clai
43
+ # or
44
+ scoop bucket add clai https://github.com/pentoshi007/clai && scoop install clai
63
45
  ```
64
46
 
65
47
  ### npm / from source
66
-
67
48
  ```sh
68
49
  npm i -g @pentoshi/clai
69
-
70
50
  # or
71
51
  git clone https://github.com/pentoshi007/clai.git
72
52
  cd clai && npm install && npm run build && npm start
73
53
  ```
74
54
 
75
- Type `clai` in any terminal to start.
55
+ Node.js ≥ 20. Type `clai` in any terminal to start.
76
56
 
77
57
  ---
78
58
 
79
- ## Quick start (security)
59
+ ## Quick start
60
+
61
+ Get a free key from any supported provider, add it, and go:
80
62
 
81
63
  ```sh
82
- # Full-screen agent UI
64
+ # Add a free key (Groq shown; NVIDIA/Gemini/OpenRouter/Bynara/Kimchi work the same)
65
+ clai set groq gsk_your_key_here
66
+
67
+ # Launch the full-screen agent console
83
68
  clai
84
69
 
85
- # Authorize offensive tools for this machine (once)
86
- clai authorize-pentest AGREE
70
+ # Or one-shot from the shell
71
+ clai "explain what this repo does and find the entrypoint"
72
+ clai --mode agent "add a /health endpoint to the Express app and run the tests"
73
+ ```
87
74
 
88
- # Optional: remember engagement boundaries
89
- clai scope add --targets lab.example.com,10.10.0.0/24
75
+ Prefer fully local and offline? Point at Ollama:
90
76
 
91
- # One-shot agent against an in-scope target
92
- clai --mode agent "recon lab.example.com — open ports, stack, and interesting endpoints"
77
+ ```sh
78
+ clai set ollama --url http://localhost:11434
79
+ clai use ollama
80
+ ```
81
+
82
+ ---
83
+
84
+ ## Run it on free tiers (and keep it running)
85
+
86
+ This is the core of clai's design: assemble capacity from free tiers, then survive rate limits automatically.
87
+
88
+ ### Supported providers
89
+
90
+ | Provider | Default model | Tier | Env var |
91
+ |----------|---------------|------|---------|
92
+ | NVIDIA NIM | `openai/gpt-oss-20b` | Free | `NVIDIA_API_KEY` |
93
+ | Groq | `llama-3.3-70b-versatile` | Free | `GROQ_API_KEY` |
94
+ | Google Gemini | `gemini-3.5-flash` | Free | `GEMINI_API_KEY` |
95
+ | OpenRouter | `meta-llama/llama-3.3-70b-instruct:free` | Free | `OPENROUTER_API_KEY` |
96
+ | Bynara | `mimo-v2.5-free` | Free | `BYNARA_API_KEY` |
97
+ | Kimchi | `kimi-k2.6` | Free | `CASTAI_API_KEY` |
98
+ | Ollama | `llama3.1:8b` | Local / free | `OLLAMA_HOST` |
99
+ | OpenAI | `gpt-5.4-mini` | Paid | `OPENAI_API_KEY` |
100
+ | Anthropic | `claude-3-5-haiku-latest` | Paid | `ANTHROPIC_API_KEY` |
101
+ | AgentRouter | `claude-opus-4-6` | Paid | `AGENTROUTER_API_KEY` |
102
+ | AWS Mantle | `anthropic.claude-haiku-4-5` | Paid | `ANTHROPIC_API_KEY` |
103
+ | Qwen Cloud | `qwen3.7-plus` | Paid (DashScope) | `DASHSCOPE_API_KEY` |
104
+
105
+ Several "paid" providers also expose limited free allowances — the tier label reflects what the default keys usually buy you. Flip `freeOnly` off to include paid providers in fallback.
106
+
107
+ ### Manage keys
93
108
 
94
- # Ask mode: methodology / commands only, no execution
95
- clai --mode ask "how would you enum an internal AD lab from a foothold?"
109
+ ```sh
110
+ clai set groq gsk_first_key # store a key (appends if one exists)
111
+ clai set groq gsk_second_key # add another key for the same provider
112
+ clai set gemini --from-env GEMINI_API_KEY
113
+ echo "gsk_..." | clai set groq --stdin
114
+ clai set ollama --url http://localhost:11434
115
+ clai keys # list providers + masked keys, active key marked ★
116
+ clai use groq # set active provider
117
+ clai provider # interactive provider/model picker
118
+ clai unset groq # remove ALL keys for a provider
96
119
  ```
97
120
 
98
- Inside a session:
121
+ In the console, **`/set`** opens a multi-row key editor: add rows with `+`, remove rows, **Save**, or **Reset all**. **`/keys`** lists them masked; **`/unset`** clears a provider.
122
+
123
+ ### Smart switching (how it stays up)
99
124
 
100
- ```text
101
- > recon app.lab.local and map the attack surface
102
- agent runs whois/dns/nmap/http evidence
103
- plan.create (pentest checklist)
104
- > /implement
105
- … tasks execute with live plan pane (Ctrl+H) …
106
- > verify the IDOR on /api/v1/orders/{id} with a low-impact PoC
125
+ - **Multi-key rotation** — up to **10 keys per provider**. The last key that worked is *sticky*; on failure clai rotates circularly to the next key.
126
+ - **What triggers a switch** — HTTP 429 (rate limit), 401/403 (auth), 402 / quota / billing text, transient network errors, 500–504, and empty completions. Auth and quota errors switch **immediately** (no backoff wait); rate limits back off briefly first.
127
+ - **Cross-provider fallback** *(opt-in)* `/fallback on` lets clai try other configured providers after the active one is exhausted (only when running a provider's default model).
128
+ - **Free-only mode** *(opt-in)* — `/freeonly on` excludes paid-cloud providers from the fallback chain, so you never accidentally spend.
129
+ - **Quiet status** — a single non-stacking status line shows what happened, e.g. `switching groq key [2/4] …ab12 (rate limited)`. Keys are always masked to the last 4 chars.
130
+
131
+ ```sh
132
+ /freeonly on # stay on free tiers only
133
+ /fallback on # allow other providers when the current one is exhausted
107
134
  ```
108
135
 
109
136
  ---
110
137
 
111
- ## Security & pentest capabilities
138
+ ## What clai is good at
112
139
 
113
- ### Tools that matter for engagements
140
+ ### Building & debugging
114
141
 
115
- | Area | What you get |
116
- |------|----------------|
117
- | **Network** | `net.scan` (nmap wrapper, SYN with privilege / TCP fallback), `net.context`, `net.pingSweep`, `pentest.recon` (whois + dig + top ports) |
118
- | **HTTP evidence** | `http.fetch` — status, headers, cookies, TLS, body for **raw protocol / pentest** work (not casual page reading) |
119
- | **Web reading / OSINT** | `web.search`, `web.fetch` (readable pages), plus shell for specialized CLIs |
120
- | **Batch recon** | `tool.batch` — up to 20 lookups in one call; optional `on_fail` fail-fast or selective cancel when dependents need a prerequisite |
121
- | **Discovery** | `tool.check`, `pkg.install`, `wordlist.find` — install only what is missing; locate wordlists per OS (no Kali-only path guesses) |
122
- | **DNS / ownership** | `dns.lookup`, `whois.lookup` for narrow questions |
123
- | **Shell** | Full toolbox: `nmap`, `ffuf`, `gobuster`, `feroxbuster`, `sqlmap`, `hydra`, `nikto`, `masscan`, `nuclei`, `tshark`, … via `shell.exec` |
124
- | **Jobs** | Long scanners/listeners as background jobs (`shell.start` / `/jobs` / `Ctrl+J`) |
125
- | **Reporting** | Markdown tables, artifact paths for long scans, structured finding style (title, severity, evidence, repro, impact, remediations) |
142
+ The same agent that runs recon also ships code. It explores before it writes, matches your existing stack from lockfiles, edits surgically, and proves the result:
126
143
 
127
- ### Methodology the agent is steered toward
144
+ - Scaffolds and extends apps; replaces starter boilerplate with real features (a scaffold alone is treated as incomplete).
145
+ - Surgical file tools: `fs.edit`, `fs.replaceLines`, `fs.append`, plus multi-file writes.
146
+ - Runs the checks that apply — typecheck, build, unit/integration tests — and fixes failures before claiming success.
147
+ - Starts dev servers as background jobs, tails until ready, probes `localhost`, and reports the URL / port / job id with the server left running.
148
+ - Debugging loop: reproduce → read the actual error → fix root cause → re-verify (never "diagnosed but not fixed").
128
149
 
129
- - **Recon → fingerprint → enumerate → exploit → post-ex → report**
130
- - **Tech stack from real headers/body** before directory fuzz or exploit choice (Next.js PHP wordlists)
131
- - **Fuzz, don’t guess** one bounded content-discovery pass with filters, not dozens of blind `http.fetch` paths
132
- - **Enumerate before exploit**; match vectors to the stack
133
- - **Verify from tool output** — no fabricated banners or fake CVE hits
134
- - **Scope discipline** — flag out-of-scope hosts; keep authorized targets as the boundary
150
+ ```sh
151
+ clai --mode agent "convert this Vite React app to Next.js App Router, keep all features, run the build"
152
+ clai --mode agent "this test is flaky find the race and fix it"
153
+ ```
135
154
 
136
- ### Authorization & safety gate
155
+ ### Scope-based pentesting & bug bounty
137
156
 
138
- clai assumes **you** own authorization. The product still gates risk:
157
+ clai is built to run real, authorized security work — not to narrate it. It follows a recon-first methodology and keeps you inside the boundaries you set.
139
158
 
140
- ```sh
141
- clai authorize-pentest AGREE # session-level ack before scan/attack tools
142
- clai scope add --targets a.com,10.0.0.0/24
143
- # in UI: /scope add a.com · /scope show · /scope clear
159
+ ```
160
+ recon / discovery → fingerprint stack → plan.create (kind=pentest)
161
+ ↑ │
162
+ /implement (approve)
163
+ │ ↓
164
+ └──── enumerate → exploit → post-ex → report
165
+ (revise the plan as surface grows; keep completed tasks)
144
166
  ```
145
167
 
146
- | Risk | Behavior |
147
- |------|----------|
148
- | **safe** | Auto-run read-only recon patterns, `http.fetch` GET evidence, many enum CLIs |
149
- | **confirm** | Mutating shell, writes, installs, aggressive scans |
150
- | **block** | Destructive patterns (`rm -rf /`, fork bombs, classic exfil signatures, …) |
168
+ 1. **Authorize once**, then optionally **define scope** — authorized targets, exclusions, allowed phases, rate/concurrency ceilings, and an expiry.
169
+ 2. **Recon first** (read-only discovery needs no plan): whois, DNS, `net.scan`, `net.context`, `http.fetch`, `pentest.recon`, and shell tools like `nmap`, `ffuf`, `nuclei`, `sqlmap`.
170
+ 3. **Analyze real evidence**, then `plan.create` with `kind=pentest` from actual ports/services/endpoints then stop for your approval.
171
+ 4. `/implement` and execute task-by-task; expand the plan as new attack surface appears without wiping completed work.
172
+ 5. **Report** with structure title, severity, evidence, reproduction, impact, remediation and honest residual/untested notes.
151
173
 
152
- Default posture is **non-destructive proof**. Escalate impact only when you ask for it.
174
+ **Scope enforcement is real, not cosmetic.** When scope is active, clai checks each target against your authorized/excluded lists, enforces token-bucket rate limits and a concurrency ceiling, detects **redirects that leave scope** and **DNS-rebinding escapes**, and flags out-of-scope hosts instead of touching them. Loopback GET/HEAD stays allowed for local dev verification. Scope is opt-in: with no scope defined, scoping is simply off.
153
175
 
154
- ### Plan pane for engagements
176
+ ```sh
177
+ clai authorize-pentest AGREE
178
+ clai scope new --targets lab.example.com,10.10.0.0/24 --exclude prod.example.com \
179
+ --phases recon,enumeration --max-rate 5 --max-concurrency 2
180
+ # in the console: /scope show · /scope add <targets> · /scope clear
181
+ ```
155
182
 
156
- - Live checklist while you work (`Ctrl+H`)
157
- - Full plan + notes pager (`Ctrl+P` / `/plan`)
158
- - Approve with `/implement`, revise in chat, cancel with `/discard`
159
- - Plans **survive context compaction** and **reload with `/history`**
160
- - Agent mode: working checklist + evidence-before-done; plan mode: roadmap you approve before execution
183
+ Dedicated recon tools: `pentest.recon` (bundled whois/dns/nmap), `pentest.webDiscover` (scoped path discovery), `pentest.apiEnumerate` (OpenAPI/Swagger), `pentest.authCompare` (auth-context diffing), `pentest.scanStatus` (durable scan checkpoints).
161
184
 
162
- ---
185
+ ### General security & sysadmin workflows
163
186
 
164
- ## Terminal UI (operator console)
187
+ Log triage, config hardening, packaging, network questions, OCR of a screenshot or PDF report, quick OSINT — all handled by the same agent under the same safety gate.
165
188
 
166
- Full-screen OpenTUI console by default: streaming chat, nested tool cards (including `tool.batch` sub-sections), file diffs, plan pane, pickers, history, secure key prompts. Falls back to a classic line REPL if the terminal cannot host the UI.
189
+ ---
167
190
 
168
- | Action | How |
169
- |--------|-----|
170
- | Send | `Enter` |
171
- | Newline | `Shift+Enter` |
172
- | Abort turn | `Esc` / `Ctrl+C` (cancels in-flight tools cleanly) |
173
- | Expand thinking | `Ctrl+T` (clickable on status strip) |
174
- | Expand tool / compacted output | `Ctrl+O` |
175
- | Plan pane | `Ctrl+H` |
176
- | Full plan document | `Ctrl+P` |
177
- | Background jobs | `Ctrl+J` |
178
- | Commands / files | `/` · `@` |
179
- | Exit | `Ctrl+C` twice |
191
+ ## Modes & reasoning
192
+
193
+ Three modes, switchable anytime with a slash command, `Shift+Tab`, or `clai --mode`:
180
194
 
181
- Tool cards show **command/input** clearly and keep long scan tails in **OUTPUT** (expand or open pager). File writes show a **diff preview**. Deletes always ask for confirmation (`y`/`n`); press **`v`** to preview the path before confirming. Compaction cards preserve engagement memory without dropping the plan.
195
+ | Mode | Use |
196
+ |------|-----|
197
+ | **ask** | Answers, methodology, and read-only tools — no mutations, no attacks. |
198
+ | **agent** | Executes: edits, installs, scans, verifies, works the plan. |
199
+ | **plan** | Research and design a durable plan; approve with `/implement` before execution. |
182
200
 
183
- **`/history`** restores full sessionsprompts, tool results, findings context, and the matching plan when present (including after abort / autosave).
201
+ **Reasoning / thinking** is controlled with `/variants` (alias `/reasoning`), accepting `on`, `off`, `none`, `minimal`, `low`, `medium`, `high`, or `xhigh`. clai only sends reasoning options to models that support them and if a model rejects them at runtime, it marks that model, retries once without them, and tells you (`… rejected reasoning options retrying without them`) so a session never hangs on an unsupported knob.
184
202
 
185
203
  ---
186
204
 
187
- ## Modes
205
+ ## Safety gate
188
206
 
189
- | Mode | Security use |
190
- |------|----------------|
191
- | **`/agent`** | Run recon, build a pentest plan, execute after `/implement`, verify findings with tools |
192
- | **`/ask`** | Methodology, commands, and writeups **without** executing tools |
207
+ You own authorization; clai still gates risk on every action:
193
208
 
194
- Switch anytime: `/agent`, `/ask`, or `clai --mode agent|ask "…"`.
209
+ | Level | Behavior |
210
+ |-------|----------|
211
+ | **safe** | Auto-runs read-only work: `fs.read/list/search`, `sysinfo`, `dns.lookup`, `whois.lookup`, `http.fetch` GET, `web.search`/`web.fetch`, recon scanners. |
212
+ | **confirm** | Asks first for mutations: file writes/edits, installs, moves, aggressive/mutating shell. |
213
+ | **block** | Refuses destructive patterns (`rm -rf /`, fork bombs, classic exfil signatures) and SSRF-prone fetches. |
195
214
 
196
- Coding and general sysadmin work use the same agent (scaffold, debug, packages) with the same plan gate for multi-step jobs.
215
+ `fs.delete` always confirms (with an optional `v` preview) even under allow-all. `tool.batch` inherits the highest risk level of its children. Use `/permissions` to choose the default confirmation level and `/allow` / `/disallow` for a per-session tool allow-list.
197
216
 
198
217
  ---
199
218
 
200
- ## Features (summary)
201
-
202
- - **Pentest-first agent loop** — recon-before-plan, stack-aware enum, evidence-backed findings
203
- - **Durable plans** — `plan.create` / `task.update`, side pane, approve/refine/discard; agent vs plan task workflows
204
- - **Parallel multi-tool turns** — independent reads run together; failures do **not** cancel siblings by default
205
- - **`tool.batch` fail policy** — opt-in `on_fail=cancel_pending` or selective `cancel_on_fail` / rules when later work depends on earlier success
206
- - **Native + text tool calling** — `toolCalling: auto|native|text`
207
- - **11+ LLM providers** with streaming (free tiers + local Ollama)
208
- - **Safety gate** + pentest authorization + optional engagement scope (deletes always confirm with preview)
209
- - **OS-aware** installs and wordlist discovery (macOS / Linux / Windows)
210
- - **Context compaction** (auto + `/compact`) that keeps the plan alive
211
- - **Session history** with full transcript + plan restore
212
- - **Background jobs** for long scanners and listeners
213
- - **Web OSINT** — `web.search` / `web.fetch` alongside raw `http.fetch`
214
- - **Stall / cancel robustness** — tool heartbeats, hard deadlines, clean Esc abort with results recorded
219
+ ## Terminal UI
215
220
 
216
- ---
221
+ A full-screen console by default: streaming chat, nested tool cards (including `tool.batch` sub-calls), file diffs, a live plan pane, pickers, history, and secure masked key prompts. It falls back to a classic REPL when the terminal can't host the UI.
217
222
 
218
- ## Provider setup
219
-
220
- | Provider | Default model | Free tier | Key prefix |
221
- |----------|---------------|-----------|------------|
222
- | Groq | `llama-3.3-70b-versatile` | | `gsk_` |
223
- | Gemini | `gemini-2.0-flash` | ✓ | `AIza` / `AQ.` |
224
- | OpenRouter | `meta-llama/llama-3.3-70b-instruct:free` | | `sk-or-` |
225
- | OpenAI | `gpt-4o-mini` | — | `sk-` |
226
- | Anthropic | `claude-3-5-haiku-latest` | | `sk-ant-` |
227
- | NVIDIA NIM | `openai/gpt-oss-20b` | ✓ | `nvapi-` |
228
- | AgentRouter | `gpt-5` | — | `sk-` |
229
- | Kimchi | `kimi-k2.6` | | (any) |
230
- | AWS Mantle | `anthropic.claude-haiku-4-5` | — | `sk-ant-` |
231
- | Ollama | `llama3.1:8b` | ✓ local | URL |
232
- | Bynara | `mimo-v2.5-free` | ✓ | `sk_nry_` |
223
+ | Action | Key |
224
+ |--------|-----|
225
+ | Send / newline | `Enter` / `Shift+Enter` |
226
+ | Abort turn (keeps results) | `Esc` |
227
+ | Interrupt / quit | `Ctrl+C` (twice to quit) |
228
+ | Cycle mode (ask→agent→plan) | `Shift+Tab` |
229
+ | Plan pane / plan detail | `Ctrl+H` / `Ctrl+P` |
230
+ | Background jobs | `Ctrl+J` |
231
+ | Expand thinking / tool output | `Ctrl+T` / `Ctrl+O` |
232
+ | Search transcript | `Ctrl+R` |
233
+ | Copy selection | `Ctrl+Shift+C` |
234
+ | Commands / file mentions | `/` · `@` |
235
+ | Help / shortcuts | `Ctrl+G` |
233
236
 
234
- ```sh
235
- clai set groq gsk_... # store / append an API key (multi-key supported)
236
- clai set groq gsk_another_... # add a second key for the same provider
237
- clai set gemini --from-env GEMINI_API_KEY
238
- echo "gsk_..." | clai set groq --stdin
239
- clai set ollama --url http://localhost:11434
240
- clai keys # lists each key (masked) + sticky active ★
241
- clai use groq
242
- clai provider # picker shows selected model per provider
243
- clai unset groq # removes ALL keys for that provider
244
- ```
237
+ Tool cards show the command/input clearly and keep long scan tails in an expandable OUTPUT pager (search, copy, export). File writes show a diff preview. Compaction cards preserve session memory without dropping the plan, and `/history` restores full sessions — prompts, tool results, and the matching plan — even after an abort or autosave.
245
238
 
246
- In the TUI, **`/set`** opens a multi-row key editor (like `/scope`): add with `+`, remove rows, **Save**, or **Reset all**. **`/unset`** clears every key for the chosen provider. When several keys are stored, clai **rotates** on rate limits / auth / transient errors (one retry per key, then the next key in a circle) and shows a non-stacking toast (`using groq · …ab12` / `switching …`).
239
+ ---
247
240
 
248
- Env overrides: `GROQ_API_KEY`, `GEMINI_API_KEY`, `OPENROUTER_API_KEY`, `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `NVIDIA_API_KEY`, `OLLAMA_HOST`, …
241
+ ## Slash commands
242
+
243
+ | Command | Does |
244
+ |---------|------|
245
+ | `/ask` · `/agent` · `/plan` | Switch mode (plan = design-then-approve) |
246
+ | `/implement` · `/discard` | Approve+execute or drop the current plan |
247
+ | `/model [name\|#]` · `/provider [name]` · `/use <provider>` | Pick model / switch provider |
248
+ | `/set [provider]` · `/unset [provider]` · `/keys` · `/info [provider]` | Manage API keys and view provider info |
249
+ | `/variants [level]` · `/reasoning [level]` | Thinking / reasoning effort |
250
+ | `/freeonly [on\|off]` · `/fallback [on\|off]` | Free-only filter · cross-provider fallback |
251
+ | `/search [provider]` · `/search-provider` | Choose web-search backend |
252
+ | `/scope [show\|add\|new\|clear]` | Engagement scope |
253
+ | `/output [last\|id\|list]` | Open full tool output (also `Ctrl+O`) |
254
+ | `/jobs` | Background jobs (also `Ctrl+J`) |
255
+ | `/compact` · `/context` | Compact history now · show context size |
256
+ | `/history` · `/save <name>` · `/new` · `/clear` · `/reset` | Session lifecycle |
257
+ | `/allow <tool>` · `/disallow <tool>` · `/permissions` | Tool permissions |
258
+ | `/cwd <path>` | Change working directory |
259
+ | `/think` · `/thinking` | Show thinking from the last response |
260
+ | `/privacy [...]` | Private mode · clear history/logs/artifacts |
261
+ | `/update` · `/help` · `/shortcuts` · `/clean` · `/exit` | Housekeeping |
249
262
 
250
263
  ---
251
264
 
252
- ## Commands operators use most
253
-
254
- | Command | For security work |
255
- |---------|-------------------|
256
- | `/agent` | Offensive / execution mode |
257
- | `/ask` | Research & methodology only |
258
- | `/implement` · `/discard` · `/plan` | Plan lifecycle |
259
- | `/scope` | Engagement targets |
260
- | `/output` · `Ctrl+O` | Full tool / scan tails |
261
- | `/jobs` · `Ctrl+J` | Long-running tools |
262
- | `/compact` · `/context` | Keep long engagements inside the window |
263
- | `/history` | Resume yesterday’s engagement |
264
- | `/allow` | Session tool allow-list |
265
- | `/cwd` | Switch lab / loot directory |
266
- | `/model` · `/provider` | Capacity for the job |
267
- | `/update` · `/help` · `/exit` | Housekeeping |
268
-
269
- CLI mirrors: `clai authorize-pentest`, `clai scope add`, `clai doctor` (missing tools + install hints), `clai update`.
265
+ ## CLI commands
266
+
267
+ ```sh
268
+ clai [prompt...] # interactive console, or one-shot with a prompt
269
+ --mode <ask|agent|plan> --provider <p> --model <m>
270
+ -y/--yes --no-history --classic --ui <legacy|tui|v2>
271
+
272
+ clai set <provider> [key] # --from-env <VAR> | --stdin | --url <url> | --skip-ping
273
+ clai unset <provider> # remove all keys for a provider
274
+ clai keys # list providers with masked keys
275
+ clai use <provider> # set active provider
276
+ clai provider [provider] # switch provider or open picker
277
+ clai model <model> # set model for the active provider
278
+ clai mode <ask|agent|plan> # set default mode
279
+ clai search-provider <brave|tavily|duckduckgo>
280
+ clai config [key] [value] # print / get / set config
281
+ clai doctor # check installed tools + provider config
282
+ clai history [--show <id>] # list sessions / print one
283
+ clai update # check for updates
284
+ clai authorize-pentest AGREE # enable scan/attack tools (one-time ack)
285
+ clai scope <show|new|add|clear> # engagement scope (new: --targets --exclude --phases
286
+ # --name --note --expires --max-rate --max-concurrency)
287
+ clai privacy <status|on|off|retention|clear-history|clear-logs|clear-artifacts|clear-all>
288
+ ```
270
289
 
271
290
  ---
272
291
 
273
- ## Built-in tools (agent)
292
+ ## Built-in tools
274
293
 
275
- | Tool | Role in engagements |
276
- |------|---------------------|
277
- | `shell.exec` / `shell.start` · `shell.jobs` / `tail` / `stop` | nmap, ffuf, sqlmap, hydra, custom PoCs, listeners, background jobs |
278
- | `net.scan` · `net.context` · `net.pingSweep` · `pentest.recon` | Host/port/service discovery |
279
- | `http.fetch` | Raw HTTP/TLS evidence |
280
- | `web.search` · `web.fetch` | OSINT / docs (readable), not raw exploit traffic |
281
- | `dns.lookup` · `whois.lookup` | Narrow DNS / ownership |
282
- | `tool.batch` | Fan-out up to 20 tools; `concurrency` 1–6; `on_fail` continue (default) / cancel_pending / rules; per-call `cancel_on_fail` |
283
- | `tool.check` · `pkg.install` · `wordlist.find` | Tooling readiness |
284
- | `fs.read` · `fs.list` · `fs.search` · `fs.write` · `fs.writeMany` · `fs.edit` · `fs.replaceLines` · `fs.append` · `fs.delete` | Files (sandboxed roots; delete always confirms + optional preview) |
285
- | `plan.create` · `task.update` | Engagement checklist / working tasks |
286
- | `sysinfo` · `image.ocr` · `pdf.read` | Host context, report/screenshot OCR |
287
- | `agent.handoff` | Ask mode → offer agent mode when the user wants action, not explanation |
294
+ | Group | Tools |
295
+ |-------|-------|
296
+ | **Files** | `fs.read` · `fs.list` · `fs.search` · `fs.write` · `fs.writeMany` · `fs.edit` · `fs.replaceLines` · `fs.append` · `fs.delete` |
297
+ | **Shell & jobs** | `shell.exec` · `shell.start` · `shell.jobs` · `shell.tail` · `shell.stop` · `pkg.install` |
298
+ | **Network** | `net.scan` (nmap) · `net.context` · `net.pingSweep` · `dns.lookup` · `whois.lookup` |
299
+ | **HTTP / web** | `http.fetch` (raw evidence) · `web.search` · `web.fetch` (readable) |
300
+ | **Pentest** | `pentest.recon` · `pentest.webDiscover` · `pentest.apiEnumerate` · `pentest.authCompare` · `pentest.scanStatus` |
301
+ | **Orchestration** | `tool.batch` (up to 20 calls, `on_fail` policies) · `tool.check` · `wordlist.find` |
302
+ | **Plan** | `plan.create` · `task.update` · `agent.handoff` |
303
+ | **Context** | `sysinfo` · `image.ocr` · `pdf.read` |
288
304
 
289
- ### `tool.batch` fail policy (opt-in)
305
+ ### tool.batch fail policy
290
306
 
291
- Default is **continue** — one failed lookup never kills the rest (best for recon).
307
+ Default is **continue** — one failed lookup never kills the rest (ideal for recon). Opt into fail-fast or selective cancellation when later work depends on earlier success:
292
308
 
293
309
  ```json
294
- // Fail-fast: stop remaining calls after the first failure
295
310
  {"name":"tool.batch","args":{
296
311
  "on_fail":"cancel_pending",
297
312
  "calls":[
@@ -299,21 +314,19 @@ Default is **continue** — one failed lookup never kills the rest (best for rec
299
314
  {"name":"http.fetch","args":{"url":"https://lab.example/"}}
300
315
  ]
301
316
  }}
302
-
303
- // Selective: if scan fails, cancel only fuzz (dns still runs)
304
- {"name":"tool.batch","args":{
305
- "calls":[
306
- {"id":"dns","name":"dns.lookup","args":{"target":"lab.example"}},
307
- {"id":"scan","name":"net.scan","args":{"target":"lab.example"},
308
- "cancel_on_fail":["fuzz"]},
309
- {"id":"fuzz","name":"shell.exec","args":{"command":"ffuf …"}}
310
- ]
311
- }}
312
317
  ```
313
318
 
314
- Top-level multi-tool messages (several separate tool blocks) never cancel siblings; use `tool.batch` when you need a fail policy.
319
+ Top-level messages with several separate tool blocks never cancel siblings use `tool.batch` when you need a fail policy.
320
+
321
+ ---
315
322
 
316
- ### Search providers (OSINT)
323
+ ## Web search / OSINT
324
+
325
+ | Provider | Key | Env var |
326
+ |----------|-----|---------|
327
+ | DuckDuckGo | none (default) | — |
328
+ | Brave | required | `BRAVE_SEARCH_API_KEY` |
329
+ | Tavily | required | `TAVILY_API_KEY` |
317
330
 
318
331
  ```sh
319
332
  clai set brave bsx-...
@@ -321,34 +334,27 @@ clai set tavily tvly-...
321
334
  clai search-provider tavily
322
335
  ```
323
336
 
324
- DuckDuckGo is default and keyless. Env: `BRAVE_SEARCH_API_KEY`, `TAVILY_API_KEY`.
325
-
326
- ---
327
-
328
- ## Updates & doctor
329
-
330
- ```sh
331
- clai update
332
- clai doctor # OS, keys, and which security tools are installed
333
- ```
337
+ Search-provider keys are multi-key and rotate just like model providers.
334
338
 
335
339
  ---
336
340
 
337
341
  ## Per-project context
338
342
 
339
- `.clai/context.md` in a repo injects durable notes (e.g. lab topology, in-scope hosts, stack assumptions) every turn.
343
+ Drop a `.clai/context.md` in a repo and its contents are injected every turn — lab topology, in-scope hosts, stack assumptions, coding conventions, or anything the agent should always know for that project.
340
344
 
341
345
  ---
342
346
 
343
- ## Configuration
347
+ ## Configuration & privacy
344
348
 
345
349
  ```sh
346
- clai config
347
- clai mode agent
348
- clai model <name>
350
+ clai config # view config
351
+ clai mode agent # default mode
352
+ clai model <name> # default model for the active provider
353
+ /privacy on # private mode: don't persist this session
354
+ /privacy clear-all # wipe history, logs, and artifacts
349
355
  ```
350
356
 
351
- Config lives under the OS user config dir (e.g. `~/.config/clai/`).
357
+ Config lives under your OS user config dir (e.g. `~/.config/clai/`). Keys are stored locally and shown only masked.
352
358
 
353
359
  ---
354
360
 
@@ -356,27 +362,23 @@ Config lives under the OS user config dir (e.g. `~/.config/clai/`).
356
362
 
357
363
  ```sh
358
364
  npm install
359
- npm run dev
365
+ npm run dev # run from source
360
366
  npm run typecheck
361
367
  npm run build
362
- npm test
363
- npm run compile # native binaries (Bun)
368
+ npm test # full vitest suite
369
+ npm run compile # native binaries (Bun)
364
370
  ```
365
371
 
366
- Node.js ≥ 20.
367
-
368
372
  ---
369
373
 
370
374
  ## Releasing
371
375
 
372
- Tag-driven CI (`.github/workflows/release.yml`): tests → multi-platform binaries → GitHub Release → npm `@pentoshi/clai` → Homebrew tap.
376
+ Tag-driven CI (`.github/workflows/release.yml`): validate (typecheck + tests + prompt-budget + release checks) → multi-platform binaries → GitHub Release → npm `@pentoshi/clai` → Homebrew tap.
373
377
 
374
378
  ```sh
375
- # Single source of truth: package.json "version" only.
379
+ # package.json "version" is the single source of truth.
376
380
  npm version 3.8.0 --no-git-tag-version
377
- # sync-version refreshes version.generated.ts + install manifests + lock root
378
- # (also runs automatically on build / pretest / compile)
379
- npm run sync-version
381
+ npm run sync-version # refreshes version.generated.ts + install manifests + lockfile
380
382
  git commit -am "v3.8.0" && git push origin main
381
383
  git tag -a v3.8.0 -m "clai v3.8.0" && git push origin v3.8.0
382
384
  ```
@@ -385,22 +387,20 @@ Secrets: `NPM_TOKEN`, `TAP_GITHUB_TOKEN`. Optional: `NPM_PROVENANCE=true`.
385
387
 
386
388
  ---
387
389
 
388
- ## Architecture (overview)
390
+ ## Architecture
389
391
 
390
392
  ```
391
393
  clai/
392
394
  ├─ src/
393
- │ ├─ index.ts # CLI entry
394
- │ ├─ modes/ # ask · agent
395
- │ ├─ agent/ # loop, plans, compaction, tool parsing
396
- │ ├─ llm/ # providers + streaming + native tools
397
- │ ├─ tools/ # shell, net, http, web, fs, batch, pentest, …
398
- │ ├─ safety/ # classifier + patterns
399
- │ ├─ store/ # config, history, keys, plans, scope, logs
400
- │ ├─ tui-v2/ # full-screen OpenTUI (primary)
401
- ├─ app/ # session, commands, events
402
- │ └─ prompts/ # agent methodology (incl. pentest; embedded for bun)
403
- ├─ bin/clai.mjs
395
+ │ ├─ index.ts # CLI entry + subcommands
396
+ │ ├─ agent/ # loop, plans, compaction, resume orientation, tool parsing
397
+ │ ├─ llm/ # 12 providers, streaming, native tools, key rotation + fallback
398
+ │ ├─ tools/ # fs, shell, net, http, web, pentest, batch, plan
399
+ │ ├─ safety/ # risk classifier + engagement (scope) policy
400
+ │ ├─ store/ # config, history, keys, plans, scope
401
+ │ ├─ tui-v2/ # full-screen OpenTUI console (primary)
402
+ │ ├─ app/ # session controllers, commands, events
403
+ └─ prompts/ # agent methodology (embedded for the compiled binary)
404
404
  ├─ install/ · manifests/
405
405
  └─ package.json
406
406
  ```
@@ -409,8 +409,6 @@ clai/
409
409
 
410
410
  ## License
411
411
 
412
- MIT
413
-
414
- ---
412
+ MIT.
415
413
 
416
- **Use only on systems you are authorized to test.** clai is an operator tool: authorization, scope, and impact are yours; the agent executes with the gates and confirmations you configure.
414
+ **Use only on systems you are authorized to test.** clai is an operator's tool: authorization, scope, and impact are yours. The agent executes with the gates and confirmations you configure — nothing more.