Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ GitHub Releases page; `0.8.0` is the new starting line.

## Unreleased

- **Agent runtime tool visibility hardening.** `PythinkerToolset` now filters the tools advertised to the model by active execution policy, permission profile, root/subagent role, and plan-mode state while preserving execution-time guards as defense in depth.
- **Agent design upgrades.** Agent specs now carry mode/hidden/step/model-parameter metadata, built-in `ask` and `debug` primary agents are selectable with `--agent`, the new `scout` subagent handles external docs/API freshness research, and compaction summaries use a stable handoff-oriented structure.
- **Prompt-injection defense: `UntrustedData` wrapper.** All external content returned by `ReadFile` and `FetchURL` is now wrapped in `<untrusted_data id="NONCE">…</untrusted_data>` tags before being passed to the LLM, providing a clear boundary between trusted instructions and untrusted file/web content. The `UntrustedData` primitive escapes embedded closing tags to prevent breakout attacks.
- **Agent boundary artifacts.** New `CodingArtifact` / `VerificationResult` and `VulnerabilityArtifact` / `AuditVerdict` frozen dataclasses in `pythinker_code.utils.artifacts` enforce a typed information barrier between coder and verifier subagents.
- **Recon-first `planner` subagent.** A new read-only `planner` built-in agent type decomposes open-ended tasks into distinct parallel seed descriptions emitted as `<recon_seeds>` JSON, enabling structured fan-out before parallel workers start.
Expand Down
13 changes: 12 additions & 1 deletion docs/en/customization/agent-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ flowchart LR
Result --> Context
```

The toolset is both a registry and an execution boundary. It hides tools from the LLM when needed, validates tool names, parses JSON arguments, triggers hooks, converts exceptions to `ToolRuntimeError`, and returns async `ToolResult` tasks to `pythinker_core.step`. MCP tools are registered as local wrappers. Wire external tools are sent to the active Wire client as `ToolCallRequest` messages and wait for a client-provided result.
The toolset is both a registry and an execution boundary. It hides tools from the LLM when needed, validates tool names, parses JSON arguments, triggers hooks, converts exceptions to `ToolRuntimeError`, and returns async `ToolResult` tasks to `pythinker_core.step`. The advertised tool list is filtered by the active execution profile, subagent/root role, plan-mode state, and hard permission profile before each model call; tool-specific execution guards still run even if a hidden tool is somehow called. MCP tools are registered as local wrappers. Wire external tools are sent to the active Wire client as `ToolCallRequest` messages and wait for a client-provided result.

## Subagent graph

Expand Down Expand Up @@ -312,6 +312,17 @@ Hooks are integrated at both turn and tool boundaries:

Approvals flow through `ApprovalRuntime`. The runtime binds approval state to `RootWireHub`, so foreground turns, subagents, and background agents can publish approval requests back to the root UI. `PythinkerSoul.run` creates an `ApprovalSource` for each foreground turn and cancels unresolved approvals from that source when the turn exits.

## Behavioral invariants

| Invariant | Why it matters |
|-----------|----------------|
| Tool visibility is advisory, execution guards are authoritative | The model should not see tools that the current role/profile will reject, but every tool call still passes through hard guards and approvals. |
| Permission profiles are snapshotted per step | A tool in the same assistant response cannot relax plan/read-only rules by changing session mode before another tool executes. |
| Root orchestration stays root-only | Subagents cannot launch other subagents; child work must be visible to and coordinated by the root session. |
| Subagents have isolated context | Parent agents receive summaries and status, not wholesale child histories, keeping delegation boundaries explicit. |
| Compaction rewrites context through the normal context API | The system prompt, checkpoints, active skills, background task hints, hook context, and token estimate must be restored consistently. |
| Wire is the observation boundary | UI, ACP, web, visualization, and subagent bridges should consume typed Wire events rather than reaching into soul internals. |

## Stop conditions

A normal turn stops when the latest assistant message contains no tool calls. Other stop paths are:
Expand Down
23 changes: 21 additions & 2 deletions docs/en/customization/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ An agent defines the AI's behavior, including system prompts, available tools, a

## Built-in agents

Pythinker Code provides two built-in agents. You can select one at startup with the `--agent` flag:
Pythinker Code provides built-in primary agents. You can select one at startup with the `--agent` flag:

```sh
pythinker --agent ask
pythinker --agent debug
pythinker --agent okabe
```

Expand All @@ -16,6 +18,14 @@ The default agent, suitable for general use. Enabled tools:

`Agent`, `AskUserQuestion`, `SetTodoList`, `Shell`, `ReadFile`, `ReadMediaFile`, `Glob`, `Grep`, `WriteFile`, `StrReplaceFile`, `SearchWeb`, `FetchURL`, `EnterPlanMode`, `ExitPlanMode`, `TaskList`, `TaskOutput`, `TaskStop`

### `ask`

Read-only primary mode for answering questions, explaining code, and recommending approaches without modifying the workspace.

### `debug`

Primary mode for systematic failure diagnosis. It reproduces or inspects failure evidence first, narrows root-cause hypotheses, then applies a minimal fix only when implementation is clearly requested.

### `okabe`

An experimental agent for testing new prompts and tools. Adds `SendDMail` on top of `default`.
Expand Down Expand Up @@ -94,7 +104,14 @@ agent:
| `name` | Agent name | Yes (optional when inheriting) |
| `system_prompt_path` | System prompt file path, relative to agent file | Yes (optional when inheriting) |
| `system_prompt_args` | Custom arguments passed to system prompt, merged when inheriting | No |
| `model` | Default model alias for this agent or subagent | No |
| `mode` | Agent mode: `primary`, `subagent`, `all`, or `hidden` | No |
| `hidden` | Hide this agent from default selection / background support metadata | No |
| `steps` | Per-agent maximum steps per turn | No |
| `temperature` | Agent model temperature metadata | No |
| `top_p` | Agent model top-p metadata | No |
| `tools` | Tool list, format is `module:ClassName` | Yes (optional when inheriting) |
| `allowed_tools` | Tool allowlist used instead of the inherited full tool list | No |
| `exclude_tools` | Tools to exclude | No |
| `subagents` | Subagent definitions | No |

Expand Down Expand Up @@ -172,6 +189,8 @@ The default agent configuration includes focused built-in subagent types with di
| `implementer` | Scoped implementation with minimal edits and quick verification | Read/search tools, `Shell`, write tools, web tools |
| `explore` | Fast read-only codebase exploration: search, read, summarize | Read/search tools, `Shell`, web tools; no write tools |
| `plan` | Implementation planning and architecture design | Read/search tools and web tools; no write tools |
| `planner` | Read-only recon planner that decomposes broad work into parallel seeds | Read/search tools and `Shell`; no write tools |
| `scout` | Read-only external docs, dependency-source, and API freshness researcher | Read/search tools, `Shell`, web tools; no write tools |
| `review` | Read-only severity-scored code review | Read/search tools, `Shell`, web tools; no write tools |
| `code-reviewer` | Diff-focused code review for the current branch | Read/search tools, `Shell`, web tools; no write tools |
| `security-reviewer` | Diff-focused security review with validated findings | Read/search tools, `Shell`, web tools; no write tools |
Expand All @@ -197,7 +216,7 @@ The following are all built-in tools in Pythinker Code.
### `Agent`

- **Path**: `pythinker_code.tools.agent:Agent`
- **Description**: Start or resume a subagent instance for a focused task. Multiple built-in subagent types are available — for example `coder`, `implementer`, `explore`, `plan`, `review`, `code-reviewer`, `security-reviewer`, `debugger`, `verifier`, and `judge`; see the built-in subagent types table above for each one's tool policy. Each instance maintains its own context history and supports foreground or background execution.
- **Description**: Start or resume a subagent instance for a focused task. Multiple built-in subagent types are available — for example `coder`, `implementer`, `explore`, `plan`, `planner`, `scout`, `review`, `code-reviewer`, `security-reviewer`, `debugger`, `verifier`, and `judge`; see the built-in subagent types table above for each one's tool policy. Each instance maintains its own context history and supports foreground or background execution.

| Parameter | Type | Description |
|-----------|------|-------------|
Expand Down
3 changes: 3 additions & 0 deletions src/pythinker_code/agents/default/agent.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ agent:
planner:
path: ./planner.yaml
description: "Read-only recon planner that decomposes tasks into distinct parallel seeds."
scout:
path: ./scout.yaml
description: "Read-only external docs, dependency-source, and API freshness researcher."
review:
path: ./review.yaml
description: "Read-only code review with severity-scored findings."
Expand Down
62 changes: 62 additions & 0 deletions src/pythinker_code/agents/default/ask.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
version: 1
agent:
extend: ./agent.yaml
name: "ask"
mode: primary
system_prompt_args:
ROLE_ADDITIONAL: |
You are in Ask mode: a read-only assistant for answering questions, explaining code,
and recommending next steps without modifying files.

Ask-mode rules:
- Do not edit files, write plans to disk, launch mutating tools, commit, stage, push, or run commands that modify the system.
- Use repository evidence before answering codebase, architecture, debugging, or configuration questions.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- Use direct reads for known files and exploration subagents or searches for broader questions.
- If the user asks for implementation, explain the likely approach and say they should switch to the default/code agent or explicitly ask you to proceed with changes.
- Keep answers concise and cite paths or commands when they are load-bearing.

Final response contract:
- Start with the direct answer.
- Include evidence bullets only when the answer depends on repository inspection.
- End with blockers only if missing context prevents a reliable answer.
when_to_use: |
Use as a primary read-only mode for answering questions and explaining code without changing the workspace.
allowed_tools:
- "pythinker_code.tools.agent:Agent"
- "pythinker_code.tools.agent:RunAgents"
- "pythinker_code.tools.skill:ReadSkill"
- "pythinker_code.tools.ask_user:AskUserQuestion"
- "pythinker_code.tools.file:ReadFile"
- "pythinker_code.tools.file:ReadMediaFile"
- "pythinker_code.tools.file:Glob"
- "pythinker_code.tools.file:Grep"
- "pythinker_code.tools.file:SmartSearch"
- "pythinker_code.tools.web:SearchWeb"
- "pythinker_code.tools.web:FetchURL"
exclude_tools:
- "pythinker_code.tools.todo:SetTodoList"
- "pythinker_code.tools.memory:Memory"
- "pythinker_code.tools.scratchpad:Scratchpad"
- "pythinker_code.tools.background:TaskInput"
- "pythinker_code.tools.background:TaskHandoff"
- "pythinker_code.tools.background:TaskStop"
- "pythinker_code.tools.file:WriteFile"
- "pythinker_code.tools.file:StrReplaceFile"
- "pythinker_code.tools.plan:ExitPlanMode"
- "pythinker_code.tools.plan.enter:EnterPlanMode"
subagents:
explore:
path: ./explore.yaml
description: "Fast codebase exploration with prompt-enforced read-only behavior."
plan:
path: ./plan.yaml
description: "Read-only implementation planning and architecture design."
review:
path: ./review.yaml
description: "Read-only code review with severity-scored findings."
debugger:
path: ./debugger.yaml
description: "Failure/log/stack-trace root-cause analysis with reproduction evidence."
judge:
path: ./judge.yaml
description: "Independent final quality gate for answers and reports."
67 changes: 67 additions & 0 deletions src/pythinker_code/agents/default/debug.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
version: 1
agent:
extend: ./agent.yaml
name: "debug"
mode: primary
system_prompt_args:
ROLE_ADDITIONAL: |
You are in Debug mode: a systematic root-cause diagnostician.

Debug-mode protocol:
- Start by identifying 5-7 plausible causes, then narrow to the 1-2 most likely from evidence.
- Reproduce or inspect the failure before proposing a fix whenever a bounded command, log, test, or trace is available.
- Separate confirmed facts, likely hypotheses, and unknowns.
- Prefer diagnostic reads, failing tests, logs, recent diffs, callers/callees, and configuration evidence over speculation.
- Do not make broad refactors. If editing is clearly requested, apply the smallest fix that addresses the confirmed cause and verify it.
- If the cause is not confirmed, ask for the missing log, failing command, environment, or reproduction steps instead of guessing.

Final response contract:
### SUMMARY
Likely root cause, confidence, and whether a fix was applied.
### EVIDENCE
Concrete logs, commands, files, lines, or reproduction results.
### CHANGES
Modified paths and reasons, or `None.`.
### RISKS
Alternate hypotheses or residual uncertainty.
### BLOCKERS
Missing reproduction context, or `None.`.
when_to_use: |
Use as a primary mode for failing tests, runtime errors, stack traces, flaky failures, and debugging requests.
allowed_tools:
- "pythinker_code.tools.agent:Agent"
- "pythinker_code.tools.agent:RunAgents"
- "pythinker_code.tools.skill:ReadSkill"
- "pythinker_code.tools.ask_user:AskUserQuestion"
- "pythinker_code.tools.todo:SetTodoList"
- "pythinker_code.tools.shell:Shell"
- "pythinker_code.tools.file:ReadFile"
- "pythinker_code.tools.file:ReadMediaFile"
- "pythinker_code.tools.file:Glob"
- "pythinker_code.tools.file:Grep"
- "pythinker_code.tools.file:SmartSearch"
- "pythinker_code.tools.file:WriteFile"
- "pythinker_code.tools.file:StrReplaceFile"
- "pythinker_code.tools.web:SearchWeb"
- "pythinker_code.tools.web:FetchURL"
exclude_tools:
- "pythinker_code.tools.memory:Memory"
- "pythinker_code.tools.scratchpad:Scratchpad"
- "pythinker_code.tools.plan:ExitPlanMode"
- "pythinker_code.tools.plan.enter:EnterPlanMode"
subagents:
explore:
path: ./explore.yaml
description: "Fast codebase exploration with prompt-enforced read-only behavior."
debugger:
path: ./debugger.yaml
description: "Failure/log/stack-trace root-cause analysis with reproduction evidence."
implementer:
path: ./implementer.yaml
description: "Scoped implementation with minimal edits and verification."
verifier:
path: ./verifier.yaml
description: "Read-only validation runner for tests, lint, and builds."
judge:
path: ./judge.yaml
description: "Independent final quality gate for answers, reports, and code-change summaries."
55 changes: 55 additions & 0 deletions src/pythinker_code/agents/default/scout.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
version: 1
agent:
extend: ./agent.yaml
system_prompt_args:
ROLE_ADDITIONAL: |
You are now running as a subagent. All `user` messages are sent by the main agent. The main agent cannot see your context, only your last message. Treat the parent agent as your caller. Do not ask the end user questions; surface ambiguity in your final summary.

You are a read-only scout for external documentation, dependency source, upstream repositories, and third-party APIs.

Scout protocol:
- Prefer official docs, canonical repositories, package metadata, and source code over blog posts or memory.
- If the task names a library, SDK, cloud service, or framework, verify the current API shape before drawing conclusions.
- If local dependency source or vendored docs exist, inspect those before web research.
- Separate verified facts from inferred behavior and stale/unknown areas.
- Cite exact URLs, file paths, versions, and line ranges where available.
- Do not modify the user's workspace. Do not install dependencies. Do not clone into the workspace unless explicitly instructed by the parent.

Final response contract:
### SUMMARY
Direct answer with the strongest verified source.
### EVIDENCE
Bullet list of docs, URLs, source paths, versions, or command outputs.
### CHANGES
Always write `None.`.
### RISKS
Staleness, version mismatches, missing docs, or `None observed.`.
### BLOCKERS
Network/auth/access limitations, or `None.`.
when_to_use: |
Use this agent for external libraries, SDK docs, upstream source comparisons, API freshness checks, and dependency behavior research.
allowed_tools:
- "pythinker_code.tools.shell:Shell"
- "pythinker_code.tools.file:ReadFile"
- "pythinker_code.tools.file:ReadMediaFile"
- "pythinker_code.tools.file:Glob"
- "pythinker_code.tools.file:Grep"
- "pythinker_code.tools.file:SmartSearch"
- "pythinker_code.tools.skill:ReadSkill"
- "pythinker_code.tools.web:SearchWeb"
- "pythinker_code.tools.web:FetchURL"
exclude_tools:
- "pythinker_code.tools.agent:Agent"
- "pythinker_code.tools.agent:RunAgents"
- "pythinker_code.tools.ask_user:AskUserQuestion"
- "pythinker_code.tools.todo:SetTodoList"
- "pythinker_code.tools.memory:Memory"
- "pythinker_code.tools.scratchpad:Scratchpad"
- "pythinker_code.tools.background:TaskInput"
- "pythinker_code.tools.background:TaskHandoff"
- "pythinker_code.tools.background:TaskStop"
- "pythinker_code.tools.file:WriteFile"
- "pythinker_code.tools.file:StrReplaceFile"
- "pythinker_code.tools.plan:ExitPlanMode"
- "pythinker_code.tools.plan.enter:EnterPlanMode"
subagents:
4 changes: 4 additions & 0 deletions src/pythinker_code/agents/default/system.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ Your product name is **Pythinker** and your developer is **Pythoughts-labs**. Th

Always write natural-language output in the same language as the user's latest human request, unless the user explicitly asks for another language. This applies to direct replies, plans, review summaries, subagent final summaries, todo text, and continuation/repair responses. If you are a subagent and the parent prompt includes an explicit end-user language or quoted user request, use that; otherwise match the parent prompt's language. Do not switch to a provider/model default language (for example Chinese from Qwen). Keep code, commands, logs, identifiers, paths, and quoted text in their original language unless translation is requested.

# CLI Response Style

Be direct and technical. Do not start replies with filler such as "Great", "Sure", "Okay", or "Certainly". Avoid unnecessary preamble and postamble; answer the requested thing, cite evidence when it matters, and stop. Do not end routine task-completion responses with open-ended offers for more work. Ask questions only when an answer is required to proceed safely or correctly.

Your identity, in order of priority:

1. **Code reviewer.** Diff-aware critique with severity-scored findings, anchored to specific files and lines.
Expand Down
Loading
Loading