@mrwatermeloooon/jarvis-cli
v0.4.2
Published
Jarvis — an agentic coding CLI with pluggable model backends (Anthropic, OpenAI, Ollama, HuggingFace, custom GGUF).
Readme
Jarvis CLI
v0.4.2 · An agentic coding assistant for your terminal. Jarvis can read and write files, search and run commands, browse the web, use git, connect to MCP servers, and delegate to sub-agents to actually get work done — and it runs on whatever model you want: a hosted API, a local model, or your own custom checkpoint.
Quick start
You need Node.js 20+. Then install Jarvis from npm and run it:
npm install -g @mrwatermeloooon/jarvis-cli
cd my-project # any folder you want help in
jarvis # startOn first run Jarvis asks which model provider to use and prompts for that
provider's API key, then saves it to ~/.jarvis/.env so you're never asked
again. Switching later with /model does the same — if you don't have that
provider's key yet, Jarvis asks once and remembers it. (Ollama runs locally and
needs no key at all.)
What's inside
- 10 model backends, all equal — Anthropic, DeepSeek, Gemini, Qwen, Kimi, MiniMax, OpenAI, Ollama, HuggingFace, and your own GGUF. No privileged default.
- 16 built-in tools — read, list, search (ripgrep), find_files, web_search,
web_fetch, write, edit, run command, git_status / git_diff / git_log /
git_commit, plan,
task,dispatch— plus any tools from connected MCP servers. - 🔌 MCP client — connect to any MCP server (databases, GitHub, Slack, …) in
.jarvis/settings.json; its tools are proxied straight into the agent. - ✍️ Multiline input (
<<…>>), 📎@filementions (auto-inject a file's contents), and 🖼️ image attachments (/attachor@image.png) for vision-capable models. - 🔀
/diffsession change tracking and 📸/checkpointsnapshots, on top of single-step/undo. - 📋 Structured plans — the agent keeps a
.jarvis/plan.mdchecklist you can watch with/plan. - ⚠️ Token-budget awareness — the spinner shows context usage; Jarvis warns at 80% and auto-compacts at 95%.
- 🙈
.jarvisignore— gitignore-style excludes for search and file discovery. - 🍴
/fork— branch the conversation to try a risky approach,/resumeback if it doesn't pan out. 📌/pinkeeps a file in context every message. - 👁️ Watch mode —
jarvis --watch "fix failing tests"re-runs on every save (TDD loop); also/watchmid-session. - 🔁 Pipe-friendly —
cat err.log | jarvis "what's wrong"; reads stdin when it isn't a TTY. 🎭/profileflips provider + model + persona + tool access. - Token-by-token streaming across providers.
- Sub-agents —
task(one) anddispatch(parallel), with named + built-in agents (explore,researcher,general-purpose), tool restriction, and per-agent models. - Internet — web search + fetch, plus a
researcheragent. - Sessions — auto-saved, resumable (
/resume,-c,-r). - Custom
/commandsand named agents from markdown files. - Security — per-action approval, persistent permission rules, workspace
sandbox, destructive-command blocklist, optional OS sandbox, and
/undo. - A polished TUI: welcome dashboard, syntax-highlighted writes, red/green diffs, a thinking spinner with elapsed time + token count, a live slash-command menu, and arrow-key pickers.
Backends
Every backend is a first-class equal — Jarvis has no default model. You
either name one (JARVIS_PROVIDER or --provider), or, if you've configured
exactly one below, Jarvis auto-detects it.
| Provider | Setting (JARVIS_PROVIDER) | Tool calling | Needs |
| ------------ | --------------------------- | ------------ | --------------------------- |
| Anthropic | anthropic | native | ANTHROPIC_API_KEY |
| DeepSeek | deepseek | native | DEEPSEEK_API_KEY |
| Gemini | gemini | native | GEMINI_API_KEY |
| Custom GGUF | gguf | prompted | GGUF_MODEL_PATH |
| HuggingFace | huggingface | prompted | HF_TOKEN |
| Kimi | kimi | native | KIMI_API_KEY |
| MiniMax | minimax | native | MINIMAX_API_KEY |
| Ollama | ollama | native | local Ollama running |
| OpenAI | openai | native | OPENAI_API_KEY |
| Qwen | qwen | native | QWEN_API_KEY |
"Prompted" tool calling lets models with no function-calling API still use tools via a ReAct-style JSON protocol, so your own GGUF model works through the exact same agent loop as the hosted ones.
Install the global jarvis command
So you can cd into any folder and just type jarvis:
npm install
npm run build
npm link # registers `jarvis` on your PATHThe first time you run jarvis it walks you through picking a provider and
entering its API key, saving it to ~/.jarvis/.env automatically. If you'd
rather set it up by hand, drop your key in the global config so it works
from anywhere:
# ~/.jarvis/.env (Windows: C:\Users\<you>\.jarvis\.env)
JARVIS_PROVIDER=deepseek
DEEPSEEK_API_KEY=sk-...Now, from any project:
cd my-project
jarvis # interactive session, scoped to this folder
jarvis "fix the failing test"
jarvis -p ollama "explain src/index.ts"The folder you launch in becomes the workspace root — Jarvis confines its file access to it.
Config precedence
Env vars are read in this order (first one set wins):
- Real shell environment variables
./.envin the current project~/.jarvis/.env(global)
To use your own GGUF model, also install the optional native runtime:
npm install node-llama-cppDevelop
npm run dev # run from source (no build)
npm run dev -- "list the files here" # one-shot task
npm run build # bundle to dist/ (what `jarvis` runs)Commands
Type / in the prompt for a live, filtering menu. Built-ins:
| Command | What it does |
| --- | --- |
| /help | list all commands |
| /model | switch model/provider (arrow-pick, or /model ollama llama3.1) |
| /agent | list / pick / run / edit specialized sub-agents |
| /permissions | view or edit allow/deny/ask rules |
| /tools | list the agent's tools |
| /init | generate a JARVIS.md the agent auto-loads |
| /compact | summarize the conversation to free up context |
| /cost | token usage + rough cost estimate |
| /resume | resume a past conversation |
| /plan | show the current task plan (.jarvis/plan.md) |
| /diff | show a diff of every file changed this session |
| /checkpoint | save / restore / list snapshots of session changes |
| /attach | attach an image to your next message (vision) |
| /fork | branch the conversation into a new session (/fork list) |
| /pin /unpin | inject a file into every message (/pin list) |
| /profile | apply a named config preset (/profile list) |
| /watch | re-run a task on file changes (/watch stop) |
| /undo | revert the last file change |
| /clear | reset the conversation (start a new session) |
| /exit | quit |
You can also define your own — see Custom commands.
Input: multiline, mentions, and images
- Multiline — type
<<on its own line to open a block, paste freely, then>>(or a blank line twice) to send. Handy for pasting code or stack traces. @filementions — write@src/agent/agent.tsin a message and the file's contents are injected into the prompt automatically, no "read it first" round trip. Multiple mentions per message are fine.- Image attachments —
/attach screenshot.png(or just@screenshot.png) base64-encodes the image into your next message for vision-capable models (Anthropic / OpenAI). Supports png, jpg, gif, webp.
Reviewing and undoing changes
Jarvis tracks every file it writes or edits this session:
/diffrenders a colored unified diff of everything changed since the session started — review before you commit./checkpoint save <name>snapshots all session-modified files under.jarvis/checkpoints/<name>/;/checkpoint restore <name>rolls them all back;/checkpoint listshows what you've saved. Goes beyond single-step/undofor abandoning a whole batch of work.- Git tools — the agent uses
git_status,git_diff,git_log, andgit_commitdirectly. These are read-only except for a scoped commit; there's no way to accidentallygit pushorgit reset --hard.
Task plans
For multi-step work the agent maintains a checklist in .jarvis/plan.md, ticking
items off as it goes. View the current state any time with /plan:
Plan: wire up auth
✔ add login route
◐ hash passwords
○ write tests
1/3 doneWorkflow: fork, pin, watch, profiles, pipes
/forkbranches the conversation. The current history is cloned into a new session id and you keep going on the branch; the parent transcript is preserved so you can/resumeback to it./fork listshows branches. Likegit branchfor AI sessions — explore a risky approach without losing the thread./pin <file>keeps a file in context: it's re-read fresh and appended to every message you send (no repeated@mentions)./pin list,/unpin <file>,/unpin all.Watch mode —
jarvis --watch "fix the failing tests"runs the task, then re-runs it on every workspace file change (debounced, respecting the ignore set). Perfect for a TDD loop. Mid-session,/watch <task>starts it and/watch stopends it.Pipes — when stdin isn't a TTY, Jarvis reads it and folds it into the task:
cat error.log | jarvis "what's wrong here" git diff | jarvis "write a commit message"/profile <name>applies a preset from~/.jarvis/profiles/<name>.json— switching provider, model, a system-prompt persona, and the allowed-tools list in one go./profile listshows them. Example~/.jarvis/profiles/review.json:{ "description": "read-only code reviewer", "model": "deepseek-reasoner", "systemPrompt": "You are a meticulous code reviewer. Do not edit files.", "allowedTools": ["read", "list", "search", "find", "git"] }
Token budget
The thinking spinner shows context usage once you're past ~50% of the model's
context window (▓ 72% ctx). Jarvis warns at 80% and auto-compacts the
conversation at 95% so long sessions don't fall off the end. Window sizes per
model live in src/cli/commands/cost.ts.
.jarvisignore
A gitignore-style file at the workspace root extends the built-in ignore set
(node_modules, .git, dist, …) for search and find_files — useful in
monorepos where you want some packages excluded:
# .jarvisignore
packages/legacy/
*.generated.ts
/vendorMCP servers
Jarvis is an MCP client: declare servers under mcpServers in
.jarvis/settings.json (project) or ~/.jarvis/settings.json (global) and their
tools are discovered at startup and proxied into the agent as
mcp__<server>__<tool>.
// .jarvis/settings.json
{
"mcpServers": {
// stdio server (spawned as a subprocess)
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
},
// remote HTTP/SSE server
"github": {
"url": "https://api.example.com/mcp",
"headers": { "Authorization": "Bearer ${TOKEN}" }
}
}
}MCP tools always ask for approval before running (their side effects are
unknown). Add "disabled": true to skip a server without deleting it. The
official @modelcontextprotocol/sdk ships as a dependency, so no extra install
is needed.
Architecture
src/providers/— oneProviderinterface, one file per backend. Add a new model source by implementingcomplete()and registering it.src/tools/— the agent's capabilities: read, list, search (regex grep, ripgrep-backed with a Node fallback), find_files (glob), web_search / web_fetch (internet), write, edit, run command, git (git_status,git_diff,git_log,git_commit), plan,task(one sub-agent), anddispatch(sub-agents in parallel). Add a tool by implementing theToolinterface and listing it insrc/tools/index.ts; MCP tools are appended at runtime viaregisterTools().undo.tsrecords each change, powering/undo,/diff, and/checkpoint.ignore.tsloads.jarvisignore;search.ts/findFiles.tsconsult it.- The built-in
researcheragent uses the web tools to answer questions with cited sources.
src/mcp/client.ts— connects to configured MCP servers and proxies their tools into the registry.src/agent/agent.ts— the think → act → observe loop; user messages can carry base64 image parts for vision.src/cli/— the interactive terminal UI (mentions.tsexpands@file/@image,diff.tsrenders unified diffs,watch.tsis the chokidar file watcher,repl.tshandles multiline, pins, budget warnings, and/fork).
Sub-agents
The agent can delegate a self-contained subtask to a focused sub-agent (via
the task tool) that has the same tools and a fresh context. It runs to
completion and reports back, keeping the main conversation uncluttered. Nested
activity is shown with a ┊ guide, sub-agent tool calls still ask for approval,
and nesting is capped to avoid runaway recursion.
Named agents
Define reusable, specialized agents as markdown files in .jarvis/agents/
(project) or ~/.jarvis/agents/ (global), with their own role, tool access, and
model:
---
description: Reviews code for bugs and improvements
tools: Read, List, Bash
model: deepseek-reasoner # optional per-agent model
---
You are a meticulous code reviewer. … (becomes the agent's prompt)The main agent auto-delegates to a named agent when a task matches its
description. Manage and run them with /agent:
/agent list agents
/agent reviewer <task> run a named agent on a task
/agent new <name> scaffold a new agent fileSee examples/agents/ for a starter.
Sessions
Conversations auto-save per turn to ./.jarvis/sessions/. Resume them:
jarvis -c # continue the most recent session in this folder
jarvis -r # pick a past session to resumeInside a session, /resume opens a picker of past conversations, and /clear
starts a fresh one (the old transcript is kept).
Custom commands
Drop a markdown file in a commands directory and it becomes a /command:
~/.jarvis/commands/— available in every project./.jarvis/commands/— available in this project (wins on name clashes)
foo.md → /foo. The file body is a prompt template sent to the agent:
---
description: Review the current git diff
---
Run `git diff` and review the changes. Focus on: $ARGUMENTSPlaceholders: $ARGUMENTS (all text after the command), $1, $2, … (individual
args). If there are no placeholders, typed args are appended. Custom commands
appear in /help and the live menu, and can't shadow built-ins. See
examples/commands/ for starters.
Security
Jarvis has layered protections:
1. Per-action approval. Tools that change the world (write_file,
edit_file, run_command) prompt before running, with an arrow-key menu:
Run command
npm install left-pad
Do you want to proceed?
❯ 1. Yes
2. Yes, and don't ask again for: Bash(npm install *)
3. No2. Persistent permission rules. Choosing "don't ask again" writes an allow
rule to .jarvis/settings.local.json. Rules are merged across three scopes:
| Scope | File | Use |
| ------- | --------------------------------- | ----------------------------------- |
| user | ~/.jarvis/settings.json | applies to every project |
| project | ./.jarvis/settings.json | shared, commit to git |
| local | ./.jarvis/settings.local.json | machine-only (gitignored) |
// .jarvis/settings.json
{
"permissions": {
"allow": ["Bash(npm run *)", "Read(*)", "Write(src/*)"],
"deny": ["Write(.env)", "Bash(git push *)"],
"ask": ["Bash(rm *)"]
}
}Rule format is Tool(pattern) where * is a wildcard. Tools are Bash,
Read, Write, Edit, List. Decision order is deny > allow > ask >
prompt.
3. Workspace sandbox (app-level). File reads/writes/edits are confined to
the workspace root; .git/ is protected; obviously destructive shell commands
(rm -rf /, format, fork bombs, …) are blocked outright.
4. OS-level sandbox (the real boundary). On macOS and Linux/WSL2, shell
commands can be wrapped with Anthropic's
@anthropic-ai/sandbox-runtime
(Seatbelt / bubblewrap), which enforces the write boundary at the OS level so it
holds even if a command misbehaves. Enable it with:
npm install @anthropic-ai/sandbox-runtimeWindows note: the OS-level sandbox does not run on native Windows. For true isolation on Windows, run Jarvis inside WSL2 or a container. On native Windows, layers 1–3 are your protection.
Network: web_search and web_fetch reach the public internet (read-only
GET requests). They don't send your files anywhere, but they do contact external
servers — disable them by removing the tools from src/tools/index.ts if you
need a fully offline setup.
