pcode 0.1.7__tar.gz → 0.1.9__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 (192) hide show
  1. {pcode-0.1.7 → pcode-0.1.9}/PKG-INFO +9 -6
  2. {pcode-0.1.7 → pcode-0.1.9}/README.md +5 -2
  3. {pcode-0.1.7 → pcode-0.1.9}/pyproject.toml +3 -3
  4. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/agent.py +21 -36
  5. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/app.py +454 -98
  6. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/aside.py +38 -4
  7. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/aside_ui.py +154 -64
  8. pcode-0.1.9/src/pcode/auth.py +17 -0
  9. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/background_delegation.py +1 -1
  10. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/browser.py +324 -3
  11. pcode-0.1.9/src/pcode/btw_view.py +211 -0
  12. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/cache_settings.py +1 -2
  13. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/cache_warnings.py +2 -2
  14. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/__init__.py +2 -3
  15. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/errors.py +1 -1
  16. pcode-0.1.9/src/pcode/claude_sdk/login.py +114 -0
  17. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/model.py +1 -2
  18. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/clipboard.py +48 -1
  19. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/compaction.py +6 -39
  20. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/config.py +11 -12
  21. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/controller.py +367 -153
  22. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/conversation_ids.py +6 -5
  23. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/conversation_tree.py +47 -11
  24. pcode-0.1.9/src/pcode/copy_ui.py +296 -0
  25. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/edits.py +4 -2
  26. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/extensions/browser.py +104 -5
  27. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/extensions/plan_mode.py +52 -77
  28. pcode-0.1.9/src/pcode/extensions/reflect.py +364 -0
  29. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/extensions/sandbox.py +12 -5
  30. pcode-0.1.9/src/pcode/extensions/session_history.py +179 -0
  31. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/file_refs.py +2 -1
  32. pcode-0.1.9/src/pcode/filesystem.py +289 -0
  33. pcode-0.1.9/src/pcode/glyphs.py +202 -0
  34. pcode-0.1.9/src/pcode/history.py +705 -0
  35. pcode-0.1.9/src/pcode/history_index.py +331 -0
  36. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/host.py +37 -7
  37. pcode-0.1.9/src/pcode/images.py +257 -0
  38. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/inspection.py +18 -6
  39. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/keymap.py +9 -3
  40. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/live.py +233 -45
  41. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/logins.py +7 -109
  42. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/mcp_notice.py +1 -1
  43. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/mcp_oauth.py +1 -1
  44. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/model_metadata.py +51 -38
  45. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/models.py +4 -32
  46. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/native_results.py +3 -3
  47. pcode-0.1.9/src/pcode/obsidian_plans.py +213 -0
  48. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/output_limits.py +1 -1
  49. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/popup_ui.py +69 -7
  50. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/preferences.py +83 -44
  51. pcode-0.1.9/src/pcode/prompt_images.py +179 -0
  52. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/prompt_keys.py +181 -14
  53. pcode-0.1.9/src/pcode/reminders.py +48 -0
  54. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/remote.py +9 -9
  55. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/remote_profile.py +0 -5
  56. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/replay_benchmark.py +13 -0
  57. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/retries.py +5 -1
  58. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/session_naming.py +18 -3
  59. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/session_ui.py +63 -3
  60. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/sessions.py +46 -30
  61. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/stall_log.py +8 -3
  62. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/startup_input.py +40 -7
  63. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/steering.py +27 -8
  64. pcode-0.1.9/src/pcode/terminal_color.py +122 -0
  65. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/theme.py +88 -15
  66. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/tool_display.py +34 -3
  67. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/tool_output_limits.py +36 -5
  68. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/tool_panel.py +1 -1
  69. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/tree_ui.py +218 -57
  70. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/turn.py +3 -0
  71. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/ui.py +863 -194
  72. pcode-0.1.9/src/pcode/usage.py +213 -0
  73. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/word_wrap.py +76 -4
  74. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/workspace_filesystem.py +2 -0
  75. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/worktree.py +43 -4
  76. pcode-0.1.7/src/pcode/anthropic_oauth.py +0 -469
  77. pcode-0.1.7/src/pcode/auth.py +0 -113
  78. pcode-0.1.7/src/pcode/copy_ui.py +0 -394
  79. pcode-0.1.7/src/pcode/extensions/basic_memory/Brief format.md +0 -91
  80. pcode-0.1.7/src/pcode/extensions/basic_memory/Briefs.base +0 -50
  81. pcode-0.1.7/src/pcode/extensions/basic_memory/Home.md +0 -11
  82. pcode-0.1.7/src/pcode/extensions/basic_memory/__init__.py +0 -731
  83. pcode-0.1.7/src/pcode/extensions/basic_memory/memory-states.css +0 -58
  84. pcode-0.1.7/src/pcode/extensions/session_history.py +0 -170
  85. pcode-0.1.7/src/pcode/filesystem.py +0 -131
  86. pcode-0.1.7/src/pcode/history.py +0 -589
  87. pcode-0.1.7/src/pcode/history_cursor.py +0 -147
  88. pcode-0.1.7/src/pcode/meridian.py +0 -233
  89. pcode-0.1.7/src/pcode/meridian_process.py +0 -337
  90. pcode-0.1.7/src/pcode/meridian_reminders.py +0 -120
  91. pcode-0.1.7/src/pcode/meridian_setup.py +0 -356
  92. pcode-0.1.7/src/pcode/oauth_pages.py +0 -66
  93. pcode-0.1.7/src/pcode/usage.py +0 -293
  94. {pcode-0.1.7 → pcode-0.1.9}/.gitignore +0 -0
  95. {pcode-0.1.7 → pcode-0.1.9}/LICENSE +0 -0
  96. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/__init__.py +0 -0
  97. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/_job_supervisor.py +0 -0
  98. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/appearance.py +0 -0
  99. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/aside_guard.py +0 -0
  100. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/block.py +0 -0
  101. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/cache_diagnostics.py +0 -0
  102. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/cli.py +0 -0
  103. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/messages.py +0 -0
  104. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/resume.py +0 -0
  105. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/session.py +0 -0
  106. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/session_pool.py +0 -0
  107. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/web.py +0 -0
  108. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/workspace.py +0 -0
  109. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/cli.py +0 -0
  110. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/code_mode.py +0 -0
  111. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/codex_login.py +0 -0
  112. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/command_transcript.py +0 -0
  113. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/commands.py +0 -0
  114. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/completion.py +0 -0
  115. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/config_ui.py +0 -0
  116. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/context_breakdown.py +0 -0
  117. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/context_usage.py +0 -0
  118. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/delegation.py +0 -0
  119. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/delta.py +0 -0
  120. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/diagnostics.py +0 -0
  121. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/edit_preview.py +0 -0
  122. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/edit_transcript.py +0 -0
  123. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/edit_ui.py +0 -0
  124. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/__init__.py +0 -0
  125. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/cli.py +0 -0
  126. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/listener.py +0 -0
  127. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/mailbox.py +0 -0
  128. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/outbound.py +0 -0
  129. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/parsing.py +0 -0
  130. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/render.py +0 -0
  131. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/state.py +0 -0
  132. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/error_report.py +0 -0
  133. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/ext.py +0 -0
  134. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/extension_guide.md +0 -0
  135. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/extensions/ponytail.py +0 -0
  136. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/extensions/web_research.py +0 -0
  137. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/frame.py +0 -0
  138. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/gateway.py +0 -0
  139. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/git_diff.py +0 -0
  140. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/history_embeddings.py +0 -0
  141. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/host_protocol.py +0 -0
  142. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/host_ui.py +0 -0
  143. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/input_keys.py +0 -0
  144. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/inspector_ui.py +0 -0
  145. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/isolated_delegation.py +0 -0
  146. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/job_notices.py +0 -0
  147. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/jobs.py +0 -0
  148. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/jobs_ui.py +0 -0
  149. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/keyboard_protocol.py +0 -0
  150. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/layout_speed.py +0 -0
  151. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/links.py +0 -0
  152. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/links_ui.py +0 -0
  153. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/llm_proxy.py +0 -0
  154. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/mcp.py +0 -0
  155. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/model_ui.py +0 -0
  156. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/path_completion.py +0 -0
  157. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/plan_preview.py +0 -0
  158. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/plan_sizes.py +0 -0
  159. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/planning.py +0 -0
  160. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/prefix_keys.py +0 -0
  161. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/proctitle.py +0 -0
  162. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/profile_benchmark.py +0 -0
  163. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/profiling.py +0 -0
  164. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/project_trust.py +0 -0
  165. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/remote_print.py +0 -0
  166. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/repo_context.py +0 -0
  167. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/rpc.py +0 -0
  168. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/runtime.py +0 -0
  169. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/sandbox.py +0 -0
  170. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/shell.py +0 -0
  171. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/shell_mode.py +0 -0
  172. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/shell_tools.py +0 -0
  173. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/skills.py +0 -0
  174. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/stream_display.py +0 -0
  175. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/stream_events.py +0 -0
  176. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/strict_tools.py +0 -0
  177. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/syntax.py +0 -0
  178. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/syntax_colors.py +0 -0
  179. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/task_prompt.py +0 -0
  180. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/task_worktrees.py +0 -0
  181. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/terminal_notify.py +0 -0
  182. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/terminal_text.py +0 -0
  183. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/text_selection.py +0 -0
  184. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/theme_gallery.py +0 -0
  185. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/thinking_markdown.py +0 -0
  186. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/token_accounting.py +0 -0
  187. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/transcript_log.py +0 -0
  188. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/transcript_notice.py +0 -0
  189. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/update_check.py +0 -0
  190. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/worker_ui.py +0 -0
  191. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/workers.py +0 -0
  192. {pcode-0.1.7 → pcode-0.1.9}/src/pcode/workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pcode
