Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
377e450
feat(agent): land Phase 0 agent-design enhancements
elkaix Jun 8, 2026
4009efc
feat(security): wrap shell + web-search output as untrusted data
elkaix Jun 8, 2026
85b5477
feat(security): scope session approval per-command + destructive back…
elkaix Jun 8, 2026
8be32da
feat(security): strip invisible unicode from untrusted tool output
elkaix Jun 8, 2026
95c1ee5
feat(security): de-duplicate identical concurrent approval prompts
elkaix Jun 8, 2026
512480a
feat(security): protect pythinker config surface from edits + injection
elkaix Jun 8, 2026
792f1c5
fix(ui): hide <untrusted_data> wrapper from tool-output display
elkaix Jun 8, 2026
67a4240
fix(tests): restore green pyright + format gate on security tests
elkaix Jun 8, 2026
127b3bb
feat(security): wrap Grep content output as untrusted data
elkaix Jun 8, 2026
67a0901
docs(agent): add remaining-work execution plan + gap analysis
elkaix Jun 8, 2026
d8bc283
feat(reliability): yield to user on degenerate stuck loops (obs-eval-5)
elkaix Jun 8, 2026
58369d6
docs(agent): log progress — injdef-2-grep + obs-eval-5 done
elkaix Jun 8, 2026
c5d7c1c
feat(tools): suggest closest tool name on unknown tool call
elkaix Jun 8, 2026
df1a172
feat(reliability): graceful max-steps handoff summary (sysprompt-2)
elkaix Jun 8, 2026
e6204fe
feat(context): graduated stale-tool-output pruning before compaction …
elkaix Jun 8, 2026
0c2ad89
fix(security): harden approval gates and config-surface classification
elkaix Jun 8, 2026
ebd1408
feat(tools): add Progress checkpoint tool to the default agent
elkaix Jun 8, 2026
af8afbf
feat(soul): add model-keyed protocol-defense injection provider
elkaix Jun 8, 2026
0d732d0
docs(agent): log sysprompt-1 + uxsteer-1 done; 6/22, 16 remaining
elkaix Jun 8, 2026
92b862d
test(backfill): lock plan verification clause + LLM cache-token counters
elkaix Jun 8, 2026
6daa6b7
feat(memory): add opt-in durable-memory profile (memory-2)
elkaix Jun 8, 2026
1fa5e24
feat(skills): surface bundled-resource manifest when a skill is loade…
elkaix Jun 8, 2026
88735be
docs(agent): log backfill + memory-2 + skills-1; 8/22 done, 14 remaining
elkaix Jun 8, 2026
eafba2c
feat(subagents): roll child token/cost spend up to the orchestrator (…
elkaix Jun 8, 2026
27d7fe2
feat(skills): add agent-creator and customize-pythinker builtin skill…
elkaix Jun 8, 2026
e039243
docs(agent): log subagent-2 + mode-1 + skills-2; 11/22 done, 11 remai…
elkaix Jun 8, 2026
b655f32
feat(tools): spill truncated tool output to disk with recovery hint (…
elkaix Jun 8, 2026
3591b08
docs(agent): log tooldesc-2/ctxmgmt-1 done; obs-eval-1 in review; 12/22
elkaix Jun 8, 2026
3f1f300
test(subagents): set usage=None in __init__-bypassing compaction harn…
elkaix Jun 8, 2026
3343df1
feat(telemetry): connect the trace tree + GenAI semconv on spans (obs…
elkaix Jun 8, 2026
a804ab3
docs(agent): log obs-eval-1 done; 13/22, 9 remaining
elkaix Jun 8, 2026
4a8424e
feat(mcp): expose MCP resources and prompts via read-only tools (mcpe…
elkaix Jun 8, 2026
9cf1b41
docs(agent): log mcpext-1 done; 14/22, 8 remaining
elkaix Jun 8, 2026
d0af862
refactor(mcp): robust binary-content size + failed-server read test (…
elkaix Jun 8, 2026
d578e76
fix(test): silence reportArgumentType on duck-typed approval-key test
elkaix Jun 8, 2026
b41edf9
feat(mcp): docker --rm hygiene + isolated client-close on teardown (m…
elkaix Jun 8, 2026
60980d2
docs(agent): log mcpext-3 done; 15/22, 7 remaining
elkaix Jun 8, 2026
5983725
feat(mcp): discover project-scoped .pythinker/mcp.json layered over g…
elkaix Jun 8, 2026
b639730
docs(agent): log mcpext-2(c) done; 16 commits, 6 items remaining
elkaix Jun 8, 2026
2d049d7
docs(agent): capture recall-subsystem orientation for memory-1/memory…
elkaix Jun 8, 2026
378dc99
fix(soul): close shell sub-command bypasses and phase0 review findings
elkaix Jun 9, 2026
cd5c9d7
test: regenerate stale mcp_resource snapshots from mcpext-1
elkaix Jun 9, 2026
588de07
feat(memory): cross-session Recall tool (memory-1 / ctxmgmt-3)
elkaix Jun 9, 2026
bde1c62
fix(memory): harden Recall read path (memory-1 review)
elkaix Jun 9, 2026
7020426
feat(memory): re-arm recall on working-set / topic shift (memory-3)
elkaix Jun 9, 2026
de7e61d
docs(agent): log memory-1 + memory-3 done; 18/22, 4 remaining (uxstee…
elkaix Jun 9, 2026
7779a8b
feat(ux): non-blocking Suggestion affordance (uxsteer-2)
elkaix Jun 9, 2026
d0cf701
feat(ux): ACP question consistency + steer-cancels-question + print/A…
elkaix Jun 9, 2026
e06dad0
docs(agent): log uxsteer-2/3 done; 20/22, 2 L-items remaining (obs-ev…
elkaix Jun 9, 2026
bf56a88
feat(eval): versioned eval-case schema + efficiency scoring (obs-eval…
elkaix Jun 9, 2026
4e24c6a
feat(eval): record-replay cassette layer for LLM traffic (obs-eval-3,…
elkaix Jun 9, 2026
84e1682
docs(agent): all 22 plan items done; L-items shipped offline cores; f…
elkaix Jun 9, 2026
23d547e
test(e2e): normalize <untrusted_data> nonce + refresh wire snapshots
elkaix Jun 9, 2026
6a987a0
fix: close approval-drain escalation and 11 more review findings
elkaix Jun 9, 2026
a4f4f74
feat: friendly 429 usage-limit messaging and login account switch
elkaix Jun 9, 2026
a20eec2
chore: AGENTS guidance, asyncio-trace diagnostic, docs config
elkaix Jun 9, 2026
2e47943
docs(agents): move global invariants above merge-truncation tail
elkaix Jun 9, 2026
b1e771a
feat: lead 429 messages with live usage windows; log unparsed payloads
elkaix Jun 9, 2026
34feb4a
docs(changelog): note 429 usage-limit messaging and agent phase-0 work
elkaix Jun 9, 2026
5ac1958
fix: typo and formatting in 429 rate-limit diagnostics
elkaix Jun 9, 2026
cab02ac
fix(429): humanize unix reset times; fail-fast hard usage limits
elkaix Jun 9, 2026
5830723
fix: address CodeRabbit review findings on PR #89
elkaix Jun 9, 2026
30395a8
fix: stop spurious never-awaited warnings; harden read-only shell guard
elkaix Jun 9, 2026
2db6915
feat(agent): teach default agent to set up MCP servers
elkaix Jun 9, 2026
f0aaf04
feat(mcp): document removal and warn on mcpServers in config.yaml
elkaix Jun 9, 2026
48a5581
Merge branch 'main' into feat/agent-phase0-enhancements
elkaix Jun 9, 2026
2058f26
Merge remote-tracking branch 'origin/main' into feat/agent-phase0-enh…
elkaix Jun 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 74 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,55 @@ subagents, skills, web/visualization UIs, and multi-provider LLM authentication.
Context7 MCP documentation lookups and targeted web search to verify the latest updates, APIs,
CI/GitHub Actions behavior, dependency guidance, and best practices relevant to the task.

## Global invariants and tripwires

Always-on, tracked safety and truthfulness invariants — promoted here from the local
`AGENTS.local` contract so they apply on a fresh clone and in CI, not only where a local file
exists. They complement the rules above; the full contract, defensive patterns (P1–P7), and PR
template live in `AGENTS.local` when present.

### Failure truthfulness contract

Observable output must reflect whether an operation succeeded, failed, partially succeeded, or
degraded.

- Never return success / `true` / `ok` / empty after a required internal step failed; never
report healthy when a required dependency is down; never continue startup past a critical
initialization failure.
- Use explicit error contracts that distinguish no-data, invalid input, unauthenticated,
unauthorized, forbidden, conflict, timeout, dependency-unavailable, partial failure, and
internal error. Prefer typed results, domain exceptions, or status enums over ambiguous
`None`/empty/`False` returns. Convert errors at boundaries, not deep in domain logic.
- Fallbacks are explicit decisions: degraded, stale, estimated, cached, or partial output must
carry source/status and be logged — and must never feed authorization or security decisions.
Security, approval, signature, and idempotency uncertainty fail closed.

### AI-risk audit tripwires (C01–C15)

Reject or flag for human review any change that exhibits:

- **C01** success returned after a critical internal failure.
- **C02** silent drop of audit, telemetry, transaction, or security evidence.
- **C03** broad `except`/catch that swallows errors without logging, recovery, rethrow, or typed conversion.
- **C04** scattered fallback values that hide dependency failures or weaken guarantees.
- **C05** hidden flags, debug routes, local shortcuts, or backdoors past auth/validation/limits/audit.
- **C06** returns that blur no-data, failure, denial, and partial success.
- **C07** duplicate business-logic paths that can diverge from the primary rule.
- **C08** background tasks/threads/queues without lifecycle, cancellation, error handling, timeout, and observability.
- **C09** safety disabled on an environment flag unless narrow, documented, tested, and impossible in production.
- **C10** startup that continues after critical init failure, or readiness that ignores required-dependency health.
- **C11** non-determinism in execution-critical paths (unseeded randomness, floating temperature, wall-clock-dependent decisions).
- **C12** missing source-to-output lineage for outbound payloads, persisted records, and audit events.
- **C13** degraded/estimated/stale/fallback output presented as authoritative.
- **C14** tests covering only happy paths — ignoring failure, security, edge, concurrency, and malformed-input cases.
- **C15** retries around writes without proven idempotency (keys, constraints, dedupe records, atomic operations).

In this codebase the most load-bearing instances are: approvals fail closed and are never
bypassed (`soul/approval.py`); untrusted content is wrapped/neutralized before the prompt
(`utils/trust.py`); hooks fail open by design *except* that a `PreToolUse` block result is
never discarded; background workers must define lifecycle and recovery; and tool/LLM output is
validated, never trusted.

## Simplicity and scope discipline

- Before implementing, identify the Minimum Viable Change: the smallest code delta that solves the
Expand Down Expand Up @@ -159,14 +208,24 @@ instead of claiming success.

## Repo map

For the full per-subsystem routing index (entry points, key interfaces, trust boundaries),
see `docs/en/customization/architecture.md`. This list is a quick orientation only.

- `src/pythinker_code/agents/`: built-in YAML agent specs and prompt files.
- `src/pythinker_code/auth/`: OAuth/API-key provider integrations.
- `src/pythinker_code/background/`: background task worker/runtime support.
- `src/pythinker_code/cli/`: Typer command tree, including MCP, plugin, web, vis, info, export,
and terminal commands.
- `src/pythinker_code/cli/`: Typer command tree (lazy-loaded subcommands `mcp`, `plugin`,
`skill`, `web`, `vis`, `info`, `export`, `review`, `secscan`, `security-scan`, `debug`,
`update`, plus eager `login`, `logout`, `term`, `acp`).
- `src/pythinker_code/hooks/`: hook definitions and execution engine.
- `src/pythinker_code/plugin/`: plugin discovery and installation support.
- `src/pythinker_code/prompts/`: shared prompt templates.
- `src/pythinker_code/prompts/`: shared prompt templates (`INIT`, `COMPACT`).
- `src/pythinker_code/telemetry/`, `src/pythinker_code/notifications/`: opt-out telemetry
(OTel + Sentry) and the claim/ack/recover notification delivery queue.
- `src/pythinker_code/memory/`, `src/pythinker_code/approval_runtime/`,
`src/pythinker_code/wire/`, `src/pythinker_code/utils/`: recall/consolidation, the pending-
approval source of truth, the Wire event protocol, and shared security-relevant helpers.
- `src/pythinker_code/deps/`: build-time `Makefile` target that vendors the ripgrep binary.
- `src/pythinker_code/skill/`, `src/pythinker_code/skills/`: skill discovery, loading, bundled
skills, and flow-skill support.
- `src/pythinker_code/soul/`: core runtime loop, context, compaction, approvals, slash commands.
Expand Down Expand Up @@ -233,7 +292,9 @@ from the active model, not from a hard-coded list.

- **Supported providers** (`src/pythinker_code/auth/`): `openai` (API + ChatGPT OAuth),
`anthropic_direct` (API + Anthropic OAuth), `opencode_go` (OAuth), `minimax` (OAuth),
`deepseek` (API key), `openrouter` (API key).
`deepseek` (API key), `openrouter` (API key), plus `z_ai`, `alibaba`, `moonshot`,
`lm_studio`, `ollama` (local), and `github_feedback`. Derive the provider from the active
model; never hard-code the list.
- **Shared token store / refresh**: `OAuthManager` in `src/pythinker_code/auth/oauth.py`.
- **Platform registry**: `src/pythinker_code/auth/platforms.py` defines `Platform` records and key
conventions:
Expand Down Expand Up @@ -287,12 +348,18 @@ everything sequentially.
- **Parallelize independent work**: batch unrelated reads/searches/checks in one turn. If an
investigation needs more than a few tool calls, launch multiple `explore` subagents concurrently
and synthesize their findings before editing.
- **Use role-specific subagents**:
- **Use role-specific subagents** (12 built-ins registered in
`src/pythinker_code/agents/default/agent.yaml`):
- `explore`: read-only mapping, call-site discovery, architecture reconnaissance.
- `plan`: evidence-backed implementation strategy and trade-offs.
- `scout`: read-only, breadth-first fan-out reconnaissance over many files at once.
- `plan` / `planner`: evidence-backed implementation strategy; `planner` decomposes a task
into distinct parallel seeds.
- `coder`: general software-engineering work when the brief still needs judgment.
- `implementer`: tightly scoped edits from a concrete brief; no drive-by refactors.
- `review`: severity-scored read-only critique with suggested fixes.
- `debugger`: failure/log/stack-trace root-cause analysis with reproduction evidence.
- `review` / `code-reviewer`: severity-scored read-only critique with suggested fixes
(`code-reviewer` is diff-focused).
- `security-reviewer`: read-only security critique.
- `verifier`: run tests/lint/build gates and report PASS / FAIL / FLAKY without fixing.
- `judge`: independent final quality gate for non-trivial code changes, reports, and findings.
- **Steer with complete prompts**: new subagents do not inherit the full parent transcript by
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ GitHub Releases page; `0.8.0` is the new starting line.

- **Refreshed TUI theme and Catppuccin syntax highlighting.** The interface adopts a brand periwinkle/indigo accent (`#B3B9F4` dark / `#0B114E` light) with a reharmonized selection tint, and code blocks now highlight with Catppuccin Mocha (dark) / Latte (light), adaptive to the active theme — implemented as foreground-only Pygments styles with no new dependency. Markdown inline code and links render terminal-native cyan, blockquotes green, and ordered-list markers bright blue (so they adapt per terminal), and user messages sit on a neutral grey block instead of the prior blue tint.
- **Homebrew updater no longer no-ops or false-reports success.** `pythinker update` on a Homebrew install now runs `brew update` to refresh the tap before `brew upgrade`, so a stale local tap clone can't pin the old formula and silently no-op ("0.37.0 already installed"). After upgrading it re-checks the installed version via `brew list --versions` and reports a clear failure instead of "Updated successfully!" when the version did not actually advance.
- **Friendlier usage-limit (429) messages and ChatGPT account switching.** When a provider returns a 429, Pythinker now renders a human-readable notice — the plan name, the reset window, and a dimmed `Server:` detail line (all markup-escaped) — instead of a raw error string. `/login` for ChatGPT now uses `prompt=login`, so you can switch between ChatGPT accounts instead of being silently kept on the previous session.
- **Agent phase-0 enhancements.** Adds a model-invocable cross-session Recall tool (search and read prior sessions on demand, sanitized and read-only for subagents), read-only MCP resources/prompts surfaced as tools, project-scoped `.pythinker/mcp.json` layering, subagent token/cost roll-up to the orchestrator, and truncated tool output that spills to disk with a recovery hint instead of being lost.
- **No more spurious `coroutine … was never awaited` warnings.** Dropped Sentry's `AsyncioIntegration`, whose `create_task` monkeypatch wrapped every coroutine and — when a task was cancelled before its first step during turn/prompt teardown — orphaned the inner coroutine, printing `WireUISide.receive` and prompt_toolkit "never awaited" `RuntimeWarning`s to the console. The integration added no spans (tracing/profiling are off), and exception capture for async tasks is preserved by the existing asyncio exception handler.
- **Read-only profile guard hardened against version-pinned interpreters.** Inline-code interpreter invocations that use a version-suffixed or absolute binary (`python3.14 -c …`, `/usr/bin/python3.12 -c …`, `node20 -e …`) are now classified as mutating/destructive just like the bare `python`/`node` forms, so they can no longer bypass a read-only subagent profile or skip destructive deliberation.
- **The agent sets up and removes MCP servers on request instead of refusing.** Asked to add, remove, or set up an MCP server, the default agent now knows it runs in Pythinker: it configures the server with the `pythinker mcp add`/`remove` CLI (or by editing `~/.pythinker/mcp.json` / `./.pythinker/mcp.json`), verifies with `pythinker mcp list`/`test`, and tells you to restart or `/reload` to load the change — rather than refusing or citing Claude Code/Desktop config paths (`~/.claude.json`) it cannot use. The prompt now also hard-steers the agent away from writing `mcpServers` into `~/.pythinker/config.yaml` (YAML is never parsed for MCP, so such an entry is silently dropped and the server never appears in `/mcp`). As a backstop, MCP config loading now logs a warning when it finds an `mcpServers` block in a `config.yaml` (global or project), so a human or agent that misplaces it gets a diagnosable trace instead of a silent drop.
- **Security: dependency vulnerability remediation.** Cleared the open Dependabot advisories across all manifests. Python: `asyncssh` 2.22.0 → 2.23.0 (path-traversal in `AuthorizedKeysFile %u`) in the `pythinker-host` pin and both lockfiles, and `starlette` 1.0.0 → 1.2.1 (Host-header path poisoning). JS: regenerated the `web`, `vis`, and `install-counter-worker` lockfiles and bumped the worker's `vitest` to `^3.2.6` (critical Vitest UI arbitrary file read/exec), clearing all critical/high/moderate advisories. The only residual is a handful of low-severity transitive `elliptic`/`bn.js` advisories in `web`'s browser crypto polyfill chain, left unforced because the fix downgrades `vite-plugin-node-polyfills` and majors `ai`, breaking the build for marginal benefit.

## 0.38.0 (2026-06-08)
Expand Down
1 change: 1 addition & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export default withMermaid(defineConfig({
{ text: 'Agent Skills', link: '/en/customization/skills' },
{ text: 'Agents and Subagents', link: '/en/customization/agents' },
{ text: 'Agent Architecture', link: '/en/customization/agent-architecture' },
{ text: 'Repository Map', link: '/en/customization/architecture' },
{ text: 'Print Mode', link: '/en/customization/print-mode' },
{ text: 'Wire Mode', link: '/en/customization/wire-mode' },
],
Expand Down
Loading
Loading