Frontier quality. Local first. Chat with your PDFs and Office files, search the web, and connect MCP servers, all from the terminal. If no local agent is running, the CLI downloads the framework and models it needs and starts one itself.
It installs as docent, and as smartloop (its old name) so existing commands keep working; the two are the same binary.
More at: docs.smartloop.ai
macOS and Linux
curl -fsSL https://smartloop.ai/install | shWindows (PowerShell):
irm https://smartloop.ai/install.ps1 | iexThe binary goes to $CARGO_HOME/bin (~/.cargo/bin) when a Rust toolchain
already owns that directory, since it is on your PATH anyway; otherwise to
~/.local/bin. If the chosen directory is not on your PATH, the installer
appends an export line to the startup file for your shell — ~/.bashrc,
~/.zshrc, or fish_add_path in config.fish — so a new terminal picks it up.
Re-running the installer will not add that line twice.
On Windows the binary goes to %USERPROFILE%\.smartloop\bin and the installer
sets your user PATH through the registry. Restart the shell to pick it up.
Set SMARTLOOP_CLI_INSTALL_DIR to install elsewhere, or SMARTLOOP_CLI_VERSION
to pin a specific release.
Prebuilt binaries are published for Linux (x86_64, aarch64; glibc, with the Vulkan loader bundled), macOS (Apple Silicon, signed and notarized) and Windows (x86_64, signed). The agent is built in, with GPU inference through Metal on macOS and Vulkan on Linux and Windows.
On Linux the release folder goes to ~/.local/share/docent/<version>/, and
the bin directory gets symlinks to it.
Requires Rust (2024 edition), CMake and a C/C++ toolchain, since the built-in agent compiles llama.cpp. Pick the GPU backend with a feature:
cargo install --path . --features metal # macOS
cargo install --path . --features vulkan # Linux, Windows (needs the Vulkan SDK)
cargo install --path . # CPU onlyThe framework crate comes from Smartloop's public registry at
https://dl.smartloop.ai/crates/, declared in .cargo/config.toml; no
account or token is needed. scripts/update-smartloop.sh [version] moves it to
the newest (or given) release, and also picks up a version republished under
the same number; the Update smartloop workflow does the same on main
and can start a release after it.
All you need is docent. Run it and you're chatting: no account and no
separate agent setup.
docentThe first run downloads and starts the local agent for you (see First run). Everything below is optional:
- AI search:
/loginin the chat signs you in and enables web (AI) search. - Agent control:
docent agent stopstops the local agent anddocent agent startstarts it again.
Any command that talks to the agent starts it when none is running. It
listens on a free port it picks itself and writes it to
~/.smartloop/server.port, where the CLI reads it. On first use that means:
- Start the agent, which is built into the CLI (SLP framework 1.2.9), in
the background with
SLP_HOME=~/.smartloop, logging to~/.smartloop/server.log. An agent the chat started stops when it exits (unless anotherdocentis still open); one started withdocent agent startkeeps running. An agent Studio desktop runs on the same home is used instead, when it is the same framework version. - Download the embedding model (
bge-m3-Q4_K_M.gguf, ~417 MB) into the workspace'smodels/embeddings/folder for document search. - Run the agent's bootstrap, which downloads the decision model, creates the default project and loads the model.
Each step is skipped when its files are already there. Progress shows as a checklist on stderr under the Docent banner that redraws in place, with the active download's bar in Smartloop pink:
■ Start agent port 50578
■ Embeddings (bge-m3) 417 MB
■ Decision model sl-mini
██████████████▋░░░░░░░░░░░░░░░ 49% 377 MB/769 MB
□ Default project
□ Load model
□ Skills and connections
A step without a bar shows its elapsed time once it runs past a couple of
seconds, and it ends with ✓ Setup complete in 1min 12s.
When stderr isn't a terminal, each step prints one line as it finishes
instead. Enabling a model with /models shows the same checklist for its
download.
To do this up front, or to stop (and later restart) the agent. Optional; the agent starts on its own when needed:
docent agent start
docent agent stopThese live in the chat: /login signs in (optional; it unlocks AI search and
the models marked (sign in)), /project switches, creates, imports and
deletes projects, and /models enables and disables models. See the command
table under the chat.
Check which endpoint the CLI uses, whether the local agent is running there, which model it has loaded, and the per-project agents it has started:
docent agent statusEndpoint: http://localhost:50578
Status: healthy
Model: sl-mini (Q4_K_M, 32768 ctx, 769 MB)
Process: pid 8738, 250 MB
+--------------+------+-------+-------+------+--------+
| Project | PID | Port | Alive | Idle | Memory |
+--------------+------+-------+-------+------+--------+
| general_chat | 2668 | 62110 | true | 94s | 122 MB |
+--------------+------+-------+-------+------+--------+
Endpoint is the URL the CLI talks to (SMARTLOOP_API_URL, or the default).
The command exits with status 1 when the agent can't be reached there.
Start an interactive chat with the local agent:
docentdocent on its own is short for docent run. In a terminal this opens a full-screen app, laid out like Claude Code. While
a reply runs, a live status line above the prompt shows the agent's current
step (web search, document lookup, model selection) and for how long, with a
line per running download. Replies render as markdown, as in Claude Code:
headings, bold and italics, lists, quotes, syntax-highlighted code, and tables
drawn to fit the width. The finished reply keeps its sources and the model
that answered:
> what is the capital of France?
■ Paris is the capital of France.
References
[1] https://en.wikipedia.org/wiki/Paris
⎿ sl-mini · 7 tokens · 0.4 tok/s · 16s
[-] Reading en.wikipedia.org… (4s)
╭──────────────────────────────────────────────────────────────────────╮
│ > │
╰──────────────────────────────────────────────────────────────────────╯
[enter] send [esc] interrupt [?] shortcuts
It chats in the server's current project, or the one given with --project.
On exit it prints the session id, to resume with --session.
| Key | Does |
|---|---|
? |
shortcuts |
Shift+Enter, Alt+Enter, Ctrl+J |
new line |
Esc |
interrupt the reply |
wheel, PgUp/PgDn |
scroll; drag to select and copy |
| drop a file | attach an image (PNG, JPEG) or document (PDF, Office, CSV, text) |
drop a .zip |
on an empty prompt, fills in /project import for it |
Ctrl+O |
models: enable, disable, download |
Ctrl+P |
projects: switch, create, import, delete |
Ctrl+S |
web search on or off |
| Command | Does |
|---|---|
/login, /logout |
sign in in the browser (--token to paste one) |
/models |
enable, disable and download models |
/models <name> caps <list|auto> |
set a model's capabilities here, over the catalog's, as in text,vision,reasoning; auto goes back to the catalog's |
/mcp |
MCP servers; /mcp add <url> connects one |
/project |
projects: switch (in a new session), create, import, delete |
/project <name> |
switch to a project by its name or ID |
/project new <name> |
create a project and switch to it |
/project import <zip> |
import an exported project and switch to it |
/status |
account, model, agent and versions |
/usage |
web searches and credits left this month, tokens and cost saved |
/upgrade |
Pro plan: 1,000 web searches a month |
/code [on|off|auto] |
whether prompts in this folder are answered with code (see Coding); on and off mark the folder over what its files say, auto unmarks it |
/write [path] |
write the last reply's files that were left unwritten, or one of them |
/clear |
clear the chat and start a new session |
/<skill> [prompt] |
run one of the project's skills; / lists them with the commands |
!<command> |
run a shell command in the working directory, its output shown as it comes, each command of a script on a $ line over what it printed; the output goes to the agent with your next prompt, so it stays in the session. The prompt turns pink with ! ahead as it's typed, and the footer says shell mode, as in Claude Code |
!<command> & |
run it in the background, as a dev server: nothing waits for it, and it's listed under the prompt, out of the chat, until it ends |
/tasks |
the commands still running, as in Claude Code: ↑ ↓ pick one, Enter shows all it printed, x stops it; ctrl+b opens it too (twice under tmux, where it's the prefix) |
/stop [word] |
stop the shell commands still running, or those with the word in their command; a click on a running command's ✕ stop in its entry stops it too, and a click on its command expands all it printed |
/help, /quit |
Pass an initial prompt to send immediately:
docent run "what are some things to do in madrid spain?"Options:
docent run --project <project-id> # chat in this project
docent run --session <session-id> # resume an existing session; a new one is created when omitted
docent run --plain # line-by-line chat instead of the full-screen appWhen stdin or stdout isn't a terminal, or with --plain, run chats line by
line instead: without --project it lists your projects and asks which one to
chat in (press Enter for the current one), then keeps reading prompts from
stdin until EOF, /quit, /exit, /q, or exit. The response streams token
by token on stdout, and the agent's progress is printed on stderr as
[step] message lines, so it doesn't interleave with the answer. When the
answer draws on documents or web pages, the sources it used follow it on
stdout as a numbered list:
References
[1] https://releases.rs/
In the chat, /sync keeps the project you're in up to date with the folder
docent was opened in. It maps the folder into .docent/manifest.json (every
document and skill pushed: its hash, and the name or id it has at Smartloop),
then every few seconds pushes only what was added, changed or removed:
/sync sync this folder to the current project
/sync status what's synced, and what the next pass would push
/sync stop stop syncing this folder (/sync starts it again)
-
Opening
docentin a folder that isn't linked to a project yet gives it one of its own, named after the folder (a project by that name with no folder of its own is reused), writes the link to.docent/manifest.json, and syncs the folder to it from then on. A folder of more than 200 documents or 500 MB is linked but not synced until/sync --yes. Openingdocentin a linked folder, or one under it, opens the chat in its project and keeps syncing it, until/sync stop.--projectopens another project instead, and links nothing. -
The folder synced is the nearest one up from where
docentwas opened that holds a.docent/, as git finds its repository, so opening it in a subfolder of a synced project syncs the project. With none, it's the folderdocentwas opened in. -
Syncing runs while the chat is open, checking every 5 seconds and waiting while the chat is answering; changes made while it's closed go on the first check after it opens.
/syncon a folder already syncing says it's up to date. -
Your home folder (or one holding it) is never synced. A first sync of more than 200 documents or 500 MB asks first;
/sync --yesgoes ahead. -
Documents are the folder's PDF, Word, PowerPoint, Excel, CSV, Markdown and text files. Hidden folders,
.gitignoreand a.docentignore(same syntax) keep files out, and so are build output and dependencies always:node_modules,target,dist,build,vendor,venvand the like. A document in a subfolder is stored flat, asdocs__guide.pdf. -
.docentignorekeeps files out of the project without keeping them out of git. Put it in the synced folder (or any folder under it, for that folder's files) and list paths or patterns, one per line, as in.gitignore:README.md drafts/ *.csvA file ignored after it was synced is deleted from the project on the next pass, as if it had been removed; take it out of
.docentignoreto push it again. -
Skills are
.docent/skills/<name>.mdor.docent/skills/<name>/SKILL.md, with optionalname:anddescription:frontmatter. They are what you commit from.docent/; the manifest is kept out of git by.docent/.gitignore, as it names this machine's project. -
While it pushes, a note appears in the chat when something was pushed, a warning when something failed, and a line above the prompt says "Indexing N documents", counting down as the agent gets through them.
-
A document the project already has, by content, is taken up rather than pushed again, so a fresh
.docent/(or a lost manifest) doesn't upload the folder twice. A first sync also says which documents the project has that aren't in the folder; it leaves those alone, as they may have come from elsewhere. -
A document removed or changed before the project has registered its upload waits until the project lists it, then is deleted or replaced, so no copy is left behind.
-
A document or skill deleted at Smartloop is pushed again on the next pass. If the project itself is deleted, syncing stops;
/synclinks the folder to the current project instead.
Open docent in a code project and just ask for a change. It reads the
folder, writes the code, builds it, fixes what breaks, and then asks before it
touches anything outside your files:
› make greet take a name and commit it
← src/main.rs +2 −2
@@ -1,4 +1,4 @@
1 1 fn main() {
2 - greet();
2 + greet("docent");
3 3 }
4 -fn greet() { println!("hello"); }
4 +fn greet(name: &str) { println!("hello, {name}"); }
! cargo check --quiet
✓ done
? Run these in the folder?
$ git commit -am "greet takes a name"
[enter] run [tab] always this session [esc] skip
What happens on each prompt:
- It reads the project. The agent gets the file tree, the contents of
the files the prompt is about, and the git state (branch, remotes, what's
changed), so it answers from your code, and goes to the web only for what
the code can't tell it, like a library's current API. It's also told about
the machine (OS and version, shell, the package managers and toolchains on
PATH, active virtualenvs), so commands useapt-geton Ubuntu andbrewon a Mac. - You see diffs as they stream in. Each file shows as numbered hunks, additions in green and removals in red. Then it's written into the folder.
- It checks the build and fixes it. It runs a fast check for the kind of
project:
cargo check,go build,tsc --noEmit, orbash -nandpy_compilefor loose scripts. Errors go back to the agent, round after round, until the check passes or a round changes nothing.Escstops it. - Commands wait for your OK. Commits, installs and test runs come back
as shell commands.
Enterruns them,Tabruns them and approves every later one too, andEscskips them. Their output streams into the chat and goes back to the agent, so a failing test gets fixed next. - Long runs go to the background. Dev servers and watchers (
npm run dev &) keep running under the prompt while you go on chatting.
| Command | Does |
|---|---|
/code on|off|auto |
treat this folder as a code project, or not |
/write [path] |
write files a reply left unwritten |
!<command> [&] |
run a shell command yourself, in the background with & |
/tasks or ctrl+b, /stop |
see, expand or stop running commands |
Tab on an empty prompt |
turn auto-approve on or off |
More in the coding docs.
The CLI connects to the local agent on whatever port it picked
(~/.smartloop/server.port). Point it elsewhere with SMARTLOOP_API_URL:
SMARTLOOP_API_URL=http://localhost:9000 docent agent statusWith SMARTLOOP_API_URL set, the CLI only connects: it never installs or starts
an agent for that URL.
| Variable | Default | Effect |
|---|---|---|
SLP_HOME |
~/.smartloop |
Where the workspace, models and logs live |
SLP_PORT |
a free port | Pin the managed local agent to this port |
Released under the MIT License.
