paimon 0.2.7__tar.gz → 0.2.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. {paimon-0.2.7/paimon.egg-info → paimon-0.2.8}/PKG-INFO +39 -20
  2. {paimon-0.2.7 → paimon-0.2.8}/README.md +34 -18
  3. {paimon-0.2.7 → paimon-0.2.8}/README.zh-CN.md +34 -18
  4. {paimon-0.2.7 → paimon-0.2.8}/paimon/agent.py +193 -66
  5. paimon-0.2.8/paimon/agentpane.py +136 -0
  6. paimon-0.2.8/paimon/antigravity.py +422 -0
  7. {paimon-0.2.7 → paimon-0.2.8}/paimon/app.py +92 -114
  8. {paimon-0.2.7 → paimon-0.2.8}/paimon/app.tcss +38 -14
  9. paimon-0.2.8/paimon/chatgpt.py +208 -0
  10. {paimon-0.2.7 → paimon-0.2.8}/paimon/cli.py +27 -18
  11. {paimon-0.2.7 → paimon-0.2.8}/paimon/commandpane.py +5 -5
  12. {paimon-0.2.7 → paimon-0.2.8}/paimon/commands.py +125 -42
  13. {paimon-0.2.7 → paimon-0.2.8}/paimon/compaction.py +24 -47
  14. {paimon-0.2.7 → paimon-0.2.8}/paimon/config.py +123 -116
  15. {paimon-0.2.7 → paimon-0.2.8}/paimon/errors.py +1 -1
  16. {paimon-0.2.7 → paimon-0.2.8}/paimon/headless.py +6 -4
  17. paimon-0.2.8/paimon/llm.py +250 -0
  18. {paimon-0.2.7 → paimon-0.2.8}/paimon/login.py +98 -41
  19. paimon-0.2.8/paimon/oauth.py +234 -0
  20. {paimon-0.2.7 → paimon-0.2.8}/paimon/pane.py +56 -340
  21. paimon-0.2.8/paimon/review.py +170 -0
  22. {paimon-0.2.7 → paimon-0.2.8}/paimon/skill/SKILL.md +9 -9
  23. {paimon-0.2.7 → paimon-0.2.8}/paimon/tabs.py +17 -22
  24. {paimon-0.2.7 → paimon-0.2.8}/paimon/telemetry.py +1 -1
  25. paimon-0.2.8/paimon/textual_debug.py +230 -0
  26. {paimon-0.2.7 → paimon-0.2.8}/paimon/tools.py +415 -481
  27. paimon-0.2.8/paimon/transcript.py +287 -0
  28. {paimon-0.2.7 → paimon-0.2.8}/paimon/ui.py +241 -26
  29. {paimon-0.2.7 → paimon-0.2.8/paimon.egg-info}/PKG-INFO +39 -20
  30. {paimon-0.2.7 → paimon-0.2.8}/paimon.egg-info/SOURCES.txt +7 -1
  31. paimon-0.2.8/paimon.egg-info/requires.txt +9 -0
  32. {paimon-0.2.7 → paimon-0.2.8}/paimon.egg-info/scm_file_list.json +12 -2
  33. paimon-0.2.8/paimon.egg-info/scm_version.json +8 -0
  34. {paimon-0.2.7 → paimon-0.2.8}/pyproject.toml +4 -1
  35. paimon-0.2.7/paimon/llm.py +0 -130
  36. paimon-0.2.7/paimon/model_windows.py +0 -2852
  37. paimon-0.2.7/paimon.egg-info/requires.txt +0 -6
  38. paimon-0.2.7/paimon.egg-info/scm_version.json +0 -8
  39. {paimon-0.2.7 → paimon-0.2.8}/LICENSE +0 -0
  40. {paimon-0.2.7 → paimon-0.2.8}/MANIFEST.in +0 -0
  41. {paimon-0.2.7 → paimon-0.2.8}/paimon/__init__.py +0 -0
  42. {paimon-0.2.7 → paimon-0.2.8}/paimon/__main__.py +0 -0
  43. {paimon-0.2.7 → paimon-0.2.8}/paimon/_grep_worker.py +0 -0
  44. {paimon-0.2.7 → paimon-0.2.8}/paimon/diff.py +0 -0
  45. {paimon-0.2.7 → paimon-0.2.8}/paimon/herdr.py +0 -0
  46. {paimon-0.2.7 → paimon-0.2.8}/paimon/lockfile.py +0 -0
  47. {paimon-0.2.7 → paimon-0.2.8}/paimon/mentions.py +0 -0
  48. {paimon-0.2.7 → paimon-0.2.8}/paimon/prompt.py +0 -0
  49. {paimon-0.2.7 → paimon-0.2.8}/paimon/retry.py +0 -0
  50. {paimon-0.2.7 → paimon-0.2.8}/paimon/session.py +0 -0
  51. {paimon-0.2.7 → paimon-0.2.8}/paimon/skills.py +0 -0
  52. {paimon-0.2.7 → paimon-0.2.8}/paimon/turns.py +0 -0
  53. {paimon-0.2.7 → paimon-0.2.8}/paimon/websearch.py +0 -0
  54. {paimon-0.2.7 → paimon-0.2.8}/paimon.egg-info/dependency_links.txt +0 -0
  55. {paimon-0.2.7 → paimon-0.2.8}/paimon.egg-info/entry_points.txt +0 -0
  56. {paimon-0.2.7 → paimon-0.2.8}/paimon.egg-info/top_level.txt +0 -0
  57. {paimon-0.2.7 → paimon-0.2.8}/setup.cfg +0 -0
