dostuff 0.2.0__tar.gz → 0.2.2__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 (129) hide show
  1. {dostuff-0.2.0 → dostuff-0.2.2}/PKG-INFO +97 -38
  2. {dostuff-0.2.0 → dostuff-0.2.2}/README.md +95 -35
  3. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/__init__.py +5 -0
  4. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/agent/call_agent.py +2 -2
  5. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/agent/loop.py +18 -12
  6. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/agent/permissions.py +47 -5
  7. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/agent/run_tool.py +2 -0
  8. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/cli.py +69 -51
  9. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/cli_tui.py +412 -29
  10. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/config.py +49 -5
  11. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/headless.py +56 -13
  12. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/agent/constants.py +7 -2
  13. dostuff-0.2.2/dostuff/helpers/agent/context_usage.py +85 -0
  14. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/agent/get_model_token_limit.py +2 -2
  15. dostuff-0.2.2/dostuff/helpers/agent/quick_memory.py +33 -0
  16. dostuff-0.2.2/dostuff/helpers/mcp/token_store.py +81 -0
  17. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/models/list_models.py +13 -1
  18. dostuff-0.2.2/dostuff/helpers/models/opencode.py +76 -0
  19. dostuff-0.2.2/dostuff/helpers/skills/custom_commands.py +51 -0
  20. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/skills/skill_command.py +12 -6
  21. dostuff-0.2.2/dostuff/helpers/ui/doctor.py +47 -0
  22. dostuff-0.2.2/dostuff/helpers/ui/terminal_signals.py +50 -0
  23. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/lib/mcp/mcp_client.py +90 -36
  24. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/lib/memory/session_store.py +14 -0
  25. dostuff-0.2.2/dostuff/lib/model.py +60 -0
  26. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/setup_wizard.py +13 -3
  27. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/templates/config.example.yaml +11 -0
  28. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/templates/env.example +1 -0
  29. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/settings.py +2 -2
  30. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff.egg-info/PKG-INFO +97 -38
  31. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff.egg-info/SOURCES.txt +9 -0
  32. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff.egg-info/requires.txt +1 -3
  33. {dostuff-0.2.0 → dostuff-0.2.2}/pyproject.toml +3 -5
  34. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_checkpoints_todos_caching.py +0 -1
  35. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_cli_commands.py +50 -1
  36. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_mcp_oauth.py +110 -1
  37. dostuff-0.2.2/tests/test_opencode.py +81 -0
  38. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_permissions.py +35 -0
  39. dostuff-0.2.2/tests/test_roadmap_021.py +84 -0
  40. dostuff-0.2.2/tests/test_terminal_signals.py +57 -0
  41. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_tui.py +166 -0
  42. dostuff-0.2.0/dostuff/helpers/mcp/token_store.py +0 -46
  43. dostuff-0.2.0/dostuff/lib/model.py +0 -36
  44. {dostuff-0.2.0 → dostuff-0.2.2}/LICENSE +0 -0
  45. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/__main__.py +0 -0
  46. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/agent/instructions.py +0 -0
  47. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/agent/append_step.py +0 -0
  48. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/agent/consume_stream.py +0 -0
  49. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/agent/environment_context.py +0 -0
  50. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/agent/file_mentions.py +0 -0
  51. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/agent/load_identity.py +0 -0
  52. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/agent/load_project_instructions.py +0 -0
  53. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/agent/loop_check_cancelled.py +0 -0
  54. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/agent/loop_emit.py +0 -0
  55. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/agent/manage_context.py +0 -0
  56. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/agent/model_cost.py +0 -0
  57. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/agent/pastes.py +0 -0
  58. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/agent/slash_suggestion.py +0 -0
  59. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/agent/tool_output.py +0 -0
  60. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/mcp/load_mcp_config.py +0 -0
  61. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/mcp/mcp_oauth.py +0 -0
  62. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/mcp/server_config.py +0 -0
  63. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/memory/export_session.py +0 -0
  64. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/memory/resolve_memory_operation.py +0 -0
  65. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/memory/shell_step.py +0 -0
  66. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/models/add_model_entry.py +0 -0
  67. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/skills/discover_skills.py +0 -0
  68. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/tools/diff.py +0 -0
  69. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/tools/generate_tool_schema.py +0 -0
  70. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/tools/project_root.py +0 -0
  71. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/tools/resolve_safe_path.py +0 -0
  72. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/ui/__init__.py +0 -0
  73. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/ui/emit.py +0 -0
  74. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/helpers/ui/prompt_history.py +0 -0
  75. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/lib/checkpoints.py +0 -0
  76. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/lib/exceptions.py +0 -0
  77. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/lib/mcp/mcp_client_registration_store.py +0 -0
  78. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/lib/mcp/mcp_tool_registry_store.py +0 -0
  79. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/lib/memory/chroma.py +0 -0
  80. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/lib/memory/episodic_memory_store.py +0 -0
  81. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/lib/memory/semantic_memory_store.py +0 -0
  82. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/lib/memory/stores.py +0 -0
  83. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/lib/memory/types.py +0 -0
  84. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/lib/tracing.py +0 -0
  85. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/lib/worktree.py +0 -0
  86. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/memory/__init__.py +0 -0
  87. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/skills.py +0 -0
  88. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/__init__.py +0 -0
  89. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/bash/bash_command.py +0 -0
  90. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/definitions.py +0 -0
  91. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/delegate_to_subagent.py +0 -0
  92. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/files/delete_file.py +0 -0
  93. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/files/edit_file.py +0 -0
  94. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/files/list_files.py +0 -0
  95. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/files/read_file.py +0 -0
  96. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/files/write_file.py +0 -0
  97. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/get_current_datetime.py +0 -0
  98. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/mcp/call_mcp_tool.py +0 -0
  99. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/mcp/get_mcp_tool_details.py +0 -0
  100. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/mcp/search_mcp_tools.py +0 -0
  101. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/memory/save_episode.py +0 -0
  102. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/memory/save_memory.py +0 -0
  103. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/search/glob.py +0 -0
  104. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/search/grep.py +0 -0
  105. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/search/walk.py +0 -0
  106. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/todo_write.py +0 -0
  107. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/web_fetch.py +0 -0
  108. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff/tools/web_search.py +0 -0
  109. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff.egg-info/dependency_links.txt +0 -0
  110. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff.egg-info/entry_points.txt +0 -0
  111. {dostuff-0.2.0 → dostuff-0.2.2}/dostuff.egg-info/top_level.txt +0 -0
  112. {dostuff-0.2.0 → dostuff-0.2.2}/setup.cfg +0 -0
  113. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_config_memory_mcp.py +0 -0
  114. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_file_mentions.py +0 -0
  115. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_file_tools.py +0 -0
  116. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_loop.py +0 -0
  117. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_mcp_e2e.py +0 -0
  118. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_optional_memory_and_instructions.py +0 -0
  119. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_pastes.py +0 -0
  120. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_session_store.py +0 -0
  121. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_settings_tools.py +0 -0
  122. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_setup_wizard.py +0 -0
  123. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_skill_command.py +0 -0
  124. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_slash_suggestion.py +0 -0
  125. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_subagent.py +0 -0
  126. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_tool_schemas.py +0 -0
  127. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_web_fetch.py +0 -0
  128. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_web_search.py +0 -0
  129. {dostuff-0.2.0 → dostuff-0.2.2}/tests/test_worktree.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dostuff
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: DoStuff - a terminal coding agent for any LLM: TUI and headless mode, permissions, MCP, skills, web tools, sessions and git worktrees
5
5
  Author-email: Varun Kumawat <varunkumawatleap2@gmail.com>
