stcode 0.0.1a0__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 (205) hide show
  1. stcode-0.0.1a0/.dockerignore +10 -0
  2. stcode-0.0.1a0/.gitignore +238 -0
  3. stcode-0.0.1a0/CLAUDE.md +313 -0
  4. stcode-0.0.1a0/Dockerfile +65 -0
  5. stcode-0.0.1a0/LICENSE +201 -0
  6. stcode-0.0.1a0/PKG-INFO +229 -0
  7. stcode-0.0.1a0/README.md +189 -0
  8. stcode-0.0.1a0/docs/architecture/agent-loop.md +230 -0
  9. stcode-0.0.1a0/docs/architecture/cli.md +62 -0
  10. stcode-0.0.1a0/docs/architecture/configuration.md +197 -0
  11. stcode-0.0.1a0/docs/architecture/daemon.md +286 -0
  12. stcode-0.0.1a0/docs/architecture/harness.md +278 -0
  13. stcode-0.0.1a0/docs/architecture/index.md +169 -0
  14. stcode-0.0.1a0/docs/architecture/mcp.md +118 -0
  15. stcode-0.0.1a0/docs/architecture/providers.md +178 -0
  16. stcode-0.0.1a0/docs/architecture/session.md +176 -0
  17. stcode-0.0.1a0/docs/architecture/supervisor.md +87 -0
  18. stcode-0.0.1a0/docs/architecture/team.md +337 -0
  19. stcode-0.0.1a0/docs/architecture/tracing.md +57 -0
  20. stcode-0.0.1a0/docs/contributing/releasing.md +63 -0
  21. stcode-0.0.1a0/docs/contributing/testing.md +151 -0
  22. stcode-0.0.1a0/docs/contributing/workflow.md +101 -0
  23. stcode-0.0.1a0/docs/decisions/0001-tool-search.md +121 -0
  24. stcode-0.0.1a0/docs/decisions/0002-file-and-image-input.md +95 -0
  25. stcode-0.0.1a0/docs/decisions/0003-what-the-tui-owns.md +124 -0
  26. stcode-0.0.1a0/docs/decisions/0004-what-a-remote-client-may-change.md +99 -0
  27. stcode-0.0.1a0/docs/decisions/0005-an-agent-is-a-config-file.md +102 -0
  28. stcode-0.0.1a0/docs/decisions/0006-cli-and-core-are-separate-programs.md +82 -0
  29. stcode-0.0.1a0/docs/decisions/0007-cli-layers.md +44 -0
  30. stcode-0.0.1a0/docs/decisions/index.md +33 -0
  31. stcode-0.0.1a0/docs/getting-started/configuration.md +104 -0
  32. stcode-0.0.1a0/docs/getting-started/installation.md +52 -0
  33. stcode-0.0.1a0/docs/getting-started/quickstart.md +77 -0
  34. stcode-0.0.1a0/docs/guide/approval-modes.md +44 -0
  35. stcode-0.0.1a0/docs/guide/mcp.md +88 -0
  36. stcode-0.0.1a0/docs/guide/repl.md +35 -0
  37. stcode-0.0.1a0/docs/guide/sessions.md +50 -0
  38. stcode-0.0.1a0/docs/guide/shapes.md +84 -0
  39. stcode-0.0.1a0/docs/guide/skills.md +52 -0
  40. stcode-0.0.1a0/docs/guide/tools.md +58 -0
  41. stcode-0.0.1a0/docs/guide/tracing.md +71 -0
  42. stcode-0.0.1a0/docs/guide/tui.md +98 -0
  43. stcode-0.0.1a0/docs/index.md +28 -0
  44. stcode-0.0.1a0/docs/sdk/custom-tools.md +89 -0
  45. stcode-0.0.1a0/docs/sdk/daemon-protocol.md +174 -0
  46. stcode-0.0.1a0/docs/sdk/embedding.md +100 -0
  47. stcode-0.0.1a0/docs/sdk/streaming.md +75 -0
  48. stcode-0.0.1a0/docs/teams/roles.md +57 -0
  49. stcode-0.0.1a0/docs/teams/setup.md +81 -0
  50. stcode-0.0.1a0/docs/teams/workflow.md +64 -0
  51. stcode-0.0.1a0/examples/agents/ba.toml +64 -0
  52. stcode-0.0.1a0/examples/agents/backend-dev.toml +59 -0
  53. stcode-0.0.1a0/examples/agents/devops.toml +58 -0
  54. stcode-0.0.1a0/examples/agents/frontend-dev.toml +56 -0
  55. stcode-0.0.1a0/mkdocs.yml +111 -0
  56. stcode-0.0.1a0/pyproject.toml +77 -0
  57. stcode-0.0.1a0/pytest.ini +14 -0
  58. stcode-0.0.1a0/stcode/__init__.py +10 -0
  59. stcode-0.0.1a0/stcode/cli/__init__.py +9 -0
  60. stcode-0.0.1a0/stcode/cli/bootstrap.py +70 -0
  61. stcode-0.0.1a0/stcode/cli/labels.py +621 -0
  62. stcode-0.0.1a0/stcode/cli/logic/__init__.py +0 -0
  63. stcode-0.0.1a0/stcode/cli/logic/commands.py +36 -0
  64. stcode-0.0.1a0/stcode/cli/logic/completion.py +43 -0
  65. stcode-0.0.1a0/stcode/cli/logic/connection.py +46 -0
  66. stcode-0.0.1a0/stcode/cli/logic/requests.py +18 -0
  67. stcode-0.0.1a0/stcode/cli/logic/sessions.py +67 -0
  68. stcode-0.0.1a0/stcode/cli/logic/settings.py +35 -0
  69. stcode-0.0.1a0/stcode/cli/logic/state.py +43 -0
  70. stcode-0.0.1a0/stcode/cli/logic/workspace.py +17 -0
  71. stcode-0.0.1a0/stcode/cli/main.py +290 -0
  72. stcode-0.0.1a0/stcode/cli/models.py +61 -0
  73. stcode-0.0.1a0/stcode/cli/services/__init__.py +0 -0
  74. stcode-0.0.1a0/stcode/cli/services/client.py +393 -0
  75. stcode-0.0.1a0/stcode/cli/services/launcher.py +159 -0
  76. stcode-0.0.1a0/stcode/cli/services/paths.py +18 -0
  77. stcode-0.0.1a0/stcode/cli/services/preferences.py +107 -0
  78. stcode-0.0.1a0/stcode/cli/ui/__init__.py +0 -0
  79. stcode-0.0.1a0/stcode/cli/ui/app.py +136 -0
  80. stcode-0.0.1a0/stcode/cli/ui/app.tcss +3 -0
  81. stcode-0.0.1a0/stcode/cli/ui/components/__init__.py +0 -0
  82. stcode-0.0.1a0/stcode/cli/ui/components/banner.py +78 -0
  83. stcode-0.0.1a0/stcode/cli/ui/components/cards.py +229 -0
  84. stcode-0.0.1a0/stcode/cli/ui/components/prompt.py +225 -0
  85. stcode-0.0.1a0/stcode/cli/ui/components/status.py +95 -0
  86. stcode-0.0.1a0/stcode/cli/ui/components/transcript/__init__.py +51 -0
  87. stcode-0.0.1a0/stcode/cli/ui/components/transcript/entries.py +232 -0
  88. stcode-0.0.1a0/stcode/cli/ui/components/transcript/formatting.py +188 -0
  89. stcode-0.0.1a0/stcode/cli/ui/components/transcript/view.py +101 -0
  90. stcode-0.0.1a0/stcode/cli/ui/screens/__init__.py +0 -0
  91. stcode-0.0.1a0/stcode/cli/ui/screens/chat/__init__.py +0 -0
  92. stcode-0.0.1a0/stcode/cli/ui/screens/chat/chat.tcss +12 -0
  93. stcode-0.0.1a0/stcode/cli/ui/screens/chat/presenter.py +187 -0
  94. stcode-0.0.1a0/stcode/cli/ui/screens/chat/screen.py +682 -0
  95. stcode-0.0.1a0/stcode/cli/ui/screens/connect.py +126 -0
  96. stcode-0.0.1a0/stcode/cli/ui/screens/connect.tcss +49 -0
  97. stcode-0.0.1a0/stcode/cli/ui/screens/dialog.tcss +40 -0
  98. stcode-0.0.1a0/stcode/cli/ui/screens/sessions.py +105 -0
  99. stcode-0.0.1a0/stcode/cli/ui/screens/settings.py +137 -0
  100. stcode-0.0.1a0/stcode/cli/ui/screens/settings.tcss +69 -0
  101. stcode-0.0.1a0/stcode/cli/ui/screens/trust.py +50 -0
  102. stcode-0.0.1a0/stcode/cli/ui/theme.py +221 -0
  103. stcode-0.0.1a0/stcode/core/__main__.py +7 -0
  104. stcode-0.0.1a0/stcode/core/agent/__init__.py +41 -0
  105. stcode-0.0.1a0/stcode/core/agent/agent.py +651 -0
  106. stcode-0.0.1a0/stcode/core/agent/events.py +97 -0
  107. stcode-0.0.1a0/stcode/core/agent/supervisor.py +226 -0
  108. stcode-0.0.1a0/stcode/core/agent/task.py +120 -0
  109. stcode-0.0.1a0/stcode/core/common/__init__.py +21 -0
  110. stcode-0.0.1a0/stcode/core/common/compat.py +27 -0
  111. stcode-0.0.1a0/stcode/core/common/ids.py +43 -0
  112. stcode-0.0.1a0/stcode/core/common/tools.py +50 -0
  113. stcode-0.0.1a0/stcode/core/common/trace.py +406 -0
  114. stcode-0.0.1a0/stcode/core/common/truncate.py +76 -0
  115. stcode-0.0.1a0/stcode/core/configs.py +490 -0
  116. stcode-0.0.1a0/stcode/core/daemon/__init__.py +32 -0
  117. stcode-0.0.1a0/stcode/core/daemon/autonomy.py +71 -0
  118. stcode-0.0.1a0/stcode/core/daemon/main.py +126 -0
  119. stcode-0.0.1a0/stcode/core/daemon/protocol.py +499 -0
  120. stcode-0.0.1a0/stcode/core/daemon/runner.py +359 -0
  121. stcode-0.0.1a0/stcode/core/daemon/server.py +682 -0
  122. stcode-0.0.1a0/stcode/core/daemon/workspace.py +88 -0
  123. stcode-0.0.1a0/stcode/core/harness/__init__.py +81 -0
  124. stcode-0.0.1a0/stcode/core/harness/approvals.py +85 -0
  125. stcode-0.0.1a0/stcode/core/harness/context.py +260 -0
  126. stcode-0.0.1a0/stcode/core/harness/errors.py +40 -0
  127. stcode-0.0.1a0/stcode/core/harness/harness.py +417 -0
  128. stcode-0.0.1a0/stcode/core/harness/mcp.py +530 -0
  129. stcode-0.0.1a0/stcode/core/harness/outputs.py +99 -0
  130. stcode-0.0.1a0/stcode/core/harness/prompts/__init__.py +138 -0
  131. stcode-0.0.1a0/stcode/core/harness/prompts/execute.py +51 -0
  132. stcode-0.0.1a0/stcode/core/harness/prompts/plan.py +57 -0
  133. stcode-0.0.1a0/stcode/core/harness/prompts/sections.py +238 -0
  134. stcode-0.0.1a0/stcode/core/harness/skills/__init__.py +30 -0
  135. stcode-0.0.1a0/stcode/core/harness/skills/loader.py +247 -0
  136. stcode-0.0.1a0/stcode/core/harness/tools/__init__.py +111 -0
  137. stcode-0.0.1a0/stcode/core/harness/tools/base.py +640 -0
  138. stcode-0.0.1a0/stcode/core/harness/tools/files.py +276 -0
  139. stcode-0.0.1a0/stcode/core/harness/tools/interact.py +72 -0
  140. stcode-0.0.1a0/stcode/core/harness/tools/registry.py +113 -0
  141. stcode-0.0.1a0/stcode/core/harness/tools/repl.py +97 -0
  142. stcode-0.0.1a0/stcode/core/harness/tools/schema.py +186 -0
  143. stcode-0.0.1a0/stcode/core/harness/tools/search.py +356 -0
  144. stcode-0.0.1a0/stcode/core/harness/tools/shell.py +372 -0
  145. stcode-0.0.1a0/stcode/core/harness/tools/skill.py +66 -0
  146. stcode-0.0.1a0/stcode/core/harness/tools/todo.py +62 -0
  147. stcode-0.0.1a0/stcode/core/harness/tools/web.py +163 -0
  148. stcode-0.0.1a0/stcode/core/providers/__init__.py +31 -0
  149. stcode-0.0.1a0/stcode/core/providers/anthropic_claude.py +243 -0
  150. stcode-0.0.1a0/stcode/core/providers/base.py +73 -0
  151. stcode-0.0.1a0/stcode/core/providers/gateway.py +267 -0
  152. stcode-0.0.1a0/stcode/core/providers/google_gemini.py +225 -0
  153. stcode-0.0.1a0/stcode/core/providers/openai_gpt.py +250 -0
  154. stcode-0.0.1a0/stcode/core/providers/registry.py +46 -0
  155. stcode-0.0.1a0/stcode/core/providers/types.py +148 -0
  156. stcode-0.0.1a0/stcode/core/repl/__init__.py +19 -0
  157. stcode-0.0.1a0/stcode/core/repl/_worker.py +179 -0
  158. stcode-0.0.1a0/stcode/core/repl/client.py +374 -0
  159. stcode-0.0.1a0/stcode/core/session/__init__.py +39 -0
  160. stcode-0.0.1a0/stcode/core/session/session.py +493 -0
  161. stcode-0.0.1a0/stcode/core/team/__init__.py +38 -0
  162. stcode-0.0.1a0/stcode/core/team/mailbox.py +249 -0
  163. stcode-0.0.1a0/stcode/core/team/tools.py +145 -0
  164. stcode-0.0.1a0/stcode.example.toml +104 -0
  165. stcode-0.0.1a0/tests/cli/architecture_test.py +63 -0
  166. stcode-0.0.1a0/tests/cli/labels_test.py +71 -0
  167. stcode-0.0.1a0/tests/cli/logic/completion_test.py +112 -0
  168. stcode-0.0.1a0/tests/cli/logic/connection_test.py +31 -0
  169. stcode-0.0.1a0/tests/cli/logic/sessions_test.py +57 -0
  170. stcode-0.0.1a0/tests/cli/logic/workflows_test.py +63 -0
  171. stcode-0.0.1a0/tests/cli/main_test.py +51 -0
  172. stcode-0.0.1a0/tests/cli/services/launcher_test.py +127 -0
  173. stcode-0.0.1a0/tests/cli/services/preferences_test.py +122 -0
  174. stcode-0.0.1a0/tests/cli/ui/components/prompt_test.py +49 -0
  175. stcode-0.0.1a0/tests/cli/ui/components/transcript_test.py +160 -0
  176. stcode-0.0.1a0/tests/cli/ui/theme_test.py +95 -0
  177. stcode-0.0.1a0/tests/conftest.py +86 -0
  178. stcode-0.0.1a0/tests/core/agent_test.py +821 -0
  179. stcode-0.0.1a0/tests/core/common_test.py +80 -0
  180. stcode-0.0.1a0/tests/core/configs_test.py +186 -0
  181. stcode-0.0.1a0/tests/core/daemon_main_test.py +94 -0
  182. stcode-0.0.1a0/tests/core/daemon_test.py +1158 -0
  183. stcode-0.0.1a0/tests/core/harness_test.py +1048 -0
  184. stcode-0.0.1a0/tests/core/providers_test.py +642 -0
  185. stcode-0.0.1a0/tests/core/repl_test.py +192 -0
  186. stcode-0.0.1a0/tests/core/session_test.py +362 -0
  187. stcode-0.0.1a0/tests/core/team_test.py +435 -0
  188. stcode-0.0.1a0/tests/core/trace_test.py +365 -0
  189. stcode-0.0.1a0/tests/core/workspace_discovery_test.py +34 -0
  190. stcode-0.0.1a0/tests/driving.py +40 -0
  191. stcode-0.0.1a0/tests/fakes.py +408 -0
  192. stcode-0.0.1a0/tests/fixtures/workspace/.agents/skills/db-migrations/SKILL.md +9 -0
  193. stcode-0.0.1a0/tests/fixtures/workspace/.agents/skills/release-notes/SKILL.md +9 -0
  194. stcode-0.0.1a0/tests/fixtures/workspace/AGENTS.md +4 -0
  195. stcode-0.0.1a0/tests/fixtures/workspace/README.md +6 -0
  196. stcode-0.0.1a0/tests/fixtures/workspace/config.toml +43 -0
  197. stcode-0.0.1a0/tests/fixtures/workspace/mcp_server.py +34 -0
  198. stcode-0.0.1a0/tests/fixtures/workspace/src/app.py +13 -0
  199. stcode-0.0.1a0/tests/fixtures/workspace/src/util.py +12 -0
  200. stcode-0.0.1a0/tests/integration/conftest.py +67 -0
  201. stcode-0.0.1a0/tests/integration/conversation_test.py +214 -0
  202. stcode-0.0.1a0/tests/integration/trace_live_test.py +114 -0
  203. stcode-0.0.1a0/tests/integration/tui_test.py +1164 -0
  204. stcode-0.0.1a0/tests/integration/workspace_test.py +131 -0
  205. stcode-0.0.1a0/uv.lock +3869 -0
