Skip to main content

scoot

PyPI tests Python 3.9+ Dependencies: none Platform Providers License: MIT

       ╭───╮      scoot: a tiny coding agent that goes where you point it.
       │o o│
    T──┤───┤      pipx install scootcli
    │  ╰┬─┬╯      scoot
  (o)═══╧═╧═(o)

scoot is a terminal coding agent in plain Python. You type what you want in natural language; it reads, searches, edits, and runs things in your repo, asking before anything risky. It talks to official model APIs (OpenAI, Anthropic, and a local Ollama for free) and has zero third-party dependencies: the whole tool is the Python standard library, and it ships as a single-file zipapp as well as a wheel.

Where this comes from

scoot began as mini_agent, a fifty-line Python script written to answer one question: where exactly does a chatbot turn into an agent? The answer was a while loop that sends the conversation to a model, runs whatever tool the model asks for, appends the result, and goes around again until the model answers without calling a tool. The article Building an AI Agent from Scratch: No Magic, Just a Deterministic Loop (free link) walks through that script, swaps the cloud model for a local one, and adds tools and MCP on top of the same loop. Its conclusion is the design brief for this tool:

There's no magic. The model observes the conversation history, decides whether it has enough to answer or needs a tool, and repeats until it's done.

Build the naive version first. Then decide.

The naive version did real work in my repos for long enough that the next step was obvious: keep the deterministic loop at the centre and build the rest of a proper command-line tool around it, approvals, sessions, a REPL, and a provider layer, without adding a framework or a dependency.

Quick start

pipx install scootcli            # or: pip install scootcli
scoot auth set openai            # paste your OpenAI API key once (hidden input, validated, stored 0600)
cd ~/code/your-project
scoot                            # open the REPL

Or run entirely local with Ollama, no key at all:

ollama pull llama3.2
scoot --model ollama/llama3.2

The first prompt:

❯ add a --version flag to cli.py
  I'll read cli.py, then add the flag.
  ● read_file {"path": "cli.py"}
  ✔ read_file  128 lines
  ● edit_file {"path": "cli.py", ...}   (+6 -0)
  ✔ edit_file  cli.py +6 -0
🛴 scoot
  Added --version to the parser; it prints the package version and exits.

Providers and models

Models are addressed as provider/model. A bare name means the default provider, which is the first provider that has a key, else Ollama.

provider how it is reached key default model
openai OpenAI Responses API OPENAI_API_KEY gpt-5.3-codex
ollama local Ollama, Responses API none llama3.2
anthropic Anthropic Messages API ANTHROPIC_API_KEY claude-opus-5
scoot models                         # every configured provider, grouped
scoot models --provider ollama       # one provider
scoot --model openai/gpt-5.3-codex "..."
scoot --model auto "..."             # pick a model per prompt from the live list (cheap for trivial, strong for edits)

Inside the REPL, /model <provider/model> switches and is remembered for the next launch; /model default goes back to the provider's preferred model. SCOOT_EFFORT (low | medium | high | xhigh, default medium) sets the reasoning effort for models that take it, on both OpenAI and Anthropic. On Claude Opus 5 the server-side refusal fallback is requested by default, so a declined request is retried on another Claude model inside the same call; SCOOT_ANTHROPIC_FALLBACKS=0 turns that off.

A note on how this is built: scoot speaks the OpenAI chat format internally and translates at the edge. Adding a provider that speaks that format is one registry row; a different wire format is one small adapter (src/scootcli/providers/).

Configuration

Settings resolve as CLI flag → environment variable → project .env → global .env → default.

Two optional .env files are read: ~/.config/scoot/.env (the stable place for keys) and the nearest .env walking up from the current directory. Only scoot's own keys are imported from them: SCOOT_*, provider API keys, and HTTPS_PROXY / NO_PROXY. A project's other secrets never enter scoot's process through a .env file.

cp .env.example ~/.config/scoot/.env && chmod 600 ~/.config/scoot/.env

