CLI
Circle has one command, circle, and three subcommands: circle update, circle uninstall and circle schedule. Without options circle opens the full-screen interface in a folder you choose. With -p it runs a prompt and prints the answer.
circle [options] [folder] [@file ...] [message ...]
circle -p "prompt" [folder]
circle update [version] [--check]
circle uninstall [--purge] [--yes]
circle schedule <command> [name] [options]
Folder, messages and files
The words after circle are a folder, files and messages, in any order of options:
- The folder Circle works in comes first. It defaults to the current folder.
~is expanded and symlinks are resolved. It does not have to be a git repository. A first word without spaces is always read as a folder, so a mistyped folder name is an error and not a message. A message of one word goes after the folder:circle . refactor. - Messages are sent when the session opens, one turn each, in order. A message with spaces needs quotes.
circle "fix the failing test"works in the current folder;circle "fix it" ~/code/appworks too. Without a terminal, messages run as print mode. @pathadds a text file to the first message, as<file path="…">after it. The path is looked for in the current folder, then in the folder Circle works in. An image or a PDF goes as an attachment instead, from that folder or from anywhere else. A file that is missing or not text is an error. The conversation on screen shows@path; the model gets the text.--ends the options, so a message can start with-.
circle ~/code/app "explain how the router works" @src/router.ts
circle -p "review this" @src/app.ts "now list the risks"
Arguments and options
| Argument | What it does |
|---|---|
-p, --print [PROMPT] |
Send the prompt, and any messages after it, one turn each; write the last answer to standard output and exit. See Print mode. |
--mode json |
Like -p, but write every step to standard output as one JSON object per line. See JSON events. |
--mode rpc |
Run as a child process driven by JSON commands on standard input, until it closes. See RPC mode. |
-c, --continue |
Go on with the most recent conversation in this folder. Works with the full-screen interface, -p, --line and --mode. See Sessions. |
-r, --resume |
Choose a saved conversation from a list, then open it. Full-screen interface only. See Sessions. |
--session ID |
Reopen a saved conversation by its id, or by the end of it when only one matches. A conversation of another folder is copied into this one. /resume lists the ids. |
--session-id ID |
Open the conversation of this folder whose id is exactly ID, or start a new one with that id. An id is letters, digits, ., _ and -, starting and ending with a letter or digit. Useful in scripts that come back to the same conversation. |
--fork ID |
Start a new conversation in this folder with a copy of a saved one, from any folder. The original is not changed. Combine with --session-id to choose the new id. |
--no-session |
Keep the conversation in memory only. It is not saved and not listed in /resume. |
-n, --name NAME |
Give the conversation a title, as /name does. |
-m, --model NAME |
Use this model id for this run. It is not saved; alt+d in /models inside a session saves one. |
--thinking LEVEL |
The thinking depth for this run: minimal, low, medium, high, xhigh or max. It is not saved. See Models. |
--models PATTERNS |
The models ctrl+p switches between in this run, comma-separated, such as step-3.7-flash,step-5-*. In place of enabled_models in settings. |
--export ID [FILE] |
Write a saved conversation as HTML, or as a JSONL bundle when FILE ends in .jsonl, and exit. FILE defaults to <id>.html in the current folder. See Sessions. |
--list-models [SEARCH] |
Print the models the endpoint offers and exit. With words, only the models that contain all of them. The current model is marked (current). |
--system-prompt TEXT\|FILE |
Replace Circle’s own instructions with this text, or with the file’s text when it names a file. The instruction files, the environment and anything appended still follow. See Configuration. |
--append-system-prompt TEXT\|FILE |
Add this text, or the file’s text, to the end of the system prompt. Can be given more than once. Replaces APPEND_SYSTEM.md for this run. |
-nc, --no-context-files |
Do not read AGENTS.md or CLAUDE.md, in the project or elsewhere. |
-t, --tools LIST |
The model gets only these tools, comma-separated. pi’s names work too: read, write, edit, bash and find mean read_file, write_file, edit_file, execute and glob. |
-xt, --exclude-tools LIST |
The model does not get these tools. |
-nt, --no-tools |
The model gets no tools. |
--yolo |
With -p, --line or --mode: run commands and file changes without asking. See Print mode. |
--trust |
Trust the folder for this run and remember it in trusted_folders, including when nothing is at a terminal. A folder already trusted, or sitting inside one, does not need it. See Print mode. |
--approve-hooks |
Approve the folder’s project hooks files as they are now, without a card, and remember that version. Standard error lists each hook it approved in print, line and rpc mode. See Hooks. |
--extensions |
With -p, --line or --mode: load MCP servers and enabled extensions, which print, line and rpc modes otherwise leave out. See Print mode. |
--verbose |
With -p or --line: show each tool call, calls not run, failed results, retries and the tokens used on standard error. |
-v, --version |
Print the version and exit. |
--task [NAME] |
Work in a folder of Circle’s own under the task folder, named NAME or today’s date and a short id: for work that belongs to no project. The folder is made and trusted. Without the flag, Circle still works in the folder you started it in. See Tasks with no project. |
--print-home |
Print the data folder (see Configuration) and exit. Nothing is created. |
--init |
Run model setup again, even if Circle is already set up. See Setting up again. |
--line |
Use the plain line-by-line mode instead of the full-screen interface. |
-h, --help |
Show usage. |
-p can also come first as a flag: in circle -p -c "what changed?" ~/code/app the first word after the options is the prompt and the second is the folder.
A tool left out with --tools, --exclude-tools or --no-tools is not offered to the model, and a call to it anyway is answered with an error instead of being run. The limit applies to the main agent; a subagent started with task keeps its own tools, so leave out task too when that matters. compact_conversation is always offered.
Some options cannot go together, and Circle stops with exit code 2 when they are: --fork with -c, -r, --session or --no-session; --session-id with -c, -r or --session; --no-session with anything that opens a saved conversation; -r with -p, --line, --mode or messages; --line with --mode or messages; --mode rpc with messages or @files.
Print mode
circle -p runs one turn, or one per message, and exits. The last answer is the only thing written to standard output, so it can be piped or captured:
circle -p "Summarize README.md in one sentence"
git diff | circle -p "Review this change"
circle -p -c "Now write the tests for it"
Piped input is put before the prompt. When you give a prompt, Circle waits up to three seconds for piped input to start and then goes on without it, so a script that leaves standard input open does not hang it; standard error says so. Use </dev/null to skip the wait. With no prompt, the piped input is the prompt.
Nobody can answer an approval card in print mode, so each call that would ask is decided by a rule:
- Without
--yoloit is not run, and the model is told it needs--yoloor approval. Listing, reading and searching need no approval, so a question about the code can still be answered. Standard error says how many calls were not run. - With
--yoloit runs, except the calls Circle always asks about: deleting,rm -rf, force-push and the other cases listed in Security. Those are still not run. - A command matching an
allowed_commandspattern in the settings runs with or without--yolo, one that always asks included. See Security. - Commands the policy refuses (
sudo, credential files) are refused as in a session.
A question from the model comes back to it as text, and it asks the question in its answer.
Background jobs the model started (commands, subagents, watches) are waited for after its answer: when one ends, the model gets its notice and answers again, and that answer is the one printed. The wait lasts up to CIRCLE_JOB_WAIT seconds (1800 by default, 0 does not wait) and ten such answers; what still runs then is stopped. Processes a command left running, usually servers, are stopped at once. Background subagents follow the same approval rule.
Print mode does not load MCP servers, extensions or custom commands, unless you add --extensions: then MCP servers and enabled extensions load before the first prompt, as in the full-screen interface, and their tools are there from the first turn. Custom commands still are not. It does apply credential_files and a project’s .circle/settings.json. The conversation is saved, so circle -c (with or without -p) can go on with it.
Print mode, line mode and RPC mode need Circle set up and the folder trusted. When standard input is a terminal, they ask the setup and trust questions line by line first; otherwise they stop with exit code 2, unless you pass --trust, which trusts this folder and remembers it for later runs. A trusted parent covers the folders inside it.
A project hooks file runs only in a version you approved, and these modes cannot show the card that asks. A file that waits does not run; standard error names it once for the run and says how to approve it: with circle in a terminal in that folder, or with --approve-hooks. See Hooks.
| Exit code | When |
|---|---|
0 |
The model answered. |
1 |
No answer: the request failed, or the turn ended without text. The reason is on standard error. Also an unknown --session, or -c with nothing saved in this folder. |
2 |
A usage error: no prompt, an unknown option, a missing @file, options that cannot go together, a folder that does not exist, a settings.json that cannot be read, and without a terminal: settings not set up or the folder not trusted. |
130 |
Interrupted with ctrl+c. |
JSON events
circle --mode json "prompt" runs like -p and writes one JSON object per line to standard output, for a program to read. Errors are also written to standard error.
type |
Fields | When |
|---|---|---|
session |
id, workspace, model |
First. |
turn_start |
message, absent for a turn started for finished jobs |
Before each prompt is sent. |
assistant |
id, text, tool_calls (each id, name, args), usage (input_tokens, output_tokens, cache_read_tokens, and cache_write_tokens when the endpoint reports it) |
Each time the model answers, with or without tool calls. |
tool_result |
id (the call’s), name, status (success or error), output |
Each tool result. |
not_run |
name, args, reason (why the call would ask, such as runs a shell command or destructive operation) |
A call that is not run because nobody can approve it. Its tool_result follows with the error. |
job |
event (started, updated, ended), job (id, kind, title, status, reason, exitCode, startedBy, elapsed in seconds, output, sessionId) |
A background job started, changed or ended. |
compaction |
phase, trigger, and as the phase has them tokens_before, tokens_after, summarized, kept, file, seconds, message |
A compaction started, moved on, ended or failed. |
subagent_event |
event, the event’s fields, tags (subagent, name, and job_id for a background one) |
Something a subagent did. After an info event whose model_notice is a retry, the text a subagent streams (llm_token) starts over. |
turn_end |
answer, usage (this turn) |
When a prompt’s turn ends. |
error |
message |
The run stopped. |
circle --mode json "list the TODOs" | jq -r 'select(.type=="turn_end") | .answer'
The exit codes are those of print mode.
RPC mode
circle --mode rpc [folder] keeps running and takes one JSON command per line on standard input: prompts, steering, follow-ups, stopping, switching models, listing and stopping jobs. The work it starts is written as the JSON events above. See RPC mode for the commands.
Scheduled tasks
circle schedule keeps prompts that run on a clock. Prompts that stand until the screen
is closed are background jobs; prompts that stand until tomorrow
morning are schedules, and they run headless whether or not a terminal is open:
circle schedule add notes "summarize yesterday's commits in NOTES.md" --daily 09:30
circle schedule start
circle schedule --help lists the commands: add, list, show, pause, resume,
remove, run, tick, status, start, stop and daemon. Like update and
uninstall, the subcommand is read before any option: to open a folder that is called
schedule, write ./schedule. See Scheduled tasks.
Updating
circle update [version] [--check]
| Option | What it does |
|---|---|
| (none) | Install the newest release. |
--check |
Say whether a newer release exists. Install nothing. |
version, --version X.Y.Z |
Install that release instead, including an older one, to go back. |
circle update works on a copy that install.sh or install.ps1 put in place. It asks GitHub for the newest release of the repository recorded at install time and downloads the file for your operating system and processor. On a terminal one line shows how far the download has got, downloading circle-1.1.0-darwin-arm64.tar.gz 45% 23.6/52.4 MB 9.6 MB/s; elsewhere one line says what it downloads. ctrl+c stops the download and changes nothing; a download that gets no data for a minute stops by itself. Then it runs the copy of the installer that came with the running version on that file, with the same folders: the installer checks its sha256, runs the new program once, and only then switches to it, saying each step in a line that starts with [circle-install]. After it switches, it prints what’s new: a link to the release notes of every version after the one you had, up to the one you installed. When an updater older than 1.10.0 runs the current installer, the installer prints the target release’s link instead, without requesting release history. It also says how much space the kept older copies use under versions/, and the command that removes one of them once nothing is still running from it. See Installation and updates.
If the release lookup comes back HTTP 403 or HTTP 429, or the request never gets an answer, the message says GitHub may be rate limiting this machine or the network blocked it, and to run circle update again.
A copy that runs from a git checkout is not changed: circle update stops with circle update requires an installer-managed installation. Update a checkout with git pull, npm ci and npm run build. To open a folder that is called update, write ./update.
| Code | When |
|---|---|
0 |
Updated, already up to date, or --check finished. |
1 |
It could not: GitHub was not reachable, no release matches, the download stopped or was cancelled, the version is not a version like 1.0.0, the installer failed, or this copy was not installed by the installer. |
If GitHub is reached through a proxy that inspects HTTPS, give Circle its certificate with SSL_CERT_FILE=/path/to/ca.pem. circle update downloads with it too, so the installer’s own setting (CURL_CA_BUNDLE on macOS and Linux, the Windows certificate store on Windows) matters only for the one-command install. See Known issues.
The reminder
When the full-screen interface starts, Circle checks once a day whether a newer release exists, and if it does, adds one faint line to the conversation: Circle 1.1.0 is available (you have 1.0.0) · run `circle update`. The check is a HEAD request to github.com/<repo>/releases/latest, made in the background; it sends nothing beyond what any web request carries. The answer is kept in update-check.json in the data folder. Print mode, line mode and RPC mode never check.
Turn it off with "update_check": false in settings, or CIRCLE_NO_UPDATE_CHECK=1 in the environment.
Uninstalling
circle uninstall [--purge] [--yes]
circle schedule <command> [name] [options]
| Option | What it does |
|---|---|
| (none) | Remove the installation. On a terminal, ask first. |
--purge |
Also delete the data folder, ~/.circle (or CIRCLE_HOME), with the settings, keys and sessions in it. |
-y, --yes |
Do not ask. Required without a terminal. |
circle uninstall removes what the installer put on the machine: the circle launcher, every version under the prefix with current.ref and installation.json, and the PATH change — the lines marked # circle path in ~/.zshrc or ~/.bashrc, or on Windows the launcher’s folder in your user PATH. The data folder stays unless --purge deletes it too. On a terminal it lists what goes and asks; anywhere else it needs --yes. Files of other programs in the prefix folder, and a startup-file block for another folder, are left alone.
Like circle update, it works on a copy that install.sh or install.ps1 put in place: a git checkout is not touched, and the command stops with circle uninstall requires an installer-managed installation. It also stops, changing nothing, while another circle session runs from the same installation. On Windows it lists the running programs only when a program of the installation is in use; if that list takes longer than 30 seconds, or no process in it runs the program in use, it names the program and stops the same way. On Windows the launcher and the running version’s own files are still in use while circle runs; a small helper removes them, and the launcher folder and prefix when nothing else is left in them, a moment after this session ends. To open a folder that is called uninstall, write ./uninstall.
| Code | When |
|---|---|
0 |
Removed. A PATH entry that could not be removed is a warning, not a failure. |
1 |
The question was declined, another session is running, the copy was not installed by the installer, the receipt could not be read, or a removal failed. |
2 |
An unknown option, or no terminal and no --yes. |
When the Windows process check stops because an executable is in use and no process was identified, its error includes the last captured query boundary, bounded marker counts, the native exit or timeout code, the signal and process ID the query runner reported, and how much output it returned, in UTF-16 code units and lines; the output itself is not shown. A missing marker or runner value is unknown; a count of 32 may be capped. These observations do not identify the operation that stalled: reaching COMPLETE does not establish a successful query, a reported process ID does not establish that the query started, and a reported signal does not establish what stopped it.
The desktop application is removed separately: on Windows through Settings → Apps, on macOS and Linux by deleting the application.
Full-screen and line mode
Circle uses the full-screen interface when both standard input and standard output are terminals, -p, --line and --mode are not given, and CIRCLE_NO_TUI is not 1, true, or yes. Otherwise it runs line mode, or print mode when there are messages.
Line mode reads one prompt per line and prints each answer, all in one conversation:
printf 'Summarize README.md in one sentence\nNow list its sections\n' | circle ~/code/my-project
Approvals follow the same rules as print mode, and --yolo and --verbose work the same way. When a background job ends, standard error says so (Background job j3 ended.); the model reads its notice with your next line. Leaving stops the jobs still running. It does not load MCP servers, extensions, or custom commands, unless you add --extensions (custom commands never). /exit (/quit, /q) leaves and /help lists those two. Any other line shaped like a command, such as /compact or a misspelt one, is not sent: standard error says it works in the full-screen interface only. A path such as /usr/bin/env is missing, or a line that starts with a space, is sent as a message.
Exit codes
| Code | When |
|---|---|
0 |
Normal exit, --version, --print-home, --help. Leaving the setup or trust question of the full-screen interface also exits 0. |
1 |
Setup or the trust question was left unanswered in line mode, the last line’s turn failed in line mode, an unknown --session, -c with nothing saved in this folder, or Circle crashed. |
2 |
A usage error: an unknown option, options that cannot go together, a folder that does not exist, a settings.json that cannot be read, an unknown --export session. Without a terminal: settings not set up, or the folder not trusted. |
130 |
Line mode stopped with ctrl+c. |
Print mode has its own codes, listed above.
Setting up again
circle --init runs the same setup as the first start. An empty enter keeps the saved URL, so you can fix the key without typing the URL again. It keeps the saved key only while the URL stays on the saved endpoint’s host and port; a URL on another host needs its own key.
It replaces only the connection, auth in settings.json: endpoint, protocol and model. Everything else stays, including trusted_folders, mcp_servers, extensions, credential_files, theme and keys Circle does not know. When the endpoint changes, enabled_models is cleared, since it named the old endpoint’s models. credentials.json is merged, so earlier keys stay.
Inside a session, /login asks the same questions and switches the session without a restart. See Change the endpoint or the key.
To change only the model, pick it in /models inside a session and press alt+d instead. See Settings.