6
6
  License-Expression: MIT
@@ -32,6 +32,7 @@ Requires-Dist: opentelemetry-api>=1.20
32
32
  Requires-Dist: opentelemetry-sdk>=1.20
33
33
  Requires-Dist: textual>=0.50.0
34
34
  Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.20
35
+ Requires-Dist: keyring>=24
35
36
  Provides-Extra: memory
36
37
  Requires-Dist: chromadb>=1.5.0; extra == "memory"
37
38
  Provides-Extra: search
@@ -40,8 +41,6 @@ Provides-Extra: full
40
41
  Requires-Dist: dostuff[memory,search]; extra == "full"
41
42
  Requires-Dist: onnxruntime>=1.16; extra == "full"
42
43
  Requires-Dist: grpcio>=1.52; extra == "full"
43
- Provides-Extra: keyring
44
- Requires-Dist: keyring>=24; extra == "keyring"
45
44
  Provides-Extra: dev
46
45
  Requires-Dist: pytest>=8; extra == "dev"
47
46
  Requires-Dist: mypy>=1.10; extra == "dev"
@@ -74,26 +73,28 @@ DoStuff is a terminal AI agent that runs anywhere `pip` runs. It gives you a ful
74
73
 
75
74
  ## Features
76
75
 
77
- - **Textual TUI** with per-role colored messages, status bar, and a loading/timer spinner
78
- - **Multi-provider LLMs** via [litellm](https://docs.litellm.ai/docs/providers) — OpenAI, Anthropic, Gemini, Groq, Mistral, Ollama, OpenRouter
79
- - **Persistent sessions** in SQLite; resume with `dostuff resume` or `dostuff --session <id>`
76
+ - **Textual TUI** with a `/` command menu, `@file` completion, `!shell` commands, an in-app config editor, a configurable status bar and a live turn timer
77
+ - **Headless mode** — `dostuff -p "<prompt>"` runs one prompt and prints the answer (`--output-format json|stream-json`, `--max-turns`, `--allowed-tools` for scripts and CI)
78
+ - **Multi-provider LLMs** via [litellm](https://docs.litellm.ai/docs/providers) — OpenAI, Anthropic, Gemini, Groq, Mistral, Ollama, OpenRouter, OpenCode Zen / Go
79
+ - **Persistent sessions** in SQLite; resume with `dostuff -c`, `dostuff resume` or `dostuff --session <id>`, branch one off with `/fork`
80
+ - **Git worktrees** — `/worktree` or `dostuff -w` runs a session on its own branch and checkout; subagents can run in their own worktree too
80
81
  - **Long-term memory** (semantic + episodic) backed by ChromaDB — optional, `pip install "dostuff[memory]"`
81
82
  - **MCP server support** — stdio (npx, uvx) and HTTP transports
82
83
  - **`@file` mentions** — type `@` in the prompt to pick a file or folder; its content (or listing) is sent with the message
83
84
  - **Project instructions** — `AGENTS.md` / `CLAUDE.md` from `~/.dostuff/`, the repo root and every folder down to the current one, combined
84
85
  - **Coding tools** — `read_file` (line numbers, offset/limit), `edit_file` (exact replacement), `write_file`, `grep`, `glob`, `list_files`, `delete_file`, `bash_command`, `web_fetch` (read a URL as text), `web_search` (free, no API key)
85
- - **Permission layer** — mutating tool calls ask for approval (`y` once / `a` always this session / `n` deny); read-only shell commands run without asking; modes `ask` / `allowlist` / `auto`
86
+ - **Permission layer** — mutating tool calls ask for approval (allow once / always this session / deny with a note); read-only shell commands run without asking; modes `ask` / `allowlist` / `auto`; `/undo` reverts the agent's file changes
86
87
  - **File sandbox** — file tools stay inside the project directory and never read `.env*` files or `~/.dostuff/`
87
88
  - **Skills loader** — drop a `SKILL.md` in the right folder, restart, done; run one with `/<skill-name> [args]`
88
89
  - **Subagents** — `delegate_to_subagent` runs a bounded task with a restricted tool set; its approval prompts and ESC go through the same TUI
89
90
  - **Per-tool timeout** (120s) to prevent hung servers; long tool output is truncated (head + tail) before it reaches the model
90
91
  - **Retries with backoff** for rate limits, timeouts and 5xx errors (6 by default, exponential with jitter, honors `Retry-After`; `loop.max_retries` / `loop.retry_max_delay`); auth / bad-request errors fail fast
91
- - **Token and cost tracking** — per-turn and cumulative totals in `/status` and the line after each turn (`✻ Worked for 1m 5s · $0.01`); cost in USD from litellm's price table (hidden when the model has no known price)
92
+ - **Token and cost tracking** — per-turn and cumulative totals in `/status` and the line after each turn (`✻ Worked for 1m 5s · $0.01`); cost in USD from litellm's price table (hidden when the model has no known price). The table bundled with litellm is used, so startup doesn't wait on a download; set `LITELLM_LOCAL_MODEL_COST_MAP=False` to fetch the latest one from GitHub instead
92
93
  - **Long-term memory tools** — the agent saves facts (`save_memory`) and notable moments (`save_episode`) as they come up; both are recalled in later sessions
93
94
  - **Graceful exit** — `Ctrl+Q` or `/exit` saves the session, cleans up, and stops background workers
94
95
  - **Clean Cancellation** — `Escape` can cancel in-flight agent turns cleanly without corrupting the session
95
96
  - **2-state session split** — `session_steps` (full audit) / `working_history` (LLM payload); DB persists both plus `compaction_notes` + `last_input_tokens`
96
- - **Auto & Manual Compaction** — Manual `/compact` runs compaction and saves it. Auto-compaction triggers automatically during the agent loop if context usage (`last_input_tokens`) exceeds 50% of the model's token limit. It keeps at least 15% or 20k tokens of the most recent steps in the working history, summarizing the rest into `compaction_notes` which are appended to system instructions.
97
+ - **Auto & Manual Compaction** — Manual `/compact` runs compaction and saves it. Auto-compaction triggers automatically during the agent loop if context usage (`last_input_tokens`) exceeds `loop.auto_compact_threshold` (default 50%) of the model's token limit; `off` disables it (an overflowing window is still compacted), and `/compact auto <N|off>` changes it for the session. It keeps at least 15% or 20k tokens of the most recent steps in the working history, summarizing the rest into `compaction_notes` which are appended to system instructions.
97
98
  - **Tracing (opt-in)** — OTLP tracing support built into `lib/tracing.py`; prompt and tool content are redacted from spans by default
98
99
 
99
100
  ---
@@ -108,15 +109,19 @@ pip install dostuff
108
109
 
109
110
  This installs the `dostuff` command on your `PATH`. Done.
110
111
 
111
- Long-term memory (the agent remembers facts and past decisions across sessions) needs ChromaDB,
112
- a large download, so it's an extra:
112
+ Optional features come as extras:
113
113
 
114
- ```bash
115
- pip install "dostuff[memory]"
116
- ```
114
+ | Install | Adds |
115
+ |---|---|
116
+ | `pip install dostuff` | Everything except the extras below, including MCP (with OAuth tokens kept in the OS keyring) |
117
+ | `pip install "dostuff[memory]"` | Long-term memory (facts and past decisions across sessions) and semantic MCP tool search, via ChromaDB. Large download |
118
+ | `pip install "dostuff[search]"` | Steadier `web_search` through the `ddgs` package (several engines) instead of DuckDuckGo's HTML page |
119
+ | `pip install "dostuff[full]"` | `memory` + `search` |
120
+ | `pip install "dostuff[dev]"` | `pytest` and `mypy`, for working on dostuff itself |
117
121
 
118
- Without it everything else works: the memory tools are hidden from the model and MCP tool search
119
- matches keywords instead of meaning. `dostuff doctor` shows whether memory is on.
122
+ Extras combine, e.g. `pip install "dostuff[memory,search]"`. Without `memory` everything else
123
+ works: the memory tools are hidden from the model and MCP tool search matches keywords instead of
124
+ meaning. `dostuff doctor` shows whether memory is on.
120
125
 
121
126
  ### Other install methods
122
127
 
@@ -124,17 +129,18 @@ For an isolated install with [pipx](https://pypa.github.io/pipx/):
124
129
 
125
130
  ```bash
126
131
  pipx install dostuff
132
+ pipx install "dostuff[full]" # with extras
127
133
  ```
128
134
 
129
135
  For development (editable mode, from a clone):
130
136
 
131
137
  ```bash
132
- git clone https://github.com/<you>/dostuff.git
133
- cd dostuff
138
+ git clone https://github.com/kVarunkk/DoStuff.git
139
+ cd DoStuff
134
140
  pip install -e . # core
135
141
  pip install -e ".[memory]" # + long-term memory (chromadb)
136
- pip install -e ".[full]" # + memory + onnxruntime + grpcio
137
- pip install -e ".[keyring]" # persist MCP OAuth tokens in the OS keyring
142
+ pip install -e ".[search]" # + ddgs web search
143
+ pip install -e ".[full]" # + memory + search
138
144
  pip install -e ".[dev]" # + pytest + mypy
139
145
 
140
146
  python -m pytest -q tests
@@ -185,17 +191,19 @@ In the TUI:
185
191
  | `dostuff` | Launch the interactive TUI |
186
192
  | `dostuff --version` | Print the version (`-V`) |
187
193
  | `dostuff --session <id>` | Resume a prior session (asks before starting a new one if the ID is unknown) |
194
+ | `dostuff -c` / `--continue` | Resume the latest session in the current directory (same as `dostuff resume`; works with `-p` too) |
195
+ | `dostuff -w` / `--worktree-name <name>` | Start the session in a new git worktree (`.dostuff/worktrees/<name>`, branch `dostuff/<name>`) |
188
196
  | `dostuff init [--force]` | Create `.dostuff/` config/skills in current dir (won't overwrite without `--force`) |
189
197
  | `dostuff setup` | Pick a model, save its API key, write `~/.dostuff/config.yaml` (runs automatically on first launch) |
190
198
  | `dostuff config` | Show resolved config paths and values |
191
199
  | `dostuff doctor` | Health check: config, API key, MCP, data dir; prints a fix for each problem |
192
- | `dostuff resume [<id>]` | Resume the latest session started in the current directory (or the given one; a unique ID prefix is enough) |
200
+ | `dostuff resume [<id>]` | Resume the latest session started in the current directory (or the given one; a unique ID prefix is enough). `--fork` resumes a copy, `--worktree` moves it into a new worktree |
193
201
  | `dostuff sessions [--all] [-n N]` | List sessions in the current directory with their title or first prompt (`--all`: every directory) |
194
202
  | `dostuff sessions rename <id> <title>` | Name a session |
195
203
  | `dostuff sessions rm <id>... [-y]` | Delete sessions and their `/undo` checkpoints |
196
204
  | `dostuff sessions prune [--older-than 30d] [--dry-run] [-y]` | Delete empty sessions, and sessions not used for the given time (`45m`, `12h`, `30d`, `2w`) |
197
205
  | `dostuff export [<id>] [-o file\|-]` | Save a session (default: latest here) as Markdown: prompts, answers, tool calls and results |
198
- | `dostuff -p "<prompt>"` | Headless: run one prompt, print the answer to stdout, exit. Progress goes to stderr. Piped stdin is appended to the prompt (`-p -` reads the prompt from stdin). `--session <id>` continues a session, `--json` prints `{result, session_id, usage, ...}`, `-q` hides progress, `--permission-mode ask\|allowlist\|auto`. Without a terminal, calls that need approval are denied |
206
+ | `dostuff -p "<prompt>"` | Headless: run one prompt, print the answer to stdout, exit. Progress goes to stderr. Piped stdin is appended to the prompt (`-p -` reads the prompt from stdin). `--session <id>` continues a session, `--output-format json` (or `--json`) prints `{result, session_id, usage, ...}`, `--output-format stream-json` prints one JSON event per line (`init`, `assistant`, `tool_call`, `tool_result`, `usage`, `error`, then `result`), `-q` hides progress, `--permission-mode ask\|allowlist\|auto\|plan`. `--max-turns N` stops after N model calls (exit code 1). `--allowed-tools` (comma-separated or repeated) runs matching calls without asking in any mode, in the `permissions.allow` syntax (`"npm test"`, `web_fetch:docs.python.org`) or a tool name for every call of it (`write_file`, `bash_command`). Without a terminal, other calls that need approval are denied |
199
207
  | `dostuff mcp list` | Show MCP servers and the file each comes from |
200
208
  | `dostuff mcp add <name> [-e K=V] -- <command> [args...]` | Add a stdio server; `--url <url> [-H "Name: value"]` for HTTP; `--project` writes `./.dostuff/mcp_config.json` |
201
209
  | `dostuff mcp remove <name> [--project]` | Remove a server |
@@ -209,23 +217,39 @@ In the TUI:
209
217
  | Key / command | Action |
210
218
  | ------------- | ----------------------------------- |
211
219
  | `Enter` | Submit message |
220
+ | `/` | Open the command menu (type to filter, `Tab` completes, `Enter` runs) |
221
+ | `!<command>` | Run a shell command directly (no approval); the command and its output are shown to the model on the next turn |
222
+ | `# <note>` | Add `- <note>` to `AGENTS.md`: you pick this project's or the global one (`~/.dostuff/AGENTS.md`); the agent follows it from the next message |
212
223
  | `Shift+Enter` | Insert a newline (multi-line input). If your terminal sends it as plain Enter, use `\` then `Enter`, `Ctrl+Enter`, `Alt+Enter` or `Ctrl+J` |
213
224
  | `@path` | Attach a file (numbered lines) or a folder listing to the message. Typing `@` lists matching project paths: `Tab` / `Enter` completes, a folder opens for the next part. `@"a b.txt"` for spaces. Also works with `dostuff -p`. `.env` files and binaries are never attached |
214
225
  | `Tab` | While typing a slash command, accept the dim ghost text after the cursor: the rest of the command name, then its flag (`/model ` → `--active`, `/fork ` → `--worktree`). `Right` accepts it too |
215
226
  | Paste | A paste over 10 lines (`ui.paste_collapse_lines`) or 2,000 chars shows as `[Pasted text #1 +243 lines]` and is expanded when you send it. Over 200 lines (`loop.paste_file_lines`) it's saved to `.dostuff/pastes/` and the model reads it from there, so it doesn't fill the context; files are removed after `loop.paste_retention_days` (7) |
216
227
  | `Up` / `Down` | On the first / last line of the input: previous / next prompt typed in this directory (saved in `~/.dostuff/data/prompt_history.jsonl`) |
228
+ | `Ctrl+R` | Search the prompts typed in this directory (type to filter, `Enter` puts the prompt in the input) |
229
+ | `Esc` `Esc` | With an empty input: take back your last prompt. It and everything after it (answer, tool calls) leave the conversation and the prompt goes back in the input to edit and resend. Files that turn changed stay as they are; `/undo` restores them |
217
230
  | `Ctrl+O` | Expand / collapse every truncated tool and shell result (click one to toggle just that one) |
231
+ | `Shift+Tab` | Cycle the permission mode for this session: ask → auto → plan → allowlist (shown in the status bar) |
232
+ | `Ctrl+Backspace` / `Ctrl+W` / `Alt+Backspace` | Delete the previous word; `Ctrl+Delete` / `Alt+Delete` the next one |
218
233
  | `/exit` | Save the session and quit |
219
234
  | `/clear` | Start a new session; the old one stays resumable |
220
235
  | `/resume [<id>]` | Pick another session from this directory (or switch to the given one) |
236
+ | `/fork [title] [--worktree]` | Copy this session into a new one and switch to it; the original is unchanged |
237
+ | `/worktree [name]` / `/worktree exit` | Move the session into a new git worktree on branch `dostuff/<name>` / leave it (removed if unchanged, otherwise keep or remove) |
238
+ | `/permissions [mode]` | Show or change the permission mode for this session (`ask`, `allowlist`, `auto`, `plan`) |
239
+ | `/copy` | Copy the model's last answer to the clipboard |
240
+ | `/notifications [on\|off\|bell\|osc9]` | Turn turn-finished / approval notifications on or off for this session (default from `ui.notifications`) |
221
241
  | `/model [<provider/model>] [--active]` | Pick a model: your saved ones (`models:` in config.yaml) first, then "More <provider> models…" for each provider's list (type to filter; Enter on no match uses what you typed). A model that isn't saved yet is added to `~/.dostuff/config.yaml`. A plain `/model` switch lasts only for this session; add `--active` (e.g. `/model --active`, or `/model anthropic/claude-sonnet-5-5 --active`) to make it the default that new sessions start with |
222
242
  | `/config [mcp] [project]` | Edit a settings file right in the TUI: pick `config.yaml` or the MCP servers, user (`~/.dostuff`) or project (`./.dostuff`), or name one (`/config mcp project`). `Ctrl+S` checks the file, saves it and applies it without a restart (an invalid file stays open with the error); `Esc` closes, twice if there are unsaved changes. A new file starts with every option commented out. `.env` files aren't offered |
223
243
  | `/status` | Session, directory, model, permission mode, tokens, context use, MCP servers |
244
+ | `/context` | What fills the context window: system prompt, tools, MCP tools, project instructions, compaction summary and messages, with tokens, % and a bar |
245
+ | `/memory [project\|global]` | Edit `AGENTS.md` (this project's or `~/.dostuff/AGENTS.md`) in the same editor as `/config`; `Ctrl+S` saves and the agent follows it from the next message |
246
+ | `/doctor` | The `dostuff doctor` checks (config, API key, MCP config, memory), with a fix for each problem |
224
247
  | `/<skill> [args]` | Run a skill: every discovered skill is a command (listed in the `/` menu and `/help`). See [Skills](#skills) |
248
+ | `/<command> [args]` | Run a custom command from `.dostuff/commands/` or `~/.dostuff/commands/`. See [Custom commands](#custom-commands) |
225
249
  | `/rename <title>` | Name this session (shown by `dostuff sessions`) |
226
250
  | `/export [<path>]` | Save this session as Markdown (default `dostuff-session-<id>.md`) |
227
251
  | `/undo [force]` | Revert the agent's file changes from its last file-editing turn |
228
- | `/compact` | Manually trigger context compaction |
252
+ | `/compact` | Manually trigger context compaction; `/compact auto <1-100\|off>` sets the auto-compaction threshold for this session |
229
253
  | `/memories` | List the facts saved about you (and where each came from) |
230
254
  | `/episodes` | List saved episodes (decisions, corrections, fixes) recalled here, newest first |
231
255
  | `/forget <key or id>` | Delete a saved fact (by key) or episode (by the id shown in `/episodes`) |
@@ -235,14 +259,15 @@ In the TUI:
235
259
 
236
260
  **Visual elements:**
237
261
 
238
- - **User messages** — blue background
239
- - **Agent messages** — neutral
240
- - **Tool calls and results** — teal/green background
241
- - **Confirmations** — yellow background (respond `y` = allow once, `a` = always this session, anything else = deny)
262
+ - **Messages** — `>` for your prompts (on a grey band), `●` for agent replies and tool calls, `⎿` for tool results; the terminal background shows through
263
+ - **Approvals** — a selector (arrows, a number, or `y` = allow once, `a` = always this session, `n` = deny with an optional note); several calls in one response can be approved together
264
+ - **Turn summary** — `✻ Worked for 1m 5s · $0.01 · done 12:59 PM` after each turn
242
265
  - **Diffs** — `write_file` / `edit_file` changes shown as a coloured diff
243
266
  - **Errors** — red background
244
267
  - **Status bar** — `cwd • model • permission mode • context usage %` by default; `help`, `session`, `tokens` and `cost` can be added. Choose and order the items with `ui.status_bar` in `config.yaml`; when the terminal is too narrow (or zoomed in), long items are shortened and the least important dropped (help, session, cwd, tokens, cost, model, context, mode) instead of being cut off
245
268
  - **Loading** — bold `Working...` with a live elapsed timer and queued-prompt count, or streamed thoughts displayed live
269
+ - **Terminal title** — the tab / window title shows the run status: `⏳ dostuff · <folder>` while working, `✋` while an approval waits, `✓` when done; the old title comes back on exit. `ui.terminal_title: false` turns it off
270
+ - **Notifications** (off by default) — `ui.notifications: bell` (terminal bell) or `osc9` (desktop notification in iTerm2, WezTerm, Ghostty, kitty …) when a turn finishes or an approval is waiting, if it took longer than `ui.notify_after_seconds` (30) or the terminal is in the background. `/notifications` switches it per session
246
271
 
247
272
  ---
248
273
 
@@ -265,6 +290,9 @@ In the TUI:
265
290
  - `ask` (default) — as in the table above.
266
291
  - `allowlist` — as `ask`, plus the patterns in `permissions.allow` run without asking (a shell command prefix such as `npm test`, a tool name such as `write_file`, `call_mcp_tool:<server>__<tool>`, `web_fetch:<domain>`, or `web_search`).
267
292
  - `auto` — nothing asks. A red warning is shown at startup.
293
+ - `plan` — read-only: reads and read-only shell commands run; file changes, other shell commands and settings changes are denied with a "plan mode" note, and the model is told to investigate and answer with a plan. Web and MCP calls ask as in `ask`.
294
+
295
+ In the TUI, `Shift+Tab` cycles the mode for the session (ask → auto → plan → allowlist); `/permissions <mode>` picks one.
268
296
 
269
297
  Answering `a` (always) approves that tool, or for the shell those commands, for the rest of the session.
270
298
 
@@ -333,7 +361,7 @@ memory:
333
361
  episodic_scope: project # recall past episodes from this directory (project) or anywhere (user)
334
362
 
335
363
  permissions:
336
- mode: ask # ask | allowlist | auto
364
+ mode: ask # ask | allowlist | auto | plan
337
365
  allow: []
338
366
  ```
339
367
 
@@ -367,10 +395,12 @@ The model resolution maps model names (using [litellm format](https://docs.litel
367
395
  | Provider | Example Model name | API key env |
368
396
  | --------- | -------------------------------------- | ------------------- |
369
397
  | OpenAI | `openai/gpt-4o-mini` | `OPENAI_API_KEY` |
370
- | Anthropic | `anthropic/claude-3-5-sonnet-20240620` | `ANTHROPIC_API_KEY` |
398
+ | Anthropic | `anthropic/claude-sonnet-5-5` | `ANTHROPIC_API_KEY` |
371
399
  | Gemini | `gemini/gemini-3.1-flash-lite` | `GEMINI_API_KEY` |
372
400
  | Groq | `groq/llama-3.1-70b-versatile` | `GROQ_API_KEY` |
373
401
  | Ollama | `ollama/llama3.1` | _(none)_ |
402
+ | OpenCode Zen | `opencode/claude-sonnet-5-5` | `OPENCODE_API_KEY` |
403
+ | OpenCode Go | `opencode-go/kimi-k3` | `OPENCODE_API_KEY` |
374
404
 
375
405
  If `name` has no `/`, the provider prefix is dynamically inferred from the model name prefix or configured `provider` fields.
376
406
 
@@ -382,7 +412,9 @@ dostuff models add anthropic/claude-sonnet-5-5 # add it (pick it with
382
412
  dostuff models add groq/llama-3.3-70b-versatile --active # add it and make it the default
383
413
  ```
384
414
 
385
- or `/model` inside the TUI. Model lists come from litellm's catalog (chat models, without dated snapshots that have an alias), from OpenRouter's public model list, and for Ollama from the models you've pulled (the server must be running). A name that isn't listed still works. Then put the provider's key in `~/.dostuff/.env`. A project's `./.dostuff/config.yaml` with its own `models:` list replaces the global list in that directory.
415
+ or `/model` inside the TUI. Model lists come from litellm's catalog (chat models, without dated snapshots that have an alias), from OpenRouter's and OpenCode's public model lists, and for Ollama from the models you've pulled (the server must be running). A name that isn't listed still works. Then put the provider's key in `~/.dostuff/.env`. A project's `./.dostuff/config.yaml` with its own `models:` list replaces the global list in that directory.
416
+
417
+ OpenCode models (`opencode/<id>` for Zen, `opencode-go/<id>` for a Go subscription) use the ids from the [OpenCode docs](https://opencode.ai/docs/zen/). litellm has no OpenCode provider, so DoStuff sends each model to the gateway endpoint for its family: Claude models (and a few Qwen / MiniMax models) to the Anthropic Messages endpoint, GPT / Grok / Muse models to the Responses endpoint, Gemini models to the Gemini endpoint, and all other models to chat completions. One console key in `OPENCODE_API_KEY` works for Zen and Go. OpenCode only allows its free models from its own app, so use paid models or Go.
386
418
 
387
419
  ---
388
420
 
@@ -434,7 +466,7 @@ MCP servers connect concurrently in the background, so the TUI never blanks duri
434
466
 
435
467
  MCP tools are named `<server>__<tool>` (e.g. `github__create_issue`), so two servers can expose a tool with the same name. `search_mcp_tools` only returns tools of servers that are connected right now.
436
468
 
437
- **OAuth (HTTP servers):** a browser login opens when the server answers 401. The flow uses PKCE, a random `state` and an RFC 8707 `resource` indicator; the local callback on port 8085 times out after 120 s. Tokens are kept in memory, or in the OS keyring if you install `dostuff[keyring]`, never in a plain file. A tool call that fails with 401 re-authenticates once and retries.
469
+ **OAuth (HTTP servers):** a browser login opens when the server answers 401. The flow uses PKCE, a random `state` and an RFC 8707 `resource` indicator; the local callback on port 8085 times out after 120 s. Tokens are stored in the OS keyring (memory only if no keyring backend is available), never in a plain file. Expired access tokens are refreshed with the refresh token, before a request or after a 401, without opening the browser; you sign in again only when the refresh token itself is rejected.
438
470
 
439
471
  To force a re-registration, delete:
440
472
 
@@ -452,7 +484,8 @@ added to the system prompt, most general first, so the closest one wins where th
452
484
  1. `~/.dostuff/AGENTS.md` — your instructions for every project
453
485
  2. one per folder from the top of the path down to the current directory (e.g. the repo root, then a sub-package)
454
486
 
455
- In a folder with both, `AGENTS.md` is used. They're read once at startup.
487
+ In a folder with both, `AGENTS.md` is used. They're read once at startup, and again after you change
488
+ one from the TUI: `# <note>` adds a line to this project's or the global file, and `/memory` opens one in an editor.
456
489
 
457
490
  ---
458
491
 
@@ -470,8 +503,6 @@ Skills are directories containing a `SKILL.md` (frontmatter with `name` and `des
470
503
 
471
504
  **Conflict resolution:** No deduplication in the system prompt. If two skills share the same name (from different directories), both are loaded and passed to the model — the agent may see the same skill twice with different `location` paths. To avoid confusion, keep names unique across the search paths.
472
505
 
473
- **Running a skill:** every skill is also a slash command, `/<name> [args]` (shown in the `/` menu marked `(skill)` and in `/help`). It runs a turn with the skill's `SKILL.md` body plus your arguments; `@mentions` in the arguments are expanded. Also works headless: `dostuff -p "/my-skill fix the tests"`. Built-in commands win a name clash, the first skill found (in the order above) wins between skills, and names with spaces get no command.
474
-
475
506
  **Example structure:**
476
507
 
477
508
  ```text
@@ -493,10 +524,28 @@ description: One-line description of what this skill does
493
524
  Detailed instructions for the agent go here.
494
525
  ```
495
526
 
496
- **Running a skill yourself:** each skill is also a slash command, `/<name> [arguments]` (e.g. `/my-skill src/app.py`), in the TUI and with `dostuff -p "/my-skill ..."`. The turn's message is the skill's `SKILL.md` body plus your arguments (which can use `@path` mentions), so the model follows it straight away instead of deciding whether to read it. Built-in commands win a name clash, and names with spaces can't be run this way; the model can still use those skills on its own.
527
+ **Running a skill yourself:** each skill is also a slash command, `/<name> [arguments]` (e.g. `/my-skill src/app.py`), in the TUI and with `dostuff -p "/my-skill ..."`. The turn's message is the skill's `SKILL.md` body plus your arguments (which can use `@path` mentions), so the model follows it straight away instead of deciding whether to read it. The command shows in the `/` menu marked `(skill)` and in `/help`. Built-in commands win a name clash, the first skill found (in the order above) wins between skills, and names with spaces can't be run this way; the model can still use those skills on its own.
497
528
 
498
529
  Run `dostuff init` to bootstrap a local `.dostuff/skills/` folder. Restart the agent after adding new skills.
499
530
 
531
+ ### Custom commands
532
+
533
+ A Markdown file in `.dostuff/commands/` (this project) or `~/.dostuff/commands/` (every project) is a slash
534
+ command named after the file: `.dostuff/commands/review.md` is `/review`. Running `/review src/app.py` sends the
535
+ file's text as your message, with `$ARGUMENTS` replaced by `src/app.py` (with no `$ARGUMENTS` in the file, the
536
+ arguments are added at the end). An optional frontmatter `description:` is shown in the `/` menu, otherwise the
537
+ first line is. Works in the TUI and with `dostuff -p "/review src/app.py"`.
538
+
539
+ ```markdown
540
+ ---
541
+ description: Review a file for bugs
542
+ ---
543
+ Review $ARGUMENTS for bugs and missing tests. List problems by severity.
544
+ ```
545
+
546
+ Built-in commands win a name clash, then project commands, then user commands, then skills. Restart dostuff
547
+ after adding a command.
548
+
500
549
  ---
501
550
 
502
551
  ## Sessions and memory
@@ -599,23 +648,31 @@ dostuff/
599
648
  ├── helpers/ # sub-modules for agent, mcp, memory, skills, tools, ui
600
649
  │ ├── agent/ # state, exit handlers, system prompts, token limit utilities
601
650
  │ ├── mcp/ # config loading, oauth
602
- │ ├── memory/ # transcript formatting and memory extractors
651
+ │ ├── memory/ # memory resolver, session export, shell steps
603
652
  │ ├── skills/ # skill discovery logic
604
653
  │ ├── tools/ # schemas and path resolution
605
654
  │ └── ui/ # event emission shims
606
655
  ├── lib/ # core logic
656
+ │ ├── checkpoints.py # per-turn file checkpoints for /undo
607
657
  │ ├── exceptions.py # validation, confirmation, and workflow exceptions
608
658
  │ ├── mcp/ # mcp transport client & local registrations
609
659
  │ ├── memory/ # semantic, episodic, and session stores
610
660
  │ ├── model.py # model and provider resolution
611
- │ └── tracing.py # opentelemetry tracing bootstrap
661
+ │ ├── tracing.py # opentelemetry tracing bootstrap
662
+ │ └── worktree.py # git worktree create / exit / cleanup
612
663
  ├── memory/ # DB management
613
664
  │ └── __init__.py # DB initiation exports
614
665
  ├── tools/ # defined tools
615
666
  │ ├── bash/ # terminal command execution tools
616
667
  │ ├── files/ # read, write, edit, delete, list
617
668
  │ ├── search/ # grep and glob (pure Python, default excludes)
618
- │ └── mcp/ # mcp tool search, detail, and execution wrappers
669
+ │ ├── mcp/ # mcp tool search, detail, and execution wrappers
670
+ │ ├── memory/ # save_memory / save_episode
671
+ │ ├── settings.py # read_settings, edit_config, set/remove_mcp_server
672
+ │ ├── web_fetch.py # read a URL as text
673
+ │ ├── web_search.py # free web search (SearXNG / ddgs / DuckDuckGo)
674
+ │ ├── todo_write.py # visible task list
675
+ │ └── delegate_to_subagent.py # bounded subagents (optionally in a worktree)
619
676
  ├── cli.py # CLI typer entrypoints and doctor checkup utilities
620
677
  ├── cli_tui.py # Textual TUI Application and adapter translates state
621
678
  ├── config.py # layered config loader supporting project/global yaml and multi-model configuration
@@ -631,3 +688,5 @@ dostuff/
631
688
  - **Author:** [varun](mailto:varunkumawatleap2@gmail.com)
632
689
  - **Repository:** https://github.com/kVarunkk/DoStuff
633
690
  - **Issues:** https://github.com/kVarunkk/DoStuff/issues
691
+ - **Changelog:** [CHANGELOG.md](CHANGELOG.md)
692
+ - **PyPI:** https://pypi.org/project/dostuff/