The most useful settings (see .env.example for all of them):

setting meaning default
OPENAI_API_KEY OpenAI key (or scoot auth set openai)
SCOOT_PROVIDER default provider for bare model names first with a key, else ollama
SCOOT_MODEL default, auto, or provider/model default
SCOOT_EFFORT reasoning effort medium
SCOOT_APPROVAL always · auto-read · auto-edits · yolo yolo
SCOOT_MAX_STEPS tool-call steps per turn before asking to continue 50
SCOOT_OLLAMA_BASE_URL where Ollama listens http://localhost:11434/v1
HTTPS_PROXY proxy for hosted providers; localhost is never proxied

Usage

scoot                                # interactive REPL
scoot "explain what a Python dataclass is"   # one-shot turn, then exit
scoot explain src/auth.py            # preset: explain a file (read-only)
scoot edit cli.py -m "add a --version flag"  # preset: edit with an instruction
scoot --continue                     # resume the most recent session for this directory
scoot --resume <id>                  # resume a specific saved session
scoot --yes "fix the failing test"   # auto-approve every tool call (scripting/CI)
scoot --approval auto-edits "..."    # auto reads and edits, prompt only for shell
scoot --json "..."                   # machine-readable result (never streamed)
scoot --verbose "..."                # model and token usage on stderr
scoot models --json                  # machine-readable model list
scoot auth                           # which providers have a key
scoot auth set openai                # save a key; scoot auth clear openai forgets it
scoot --no-logo                      # hide the mascot; /logo off remembers it
scoot --no-panel --no-dock           # plain prompt, no status bar (also what you get without a TTY)

In the REPL

/help      list commands            /reset     clear the conversation
/status    provider, model, tokens  /save FILE dump the transcript
/init      scan project → AGENTS.md /compact   summarize and shrink context
/model     list or switch model     /approve   set mode (always|auto-read|auto-edits|yolo)
/yolo      auto-approve all         /worktree  isolate work in a git worktree
/auth      provider keys            /logo      show or toggle the mascot
/sessions  list saved sessions      /resume    resume a saved session ([id])
/forget    delete session(s)        /panel     toggle the bottom status bar
/verbosity feed detail (full|compact|quiet)
/c         copy last answer (Ctrl-S) /exit      quit (also Ctrl-C)

Press ESC while a turn is running to interrupt it; the conversation is kept. Type / and press Tab to complete slash commands.

Terminals. scoot works in macOS Terminal, iTerm2, and inside tmux; the status bar uses a scroll region, the input dock uses raw mode, and clipboard copy uses the system tool or an OSC-52 escape. Under tmux, ESC reaches scoot only after tmux's escape-time has passed, so with the default 500 ms the interrupt feels delayed; set -sg escape-time 10 in ~/.tmux.conf makes it immediate. For clipboard copy through tmux, set -g set-clipboard on (or external) lets the OSC-52 escape reach the outer terminal. Without a TTY, scoot falls back to a plain prompt with no bar and no dock.

Tools and approvals