3
- Version: 0.1.7
3
+ Version: 0.1.9
4
4
  Summary: Terminal-native AI coding agent with background jobs, parallel worktrees, forkable sessions, and multi-model support
5
5
  Project-URL: Homepage, https://github.com/cruxwell/pcode
6
6
  Project-URL: Documentation, https://cruxwell.github.io/pcode/
@@ -25,13 +25,13 @@ Requires-Dist: genai-prices<0.2,>=0.1.7
25
25
  Requires-Dist: httpx2<3,>=2.13.1
26
26
  Requires-Dist: prompt-toolkit==3.0.53
27
27
  Requires-Dist: psutil<8,>=6
28
- Requires-Dist: pydantic-ai-harness[codemode,coder,exa,playwright]<0.56,>=0.55.0
29
- Requires-Dist: pydantic-ai-slim[anthropic,bedrock,duckduckgo,google,groq,mcp,openai,web-fetch,xai]<3,>=2.55.0
28
+ Requires-Dist: pydantic-ai-harness[codemode,coder,exa,playwright]<0.57,>=0.56.0
29
+ Requires-Dist: pydantic-ai-slim[anthropic,bedrock,duckduckgo,google,groq,mcp,openai,web-fetch,xai]<3,>=2.56.0
30
30
  Requires-Dist: rich<16,>=15
