miniouto
A minimal, file-driven CLI agent harness built on coreouto.
Three principles:
- Minimalism — No bloat. Extend with styles.
- Automation-friendly — Full CLI; TUI is optional.
- Fluidity — Adapts to any environment. Delegation is just a
miniouto chat "<brief>" --style <style> --role <tag>shell command in a separate process, so a brief fits any harness the same way.
Preview
Install
uv tool install miniouto
# or
pip install miniouto
License
Quick start
# Either add a custom provider by hand:
miniouto provider custom add \
--name openai \
--api-key sk-... \
--base-url https://api.openai.com/v1 \
--default-model gpt-5.5 # optional; used when neither chat --pm nor the session pin names a model
# Or browse the lma (llm-model-api) catalog and add from there:
miniouto provider providers # see all 144 catalog providers
miniouto provider add Anthropic --api-key sk-ant-... # adds it with the first catalog model
miniouto provider default openai
miniouto style set default
miniouto chat "hello"
miniouto # TUI mode
Computer use (GUI control)
The outo agent can operate GUI applications inside a virtual headless display (via py-Vwayland): launch apps, take screenshots, click, type, scroll, drag. Enabled automatically on Linux x86_64 (glibc ≥ 2.28) — no setup needed; the tool simply doesn't appear on unsupported platforms. Set MINIOUTO_COMPUTER=0 to disable it explicitly. Requires a vision-capable model so the agent can see its screenshots.
Screen dumps are written to ~/.miniouto/computer-screens/ as Unicode .art: eight sub-pixels per terminal cell, each cell drawn as a solid █, a BLOCK OCTANT (Unicode 16.0) when it is two crisp solid regions, or BRAILLE dots when it is a blend, each in truecolour fg/bg. View one yourself with miniouto computer show [file] (add --plain for a luminance ramp). Old halfblock-truecolor dumps still render unchanged.
Delegation
Delegation is a Bash command, not an in-process tool, and there is no separate spawn command — a delegated run is a miniouto chat run. The agent runs:
# background (fire and forget): detach, write the answer to a file, alarm on completion
miniouto chat "<brief>" --style <style> --role <tag> --bg --pm <provider>/<model> --alarm-session <session> --return
# foreground: same thing, answer inline in the tool result
miniouto chat "<brief>" --style <style> --role <tag> --pm <provider>/<model> --return
Each delegated run is its own process (with --bg, detached, so it survives the turn that started it) and is mechanistically identical to an outo run — same tools, same chain, same watchdog. Only four things differ, each one a flag: --style <style> --role <tag> selects a top-level <tag>...</tag> body from that style as the system prompt (omit --role to run the <outo> body), --pm 'PROVIDER/MODEL[:REASONING]' takes provider/model/reasoning outright, and bundled styles write it with the {subagent_pm} token so it always names the effective subagent_* trio (this run's session pin first, then the global default); --use-subagent-provider resolves that same trio at call time when a hand-written command carries no --pm, --alarm-session <session> names the session that receives the completion message, and --return writes the final answer as markdown (bare = ~/.miniouto/subagent-results/; the file holds only the answer text). Every value is spelled out: --role requires --style, --alarm-session requires a session name, and --pm carries a concrete provider/model, because a command that reads settings.style or settings.session behind your back is not the same command twice. Bundled styles are taught with {style} / {this_session} / {subagent_pm} tokens that expand into literal values per run, so what the model copies is always self-contained. --return is the only flag whose value is optional.
When the run finishes it writes that file and inserts exactly one completion message into the target session's inbox. That message's first line is always [SYSTEM ALARM - THIS IS NOT A USER MESSAGE], so the agent can tell it apart from a real one, and it names the run's own Session: <name> — <path> so the receiver can open that transcript. Every chat run writes its session file, delegated or not; --answer-only / -a suppresses stdout only. A delegated run never changes your active session, though: it mints its own chat-/spawn- session name, writes its transcript there, and leaves settings.toml's session exactly where your plain miniouto chat left it.
Alarms are wakeups
A chat run never waits. It answers its prompt, prints exactly one ------finish------, and exits — even if background runs of its own are still going. Anything that arrives afterwards (a detached run's completion alarm, a cron job, another agent) waits in ~/.miniouto/inbox/<session>/ for the next wakeup, which is the TUI's 1 s poll or the explicit CLI door:
miniouto message insert --session <s> "something happened" # from any process, any tool
miniouto message list --session <s> # non-destructive peek
miniouto chat --alarms -c --name <s> # wake: drain the queue, run one turn, exit
--alarms takes no prompt (the queued messages are the prompt), requires -c (history is never loaded implicitly), and requires the session to exist. An empty inbox is a no-op: one line, exit 0, no model call — so a monitor can poll it for free. Nothing here is locked in: any tool that can run a shell can insert, observe, or wake. Monitoring recipes and jq recipes for extracting a transcript from a session file are in docs/automation.md.
Long runs: explicit summaries, session hand-off
There is no implicit summarization — nothing rewrites the conversation behind the model's back. When a turn has eaten ~80% of its context window, the harness sends one system message ([SYSTEM ALARM - THIS IS NOT A USER MESSAGE] + Context budget: {pct}% of this session's window is consumed ({used}/{window} tokens). Explicit summarization is required now., arriving as a user message) telling the agent to write summary documents into ./.miniouto/summary/<session>/ and call the continue_session tool. That ends the conversation and continues in a fresh cont-* session that reads those documents; a delegated run carries its contract (alarm session, result file, role, style) across, and its result file and completion alarm name the session it finally ended in. Summary documents live next to your code on purpose, so they can be reviewed and committed with the work they describe.
Model resolution
The active provider, model and reasoning effort each come from the first match in:
miniouto chat --pm 'PROVIDER/MODEL[:REASONING]'— for that one call and nothing else. This is the only per-call override; the old--provider/--model/--reasoning/--subagent-provider/--subagent-modelflags are gone. The provider is everything before the first/(a model name may contain slashes), and reasoning is split off the last:; both are optional parts, and a missing/is rejected before anything is resolved.- this session's pin,
~/.miniouto/session-config/<session>.toml— frozen the first time that session resolves, so a model switch made in another process can never redirect a conversation already under way. - the global default —
settings.providerplus the provider record'sdefault_model/reasoning_effort(a legacysettings.modelstill reads at the bottom of that chain). - error — no provider configured, or no model can be inferred.
That middle tier is the point: each session keeps the settings it started with, and only the default moves (the most recent TUI change wins). A session minted on the fly — a delegated chat-/spawn- run, a summary hand-off's cont-* session, the TUI's "new session" — inherits the pin of the session it continues, copy-if-absent. So several miniouto processes can run on different providers at the same time without redirecting each other.
In the TUI, both provider chips open the same popup: three rows, Provider / Model / Reasoning, each with its own picker. Picking a provider or a model resets Reasoning to that model's default (an effort level belongs to a model), and every change writes both the session pin and the global default.
The subagent (a delegated run that asks for the subagent profile — --use-subagent-provider, or the --pm value the {subagent_pm} token renders) can run on a different provider/model, and resolves the same way, pin-first against its own session: --pm > the pin's subagent_provider > settings.subagent_provider (via miniouto subagent set) > inherit outo's provider; and --pm > the pin's subagent_model > settings.subagent_model > the subagent provider's default_model > inherit outo's model (only reachable when no subagent provider is set). A model-only setting (no subagent provider) is also valid — the run then uses outo's provider with that model. Reasoning resolves as: the --pm suffix > the pin's subagent_reasoning > settings.subagent_reasoning > the subagent provider's reasoning_effort > lma's default.
Commands
| Command | Purpose |
|---|---|
miniouto chat "prompt" |
One-shot chat turn — also the delegation door (--style+--role, --bg, --pm, --alarm-session <s>, --return) and, with --alarms -c, the wakeup door |
miniouto |
TUI mode |
miniouto status |
Show current configuration |
miniouto message insert/list/clear |
Insert into or inspect a session inbox (--session <s>) |
miniouto computer show |
Render a captured .art screen dump |
miniouto provider providers/models/add |
Browse the lma catalog and add providers from it |
miniouto provider custom add |
Add a custom provider by hand (api_format, base_url, api_key, default_model) |
miniouto provider list/remove/default |
Manage saved providers |
miniouto style list/set/add/update/show |
Manage style documents (update re-seeds bundled + re-fetches all repo styles) |
miniouto skill list/show |
List/show skills from ./skills/ (project-local) + ~/.agents/skills/ |
miniouto subagent show/set/clear |
Manage the global default subagent provider/model/reasoning (empty = inherit outo's) |
chat flags
| Flag | Effect |
|---|---|
--name |
Session name (persists to ~/.miniouto/settings.toml) |
--pm 'PROVIDER/MODEL[:REASONING]' |
Override provider/model/reasoning for this call only. The one per-call provider override; wins over the session pin and the global default |
--style |
Override the active style for this call. Required with --role |
--role |
Run as this style role's system prompt (a <tag>...</tag> body) — what makes the turn a delegated one. Requires --style |
--use-subagent-provider |
Resolve provider/model/reasoning from the subagent trio (this session's pin, else the subagent_* settings default) instead of outo's. An explicit --pm still wins — and prefer --pm in generated commands, since a literal provider/model makes a copied command idempotent |
--max-tokens |
Cap output tokens |
--temperature |
Sampling temperature |
--alarm-session NAME |
Insert one completion alarm into that session's inbox on completion. The value is required — there is no bare form |
--return [PATH] |
Write the final answer as markdown to this path (bare = subagent-results/); a directory receives the generated filename |
--bg |
Detach the run into its own process and return immediately |
--continue / -c |
Prepend the session's previous history. Never implied — and mandatory with --alarms |
--alarms |
Wake a session from its queued messages: the inbox is drained and the joined texts become the turn's user message. No prompt argument; requires -c and an existing session; an empty inbox is a no-op |
--answer-only / -a |
Print only the final answer (no session marker, no loop events, no finish marker) |
--with-session |
Print only the session marker + final answer (no loop events, no finish marker) |
Talking to a running turn
Anything can drop a message into a session's inbox from outside, and a turn that is already running picks it up at its next iteration. With nothing running, the message simply waits for the next wakeup (miniouto chat --alarms -c, or the TUI):
miniouto message insert --session mysession "actually, use tabs"
miniouto message list --session mysession # peek: never consumes
miniouto message clear --session mysession
Storage
Everything lives under ~/.miniouto/:
providers.toml— provider configs (one top-level TOML table per provider:api_format,base_url,api_key,default_model,source)settings.toml— the global defaultprovider,style,session,theme,subagent_provider,subagent_model,subagent_reasoning(plus a legacy, read-onlymodel)session-config/<session>.toml— that session's pinnedprovider,model,reasoningandsubagent_*; an empty key means "follow the default"style/<name>.md— style documentssessions/<name>.json— conversation historyinbox/<session>/— one JSON file per pending message for that session (alarms andminiouto message insert)spawn-logs/— background-run liveness markers (<id>.json) plus bg stdio logs (<id>.log)computer-screens/—.artUnicode screen dumps written by the Computer tool (screen;screenshotwrites the same art as a best-effort sibling of its capture)subagent-results/— one markdown file per finished delegated run, holding the final answer (the completion alarm names the file)logs/— reserved (currently unused)
Summary documents are the one exception: they live project-local at ./.miniouto/summary/<session>/ (relative to the directory you invoked miniouto from), because a summary is a project artifact rather than harness state.
Skills live outside this tree, in one of two default roots: the project-local ./skills/<name>/SKILL.md (relative to the directory you invoked miniouto from — check it into your repo and everyone gets it) and ~/.agents/skills/<name>/SKILL.md (the Anthropic convention). A style advertises them to the model with the {skills} token in its body, which lists both defaults, project-local first; {skills:~/.claude/skills} lists whatever directories you name instead. The harness adds nothing implicitly: the system prompt is the style body with its tokens expanded, nothing else.
Override the root with the MINIOUTO_HOME environment variable.
Metadata
Release files for miniouto 0.11.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| miniouto-0.11.3.tar.gz | 6.4 MB | With provenance | Details for miniouto-0.11.3.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| miniouto-0.11.3-py3-none-any.whl | Python 3 | none | any | Details for miniouto-0.11.3-py3-none-any.whl |
Total release size: 6.6 MB
Release files / miniouto-0.11.3.tar.gz
| Download URL | miniouto-0.11.3.tar.gz |
|---|---|
| Size | 6.4 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6eb3f750a7a2657f2f29eee9c57f047725b57d1b24f699ce29d0eb978607dc3a
|
|
BLAKE2b-256 checksum How to use checksums |
1840bfa3a9b065cd6897a7246d0b6970af6995b16b349a503a79611558a1c738
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.
Transparency logRelease files / miniouto-0.11.3-py3-none-any.whl
| Download URL | miniouto-0.11.3-py3-none-any.whl |
|---|---|
| Size | 294.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
221a04e913131e2bcfd60d42961b47e7aafaefbab43e1d78b1bf9e86a606ed8e
|
|
BLAKE2b-256 checksum How to use checksums |
442477a3c339a4d5c793c87ed0e9d7cbe7b7c76317e46de362e485d6eca0703a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.
Transparency logSecurity for miniouto 0.11.3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for miniouto-0.11.3.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.