Skip to content

Release Notes

v0.6.2

v0.6.1

v0.6.0

v0.5.0

  • βš™οΈ pycodeloop --version/-V prints the installed version and exits β€” nothing previously let a caller check it without importing the package; the VS Code extension uses this to detect an outdated CLI and offer to update it
  • βš™οΈ VS Code extension: CLI update check β€” on connect, compares the installed pycodeloop --version against the latest release on PyPI and, if outdated, shows a card with an "Update CodeLoop CLI" button (pip install --user --upgrade pycodeloop)

Security hardening β€” tools

  • ⚠️ sql_query/sql_schema are now dangerous (require confirm) and open the connection read-only at the driver level (PRAGMA query_only/SET TRANSACTION READ ONLY) instead of trusting a regex alone. The regex itself got stricter too: a _FORBIDDEN list blocks INTO OUTFILE/INTO DUMPFILE/LOAD_FILE()/pg_read_file()/COPY ... TO/ATTACH DATABASE, and PRAGMA is now checked against an explicit safe-list instead of being allowed wholesale. Connection URLs are validated against an allowlist of SQLAlchemy schemes (sqlite/postgresql/mysql/mariadb variants) before a connection is even attempted
  • ⚠️ git_commit now requires an explicit paths list and refuses -A/-u/--all β€” it could previously default to git add -A, contradicting this repo's own "never git add -A" rule
  • ⚠️ Filesystem tools (read_file, write_file, edit_file, delete_file, grep, glob) are jailed to the workspace root (pycodeloop/tools/_workspace.py) β€” an absolute path or a .. escape outside the process cwd is now refused instead of silently followed
  • ⚠️ http_request/web_fetch/safe_request reject any URL whose scheme isn't http/https before the SSRF host check runs, and is_blocked_host now also blocks multicast and unspecified addresses
  • ⚠️ env's sensitive-name matching widened (AUTH, BEARER, COOKIE, SESSION, PASSWD, PASSPHRASE, APIKEY, …) and now matches whole name segments instead of a raw substring, so it also masks more accurately

Reliability

  • πŸͺ² Agent refuses to run a dangerous tool when no confirm callback is set instead of running it unconfirmed β€” closes a fail-open gap when Agent is used as a library without wiring a confirm handler
  • πŸͺ² pycodeloop serve now emits a chat/turnEnd notification after each provider turn, so an editor client can end the current text bubble at the right point instead of concatenating text from before and after a tool call into one run-on message
  • πŸͺ² FileAccessLog/SqliteSessions dispose their SQLite engine (NullPool + explicit close()/__del__) instead of leaking connections/ResourceWarnings across the process lifetime
  • πŸͺ² The interactive input-reader thread no longer raises when stdin closes out from under it mid-read

CI / quality gates

  • ⬆️ mypy now runs with the correct config path in CI; .pre-commit-config.yaml's file glob pointed at the pre-rename codeloop/ package instead of pycodeloop/; CI now diffs templates/ against pycodeloop/providers/templates/ to catch the two going out of sync
  • πŸ“ ruff target-version bumped to py310 (matches requires-python) and the full tree reformatted to it β€” full ruff check/ruff format --check pass

v0.4.0

