Skip to main content

Pythinker Code is your next CLI agent.

Project description

Pythinker logo Pythinker Code

Think first, then code. Your terminal-native review-first AI engineering agent.

Code reviewer · Security & vulnerability scanner · Root-cause debugger — then code creator. Pythinker reads your repo, audits it, and only writes code after the analysis. All from the shell you already live in.


PyPI Python License: Apache-2.0 CI

Downloads Code style: Ruff ACP ready MCP tools Homepage


🌐 Website  ·  ⚡ Quick Start  ·  ✨ Features  ·  🧩 IDE Integration  ·  🔌 MCP  ·  🔐 Privacy  ·  🛠️ Develop



Pythinker Code terminal demo

💡 What is Pythinker?

Pythinker Code is an open-source, review-first AI engineering agent that lives in your terminal. Before it writes a single line, it reads yours — auditing diffs, scanning for vulnerabilities, and root-causing failures. Unlike chat assistants that jump straight to code, Pythinker leads with code review, security scanning, and root-cause diagnosis, and only edits files once the analysis points at a fix.

It ships with first-class subagents for each role — code-reviewer for severity-scored diff critique, security-reviewer for validated vulnerability findings, debugger for failure root-causing, and coder/implementer for the scoped edits that follow. All running in a single iterative loop, driven by the model of your choice, with full access to your repo, the shell, the web, and MCP tools.

It speaks the Agent Client Protocol (ACP), so it slots cleanly into ACP-aware editors like Zed and JetBrains. It loads Model Context Protocol (MCP) servers, so the same tools your other agents use just work. And it's hackable: subagents, skills, hooks, and plugins are all first-class extension points.

🎯 Review · Secure · Diagnose · then Create. One agent, one shell, one workflow. No tab-switching. No context loss. No magic.


