diff --git a/CHANGELOG.md b/CHANGELOG.md
index c7d07db6..bda2ea4f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,13 +15,18 @@ GitHub Releases page; `0.8.0` is the new starting line.
## Unreleased
+## 0.33.0 (2026-06-03)
+
+### What changed in this release
+
- **Three-scope config resolution (User → Project → Local).** `load_config()` now runs a five-step pipeline — Ingest → Guard → Merge → Env → Validate — merging `~/.pythinker/config.toml`, `.pythinker/config.toml`, and `.pythinker/config.local.toml` with type-based rules. Scalars use last-writer-wins; lists are concatenated (deduplication for `allowed_domains` and `extra_skill_dirs`); dicts are recursively merged. Scope-locked fields (`providers.*`, `services.*`, `feedback.api_key`) are blocked from project/local files with a clear error. The resolved config now tracks which files contributed via `source_scopes`. Local config files are auto-gitignored on first use. PYTHINKER_* environment variables overlay all file-sourced values.
- **Pythinker identity: developed by Pythoughts-labs.** Package metadata, `--version` output, and `pythinker info` now reflect Pythoughts-labs as the author organisation.
-
- **❓ question marker standardized across all question surfaces.** A new `QUESTION_MARKER` constant in `glyphs.py` replaces the inconsistent mix of `●` (inline transcript) and `?` (interactive panel, pager, prompt) with a single `❓` glyph (ASCII fallback: `?`) used everywhere.
- **Scratchpad isolated to current session; cleans up on interruption.** Agents no longer fast-skim all prior sessions' scratch files on startup, eliminating the post-interrupt confusion where stale planning from previous sessions was injected into a new session's context. Scratch files are now deleted on every session exit — success or interruption — so files no longer accumulate.
- **`SetTodoList` gated behind explicit plan approval.** The tool description and agent system prompt now require that todos are set only after the user agrees on the plan. During planning and exploration the tool must not be called; once set, the list is the single source of truth for execution with status-only updates.
+Upgrade with `pythinker update`, `pip install --upgrade pythinker-code==0.33.0`, or use the native installer for your OS (see the README install table).
+
## 0.32.0 (2026-06-03)
### What changed in this release
diff --git a/README.md b/README.md
index 002eb1f0..32c5178f 100644
--- a/README.md
+++ b/README.md
@@ -50,14 +50,15 @@ It speaks the [**Agent Client Protocol (ACP)**](https://github.com/agentclientpr
---
-## 🆕 What's New in 0.32.0
+## 🆕 What's New in 0.33.0
-- **`pythinker mcp add` no longer crashes on Windows and Linux native builds.** `copy_metadata()` replaces the fragile `collect_data_files()` approach in all three PyInstaller specs, so `fastmcp` and `mcp` dist-info are bundled and `importlib.metadata` resolves correctly in frozen binaries.
-- **Pythinker work directories are automatically gitignored on startup.** `.pythinker/`, `.pythinker-review/`, and `.pythinker-review-flow/` are silently added to the project's `.gitignore` when the agent starts inside a git repo, keeping the working tree clean.
-- **Old sessions and plan files are swept on startup.** Archives older than `session_retention_days` (default 30) are removed non-interactively at launch. Set `session_retention_days = 0` to disable.
-- **Windows upgrade version display fix.** Inno Setup now wipes `_internal` before installing new files, so in-place upgrades no longer show a stale version number or re-trigger the update prompt.
+- **Three-scope config resolution (User → Project → Local).** `load_config()` merges `~/.pythinker/config.toml`, `.pythinker/config.toml`, and `.pythinker/config.local.toml` through a five-step pipeline. Scope-locked fields are blocked from project/local files with a clear error; local files are auto-gitignored on first use; PYTHINKER_* env vars overlay everything.
+- **Pythinker identity: developed by Pythoughts-labs.** Package metadata, `--version` output, and `pythinker info` now reflect Pythoughts-labs as the author organisation.
+- **❓ question marker standardized across all question surfaces.** A single `QUESTION_MARKER` constant replaces the inconsistent mix of glyphs used in the inline transcript, interactive panel, pager, and prompt.
+- **Scratchpad isolated to current session; cleans up on interruption.** Scratch files are deleted on every session exit so stale planning from previous sessions can no longer be injected into a new session's context.
+- **`SetTodoList` gated behind explicit plan approval.** Todos may only be set after the user agrees on the plan; the tool description and system prompt now enforce this contract.
-Upgrade with `pythinker update`, `pip install --upgrade pythinker-code==0.32.0`, or use the native installer for your platform from the [Releases page](https://github.com/Pythoughts-labs/pythinker-code/releases/latest).
+Upgrade with `pythinker update`, `pip install --upgrade pythinker-code==0.33.0`, or use the native installer for your platform from the [Releases page](https://github.com/Pythoughts-labs/pythinker-code/releases/latest).
---
@@ -147,7 +148,7 @@ matches your OS — no Python, Node, or `uv` prerequisite.
| Platform | Recommended install | Artifact source |
|---|---|---|
-| **🪟 Windows** | `irm https://pythinker.com/install.ps1 \| iex` | `PythinkerSetup-0.32.0.exe` from [Releases](https://github.com/Pythoughts-labs/pythinker-code/releases/latest) |
+| **🪟 Windows** | `irm https://pythinker.com/install.ps1 \| iex` | `PythinkerSetup-0.33.0.exe` from [Releases](https://github.com/Pythoughts-labs/pythinker-code/releases/latest) |
| **
/
** | `curl -fsSL https://pythinker.com/install.sh \| bash` | native tarball from [Releases](https://github.com/Pythoughts-labs/pythinker-code/releases/latest) |
| **
— Homebrew** | `brew install Pythoughts-labs/pythinker/pythinker-code` | auto-published Homebrew tap |
| **🐳 Docker** | `docker run --rm -it ghcr.io/pythoughts-labs/pythinker-code` | GHCR multi-arch image |
@@ -175,7 +176,7 @@ pythinker # start the interactive TUI
### 🪟 Windows — native installer
-`PythinkerSetup-0.32.0.exe` is a signed* Inno Setup wizard. Installs per-user
+`PythinkerSetup-0.33.0.exe` is a signed* Inno Setup wizard. Installs per-user
into `%LOCALAPPDATA%\Programs\Pythinker`, registers `pythinker` on your user
PATH (`HKCU\Environment`), broadcasts `WM_SETTINGCHANGE` so new shells see
the change. **No UAC prompt.**
@@ -186,13 +187,13 @@ irm https://pythinker.com/install.ps1 | iex
# Or manually download the installer + checksum from the Releases page,
# verify with Get-FileHash, then run:
-.\PythinkerSetup-0.32.0.exe
+.\PythinkerSetup-0.33.0.exe
# Open a fresh PowerShell
pythinker --version
```
-**Per-machine install** (IT-managed boxes): `.\PythinkerSetup-0.32.0.exe /ALLUSERS`
+**Per-machine install** (IT-managed boxes): `.\PythinkerSetup-0.33.0.exe /ALLUSERS`
installs to `%ProgramFiles%\Pythinker` and writes PATH to HKLM (requires admin).
**Upgrade:** `pythinker update` from inside the running app — it downloads
@@ -243,26 +244,26 @@ attached to every GitHub Release.
```sh
# Debian / Ubuntu (x86_64)
-sudo dpkg -i pythinker-code_0.32.0_amd64.deb
+sudo dpkg -i pythinker-code_0.33.0_amd64.deb
sudo apt-get install -f # only if dpkg reports missing deps
# Debian / Ubuntu (ARM64)
-sudo dpkg -i pythinker-code_0.32.0_arm64.deb
+sudo dpkg -i pythinker-code_0.33.0_arm64.deb
# Fedora / RHEL / openSUSE (x86_64)
-curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.32.0/pythinker-code-0.32.0.x86_64.rpm
-curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.32.0/pythinker-code-0.32.0.x86_64.rpm.sha256
-sha256sum -c pythinker-code-0.32.0.x86_64.rpm.sha256
+curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.33.0/pythinker-code-0.33.0.x86_64.rpm
+curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.33.0/pythinker-code-0.33.0.x86_64.rpm.sha256
+sha256sum -c pythinker-code-0.33.0.x86_64.rpm.sha256
# Fedora / RHEL:
-sudo dnf install ./pythinker-code-0.32.0.x86_64.rpm
+sudo dnf install ./pythinker-code-0.33.0.x86_64.rpm
# openSUSE:
-sudo zypper install ./pythinker-code-0.32.0.x86_64.rpm
+sudo zypper install ./pythinker-code-0.33.0.x86_64.rpm
# Fedora / RHEL (aarch64)
-curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.32.0/pythinker-code-0.32.0.aarch64.rpm
-curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.32.0/pythinker-code-0.32.0.aarch64.rpm.sha256
-sha256sum -c pythinker-code-0.32.0.aarch64.rpm.sha256
-sudo dnf install ./pythinker-code-0.32.0.aarch64.rpm
+curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.33.0/pythinker-code-0.33.0.aarch64.rpm
+curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.33.0/pythinker-code-0.33.0.aarch64.rpm.sha256
+sha256sum -c pythinker-code-0.33.0.aarch64.rpm.sha256
+sudo dnf install ./pythinker-code-0.33.0.aarch64.rpm
```
Both packages drop a small `/usr/bin/pythinker` launcher that execs the real
@@ -271,8 +272,8 @@ binary under `/usr/lib/pythinker/`, so your `$PATH` stays tidy.
**Verify before install:**
```sh
-sha256sum -c pythinker-code_0.32.0_amd64.deb.sha256 # Debian/Ubuntu
-sha256sum -c pythinker-code-0.32.0.x86_64.rpm.sha256 # Fedora/RHEL
+sha256sum -c pythinker-code_0.33.0_amd64.deb.sha256 # Debian/Ubuntu
+sha256sum -c pythinker-code-0.33.0.x86_64.rpm.sha256 # Fedora/RHEL
```
**Upgrade:** download the new `.deb`/`.rpm` from Releases and `dpkg -i` /
diff --git a/docs/en/guides/getting-started.md b/docs/en/guides/getting-started.md
index 24d0be2f..f0bbeac7 100644
--- a/docs/en/guides/getting-started.md
+++ b/docs/en/guides/getting-started.md
@@ -44,7 +44,7 @@ On Windows, run the PowerShell bootstrap. It downloads the native installer, ver
irm https://pythinker.com/install.ps1 | iex
```
-You can also download `PythinkerSetup-0.32.0.exe` manually from the [latest release](https://github.com/Pythoughts-labs/pythinker-code/releases/latest).
+You can also download `PythinkerSetup-0.33.0.exe` manually from the [latest release](https://github.com/Pythoughts-labs/pythinker-code/releases/latest).
Verify the installation:
diff --git a/docs/en/release-notes/breaking-changes.md b/docs/en/release-notes/breaking-changes.md
index 95dbaff6..3a410f58 100644
--- a/docs/en/release-notes/breaking-changes.md
+++ b/docs/en/release-notes/breaking-changes.md
@@ -4,6 +4,10 @@ This page documents breaking changes in Pythinker Code releases and provides mig
## Unreleased
+## 0.33.0 (2026-06-03)
+
+No breaking changes. This release is compatible with 0.32.0 user configuration, native installs, and session data.
+
## 0.32.0 (2026-06-03)
No breaking changes. This release is compatible with 0.31.0 user configuration, native installs, and session data.
diff --git a/docs/en/release-notes/changelog.md b/docs/en/release-notes/changelog.md
index 7fc34ba7..b4b62b4b 100644
--- a/docs/en/release-notes/changelog.md
+++ b/docs/en/release-notes/changelog.md
@@ -17,6 +17,18 @@ GitHub Releases page; `0.8.0` is the new starting line.
## Unreleased
+## 0.33.0 (2026-06-03)
+
+### What changed in this release
+
+- **Three-scope config resolution (User → Project → Local).** `load_config()` now runs a five-step pipeline — Ingest → Guard → Merge → Env → Validate — merging `~/.pythinker/config.toml`, `.pythinker/config.toml`, and `.pythinker/config.local.toml` with type-based rules. Scalars use last-writer-wins; lists are concatenated (deduplication for `allowed_domains` and `extra_skill_dirs`); dicts are recursively merged. Scope-locked fields (`providers.*`, `services.*`, `feedback.api_key`) are blocked from project/local files with a clear error. The resolved config now tracks which files contributed via `source_scopes`. Local config files are auto-gitignored on first use. PYTHINKER_* environment variables overlay all file-sourced values.
+- **Pythinker identity: developed by Pythoughts-labs.** Package metadata, `--version` output, and `pythinker info` now reflect Pythoughts-labs as the author organisation.
+- **❓ question marker standardized across all question surfaces.** A new `QUESTION_MARKER` constant in `glyphs.py` replaces the inconsistent mix of `●` (inline transcript) and `?` (interactive panel, pager, prompt) with a single `❓` glyph (ASCII fallback: `?`) used everywhere.
+- **Scratchpad isolated to current session; cleans up on interruption.** Agents no longer fast-skim all prior sessions' scratch files on startup, eliminating the post-interrupt confusion where stale planning from previous sessions was injected into a new session's context. Scratch files are now deleted on every session exit — success or interruption — so files no longer accumulate.
+- **`SetTodoList` gated behind explicit plan approval.** The tool description and agent system prompt now require that todos are set only after the user agrees on the plan. During planning and exploration the tool must not be called; once set, the list is the single source of truth for execution with status-only updates.
+
+Upgrade with `pythinker update`, `pip install --upgrade pythinker-code==0.33.0`, or use the native installer for your OS (see the README install table).
+
## 0.32.0 (2026-06-03)
### What changed in this release
diff --git a/packages/linux-installer/README.md b/packages/linux-installer/README.md
index 5ab2d79b..d276263f 100644
--- a/packages/linux-installer/README.md
+++ b/packages/linux-installer/README.md
@@ -8,19 +8,19 @@ End-user install from the current GitHub Release:
```sh
# Debian / Ubuntu
-curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.32.0/pythinker-code_0.32.0_amd64.deb
-curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.32.0/pythinker-code_0.32.0_amd64.deb.sha256
-sha256sum -c pythinker-code_0.32.0_amd64.deb.sha256
-sudo dpkg -i pythinker-code_0.32.0_amd64.deb
+curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.33.0/pythinker-code_0.33.0_amd64.deb
+curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.33.0/pythinker-code_0.33.0_amd64.deb.sha256
+sha256sum -c pythinker-code_0.33.0_amd64.deb.sha256
+sudo dpkg -i pythinker-code_0.33.0_amd64.deb
sudo apt-get install -f # only needed if dependencies fail to resolve
# Fedora / RHEL / openSUSE
-curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.32.0/pythinker-code-0.32.0.x86_64.rpm
-curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.32.0/pythinker-code-0.32.0.x86_64.rpm.sha256
-sha256sum -c pythinker-code-0.32.0.x86_64.rpm.sha256
-sudo dnf install ./pythinker-code-0.32.0.x86_64.rpm
+curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.33.0/pythinker-code-0.33.0.x86_64.rpm
+curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.33.0/pythinker-code-0.33.0.x86_64.rpm.sha256
+sha256sum -c pythinker-code-0.33.0.x86_64.rpm.sha256
+sudo dnf install ./pythinker-code-0.33.0.x86_64.rpm
# or, on openSUSE:
-sudo zypper install ./pythinker-code-0.32.0.x86_64.rpm
+sudo zypper install ./pythinker-code-0.33.0.x86_64.rpm
```
The package drops a single executable at `/usr/bin/pythinker` and a license
@@ -36,17 +36,17 @@ file at `/usr/share/doc/pythinker-code/LICENSE`.
## Build
```sh
-bash packages/linux-installer/build.sh 0.32.0
+bash packages/linux-installer/build.sh 0.33.0
```
Outputs to `dist/`:
-- `pythinker-code_0.32.0_amd64.deb`
-- `pythinker-code-0.32.0.x86_64.rpm`
+- `pythinker-code_0.33.0_amd64.deb`
+- `pythinker-code-0.33.0.x86_64.rpm`
The portable tarball used by `scripts/install-native.sh` is published by
the existing `release-pythinker-cli.yml` workflow under the cargo-dist
-target-triple naming (e.g. `pythinker-0.32.0-x86_64-unknown-linux-gnu.tar.gz`).
+target-triple naming (e.g. `pythinker-0.33.0-x86_64-unknown-linux-gnu.tar.gz`).
## CI
diff --git a/pyproject.toml b/pyproject.toml
index 54136d2f..4f520221 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "pythinker-code"
-version = "0.32.0"
+version = "0.33.0"
description = "Pythinker — an agentic CLI developed by Pythoughts-labs."
readme = "README.md"
requires-python = ">=3.12"
diff --git a/uv.lock b/uv.lock
index 3d5c26c9..f6bd4112 100644
--- a/uv.lock
+++ b/uv.lock
@@ -2515,7 +2515,7 @@ wheels = [
[[package]]
name = "pythinker-code"
-version = "0.32.0"
+version = "0.33.0"
source = { editable = "." }
dependencies = [
{ name = "agent-client-protocol" },