@@ -1,15 +1,18 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paimon
3
- Version: 0.2.7
3
+ Version: 0.2.8
4
4
  Summary: A minimal code agent built on pydantic-ai + textual
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
7
7
  License-File: LICENSE
8
8
  Requires-Dist: httpx>=0.27
9
- Requires-Dist: pydantic-ai-slim[anthropic,openai]>=2.38.0
9
+ Requires-Dist: genai-prices>=0.1.6
10
+ Requires-Dist: pydantic-ai-slim[anthropic,google,openai]>=2.54.0
10
11
  Requires-Dist: textual>=8.2.7
11
12
  Requires-Dist: textual-serve>=1.1.3
12
13
  Requires-Dist: pyyaml>=6
14
+ Requires-Dist: pydantic>=2.10
15
+ Requires-Dist: typing-extensions>=4.12
13
16
  Requires-Dist: ddgs>=9
14
17
  Dynamic: license-file
15
18
 
@@ -39,11 +42,11 @@ Or run it without installing anything:
39
42
  uvx paimon
40
43
  ```
41
44
 
42
- The first launch asks for a provider, model, API base and key. Then just type what you want done. Write `@path/to/file` in a prompt to hand a file to the agent.
45
+ The first launch asks for a provider, its API base and key, then a model. Then just type what you want done. Write `@path/to/file` in a prompt to hand a file to the agent.
43
46
 
44
- While it runs: `Shift+Tab` switches how much the agent may do on its own (**read** asks before writing files or running commands, **edit** lets edits inside the working directory through, **yolo** never asks and is the default), `Esc` interrupts the current turn, `Ctrl+P` opens the command palette, `Ctrl+C` quits. A line starting with `!` runs in a shell instead of being sent, and Paimon sees what it printed. `!!` keeps it to yourself.
47
+ While it runs: `Shift+Tab` switches how much the agent may do on its own (**read** only reads, **auto** edits inside the working directory and has a second model call approve everything else, **yolo** checks nothing and is the default), `Esc` interrupts the current turn, `Ctrl+P` opens the command palette, `Ctrl+C` quits. A line starting with `!` runs in a shell instead of being sent, and Paimon sees what it printed. `!!` keeps it to yourself.
45
48
 
46
- `Ctrl+T` opens another session in a pane of its own, `Ctrl+W` closes one, `Ctrl+PageUp` and `Ctrl+PageDown` move between them, and `Ctrl+G` jumps to a pane waiting for permission. Paimon can work in parallel: ask for two independent things and it starts a second agent in the background, whose answer comes back into the conversation when it is done. It can also leave a command running in a tab of its own, a dev server or a watcher, instead of holding up a turn.
49
+ `Ctrl+T` opens another session in a pane of its own, `Ctrl+W` closes one, `Ctrl+PageUp` and `Ctrl+PageDown` move between them, and `Ctrl+G` jumps to a pane waiting for permission. Paimon can work in parallel: ask for two independent things and it starts a second agent in a tab of its own, where you can watch it work and answer what it asks, and whose answer comes back into the conversation when it is done. Closing the tab stops it. It can also leave a command running in a tab, a dev server or a watcher, instead of holding up a turn.
47
50
 
48
51
  ## Web search
49
52
 
@@ -55,11 +58,11 @@ Paimon loads [Agent Skills](https://agentskills.io) from `~/.config/paimon/skill
55
58
 
56
59
  ## Using Paimon as a subagent
57
60
 
58
- Frontier models are good at planning and reviewing; the steps in between are often mechanical. Point Paimon at a cheaper model and let Claude Code or Codex write the plan and check the result. A profile keeps that model's account separate:
61
+ Frontier models are good at planning and reviewing; the steps in between are often mechanical. Point Paimon at a cheaper model and let Claude Code or Codex write the plan and check the result. Log in to that model's provider once, then name the model on each run:
59
62
 
60
63
  ```bash
61
- paimon login --profile glm --model zai:glm-4.7 --api-key-env ZAI_API_KEY
62
- paimon --profile glm -p "apply the plan in PLAN.md" --mode edit --output-format result
64
+ paimon login zai --api-key-env ZAI_API_KEY
65
+ paimon --model zai:glm-4.7 -p "apply the plan in PLAN.md" --mode auto --output-format result
63
66
  ```
64
67
 
65
68
  The bundled skill teaches the calling agent this workflow:
@@ -80,7 +83,7 @@ import asyncio
80
83
  from paimon.agent import Agent, TextDelta
81
84
 
82
85
  async def main():
83
- agent = Agent.open(mode="edit")
86
+ agent = Agent.open(mode="auto")
84
87
  async for event in agent.run("summarize the tests in this directory"):
85
88
  if isinstance(event, TextDelta):
86
89
  print(event.text, end="", flush=True)
@@ -88,7 +91,7 @@ async def main():
88
91
  asyncio.run(main())
89
92
  ```
90
93
 
91
- `Agent.open()` also takes a working directory, an async `confirm` callback for permission prompts, and a `toolset` to hand the model fewer tools or tools of your own. An agent holds its session until it goes away; to give it back at a definite moment, call `close()` or use the agent as a context manager. It writes the same session files as the CLI, so a run started in code can be resumed later with `paimon -r`.
94
+ `Agent.open()` also takes a working directory, an async `confirm` callback for the permission prompts that are left, and a `toolset` to hand the model fewer tools or tools of your own. An agent holds its session until it goes away; to give it back at a definite moment, call `close()` or use the agent as a context manager. It writes the same session files as the CLI, so a run started in code can be resumed later with `paimon -r`.
92
95
 
93
96
  ## Sessions
94
97
 
@@ -106,43 +109,55 @@ paimon log a1b2c3 # what a session did, one line per event
106
109
 
107
110
  ```bash