pycodeloop core

  • βš™οΈ Sub-agent delegation (--delegate, off by default) β€” a delegate tool spawns a fresh sub-agent (same provider, read-only tools: read_file/list_dir/glob/grep/git status/diff/log/web_fetch/sql_schema/sql_query, no write/edit/delete/bash) for an independent subtask. Several delegate calls in the same turn run in parallel
  • πŸͺ² Agent._can_parallelize previously forced any repeated tool name in a batch to run sequentially, even for stateless tools β€” added Tool.concurrent_safe (opt-in, default False, preserves existing behavior for every built-in tool) so delegate can declare its repeated calls safe to run concurrently
  • βš™οΈ Persistent project memory (--memory, on by default) β€” .pycodeloop/memory.md auto-loaded into the system prompt every run, plus a remember tool the agent calls when the user corrects its approach or states a standing rule. remember is gated behind confirmation like every other write tool
  • πŸͺ² write_file/edit_file reject content that looks like a pasted unified diff (@@ ... @@ hunk header, or ---/+++ file headers) instead of writing the diff syntax itself into the file
  • βš™οΈ Six more ready-made provider templates: AWS Bedrock (aws.json, via the bearer-token bedrock-mantle endpoint β€” no SigV4 needed), Kimi/Moonshot AI (kimi.json), DeepSeek (deepseek.json), Llama via Together AI (llama.json β€” Meta retired its own Llama API on 2026-07-06), Qwen/Alibaba DashScope (qwen.json), NVIDIA NIM (nvidia.json)
  • πŸͺ² Grok template was pointing at grok-4/grok-4-fast/grok-code-fast-1 β€” all retired 2026-05-15. Moved to grok-4.5/grok-4.3/grok-build-0.1. OpenAI template's gpt-5/gpt-5-mini/gpt-5-nano moved to the current gpt-5.6 family
  • πŸͺ² Gemini 3's thinking models attach extra_content.google.thought_signature to tool_calls and reject the next turn if it isn't echoed back unchanged β€” and thinking can't be disabled on Gemini 3 (minimum is LOW, which still requires the signature). Rather than staying pinned to Gemini 2.5 (itself now 404ing for new API keys), GenericProvider round-trips arbitrary vendor-specific tool_call fields via a new ToolCall.extra, so Gemini's default is gemini-3.6-flash again
  • βš™οΈ Anthropic prompt caching β€” set "prompt_cache": true in a provider's request config (already on by default in anthropic.json) to mark the system prompt and the last tool definition with cache_control: {"type": "ephemeral"}, so Anthropic reuses the cached system prompt + tool schema across turns instead of reprocessing them every request (cache reads cost ~10% of a normal input token)
  • βš™οΈ Two new tools: sql_schema (list a database's tables, or one table's columns) and sql_query (a single read-only SELECT/WITH/EXPLAIN/PRAGMA/SHOW/DESCRIBE statement, no writes/DDL/stacked statements) β€” any SQLAlchemy-supported database via a connection URL
  • βš™οΈ Token-saving read cache β€” read_file now logs every read/write/edit/delete to a file_access table (~/.pycodeloop/pycodeloop.db), scoped to the session. Reading the exact same path/offset/limit twice with no change on disk in between returns a short "unchanged since you last read" notice instead of repeating the content β€” pass force=true to see it again
  • πŸ—‘οΈ Removed the todo tool (scratchpad checklist) β€” never adopted, dead weight in the default tool list
  • πŸͺ² http_request/web_fetch had a DNS-rebinding gap in their SSRF guard: the hostname was resolved once to check it wasn't private/internal, then resolved again, independently, for the actual connection β€” a rebinding DNS answer between those two lookups could hand the request to a blocked address the check had just approved. Both now resolve once and connect directly to that pinned address (Host header + TLS SNI still carry the real hostname, so routing/cert validation are unaffected)
  • πŸͺ² git_diff/git_log/etc never capped their output, unlike every other tool (bash, filesystem, grep, http_request, web_fetch) β€” a large diff or a deep log could blow out the context. http_request/web_fetch also each hand-rolled the same 20000-char truncation _limits.truncate() already provides; both now use it
  • πŸͺ² env now also masks values shaped like scheme://user:pass@host (e.g. a DATABASE_URL), not just names containing SECRET/KEY/TOKEN/PASSWORD/CREDENTIAL; grep skips binary files instead of searching through decoded garbage
  • 🎨 core/ split: store/ (SQLite/JSON/file sessions, usage tracking, user settings, ORM models), tools/ (built-in Tool implementations β€” the Tool ABC already lived in abc/, not core/), and the optional-feature modules skills.py/memory.py/mcp.py moved out to be siblings of core/, which now only holds the agent engine itself (agent, config, session, codeloop, context_window, exception). clipboard.py moved into cli/ β€” it's only used by the interactive Textual chat
  • 🎨 New protocol/ module: Message moved out of core/session.py into protocol/messages.py; the JSON-RPC envelope builders (notification/response/error_response, error codes) pycodeloop serve was hand-assembling inline moved into protocol/events.py
  • 🎨 providers/generic.py (one class doing config loading, three response-parsing strategies, a request-builder factory, and raw HTTP/SSE transport) split β€” the response parsers moved to a new providers/_responses.py, the config-driven request builder moved into providers/_shapes.py next to the message/tool-schema builders it already used. GenericProvider now only orchestrates config loading and HTTP transport
  • 🎨 Config._append_to_system_prompt helper extracted (was duplicated between skills discovery and memory loading); tools/__init__.py's DEFAULT_TOOLS/READ_ONLY_TOOLS no longer double-instantiate the tools they share
  • πŸ—‘οΈ Removed the anthropic/openai poetry extras β€” dead weight, GenericProvider is stdlib-only and never imports either SDK. The mcp extra (actually used, by pycodeloop/mcp.py) stays

