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.
- {pcode-0.1.7 → pcode-0.1.9}/PKG-INFO +9 -6
- {pcode-0.1.7 → pcode-0.1.9}/README.md +5 -2
- {pcode-0.1.7 → pcode-0.1.9}/pyproject.toml +3 -3
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/agent.py +21 -36
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/app.py +454 -98
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/aside.py +38 -4
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/aside_ui.py +154 -64
- pcode-0.1.9/src/pcode/auth.py +17 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/background_delegation.py +1 -1
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/browser.py +324 -3
- pcode-0.1.9/src/pcode/btw_view.py +211 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/cache_settings.py +1 -2
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/cache_warnings.py +2 -2
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/__init__.py +2 -3
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/errors.py +1 -1
- pcode-0.1.9/src/pcode/claude_sdk/login.py +114 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/model.py +1 -2
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/clipboard.py +48 -1
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/compaction.py +6 -39
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/config.py +11 -12
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/controller.py +367 -153
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/conversation_ids.py +6 -5
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/conversation_tree.py +47 -11
- pcode-0.1.9/src/pcode/copy_ui.py +296 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/edits.py +4 -2
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/extensions/browser.py +104 -5
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/extensions/plan_mode.py +52 -77
- pcode-0.1.9/src/pcode/extensions/reflect.py +364 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/extensions/sandbox.py +12 -5
- pcode-0.1.9/src/pcode/extensions/session_history.py +179 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/file_refs.py +2 -1
- pcode-0.1.9/src/pcode/filesystem.py +289 -0
- pcode-0.1.9/src/pcode/glyphs.py +202 -0
- pcode-0.1.9/src/pcode/history.py +705 -0
- pcode-0.1.9/src/pcode/history_index.py +331 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/host.py +37 -7
- pcode-0.1.9/src/pcode/images.py +257 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/inspection.py +18 -6
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/keymap.py +9 -3
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/live.py +233 -45
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/logins.py +7 -109
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/mcp_notice.py +1 -1
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/mcp_oauth.py +1 -1
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/model_metadata.py +51 -38
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/models.py +4 -32
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/native_results.py +3 -3
- pcode-0.1.9/src/pcode/obsidian_plans.py +213 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/output_limits.py +1 -1
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/popup_ui.py +69 -7
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/preferences.py +83 -44
- pcode-0.1.9/src/pcode/prompt_images.py +179 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/prompt_keys.py +181 -14
- pcode-0.1.9/src/pcode/reminders.py +48 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/remote.py +9 -9
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/remote_profile.py +0 -5
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/replay_benchmark.py +13 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/retries.py +5 -1
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/session_naming.py +18 -3
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/session_ui.py +63 -3
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/sessions.py +46 -30
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/stall_log.py +8 -3
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/startup_input.py +40 -7
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/steering.py +27 -8
- pcode-0.1.9/src/pcode/terminal_color.py +122 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/theme.py +88 -15
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/tool_display.py +34 -3
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/tool_output_limits.py +36 -5
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/tool_panel.py +1 -1
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/tree_ui.py +218 -57
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/turn.py +3 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/ui.py +863 -194
- pcode-0.1.9/src/pcode/usage.py +213 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/word_wrap.py +76 -4
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/workspace_filesystem.py +2 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/worktree.py +43 -4
- pcode-0.1.7/src/pcode/anthropic_oauth.py +0 -469
- pcode-0.1.7/src/pcode/auth.py +0 -113
- pcode-0.1.7/src/pcode/copy_ui.py +0 -394
- pcode-0.1.7/src/pcode/extensions/basic_memory/Brief format.md +0 -91
- pcode-0.1.7/src/pcode/extensions/basic_memory/Briefs.base +0 -50
- pcode-0.1.7/src/pcode/extensions/basic_memory/Home.md +0 -11
- pcode-0.1.7/src/pcode/extensions/basic_memory/__init__.py +0 -731
- pcode-0.1.7/src/pcode/extensions/basic_memory/memory-states.css +0 -58
- pcode-0.1.7/src/pcode/extensions/session_history.py +0 -170
- pcode-0.1.7/src/pcode/filesystem.py +0 -131
- pcode-0.1.7/src/pcode/history.py +0 -589
- pcode-0.1.7/src/pcode/history_cursor.py +0 -147
- pcode-0.1.7/src/pcode/meridian.py +0 -233
- pcode-0.1.7/src/pcode/meridian_process.py +0 -337
- pcode-0.1.7/src/pcode/meridian_reminders.py +0 -120
- pcode-0.1.7/src/pcode/meridian_setup.py +0 -356
- pcode-0.1.7/src/pcode/oauth_pages.py +0 -66
- pcode-0.1.7/src/pcode/usage.py +0 -293
- {pcode-0.1.7 → pcode-0.1.9}/.gitignore +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/LICENSE +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/__init__.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/_job_supervisor.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/appearance.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/aside_guard.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/block.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/cache_diagnostics.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/cli.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/messages.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/resume.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/session.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/session_pool.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/web.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/claude_sdk/workspace.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/cli.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/code_mode.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/codex_login.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/command_transcript.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/commands.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/completion.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/config_ui.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/context_breakdown.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/context_usage.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/delegation.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/delta.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/diagnostics.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/edit_preview.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/edit_transcript.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/edit_ui.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/__init__.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/cli.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/listener.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/mailbox.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/outbound.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/parsing.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/render.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/email_remote/state.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/error_report.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/ext.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/extension_guide.md +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/extensions/ponytail.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/extensions/web_research.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/frame.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/gateway.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/git_diff.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/history_embeddings.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/host_protocol.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/host_ui.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/input_keys.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/inspector_ui.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/isolated_delegation.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/job_notices.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/jobs.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/jobs_ui.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/keyboard_protocol.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/layout_speed.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/links.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/links_ui.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/llm_proxy.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/mcp.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/model_ui.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/path_completion.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/plan_preview.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/plan_sizes.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/planning.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/prefix_keys.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/proctitle.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/profile_benchmark.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/profiling.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/project_trust.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/remote_print.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/repo_context.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/rpc.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/runtime.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/sandbox.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/shell.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/shell_mode.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/shell_tools.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/skills.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/stream_display.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/stream_events.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/strict_tools.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/syntax.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/syntax_colors.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/task_prompt.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/task_worktrees.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/terminal_notify.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/terminal_text.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/text_selection.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/theme_gallery.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/thinking_markdown.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/token_accounting.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/transcript_log.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/transcript_notice.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/update_check.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/worker_ui.py +0 -0
- {pcode-0.1.7 → pcode-0.1.9}/src/pcode/workers.py +0 -0
- {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.
|
|
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.
|
|
29
|
-
Requires-Dist: pydantic-ai-slim[anthropic,bedrock,duckduckgo,google,groq,mcp,openai,web-fetch,xai]<3,>=2.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
500
|
-
if
|
|
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)
|