108
111
  paimon --mode read # start in a more cautious permission mode (yolo is the default)
109
- paimon --strict # ask before every command, even read-only ones
112
+ paimon --strict # hold every command, even read-only ones
110
113
  paimon --no-web-search # take the web search tool away for this run
111
114
  paimon --web # the same UI in a browser (--port, default 8000)
112
115
  paimon -p "what does cli.py do?" # one answer on stdout, no UI
113
116
  cat log.txt | paimon -p "summarize this"
114
117
  paimon --model zai:glm-4.7 # this model for this run only
115
- paimon --profile work # a separately configured account
116
118
  ```
117
119
 
118
120
  `-p` never stops to ask, so with the default `yolo` mode it can already write files and run commands. Add `--output-format result` for a single JSON object with the outcome, which is what a calling program should read. `paimon --help` lists the rest.
119
121
 
120
122
  Inside a [Herdr](https://herdr.dev) pane the UI reports its state and resume command to Herdr on its own, with nothing to install.
121
123
 
124
+ ### Debugging the Textual UI
125
+
126
+ Start with `paimon --textual-debug` (also works with `--web`) when Paimon needs to diagnose its own layout or styling. It is off by default. When enabled, the model receives five tools scoped to the live UI process:
127
+
128
+ - `textual_inspect` queries the DOM by CSS selector and reports geometry, pseudo-classes, focus and computed CSS;
129
+ - `textual_eval` / `textual_exec` run Python in the UI process, including private APIs, persistent variables and top-level `await`;
130
+ - `textual_apply_css` layers on CSS and relayouts immediately;
131
+ - `textual_screenshot` exports the current render to SVG.
132
+
133
+ You can ask it, for example, to “find why `#prompt` is narrower than expected, try a live fix, and take a screenshot.” `textual_exec` deliberately provides unrestricted in-process Python and can change any Textual or Paimon state. Use this development option only with trusted prompts. Live changes last only until exit; after confirming a fix, ask Paimon to edit the source.
134
+
122
135
  ## Configuration
123
136
 
124
- Each profile keeps its model settings in `~/.config/paimon/<name>/config.json`, written by the first launch or by `paimon login`. Sessions live in `~/.local/share/paimon/sessions/`.
137
+ Model settings are kept in `~/.config/paimon/config.json`, written by the first launch or by `paimon login`. Each provider keeps its own credentials, and `paimon model provider:name` or Switch model in the command palette picks the model to run on. A ChatGPT plan works in place of an API key: `paimon login chatgpt` signs in through the browser. `paimon login antigravity` does the same for an Antigravity plan, which Google does not support outside Antigravity: Paimon signs in as the Antigravity client and calls an internal endpoint, so the account may be limited or closed, and the risk is yours. Sessions live in `~/.local/share/paimon/sessions/`.
125
138
 
126
- Read and edit modes run a small set of clearly read-only commands (`ls`, `cat`, `git status`, …) without asking; `--strict` turns that off. On Windows, where cmd.exe runs the commands, every command asks. **This is a guardrail against agent mistakes, not a security boundary.** For real isolation, run Paimon inside a container or VM.
139
+ Read and auto modes run a small set of clearly read-only commands (`ls`, `cat`, `git status`, …) on their own; `--strict` turns that off, and on Windows, where cmd.exe runs the commands, none are recognized. Read mode refuses everything else. Auto mode asks a reviewer model, which sees your messages and the agent's tool calls but not its reasoning or any tool output, and answers allow or block. It asks you instead when the reviewer cannot be reached or has blocked three calls in a row, and under `-p` those are refusals. Current models review with their provider's fast tier by default (GPT with Luna, Claude with Haiku, GLM with Flash) and the rest review with themselves; set `"review_model": "provider:name"` in the config to choose. **All of this is a guardrail against agent mistakes, not a security boundary.** For real isolation, run Paimon inside a container or VM.
127
140
 
128
141
  ## Architecture
129
142
 
130
- `Agent.run` is a UI-agnostic stream of events; the TUI, `--web` and headless mode are three renderers over that one stream. An agent holds the subagents and background commands it starts. A subagent is another `Agent` running as a task in the same process, and its answer is delivered to its parent as a message.
143
+ `Agent.run` is a UI-agnostic stream of events; the TUI, `--web` and headless mode are three renderers over that one stream. An agent holds the subagents and background commands it starts. A subagent is another `Agent` running as a task in the same process, and its answer is delivered to its parent as a message. A UI that wants to show a job hooks `Agent.open_job`, which is how the TUI gives each one a pane.
131
144
 