VS Code extension β€” now its own repo, dotflow-io/vscodeloop

The extension moved out of this repo's vscode-extension/ into its own, with full commit history preserved. It still ships as the pycodeloop/"CodeLoop" VS Code extension; only where the code lives changed.

  • βš™οΈ Provider gallery (βš™ β†’ Select Provider…, or /provider): card picker for all 13 providers (Anthropic, OpenAI, Gemini, Grok, Groq, AWS Bedrock, Kimi, DeepSeek, Llama, Qwen, NVIDIA NIM, Ollama, LM Studio) with a connected/local/needs-key status per card, a per-provider model picker, and a custom-JSON/generic-URL fallback. API keys and the chosen model are remembered per provider, so switching back doesn't re-prompt
  • βš™οΈ Dedicated Sessions page (Sessions toolbar button, replacing the native quickpick): cards show message count, working directory, last-updated time, and an Active badge, each with a Switch action
  • βš™οΈ pycodeloop.delegation and pycodeloop.memory settings, gear-menu toggles, /delegate and /memory slash commands
  • βš™οΈ Claude Code-style status line ("● Thinking… Β· 12s") replacing the earlier 3-dot bubble β€” live elapsed-time counter, and switches to "N sub-agents working…" while parallel delegate calls are in flight
  • βš™οΈ Completed write_file/edit_file/delete_file tool cards now render the diff computed for the confirmation prompt (colored +/- lines, "Added N lines" summary) instead of discarding it for a bare "Edited path" string
  • πŸͺ² A per-provider model choice that's since been retired by the vendor (e.g. Gemini's gemini-2.5-flash, no longer available to new API keys) used to keep 404ing every session until manually changed β€” the extension now self-heals it back to the provider's current default the next time it connects
  • 🎨 Panel reworked to an owline-style visual language: thin 1px borders, sharp corners, monospace uppercase for buttons/labels, SVG line icons instead of emoji, no VS Code default rounded-button chrome β€” all still on var(--vscode-*) tokens so it follows the user's editor theme
  • 🎨 "API Key" removed from the gear menu β€” redundant with the provider gallery's own connect/key flow, which is where the key actually gets set
  • 🎨 src/ restructured from a flat bag of lib/config/webview files into features/ (chat, sessions, settings β€” each with its own controller), vscode/ (webview shell, sidebar registration), core-client/ (RPC client, process management, wire protocol), and services/ (credentials, settings, storage, terminal, workspace)
  • 🎨 media/main.js (1511 lines, one file) split into 9 plain <script> files (dom, render-utils, chat-turns, chat-tools, chat-apikey, composer, menu, gallery, app) loaded in a fixed order β€” still no bundler, they share one global scope by design, same as before
  • πŸ“˜ ESLint added (flat config, typescript-eslint) with an npm run lint script
  • πŸ“˜ WebviewMessage discriminated union replaces onWebviewMessage(message: any); 11 near-identical gear-menu handlers deduplicated into one onMenuClick(button, action) helper
  • πŸ“˜ AGENTS.md added at the (former) repo root capturing standing rules (provider JSONs synced across template dirs, verify model IDs against current vendor docs, no emoji icons, rebuild+reinstall the .vsix after every extension change) for skills discovery to pick up automatically

