**manual_slop** is a local GUI tool for manually curating and sending context to AI APIs. It aggregates files, screenshots, and discussion history into a structured markdown file and sends it to a chosen AI provider with a user-written message. The AI can also execute PowerShell scripts within the project directory, with user confirmation required before each execution. **Stack:** - `dearpygui` - GUI with docking/floating/resizable panels - `google-genai` - Gemini API - `anthropic` - Anthropic API - `tomli-w` - TOML writing - `uv` - package/env management **Files:** - `gui.py` - main GUI, `App` class, all panels, all callbacks, confirmation dialog - `ai_client.py` - unified provider wrapper, model listing, session management, send, tool/function-call loop - `aggregate.py` - reads config, collects files/screenshots/discussion, writes numbered `.md` files to `output_dir` - `shell_runner.py` - subprocess wrapper that runs PowerShell scripts sandboxed to `base_dir`, returns stdout/stderr/exit code as a string - `config.toml` - namespace, output_dir, files paths+base_dir, screenshots paths+base_dir, discussion history array, ai provider+model - `credentials.toml` - gemini api_key, anthropic api_key **GUI Panels:** - **Config** - namespace, output dir, save - **Files** - base_dir, scrollable path list with remove, add file(s), add wildcard - **Screenshots** - base_dir, scrollable path list with remove, add screenshot(s) - **Discussion History** - multiline text box, `---` as separator between excerpts, save splits on `---` back into toml array - **Provider** - provider combo (gemini/anthropic), model listbox populated from API, fetch models button, status line - **Message** - multiline input, Gen+Send button, MD Only button, Reset session button - **Response** - readonly multiline displaying last AI response - **Tool Calls** - scrollable log of every PowerShell tool call the AI made, showing script and result; Clear button **AI Tool Use (PowerShell):** - Both Gemini and Anthropic are configured with a `run_powershell` tool/function declaration - When the AI wants to edit or create files it emits a tool call with a `script` string - `ai_client` runs a loop (max `MAX_TOOL_ROUNDS = 5`) feeding tool results back until the AI stops calling tools - Before any script runs, `gui.py` shows a modal `ConfirmDialog` on the main thread; the background send thread blocks on a `threading.Event` until the user clicks Approve or Reject - The dialog displays `base_dir`, shows the script in an editable text box (allowing last-second tweaks), and has Approve & Run / Reject buttons - On approval the (possibly edited) script is passed to `shell_runner.run_powershell()` which prepends `Set-Location -LiteralPath ''` and runs it via `powershell -NoProfile -NonInteractive -Command` - Every script (original, before Set-Location is prepended) is saved to ./scripts/generated/ai_.ps1 before execution; the saved path appears in the tool result - stdout, stderr, and exit code are returned to the AI as the tool result - Rejections return `"USER REJECTED: command was not executed"` to the AI - All tool calls (script + result/rejection) are appended to `_tool_log` and displayed in the Tool Calls panel **Data flow:** 1. GUI edits are held in `App` state lists (`self.files`, `self.screenshots`, `self.history`) and dpg widget values 2. `_flush_to_config()` pulls all widget values into `self.config` dict 3. `_do_generate()` calls `_flush_to_config()`, saves `config.toml`, calls `aggregate.run(config)` which writes the md and returns `(markdown_str, path)` 4. `cb_generate_send()` calls `_do_generate()` then threads a call to `ai_client.send(md, message, base_dir)` 5. `ai_client.send()` prepends the md as a `` block to the user message and sends via the active provider chat session 6. If the AI responds with tool calls, the loop handles them (with GUI confirmation) before returning the final text response 7. Sessions are stateful within a run (chat history maintained), `Reset` clears them and the tool log **Config persistence:** - Every send and save writes `config.toml` with current state including selected provider and model under `[ai]` - Discussion history is stored as a TOML array of strings in `[discussion] history` - File and screenshot paths are stored as TOML arrays, support absolute paths, relative paths from base_dir, and `**/*` wildcards **Threading model:** - DPG render loop runs on the main thread - AI sends and model fetches run on daemon background threads - `_pending_dialog` (guarded by a `threading.Lock`) is set by the background thread and consumed by the render loop each frame, calling `dialog.show()` on the main thread - `dialog.wait()` blocks the background thread on a `threading.Event` until the user acts **Known extension points:** - Add more providers by adding a section to `credentials.toml`, a `_list_*` and `_send_*` function in `ai_client.py`, and the provider name to the `PROVIDERS` list in `gui.py` - System prompt support could be added as a field in `config.toml` and passed in `ai_client.send()` - Discussion history excerpts could be individually toggleable for inclusion in the generated md - `MAX_TOOL_ROUNDS` in `ai_client.py` caps agentic loops at 5 rounds; adjustable