The agent has eight tools: read_file, list_dir, search, write_file, edit_file, run_shell, open_editor (hands a file to IntelliJ IDEA's idea -e or to VS Code, SCOOT_EDITOR picks), and update_plan (a progress checklist for multi-step work). Every tool is sandboxed to the workspace root.

When a call needs approval you can approve once [a], trust that tool for the session [t], approve everything this session [A], edit the arguments [e], skip [s], or quit [q]. /approve <mode> sets how much runs without asking: always prompts for everything, auto-read auto-approves reads, auto-edits also auto-approves file edits, yolo runs everything. Catastrophic shell commands (a denylist: rm -rf /, git push --force, piping downloads into a shell, and so on) are re-confirmed in every mode.

For risky autonomous runs, /worktree start moves the work into a throwaway git worktree; /worktree merge or /worktree discard when done.

Streaming, images, sessions

Responses stream live and stay interruptible. Drag an image into the prompt and a vision-capable model describes it into the turn as text, so even a text-only coding model can act on it; SCOOT_VISION_MODEL pins the describer, --no-images turns the feature off. Every turn auto-saves under ~/.local/state/scoot/sessions/ (owner-only, secrets redacted, last 20 kept); scoot --continue or /resume picks up where you left off.

The status bar

The bottom row shows the mascot's face (its eyes follow the turn: o o idle, > > thinking, - - stopped), the provider, the workspace and session id, the model, the approval mode, context size against the auto-compact threshold, cumulative tokens, message count, and the last error if any.

Install options

pipx install scootcli                          # recommended: isolated, `scoot` on PATH
pip install scootcli                           # anywhere
curl -LO https://github.com/sergenes/scootcli/releases/latest/download/scoot.pyz && python3 scoot.pyz  # single file, no install
git clone https://github.com/sergenes/scootcli && cd scootcli && pip install -e .                       # from source

Requirements: Python 3.9 or newer on macOS or Linux. Nothing else: no compiler, no packages, no curl.

Development

pip install -e .
python -m pytest -q          # network-free suite
./scripts/build.sh           # dist/scoot.pyz + wheel + sdist

Design notes live in DESIGN.md, the behaviour spec in SPEC.md, what is next in ROADMAP.md, and the release history in CHANGELOG.md. New capability is a drop-in file: a tool in tools/, a slash command in commands/, a provider row or adapter in providers/.

Security

  • API keys are read from the environment or from ~/.config/scoot/credentials.json (directory 0700, file 0600), validated before saving, and never echoed; rendering.redact() masks key-shaped strings in all output.
  • Only allowlisted keys are imported from .env files.
  • All file and shell tools are sandboxed to the workspace root; destructive shell commands are always re-confirmed.
  • Saved sessions are owner-only with secrets redacted; /forget all removes them.
  • No third-party dependencies means no third-party code to audit.

Contributing

Stars and forks are welcome, and so is using scoot to improve scoot: it is a coding agent, so point it at its own repo and let it do the work while you review. Bug reports with a way to reproduce them are the most useful thing you can send.

Pull requests are welcome too, with one honest caveat: I intend to keep this tool small, so I will not merge most feature proposals. A feature gets in when it is clearly useful to most users of a coding agent, fits the stdlib-only constraint, and comes with tests. If you have an idea that does not meet that bar, a fork is the right home for it, and I am happy to link to forks that go somewhere interesting.

License

MIT, see LICENSE. Written by Sergey Nes.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

scootcli-0.2.0.tar.gz (150.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

scootcli-0.2.0-py3-none-any.whl (135.3 kB view details)

Uploaded Python 3

File details

Details for the file scootcli-0.2.0.tar.gz.

File metadata

  • Download URL: scootcli-0.2.0.tar.gz
  • Upload date:
  • Size: 150.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.2

File hashes

Hashes for scootcli-0.2.0.tar.gz
Algorithm Hash digest
SHA256 5ce3aee7e580b8dc625c549f04a1480f5845ccafb048658f558fcc97ee5cdc2b
MD5 203d66dfc3ffda91334e84ab0b03db9f
BLAKE2b-256 4e61aaebcab0ed2956bfa8981794f1b0882a36cc20120c2898220b5956644dc3

See more details on using hashes here.

File details

Details for the file scootcli-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: scootcli-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 135.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.2

File hashes

Hashes for scootcli-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 49e811dd6063a2c9a2de37a502a5940f9152ef007ba50185e45d2692413438c0
MD5 22078df3934d0bc842b269d9f61b910b
BLAKE2b-256 8cdcb80caae5aa14b99e27b45c8f4f4af2d1a4f68eb94714f385145e6ee2f860

See more details on using hashes here.

Release history Release notifications | RSS feed

0.3.0

2 files

This release

0.2.0 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page