v0.3.0

  • βš™οΈ Ready-made provider templates for Gemini (templates/gemini.json), Grok/xAI (templates/grok.json), and Groq (templates/groq.json) β€” same GenericProvider JSON shape, OpenAI-compatible endpoints, no code required
  • βš™οΈ VS Code extension (0.3.0): a provider gallery (βš™ β†’ Select Provider…, or /provider) replaces the flat quickpick β€” card picker for Anthropic/OpenAI/Gemini/Grok/Groq/Ollama/LM Studio with a connected/local/needs-key status per card, plus a custom-JSON/generic-URL fallback. API keys are now remembered per provider, so switching back doesn't re-prompt. The panel's visual style was also reworked (thin borders, sharp corners, monospace labels) while staying on VS Code's own theme tokens

v0.2.1

  • βš™οΈ VS Code extension source restructured by responsibility β€” thin extension.ts entrypoint, chatViewProvider.ts for orchestration, config/settings.ts for typed config access, pure lib/ helpers, and webview/html.ts for the panel template β€” plus 26 unit tests (npm test, no new dependency)
  • βš™οΈ Skills-discovery toggle and MCP server management (add/remove) added to the extension's gear menu and settings, wired into pycodeloop serve's existing --no-skills/--mcp flags
  • βš™οΈ Slash commands (/new, /sessions, /provider, /model, /auto-approve, /skills, /mcp, /reload, /settings, /help) with an autocomplete dropdown in the extension's prompt box
  • πŸͺ² Session.history() self-heals a session left with a dangling tool_use (no matching tool_result) after the process was killed mid-turn β€” previously left that conversation permanently rejected by the provider
  • πŸͺ² Extension's CLI-missing detection fixed (was probing --version, a flag pycodeloop doesn't have) and its auto-install now always installs the CLI globally, matching pycodeloop.command's default of a bare pycodeloop resolved off PATH

v0.2.0

  • βš™οΈ VS Code extension β€” a sidebar chat panel talking to pycodeloop serve over JSON-RPC, with session switching, screenshot/image attachments, auto-approve setting, and Esc-to-cancel
  • βš™οΈ pycodeloop serve β€” a JSON-RPC-over-stdio server exposing chat/send, chat/cancel, chat/confirmResponse, and session/list/session/load, plus a --yes auto-approve flag, for editor integrations
  • βš™οΈ GenericProvider is now the sole provider implementation β€” dedicated Anthropic/OpenAI SDK-backed providers were removed in favor of the vendor-agnostic JSON-configured HTTP client
  • βš™οΈ Agent loop: retries transient provider errors, runs independent tool calls in parallel, auto-compacts older history into the first kept message with tool-result summarization, and a TUI thinking indicator with live context %
  • πŸͺ² Fixed a CodeLoop session leak across session_key switches and a doubled pypycodeloop typo in install docs
  • πŸ“˜ README and docs updated for the GenericProvider-only model; repository moved to dotflow-io/pycodeloop

v0.1.0

Initial release.

  • βš™οΈ Core agent loop (Agent), dependency-injection container (Config), conversation state (Session), and the CodeLoop entrypoint
  • βš™οΈ Provider ABC with GenericProvider β€” any HTTP chat-completions-style API via the stdlib, no vendor SDK, configured declaratively for Anthropic, OpenAI, Ollama, and other backends via JSON (see templates/)
  • βš™οΈ Tool ABC with built-in read_file, write_file, edit_file, delete_file, list_dir, glob, grep, bash, web_fetch, http_request, git_status, git_diff, git_log, git_commit, env, todo
  • βš™οΈ Dangerous-tool confirmation gate with diff/command preview
  • βš™οΈ Streaming text output and per-turn/cumulative token usage tracking
  • βš™οΈ Auto-compaction of older conversation history and retry with backoff on transient provider failures
  • βš™οΈ MCP client β€” connect to any Model Context Protocol server over stdio and use its tools like local ones
  • βš™οΈ Skills discovery β€” Claude Code, Cursor, and AGENTS.md skills/instructions found on disk are exposed as a read_skill tool
  • βš™οΈ Custom and local providers β€” dotted-path loading (module.path:ClassName) and base_url support for any OpenAI-compatible server
  • βš™οΈ pycodeloop CLI (run, chat, serve) with permission prompts, streaming, and token usage reporting β€” serve speaks JSON-RPC over stdio for editor integrations like the VS Code extension