31
31
  Requires-Dist: websockets<17,>=15.0.1
32
32
  Requires-Dist: yappi<2,>=1.7.6
33
33
  Provides-Extra: claude
34
- Requires-Dist: claude-agent-sdk<0.3,>=0.2.164; extra == 'claude'
34
+ Requires-Dist: claude-agent-sdk<0.3,>=0.2.167; extra == 'claude'
35
35
  Description-Content-Type: text/markdown
36
36
 
37
37
  <img width="1392" height="1522" alt="pcode in a dark terminal" src="docs/assets/screenshots/tabs-dark.png" />
@@ -64,6 +64,8 @@ your Claude or ChatGPT subscription.
64
64
 
65
65
  **Documentation: [cruxwell.github.io/pcode](https://cruxwell.github.io/pcode/)**
66
66
 
67
+ **Tried it? [Share feedback](https://github.com/cruxwell/pcode/discussions/4)**: what worked, what didn't, and where you got stuck.
68
+
67
69
  ## Install
68
70
 
69
71
  With [Homebrew](https://brew.sh/):
@@ -76,7 +78,7 @@ brew install cruxwell/pcode/pcode
76
78
  Or from [PyPI](https://pypi.org/project/pcode/) with [uv](https://docs.astral.sh/uv/):
77
79
 
78
80
  ```sh
79
- uv tool install --python 3.14 'pcode[claude]'
81
+ uv tool install --python 3.15 'pcode[claude]'
80
82
  ```
81
83
 
82
84
  `brew install --HEAD` tracks `master` instead of the latest release.
@@ -131,7 +133,7 @@ See [PLAN.md](https://github.com/cruxwell/pcode/blob/master/PLAN.md) for the lon
131
133
  | [Configuration](https://cruxwell.github.io/pcode/configuration/) | `pcode config`, per-repository overrides, trusting repository code, the settings table, syntax styles |
132
134
  | [Commands and keys](https://cruxwell.github.io/pcode/commands/) | Slash commands, key bindings, vi mode, tmux newlines, status line, `!command`, the diff and tool inspectors |
133
135
  | [Keybindings](https://cruxwell.github.io/pcode/keybindings/) | Custom command mappings with `/bind`, Ctrl shortcuts, vi editing, a normal-mode leader, and custom escape sequences such as `jj` |
134
- | [Terminal setup](https://cruxwell.github.io/pcode/terminal/) | Tab titles, the progress bar, iTerm2 and tmux settings |
136
+ | [Terminal setup](https://cruxwell.github.io/pcode/terminal/) | Tab titles, the progress bar, symbols and colors, iTerm2 and tmux settings |
135
137
  | [Tools](https://cruxwell.github.io/pcode/tools/) | Tool permissions, web search, the browser, code mode |
136
138
  | [MCP servers](https://cruxwell.github.io/pcode/mcp/) | Opt-in MCP configuration, OAuth sign-in, deferred tool search |
137
139
  | [Working in a repository](https://cruxwell.github.io/pcode/workspace/) | `AGENTS.md`/`CLAUDE.md`, skills as slash commands, one worktree per session |
@@ -148,6 +150,7 @@ checks every page and anchor link.
148
150
  ## Contributing
149
151
 
150
152
  Bugs: [open an issue](https://github.com/cruxwell/pcode/issues/new/choose).
153
+ Feedback and ideas: [the feedback discussion](https://github.com/cruxwell/pcode/discussions/4).
151
154
  Security problems: see [SECURITY.md](https://github.com/cruxwell/pcode/blob/master/SECURITY.md). Setup and checks are in
152
155
  [CONTRIBUTING.md](https://github.com/cruxwell/pcode/blob/master/CONTRIBUTING.md).
153
156
 
@@ -28,6 +28,8 @@ your Claude or ChatGPT subscription.
28
28
 
29
29
  **Documentation: [cruxwell.github.io/pcode](https://cruxwell.github.io/pcode/)**
30
30
 
31
+ **Tried it? [Share feedback](https://github.com/cruxwell/pcode/discussions/4)**: what worked, what didn't, and where you got stuck.
32
+
31
33
  ## Install
32
34
 
33
35
  With [Homebrew](https://brew.sh/):
@@ -40,7 +42,7 @@ brew install cruxwell/pcode/pcode
40
42
  Or from [PyPI](https://pypi.org/project/pcode/) with [uv](https://docs.astral.sh/uv/):
41
43
 
42
44
  ```sh
43
- uv tool install --python 3.14 'pcode[claude]'
45
+ uv tool install --python 3.15 'pcode[claude]'
44
46
  ```
45
47
 
46
48
  `brew install --HEAD` tracks `master` instead of the latest release.
@@ -95,7 +97,7 @@ See [PLAN.md](https://github.com/cruxwell/pcode/blob/master/PLAN.md) for the lon
95
97
  | [Configuration](https://cruxwell.github.io/pcode/configuration/) | `pcode config`, per-repository overrides, trusting repository code, the settings table, syntax styles |
96
98
  | [Commands and keys](https://cruxwell.github.io/pcode/commands/) | Slash commands, key bindings, vi mode, tmux newlines, status line, `!command`, the diff and tool inspectors |
97
99
  | [Keybindings](https://cruxwell.github.io/pcode/keybindings/) | Custom command mappings with `/bind`, Ctrl shortcuts, vi editing, a normal-mode leader, and custom escape sequences such as `jj` |
98
- | [Terminal setup](https://cruxwell.github.io/pcode/terminal/) | Tab titles, the progress bar, iTerm2 and tmux settings |
100
+ | [Terminal setup](https://cruxwell.github.io/pcode/terminal/) | Tab titles, the progress bar, symbols and colors, iTerm2 and tmux settings |
99
101
  | [Tools](https://cruxwell.github.io/pcode/tools/) | Tool permissions, web search, the browser, code mode |
100
102
  | [MCP servers](https://cruxwell.github.io/pcode/mcp/) | Opt-in MCP configuration, OAuth sign-in, deferred tool search |
101
103
  | [Working in a repository](https://cruxwell.github.io/pcode/workspace/) | `AGENTS.md`/`CLAUDE.md`, skills as slash commands, one worktree per session |
@@ -112,6 +114,7 @@ checks every page and anchor link.
112
114
  ## Contributing
113
115
 
114
116
  Bugs: [open an issue](https://github.com/cruxwell/pcode/issues/new/choose).
117
+ Feedback and ideas: [the feedback discussion](https://github.com/cruxwell/pcode/discussions/4).
115
118
  Security problems: see [SECURITY.md](https://github.com/cruxwell/pcode/blob/master/SECURITY.md). Setup and checks are in
116
119
  [CONTRIBUTING.md](https://github.com/cruxwell/pcode/blob/master/CONTRIBUTING.md).
117
120
 
@@ -33,11 +33,11 @@ dependencies = [
33
33
  # itself is downloaded on first use, not at install.
34
34
  # Harness ships from the pydantic-ai repo with every Pydantic AI release and
35
35
  # pins pydantic-ai-slim to the same minor; bump both together.
36
- "pydantic-ai-harness[exa,coder,codemode,playwright]>=0.55.0,<0.56",
36
+ "pydantic-ai-harness[exa,coder,codemode,playwright]>=0.56.0,<0.57",
37
37
  # duckduckgo and web-fetch back the bundled web_research extension when no
38
38
  # provider-native search or Exa key is available.
39
39
  # google covers both google and google-cloud providers; bedrock pulls boto3.
40
- "pydantic-ai-slim[anthropic,bedrock,duckduckgo,google,groq,mcp,openai,web-fetch,xai]>=2.55.0,<3",
40
+ "pydantic-ai-slim[anthropic,bedrock,duckduckgo,google,groq,mcp,openai,web-fetch,xai]>=2.56.0,<3",
41
41
  "rich>=15,<16",
42
42
  # FastMCP 4.x OAuth callback server selects Uvicorn's websockets-sansio protocol.
43
43
  # Capped below 17 by google-genai (still <17 as of 2.29), not by pcode.
@@ -49,7 +49,7 @@ dependencies = [
49
49
  # (about 95 MB to download, 215 MB installed); the sdist would run whatever
50
50
  # `claude` is on PATH instead of the CLI version pcode was verified against.
51
51
  claude = [
52
- "claude-agent-sdk>=0.2.164,<0.3",
52
+ "claude-agent-sdk>=0.2.167,<0.3",
53
53
  ]
54
54
 
55
55
  [project.urls]
@@ -9,6 +9,7 @@ from contextvars import ContextVar
9
9
  from copy import copy
10
10
  from dataclasses import dataclass, fields, replace
11
11
  from pathlib import Path
12
+ from typing import TYPE_CHECKING
12
13
 
13
14
  from pydantic_ai import Agent
14
15
  from pydantic_ai.capabilities import (
@@ -18,13 +19,11 @@ from pydantic_ai.capabilities import (
18
19
  LocalWorkspace,
19
20
  )
20
21
  from pydantic_ai.models import Model
21
- from pydantic_ai.models.openai_codex import OpenAICodexModel
22
22
  from pydantic_ai.profiles.openai import OpenAIModelProfile
23
- from pydantic_ai.providers.openai_codex import OpenAICodexProvider
24
23
  from pydantic_ai.toolsets import CombinedToolset
25
24
  from pydantic_ai.usage import UsageLimits
26
25
  from pydantic_ai_harness.coder import Coder
27
- from pydantic_ai_harness.compaction import ClearToolResults, WarnNearLimits
26
+ from pydantic_ai_harness.compaction import ClearToolResults
28
27
  from pydantic_ai_harness.filesystem import FileSystem
29
28
  from pydantic_ai_harness.repo_context import RepoContext
30
29
  from pydantic_ai_harness.shell import LLM_API_KEY_ENV_PATTERNS, Shell
@@ -40,14 +39,12 @@ from pcode.code_mode import create_code_mode
40
39
  from pcode.delegation import DelegationReporting, stream_child_activity
41
40
  from pcode.ext import EXTENSION_GUIDE, ExtensionCapabilities
42
41
  from pcode.filesystem import DisplayFileSystem
42
+ from pcode.images import ImageGate
43
43
  from pcode.isolated_delegation import WorkspaceSubAgents
44
44
  from pcode.job_notices import JobNotices
45
45
  from pcode.jobs import isolated_registry
46
- from pcode.llm_proxy import ProxiedCodexProvider
47
46
  from pcode.mcp import configured_servers
48
47
  from pcode.mcp_notice import MCPServers
49
- from pcode.meridian import MeridianSessionIdentity
50
- from pcode.meridian_reminders import MeridianLimitWarnings
51
48
  from pcode.output_limits import ModelOutputLimits
52
49
  from pcode.planning import IdentifiedPlanning
53
50
  from pcode.preferences import SETTINGS, load_preferences, subagent_models
@@ -57,6 +54,9 @@ from pcode.strict_tools import create_strict_tools
57
54
  from pcode.tool_output_limits import create_tool_output_limits
58
55
  from pcode.workspace import WorkspaceGuard
59
56
 
57
+ if TYPE_CHECKING:
58
+ from pydantic_ai.models.openai_codex import OpenAICodexModel
59
+
60
60
  # Harness gives a child its own usage counter only when its `SubAgent` carries
61
61
  # `usage_limits`; without one the child shares the parent's counter and silently
62
62
  # gets the library's 50-request default, which a busy session has already spent.
@@ -199,8 +199,6 @@ def _adapt(capability, workspace: Path, output_limits):
199
199
  # Replace Coder's 64k truncation, so it cannot cut data before spilling.
200
200
  case ToolOutputLimits():
201
201
  return output_limits
202
- case WarnNearLimits():
203
- return MeridianLimitWarnings(**_init_fields(capability))
204
202
  case Shell():
205
203
  return _job_shell(capability, workspace)
206
204
  case _:
@@ -216,13 +214,11 @@ def _job_shell(shell: Shell, workspace: Path) -> JobShell:
216
214
  `__init__`.
217
215
  """
218
216
  values = _init_fields(shell)
219
- # direnv writes its status banner to stderr on every cd into a managed
220
- # directory, which pollutes command output the agent parses (e.g.
221
- # `... | jq`). An empty log format silences it.
222
- values["env"] = {**(shell.env or os.environ), "DIRENV_LOG_FORMAT": ""}
223
217
  # Commands inherit the whole host environment (see `JobShell`), so keep
224
218
  # provider credentials out of it, as Coder did before it left the
225
- # environment to the workspace.
219
+ # environment to the workspace. The env must be explicit: Harness applies
220
+ # `denied_env_patterns` only to an explicit env, never to `None`.
221
+ values["env"] = dict(shell.env or os.environ)
226
222
  values["denied_env_patterns"] = [*values["denied_env_patterns"], *LLM_API_KEY_ENV_PATTERNS]
227
223
  return JobShell(**values, workdir=workspace)
228
224
 
@@ -281,8 +277,8 @@ def _worker_capabilities(capabilities: Sequence) -> list:
281
277
  """
282
278
  shared_types = (
283
279
  ToolOutputLimits,
284
- MeridianSessionIdentity,
285
280
  ModelOutputLimits,
281
+ ImageGate,
286
282
  CacheBustReporting,
287
283
  TurnLimits,
288
284
  )
@@ -339,8 +335,8 @@ def _delegation(
339
335
  shared_capabilities=[
340
336
  # Extension sub-agents have no coder of their own to set it.
341
337
  ClaudeWorkspace(workspace, fallback=True),
342
- MeridianSessionIdentity(),
343
338
  ModelOutputLimits(),
339
+ ImageGate(),
344
340
  *([replace(cache_notices)] if cache_notices else []),
345
341
  ProviderCacheSettings(),
346
342
  replace(output_limits),
@@ -362,7 +358,7 @@ def create_coder(
362
358
  _ensure_bundled_rg()
363
359
  # Delegation is pcode's own `WorkspaceSubAgents`, added below. Caching is
364
360
  # `ProviderCacheSettings`' per-provider choice: Coder's default `cache=True`
365
- # would also reach Meridian and OpenAI's explicit-breakpoint models.
361
+ # would also reach OpenAI's explicit-breakpoint models.
366
362
  coder = Coder(sub_agents=False, caching=False)
367
363
  output_limits = create_tool_output_limits()
368
364
  # Keep Coder's tool selection, including its persistent shell (as a
@@ -381,8 +377,8 @@ def create_coder(
381
377
  ClaudeWorkspace(workspace),
382
378
  IdentifiedPlanning(),
383
379
  DelegationReporting(),
384
- MeridianSessionIdentity(),
385
380
  ModelOutputLimits(),
381
+ ImageGate(),
386
382
  *turn_limits(),
387
383
  ]
388
384
  # Ahead of the worker copy below, so a delegate edits under the same schema.
@@ -446,7 +442,13 @@ def codex_model(model: str) -> OpenAICodexModel:
446
442
  Without a pcode store the provider reads the CLI file at construction time
447
443
  and keeps refreshed tokens in memory only.
448
444
  """
445
+ # Imported here, not at module level: `openai_codex` loads the whole OpenAI
446
+ # SDK (about 0.3 s), which a session on any other provider never uses.
447
+ from pydantic_ai.models.openai_codex import OpenAICodexModel
448
+ from pydantic_ai.providers.openai_codex import OpenAICodexProvider
449
+
449
450
  from pcode.codex_login import credential_source
451
+ from pcode.llm_proxy import ProxiedCodexProvider
450
452
 
451
453
  proxy = os.environ.get("PCODE_LLM_PROXY", "").strip()
452
454
  source = credential_source()
@@ -478,33 +480,16 @@ def resolve_model(model: str) -> Model | str:
478
480
  """
479
481
  if model.startswith("openai-codex:"):
480
482
  return codex_model(model)
481
- if model.startswith("meridian:"):
482
- from pcode.models import LEGACY_ANTHROPIC_AUTH
483
-
484
- if not LEGACY_ANTHROPIC_AUTH:
485
- name = model.removeprefix("meridian:")
486
- raise ValueError(f"Meridian is turned off; switch to claude:{name} with /model.")
487
- from pcode.meridian import meridian_model
488
-
489
- return meridian_model(model)
490
483
  if model.startswith("claude:"):
491
484
  from pcode.claude_sdk import claude_model
492
485
 
493
486
  return claude_model(model)
494
487
  if not model.startswith("anthropic:"):
495
488
  return model
496
- from pcode.anthropic_oauth import anthropic_auth_source
497
489
  from pcode.auth import anthropic_model
498
490
 
499
- auth_source = anthropic_auth_source()
500
- if auth_source == "oauth":
501
- from pcode.anthropic_oauth import AnthropicOAuthModel
502
-
503
- return AnthropicOAuthModel(model)
504
- if auth_source == "api-key":
505
- key = os.environ.get("ANTHROPIC_API_KEY", "").strip()
506
- return anthropic_model(model, key) if key else model
507
- raise ValueError("PCODE_ANTHROPIC_AUTH must be api-key or oauth.")
491
+ key = os.environ.get("ANTHROPIC_API_KEY", "").strip()
492
+ return anthropic_model(model, key) if key else model
508
493
 
509
494
 
510
495
  @dataclass(frozen=True)