raunen

A small terminal agent for local LLMs.

One Go binary, no runtime, no server. Point it at Ollama, LM Studio, llama.cpp, vLLM, OpenRouter โ€” anything that speaks the OpenAI /v1/chat/completions format. It reads and writes files, runs commands, and keeps the conversation where you can see it.

curl -fsSL https://raw.githubusercontent.com/devjasha/raunen/main/install.sh | sh

macOS and Linux, Intel and ARM ยท verified against the release checksums ยท about 3 MB ยท free to run

~/Projects/raunen
  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 10:42
  โ–Œ what does main.go do?

    โบ read  main.go
      โ†ณ 84 lines

  It parses flags, loads the config, and starts either the TUI or a
  single one-shot turn.

  โ€ข --continue resumes the last session for the directory
  โ€ข a prompt as an argument skips the UI entirely

  โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
  โ”‚ โ€บ                                                          โ”‚
  โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
  auto ยท โއ main ยท qwen3.5-8k:latest ยท โ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ 22% ยท 1.8k

What it is

An agent that works in the directory you start it in. Tools are rooted there, so raunen in a project is what gives it something to read. There is no separate window and no web UI โ€” a running agent has nowhere else to put things.

Any endpoint

Adding a provider is a base URL, not adapter code โ€” they all speak the same wire format.

Eight tools

read, write, edit, list, bash, grep, glob and result โ€” plus anything an MCP server brings along.

Three modes

tab cycles auto, accept edits and plan. The mode goes into the system prompt, so the model knows the rules.

Sub-agents

Investigation is delegated to a sub-agent with its own empty context, which returns only its answer. Several run at once.

Sessions

The conversation is saved per directory. raunen --continue picks it back up tomorrow.

Visible context

A bar in the status row, because running out of room is the most common cause of a bad answer.

Skills & instructions

Save a checklist as a SKILL.md and pull it in with #, or drop an AGENTS.md in the repo so the agent learns the project's conventions.

Search without the shell

grep and glob are first-class tools, not bash commands โ€” so they always run and never trip plan mode.


Local first, hosted when it matters

Everything runs on the local model โ€” free, unmetered, private โ€” until a conversation outgrows its window, at which point it moves to a roomier one without dropping anything it has already found.

That is the whole design in one exchange: cheapest thing that works, a bigger one only when the work demands it, and no memory lost in between.

What it costs to run โ†’

escalation
auto ยท โއ main ยท qwen3.5-8k:latest

    โบ read  README.md          โ†ณ 210 lines
    โบ read  internal/ui/ui.go  โ†ณ 196 lines

  The UI is a terminal user interface that takes
  the alternate screen โ€ฆ

    โ‡… switched to omniroute/auto/best-coding
      โ€” context full at 8192 tokens

auto ยท โއ main ยท auto/best-coding ยท โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ 0% ยท 5.9k

Every token is spent on purpose

A small model lives or dies by what is in its window. Most of what fills one is not the work โ€” it is a test run the agent read once and now re-sends every single turn. Four things keep that from happening, and they matter most on the models that cost nothing.

Big results are kept, not pasted

A build log is four thousand lines of which six matter, and which six is not knowable until the model looks. So a large result is stored whole and only its head goes into the conversation, with a handle for the rest.

The model searches the full text through that handle, or pages through it. Only what it asks for is charged to the context โ€” an 85 KB test run costs 2.2 KB, and the other 82 KB never enters the conversation, so it is not in every later request either.

a failing test run
    โบ bash  go test ./...

      ok   pkg/thing1   0.01s
      ok   pkg/thing2   0.02s
      โ€ฆ
      ... [2919 more lines, 84828 bytes total. Kept as r1:
      call result with a match pattern to search it.]

    โบ result  {"id": "r1", "match": "^FAIL"}
      โ†ณ 3001: FAIL raunen/internal/widget

  One package fails to build. Looking at it now.

Summarise before forgetting

When the window fills, one model call writes down what the older messages established โ€” paths, decisions, what is still open โ€” and the summary goes in where they were. Typically 240k โ†’ 31k tokens. Only if that is impossible are messages dropped, and it says so plainly when it happens.

The recent tail stays verbatim

Whatever you are working on right now is worth more in full than in prรฉcis, so the last stretch of the conversation is never summarised. /compact does it on demand, before the window forces the issue.

Output is cleaned first

ANSI colour codes, progress bars redrawn over themselves and repeated lines are stripped before anything is charged to the context. On tidy output that saves nothing; on a noisy build it saves a great deal.

Searching happens elsewhere

A sub-agent gets its own empty context and returns only its answer, so a long investigation never sits in the main conversation being re-sent. Several run at once.

The practical difference: a 32k window that compacted twice during a build-fix loop now does not compact at all. What it costs to run โ†’


The dashboard is in the conversation

/status answers the questions that otherwise need guessing: whether an endpoint is actually up, which ones are missing a key, how close the context is to full, and what the agent will switch to when it runs out of room.

Everything known locally appears at once and the endpoints fill in as they answer, because a report you have to wait for is a worse report.

/status
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ status
  version   v0.7.0
  model     ollama/qwen3.5-8k:latest  ยท  8192
  mode      auto
  context   940 of 8.2k  (11%)
  ladder    18 models
  subagents on
  providers ollama      3 models     :11434
            lmstudio    unreachable  :1234
            openrouter  411 models   needs key

Levels you actually earn

The dragon is not decoration: it grows on the one thing every provider charges in, which is context. Feed it enough โ€” across every model, every session โ€” and you climb from a quiet Hush to a roaring Thunder.

It is yours, not a model's, and it carries forward between sessions, so the work you put in shows up next time you open raunen.

How levels work โ†’

1Hush
2Whisper
3Murmur
4Rumour
5Echo
6Chant
7Chorus
8Bellow
9Roar
10Thunder

Getting started

Three steps, and the third one is asking it something.

shell
# 1. have a model to talk to โ€” anything speaking the OpenAI API
$ ollama pull qwen3.5

# 2. run it in the directory you want to work in
$ cd ~/Projects/my-thing
$ raunen

raunen: no default model set, using ollama/qwen3.5:latest

# 3. ask it something. /help lists everything, ctrl+c leaves.

The first run writes ~/.config/raunen/config.json and, since no model is configured yet, asks your endpoints what they have and picks one โ€” preferring anything local. Read the docs or the full README.

Or skip the UI entirely and get one answer back:

shell
$ raunen --json 'summarise the diff on this branch'
  โ†’ a single JSON document on stdout, ready for a script

Pass a prompt as an argument for a one-shot turn, or --json for machine-readable output with an exit status. See scripting.