agent-shell-py 0.3.2__tar.gz → 0.5.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 (185) hide show
  1. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/.github/workflows/build.yml +13 -2
  2. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/.github/workflows/ci.yml +15 -2
  3. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/.gitignore +9 -0
  4. agent_shell_py-0.5.0/AGENTS.md +115 -0
  5. agent_shell_py-0.5.0/PKG-INFO +120 -0
  6. agent_shell_py-0.5.0/README.md +111 -0
  7. agent_shell_py-0.5.0/docs/architecture/class_diagram.md +501 -0
  8. agent_shell_py-0.5.0/docs/architecture/dependency_boundaries.md +88 -0
  9. agent_shell_py-0.5.0/docs/assets/agentshell-banner.png +0 -0
  10. agent_shell_py-0.5.0/docs/assets/agentshell-banner.svg +1 -0
  11. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/docs/development/agent_parameter_comparison.md +113 -1
  12. agent_shell_py-0.5.0/docs/development/import_linter_audit.md +79 -0
  13. agent_shell_py-0.5.0/docs/development/issue_25_plan.md +64 -0
  14. agent_shell_py-0.5.0/docs/development/package_management.md +64 -0
  15. agent_shell_py-0.3.2/PKG-INFO → agent_shell_py-0.5.0/docs/examples.md +229 -127
  16. agent_shell_py-0.5.0/examples/interactive_demo.py +129 -0
  17. agent_shell_py-0.5.0/pyproject.toml +133 -0
  18. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/__init__.py +4 -1
  19. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/_version.py +2 -2
  20. agent_shell_py-0.5.0/src/agent_shell/adapters/agent_adapter_protocol.py +3 -0
  21. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/claude_code_adapter.py +108 -27
  22. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/codex_adapter.py +73 -26
  23. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/copilot_cli_adapter.py +97 -27
  24. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/cursor_adapter.py +85 -26
  25. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/grok_adapter.py +101 -26
  26. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/health.py +2 -0
  27. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/opencode_adapter.py +111 -27
  28. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/pi_adapter.py +264 -27
  29. agent_shell_py-0.5.0/src/agent_shell/adapters/pi_resources.py +97 -0
  30. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/response.py +15 -3
  31. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/tool_denial.py +6 -0
  32. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/execution.py +7 -79
  33. agent_shell_py-0.5.0/src/agent_shell/interactive.py +196 -0
  34. agent_shell_py-0.5.0/src/agent_shell/interactive_event_writer.py +19 -0
  35. agent_shell_py-0.5.0/src/agent_shell/interactive_terminal.py +287 -0
  36. agent_shell_py-0.5.0/src/agent_shell/interactive_worker.py +111 -0
  37. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/models/agent.py +12 -0
  38. agent_shell_py-0.5.0/src/agent_shell/models/resources.py +25 -0
  39. agent_shell_py-0.5.0/src/agent_shell/ports/__init__.py +1 -0
  40. agent_shell_py-0.3.2/src/agent_shell/adapters/agent_adapter_protocol.py → agent_shell_py-0.5.0/src/agent_shell/ports/agent.py +23 -3
  41. agent_shell_py-0.5.0/src/agent_shell/ports/execution.py +84 -0
  42. agent_shell_py-0.5.0/src/agent_shell/ports/interactive.py +68 -0
  43. agent_shell_py-0.5.0/src/agent_shell/ports/resources.py +28 -0
  44. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/process_cleanup.py +7 -68
  45. agent_shell_py-0.5.0/src/agent_shell/process_guardian.py +98 -0
  46. agent_shell_py-0.5.0/src/agent_shell/resources.py +162 -0
  47. agent_shell_py-0.5.0/src/agent_shell/shell.py +253 -0
  48. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/tmux.py +178 -73
  49. agent_shell_py-0.5.0/src/agent_shell/tmux_ownership.py +39 -0
  50. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_codex_e2e.py +9 -2
  51. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_execution_host_e2e.py +4 -2
  52. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_health_check_e2e.py +9 -3
  53. agent_shell_py-0.5.0/tests/e2e/test_interactive_attachment_e2e.py +60 -0
  54. agent_shell_py-0.5.0/tests/e2e/test_interactive_harness_e2e.py +136 -0
  55. agent_shell_py-0.5.0/tests/e2e/test_pi_packages_e2e.py +114 -0
  56. agent_shell_py-0.5.0/tests/e2e/test_session_resources_e2e.py +190 -0
  57. agent_shell_py-0.5.0/tests/integration/test_architecture.py +296 -0
  58. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_health_check_integration.py +18 -0
  59. agent_shell_py-0.5.0/tests/integration/test_interactive_agents.py +549 -0
  60. agent_shell_py-0.5.0/tests/integration/test_interactive_attachment.py +342 -0
  61. agent_shell_py-0.5.0/tests/integration/test_interactive_terminal.py +748 -0
  62. agent_shell_py-0.5.0/tests/integration/test_packages_unsupported.py +20 -0
  63. agent_shell_py-0.5.0/tests/integration/test_pi_packages.py +337 -0
  64. agent_shell_py-0.5.0/tests/integration/test_session_resources.py +778 -0
  65. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_tmux_execution_host.py +45 -21
  66. agent_shell_py-0.5.0/tests/unit/test_interactive_attachment.py +93 -0
  67. agent_shell_py-0.5.0/tests/unit/test_package_spec.py +10 -0
  68. agent_shell_py-0.5.0/tests/unit/test_port_exports.py +36 -0
  69. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_process_cleanup.py +1 -1
  70. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_shell.py +10 -10
  71. agent_shell_py-0.5.0/tests/unit/test_shell_cancellation.py +32 -0
  72. agent_shell_py-0.5.0/uv.lock +244 -0
  73. agent_shell_py-0.3.2/AGENTS.md +0 -300
  74. agent_shell_py-0.3.2/README.md +0 -542
  75. agent_shell_py-0.3.2/docs/assets/skill_banner.png +0 -0
  76. agent_shell_py-0.3.2/pyproject.toml +0 -33
  77. agent_shell_py-0.3.2/src/agent_shell/shell.py +0 -181
  78. agent_shell_py-0.3.2/tests/unit/test_shell_cancellation.py +0 -72
  79. agent_shell_py-0.3.2/uv.lock +0 -104
  80. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/.github/workflows/publish.yml +0 -0
  81. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/.python-version +0 -0
  82. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/LICENSE +0 -0
  83. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/docs/development/disabled_tools.md +0 -0
  84. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/docs/development/info.md +0 -0
  85. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/docs/development/total_token_count.md +0 -0
  86. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/skills/delegating-code-review/SKILL.md +0 -0
  87. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/skills/invoking-cli-agents/SKILL.md +0 -0
  88. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/skills/invoking-cli-agents/api-reference.md +0 -0
  89. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/__init__.py +0 -0
  90. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/model_discovery.py +0 -0
  91. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/outcome.py +0 -0
  92. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/process_failure.py +0 -0
  93. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/stderr_format.py +0 -0
  94. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/herdr.py +0 -0
  95. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/herdr_protocol.py +0 -0
  96. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/herdr_worker.py +0 -0
  97. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/models/__init__.py +0 -0
  98. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/terminal_protocol.py +0 -0
  99. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/terminal_window.py +0 -0
  100. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/terminal_worker.py +0 -0
  101. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/tmux_bridge.py +0 -0
  102. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/tmux_protocol.py +0 -0
  103. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/__init__.py +0 -0
  104. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/conftest.py +0 -0
  105. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/__init__.py +0 -0
  106. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_claude_code_e2e.py +0 -0
  107. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_copilot_cli_e2e.py +0 -0
  108. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_cursor_e2e.py +0 -0
  109. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_grok_e2e.py +0 -0
  110. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_model_discovery_e2e.py +0 -0
  111. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_opencode_e2e.py +0 -0
  112. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_pi_e2e.py +0 -0
  113. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_terminal_window_execution_host_e2e.py +0 -0
  114. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_tmux_execution_host_e2e.py +0 -0
  115. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/__init__.py +0 -0
  116. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_claude_code_integration.py +0 -0
  117. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_claude_code_mcp_integration.py +0 -0
  118. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_codex_integration.py +0 -0
  119. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_codex_mcp_integration.py +0 -0
  120. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_copilot_cli_integration.py +0 -0
  121. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_copilot_cli_mcp_integration.py +0 -0
  122. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_cursor_integration.py +0 -0
  123. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_cursor_mcp_integration.py +0 -0
  124. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_execution_host.py +0 -0
  125. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_grok_integration.py +0 -0
  126. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_grok_mcp_integration.py +0 -0
  127. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_herdr_execution_host.py +0 -0
  128. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_model_discovery_integration.py +0 -0
  129. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_opencode_integration.py +0 -0
  130. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_opencode_mcp_integration.py +0 -0
  131. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_pi_integration.py +0 -0
  132. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_pi_mcp_integration.py +0 -0
  133. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_process_lifecycle.py +0 -0
  134. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_terminal_window_execution_host.py +0 -0
  135. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/__init__.py +0 -0
  136. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/adapter_matrix.py +0 -0
  137. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/codex_fixtures.py +0 -0
  138. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/copilot_fixtures.py +0 -0
  139. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/cursor_fixtures.py +0 -0
  140. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/fixtures.py +0 -0
  141. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/grok_fixtures.py +0 -0
  142. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/opencode_fixtures.py +0 -0
  143. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/pi_fixtures.py +0 -0
  144. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_adapter_transport.py +0 -0
  145. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_cancel.py +0 -0
  146. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_codex_cancel.py +0 -0
  147. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_codex_execute.py +0 -0
  148. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_codex_parse_event.py +0 -0
  149. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_codex_warnings.py +0 -0
  150. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_copilot_cli_cancel.py +0 -0
  151. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_copilot_cli_execute.py +0 -0
  152. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_copilot_cli_parse_event.py +0 -0
  153. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_copilot_cli_stream.py +0 -0
  154. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_cursor_cancel.py +0 -0
  155. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_cursor_execute.py +0 -0
  156. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_cursor_parse_event.py +0 -0
  157. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_cursor_warnings.py +0 -0
  158. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_execute.py +0 -0
  159. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_execute_outcome.py +0 -0
  160. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_grok_cancel.py +0 -0
  161. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_grok_execute.py +0 -0
  162. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_grok_parse_event.py +0 -0
  163. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_grok_warnings.py +0 -0
  164. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_health_probe.py +0 -0
  165. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_mcp_server_spec.py +0 -0
  166. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_model_discovery.py +0 -0
  167. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_models.py +0 -0
  168. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_opencode_cancel.py +0 -0
  169. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_opencode_execute.py +0 -0
  170. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_opencode_parse_event.py +0 -0
  171. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_opencode_spawn.py +0 -0
  172. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_opencode_stream.py +0 -0
  173. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_parse_event.py +0 -0
  174. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_pi_cancel.py +0 -0
  175. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_pi_execute.py +0 -0
  176. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_pi_parse_event.py +0 -0
  177. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_pi_warnings.py +0 -0
  178. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_process_group_registration.py +0 -0
  179. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_public_exports.py +0 -0
  180. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_response_aggregation.py +0 -0
  181. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_shell_mcp.py +0 -0
  182. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_stderr_format.py +0 -0
  183. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_stream.py +0 -0
  184. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_terminal_window_execution_host.py +0 -0
  185. {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_tool_denial.py +0 -0
@@ -4,6 +4,13 @@ on:
4
4
  push:
5
5
  tags: ["v*"]
6
6
 
7
+ permissions:
8
+ contents: read
9
+
10
+ concurrency:
11
+ group: ${{ github.workflow }}-${{ github.ref }}
12
+ cancel-in-progress: true
13
+
7
14
  jobs:
8
15
  build:
9
16
  runs-on: ubuntu-latest
@@ -12,6 +19,7 @@ jobs:
12
19
  - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
13
20
  with:
14
21
  fetch-depth: 0
22
+ persist-credentials: false
15
23
 
16
24
  - name: Install uv
17
25
  uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
@@ -20,10 +28,13 @@ jobs:
20
28
  run: uv python install 3.12
21
29
 
22
30
  - name: Install dependencies
23
- run: uv sync --group dev && uv pip install -e .
31
+ run: uv sync --locked --group dev
32
+
33
+ - name: Check architecture boundaries
34
+ run: uv run --no-sync lint-imports --no-cache
24
35
 
25
36
  - name: Run unit and integration tests
26
- run: uv run pytest tests/unit tests/integration -v
37
+ run: uv run --no-sync pytest tests/unit tests/integration -v
27
38
 
28
39
  - name: Build package
29
40
  run: uv build
@@ -6,15 +6,25 @@ on:
6
6
  pull_request:
7
7
  branches: [main]
8
8
 
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
9
16
  jobs:
10
17
  test:
11
18
  runs-on: ubuntu-latest
12
19
  strategy:
20
+ fail-fast: false
13
21
  matrix:
14
22
  python-version: ["3.12"]
15
23
 
16
24
  steps:
17
25
  - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
26
+ with:
27
+ persist-credentials: false
18
28
 
19
29
  - name: Install uv
20
30
  uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
@@ -23,7 +33,10 @@ jobs:
23
33
  run: uv python install ${{ matrix.python-version }}
24
34
 
25
35
  - name: Install dependencies
26
- run: uv sync --group dev && uv pip install -e .
36
+ run: uv sync --locked --group dev
37
+
38
+ - name: Check architecture boundaries
39
+ run: uv run --no-sync lint-imports --no-cache
27
40
 
28
41
  - name: Run unit and integration tests
29
- run: uv run pytest tests/unit tests/integration -v
42
+ run: uv run --no-sync pytest tests/unit tests/integration -v
@@ -9,3 +9,12 @@ src/agent_shell/_version.py
9
9
 
10
10
  # Virtual environments
11
11
  .venv
12
+
13
+ # Local Pi workspace data
14
+ /.pi/
15
+
16
+ # Local credentials
17
+ /.env
18
+
19
+ # Local SonarQube configuration and scanner output
20
+ /.sonarqube/
@@ -0,0 +1,115 @@
1
+ # Agent Shell
2
+
3
+ A lightweight, async Python package that executes CLI coding agents headlessly and returns output
4
+ through a unified interface. Each agent's CLI differences are hidden behind a common adapter
5
+ protocol, so consuming code never changes regardless of which agent is running underneath.
6
+
7
+ ## Architecture
8
+
9
+ Before any planning, discussion of solution or code change work begins, you must read the
10
+ [architecture class diagram](docs/architecture/class_diagram.md). It documents the interfaces,
11
+ execution hosts, isolation policies, interactive sessions, and API behaviour.
12
+
13
+ Keep agent-specific CLI flags, raw output parsing, configuration formats, and workarounds in
14
+ that agent's adapter or agent-specific helpers. Shared code must use protocols and normalised
15
+ models, not agent-name branches, concrete-adapter checks, private adapter state, or copied
16
+ agent-specific logic. Host-specific terminal/process details belong in execution hosts.
17
+ Concrete agent-adapter imports are permitted only in `shell.py` for construction/selection;
18
+ shared helpers under `adapters/` are not exempt. Import Linter contracts in `pyproject.toml`
19
+ enforce the [dependency boundaries](docs/architecture/dependency_boundaries.md), including
20
+ indirect imports. New inner code uses `ports/`, not implementation-bearing compatibility
21
+ facades. New top-level modules and adapter helpers must be classified in the contracts.
22
+ Review must still catch copied agent-specific logic and dynamic imports.
23
+ If a shared contract cannot express a feature, discuss the boundary change before adding a
24
+ workaround or weakening the test.
25
+
26
+ ## Supported Agents
27
+
28
+ - [x] Claude Code
29
+ - [x] OpenCode
30
+ - [x] Copilot CLI
31
+ - [x] Codex
32
+ - [x] Pi
33
+ - [x] Cursor
34
+ - [x] Grok
35
+
36
+ ## MCP Server Configuration
37
+
38
+ `AgentShell` exposes a unified API for registering MCP servers across all supported agents:
39
+
40
+ ```python
41
+ from agent_shell.shell import AgentShell
42
+ from agent_shell.models.agent import AgentType, MCPServerSpec, MCPServerType
43
+
44
+ shell = AgentShell(agent_type=AgentType.CLAUDE_CODE)
45
+
46
+ await shell.add_mcp_server(MCPServerSpec(
47
+ name="forgetful",
48
+ type=MCPServerType.STDIO,
49
+ command="uvx",
50
+ args=["forgetful-ai"],
51
+ env={"FORGETFUL_API_KEY": "..."},
52
+ ))
53
+ ```
54
+
55
+ All adapters write to user-scope configuration:
56
+
57
+ | Agent | Mechanism | Location |
58
+ |-------|-----------|----------|
59
+ | Claude Code | `claude mcp add --scope user` subprocess | `~/.claude.json` (managed by CLI) |
60
+ | OpenCode | direct JSON file write | `~/.config/opencode/opencode.json` |
61
+ | Copilot CLI | direct JSON file write | `~/.copilot/mcp-config.json` |
62
+ | Codex | `codex mcp add` subprocess | Codex config |
63
+ | Cursor | direct JSON file write | `~/.cursor/mcp.json` |
64
+ | Grok | `grok mcp add --scope user` subprocess | `~/.grok/config.toml` (managed by CLI) |
65
+
66
+ Adds are idempotent (update existing entries with the same name). Cursor preserves native fields
67
+ that `MCPServerSpec` cannot represent when an update keeps the same transport, and writes its file
68
+ atomically with user-only permissions. Removes warn rather than raise when the named server is not
69
+ found. Claude Code listing reads the user-scope `mcpServers`
70
+ entries from `~/.claude.json` directly, avoiding the health checks and human-readable output of
71
+ `claude mcp list`. Cursor manages user-scope MCP entries directly in `~/.cursor/mcp.json` because
72
+ its `mcp` subcommands have no add/remove commands. Grok listing reads user-scope `mcp_servers`
73
+ entries from `~/.grok/config.toml` directly for the same reason. Pi's MCP add/remove/list methods
74
+ raise `NotImplementedError`.
75
+
76
+ ## Package Management
77
+
78
+ See [package management](docs/development/package_management.md) for the API, Pi behaviour,
79
+ scope, and validation details.
80
+
81
+ ## Test Philosophy
82
+
83
+ Tests validate real functionality, not code coverage metrics. Three tiers, each with a distinct
84
+ purpose:
85
+
86
+ | Tier | Scope | Runs in CI | Real CLI calls |
87
+ |------|-------|-----------|----------------|
88
+ | **Unit** | Isolated parsing, adapter resolution, input validation | Yes | No |
89
+ | **Integration** | Shell -> adapter -> parser, with mocked agent subprocess | Yes | No |
90
+ | **E2E** | Real CLI calls; usually real API costs | No (local only) | Yes |
91
+
92
+ The model-discovery E2E test is the exception: it calls all seven real CLIs but only reads
93
+ metadata, so it sends no inference request and incurs no model-token cost.
94
+
95
+ Integration tests mirror the E2E tests but substitute mocked subprocesses emitting captured CLI
96
+ output fixtures. This lets CI validate the full class interaction chain without credentials or API
97
+ spend. E2E tests remain local smoke tests for the real agents.
98
+
99
+ All tests follow the **AAA pattern** (Arrange, Act, Assert).
100
+
101
+ ```bash
102
+ # Architecture contracts (development dependency only)
103
+ uv run --locked lint-imports --no-cache
104
+
105
+ # CI suite (unit + integration, including deliberate boundary violations in temp copies)
106
+ uv run --locked pytest tests/unit tests/integration -v
107
+
108
+ # Full suite including E2E (requires agent CLI + credentials)
109
+ uv run pytest -v
110
+ ```
111
+
112
+ ## CI/CD
113
+
114
+ - **CI**: Runs architecture contracts and unit + integration tests on every push and PR
115
+ - **Build**: Triggers on `v*` tags, runs contracts/tests then builds release artifacts
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.5
2
+ Name: agent-shell-py
3
+ Version: 0.5.0
4
+ Summary: A lightweight abstraction for executing CLI coding agents headlessly
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.12
8
+ Description-Content-Type: text/markdown
9
+
10
+ ![AgentShell — run CLI coding agents from Python](docs/assets/agentshell-banner.png?v=rounded)
11
+
12
+ <h1 align="center">Agent Shell</h1>
13
+ Agent Shell is a light weight abstraction for executing a cli coding agent headlessly
14
+ and returning the output that can be used programatically as a unified contract
15
+
16
+ ## Features
17
+
18
+ - **One unified contract** — the same `execute`, `stream`, `health_check`, and
19
+ `list_models` API across every agent; swap the backend without changing consuming code.
20
+ - **Seven CLI agents** — Claude Code, OpenCode, Copilot CLI, Codex, Pi, Cursor, and Grok
21
+ behind a common adapter protocol.
22
+ - **Execute or stream** — get one `AgentResponse` (raises `AgentExecutionError` on a failed run),
23
+ or async-iterate normalized `StreamEvent`s with optional thinking/reasoning.
24
+ - **Composable execution policy** — preserve native execution by default, or opt into Linux PID
25
+ namespace isolation without changing an agent adapter.
26
+ - **Session resumption** — continue any conversation by passing back its `session_id`.
27
+ - **Normalized cost & tokens** — consistent `cost` and `output_tokens` (reasoning included)
28
+ regardless of how each CLI reports them.
29
+ - **Model discovery** — retrieve the exact account/workspace-aware model strings accepted by
30
+ each CLI, without inference calls, SDK dependencies, or static catalogs.
31
+ - **Health checks** — confirm an agent + model combination actually works before you rely on
32
+ it, read from the event stream rather than unreliable exit codes.
33
+ - **Portable tool control** — one canonical allow/deny vocabulary
34
+ (`bash, edit, read, web_search, web_fetch`) translated to each CLI's own tool names.
35
+ - **Unified MCP management** — register, remove, and list MCP servers across agents through a
36
+ single API.
37
+ - **Package management** — install/register, list, and remove harness packages through a shared
38
+ API, with Pi as the first supported agent.
39
+ - **Async & dependency-free** — pure `asyncio`, zero runtime dependencies, Python 3.12+.
40
+
41
+ ## Installation
42
+
43
+ ```bash
44
+ uv add agent-shell-py
45
+ ```
46
+
47
+ or with pip:
48
+
49
+ ```bash
50
+ pip install agent-shell-py
51
+ ```
52
+
53
+ ## Agent skills
54
+
55
+ The repository includes reusable skills that teach coding agents how to use AgentShell:
56
+
57
+ - `invoking-cli-agents` — invoke, stream, resume, and restrict CLI agents.
58
+ - `delegating-code-review` — delegate an independent code review through AgentShell.
59
+
60
+ Install them interactively with the Vercel Skills CLI:
61
+
62
+ ```bash
63
+ npx skills add ScottRBK/agent-shell
64
+ ```
65
+
66
+ Or install both skills globally for every coding agent supported by AgentShell:
67
+
68
+ ```bash
69
+ npx skills add ScottRBK/agent-shell --global \
70
+ --skill '*' \
71
+ --agent claude-code opencode github-copilot codex pi cursor grok \
72
+ --yes
73
+ ```
74
+
75
+ Install only the core AgentShell skill with:
76
+
77
+ ```bash
78
+ npx skills add ScottRBK/agent-shell --skill invoking-cli-agents
79
+ ```
80
+
81
+ The skills provide agent instructions. Install `agent-shell-py` and the chosen coding-agent CLIs
82
+ separately.
83
+
84
+ ## Examples
85
+
86
+ ### Execute
87
+
88
+ ```python
89
+ from agent_shell.shell import AgentShell
90
+ from agent_shell.models.agent import AgentType
91
+
92
+ shell = AgentShell(agent_type=AgentType.CLAUDE_CODE)
93
+
94
+ response = await shell.execute(
95
+ cwd="/path/to/project",
96
+ prompt="Can you tell me about this project?",
97
+ allowed_tools=["Read", "Glob", "Grep"],
98
+ model="sonnet",
99
+ )
100
+
101
+ print(response.response)
102
+ print(f"Cost: ${response.cost:.4f}")
103
+ print(f"Output tokens: {response.output_tokens}") # billed output, reasoning included
104
+ print(f"Session: {response.session_id}")
105
+
106
+ # Resume the conversation using the session_id
107
+ follow_up = await shell.execute(
108
+ cwd="/path/to/project",
109
+ prompt="Now refactor the auth module based on your findings",
110
+ allowed_tools=["Read", "Edit", "Bash"],
111
+ model="sonnet",
112
+ session_id=response.session_id,
113
+ )
114
+ ```
115
+
116
+ > `output_tokens` is a cost measure: the billed output-token count, which **includes reasoning
117
+ > tokens** (they are billed at the output rate). It is reported consistently across all adapters.
118
+
119
+ See [more examples](docs/examples.md) for isolation and execution hosts, failure handling,
120
+ streaming, model discovery, health checks, tool restrictions, MCP servers, packages, and logging.
@@ -0,0 +1,111 @@
1
+ ![AgentShell — run CLI coding agents from Python](docs/assets/agentshell-banner.png?v=rounded)
2
+
3
+ <h1 align="center">Agent Shell</h1>
4
+ Agent Shell is a light weight abstraction for executing a cli coding agent headlessly
5
+ and returning the output that can be used programatically as a unified contract
6
+
7
+ ## Features
8
+
9
+ - **One unified contract** — the same `execute`, `stream`, `health_check`, and
10
+ `list_models` API across every agent; swap the backend without changing consuming code.
11
+ - **Seven CLI agents** — Claude Code, OpenCode, Copilot CLI, Codex, Pi, Cursor, and Grok
12
+ behind a common adapter protocol.
13
+ - **Execute or stream** — get one `AgentResponse` (raises `AgentExecutionError` on a failed run),
14
+ or async-iterate normalized `StreamEvent`s with optional thinking/reasoning.
15
+ - **Composable execution policy** — preserve native execution by default, or opt into Linux PID
16
+ namespace isolation without changing an agent adapter.
17
+ - **Session resumption** — continue any conversation by passing back its `session_id`.
18
+ - **Normalized cost & tokens** — consistent `cost` and `output_tokens` (reasoning included)
19
+ regardless of how each CLI reports them.
20
+ - **Model discovery** — retrieve the exact account/workspace-aware model strings accepted by
21
+ each CLI, without inference calls, SDK dependencies, or static catalogs.
22
+ - **Health checks** — confirm an agent + model combination actually works before you rely on
23
+ it, read from the event stream rather than unreliable exit codes.
24
+ - **Portable tool control** — one canonical allow/deny vocabulary
25
+ (`bash, edit, read, web_search, web_fetch`) translated to each CLI's own tool names.
26
+ - **Unified MCP management** — register, remove, and list MCP servers across agents through a
27
+ single API.
28
+ - **Package management** — install/register, list, and remove harness packages through a shared
29
+ API, with Pi as the first supported agent.
30
+ - **Async & dependency-free** — pure `asyncio`, zero runtime dependencies, Python 3.12+.
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ uv add agent-shell-py
36
+ ```
37
+
38
+ or with pip:
39
+
40
+ ```bash
41
+ pip install agent-shell-py
42
+ ```
43
+
44
+ ## Agent skills
45
+
46
+ The repository includes reusable skills that teach coding agents how to use AgentShell:
47
+
48
+ - `invoking-cli-agents` — invoke, stream, resume, and restrict CLI agents.
49
+ - `delegating-code-review` — delegate an independent code review through AgentShell.
50
+
51
+ Install them interactively with the Vercel Skills CLI:
52
+
53
+ ```bash
54
+ npx skills add ScottRBK/agent-shell
55
+ ```
56
+
57
+ Or install both skills globally for every coding agent supported by AgentShell:
58
+
59
+ ```bash
60
+ npx skills add ScottRBK/agent-shell --global \
61
+ --skill '*' \
62
+ --agent claude-code opencode github-copilot codex pi cursor grok \
63
+ --yes
64
+ ```
65
+
66
+ Install only the core AgentShell skill with:
67
+
68
+ ```bash
69
+ npx skills add ScottRBK/agent-shell --skill invoking-cli-agents
70
+ ```
71
+
72
+ The skills provide agent instructions. Install `agent-shell-py` and the chosen coding-agent CLIs
73
+ separately.
74
+
75
+ ## Examples
76
+
77
+ ### Execute
78
+
79
+ ```python
80
+ from agent_shell.shell import AgentShell
81
+ from agent_shell.models.agent import AgentType
82
+
83
+ shell = AgentShell(agent_type=AgentType.CLAUDE_CODE)
84
+
85
+ response = await shell.execute(
86
+ cwd="/path/to/project",
87
+ prompt="Can you tell me about this project?",
88
+ allowed_tools=["Read", "Glob", "Grep"],
89
+ model="sonnet",
90
+ )
91
+
92
+ print(response.response)
93
+ print(f"Cost: ${response.cost:.4f}")
94
+ print(f"Output tokens: {response.output_tokens}") # billed output, reasoning included
95
+ print(f"Session: {response.session_id}")
96
+
97
+ # Resume the conversation using the session_id
98
+ follow_up = await shell.execute(
99
+ cwd="/path/to/project",
100
+ prompt="Now refactor the auth module based on your findings",
101
+ allowed_tools=["Read", "Edit", "Bash"],
102
+ model="sonnet",
103
+ session_id=response.session_id,
104
+ )
105
+ ```
106
+
107
+ > `output_tokens` is a cost measure: the billed output-token count, which **includes reasoning
108
+ > tokens** (they are billed at the output rate). It is reported consistently across all adapters.
109
+
110
+ See [more examples](docs/examples.md) for isolation and execution hosts, failure handling,
111
+ streaming, model discovery, health checks, tool restrictions, MCP servers, packages, and logging.