132
145
  ```mermaid
133
146
  flowchart TD
134
147
  subgraph entry["Entry points"]
135
148
  CLI["cli.py"]
136
- Commands["commands.py<br/>status / login / sessions"]
149
+ Commands["commands.py<br/>status / login / model / sessions"]
137
150
  Headless["headless.py<br/>-p, one-shot"]
138
151
  App["app.py<br/>Textual TUI / --web"]
139
152
  end
140
153
 
141
154
  subgraph tui["TUI widgets"]
142
155
  Pane["pane.py<br/>SessionPane"]
156
+ AgentPane["agentpane.py<br/>subagent pane"]
143
157
  CommandPane["commandpane.py<br/>background command pane"]
158
+ Transcript["transcript.py<br/>conversation log, event renderer"]
144
159
  Tabs["tabs.py<br/>pane strip"]
145
- Login["login.py<br/>provider / model / key"]
160
+ Login["login.py<br/>provider / key"]
146
161
  UIWidgets["ui.py<br/>prompt input, confirmations"]
147
162
  Diff["diff.py<br/>side-by-side diff rendering"]
148
163
  end
@@ -154,14 +169,13 @@ flowchart TD
154
169
  ToolsMod["tools.py<br/>tool REGISTRY"]
155
170
  SessionMod["session.py<br/>JSONL persistence"]
156
171
  Compaction["compaction.py"]
157
- ModelWindows["model_windows.py<br/>context window sizes"]
158
172
  Retry["retry.py"]
159
173
  Mentions["mentions.py<br/>@path expansion"]
160
174
  Jobs["turns.py<br/>turn driver"]
161
175
  end
162
176
 
163
177
  subgraph support["Config & skills"]
164
- Config["config.py<br/>profiles, credentials"]
178
+ Config["config.py<br/>settings, credentials"]
165
179
  Skills["skills.py<br/>Agent Skills discovery"]
166
180
  end
167
181
 
@@ -174,6 +188,7 @@ flowchart TD
174
188
  Headless --> Mentions
175
189
 
176
190
  App --> Pane
191
+ App --> AgentPane
177
192
  App --> CommandPane
178
193
  App --> Tabs
179
194
  App --> Login
@@ -182,9 +197,13 @@ flowchart TD
182
197
  Pane --> Jobs
183
198
  Pane --> AgentLoop
184
199
  Pane --> Diff
200
+ Pane --> Transcript
185
201
  Pane --> UIWidgets
186
202
  Pane --> LLM
203
+ AgentPane --> Pane
204
+ AgentPane --> Transcript
187
205
  CommandPane --> Pane
206
+ Transcript --> UIWidgets
188
207
  UIWidgets --> Diff
189
208
 
190
209
  AgentLoop --> LLM
@@ -195,10 +214,10 @@ flowchart TD
195
214
  AgentLoop --> Retry
196
215
  AgentLoop --> Mentions
197
216
  AgentLoop -. "spawn_agent" .-> AgentLoop
217
+ AgentLoop -. "spawn_agent" .-> AgentPane
198
218
  AgentLoop -. "run_background" .-> CommandPane
199
219
 
200
220
  PromptMod --> Skills
201
- Compaction --> ModelWindows
202
221
 
203
222
  Jobs --> AgentLoop
204
223
 
@@ -24,11 +24,11 @@ Or run it without installing anything:
24
24
  uvx paimon
25
25
  ```
26
26
 
27
- The first launch asks for a provider, model, API base and key. Then just type what you want done. Write `@path/to/file` in a prompt to hand a file to the agent.
27
+ The first launch asks for a provider, its API base and key, then a model. Then just type what you want done. Write `@path/to/file` in a prompt to hand a file to the agent.
28
28
 
29
- While it runs: `Shift+Tab` switches how much the agent may do on its own (**read** asks before writing files or running commands, **edit** lets edits inside the working directory through, **yolo** never asks and is the default), `Esc` interrupts the current turn, `Ctrl+P` opens the command palette, `Ctrl+C` quits. A line starting with `!` runs in a shell instead of being sent, and Paimon sees what it printed. `!!` keeps it to yourself.
29
+ While it runs: `Shift+Tab` switches how much the agent may do on its own (**read** only reads, **auto** edits inside the working directory and has a second model call approve everything else, **yolo** checks nothing and is the default), `Esc` interrupts the current turn, `Ctrl+P` opens the command palette, `Ctrl+C` quits. A line starting with `!` runs in a shell instead of being sent, and Paimon sees what it printed. `!!` keeps it to yourself.
30
30
 
31
- `Ctrl+T` opens another session in a pane of its own, `Ctrl+W` closes one, `Ctrl+PageUp` and `Ctrl+PageDown` move between them, and `Ctrl+G` jumps to a pane waiting for permission. Paimon can work in parallel: ask for two independent things and it starts a second agent in the background, whose answer comes back into the conversation when it is done. It can also leave a command running in a tab of its own, a dev server or a watcher, instead of holding up a turn.
31
+ `Ctrl+T` opens another session in a pane of its own, `Ctrl+W` closes one, `Ctrl+PageUp` and `Ctrl+PageDown` move between them, and `Ctrl+G` jumps to a pane waiting for permission. Paimon can work in parallel: ask for two independent things and it starts a second agent in a tab of its own, where you can watch it work and answer what it asks, and whose answer comes back into the conversation when it is done. Closing the tab stops it. It can also leave a command running in a tab, a dev server or a watcher, instead of holding up a turn.
32
32
 
33
33
  ## Web search
34
34
 