🆕 What's New in 0.12.0

  • Native Windows installer. A PythinkerSetup-0.12.0.exe is now attached to every GitHub Release. One double-click installs Pythinker per-user with no UAC prompt, no Python / Node / uv prerequisite, and registers pythinker on your PATH automatically. Uninstall via Apps & Features reverses every change. See the new Windows — native installer section in Quick Start for details.
  • In-app updates for the native build. pythinker update from inside the native installer detects the build, fetches the latest installer from GitHub Releases, verifies its SHA-256, and re-runs it silently. The existing PYTHINKER_CLI_NO_AUTO_UPDATE env var now gates both the PyPI and native update flows — one opt-out, both paths.
  • Tag-triggered Windows CI. A new .github/workflows/windows-installer.yml runs on every pythinker-code-v* tag, freezes pythinker via PyInstaller (--onedir), compiles the Inno Setup script, signs the result when the Authenticode cert is available, and uploads the .exe + SHA-256 to the Release.
  • Shell terminal rhythm refinements. Tone tokens, motion timing, and the sky-blue accent palette (#7dd3fc / #93c5fd) were retuned so transcript rows, motion status, and dialog surfaces breathe consistently. UI snapshot tests updated to lock the new rhythm in place.

Upgrade with pythinker update, pip install --upgrade pythinker-code==0.12.0, or — on Windows — download PythinkerSetup-0.12.0.exe from the Releases page.


✨ Features

🖥️ Terminal-First

Plan, edit, run, and verify without leaving your shell. Every action is visible, scriptable, and auditable.

⚡ Shell Command Mode

Press Ctrl-X to drop into a direct shell prompt inside the agent. Run commands, then snap back into AI mode with full context preserved.

🧩 ACP IDE Integration

Run pythinker acp and any Agent Client Protocol editor — Zed, JetBrains, and more — gets a full Pythinker session inline.

🔌 MCP Tool Loading

Manage stdio and HTTP MCP servers with pythinker mcp. OAuth-backed servers, persistent config, ad-hoc files — all supported.

🤖 Subagents & Skills

Delegate focused work to built-in subagents. Load reusable instructions via /skill:<name> and bundled prompt flows via /flow:<name>.

🪝 Hooks & Plugins

Observe or block tool execution with hook events. Install community extensions with pythinker plugin.

🌐 Web & Visualization UIs

Optional web frontend and visualization frontend ship alongside the CLI for richer inspection workflows.

🤖 Bring Your Own Model

Swap providers and models per-session: --model openai/gpt-5.5, hosted Pythinker models, or your own keys.

[!NOTE] Built-in shell commands such as cd are not yet supported in shell command mode.

Shell command mode demo

⚡ Quick Start

🪟 Windows — native installer (recommended)

PythinkerSetup-x.y.z.exe is attached to every GitHub Release. It bundles Pythinker as a self-contained executable — you do not need Python, Node, or uv installed, and there is no UAC / admin prompt.

Install in three steps:

  1. Download PythinkerSetup-x.y.z.exe and its .sha256 companion from the latest Release.
  2. (Optional, recommended) Verify the SHA-256:
    Get-FileHash .\PythinkerSetup-x.y.z.exe -Algorithm SHA256
    Get-Content  .\PythinkerSetup-x.y.z.exe.sha256
    
    The hash from Get-FileHash must match the one in the .sha256 file.
  3. Double-click the installer. It writes to %LOCALAPPDATA%\Programs\Pythinker, registers pythinker on your user PATH (HKCU\Environment), and broadcasts WM_SETTINGCHANGE so any new shell window picks it up.

Open a fresh PowerShell and run pythinker --version to confirm.

🛡 First-launch SmartScreen warning — until the Authenticode signing cert is wired into the CI pipeline (see build.ps1 and the WINDOWS_CERT_PFX_BASE64 / WINDOWS_CERT_PASSWORD secrets), the installer ships unsigned and Windows SmartScreen will show "Windows protected your PC." Click More info → Run anyway. The published .sha256 is your integrity check in the meantime.

Built-in auto-update: running pythinker update from inside the native build queries the GitHub Releases API, downloads the newest installer, verifies its SHA-256, and re-runs it silently (/VERYSILENT /SUPPRESSMSGBOXES /NORESTART). Set PYTHINKER_CLI_NO_AUTO_UPDATE=1 to disable the proactive update check on shell startup (this is the same opt-out the PyPI/uv install path uses — one knob, both flows).

Uninstall: Apps & Features → Pythinker Code → Uninstall. The uninstaller removes the install directory and reverts the user-PATH edit. A new shell will no longer find pythinker.

Per-machine install (multi-user / IT-managed boxes): pass /ALLUSERS to the installer from an admin console:

.\PythinkerSetup-x.y.z.exe /ALLUSERS

This installs to %ProgramFiles%\Pythinker and registers PATH at the HKLM scope. The default (no flag) remains per-user.

✨ Recommended install (clean, with logo)

curl -fsSL https://raw.githubusercontent.com/mohamed-elkholy95/Pythinker-Code/main/scripts/install.sh | bash

Windows PowerShell:

$installer = Join-Path $env:TEMP "pythinker-install.ps1"
iwr -UseBasicParsing https://raw.githubusercontent.com/mohamed-elkholy95/Pythinker-Code/main/scripts/install.ps1 -OutFile $installer
& $installer
Remove-Item $installer

The installer fetches uv if missing, installs pythinker-code quietly, and prints a single-line confirmation instead of the full dependency wall. Windows downloads the script to a file (instead of irm ... | iex) so PowerShell antivirus scanning is less likely to block it, but it is invoked with & in the current session so PATH updates from uv are immediately visible — pythinker works without opening a new shell.

🚀 One-off run with uvx

uvx pythinker-code

📦 Install as a uv tool

uv tool install pythinker-code
pythinker

🔐 Authenticate (optional)

For hosted Pythinker models or ACP terminal auth:

pythinker login

💬 Try it out

# Interactive session
pythinker

# One-shot prompt
pythinker --prompt "summarize this repository and suggest the next test to add"

# Pick a specific model
pythinker --model openai/gpt-5.5

# Inline config override
pythinker --config '{"default_thinking": true}'

🏠 Using Local Models (LM Studio & Ollama)

Run Pythinker entirely on your own machine — no API key, no cloud. Pythinker speaks each runtime's OpenAI-compatible API, so tools, streaming, JSON mode, vision, and reasoning_effort all work the same as with hosted providers.

LM Studio

1. Set up LM Studio.

  • Install LM Studio and download at least one chat model.
  • In the LM Studio app, open the model and raise its Context Length (gear icon → Context Length). See Context length matters below.
  • Start the server: Developer → Status: Running (or lms server start --port 1234).

2. Connect Pythinker.

pythinker login --lm-studio

This auto-discovers every chat-capable model loaded in LM Studio, registers each as lm-studio/<model-id>, and picks the largest-context one as your default. Embedding models are filtered out.

3. Use it.

# Default LM Studio model
pythinker -p "explain quicksort"

# Specific model
pythinker -m lm-studio/qwen/qwen3-coder-next -p "write a python http server"

# Interactive shell, then switch models with /model
pythinker

4. Disconnect.

pythinker logout --lm-studio

Ollama

# 1. start the server in one terminal
ollama serve

# 2. pull a model
ollama pull llama3.1:8b

# 3. connect Pythinker
pythinker login --ollama

# 4. use it
pythinker -p "explain monad transformers"
pythinker -m ollama/llama3.1:8b -p "..."
pythinker logout --ollama

Discovery uses Ollama's /api/tags for the model list and /api/show per model to read the real context window.

Remote LM Studio / Ollama (LAN host or alternate port)

pythinker login --lm-studio --base-url http://192.168.1.10:1234/v1
pythinker login --ollama    --base-url http://lan-box:11434/v1

The override is saved in your config and used by every subsequent run.

From inside the interactive shell

The same wiring is available as slash commands:

/login lm-studio        # or  /login lmstudio  (no dash also accepted)
/login ollama
/logout lm-studio
/logout ollama
/login                  # opens a chooser; entries 9 and 10 are the local providers
/model lm-studio/google/gemma-4-e4b   # switch model mid-session

⚠️ Context length matters (a common gotcha)

Pythinker's agent prompt — system instructions + tool schemas + skills + your message + recent history — is large. Tens of thousands of tokens before you've even sent your first message.

LM Studio loads a model with a small default context window (often 4096). If you start chatting against that, you'll see:

LLM provider error: Error: The number of tokens to keep from the initial
prompt is greater than the context length (n_keep: 16690 >= n_ctx: 4096).

The shell now prints a friendly recovery hint when this happens, but the cure is in LM Studio:

  1. In LM Studio, open the model in the Chat tab and click the gear/settings icon (or My Models → Edit).
  2. Set Context Length to at least 32768, and prefer 131072 if your VRAM allows. Practical experience: 64k still triggers errors during longer sessions; 128k is a safer floor.
  3. Reload the model (LM Studio prompts you).
  4. Restart Pythinker so it picks up the new state (Ctrl+D then pythinker, or pythinker -r <session-id> to resume).

Tip: the bigger you set the context, the more VRAM the model uses. If you OOM, try a smaller quantization (e.g., Q4_K_M instead of Q8_0) or a smaller model variant.

Ollama configures context per-request and Pythinker reads the model's max from /api/show, so this gotcha is mostly LM-Studio-specific.

VRAM-friendly model picks

Local models vary wildly in memory use. Rough guide on a 16 GB GPU (e.g., RTX 5080 mobile):

Model size Quant Approx. VRAM Fits 16 GB?
2-4 B Q4-Q8 2-4 GB Yes, easily
7-8 B Q4 5-6 GB Yes
7-8 B Q8 8-9 GB Yes
13-14 B Q4 8-10 GB Yes
27-31 B Q4 17-20 GB Tight / no
27-31 B Q8 30-35 GB No

If LM Studio errors with Failed to load model, you've exceeded VRAM — pick a smaller model or lower-bit quantization.

Environment variables

These override the defaults at both login and runtime:

Variable Purpose
LM_STUDIO_BASE_URL Override http://localhost:1234/v1
LM_STUDIO_API_KEY Set if you've enabled token auth in LM Studio
OLLAMA_BASE_URL Override http://localhost:11434/v1
OLLAMA_API_KEY Rarely needed (Ollama is unauthenticated by default)

Example:

LM_STUDIO_BASE_URL=http://workstation.lan:1234/v1 pythinker -p "..."

Refreshing the model list

If you load/unload models in LM Studio (or ollama pull/rm), re-run login to refresh:

pythinker login --lm-studio    # or --ollama

(Pythinker intentionally does NOT auto-refresh local providers in the background — login owns that state, so manual edits to your config aren't silently overwritten.)


🧩 IDE Integration via ACP

Pythinker speaks Agent Client Protocol natively. Point your ACP-compatible editor at pythinker acp and you get a multi-session agent server inside your IDE.

📝 Configuration for Zed / JetBrains
{
  "agent_servers": {
    "Pythinker Code": {
      "type": "custom",
      "command": "pythinker",
      "args": ["acp"],
      "env": {}
    }
  }
}

The ACP server provides:

Capability Description
🔑 Terminal auth pythinker login flow exposed to the IDE
📂 Session listing & resume Pick up where you left off
🔄 Hot model swap Change models for a running ACP session
ACP IDE integration demo

🔌 MCP Tooling

Pythinker loads Model Context Protocol tools from persistent config or ad-hoc files. Same tools, every agent — no rewriting.

🛠️ Manage persistent MCP servers

# 🌐 Streamable HTTP server with API key
pythinker mcp add --transport http context7 https://mcp.context7.com/mcp \
  --header "CONTEXT7_API_KEY: ctx7sk-your-key"

# 🔐 Streamable HTTP server with OAuth
pythinker mcp add --transport http --auth oauth linear https://mcp.linear.app/mcp

# 💻 stdio server
pythinker mcp add --transport stdio chrome-devtools -- npx chrome-devtools-mcp@latest

# 📋 List, authorize, test, and remove
pythinker mcp list
pythinker mcp auth linear
pythinker mcp test chrome-devtools
pythinker mcp remove chrome-devtools

📄 Use an ad-hoc MCP config file

{
  "mcpServers": {
    "context7": {
      "url": "https://mcp.context7.com/mcp",
      "headers": {
        "CONTEXT7_API_KEY": "YOUR_API_KEY"
      }
    },
    "chrome-devtools": {
      "command": "npx",
      "args": ["-y", "chrome-devtools-mcp@latest"]
    }
  }
}
pythinker --mcp-config-file /path/to/mcp.json

🧬 Extensibility

Pythinker is a small, extensible runtime — not a monolith. Build on it.

Extension Point What it does Where to look
🤖 Agents & subagents YAML specs define tools, prompts, and built-in subagent types src/pythinker_code/agents/
🎓 Skills /skill:<name> loads reusable instructions on demand bundled & user-defined
🌊 Flows /flow:<name> executes bundled prompt flows bundled & user-defined
🪝 Hooks Observe or block tool execution; integrate policy or automation hook events API
🧩 Plugins Installable extension packages pythinker plugin

🏗️ Architecture

Pythinker Code architecture diagram

🔐 Privacy & Telemetry

Pythinker is the agent framework, not the LLM. You bring your own API key (OpenAI, Anthropic, your local LM Studio model, etc.); your prompts and the model's responses go directly between your terminal and the model provider you configured. Pythinker never sees, stores, or forwards them.

If you opt in, Pythinker can collect a small amount of diagnostic telemetry about how the agent runs to improve the framework itself. It's strictly anonymous, never includes your prompts, model output, file contents, file paths, or any user-identifying data. Two channels:

Channel What lands there Endpoint
Errors (Sentry-protocol) Unhandled exceptions and crash stack traces, with absolute paths above site-packages/ rewritten to <env>/ so home directories don't leak errors.pythinker.com (self-hosted Bugsink)
Traces + structured logs (OpenTelemetry) Lifecycle events (session_started, started, model_switch), agent-loop spans (pythinker.turn / pythinker.llm / pythinker.tool), and per-event counters otel.pythinker.com (self-hosted SigNoz)

What we collect

  • Lifecycle events: session start, command-line flags actually used (booleans only), startup timing, model name (just the identifier, e.g. claude-opus-4-7), thinking-mode toggle, plan-mode toggle.
  • Agent-loop spans: turn duration, step count, stop reason (no_tool_calls / max_steps / error), tool name (Read, Bash, Edit, …), tool success/failure, tool duration, LLM call duration, input/output token counts (numbers — never the content).
  • Crashes: exception class name, scrubbed stack trace, library versions. We do not send local variable values.
  • Static context: pythinker version, OS family, Python version, terminal type (TERM_PROGRAM), CI flag (CI env var presence), locale.
  • A persistent, random device_id so we can count "how many distinct installs" without identifying a person.

What we never collect

  • Your prompts, the model's responses, or any conversation content
  • File contents, file paths, working directory names, or workspace structure
  • Your API keys, OAuth tokens, environment variables
  • Your real name, email, IP address, hostname (host name field is dropped at the edge collector)
  • Tool arguments (e.g. what file you read, what command you ran)

Opting in or forcing off

Telemetry is off by default. To enable it for a process:

export PYTHINKER_ENABLE_TELEMETRY=1
pythinker

To force telemetry off even if another setting enabled it:

# 1. Per-invocation CLI flag
pythinker --no-telemetry

# 2. Environment variable (works in shells, .env files, CI configs)
export PYTHINKER_DISABLE_TELEMETRY=1
pythinker

# 3. Permanently in your config file (~/.pythinker/config.toml)
[default]
telemetry = false

When telemetry is disabled, Pythinker short-circuits Sentry initialization, OTel exporter creation, and the in-process event sink. No network requests are made to the telemetry endpoints.

Pointing telemetry at your own infrastructure

If you operate pythinker for a team and want telemetry routed to your own SigNoz / Bugsink instead, override the endpoints via environment variables:

export PYTHINKER_SENTRY_DSN="https://<key>@your-bugsink.example.com/<project>"
export PYTHINKER_OTEL_ENDPOINT="https://your-otel-collector.example.com"
export PYTHINKER_OTEL_TOKEN="<your bearer token>"

The defaults point at infrastructure operated by the pythinker maintainers; set PYTHINKER_ENABLE_TELEMETRY=1 to use them.


🛠️ Development

🏁 Prepare the workspace

git clone https://github.com/mohamed-elkholy95/Pythinker-Code.git
cd Pythinker-Code
make prepare

🧰 Common commands

▶️ Run & iterate

uv run pythinker          # CLI from source
make format               # format all packages
make check                # lint + type-check

🧪 Test

make test                 # all unit + e2e tests
make ai-test              # AI-driven tests
make test-pythinker-code   # CLI only
make test-pythinker-core  # Core only
make test-pythinker-host  # Host only
make test-pythinker-sdk   # SDK only

🌐 Frontends

make web-back             # web backend
make web-front            # web frontend
make vis-back             # vis backend
make vis-front            # vis frontend

📦 Build

make build                # Python packages
make build-bin            # standalone binary
make help                 # all targets

💡 make build and make build-bin build and embed the web and visualization frontends before packaging.


🗂️ Project Layout

pythinker-code/
├── 📦 src/pythinker_code/         CLI runtime · tools · UIs · ACP · MCP · hooks · plugins · skills · web · vis backends
├── 🧱 packages/
│   ├── pythinker-core/           Provider-agnostic message, tool, and chat-provider abstractions
│   ├── pythinker-host/           Local/remote host filesystem and command execution
│   └── pythinker-code/           Console-script distribution package
├── 🧰 sdks/pythinker-sdk/        Python SDK
└── 🧪 tests/ · tests_e2e/ · tests_ai/   Unit · wire/CLI e2e · AI-driven test suites

🤝 Contributing

Contributions are warmly welcome — bug reports, PRs, plugins, skills, and docs all help.

If Pythinker helps you, a ⭐ on GitHub goes a long way.


📜 License

Distributed under the Apache-2.0 License. See LICENSE for the full text and NOTICE for attributions.


Built with ❤️ for engineers who live in the terminal.

🌐 pythinker.com  ·  📦 PyPI  ·  🐙 GitHub  ·  🧩 ACP  ·  🔌 MCP

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pythinker_code-0.12.0.tar.gz (6.0 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pythinker_code-0.12.0-py3-none-any.whl (6.3 MB view details)

Uploaded Python 3

File details

Details for the file pythinker_code-0.12.0.tar.gz.

File metadata

  • Download URL: pythinker_code-0.12.0.tar.gz
  • Upload date:
  • Size: 6.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pythinker_code-0.12.0.tar.gz
Algorithm Hash digest
SHA256 c839a46fa5704426c3924b32f866efe5430e1d9bccb79f72147fc17a51834ef5
MD5 dfcc559e12d7ec4762481f8a83510414
BLAKE2b-256 1cf0e4e6b543b2d6994c43606ed9c3682bd92cee5900c18bf54e27fc6d90acf9

See more details on using hashes here.

Provenance

The following attestation bundles were made for pythinker_code-0.12.0.tar.gz:

Publisher: release-pythinker-cli.yml on mohamed-elkholy95/Pythinker-Code

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pythinker_code-0.12.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pythinker_code-0.12.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3c017968e96b565388e94e2a91db4468d46706c471e288ca024df2d875150c1b
MD5 a10cfd6bf3937964bf7fb9e6505453c5
BLAKE2b-256 cb2610595af820df1c71b76cea6fe99fac414c1e911101e2a1c82d3f15e7c7a2

See more details on using hashes here.

Provenance

The following attestation bundles were made for pythinker_code-0.12.0-py3-none-any.whl:

Publisher: release-pythinker-cli.yml on mohamed-elkholy95/Pythinker-Code

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page