pcode 0.1.0__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 (163) hide show
  1. pcode-0.1.0/.gitignore +12 -0
  2. pcode-0.1.0/LICENSE +21 -0
  3. pcode-0.1.0/PKG-INFO +145 -0
  4. pcode-0.1.0/README.md +108 -0
  5. pcode-0.1.0/pyproject.toml +99 -0
  6. pcode-0.1.0/src/pcode/__init__.py +7 -0
  7. pcode-0.1.0/src/pcode/_job_supervisor.py +65 -0
  8. pcode-0.1.0/src/pcode/agent.py +592 -0
  9. pcode-0.1.0/src/pcode/anthropic_oauth.py +469 -0
  10. pcode-0.1.0/src/pcode/app.py +3165 -0
  11. pcode-0.1.0/src/pcode/appearance.py +181 -0
  12. pcode-0.1.0/src/pcode/aside.py +541 -0
  13. pcode-0.1.0/src/pcode/aside_guard.py +39 -0
  14. pcode-0.1.0/src/pcode/aside_ui.py +683 -0
  15. pcode-0.1.0/src/pcode/auth.py +113 -0
  16. pcode-0.1.0/src/pcode/block.py +39 -0
  17. pcode-0.1.0/src/pcode/browser.py +393 -0
  18. pcode-0.1.0/src/pcode/cache_diagnostics.py +336 -0
  19. pcode-0.1.0/src/pcode/cache_settings.py +58 -0
  20. pcode-0.1.0/src/pcode/cache_warnings.py +139 -0
  21. pcode-0.1.0/src/pcode/claude_sdk/__init__.py +96 -0
  22. pcode-0.1.0/src/pcode/claude_sdk/cli.py +52 -0
  23. pcode-0.1.0/src/pcode/claude_sdk/errors.py +61 -0
  24. pcode-0.1.0/src/pcode/claude_sdk/messages.py +154 -0
  25. pcode-0.1.0/src/pcode/claude_sdk/model.py +179 -0
  26. pcode-0.1.0/src/pcode/claude_sdk/resume.py +114 -0
  27. pcode-0.1.0/src/pcode/claude_sdk/session.py +547 -0
  28. pcode-0.1.0/src/pcode/claude_sdk/session_pool.py +251 -0
  29. pcode-0.1.0/src/pcode/claude_sdk/workspace.py +34 -0
  30. pcode-0.1.0/src/pcode/cli.py +73 -0
  31. pcode-0.1.0/src/pcode/clipboard.py +76 -0
  32. pcode-0.1.0/src/pcode/code_mode.py +43 -0
  33. pcode-0.1.0/src/pcode/codex_login.py +189 -0
  34. pcode-0.1.0/src/pcode/command_transcript.py +71 -0
  35. pcode-0.1.0/src/pcode/commands.py +145 -0
  36. pcode-0.1.0/src/pcode/compaction.py +457 -0
  37. pcode-0.1.0/src/pcode/completion.py +263 -0
  38. pcode-0.1.0/src/pcode/config.py +223 -0
  39. pcode-0.1.0/src/pcode/context_breakdown.py +178 -0
  40. pcode-0.1.0/src/pcode/context_usage.py +52 -0
  41. pcode-0.1.0/src/pcode/controller.py +3496 -0
  42. pcode-0.1.0/src/pcode/conversation_ids.py +27 -0
  43. pcode-0.1.0/src/pcode/conversation_tree.py +160 -0
  44. pcode-0.1.0/src/pcode/copy_ui.py +172 -0
  45. pcode-0.1.0/src/pcode/delegation.py +236 -0
  46. pcode-0.1.0/src/pcode/delta.py +295 -0
  47. pcode-0.1.0/src/pcode/diagnostics.py +226 -0
  48. pcode-0.1.0/src/pcode/edit_preview.py +158 -0
  49. pcode-0.1.0/src/pcode/edit_transcript.py +287 -0
  50. pcode-0.1.0/src/pcode/edit_ui.py +850 -0
  51. pcode-0.1.0/src/pcode/edits.py +162 -0
  52. pcode-0.1.0/src/pcode/email_remote/__init__.py +14 -0
  53. pcode-0.1.0/src/pcode/email_remote/cli.py +133 -0
  54. pcode-0.1.0/src/pcode/email_remote/listener.py +695 -0
  55. pcode-0.1.0/src/pcode/email_remote/mailbox.py +336 -0
  56. pcode-0.1.0/src/pcode/email_remote/outbound.py +75 -0
  57. pcode-0.1.0/src/pcode/email_remote/parsing.py +226 -0
  58. pcode-0.1.0/src/pcode/email_remote/render.py +175 -0
  59. pcode-0.1.0/src/pcode/email_remote/state.py +79 -0
  60. pcode-0.1.0/src/pcode/error_report.py +38 -0
  61. pcode-0.1.0/src/pcode/ext.py +602 -0
  62. pcode-0.1.0/src/pcode/extension_guide.md +311 -0
  63. pcode-0.1.0/src/pcode/extensions/browser.py +284 -0
  64. pcode-0.1.0/src/pcode/extensions/ponytail.py +217 -0
  65. pcode-0.1.0/src/pcode/extensions/sandbox.py +138 -0
  66. pcode-0.1.0/src/pcode/extensions/session_history.py +170 -0
  67. pcode-0.1.0/src/pcode/extensions/web_research.py +89 -0
  68. pcode-0.1.0/src/pcode/file_refs.py +265 -0
  69. pcode-0.1.0/src/pcode/filesystem.py +138 -0
  70. pcode-0.1.0/src/pcode/frame.py +149 -0
  71. pcode-0.1.0/src/pcode/gateway.py +465 -0
  72. pcode-0.1.0/src/pcode/git_diff.py +497 -0
  73. pcode-0.1.0/src/pcode/history.py +589 -0
  74. pcode-0.1.0/src/pcode/history_cursor.py +147 -0
  75. pcode-0.1.0/src/pcode/history_embeddings.py +102 -0
  76. pcode-0.1.0/src/pcode/host.py +941 -0
  77. pcode-0.1.0/src/pcode/host_protocol.py +291 -0
  78. pcode-0.1.0/src/pcode/host_ui.py +225 -0
  79. pcode-0.1.0/src/pcode/input_keys.py +35 -0
  80. pcode-0.1.0/src/pcode/inspection.py +289 -0
  81. pcode-0.1.0/src/pcode/inspector_ui.py +448 -0
  82. pcode-0.1.0/src/pcode/isolated_delegation.py +425 -0
  83. pcode-0.1.0/src/pcode/job_notices.py +54 -0
  84. pcode-0.1.0/src/pcode/jobs.py +584 -0
  85. pcode-0.1.0/src/pcode/jobs_ui.py +265 -0
  86. pcode-0.1.0/src/pcode/keymap.py +215 -0
  87. pcode-0.1.0/src/pcode/layout_speed.py +103 -0
  88. pcode-0.1.0/src/pcode/links.py +90 -0
  89. pcode-0.1.0/src/pcode/links_ui.py +200 -0
  90. pcode-0.1.0/src/pcode/live.py +1301 -0
  91. pcode-0.1.0/src/pcode/llm_proxy.py +44 -0
  92. pcode-0.1.0/src/pcode/logins.py +233 -0
  93. pcode-0.1.0/src/pcode/mcp.py +683 -0
  94. pcode-0.1.0/src/pcode/mcp_notice.py +91 -0
  95. pcode-0.1.0/src/pcode/mcp_oauth.py +381 -0
  96. pcode-0.1.0/src/pcode/meridian.py +233 -0
  97. pcode-0.1.0/src/pcode/meridian_process.py +337 -0
  98. pcode-0.1.0/src/pcode/meridian_reminders.py +107 -0
  99. pcode-0.1.0/src/pcode/meridian_setup.py +356 -0
  100. pcode-0.1.0/src/pcode/model_metadata.py +451 -0
  101. pcode-0.1.0/src/pcode/model_ui.py +168 -0
  102. pcode-0.1.0/src/pcode/models.py +209 -0
  103. pcode-0.1.0/src/pcode/native_results.py +119 -0
  104. pcode-0.1.0/src/pcode/oauth_pages.py +66 -0
  105. pcode-0.1.0/src/pcode/output_limits.py +41 -0
  106. pcode-0.1.0/src/pcode/paste.py +45 -0
  107. pcode-0.1.0/src/pcode/path_completion.py +66 -0
  108. pcode-0.1.0/src/pcode/plan_preview.py +131 -0
  109. pcode-0.1.0/src/pcode/plan_sizes.py +35 -0
  110. pcode-0.1.0/src/pcode/planning.py +161 -0
  111. pcode-0.1.0/src/pcode/popup_ui.py +873 -0
  112. pcode-0.1.0/src/pcode/preferences.py +1176 -0
  113. pcode-0.1.0/src/pcode/prefix_keys.py +490 -0
  114. pcode-0.1.0/src/pcode/profile_benchmark.py +332 -0
  115. pcode-0.1.0/src/pcode/profiling.py +566 -0
  116. pcode-0.1.0/src/pcode/project_trust.py +94 -0
  117. pcode-0.1.0/src/pcode/prompt_keys.py +286 -0
  118. pcode-0.1.0/src/pcode/remote.py +717 -0
  119. pcode-0.1.0/src/pcode/remote_print.py +125 -0
  120. pcode-0.1.0/src/pcode/remote_profile.py +237 -0
  121. pcode-0.1.0/src/pcode/replay_benchmark.py +319 -0
  122. pcode-0.1.0/src/pcode/repo_context.py +158 -0
  123. pcode-0.1.0/src/pcode/retries.py +28 -0
  124. pcode-0.1.0/src/pcode/rpc.py +280 -0
  125. pcode-0.1.0/src/pcode/runtime.py +244 -0
  126. pcode-0.1.0/src/pcode/sandbox.py +454 -0
  127. pcode-0.1.0/src/pcode/session_naming.py +82 -0
  128. pcode-0.1.0/src/pcode/session_ui.py +550 -0
  129. pcode-0.1.0/src/pcode/sessions.py +892 -0
  130. pcode-0.1.0/src/pcode/shell.py +113 -0
  131. pcode-0.1.0/src/pcode/shell_mode.py +172 -0
  132. pcode-0.1.0/src/pcode/shell_tools.py +459 -0
  133. pcode-0.1.0/src/pcode/skills.py +161 -0
  134. pcode-0.1.0/src/pcode/stall_log.py +187 -0
  135. pcode-0.1.0/src/pcode/startup_input.py +96 -0
  136. pcode-0.1.0/src/pcode/steering.py +27 -0
  137. pcode-0.1.0/src/pcode/stream_display.py +188 -0
  138. pcode-0.1.0/src/pcode/stream_events.py +437 -0
  139. pcode-0.1.0/src/pcode/strict_tools.py +130 -0
  140. pcode-0.1.0/src/pcode/syntax.py +43 -0
  141. pcode-0.1.0/src/pcode/syntax_colors.py +206 -0
  142. pcode-0.1.0/src/pcode/task_prompt.py +28 -0
  143. pcode-0.1.0/src/pcode/task_worktrees.py +482 -0
  144. pcode-0.1.0/src/pcode/terminal_notify.py +383 -0
  145. pcode-0.1.0/src/pcode/theme.py +135 -0
  146. pcode-0.1.0/src/pcode/theme_gallery.py +88 -0
  147. pcode-0.1.0/src/pcode/thinking_markdown.py +41 -0
  148. pcode-0.1.0/src/pcode/token_accounting.py +67 -0
  149. pcode-0.1.0/src/pcode/tool_display.py +784 -0
  150. pcode-0.1.0/src/pcode/tool_output_limits.py +108 -0
  151. pcode-0.1.0/src/pcode/tool_panel.py +377 -0
  152. pcode-0.1.0/src/pcode/transcript_log.py +127 -0
  153. pcode-0.1.0/src/pcode/transcript_notice.py +103 -0
  154. pcode-0.1.0/src/pcode/tree_ui.py +288 -0
  155. pcode-0.1.0/src/pcode/turn.py +44 -0
  156. pcode-0.1.0/src/pcode/ui.py +3745 -0
  157. pcode-0.1.0/src/pcode/usage.py +293 -0
  158. pcode-0.1.0/src/pcode/word_wrap.py +107 -0
  159. pcode-0.1.0/src/pcode/worker_ui.py +235 -0
  160. pcode-0.1.0/src/pcode/workers.py +136 -0
  161. pcode-0.1.0/src/pcode/workspace.py +57 -0
  162. pcode-0.1.0/src/pcode/workspace_filesystem.py +72 -0
  163. pcode-0.1.0/src/pcode/worktree.py +650 -0