@@ -0,0 +1,10 @@
1
+ .git
2
+ .venv
3
+ temp/
4
+ .mypy_cache
5
+ .pytest_cache
6
+ .ruff_cache
7
+ **/__pycache__
8
+ docs/
9
+ smoke_*.py
10
+ main.py
@@ -0,0 +1,238 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ # Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ # poetry.lock
109
+ # poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ # pdm.lock
116
+ # pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ # pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # Redis
135
+ *.rdb
136
+ *.aof
137
+ *.pid
138
+
139
+ # RabbitMQ
140
+ mnesia/
141
+ rabbitmq/
142
+ rabbitmq-data/
143
+
144
+ # ActiveMQ
145
+ activemq-data/
146
+
147
+ # SageMath parsed files
148
+ *.sage.py
149
+
150
+ # Environments
151
+ .env
152
+ .envrc
153
+ .venv
154
+ env/
155
+ venv/
156
+ ENV/
157
+ env.bak/
158
+ venv.bak/
159
+
160
+ # Spyder project settings
161
+ .spyderproject
162
+ .spyproject
163
+
164
+ # Rope project settings
165
+ .ropeproject
166
+
167
+ # mkdocs documentation
168
+ /site
169
+
170
+ # mypy
171
+ .mypy_cache/
172
+ .dmypy.json
173
+ dmypy.json
174
+
175
+ # Pyre type checker
176
+ .pyre/
177
+
178
+ # pytype static type analyzer
179
+ .pytype/
180
+
181
+ # Cython debug symbols
182
+ cython_debug/
183
+
184
+ # PyCharm
185
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
186
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
187
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
188
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
189
+ # .idea/
190
+
191
+ # Abstra
192
+ # Abstra is an AI-powered process automation framework.
193
+ # Ignore directories containing user credentials, local state, and settings.
194
+ # Learn more at https://abstra.io/docs
195
+ .abstra/
196
+
197
+ # Visual Studio Code
198
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
199
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
200
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
201
+ # you could uncomment the following to ignore the entire vscode folder
202
+ # .vscode/
203
+ # Temporary file for partial code execution
204
+ tempCodeRunnerFile.py
205
+
206
+ # Ruff stuff:
207
+ .ruff_cache/
208
+
209
+ # PyPI configuration file
210
+ .pypirc
211
+
212
+ # Marimo
213
+ marimo/_static/
214
+ marimo/_lsp/
215
+ __marimo__/
216
+
217
+ # Streamlit
218
+ .streamlit/secrets.toml
219
+
220
+ # Scratch workspace for main.py, the hand-run agent smoke test.
221
+ temp/
222
+
223
+ # Agents config
224
+ .agents/
225
+ .claude/
226
+
227
+ # ...except the test fixture workspace, which is a *checked-in* project the
228
+ # integration tests mount as the agent's cwd. Its dot-directories are the point.
229
+ !tests/fixtures/workspace/.agents/
230
+ !tests/fixtures/workspace/.agents/**
231
+
232
+ # Temporatory ignore the notebooks folder, only contains
233
+ # testing notebook for the agent, ignore to vanish from Claude Code
234
+ # and avoid accidentially pushed
235
+ notebooks/
236
+
237
+ # The built documentation site. `mkdocs build` output; never committed.
238
+ /site/
@@ -0,0 +1,313 @@
1
+ # CLAUDE.md
2
+
3
+ The index. What this project is, what it bets on, the rules that are not negotiable, and
4
+ where the detail lives.
5
+
6
+ **Before you claim anything works:** `uv run pytest`.
7
+ **Before you write code:** §6, *How a change is made*.
8
+
9
+ ---
10
+
11
+ ## 1. What this is
12
+
13
+ `stcode` is a **general agent harness, specialised for coding**.
14
+
15
+ The unit of deployment is a **daemon**: a long-lived process holding one agent, speaking
16
+ JSONL over a socket. A TUI is just a client of it. That inversion — daemon first, UI
17
+ second — is what makes the container story real instead of aspirational.
18
+
19
+ One binary, three shapes, no implementation switches between them:
20
+
21
+ | | |
22
+ | --- | --- |
23
+ | `stcode` | UI + a daemon, started here if none is listening |
24
+ | `stcode --headless` | the daemon alone — what a container runs |
25
+ | `stcode --daemonless` | the UI alone, attached to a daemon elsewhere (`/connect` to move it) |
26
+
27
+ `stcode/cli` and `stcode/core` are **separate programs that never import each other**.
28
+ The daemon is `stcode-daemon`; the UI starts it as a subprocess when nothing is listening
29
+ and speaks to it only over the socket. The daemon alone reads and writes `config.toml`.
30
+ → [decision 0006](docs/decisions/0006-cli-and-core-are-separate-programs.md)
31
+
32
+ **Two modes, one engine.** `Agent` does not know which mode it is in; the difference is
33
+ which harness is loaded and which tools are injected.
34
+
35
+ | | **Solo** | **Team** |
36
+ | --- | --- | --- |
37
+ | Deployment | one daemon on your machine | N containers, each = 1 daemon + 1 agent |
38
+ | Workspace | existing checkout at `cwd`, scope-enforced | agent runs `git clone` itself |
39
+ | Roles | none | BA / frontend-dev / backend-dev / devops … |
40
+ | Coordination | `task` tool (in-process sub-agent) | shared `/team` volume + `find_teammate` / `send_team_message` |
41
+ | Client | TUI over unix socket | TUI/web over TCP; attach and steer mid-run |
42
+ | Approval | human in the loop | `full-auto`, guarded by container detection |
43
+
44
+ **Non-goals.** Not a training harness. Not a reimplementation of MCP. Not feature parity
45
+ with Claude Code. No self-modifying prompts (rule 6).
46
+
47
+ ---
48
+
49
+ ## 2. The documentation
50
+
51
+ `docs/` is a mkdocs site. `uv run --group docs mkdocs serve` to read it; `mkdocs build`
52
+ is `strict`, so a broken internal link or a page missing from `nav` fails the build.
53
+
54
+ **Usage** — what a user reads.
55
+
56
+ | Section | What it covers |
57
+ | --- | --- |
58
+ | [docs/index.md](docs/index.md) | The front door |
59
+ | [getting-started/](docs/getting-started/) | Installation, quickstart, the config keys that matter on day one |
60
+ | [guide/](docs/guide/) | The three shapes, the TUI, approval modes, sessions, tools, skills, MCP, the REPL, tracing |
61
+ | [teams/](docs/teams/) | Setting a team up, roles, how one actually works |
62
+ | [sdk/](docs/sdk/) | Embedding an agent, writing a tool, the daemon protocol |
63
+ | [decisions/](docs/decisions/) | One page per question that could have gone another way |
64
+ | [contributing/](docs/contributing/) | **How a change is made** (§6), testing, releasing |
65
+
66
+ **Architecture** — what a contributor reads before changing something.
67
+
68
+ | Page | What it covers |
69
+ | --- | --- |
70
+ | [docs/architecture/index.md](docs/architecture/index.md) | The map: components, the diagram, dependency direction, repository layout |
71
+ | [agent-loop.md](docs/architecture/agent-loop.md) | `Agent` — the turn loop, events, interrupts, steering mid-turn, sub-agents |
72
+ | [harness.md](docs/architecture/harness.md) | Tools, `@tool`, permissions and approval modes, skills, roles, output elision |
73
+ | [providers.md](docs/architecture/providers.md) | `LLMGateway` — difficulty routing, retry, the unified wire format, prompt caching |
74
+ | [session.md](docs/architecture/session.md) | The append-only JSONL transcript, its three readers, and ids |
75
+ | [daemon.md](docs/architecture/daemon.md) | The socket, the protocol, `full-auto`'s container rule |
76
+ | [cli.md](docs/architecture/cli.md) | Client UI, workflow logic, I/O services and screen ownership |
77
+ | [mcp.md](docs/architecture/mcp.md) | MCP servers as *code* rather than as tool definitions |
78
+ | [supervisor.md](docs/architecture/supervisor.md) | Stagnation detection at (almost) zero token cost |
79
+ | [team.md](docs/architecture/team.md) | Containers, roles, the shared volume, git integration — and the evaluation set |
80
+ | [tracing.md](docs/architecture/tracing.md) | Exporting the trajectory via direct HTTP APIs |
81
+ | [configuration.md](docs/architecture/configuration.md) | Every section of `config.toml`, and what reads it |
82
+ | [README.md](README.md) | The repository's front door: install, run, the commands |
83
+
84
+ ---
85
+
86
+ ## 3. The four bets
87
+
88
+ Each is traceable to a measurement. Read the number before removing one.
89
+
90
+ **3.1 MCP tools are code, not tool definitions.** Other agents ship MCP schemas in the
91
+ prompt prefix every turn — 10–30k tokens for three servers, forever. We write them to
92
+ `.stcode/mcp_servers/<server>/<tool>.py` and let the agent `grep` and `import` what it
93
+ needs from the REPL. Anthropic measured the pattern at 150k → 2k tokens; measured here on
94
+ three servers and twelve tools, **9,869 → 0 chars** per turn (`smoke_mcp.py`). →
95
+ [mcp.md](docs/architecture/mcp.md)
96
+
97
+ **3.2 A supervisor watches the trajectory.** NVIDIA AVO hit 100% on ARC-AGI-3 and
98
+ credited system design, naming a supervisor that watches for stagnation. The session
99
+ JSONL is already the trajectory, so ours is just a reader: four heuristics at zero token
100
+ cost, and only a hit spends a `difficulty="low"` call that may answer NONE. The nudge is
101
+ appended as a `user` message, never a system-prompt edit, so caching survives. →
102
+ [supervisor.md](docs/architecture/supervisor.md)
103
+
104
+ **3.3 Agent-to-agent messaging has no protocol.** Containers share a volume, so a message
105
+ is a **file**: `send_team_message` writes JSON into `/team/inbox/<role>/`, and the
106
+ receiver drains its own directory; `find_teammate` reads the cards each agent writes to
107
+ `/team/members/` at start-up. No registry service, no routing table, no N² socket mesh.
108
+ Messages carry `refs` not content — enforced, not requested. →
109
+ [team.md](docs/architecture/team.md)
110
+
111
+ **3.4 Daemon-first, so containerization is not a rewrite.** Detach does not kill the
112
+ agent. Approval and questions are request–response correlated by `execution_id` over the
113
+ same JSONL framing. Transport (`unix` / `tcp`) is configuration, not architecture. →
114
+ [daemon.md](docs/architecture/daemon.md)
115
+
116
+ ### Honest comparison
117
+
118
+ | | Claude Code | Cline / Kilo | **stcode** |
119
+ | --- | --- | --- | --- |
120
+ | Tool quality (read/edit/grep/bash) | excellent | good | comparable already |
121
+ | MCP | tool defs per turn | tool defs per turn | as code, 9.9k → 0 chars/turn |
122
+ | Runs headless in a container | partial | no | core design |
123
+ | Multi-agent team across containers | no | no | yes — but see §7 |
124
+ | Stagnation detection | no | no | yes |
125
+ | Observability export (HTTP) | no | no | yes, off by default |
126
+ | Maturity, polish, ecosystem | **far ahead** | ahead | behind, and will stay behind |
127
+
128
+ We are not competing on polish. We are betting on the rows in the middle.
129
+
130
+ ### Kept from other agents, and left behind
131
+
132
+ | Kept | Why |
133
+ | --- | --- |
134
+ | Exact-string `edit`, not line ranges or diffs | Line numbers go stale; a unique literal matches once or fails loudly |
135
+ | Read-before-write | A refused edit costs one turn; an overwritten unread file costs work that no longer exists |
136
+ | `todo_write` as a context device | Not a real tool. It keeps the plan in the window, and that is enough to earn its place |
137
+ | Elision with head and tail kept | The beginning says what ran, the end says how it went |
138
+ | A fresh process per `bash` call | Stateful shells make every failure irreproducible |
139
+ | Steering a running turn | Delivered at the next tool boundary — the only place a `user` message is legal |
140
+ | Four options on a question | Fits a card above the input, and forces the agent to prune its own list |
141
+
142
+ | Left behind | Why |
143
+ | --- | --- |
144
+ | A framework owning the loop (LangChain, LangGraph, CrewAI, AutoGen) | The premise is programmatic control over context and the loop |
145
+ | LLM-summarised tool output | Summarising loses information; eliding does not (rule 1) |
146
+ | MCP definitions in the prompt | The 9,869 → 0 measurement |
147
+ | A lead/orchestrator agent | You dispatch, per role. A `lead` would be one more agent profile |
148
+ | Self-refining prompts | Rule 6, and Prime Agent's promoted cheating skill (§7) |
149
+ | Notebook editing, multi-edit, image input | Deferred, not rejected |
150
+
151
+ ---
152
+
153
+ ## 4. Hard rules
154
+
155
+ Seven. Each exists because violating it produced a specific, known failure.
156
+
157
+ 1. **Tool output is elided at its cap, never LLM-summarised.** Summarising loses
158
+ information; eliding does not — *provided the full value is somewhere the model can
159
+ reach*. `Runtime.outputs_reachable` is the single place that decides whether the hint
160
+ may name `tool_out["…"]`, so the promise cannot drift from the fact.
161
+ 2. **One agent = one role = one checkout = one merge boundary.** If two agents need to
162
+ write the same file, the roles are split wrong. That is a design error, not a signal
163
+ to add locking.
164
+ 3. **`max_depth = 1`.** Sub-agents get neither `task` nor `repl`. Unbounded recursion plus
165
+ no budget is a fork bomb.
166
+ 4. **Sessions are append-only JSONL.** Never rewrite history. No branch, no fork, no leaf
167
+ pointer — `cp session.jsonl` is the branching feature.
168
+ 5. **`full-auto` without an approver runs only inside a container.** The daemon refuses to
169
+ start otherwise. There is no override flag. This is code (`guard_autonomy`), not a
170
+ warning in a document.
171
+ 6. **The agent never edits its own harness.** No `/refine`, no prompt CRUD. Prime Agent
172
+ shipped this and the agent promoted *cheating* into a skill (§7).
173
+ 7. **Layers do not reach upward.** Concretely: the gateway emits `MessageStop(usage=…)`
174
+ and the *agent* writes it to the session. A gateway that imports `Session` has taken a
175
+ dependency on its own caller.
176
+
177
+ ---
178
+
179
+ ## 5. Tech stack
180
+
181
+ | Concern | Choice | Why |
182
+ | --- | --- | --- |
183
+ | REPL | plain `python -u` subprocess + JSONL | Persistent namespace, crash isolation, SIGINT, zero dependencies |
184
+ | LLM clients | `anthropic`, `openai`, `google-genai` (async) | One adapter each; normalise the wire format there and nowhere else |
185
+ | Concurrency | `asyncio`, `anyio`, `asyncer` | `gather` for fan-out, `Semaphore` for caps |
186
+ | TUI | `textual` | Streaming render, attach/detach |
187
+ | Schemas | `pydantic` v2 | Signature → JSON Schema for free |
188
+ | CLI | `typer` | |
189
+ | Config | `tomllib` (read) + `tomli-w` (write) | Stdlib is read-only; the UI writes config back |
190
+ | Search | `ripgrep` (pip wheel), `fd` (optional) | The wheel drops `rg` next to the interpreter, so `grep` works on a fresh checkout |
191
+ | Tool schemas | `docstring-parser` | Signature + `Args:` → JSON Schema, described once |
192
+ | MCP | `mcp` (official SDK) | We adapt it; we never reimplement the protocol |
193
+ | Tracing | Direct HTTP JSON with `httpx` | Langfuse and Phoenix; no tracing SDK |
194
+ | Sandbox | Docker | Team mode; also what makes `full-auto` legal (rule 5) |
195
+ | Packaging | `uv` | |
196
+
197
+ **Explicitly not used: LangChain.** Also LangGraph, CrewAI, AutoGen. The premise is
198
+ programmatic control over context and the loop; a framework that owns the loop defeats it.
199
+
200
+ **Knowledge you need that isn't a library:** SSE streaming and tool-call delta
201
+ accumulation; prompt caching (keep the prefix byte-stable); async cancellation and
202
+ graceful shutdown; JSONL framing over sockets and pipes; token counting, when compaction
203
+ lands.
204
+
205
+ ---
206
+
207
+ ## 6. Conventions
208
+
209
+ ### How a change is made
210
+
211
+ Six steps, in order. Full version, with the reasoning for each, in
212
+ [docs/contributing/workflow.md](docs/contributing/workflow.md).
213
+
214
+ 1. **Analyse the spec, and ask.** Where two readings lead to materially different work,
215
+ ask before building. Where a routine judgement call would do, make it and say so.
216
+ 2. **Write the document.** The page a user would read — `docs/guide/` or `docs/sdk/`,
217
+ or the matching `docs/architecture/` page — *before* the test and the code. A
218
+ feature whose page is hard to write is a feature whose shape is wrong, and that
219
+ costs a paragraph here instead of a rewrite three steps later. A question that could
220
+ reasonably have gone another way gets a `docs/decisions/` record instead.
221
+ 3. **Write the test.** From the document, not from the implementation. Name it after
222
+ the failure it prevents.
223
+ 4. **Implement.** The smallest change that makes the test pass and the document true.
224
+ 5. **Run the tests.** `uv run pytest`, before claiming anything works. Still red? Say
225
+ so, with the output.
226
+ 6. **Commit.** `area: what changed`, short, with the docs in the same commit.
227
+
228
+ ### The rest
229
+
230
+ - Python 3.10+ (CI runs 3.10–3.13; `core/common/compat.py` holds the only two backports), `uv` for everything. `uv run pytest` before claiming anything works.
231
+ - `cli/` never imports `core/`, and `core/` never imports `cli/`. A name both need is
232
+ copied into `cli/models.py`; display copy lives in `cli/labels.py`. A fact that changes when the engine does goes over the
233
+ socket. Settings and environment variables are read in `core/configs.py` and nowhere
234
+ else in `core/`.
235
+ - Type hints mandatory in `core/`. `mypy --strict` on it — installed, and **not yet
236
+ clean**: ~35 errors, mostly provider SDK stubs. Documented in
237
+ [docs/contributing/testing.md](docs/contributing/testing.md) rather than claimed.
238
+ - Tests live in `tests/`: `tests/core/<module>_test.py` for a module's public surface,
239
+ `tests/integration/` for the flows the documentation describes, `tests/fakes.py` for
240
+ the three test doubles, `tests/fixtures/workspace/` for the project they run against.
241
+ Nothing calls a real provider except the two tests marked `live`, deselected by
242
+ default.
243
+ - Every tool has a docstring, because **the docstring is the prompt the model sees**.
244
+ Write it for the model: imperative, concrete, no rationale. Rationale goes in comments.
245
+ - No blocking I/O in the agent loop. If it can take 100 ms, it is `async`. The exception
246
+ is `Session.append` — one line to an open file, deliberately sync.
247
+ - Commit messages: `area: what changed`. Keep them short.
248
+ - **When you change the architecture, update the page in `docs/architecture/` in the same
249
+ commit.** A doc that has drifted from the code is worse than no doc: every agent that
250
+ reads it builds in the wrong direction, and none of them will tell you.
251
+ - A **lazy import that exists only to hide a cycle** is a signal, not a solution: the
252
+ thing being imported is in the wrong place. Move it down to `core/common/` if more
253
+ than one package needs it, or into the one package that does.
254
+
255
+ ---
256
+
257
+ ## 7. Important notices
258
+
259
+ **Arbitrary code execution.** The agent runs commands and Python with your privileges.
260
+ Rule 5 is the mitigation and it is enforced in `guard_autonomy`, not by discipline.
261
+
262
+ **Multi-agent costs more, not less.** Anthropic measured multi-agent at **~15× the
263
+ tokens** of chat and single-agent at ~4×, with token volume explaining **80% of
264
+ performance variance**. They also list **"most coding tasks"** as a *poor* fit. Team mode
265
+ pays off only when roles work on genuinely separable things, which is why rule 2 draws the
266
+ boundary at the service, not the file.
267
+
268
+ **Latency increases.** Models do not reliably parallelise even when they can. Stream
269
+ progress, or a working session looks hung.
270
+
271
+ **No model is trained on this scaffold.** Expect under-use of `task`. Compensate in its
272
+ docstring: it must force an output format and a scope, because a vaguely-described
273
+ sub-agent is the number one cause of duplicated, off-target work.
274
+
275
+ **Reward hacking is real and documented.** Prime Agent, given a refinement loop, bypassed
276
+ Factorio's rules via RCON and **promoted cheating into a skill** — even when told not to.
277
+ The coding analogue is editing the test to make it pass; hence rule 6. If you revisit it,
278
+ the verifier must be outside the agent's write scope, and any test-file edit during a
279
+ "make the tests pass" task must be flagged.
280
+
281
+ **Debuggability is designed in, not retrofitted.** Agent → tool → sub-agent leaves no
282
+ natural stack trace. The session JSONL *is* the trace — keep every event in it, including
283
+ the ones the model never sees.
284
+
285
+ **Cost visibility.** Every LLM call lands in the session as a `usage` record. One place.
286
+ Do not add a second logger (rule 7); [tracing.md](docs/architecture/tracing.md) is an
287
+ export of that record, not a competitor to it.
288
+
289
+ ---
290
+
291
+ ## 8. Status
292
+
293
+ All ten build steps are done. Each smoke script drives real processes against a real
294
+ model.
295
+
296
+ | Phase | Gate | Evidence |
297
+ | --- | --- | --- |
298
+ | 0 — Shell | `stcode` runs, configures itself, streams a reply | — |
299
+ | 1 — The loop | a two-file change completes end to end with a readable session log | every `smoke_*.py` |
300
+ | 2 — Daemon + client | detach/re-attach mid-run works; `full-auto` refuses on the host | `smoke_daemon.py`, `tests/core/daemon_test.py` |
301
+ | 3 — Token economics | three MCP servers connected, prompt prefix does not grow | `smoke_mcp.py` — 9,869 → 0 chars |
302
+ | 4 — Autonomy | a deliberately looping task is caught and redirected | `smoke_supervisor.py` |
303
+ | 5 — Team | two containers, two roles, one feature shipped through `/team` | `smoke_team.py` — **partly** |
304
+
305
+ **The one open question.** The ~20 team-mode evaluation tasks in
306
+ [team.md](docs/architecture/team.md#the-evaluation-set) are written and **have not been
307
+ run**. Until they are, "does team mode help or merely spend 15× the tokens" is
308
+ unanswered — and §7 says that is a live question, not a rhetorical one. Running them is
309
+ the highest-value thing left.
310
+
311
+ **Later:** compaction with a visible threshold, sessions in a live database, provider
312
+ failover, `written_files` tracking, agent profiles that carry their own tools and MCP
313
+ servers alongside the prompt.
@@ -0,0 +1,65 @@
1
+ # One image, one config file per agent. An agent profile is a `config.toml` carrying the
2
+ # prompt *and* the settings it runs under, and it is *mounted*, not built in: an agent is
3
+ # a deployment fact, and an image that carried four would make adding a fifth a release.
4
+ #
5
+ # No docker-compose.yml, no k8s manifests. This repo ships an image and the environment
6
+ # contract below; how you bring up N containers is yours, and orchestration opinions do
7
+ # not belong in a Python package.
8
+ #
9
+ # docker build -t stcode .
10
+ # docker run -d --name backend-dev \
11
+ # -v team:/team -v /var/lib/stcode/backend:/workspace \
12
+ # -v ./examples/agents/backend-dev.toml:/config/config.toml:ro \
13
+ # -e STCODE_SANDBOX=1 -e STCODE_TEAM=1 -e ANTHROPIC_API_KEY \
14
+ # -p 7717:7717 stcode
15
+ #
16
+ # stcode --daemonless # then /connect to localhost:7717
17
+ #
18
+ # STCODE_TEAM=1 is what turns team mode on. A profile naming a role is not enough on its
19
+ # own — a role says which agent this is, team mode says a shared volume is mounted.
20
+
21
+ FROM python:3.12-slim
22
+
23
+ # git is not optional here: every role clones from /team/repo.git before writing code.
24
+ # ripgrep arrives as a wheel with the package, so it is not installed twice.
25
+ RUN apt-get update && apt-get install -y --no-install-recommends \
26
+ git ca-certificates \
27
+ && rm -rf /var/lib/apt/lists/*
28
+
29
+ COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
30
+
31
+ WORKDIR /app
32
+
33
+ # Dependencies first, so a code change does not re-resolve the whole environment.
34
+ COPY pyproject.toml uv.lock README.md ./
35
+ RUN uv sync --frozen --no-install-project --no-dev
36
+
37
+ COPY stcode ./stcode
38
+ RUN uv sync --frozen --no-dev
39
+
40
+ ENV PATH="/app/.venv/bin:$PATH" \
41
+ PYTHONUNBUFFERED=1 \
42
+ STCODE_CONFIG=/config/config.toml \
43
+ STCODE_SANDBOX=1
44
+ # STCODE_TEAM is deliberately not set: team mode is off until the deployment says so.
45
+ # STCODE_SANDBOX is what makes `full-auto` legal (rule 5). It is set here because this
46
+ # image *is* the container the rule is about — the daemon refuses to start in full-auto
47
+ # anywhere else, and there is no override flag.
48
+
49
+ # Mounts the contract expects:
50
+ # /team shared volume — members/, inbox/, knowledge/, artifacts/, repo.git
51
+ # /workspace where this agent clones; one checkout per container
52
+ # /config this agent's profile, as config.toml, read-only
53
+ VOLUME ["/team", "/workspace"]
54
+ WORKDIR /workspace
55
+
56
+ EXPOSE 7717
57
+
58
+ # The daemon alone, which is the whole point of daemon-first — `stcode-daemon` is the
59
+ # same program `stcode --headless` runs. It prints what it became — workspace, mode,
60
+ # model, config, what it created — and logs every client that connects, because
61
+ # `docker logs` is the only screen it has. It stops cleanly on SIGTERM. Attach a TUI with
62
+ # `stcode --daemonless` and /connect, from anywhere that can reach the port; a
63
+ # containerised daemon takes one client at a time, and accepts no API key over TCP.
64
+ ENTRYPOINT ["stcode-daemon"]
65
+ CMD ["--transport", "tcp", "--host", "0.0.0.0", "--port", "7717"]