# kobito

kobito

crates.io release CI license

Like the elves in the shoemaker's tale, it works while you sleep.

`kobito` is an autonomous coding agent orchestrator. Give it a goal, it loops — invoking [Claude Code](https://github.com/anthropics/claude-code) or [Codex](https://github.com/openai/codex) on your repository, committing each iteration with an LLM-generated message that follows the project's own conventions, until you stop it. ## Installation ### Using Install Script (Recommended) ```bash curl -fsSL https://raw.githubusercontent.com/unhappychoice/kobito/main/install.sh | bash ``` Drops the binary in `~/.local/bin` by default. Override with `INSTALL_DIR=/usr/local/bin` or pin a version with `bash install.sh v0.1.0`. ### Using Homebrew ```bash brew install unhappychoice/tap/kobito ``` ### Using Cargo ```bash cargo install kobito ``` ### From Source ```bash git clone https://github.com/unhappychoice/kobito.git cd kobito cargo install --path . ``` Pre-built archives for `linux x86_64 / aarch64`, `macOS x86_64 / aarch64`, and `windows x86_64` are attached to every [GitHub release](https://github.com/unhappychoice/kobito/releases). ### Requirements Either the [`claude`](https://github.com/anthropics/claude-code) or [`codex`](https://github.com/openai/codex) CLI on `PATH` (see `--agent` below). Iteration mode additionally requires the [`gh`](https://cli.github.com/) CLI authenticated for the project's remote. ## Features - `cont` mode — one branch, many commits, run until you stop it - `iter` mode — per-task branch + PR from a `tasks.md` backlog - Claude Code and OpenAI Codex backends behind a single `Agent` trait - Preset system with `{{var}}` substitution (project + global) - Per-run `notes.md` auto-maintained by the agent - `kobito resume` with an interactive picker of recent runs - State under `$XDG_STATE_HOME/kobito/`, event-driven streaming + status bar - Per-iteration token usage logged from each agent's structured event stream Project conventions — output language, code style, commit format, branch names — are deferred to the agent's own memory files (`CLAUDE.md` / `AGENTS.md`). kobito does not inject or pin anything itself. ## Usage ### `cont` Pursue a single open-ended goal on one working branch: ```bash # from inside a clean git repo kobito cont --prompt "Increase test coverage in src/" ``` ### `iter` Consume a backlog of small tasks, one branch + PR per task: ```bash # seed the backlog (committed to the project) cat > .kobito/tasks.md <<'EOF' - [ ] Add /healthz endpoint - [ ] Wire Prometheus metrics middleware - [ ] Document the new endpoints in README EOF kobito iter ``` Or point at an explicit backlog file: ```bash kobito iter --backlog ./tasks.md ``` The first run copies `.kobito/tasks.md` (or the file passed via `--backlog`) into the state directory. From then on the state copy is the source of truth — edit it through: ```bash kobito tasks edit ``` For each unchecked item, kobito branches off the starting branch as `kobito/task--`, iterates until the agent emits `TASK_COMPLETE`, runs `gh pr create`, and marks the line `[x]` in the state copy. ### Presets Reuse a Markdown template across runs and projects. Place the file at: 1. `./.kobito/presets/.md` — project-local override 2. `$XDG_CONFIG_HOME/kobito/presets/.md` — global (defaults to `~/.config/kobito/presets/`) Resolution checks (1) first, then (2). Missing preset → error. `{{var}}` placeholders are substituted from `--var key=value` (repeatable). Unresolved variables abort the run before any branch is created. ```bash # ~/.config/kobito/presets/coverage.md # Increase test coverage for {{path}}. Aim for {{target}}% line coverage. # preset replaces --prompt entirely: kobito cont --preset coverage --var path=src/api --var target=80 ``` In `cont` mode `--preset` is **mutually exclusive with `--prompt`** — the resolved preset body becomes the goal. In `iter` mode each task in `tasks.md` is its own goal, so `--preset` instead acts as **framing prepended to every task prompt**: ```bash kobito iter --preset small-feature --backlog tasks.md ``` ### Resuming ```bash # interactive picker — shows the 10 most recent runs kobito resume # or resume a specific run id (the timestamp dir name) kobito resume --run 2026-05-01T12-00-00 ``` `kobito resume` without `--run` opens an arrow-key picker listing the most recent runs (id, branch, first line of the goal). When there is only one prior run, or when stdin is not a TTY (CI, pipes), it auto-picks the latest. Resume re-uses the original branch and agent from the run's `meta.json`, opens a new run directory, and copies the previous `notes.md` as the starting memory so the loop picks up with what the earlier iterations learned. ### Common options | flag | default | meaning | | ------------------- | --------- | ------------------------------------------- | | `--prompt`, `-p` | required (cont) | the goal to pursue | | `--backlog` | optional (iter) | path to a tasks.md backlog | | `--preset` | optional | preset name (resolved per the order above) | | `--var key=value` | repeatable | substitute `{{key}}` in the preset | | `--max-iterations` | `50` / `30` | hard cap on iterations (per task in iteration mode) | | `--max-failures` | `3` | give up after N consecutive failures | | `--agent` | `claude` | `claude` (alias `claude-code`) or `codex` | | `--allow-dirty` | `false` | skip the clean-tree check | ## How it works Each iteration: 1. Build a prompt: cross-iteration notes (if any) + the goal + a `NATURAL_STOP` / `TASK_COMPLETE` escape hatch. 2. Invoke the agent in non-interactive mode with its structured-output flag (`claude --output-format stream-json` / `codex exec --json`). Each line is parsed into a normalised `AgentEvent` (Message / ToolStart / ToolEnd / Usage / Stop / Other), formatted onto the terminal, and persisted both as a human-readable line in `log.ndjson` and as a raw JSON event in `events.ndjson`. The agent loads its own `CLAUDE.md` / `AGENTS.md` at this point. 3. If the agent emitted a diff, generate a Conventional Commits message via a one-shot agent call and commit. 4. If the agent failed, `git reset --hard` and retry with exponential backoff. 5. If the agent emits the literal sentinel token (`NATURAL_STOP` for `cont`, `TASK_COMPLETE` for `iter`), exit cleanly. Single branch, single PR, many commits — by design (`cont` mode). One branch + PR per task (`iter` mode). ## State layout ``` ~/.local/state/kobito/ └── projects/ └── -/ ├── tasks.md # iteration backlog (state copy) └── runs/ └── 2026-05-01T12-00-00/ # one directory per invocation = run id ├── meta.json # branch, goal, agent — used for resume ├── notes.md # cross-iteration learnings, agent-maintained ├── log.ndjson # human-readable streamed lines ├── events.ndjson # raw structured events from the agent └── prompts/ └── iter-0001.md ``` `notes.md` lives **per run**, not per project. Each invocation gets a fresh memory file, and `iter` mode (which starts a new run per task) automatically gets a separate notes.md per task — coverage push and refactor learnings don't bleed into each other. After every commit, the agent is asked in a one-shot call to write 1-5 short bullets distilling what is useful for the next iteration — surprising findings, dead-ends, paths or commands worth remembering — appended under a timestamped header. The next iteration reads the file back into the prompt as cross-iteration memory. Empty / `NO_NOTES` outputs are skipped. `$XDG_STATE_HOME` is honoured if set. ## Related Projects - [**gitlogue**](https://github.com/unhappychoice/gitlogue) — A cinematic Git commit replay tool for the terminal - [**GitType**](https://github.com/unhappychoice/gittype) — A CLI code-typing game that turns your source code into typing challenges ## Contributing Contributions are welcome. See [AGENTS.md](AGENTS.md) for project conventions. ## License ISC License. See [LICENSE](LICENSE) for details. ## Author [@unhappychoice](https://github.com/unhappychoice)