pcode-0.1.0/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ dist/
7
+ *.egg-info/
8
+ # no trailing slash: in a worktree, tmp is a symlink to the main checkout's
9
+ tmp
10
+ .worktrees/
11
+ # built docs site (make docs)
12
+ site/
pcode-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aaron Weisberg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
pcode-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.5
2
+ Name: pcode
3
+ Version: 0.1.0
4
+ Summary: Terminal-native AI coding agent with background jobs, parallel worktrees, forkable sessions, and multi-model support
5
+ Project-URL: Homepage, https://github.com/cruxwell/pcode
6
+ Project-URL: Documentation, https://cruxwell.github.io/pcode/
7
+ Project-URL: Source, https://github.com/cruxwell/pcode
8
+ Project-URL: Issues, https://github.com/cruxwell/pcode/issues
9
+ Author: Aaron Weisberg
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: cli,coding-agent,llm,pydantic-ai,terminal
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: MacOS
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Software Development
23
+ Requires-Python: >=3.11
24
+ Requires-Dist: filelock<4,>=3.16
25
+ Requires-Dist: genai-prices<0.2,>=0.1.7
26
+ Requires-Dist: httpx2<3,>=2.13
27
+ Requires-Dist: prompt-toolkit==3.0.53
28
+ Requires-Dist: psutil<8,>=6
29
+ Requires-Dist: pydantic-ai-harness[codemode,coder,exa,playwright]<0.53,>=0.52.0
30
+ Requires-Dist: pydantic-ai-slim[anthropic,bedrock,duckduckgo,google,groq,mcp,openai,web-fetch,xai]<3,>=2.52.0
31
+ Requires-Dist: rich<15,>=14
32
+ Requires-Dist: websockets<17,>=15.0.1
33
+ Requires-Dist: yappi<2,>=1.7.6
34
+ Provides-Extra: claude
35
+ Requires-Dist: claude-agent-sdk<0.3,>=0.2.160; extra == 'claude'
36
+ Description-Content-Type: text/markdown
37
+
38
+ <img width="1512" height="947" alt="Screenshot 2026-10-06 at 7 23 29 PM" src="https://github.com/user-attachments/assets/a648fede-d703-44ef-8b52-895d3a0cd2af" />
39
+ <img width="1360" alt="pcode fixing a bug: a word-level diff of the edit, then a worker sub-agent reviewing it with its own plan nested under the task list" src="https://raw.githubusercontent.com/cruxwell/pcode/master/docs/assets/screenshots/readme.png" />
40
+
41
+ # pcode
42
+
43
+ pcode is a terminal-native coding agent built for long-running and parallel
44
+ work. Background commands wake the agent when they finish, every session can
45
+ use its own git worktree, conversations can be rewound and forked, and every
46
+ tool call stays inspectable.
47
+
48
+ - **Slow work doesn't block you.** Long commands become background jobs, and a
49
+ finished job wakes the agent, so it can watch tests or CI and fix what fails.
50
+ - **Agents in parallel.** A git worktree per session lets several agents work
51
+ on one repo at once.
52
+ - **Rewind and fork.** `/tree` returns to any point in a conversation and
53
+ branches from there. Every session is kept, so you can resume or search it.
54
+ - **Nothing hidden.** `/tools` shows every command the agent ran and its full
55
+ output, and scrollback re-renders to show or fold every command and diff.
56
+
57
+ It runs on any model [Pydantic AI](https://ai.pydantic.dev/) supports, or on
58
+ your Claude or ChatGPT subscription.
59
+
60
+ **Documentation: [cruxwell.github.io/pcode](https://cruxwell.github.io/pcode/)**
61
+
62
+ ## Install
63
+
64
+ With [Homebrew](https://brew.sh/):
65
+
66
+ ```sh
67
+ brew tap cruxwell/pcode https://github.com/cruxwell/pcode.git
68
+ brew install --HEAD cruxwell/pcode/pcode
69
+ ```
70
+
71
+ ## Quick start
72
+
73
+ ```sh
74
+ codex login # or /login [claude|openai-codex] inside pcode, or export a provider API key
75
+ pcode -m openai-codex:gpt-5.6-luna # interactive; /model (Ctrl+L) saves a default
76
+ pcode # reuses the saved model, or opens the offline preview
77
+ pcode -C /path/to/repo "Summarize the open TODOs"
78
+ git diff | pcode -p --no-save # non-interactive: reply to stdout
79
+ pcode --continue # resume this directory's newest session
80
+ pcode --theme-preview # offline sample output and the style gallery
81
+ ```
82
+
83
+ **Live mode edits files and runs shell commands with your permissions and no
84
+ approval prompt.** Read [tool permissions](https://cruxwell.github.io/pcode/tools/#tool-permissions)
85
+ before pointing it at anything you care about.
86
+
87
+ ## More
88
+
89
+ - **Your subscription:** Claude runs through Anthropic's own Agent SDK and
90
+ Claude Code login, the way Anthropic supports, and ChatGPT through a Codex
91
+ login. See [providers](https://cruxwell.github.io/pcode/providers/).
92
+ - [Email remote control](https://cruxwell.github.io/pcode/email/): send a task
93
+ from Gmail on your phone, reply to keep going, and take the session over at a
94
+ terminal with `pcode --attach`.
95
+ - [Custom keybindings and Vim editing](https://cruxwell.github.io/pcode/keybindings/):
96
+ map keys to commands with arguments, add a Space leader in normal mode, or use
97
+ `jj` to leave insert mode.
98
+ - `/btw` side questions, background sessions, recall of past sessions, a
99
+ browser the agent can drive, and Python extensions.
100
+ - Pydantic AI's Harness coder capabilities, with the rest of a finished agent
101
+ on top: MCP with OAuth and tool search, searchable sessions, jobs,
102
+ worktrees. Extensions are plain Pydantic AI capabilities. The conversation
103
+ tree follows [pi](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/tree.md)'s.
104
+
105
+ See [PLAN.md](https://github.com/cruxwell/pcode/blob/master/PLAN.md) for the longer-term direction.
106
+
107
+ ## Documentation
108
+
109
+ | Page | What it covers |
110
+ | --- | --- |
111
+ | [Getting started](https://cruxwell.github.io/pcode/getting-started/) | Homebrew and source installs, `-C`, `--print`, shell completion |
112
+ | [Scrollback and transparency](https://cruxwell.github.io/pcode/guide/scrollback/) | Guide: what goes into scrollback, `/tools`, `/diffs` |
113
+ | [A shell for long-running work](https://cruxwell.github.io/pcode/guide/shell/) | Guide: background jobs, watching CI |
114
+ | [Parallel agents](https://cruxwell.github.io/pcode/guide/parallel/) | Guide: worktrees, parallel sub-agents, `/agents` |
115
+ | [Extending pcode](https://cruxwell.github.io/pcode/guide/extending/) | Guide: extensions, skills, settings |
116
+ | [Providers and models](https://cruxwell.github.io/pcode/providers/) | Authentication, supported providers, the model picker, reasoning effort, Claude Code, Meridian, proxies |
117
+ | [Configuration](https://cruxwell.github.io/pcode/configuration/) | `pcode config`, per-repository overrides, trusting repository code, the settings table, syntax styles |
118
+ | [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 |
119
+ | [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` |
120
+ | [Tools](https://cruxwell.github.io/pcode/tools/) | Tool permissions, web search, the browser, code mode |
121
+ | [MCP servers](https://cruxwell.github.io/pcode/mcp/) | Opt-in MCP configuration, OAuth sign-in, deferred tool search |
122
+ | [Working in a repository](https://cruxwell.github.io/pcode/workspace/) | `AGENTS.md`/`CLAUDE.md`, skills as slash commands, one worktree per session |
123
+ | [Sessions and recovery](https://cruxwell.github.io/pcode/sessions/) | Saving, resuming, recalling earlier sessions, checkpoints, retries |
124
+ | [Context, limits and caching](https://cruxwell.github.io/pcode/context/) | Prompt overhead, compaction, output limits, prompt cache notices |
125
+ | [The transcript](https://cruxwell.github.io/pcode/transcript/) | What lands in scrollback: diffs, thinking, errors, command output, `/redraw` |
126
+ | [Conversation tree](https://cruxwell.github.io/pcode/conversation-tree/) | `/tree`: rewinding and forking a conversation |
127
+ | [Side questions](https://cruxwell.github.io/pcode/side-questions/) | `/btw`: asking about the running turn without interrupting it |
128
+
129
+ The same pages build into a browsable site with `make docs-serve`; `make docs`
130
+ checks every page and anchor link.
131
+
132
+ ## Contributing
133
+
134
+ Bugs: [open an issue](https://github.com/cruxwell/pcode/issues/new/choose).
135
+ Security problems: see [SECURITY.md](https://github.com/cruxwell/pcode/blob/master/SECURITY.md). Setup and checks are in
136
+ [CONTRIBUTING.md](https://github.com/cruxwell/pcode/blob/master/CONTRIBUTING.md).
137
+
138
+ ```sh
139
+ make test # fast suite; real-tmux regressions skipped
140
+ make test-all # everything, before touching layout, streaming, the editor, or the prompt
141
+ ```
142
+
143
+ [AGENTS.md](https://github.com/cruxwell/pcode/blob/master/AGENTS.md) has the worktree workflow and the traps worth knowing
144
+ before editing. Contributor notes (architecture, dependencies, profiling, prompt
145
+ caching, provider design) live in [`dev/`](https://github.com/cruxwell/pcode/tree/master/dev), outside the published docs.
pcode-0.1.0/README.md ADDED
@@ -0,0 +1,108 @@
1
+ <img width="1512" height="947" alt="Screenshot 2026-10-06 at 7 23 29 PM" src="https://github.com/user-attachments/assets/a648fede-d703-44ef-8b52-895d3a0cd2af" />
2
+ <img width="1360" alt="pcode fixing a bug: a word-level diff of the edit, then a worker sub-agent reviewing it with its own plan nested under the task list" src="https://raw.githubusercontent.com/cruxwell/pcode/master/docs/assets/screenshots/readme.png" />
3
+
4
+ # pcode
5
+
6
+ pcode is a terminal-native coding agent built for long-running and parallel
7
+ work. Background commands wake the agent when they finish, every session can
8
+ use its own git worktree, conversations can be rewound and forked, and every
9
+ tool call stays inspectable.
10
+
11
+ - **Slow work doesn't block you.** Long commands become background jobs, and a
12
+ finished job wakes the agent, so it can watch tests or CI and fix what fails.
13
+ - **Agents in parallel.** A git worktree per session lets several agents work
14
+ on one repo at once.
15
+ - **Rewind and fork.** `/tree` returns to any point in a conversation and
16
+ branches from there. Every session is kept, so you can resume or search it.
17
+ - **Nothing hidden.** `/tools` shows every command the agent ran and its full
18
+ output, and scrollback re-renders to show or fold every command and diff.
19
+
20
+ It runs on any model [Pydantic AI](https://ai.pydantic.dev/) supports, or on
21
+ your Claude or ChatGPT subscription.
22
+
23
+ **Documentation: [cruxwell.github.io/pcode](https://cruxwell.github.io/pcode/)**
24
+
25
+ ## Install
26
+
27
+ With [Homebrew](https://brew.sh/):
28
+
29
+ ```sh
30
+ brew tap cruxwell/pcode https://github.com/cruxwell/pcode.git
31
+ brew install --HEAD cruxwell/pcode/pcode
32
+ ```
33
+
34
+ ## Quick start
35
+
36
+ ```sh
37
+ codex login # or /login [claude|openai-codex] inside pcode, or export a provider API key
38
+ pcode -m openai-codex:gpt-5.6-luna # interactive; /model (Ctrl+L) saves a default
39
+ pcode # reuses the saved model, or opens the offline preview
40
+ pcode -C /path/to/repo "Summarize the open TODOs"
41
+ git diff | pcode -p --no-save # non-interactive: reply to stdout
42
+ pcode --continue # resume this directory's newest session
43
+ pcode --theme-preview # offline sample output and the style gallery
44
+ ```
45
+
46
+ **Live mode edits files and runs shell commands with your permissions and no
47
+ approval prompt.** Read [tool permissions](https://cruxwell.github.io/pcode/tools/#tool-permissions)
48
+ before pointing it at anything you care about.
49
+
50
+ ## More
51
+
52
+ - **Your subscription:** Claude runs through Anthropic's own Agent SDK and
53
+ Claude Code login, the way Anthropic supports, and ChatGPT through a Codex
54
+ login. See [providers](https://cruxwell.github.io/pcode/providers/).
55
+ - [Email remote control](https://cruxwell.github.io/pcode/email/): send a task
56
+ from Gmail on your phone, reply to keep going, and take the session over at a
57
+ terminal with `pcode --attach`.
58
+ - [Custom keybindings and Vim editing](https://cruxwell.github.io/pcode/keybindings/):
59
+ map keys to commands with arguments, add a Space leader in normal mode, or use
60
+ `jj` to leave insert mode.
61
+ - `/btw` side questions, background sessions, recall of past sessions, a
62
+ browser the agent can drive, and Python extensions.
63
+ - Pydantic AI's Harness coder capabilities, with the rest of a finished agent
64
+ on top: MCP with OAuth and tool search, searchable sessions, jobs,
65
+ worktrees. Extensions are plain Pydantic AI capabilities. The conversation
66
+ tree follows [pi](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/tree.md)'s.
67
+
68
+ See [PLAN.md](https://github.com/cruxwell/pcode/blob/master/PLAN.md) for the longer-term direction.
69
+
70
+ ## Documentation
71
+
72
+ | Page | What it covers |
73
+ | --- | --- |
74
+ | [Getting started](https://cruxwell.github.io/pcode/getting-started/) | Homebrew and source installs, `-C`, `--print`, shell completion |
75
+ | [Scrollback and transparency](https://cruxwell.github.io/pcode/guide/scrollback/) | Guide: what goes into scrollback, `/tools`, `/diffs` |
76
+ | [A shell for long-running work](https://cruxwell.github.io/pcode/guide/shell/) | Guide: background jobs, watching CI |
77
+ | [Parallel agents](https://cruxwell.github.io/pcode/guide/parallel/) | Guide: worktrees, parallel sub-agents, `/agents` |
78
+ | [Extending pcode](https://cruxwell.github.io/pcode/guide/extending/) | Guide: extensions, skills, settings |
79
+ | [Providers and models](https://cruxwell.github.io/pcode/providers/) | Authentication, supported providers, the model picker, reasoning effort, Claude Code, Meridian, proxies |
80
+ | [Configuration](https://cruxwell.github.io/pcode/configuration/) | `pcode config`, per-repository overrides, trusting repository code, the settings table, syntax styles |
81
+ | [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 |
82
+ | [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` |
83
+ | [Tools](https://cruxwell.github.io/pcode/tools/) | Tool permissions, web search, the browser, code mode |
84
+ | [MCP servers](https://cruxwell.github.io/pcode/mcp/) | Opt-in MCP configuration, OAuth sign-in, deferred tool search |
85
+ | [Working in a repository](https://cruxwell.github.io/pcode/workspace/) | `AGENTS.md`/`CLAUDE.md`, skills as slash commands, one worktree per session |
86
+ | [Sessions and recovery](https://cruxwell.github.io/pcode/sessions/) | Saving, resuming, recalling earlier sessions, checkpoints, retries |
87
+ | [Context, limits and caching](https://cruxwell.github.io/pcode/context/) | Prompt overhead, compaction, output limits, prompt cache notices |
88
+ | [The transcript](https://cruxwell.github.io/pcode/transcript/) | What lands in scrollback: diffs, thinking, errors, command output, `/redraw` |
89
+ | [Conversation tree](https://cruxwell.github.io/pcode/conversation-tree/) | `/tree`: rewinding and forking a conversation |
90
+ | [Side questions](https://cruxwell.github.io/pcode/side-questions/) | `/btw`: asking about the running turn without interrupting it |
91
+
92
+ The same pages build into a browsable site with `make docs-serve`; `make docs`
93
+ checks every page and anchor link.
94
+
95
+ ## Contributing
96
+
97
+ Bugs: [open an issue](https://github.com/cruxwell/pcode/issues/new/choose).
98
+ Security problems: see [SECURITY.md](https://github.com/cruxwell/pcode/blob/master/SECURITY.md). Setup and checks are in
99
+ [CONTRIBUTING.md](https://github.com/cruxwell/pcode/blob/master/CONTRIBUTING.md).
100
+
101
+ ```sh
102
+ make test # fast suite; real-tmux regressions skipped
103
+ make test-all # everything, before touching layout, streaming, the editor, or the prompt
104
+ ```
105
+
106
+ [AGENTS.md](https://github.com/cruxwell/pcode/blob/master/AGENTS.md) has the worktree workflow and the traps worth knowing
107
+ before editing. Contributor notes (architecture, dependencies, profiling, prompt
108
+ caching, provider design) live in [`dev/`](https://github.com/cruxwell/pcode/tree/master/dev), outside the published docs.
@@ -0,0 +1,99 @@
1
+ [project]
2
+ name = "pcode"
3
+ version = "0.1.0"
4
+ description = "Terminal-native AI coding agent with background jobs, parallel worktrees, forkable sessions, and multi-model support"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [{ name = "Aaron Weisberg" }]
9
+ keywords = ["pydantic-ai", "coding-agent", "terminal", "llm", "cli"]
10
+ classifiers = [
11
+ "Development Status :: 3 - Alpha",
12
+ "Environment :: Console",
13
+ "Intended Audience :: Developers",
14
+ "Operating System :: MacOS",
15
+ "Operating System :: POSIX :: Linux",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.11",
18
+ "Programming Language :: Python :: 3.12",
19
+ "Programming Language :: Python :: 3.13",
20
+ "Topic :: Software Development",
21
+ ]
22
+ requires-python = ">=3.11"
23
+ dependencies = [
24
+ "filelock>=3.16,<4",
25
+ "genai-prices>=0.1.7,<0.2",
26
+ "httpx2>=2.13,<3",
27
+ # Exact: pcode relies on prompt_toolkit internals, and point releases
28
+ # change them. Bump on purpose after tests/test_prompt_toolkit_internals.py
29
+ # and make test-all pass on the new version.
30
+ "prompt-toolkit==3.0.53",
31
+ "psutil>=6,<8",
32
+ "yappi>=1.7.6,<2",
33
+ # playwright backs the bundled browser extension (/browser on); Chromium
34
+ # itself is downloaded on first use, not at install.
35
+ # Harness ships from the pydantic-ai repo with every Pydantic AI release and
36
+ # pins pydantic-ai-slim to the same minor; bump both together.
37
+ "pydantic-ai-harness[exa,coder,codemode,playwright]>=0.52.0,<0.53",
38
+ # duckduckgo and web-fetch back the bundled web_research extension when no
39
+ # provider-native search or Exa key is available.
40
+ # google covers both google and google-cloud providers; bedrock pulls boto3.
41
+ "pydantic-ai-slim[anthropic,bedrock,duckduckgo,google,groq,mcp,openai,web-fetch,xai]>=2.52.0,<3",
42
+ "rich>=14,<15",
43
+ # FastMCP 4.x OAuth callback server selects Uvicorn's websockets-sansio protocol.
44
+ "websockets>=15.0.1,<17",
45
+ ]
46
+
47
+ [project.optional-dependencies]
48
+ # claude: models. Optional because each wheel bundles the Claude Code CLI
49
+ # (about 95 MB to download, 215 MB installed); the sdist would run whatever
50
+ # `claude` is on PATH instead of the CLI version pcode was verified against.
51
+ claude = [
52
+ "claude-agent-sdk>=0.2.160,<0.3",
53
+ ]
54
+
55
+ [project.urls]
56
+ Homepage = "https://github.com/cruxwell/pcode"
57
+ Documentation = "https://cruxwell.github.io/pcode/"
58
+ Source = "https://github.com/cruxwell/pcode"
59
+ Issues = "https://github.com/cruxwell/pcode/issues"
60
+
61
+ [project.scripts]
62
+ pcode = "pcode.cli:main"
63
+ pcode-benchmark = "pcode.profile_benchmark:main"
64
+
65
+ [build-system]
66
+ # 1.27 is the first to accept an SPDX `license` string with `license-files`.
67
+ requires = ["hatchling>=1.27"]
68
+ build-backend = "hatchling.build"
69
+
70
+ [tool.hatch.build.targets.sdist]
71
+ # An explicit list: hatch otherwise ships every non-ignored file, including
72
+ # local scratch under tmp/ and agent config. Tests stay out: they read docs/,
73
+ # dev/, scripts/ and .githooks/ and expect a git checkout.
74
+ include = ["/src", "/LICENSE", "/README.md", "/pyproject.toml"]
75
+
76
+ [tool.hatch.metadata]
77
+ allow-direct-references = true
78
+
79
+ [dependency-groups]
80
+ dev = [
81
+ "pcode[claude]",
82
+ "pytest>=8",
83
+ "pexpect>=4.9; sys_platform != 'win32'",
84
+ "ruff>=0.11",
85
+ "pytest-xdist>=3.6",
86
+ ]
87
+ docs = [
88
+ "zensical>=0.0.63",
89
+ ]
90
+
91
+ [tool.pytest.ini_options]
92
+ testpaths = ["tests"]
93
+ markers = ["tmux: real-tmux layout regression (slow; opt in with --tmux)"]
94
+
95
+ [tool.ruff]
96
+ line-length = 100
97
+
98
+ [tool.ruff.lint]
99
+ select = ["E", "F", "I"]
@@ -0,0 +1,7 @@
1
+ """Scrollback-native terminal UI preview."""
2
+
3
+ import time
4
+
5
+ # When this process first loaded pcode. Modules imported lazily after a merge
6
+ # or reinstall come from newer files than the ones loaded at startup.
7
+ STARTED = time.time()
@@ -0,0 +1,65 @@
1
+ """Detached supervisor: owns one command's lifetime and publishes its exit status.
2
+
3
+ Runs in its own interpreter and its own session so the command survives agent
4
+ run teardown, event-loop shutdown, and pcode itself. It writes `status.json`
5
+ atomically, which is the only thing the parent polls: a supervisor killed
6
+ between publications leaves the last consistent snapshot rather than a partial
7
+ file.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import json
13
+ import os
14
+ import signal
15
+ import subprocess
16
+ import sys
17
+ import time
18
+ from pathlib import Path
19
+
20
+
21
+ def main() -> None: # pragma: no cover -- exercised through a real subprocess.
22
+ directory = Path(sys.argv[1])
23
+ command = sys.argv[2]
24
+ status = directory / "status.json"
25
+ pending = directory / "status.tmp"
26
+
27
+ def publish(*, pid: int, exit_code: int | None, started_at: float) -> None:
28
+ pending.write_text(
29
+ json.dumps(
30
+ {
31
+ "pid": pid,
32
+ "exit_code": exit_code,
33
+ "started_at": started_at,
34
+ "ended_at": None if exit_code is None else time.time(),
35
+ }
36
+ ),
37
+ encoding="utf-8",
38
+ )
39
+ pending.replace(status)
40
+
41
+ with (directory / "output.log").open("ab", buffering=0) as output:
42
+ started_at = time.time()
43
+ process = subprocess.Popen(
44
+ command,
45
+ shell=True,
46
+ stdin=subprocess.DEVNULL,
47
+ stdout=output,
48
+ stderr=output,
49
+ )
50
+ publish(pid=process.pid, exit_code=None, started_at=started_at)
51
+ exit_code = process.wait()
52
+ publish(pid=process.pid, exit_code=exit_code, started_at=started_at)
53
+
54
+
55
+ if __name__ == "__main__": # pragma: no cover
56
+ # The parent starts a new session for us. Ignore terminal hangups without
57
+ # changing how the child command itself handles termination. A stop is
58
+ # SIGTERM to the whole group: survive it here so the command's own exit
59
+ # under it still gets published. A Python handler rather than SIG_IGN,
60
+ # because an ignored disposition is inherited across exec and would make
61
+ # the command itself immune to the stop; a handler resets to default.
62
+ if os.name != "nt":
63
+ signal.signal(signal.SIGHUP, signal.SIG_IGN)
64
+ signal.signal(signal.SIGTERM, lambda *_: None)
65
+ main()