@@ -40,11 +40,11 @@ Paimon loads [Agent Skills](https://agentskills.io) from `~/.config/paimon/skill
40
40
 
41
41
  ## Using Paimon as a subagent
42
42
 
43
- Frontier models are good at planning and reviewing; the steps in between are often mechanical. Point Paimon at a cheaper model and let Claude Code or Codex write the plan and check the result. A profile keeps that model's account separate:
43
+ Frontier models are good at planning and reviewing; the steps in between are often mechanical. Point Paimon at a cheaper model and let Claude Code or Codex write the plan and check the result. Log in to that model's provider once, then name the model on each run:
44
44
 
45
45
  ```bash
46
- paimon login --profile glm --model zai:glm-4.7 --api-key-env ZAI_API_KEY
47
- paimon --profile glm -p "apply the plan in PLAN.md" --mode edit --output-format result
46
+ paimon login zai --api-key-env ZAI_API_KEY
47
+ paimon --model zai:glm-4.7 -p "apply the plan in PLAN.md" --mode auto --output-format result
48
48
  ```
49
49
 
50
50
  The bundled skill teaches the calling agent this workflow:
@@ -65,7 +65,7 @@ import asyncio
65
65
  from paimon.agent import Agent, TextDelta
66
66
 
67
67
  async def main():
68
- agent = Agent.open(mode="edit")
68
+ agent = Agent.open(mode="auto")
69
69
  async for event in agent.run("summarize the tests in this directory"):
70
70
  if isinstance(event, TextDelta):
71
71
  print(event.text, end="", flush=True)
@@ -73,7 +73,7 @@ async def main():
73
73
  asyncio.run(main())
74
74
  ```
75
75
 
76
- `Agent.open()` also takes a working directory, an async `confirm` callback for permission prompts, and a `toolset` to hand the model fewer tools or tools of your own. An agent holds its session until it goes away; to give it back at a definite moment, call `close()` or use the agent as a context manager. It writes the same session files as the CLI, so a run started in code can be resumed later with `paimon -r`.
76
+ `Agent.open()` also takes a working directory, an async `confirm` callback for the permission prompts that are left, and a `toolset` to hand the model fewer tools or tools of your own. An agent holds its session until it goes away; to give it back at a definite moment, call `close()` or use the agent as a context manager. It writes the same session files as the CLI, so a run started in code can be resumed later with `paimon -r`.
77
77
 
78
78
  ## Sessions
79
79
 
@@ -91,43 +91,55 @@ paimon log a1b2c3 # what a session did, one line per event
91
91
 
92
92
  ```bash
93
93
  paimon --mode read # start in a more cautious permission mode (yolo is the default)
94
- paimon --strict # ask before every command, even read-only ones
94
+ paimon --strict # hold every command, even read-only ones
95
95
  paimon --no-web-search # take the web search tool away for this run
96
96
  paimon --web # the same UI in a browser (--port, default 8000)
97
97
  paimon -p "what does cli.py do?" # one answer on stdout, no UI
98
98
  cat log.txt | paimon -p "summarize this"
99
99
  paimon --model zai:glm-4.7 # this model for this run only
100
- paimon --profile work # a separately configured account
101
100
  ```
102
101
 
103
102
  `-p` never stops to ask, so with the default `yolo` mode it can already write files and run commands. Add `--output-format result` for a single JSON object with the outcome, which is what a calling program should read. `paimon --help` lists the rest.
104
103
 
105
104
  Inside a [Herdr](https://herdr.dev) pane the UI reports its state and resume command to Herdr on its own, with nothing to install.
106
105
 
106
+ ### Debugging the Textual UI
107
+
108
+ Start with `paimon --textual-debug` (also works with `--web`) when Paimon needs to diagnose its own layout or styling. It is off by default. When enabled, the model receives five tools scoped to the live UI process:
109
+
110
+ - `textual_inspect` queries the DOM by CSS selector and reports geometry, pseudo-classes, focus and computed CSS;
111
+ - `textual_eval` / `textual_exec` run Python in the UI process, including private APIs, persistent variables and top-level `await`;
112
+ - `textual_apply_css` layers on CSS and relayouts immediately;
113
+ - `textual_screenshot` exports the current render to SVG.
114
+
115
+ You can ask it, for example, to “find why `#prompt` is narrower than expected, try a live fix, and take a screenshot.” `textual_exec` deliberately provides unrestricted in-process Python and can change any Textual or Paimon state. Use this development option only with trusted prompts. Live changes last only until exit; after confirming a fix, ask Paimon to edit the source.
116
+
107
117
  ## Configuration
108
118
 
109
- Each profile keeps its model settings in `~/.config/paimon/<name>/config.json`, written by the first launch or by `paimon login`. Sessions live in `~/.local/share/paimon/sessions/`.
119
+ Model settings are kept in `~/.config/paimon/config.json`, written by the first launch or by `paimon login`. Each provider keeps its own credentials, and `paimon model provider:name` or Switch model in the command palette picks the model to run on. A ChatGPT plan works in place of an API key: `paimon login chatgpt` signs in through the browser. `paimon login antigravity` does the same for an Antigravity plan, which Google does not support outside Antigravity: Paimon signs in as the Antigravity client and calls an internal endpoint, so the account may be limited or closed, and the risk is yours. Sessions live in `~/.local/share/paimon/sessions/`.
110
120
 
111
- Read and edit modes run a small set of clearly read-only commands (`ls`, `cat`, `git status`, …) without asking; `--strict` turns that off. On Windows, where cmd.exe runs the commands, every command asks. **This is a guardrail against agent mistakes, not a security boundary.** For real isolation, run Paimon inside a container or VM.
121
+ Read and auto modes run a small set of clearly read-only commands (`ls`, `cat`, `git status`, …) on their own; `--strict` turns that off, and on Windows, where cmd.exe runs the commands, none are recognized. Read mode refuses everything else. Auto mode asks a reviewer model, which sees your messages and the agent's tool calls but not its reasoning or any tool output, and answers allow or block. It asks you instead when the reviewer cannot be reached or has blocked three calls in a row, and under `-p` those are refusals. Current models review with their provider's fast tier by default (GPT with Luna, Claude with Haiku, GLM with Flash) and the rest review with themselves; set `"review_model": "provider:name"` in the config to choose. **All of this is a guardrail against agent mistakes, not a security boundary.** For real isolation, run Paimon inside a container or VM.
112
122
 
113
123
  ## Architecture
114
124
 
115
- `Agent.run` is a UI-agnostic stream of events; the TUI, `--web` and headless mode are three renderers over that one stream. An agent holds the subagents and background commands it starts. A subagent is another `Agent` running as a task in the same process, and its answer is delivered to its parent as a message.
125
+ `Agent.run` is a UI-agnostic stream of events; the TUI, `--web` and headless mode are three renderers over that one stream. An agent holds the subagents and background commands it starts. A subagent is another `Agent` running as a task in the same process, and its answer is delivered to its parent as a message. A UI that wants to show a job hooks `Agent.open_job`, which is how the TUI gives each one a pane.
116
126
 
117
127
  ```mermaid
118
128
  flowchart TD
119
129
  subgraph entry["Entry points"]
120
130
  CLI["cli.py"]
121
- Commands["commands.py<br/>status / login / sessions"]
131
+ Commands["commands.py<br/>status / login / model / sessions"]
122
132
  Headless["headless.py<br/>-p, one-shot"]
123
133
  App["app.py<br/>Textual TUI / --web"]
124
134
  end
125
135
 
126
136
  subgraph tui["TUI widgets"]
127
137
  Pane["pane.py<br/>SessionPane"]
138
+ AgentPane["agentpane.py<br/>subagent pane"]
128
139
  CommandPane["commandpane.py<br/>background command pane"]
140
+ Transcript["transcript.py<br/>conversation log, event renderer"]
129
141
  Tabs["tabs.py<br/>pane strip"]
130
- Login["login.py<br/>provider / model / key"]
142
+ Login["login.py<br/>provider / key"]
131
143
  UIWidgets["ui.py<br/>prompt input, confirmations"]
132
144
  Diff["diff.py<br/>side-by-side diff rendering"]
133
145
  end
@@ -139,14 +151,13 @@ flowchart TD
139
151
  ToolsMod["tools.py<br/>tool REGISTRY"]
140
152
  SessionMod["session.py<br/>JSONL persistence"]
141
153
  Compaction["compaction.py"]
142
- ModelWindows["model_windows.py<br/>context window sizes"]
143
154
  Retry["retry.py"]
144
155
  Mentions["mentions.py<br/>@path expansion"]
145
156
  Jobs["turns.py<br/>turn driver"]
146
157
  end
147
158
 
148
159
  subgraph support["Config & skills"]
149
- Config["config.py<br/>profiles, credentials"]
160
+ Config["config.py<br/>settings, credentials"]
150
161
  Skills["skills.py<br/>Agent Skills discovery"]
151
162
  end
152
163
 
@@ -159,6 +170,7 @@ flowchart TD
159
170
  Headless --> Mentions
160
171
 
161
172
  App --> Pane
173
+ App --> AgentPane
162
174
  App --> CommandPane
163
175
  App --> Tabs
164
176
  App --> Login
@@ -167,9 +179,13 @@ flowchart TD
167
179
  Pane --> Jobs
168
180
  Pane --> AgentLoop
169
181
  Pane --> Diff
182
+ Pane --> Transcript
170
183
  Pane --> UIWidgets
171
184
  Pane --> LLM
185
+ AgentPane --> Pane
186
+ AgentPane --> Transcript
172
187
  CommandPane --> Pane
188
+ Transcript --> UIWidgets
173
189
  UIWidgets --> Diff
174
190
 
175
191
  AgentLoop --> LLM
@@ -180,10 +196,10 @@ flowchart TD
180
196
  AgentLoop --> Retry
181
197
  AgentLoop --> Mentions
182
198
  AgentLoop -. "spawn_agent" .-> AgentLoop
199
+ AgentLoop -. "spawn_agent" .-> AgentPane
183
200
  AgentLoop -. "run_background" .-> CommandPane
184
201
 
185
202
  PromptMod --> Skills
186
- Compaction --> ModelWindows
187
203
 
188
204
  Jobs --> AgentLoop
189
205
 
@@ -24,11 +24,11 @@ paimon
24
24
  uvx paimon
25
25
  ```
26
26
 
27
- 首次启动会询问 provider、模型、API base 和 key。之后输入要完成的任务即可。在提示中写 `@path/to/file` 可以把文件提供给 agent。
27
+ 首次启动会询问 provider 及其 API base 和 key,然后选择模型。之后输入要完成的任务即可。在提示中写 `@path/to/file` 可以把文件提供给 agent。
28
28
 
29
- 运行时:`Shift+Tab` 切换 agent 的自主程度(**read** 写文件或执行命令前先询问,**edit** 放行工作目录内的编辑,**yolo** 从不询问,也是默认值),`Esc` 打断当前回合,`Ctrl+P` 打开命令面板,`Ctrl+C` 退出。以 `!` 开头的一行不发给模型,而是直接在 shell 里执行,输出 Paimon 也能看到。`!!` 则不告诉它。
29
+ 运行时:`Shift+Tab` 切换 agent 的自主程度(**read** 只读,**auto** 放行工作目录内的编辑,其余操作交给另一次模型调用审批,**yolo** 不做任何检查,也是默认值),`Esc` 打断当前回合,`Ctrl+P` 打开命令面板,`Ctrl+C` 退出。以 `!` 开头的一行不发给模型,而是直接在 shell 里执行,输出 Paimon 也能看到。`!!` 则不告诉它。
30
30
 
31
- `Ctrl+T` 在新 pane 里打开另一个会话,`Ctrl+W` 关闭当前 pane,`Ctrl+PageUp` 和 `Ctrl+PageDown` 在 pane 之间切换,`Ctrl+G` 跳到正在等待授权的 pane。Paimon 也能并行干活:让它同时做两件互不相干的事,它会在后台起第二个 agent,做完后结果会回到当前会话里。它也能把一条命令留在单独的 tab 里跑,比如开发服务器或者文件监视,不占着当前回合。
31
+ `Ctrl+T` 在新 pane 里打开另一个会话,`Ctrl+W` 关闭当前 pane,`Ctrl+PageUp` 和 `Ctrl+PageDown` 在 pane 之间切换,`Ctrl+G` 跳到正在等待授权的 pane。Paimon 也能并行干活:让它同时做两件互不相干的事,它会在单独的 tab 里起第二个 agent,你可以在那里看它干活、回答它的授权请求,做完后结果会回到当前会话里,关掉 tab 就是停掉它。它也能把一条命令留在 tab 里跑,比如开发服务器或者文件监视,不占着当前回合。
32
32
 
33
33
  ## 网页搜索
34
34
 
@@ -40,11 +40,11 @@ Paimon 会从 `~/.config/paimon/skills`、`~/.agents/skills` 以及工作目录
40
40
 
41
41
  ## 当作 subagent 使用
42
42
 
43
- 前沿模型擅长制定计划和验收结果,中间的执行步骤往往比较机械。让 Paimon 使用成本较低的模型执行,由 Claude Code 或 Codex 制定计划并检查结果。用一个 profile 单独保存该模型的账号:
43
+ 前沿模型擅长制定计划和验收结果,中间的执行步骤往往比较机械。让 Paimon 使用成本较低的模型执行,由 Claude Code 或 Codex 制定计划并检查结果。先登录该模型的 provider,之后每次运行时指定模型:
44
44
 
45
45
  ```bash
46
- paimon login --profile glm --model zai:glm-4.7 --api-key-env ZAI_API_KEY
47
- paimon --profile glm -p "apply the plan in PLAN.md" --mode edit --output-format result
46
+ paimon login zai --api-key-env ZAI_API_KEY
47
+ paimon --model zai:glm-4.7 -p "apply the plan in PLAN.md" --mode auto --output-format result
48
48
  ```
49
49
 
50
50
  自带的 skill 会向调用方 agent 说明这套流程:
@@ -65,7 +65,7 @@ import asyncio
65
65
  from paimon.agent import Agent, TextDelta
66
66
 
67
67
  async def main():
68
- agent = Agent.open(mode="edit")
68
+ agent = Agent.open(mode="auto")
69
69
  async for event in agent.run("summarize the tests in this directory"):
70
70
  if isinstance(event, TextDelta):
71
71
  print(event.text, end="", flush=True)
@@ -73,7 +73,7 @@ async def main():
73
73
  asyncio.run(main())
74
74
  ```
75
75
 
76
- `Agent.open()` 还接受工作目录、用于权限确认的异步 `confirm` 回调,以及 `toolset`,可以只给模型一部分工具,或者换成你自己的工具。agent 被回收时会交还会话,想在确定的时刻交还就调 `close()`,或者把它当上下文管理器用。它写的会话文件和 CLI 一样,所以代码里跑出来的会话之后可以用 `paimon -r` 恢复。
76
+ `Agent.open()` 还接受工作目录、用于剩余权限确认的异步 `confirm` 回调,以及 `toolset`,可以只给模型一部分工具,或者换成你自己的工具。agent 被回收时会交还会话,想在确定的时刻交还就调 `close()`,或者把它当上下文管理器用。它写的会话文件和 CLI 一样,所以代码里跑出来的会话之后可以用 `paimon -r` 恢复。
77
77
 
78
78
  ## 会话
79
79
 
@@ -91,41 +91,53 @@ paimon log a1b2c3 # 查看会话做了什么,每个事件一行
91
91
 
92
92
  ```bash
93
93
  paimon --mode read # 以更谨慎的权限模式启动(默认为 yolo)
94
- paimon --strict # 每条命令都先询问,包括只读命令
94
+ paimon --strict # 不再放行只读命令
95
95
  paimon --no-web-search # 本次运行不提供网页搜索工具
96
96
  paimon --web # 在浏览器中使用同一套 UI(--port,默认 8000)
97
97
  paimon -p "what does cli.py do?" # 直接在 stdout 输出回答,不启动 UI
98
98
  cat log.txt | paimon -p "summarize this"
99
99
  paimon --model zai:glm-4.7 # 仅本次运行使用该模型
100
- paimon --profile work # 单独配置的另一个账号
101
100
  ```
102
101
 
103
102
  `-p` 不会停下来询问,配合默认的 `yolo` 模式,它已经可以修改文件和执行命令。加 `--output-format result` 会输出一个包含结果的 JSON 对象,调用方程序读这个就够了。其余选项见 `paimon --help`。
104
103
 
104
+ ### 调试 Textual UI
105
+
106
+ 需要让 Paimon 排查自己的布局或样式时,用 `paimon --textual-debug` 启动(也可与 `--web` 一起使用)。默认不启用;开启后模型会多出五个只作用于当前 UI 进程的工具:
107
+
108
+ - `textual_inspect`:按 CSS selector 查看 DOM、geometry、pseudo-classes、焦点和 computed CSS;
109
+ - `textual_eval` / `textual_exec`:在 UI 进程里运行 Python,支持 private API、持久变量和 top-level `await`;
110
+ - `textual_apply_css`:动态叠加 CSS 并立即重新布局;
111
+ - `textual_screenshot`:把当前渲染结果导出成 SVG。
112
+
113
+ 例如可以直接让它“检查 `#prompt` 为什么比预期窄,动态试一个修复并截图”。`textual_exec` 有意提供完整的进程内 Python 能力,能修改任意 Textual/Paimon 状态;这个选项只适合开发调试,不应对不受信任的 prompt 开启。动态修改只保留到进程退出,确定修复后仍需让 Paimon编辑源码。
114
+
105
115
  ## 配置
106
116
 
107
- 每个 profile 的模型设置保存在 `~/.config/paimon/<name>/config.json`,由首次启动或 `paimon login` 写入。会话存放在 `~/.local/share/paimon/sessions/`。
117
+ 模型设置保存在 `~/.config/paimon/config.json`,由首次启动或 `paimon login` 写入。每个 provider 各自保存凭据,用 `paimon model provider:name` 或命令面板里的 Switch model 选择要用的模型。也可以用 ChatGPT 订阅代替 API key,`paimon login chatgpt` 会通过浏览器登录。会话存放在 `~/.local/share/paimon/sessions/`。
108
118
 
109
- read 和 edit 模式会不经询问执行一小组明确只读的命令(`ls`、`cat`、`git status` 等),`--strict` 可以关掉。Windows 上命令由 cmd.exe 执行,每条命令都会询问。**这是防止 agent 失误的护栏,不是安全边界。** 需要真正的隔离时,请在容器或虚拟机中运行 Paimon。
119
+ read 和 auto 模式会直接执行一小组明确只读的命令(`ls`、`cat`、`git status` 等),`--strict` 可以关掉,Windows 上命令由 cmd.exe 执行,一条也不识别。read 模式拒绝其余所有操作。auto 模式把它们交给审批模型,它能看到你的消息和 agent 的工具调用,看不到 agent 的推理和工具输出,只回答放行或拦截。审批模型不可用或者连续拦截三次时改为询问你,`-p` 下则直接拒绝。当前的模型默认用同一家里快速档的那个来审批(GPT 用 Luna,Claude 用 Haiku,GLM 用 Flash),其余模型自己审自己,在配置里写 `"review_model": "provider:name"` 可以自行指定。**这些都是防止 agent 失误的护栏,不是安全边界。** 需要真正的隔离时,请在容器或虚拟机中运行 Paimon。
110
120
 
111
121
  ## 架构
112
122
 
113
- `Agent.run` 产出一串与 UI 无关的事件流,TUI、`--web` 和无头模式都是这条事件流的渲染器。agent 自己持有它启动的子 agent 和后台命令。子 agent 是同一进程里作为任务运行的另一个 `Agent`,它的结果会作为一条消息送回父 agent。
123
+ `Agent.run` 产出一串与 UI 无关的事件流,TUI、`--web` 和无头模式都是这条事件流的渲染器。agent 自己持有它启动的子 agent 和后台命令。子 agent 是同一进程里作为任务运行的另一个 `Agent`,它的结果会作为一条消息送回父 agent。想把 job 显示出来的 UI 挂上 `Agent.open_job` 即可,TUI 就是这样给每个 job 开 pane 的。
114
124
 
115
125
  ```mermaid
116
126
  flowchart TD
117
127
  subgraph entry["入口"]
118
128
  CLI["cli.py"]
119
- Commands["commands.py<br/>status / login / sessions"]
129
+ Commands["commands.py<br/>status / login / model / sessions"]
120
130
  Headless["headless.py<br/>-p,单次运行"]
121
131
  App["app.py<br/>Textual TUI / --web"]
122
132
  end
123
133
 
124
134
  subgraph tui["TUI 组件"]
125
135
  Pane["pane.py<br/>SessionPane"]
136
+ AgentPane["agentpane.py<br/>子 agent pane"]
126
137
  CommandPane["commandpane.py<br/>后台命令 pane"]
138
+ Transcript["transcript.py<br/>对话记录与事件渲染"]
127
139
  Tabs["tabs.py<br/>pane 标签栏"]
128
- Login["login.py<br/>provider / 模型 / key"]
140
+ Login["login.py<br/>provider / key"]
129
141
  UIWidgets["ui.py<br/>输入框、确认面板"]
130
142
  Diff["diff.py<br/>并排 diff 渲染"]
131
143
  end
@@ -137,14 +149,13 @@ flowchart TD
137
149
  ToolsMod["tools.py<br/>工具注册表"]
138
150
  SessionMod["session.py<br/>JSONL 持久化"]
139
151
  Compaction["compaction.py"]
140
- ModelWindows["model_windows.py<br/>各模型上下文窗口大小"]
141
152
  Retry["retry.py"]
142
153
  Mentions["mentions.py<br/>@path 展开"]
143
154
  Jobs["turns.py<br/>回合驱动"]
144
155
  end
145
156
 
146
157
  subgraph support["配置与 skills"]
147
- Config["config.py<br/>profile、凭证"]
158
+ Config["config.py<br/>设置、凭证"]
148
159
  Skills["skills.py<br/>Agent Skills 发现"]
149
160
  end
150
161
 
@@ -157,6 +168,7 @@ flowchart TD
157
168
  Headless --> Mentions
158
169
 
159
170
  App --> Pane
171
+ App --> AgentPane
160
172
  App --> CommandPane
161
173
  App --> Tabs
162
174
  App --> Login
@@ -165,9 +177,13 @@ flowchart TD
165
177
  Pane --> Jobs
166
178
  Pane --> AgentLoop
167
179
  Pane --> Diff
180
+ Pane --> Transcript
168
181
  Pane --> UIWidgets
169
182
  Pane --> LLM
183
+ AgentPane --> Pane
184
+ AgentPane --> Transcript
170
185
  CommandPane --> Pane
186
+ Transcript --> UIWidgets
171
187
  UIWidgets --> Diff
172
188
 
173
189
  AgentLoop --> LLM
@@ -178,10 +194,10 @@ flowchart TD
178
194
  AgentLoop --> Retry
179
195
  AgentLoop --> Mentions
180
196
  AgentLoop -. "spawn_agent" .-> AgentLoop
197
+ AgentLoop -. "spawn_agent" .-> AgentPane
181
198
  AgentLoop -. "run_background" .-> CommandPane
182
199
 
183
200
  PromptMod --> Skills
184
- Compaction --> ModelWindows
185
201
 
186
202
  Jobs --> AgentLoop
187
203