mini-code-cli 0.1.0.4__tar.gz → 0.1.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/PKG-INFO +253 -138
  2. mini_code_cli-0.1.1.1/README.md +326 -0
  3. mini_code_cli-0.1.1.1/mini_code_cli/__init__.py +40 -0
  4. mini_code_cli-0.1.1.1/mini_code_cli/agent_loop.py +2129 -0
  5. mini_code_cli-0.1.1.1/mini_code_cli/config.py +231 -0
  6. mini_code_cli-0.1.1.1/mini_code_cli/persistence.py +547 -0
  7. mini_code_cli-0.1.1.1/mini_code_cli/plan.py +156 -0
  8. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli/prompts.py +12 -5
  9. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli/sandbox.py +6 -2
  10. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli/skills.py +6 -2
  11. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli/subagents/base.py +44 -15
  12. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli/subagents/builtin.py +2 -2
  13. mini_code_cli-0.1.1.1/mini_code_cli/tokens.py +118 -0
  14. mini_code_cli-0.1.1.1/mini_code_cli/tools.py +672 -0
  15. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli/ui.py +69 -13
  16. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli/utils.py +79 -20
  17. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli.egg-info/PKG-INFO +253 -138
  18. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli.egg-info/SOURCES.txt +5 -1
  19. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/pyproject.toml +9 -1
  20. mini_code_cli-0.1.1.1/tests/test_e2e_agent_loop.py +1127 -0
  21. mini_code_cli-0.1.1.1/tests/test_interactive.py +1008 -0
  22. mini_code_cli-0.1.1.1/tests/test_subagents.py +372 -0
  23. mini_code_cli-0.1.1.1/tests/test_tokens.py +410 -0
  24. mini_code_cli-0.1.0.4/README.md +0 -217
  25. mini_code_cli-0.1.0.4/mini_code_cli/__init__.py +0 -2
  26. mini_code_cli-0.1.0.4/mini_code_cli/agent_loop.py +0 -1406
  27. mini_code_cli-0.1.0.4/mini_code_cli/config.py +0 -19
  28. mini_code_cli-0.1.0.4/mini_code_cli/persistence.py +0 -321
  29. mini_code_cli-0.1.0.4/mini_code_cli/plan.py +0 -218
  30. mini_code_cli-0.1.0.4/mini_code_cli/tools.py +0 -308
  31. mini_code_cli-0.1.0.4/tests/test_e2e_agent_loop.py +0 -557
  32. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/LICENSE +0 -0
  33. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli/permissions.py +0 -0
  34. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli/runner.py +0 -0
  35. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli/shell_safety_utils.py +0 -0
  36. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli/subagents/__init__.py +0 -0
  37. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli.egg-info/dependency_links.txt +0 -0
  38. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli.egg-info/entry_points.txt +0 -0
  39. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli.egg-info/requires.txt +0 -0
  40. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/mini_code_cli.egg-info/top_level.txt +0 -0
  41. {mini_code_cli-0.1.0.4 → mini_code_cli-0.1.1.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mini-code-cli
3
- Version: 0.1.0.4
3
+ Version: 0.1.1.1
4
4
  Summary: Mini Coding Agent. Allows you to easily experiment with a small coding agent.
5
5
  Author-email: Nikolai Rozanov <nikolai.rozanov@gmail.com>
6
6
  License: GNU AFFERO GENERAL PUBLIC LICENSE
@@ -666,95 +666,159 @@ License: GNU AFFERO GENERAL PUBLIC LICENSE
666
666
  <https://www.gnu.org/licenses/>.
667
667
 
668
668
  Project-URL: Homepage, https://github.com/ai-nikolai/mini-code-cli
669
+ Classifier: Programming Language :: Python :: 3
670
+ Classifier: Programming Language :: Python :: 3.10
671
+ Classifier: Programming Language :: Python :: 3.11
672
+ Classifier: Programming Language :: Python :: 3.12
673
+ Classifier: Programming Language :: Python :: 3.13
674
+ Classifier: Operating System :: OS Independent
669
675
  Requires-Python: >=3.10
670
676
  Description-Content-Type: text/markdown
671
677
  License-File: LICENSE
672
678
  Requires-Dist: requests<3,>=2.31
673
679
  Dynamic: license-file
674
680
 
675
- # A minimal coding agent cli
681
+ # mini-code-cli
682
+
683
+ ### A minimal coding agent CLI
676
684
 
677
685
  > No bloat, no dependencies, no tracking, no telemetry...
678
686
 
679
- Purpose: A no bloat, minimal coding cli, to enjoy experimenting and researching...
687
+ [![CI](https://img.shields.io/github/actions/workflow/status/ai-nikolai/mini-code-cli/ci.yml?branch=main&label=CI&logo=github&style=flat-square)](https://github.com/ai-nikolai/mini-code-cli/actions/workflows/ci.yml)
688
+ [![PyPI](https://img.shields.io/pypi/v/mini-code-cli?style=flat-square&logo=pypi&logoColor=white)](https://pypi.org/project/mini-code-cli/)
689
+ [![Python](https://img.shields.io/badge/python-3.10%2B-blue?style=flat-square&logo=python&logoColor=white)](https://pypi.org/project/mini-code-cli/)
690
+ [![Stars](https://img.shields.io/github/stars/ai-nikolai/mini-code-cli?style=flat-square&logo=github)](https://github.com/ai-nikolai/mini-code-cli/stargazers)
691
+ [![License: AGPL v3](https://img.shields.io/badge/license-AGPL--3.0-blue?style=flat-square)](LICENSE)
692
+ [![Cite](https://img.shields.io/badge/cite-BibTeX-blueviolet?style=flat-square&logo=latex&logoColor=white)](#citation)
693
+
694
+ **Purpose:** a no-bloat, minimal coding CLI to enjoy experimenting and researching.
695
+
696
+ **Install** · [Quick start](#quick-start) · [Modes &amp; safety](#modes--safety) · [Options](#command-line-options) · [Tools](#available-tools) · [Sub-agents](#sub-agents) · [In-session commands](#in-session-commands) · [Development](#development) · [Docs](#documentation) · [Citation](#citation)
680
697
 
681
- ## Getting started:
698
+ > [!TIP]
699
+ > **New here?** `pip install mini-code-cli`, point it at a model (a local server on
700
+ > `localhost:30000`, or `MINI_CODE_API_KEY` + `--url`), and run `mini-code`. Everything else
701
+ > is optional.
702
+
703
+ ## Install
682
704
 
683
- ### Installation (from pypi)
684
705
  ```bash
685
706
  pip3 install mini-code-cli
686
707
  ```
687
708
 
688
- ### Run agent:
709
+ - **PyPI:** <https://pypi.org/project/mini-code-cli/>
710
+ - **Python:** `>= 3.10` &nbsp;·&nbsp; **runtime dependency:** `requests` only
711
+ - **From source / contributing:** see [docs/README_DEV.md](docs/README_DEV.md)
712
+
713
+ ## Quick start
714
+
715
+ **1 — Local model** (e.g. vLLM or SGLang on port 30000; see [serving a model locally](#serving-a-model-locally)):
689
716
 
690
- 1. Basic usage: (get local LLM running (e.g. via SGLang or Vllm))
691
717
  ```bash
692
- mini-code #run the agent using `localhost:30000/v1` model
718
+ mini-code # talks to http://0.0.0.0:30000/v1
693
719
  ```
694
- 2. Custom API based model:
720
+
721
+ **2 — Hosted / custom API:**
722
+
695
723
  ```bash
696
724
  export MINI_CODE_API_KEY="sk-YOUR_API_KEY"
697
725
  mini-code --url "https://api.deepseek.com" --model "deepseek-v4-flash"
698
726
  ```
699
- 3. Auto-mode and shell enabled: (this will run localhost:30000)
700
- ```bash
701
- mini-code --enable-shell --auto-mode
702
- mini-code -s -a --sudo
703
- mini-code -s -a -p -g -l --sudo #plan, previous session, subagents (#or short-hand the next commands)
704
- mini-code --all
705
- mini-code --all-last
706
- ```
707
727
 
708
- 4. Advanced usage:
709
- Auto-mode, Agent.md, Shell Enabled mode and a specific allowed dir:
728
+ **3 — The shortcuts** (plan mode, sub-agents, shell, auto-mode, no permission prompts):
729
+
710
730
  ```bash
711
- mini-code --enable-shell --auto-mode --agent-md "./skill.md" --allowed-dir "./" --ask-permission --system-prompt "Your awesome new system prompt..."
731
+ mini-code --all # = --plan --enable-subagents --enable-shell --auto-mode --sudo
732
+ mini-code --all-last # ...and continue your last session
712
733
  ```
713
- - auto-mode: the agent will continue querying the LLM and executing tools, until no more tool calls are possible
714
- - agent.md: this will read an agent.md file with the specified name (e.g. ./skill.md)
715
- - shell-enabled: **Be careful**: This will allow the agent to execute shell commands. **Every command is first checked by a shell-safety classifier** that sorts it into three tiers:
716
- - **DENY** — obviously destructive commands (e.g. `rm -rf /`, `dd of=/dev/...`, `mkfs.*`, fork bombs) are **refused outright** and never run.
717
- - **ASK** — risky commands (e.g. `rm file`, `sudo ...`, `chmod`, `curl ... | sh`) require your confirmation before running.
718
- - **ALLOW** — clearly safe commands (e.g. `ls`, `cat`, `git status`) run without prompting.
719
- This protection is **always enforced** for the shell tool, even in auto-mode / without `--ask-permission`, so the agent can never run dangerous commands unattended. (The classifier is a heuristic, not a sandbox — use with care.)
720
- - allowed-dir: this specifies which dirs the agent can read and write from, that does not stop the shell comands! (though dangerous shell commands are still blocked by the classifier above).
721
- - ask-permission: asks user permission before every tool call. For shell commands, commands in the ALLOW tier skip the prompt, DENY is blocked, and ASK always prompts.
722
- - system-prompt: you can override the default prompt by using a string. (Note: Agent.md is always appended after the system prompt.)
723
- - load-last-session: instead of starting a fresh conversation, automatically continue your most recently active session from the default cache dir. It resumes under a brand-new session id, so the original session is never overwritten. An explicit `--restore-session` (a specific path) takes precedence if both are given. The "most recent" session is resolved in two steps: at the end of every interactive session, its path is recorded in a tiny `.mini/last_session.json` pointer inside the `--allowed-dir`, and `--load-last-session` consults that pointer first; only if there is no pointer (e.g. a fresh allowed dir, or the `--skills` feature disabled) does it fall back to the timestamp heuristic (the session whose history was modified most recently). The `.mini` pointer is the same directory the `--skills` feature uses, but it is a single dedicated file, so the two never clash.
724
- - **Interactive session offer:** if a previous session exists in the cache dir but you did **not** explicitly ask to resume one (i.e. neither `--load-last-session` nor `--restore-session` was passed), the prompt asks what you'd like to do before the conversation starts: 1) **Resume** the previous session (splice its history in under a brand-new session id and continue it), 2) **Start a new** session (empty history), or 3) **Exit** (start nothing). Ctrl-C / EOF at the offer is treated as a graceful exit. This is distinct from `--load-last-session`, which silently resumes the most recent session without asking.
725
- - plan: `--plan` enables **plan mode**. The loop keeps two human-readable tracking files in the session directory: `CURRENT_GOAL.md` (the user's latest instruction) and `CURRENT_PLAN.md` (a step-by-step plan the loop generates for the active goal, marked finished once the goal is done). These files are authored by the *loop*, not the agent (they live outside `--allowed-dir`), and you can inspect them anytime with `/plan` (only meaningful in plan mode). After the work looks done, plan mode reviews the plan's completion and re-queues any outstanding tasks before returning to you. Plan mode also changes how history compaction works: after the history is compacted to a summary, the current `CURRENT_PLAN.md` and the user's last instruction (`CURRENT_GOAL.md`) are re-injected into the messages so the agent keeps working against the same goal. When the session ends, the active goal is marked finished in `CURRENT_PLAN.md`.
726
734
 
727
- ### Available tools
735
+ **4 — A first prompt:**
728
736
 
729
- The agent can call a small set of tools, all of which live in `mini_code_cli/tools.py`:
730
-
731
- - **`read_file` / `write_file`** — read a file or write/overwrite one.
732
- - **`grep`** — search a file for a pattern.
733
- - **`glob`** — list files matching a glob pattern.
734
- - **`web_search`** — best-effort web lookup: returns popular related queries (DuckDuckGo autocomplete) plus a short extract from the top Wikipedia match. Never raises; always returns a string.
735
- - **`read_website`** — fetch the raw text/HTML of a URL (bounded by `--tool-timeout`).
736
- - **`run_shell_command`** — run a shell command (only when `--enable-shell` is set). Every command is passed through the shell-safety classifier described above.
737
-
738
- ### Sub-agents
739
-
740
- Passing `--enable-subagents` lets the main agent **delegate a focused task to a sub-agent**, which is exposed to the model as an extra tool. A sub-agent is a self-contained, narrowed agent: it runs on its own in auto-mode (unattended), in its own isolated session folder, and hands a short text result (plus an optional `report.md`) back to the main agent. It reuses all the existing machinery -- tools, the shell-safety classifier, the `--allowed-dir` sandbox, history compaction and `--plan` mode -- and cannot recursively spawn further sub-agents.
737
+ ```txt
738
+ Write an agent.md file for me that helps an LLM write efficient triton kernels,
739
+ given a reference implementation.
740
+ ```
741
741
 
742
- Enable it and the available sub-agents appear in the help (`/help`):
742
+ > [!NOTE]
743
+ > **Every flag** is listed once, in [Command-line options](#command-line-options) — or run
744
+ > `mini-code --help`. Modes and their caveats are described in [Modes & safety](#modes--safety).
745
+
746
+ ## Command-line options
747
+
748
+ | Option | Default | What it does |
749
+ | --- | --- | --- |
750
+ | `--url URL` | `http://0.0.0.0:30000` | API host |
751
+ | `--model MODEL` | — | model name |
752
+ | `--api-key KEY` | `$MINI_CODE_API_KEY` | API key for authentication |
753
+ | `--max-tokens N` | — | reply budget; also the output headroom used when deriving the compaction limit |
754
+ | `--temperature T` | `1.0` | sampling temperature |
755
+ | `--system-prompt TEXT` | built-in | replace the system prompt (an `--agent-md` file is appended *after* it) |
756
+ | `--prompt TEXT` | — | initial user prompt |
757
+ | `-a`, `--auto-mode` | off | keep querying the model and running tools until no tool calls remain |
758
+ | `--agent-md FILE` | — | append an `agent.md` file after the system prompt (e.g. `./skill.md`) |
759
+ | `--ask-permission` | off | ask before every tool call (ALLOW-tier shell commands still skip the prompt) |
760
+ | `--sudo` | off | **dangerous:** never ask. DENY-tier commands are still refused |
761
+ | `--allowed-dir DIR` | `./` | sandbox for **file** tools (does not restrict the shell) |
762
+ | `-s`, `--enable-shell` | off | allow shell execution (classifier always applies) |
763
+ | `-g`, `--enable-subagents` | off | expose sub-agents as tools |
764
+ | `--skills` | off | enable the `.mini` skills directory (`skill.md`s, `SKILLS.md`, runnable scripts) |
765
+ | `-p`, `--plan` | off | plan mode (`CURRENT_GOAL.md` / `CURRENT_PLAN.md`, `/plan`) |
766
+ | `--llm-timeout S` | `500` | HTTP timeout for LLM requests |
767
+ | `--tool-timeout S` | `120` | timeout for a single tool call |
768
+ | `--max-context-tokens N` | derived | input-token budget before the history is compacted |
769
+ | `--cache-dir DIR` | `~/.cache/mini/sessions/` | where session histories are stored |
770
+ | `--restore-session PATH` | — | continue a specific previous session |
771
+ | `-l`, `--load-last-session` | off | continue the session recorded in the `.mini` pointer |
772
+ | `--all` | off | `--plan --enable-subagents --enable-shell --auto-mode --sudo` |
773
+ | `--all-last` | off | `--all` + `--load-last-session` |
774
+ | `--verbose` | off | print full detail (default: user/assistant turns, token usage, tool calls only) |
775
+ | `-h`, `--help` | — | show the built-in help |
776
+
777
+ ## Available tools
778
+
779
+ The agent can call a small set of tools, all defined in `mini_code_cli/tools.py`. Every
780
+ parameter a model does not need is defaulted, so omitting it keeps the previous behaviour.
781
+
782
+ | Tool | What it does |
783
+ | --- | --- |
784
+ | `read_file` | read a file; `offset` (1-based line) and `limit` page through large files |
785
+ | `write_file` | write/overwrite; `append` adds to the end, `create_dirs` creates parents |
786
+ | `edit` | replace an **exact** string (`old_string` → `new_string`); refuses a missing or ambiguous match unless `replace_all` |
787
+ | `grep` | regex search a file or directory; `recursive`, `include`, `ignore_case`, `line_numbers`, `max_results` (noise dirs skipped) |
788
+ | `glob` | list files matching a glob (one per line, `**` supported), optionally against a `root` |
789
+ | `web_search` | best-effort lookup: related queries + a short Wikipedia extract. Never raises |
790
+ | `read_website` | fetch raw text/HTML of a URL (bounded by `--tool-timeout`), `max_chars` caps size |
791
+ | `run_shell_command` | run a shell command (needs `--enable-shell`); `cwd`, `timeout`, and stdout/stderr/exit code are all reported |
792
+
793
+ ## Sub-agents
794
+
795
+ `--enable-subagents` lets the main agent **delegate a focused task** to a sub-agent, exposed to
796
+ the model as an extra tool. A sub-agent is a self-contained, narrowed agent: it runs unattended
797
+ in auto-mode, in its own isolated session folder, and hands back a short text result (plus an
798
+ optional `report.md`). It reuses all the existing machinery — tools, the shell-safety
799
+ classifier, the `--allowed-dir` sandbox, compaction and `--plan` — and cannot spawn further
800
+ sub-agents.
743
801
 
744
802
  ```bash
745
- mini-code --enable-subagents
803
+ mini-code --enable-subagents # the available sub-agents then show up in /help
746
804
  ```
747
805
 
748
- Two worked examples ship out of the box:
749
-
750
- - **`research`** -- read-only web research. Given a topic it searches the web, reads a few sources and returns a concise, sourced summary. It can only use `web_search` / `read_website` -- never the filesystem or shell -- so it is safe even without a sandbox. Accepts an optional `sources` hint (e.g. `"wikipedia.org only"`).
751
- - **`planner`** -- drafts/refines a clear step-by-step plan for a goal and returns it. Always runs in plan mode.
806
+ | Sub-agent | What it is for |
807
+ | --- | --- |
808
+ | `research` | read-only web research: searches, reads a few sources, returns a sourced summary. Can only use `web_search` / `read_website` — never the filesystem or shell. Optional `sources` hint (e.g. `"wikipedia.org only"`) |
809
+ | `planner` | drafts or refines a step-by-step plan for a goal; always runs in plan mode |
810
+ | `software_engineer` | writes, edits, refactors, fixes and tests code; can run shell commands (tests, builds) to verify |
811
+ | `generic` | general-purpose helper for anything that fits no narrower agent |
752
812
 
753
- The `tools`, `enable_shell` and `max_steps` knobs are always intersected with the parent's own permissions, so a sub-agent can never do anything the main agent could not. Sub-agents also compose with `--plan` mode: each sub-agent keeps its own `CURRENT_PLAN.md` / `CURRENT_GOAL.md` in its own session folder.
813
+ > [!NOTE]
814
+ > A sub-agent's `tools`, `enable_shell` and `max_steps` are always **intersected with the
815
+ > parent's** permissions, so it can never do anything the main agent could not. Sub-agents
816
+ > compose with `--plan`: each keeps its own `CURRENT_PLAN.md` / `CURRENT_GOAL.md`.
754
817
 
755
- #### Adding your own sub-agent
818
+ <details>
819
+ <summary><b>Adding your own sub-agent</b></summary>
756
820
 
757
- A sub-agent is just a small class. Subclass `SubAgent` and register it:
821
+ A sub-agent is just a small class — subclass `SubAgent` and register it:
758
822
 
759
823
  ```python
760
824
  # my_subagents.py
@@ -770,98 +834,147 @@ class SummarizeSubAgent(SubAgent):
770
834
  register(SummarizeSubAgent())
771
835
  ```
772
836
 
773
- Then make sure it is imported (e.g. add `import my_subagents`), and it will be discovered and exposed to the model automatically when `--enable-subagents` is set. See `mini_code_cli/subagents/builtin.py` for the full list of knobs and `ARCHITECTURE.md` (sections 2-3) for the design and every available option.
837
+ Make sure the module is imported (e.g. `import my_subagents`) and it is discovered and exposed
838
+ to the model automatically when `--enable-subagents` is set. See
839
+ `mini_code_cli/subagents/builtin.py` for every knob and
840
+ [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) (sections 2–3) for the design.
841
+
842
+ </details>
843
+
844
+ ## In-session commands
845
+
846
+ | Command | What it does |
847
+ | --- | --- |
848
+ | `/history` | list the conversation (turn number, what happened, where) |
849
+ | `/history <n>` | show the full messages recorded for turn `n` |
850
+ | `/history last` | ...for the most recent turn |
851
+ | `/reset [<n>]` | rewind to the end of turn `n` (`last` works too); drops everything after it |
852
+ | `/clear` | clear the screen (keeps the conversation history) |
853
+ | `/plan` | show the current goal + plan (plan mode only) |
854
+ | `/help` | show this help |
855
+ | `/quit`, `/exit` | save the session and exit |
856
+
857
+ > [!NOTE]
858
+ > `/history` and `/reset` are driven by `summary_history.json`, a flat recorder that maps every
859
+ > turn to the `history_{n}.json` segment and message index it lives in — so no full history is
860
+ > read just to list the conversation.
861
+ >
862
+ > * **`<n>` is validated**: `last`, or a positive 1-based turn number. `0`, negatives and
863
+ > non-numbers are rejected with `No such turn` instead of silently showing a different turn.
864
+ > * **A bare `/reset` never destroys anything**: it reports `Already at turn N` when the
865
+ > transcript already ends at the last recorded turn, and *warns instead of truncating* if
866
+ > there are messages that were never recorded. Only `/reset <n>` / `/reset last` rewind.
867
+ > * **A rewind really sticks**: the target `history_{n}.json` is truncated in place (no backup)
868
+ > and every higher `history_{m}.json` / `usage_{m}.json` segment is deleted, so a restart
869
+ > cannot resurrect the dropped turns. All history files are written atomically.
870
+ > * **Token usage is never rolled back**: a rewind does not un-spend tokens, and the session
871
+ > total is preserved. See
872
+ > [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#rewinding-reset-and-what-it-does-to-the-files)
873
+ > for the files involved.
874
+
875
+ ## Development
876
+
877
+ Linting, the test suite, CI and the release process are documented in
878
+ [**docs/README_DEV.md**](docs/README_DEV.md).
774
879
 
775
- 3. Try a prompt:
776
- ```txt
777
- Write an agent.md file for me that helps an LLM write efficient triton kernels, given a reference implementation.
778
- ```
779
-
780
- 4. Get help:
781
880
  ```bash
782
- mini-code --help
881
+ python3 scripts/lint.py # lint (standard library only)
882
+ python3 -m unittest discover -s tests -p "test_*.py" # run the test suite
783
883
  ```
784
- ```
785
- Agent loop for interacting with a language model
786
-
787
- options:
788
- -h, --help show this help message and exit
789
- --url URL API host, default=http://0.0.0.0:30000
790
- --max-tokens MAX_TOKENS
791
- Maximum tokens for LLM response, default=None
792
- --temperature TEMPERATURE
793
- Temperature for LLM, default=1.0
794
- --model MODEL Model name, default=None
795
- --api-key API_KEY API key for authentication. If not set, it tries to find it in env variable: MINI_CODE_API_KEY.
796
- --cache-dir CACHE_DIR
797
- The cache dir for the session histories. default=~/.cache/mini_code/sessions/
798
- --restore-session RESTORE_SESSION
799
- The location of a previous session to continue. (e.g. ~/.cache/mini_code/sessions/1792028090823027-a9d77653/)
800
- --load-last-session Load the most recent previous session from the cache dir and continue it (under a new session id), instead of starting fresh. --restore-session takes precedence if also given.
801
- --system-prompt SYSTEM_PROMPT
802
- Replace system prompt, with a custom system prompt.
803
- -a, --auto-mode Whether to run the agent in `auto-mode'. Or default: `manual-mode'.
804
- --agent-md AGENT_MD If the agent should use an agent-md file... (it will added after system message.)
805
- --prompt PROMPT An initial prompt from the user...
806
- --ask-permission Ask for permission before any tool call. (Shell ALLOW-tier commands skip the prompt; DENY is blocked.)
807
- --sudo DANGEROUS: never ask for permission. Every non-destructive tool call and shell command runs automatically without confirmation. Destructive (DENY-tier) commands are still refused.
808
- --allowed-dir ALLOWED_DIR
809
- Allowed directory for file operations, default='./'
810
- -s, --enable-shell Allow shell execution. default= False
811
- --enable-subagents Allow the agent to delegate work to sub-agents (exposed as extra tools). default= False
812
- --llm-timeout LLM_TIMEOUT
813
- HTTP timeout in seconds for LLM requests (reasoning models can be slow). default=500
814
- --tool-timeout TOOL_TIMEOUT
815
- Timeout in seconds for a single tool call. default=120
816
- --plan Enable plan mode: the agent keeps a CURRENT_PLAN.md
817
- (its step-by-step plan, marked finished when the goal
818
- is done) and CURRENT_GOAL.md (the user's latest
819
- instruction) in the session directory. Also changes
820
- how history compaction works.
821
- --verbose Print the full, detailed output. Without it (default),
822
- only user/assistant turns, token usage and tool calls
823
- are shown.
824
- ```
825
-
826
- ### In-session commands
827
884
 
828
- ```
829
- /history list the conversation (turn number, what happened, where)
830
- /history <n> show the full messages recorded for turn n
831
- /reset [<n>] rewind to the end of turn n (drops everything after it)
832
- /clear clear the screen (keeps the conversation history)
833
- /plan show the current goal + plan (plan mode only)
834
- /help show this help
835
- /quit, /exit save the session and exit
836
- ```
885
+ Releases are cut by tagging `main`: pushing a `v*` tag triggers
886
+ [`.github/workflows/release.yml`](.github/workflows/release.yml), which builds the sdist + wheel,
887
+ verifies them with `twine check`, and attaches them to a new GitHub release.
837
888
 
838
- ## Testing
889
+ ## Documentation
839
890
 
840
- The project ships with a small standard-library test suite (no extra dependencies to install):
891
+ Everything beyond this README lives in [`docs/`](docs/):
841
892
 
842
- ```bash
843
- # Run the whole suite from the repo root:
844
- python3 -m unittest discover -s tests -p "test_*.py"
845
-
846
- # ...or run a single test file:
847
- python3 tests/test_tools.py
848
- python3 tests/test_sandboxing.py
849
- python3 tests/test_agent_loop.py
850
- python3 tests/test_shell_safety.py
851
- ```
893
+ | Document | What it covers |
894
+ | --- | --- |
895
+ | [**docs/README_DEV.md**](docs/README_DEV.md) | developer guide — local setup, repository layout, linting, the test suite, CI and the release / PyPI upload process |
896
+ | [**docs/ARCHITECTURE.md**](docs/ARCHITECTURE.md) | design — module layout, on-disk conversation state (`history_{n}.json`, `summary_history.json`, usage files), the sub-agent framework and how to extend it |
897
+
898
+ This README stays the user-facing entry point (install, CLI flags, tools, sub-agents,
899
+ in-session commands, modes &amp; safety); the two documents above go deeper on the developer
900
+ and design side.
901
+
902
+ ## Modes & safety
903
+
904
+ ### Shell execution — `-s` / `--enable-shell`
905
+
906
+ Everything the agent runs from the shell first passes a **safety classifier** that sorts the
907
+ command into one of three tiers:
908
+
909
+ | Tier | Examples | What happens |
910
+ | --- | --- | --- |
911
+ | **DENY** | `rm -rf /`, `dd of=/dev/...`, `mkfs.*`, fork bombs | refused outright, never run |
912
+ | **ASK** | `rm file`, `sudo ...`, `chmod`, `curl ... \| sh` | requires your confirmation |
913
+ | **ALLOW** | `ls`, `cat`, `git status` | runs without prompting |
914
+
915
+ > [!WARNING]
916
+ > The classifier is **always enforced** — even in auto-mode and with `--sudo` — so the agent
917
+ > cannot run destructive commands unattended. It is a heuristic, not a sandbox: use it with care.
918
+ > `--allowed-dir` sandboxes **file tools**, not the shell.
919
+
920
+ ### Plan mode — `-p` / `--plan`
921
+
922
+ The loop keeps two human-readable tracking files in the session directory: `CURRENT_GOAL.md`
923
+ (your latest instruction) and `CURRENT_PLAN.md` (a step-by-step plan for that goal, marked
924
+ finished when it is done). They are authored by the *loop*, not the agent, live outside
925
+ `--allowed-dir`, and can be inspected any time with `/plan`.
852
926
 
853
- The tests focus on the parts of the agent that are easy to get wrong and worth guarding:
927
+ > [!NOTE]
928
+ > Plan mode also changes **history compaction**: after the transcript is compacted to a summary,
929
+ > `CURRENT_PLAN.md` and `CURRENT_GOAL.md` are re-injected, so the agent keeps working against the
930
+ > same goal. When the work looks done the plan is reviewed and any outstanding task is re-queued
931
+ > before the agent returns to you.
854
932
 
855
- - **`test_sandboxing.py`** — the `--allowed-dir` sandbox. Verifies that child paths are allowed, while `..` traversal and sibling paths outside the allowed directory are rejected.
856
- - **`test_tools.py`** — the tool functions. Confirms they *return* their results/errors (instead of printing), that `run_shell_command` captures stderr and honors a timeout, and that the generated tool schema exposes the expected parameters.
857
- - **`test_agent_loop.py`** — agent-loop behaviour. Confirms that enabling the shell forces per-command permission prompts, that memory compaction is correctly wired (accepts token accounting), and that token-usage formatting handles servers that report no usage.
858
- - **`test_shell_safety.py`** — the shell command classifier. Confirms commands are sorted into the three tiers correctly: destructive commands (`rm -rf /`, `dd of=/dev/...`, `mkfs.*`, fork bombs) are **DENY**, risky ones (`rm file`, `sudo`, `curl | sh`, redirects to `/etc/...`) are **ASK**, and safe ones (`ls`, `cat`, `git status`) are **ALLOW**.
933
+ ### Sessions — resume, or start fresh
859
934
 
860
- This keeps the tool honest as it grows, and makes it safe to experiment with riskier features (like `--enable-shell`) without regressions.
935
+ Every session is saved under `--cache-dir` (default `~/.cache/mini/sessions/`).
861
936
 
862
- ## Other useful commands:
937
+ > [!TIP]
938
+ > If a previous session exists but you did **not** ask to resume one (neither
939
+ > `--load-last-session` nor `--restore-session`), the prompt offers **Resume / Start new / Exit**
940
+ > before the conversation begins. Ctrl-C or EOF there is a graceful exit. This is the *asking*
941
+ > variant; `--load-last-session` is the *silent* one.
942
+
943
+
944
+ | Flag | Behaviour |
945
+ | --- | --- |
946
+ | `--restore-session PATH` | continue that exact session (a session directory or a bare session id under `--cache-dir`) |
947
+ | `-l`, `--load-last-session` | continue the session recorded in the `.mini/last_session.json` pointer, without asking |
948
+
949
+ `--load-last-session` continues that session **in place** (same id, same folder, same
950
+ messages), so the conversation you were in is the one you get back; an explicit
951
+ `--restore-session` wins if both are given. The "most recent" session comes from a single
952
+ source — the tiny `.mini/last_session.json` pointer written when a session starts or is
953
+ restored inside `--allowed-dir` (deliberately no timestamp fallback: with no pointer, a fresh
954
+ session starts). That pointer lives in the same `.mini` directory as `--skills`, but as its
955
+ own dedicated file, so the two never clash.
956
+
957
+ A session folder is restorable only if it has what this version writes: a valid
958
+ `summary_history.json` recorder, plus the `history_{n}.json` segment its last record names
959
+ (usage files are optional). Anything else — a folder from an older release, a hand-assembled
960
+ transcript, a recorder that does not validate, a missing segment — is **refused with a note
961
+ saying why**, and a fresh session is started instead. Nothing is repaired, guessed at, or
962
+ written into the refused folder.
963
+
964
+ ### Context compaction — `--max-context-tokens`
965
+
966
+ Compaction is decided by **tokens only**, never by message count: a few large tool outputs can
967
+ fill a window that hundreds of short turns would not. The next request is projected from the
968
+ server-reported `prompt_tokens`, plus an estimate of what was appended since, plus the output
969
+ reserve (`--max-tokens`). Unset (default) it is derived from the model's context window minus the
970
+ output reserve and a safety margin. Lower it to compact sooner, raise it to compact later — there
971
+ is no message-count cap to configure.
972
+
973
+
974
+ ## Serving a model locally
975
+
976
+ Tested with vLLM v0.30 (tool calling enabled):
863
977
 
864
- ### Serving a vllm model locally (with correct tools). vllm v0.30 (tested):
865
978
  ```bash
866
979
  vllm serve ornith-ai/Ornith-1.5-397B-FP8 \
867
980
  --tensor-parallel-size 4 \
@@ -875,17 +988,19 @@ vllm serve ornith-ai/Ornith-1.5-397B-FP8 \
875
988
 
876
989
  ## Citation
877
990
 
878
- If you use `mini-code-cli` in your research or writing, please cite it using the BibTeX entry below:
991
+ If you use `mini-code-cli` in your research or writing, please cite it:
879
992
 
880
993
  ```bibtex
881
994
  @misc{mini-code-cli,
882
995
  author = {Rozanov, Nikolai},
883
996
  title = {mini-code-cli: A minimal, dependency-light coding agent},
884
997
  year = {2026},
885
- version = {0.1.0.0},
998
+ version = {0.1.1.0},
886
999
  howpublished = {\url{https://github.com/ai-nikolai/mini-code-cli}},
887
1000
  note = {A no-bloat, dependency-free agent CLI for experimenting.}
888
1001
  }
889
1002
  ```
890
1003
 
891
- ## (C) Nikolai Rozanov, 2026 - Present
1004
+ ## License
1005
+
1006
+ [AGPL-3.0](LICENSE) — (C) Nikolai Rozanov, 2026 – present.