inspect-steward 0.2.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 (138) hide show
  1. inspect_steward-0.2.0/.gitignore +225 -0
  2. inspect_steward-0.2.0/LICENSE +21 -0
  3. inspect_steward-0.2.0/PKG-INFO +54 -0
  4. inspect_steward-0.2.0/README.md +26 -0
  5. inspect_steward-0.2.0/pyproject.toml +239 -0
  6. inspect_steward-0.2.0/src/inspect_steward/__init__.py +21 -0
  7. inspect_steward-0.2.0/src/inspect_steward/__main__.py +9 -0
  8. inspect_steward-0.2.0/src/inspect_steward/_anomaly/__init__.py +0 -0
  9. inspect_steward-0.2.0/src/inspect_steward/_anomaly/applied.py +230 -0
  10. inspect_steward-0.2.0/src/inspect_steward/_anomaly/fold.py +792 -0
  11. inspect_steward-0.2.0/src/inspect_steward/_anomaly/model.py +409 -0
  12. inspect_steward-0.2.0/src/inspect_steward/_cli/__init__.py +0 -0
  13. inspect_steward-0.2.0/src/inspect_steward/_cli/ack.py +155 -0
  14. inspect_steward-0.2.0/src/inspect_steward/_cli/anomalies.py +160 -0
  15. inspect_steward-0.2.0/src/inspect_steward/_cli/collect.py +59 -0
  16. inspect_steward-0.2.0/src/inspect_steward/_cli/init.py +78 -0
  17. inspect_steward-0.2.0/src/inspect_steward/_cli/investigate.py +68 -0
  18. inspect_steward-0.2.0/src/inspect_steward/_cli/items.py +48 -0
  19. inspect_steward-0.2.0/src/inspect_steward/_cli/launch.py +976 -0
  20. inspect_steward-0.2.0/src/inspect_steward/_cli/main.py +64 -0
  21. inspect_steward-0.2.0/src/inspect_steward/_cli/mark.py +23 -0
  22. inspect_steward-0.2.0/src/inspect_steward/_cli/note.py +33 -0
  23. inspect_steward-0.2.0/src/inspect_steward/_cli/notify.py +97 -0
  24. inspect_steward-0.2.0/src/inspect_steward/_cli/options.py +265 -0
  25. inspect_steward-0.2.0/src/inspect_steward/_cli/pause.py +79 -0
  26. inspect_steward-0.2.0/src/inspect_steward/_cli/propose.py +222 -0
  27. inspect_steward-0.2.0/src/inspect_steward/_cli/raise_item.py +155 -0
  28. inspect_steward-0.2.0/src/inspect_steward/_cli/ramp.py +119 -0
  29. inspect_steward-0.2.0/src/inspect_steward/_cli/rule.py +396 -0
  30. inspect_steward-0.2.0/src/inspect_steward/_cli/runbook.py +17 -0
  31. inspect_steward-0.2.0/src/inspect_steward/_cli/signoff.py +280 -0
  32. inspect_steward-0.2.0/src/inspect_steward/_cli/status.py +61 -0
  33. inspect_steward-0.2.0/src/inspect_steward/_cli/tasks.py +101 -0
  34. inspect_steward-0.2.0/src/inspect_steward/_cli/tend.py +84 -0
  35. inspect_steward-0.2.0/src/inspect_steward/_cli/timer.py +171 -0
  36. inspect_steward-0.2.0/src/inspect_steward/_cli/turn.py +272 -0
  37. inspect_steward-0.2.0/src/inspect_steward/_evalset/__init__.py +0 -0
  38. inspect_steward-0.2.0/src/inspect_steward/_evalset/archive.py +103 -0
  39. inspect_steward-0.2.0/src/inspect_steward/_evalset/cache.py +182 -0
  40. inspect_steward-0.2.0/src/inspect_steward/_evalset/classify.py +389 -0
  41. inspect_steward-0.2.0/src/inspect_steward/_evalset/command.py +178 -0
  42. inspect_steward-0.2.0/src/inspect_steward/_evalset/cost.py +132 -0
  43. inspect_steward-0.2.0/src/inspect_steward/_evalset/detect.py +262 -0
  44. inspect_steward-0.2.0/src/inspect_steward/_evalset/display.py +177 -0
  45. inspect_steward-0.2.0/src/inspect_steward/_evalset/instances.py +556 -0
  46. inspect_steward-0.2.0/src/inspect_steward/_evalset/manifest.py +283 -0
  47. inspect_steward-0.2.0/src/inspect_steward/_evalset/observe.py +728 -0
  48. inspect_steward-0.2.0/src/inspect_steward/_evalset/read.py +208 -0
  49. inspect_steward-0.2.0/src/inspect_steward/_launch/__init__.py +24 -0
  50. inspect_steward-0.2.0/src/inspect_steward/_launch/delta.py +483 -0
  51. inspect_steward-0.2.0/src/inspect_steward/_launch/launch.py +1079 -0
  52. inspect_steward-0.2.0/src/inspect_steward/_launch/pools.py +230 -0
  53. inspect_steward-0.2.0/src/inspect_steward/_marks/__init__.py +23 -0
  54. inspect_steward-0.2.0/src/inspect_steward/_marks/edit.py +331 -0
  55. inspect_steward-0.2.0/src/inspect_steward/_marks/run.py +474 -0
  56. inspect_steward-0.2.0/src/inspect_steward/_marks/spawn.py +100 -0
  57. inspect_steward-0.2.0/src/inspect_steward/_marks/state.py +257 -0
  58. inspect_steward-0.2.0/src/inspect_steward/_notify/__init__.py +47 -0
  59. inspect_steward-0.2.0/src/inspect_steward/_notify/channel.py +267 -0
  60. inspect_steward-0.2.0/src/inspect_steward/_notify/dialect.py +78 -0
  61. inspect_steward-0.2.0/src/inspect_steward/_notify/post.py +122 -0
  62. inspect_steward-0.2.0/src/inspect_steward/_notify/render.py +93 -0
  63. inspect_steward-0.2.0/src/inspect_steward/_notify/send.py +145 -0
  64. inspect_steward-0.2.0/src/inspect_steward/_registry.py +8 -0
  65. inspect_steward-0.2.0/src/inspect_steward/_scan/__init__.py +41 -0
  66. inspect_steward-0.2.0/src/inspect_steward/_scan/bracket.py +288 -0
  67. inspect_steward-0.2.0/src/inspect_steward/_scan/builtin.py +28 -0
  68. inspect_steward-0.2.0/src/inspect_steward/_scan/findings.py +242 -0
  69. inspect_steward-0.2.0/src/inspect_steward/_scan/integrity.py +344 -0
  70. inspect_steward-0.2.0/src/inspect_steward/_scan/model.py +33 -0
  71. inspect_steward-0.2.0/src/inspect_steward/_scan/summary.py +240 -0
  72. inspect_steward-0.2.0/src/inspect_steward/_schedule/__init__.py +51 -0
  73. inspect_steward-0.2.0/src/inspect_steward/_schedule/reconcile.py +1041 -0
  74. inspect_steward-0.2.0/src/inspect_steward/_signoff/__init__.py +41 -0
  75. inspect_steward-0.2.0/src/inspect_steward/_signoff/curate.py +88 -0
  76. inspect_steward-0.2.0/src/inspect_steward/_signoff/gate.py +280 -0
  77. inspect_steward-0.2.0/src/inspect_steward/_signoff/sign.py +931 -0
  78. inspect_steward-0.2.0/src/inspect_steward/_smoke/__init__.py +54 -0
  79. inspect_steward-0.2.0/src/inspect_steward/_smoke/checks.py +426 -0
  80. inspect_steward-0.2.0/src/inspect_steward/_smoke/digest.py +419 -0
  81. inspect_steward-0.2.0/src/inspect_steward/_smoke/run.py +1184 -0
  82. inspect_steward-0.2.0/src/inspect_steward/_store/__init__.py +33 -0
  83. inspect_steward-0.2.0/src/inspect_steward/_store/copy.py +70 -0
  84. inspect_steward-0.2.0/src/inspect_steward/_store/directory.py +183 -0
  85. inspect_steward-0.2.0/src/inspect_steward/_store/flow.py +164 -0
  86. inspect_steward-0.2.0/src/inspect_steward/_store/match.py +83 -0
  87. inspect_steward-0.2.0/src/inspect_steward/_store/store.py +213 -0
  88. inspect_steward-0.2.0/src/inspect_steward/_tend/__init__.py +89 -0
  89. inspect_steward-0.2.0/src/inspect_steward/_tend/analysis_md.py +319 -0
  90. inspect_steward-0.2.0/src/inspect_steward/_tend/anomalies_md.py +589 -0
  91. inspect_steward-0.2.0/src/inspect_steward/_tend/coverage.py +124 -0
  92. inspect_steward-0.2.0/src/inspect_steward/_tend/detect.py +334 -0
  93. inspect_steward-0.2.0/src/inspect_steward/_tend/history.py +383 -0
  94. inspect_steward-0.2.0/src/inspect_steward/_tend/items.py +1655 -0
  95. inspect_steward-0.2.0/src/inspect_steward/_tend/notify.py +729 -0
  96. inspect_steward-0.2.0/src/inspect_steward/_tend/progress.py +573 -0
  97. inspect_steward-0.2.0/src/inspect_steward/_tend/render.py +768 -0
  98. inspect_steward-0.2.0/src/inspect_steward/_tend/rulings.py +1105 -0
  99. inspect_steward-0.2.0/src/inspect_steward/_tend/table.py +234 -0
  100. inspect_steward-0.2.0/src/inspect_steward/_tend/tuning.py +779 -0
  101. inspect_steward-0.2.0/src/inspect_steward/_tend/turn.py +2610 -0
  102. inspect_steward-0.2.0/src/inspect_steward/_timer/__init__.py +47 -0
  103. inspect_steward-0.2.0/src/inspect_steward/_timer/arm.py +230 -0
  104. inspect_steward-0.2.0/src/inspect_steward/_timer/cron.py +198 -0
  105. inspect_steward-0.2.0/src/inspect_steward/_timer/entry.py +155 -0
  106. inspect_steward-0.2.0/src/inspect_steward/_timer/launchd.py +107 -0
  107. inspect_steward-0.2.0/src/inspect_steward/_timer/scheduler.py +106 -0
  108. inspect_steward-0.2.0/src/inspect_steward/_timer/systemd.py +133 -0
  109. inspect_steward-0.2.0/src/inspect_steward/_util/__init__.py +0 -0
  110. inspect_steward-0.2.0/src/inspect_steward/_util/duration.py +105 -0
  111. inspect_steward-0.2.0/src/inspect_steward/_util/jsonl.py +184 -0
  112. inspect_steward-0.2.0/src/inspect_steward/_util/process.py +52 -0
  113. inspect_steward-0.2.0/src/inspect_steward/_util/size.py +17 -0
  114. inspect_steward-0.2.0/src/inspect_steward/_version.py +24 -0
  115. inspect_steward-0.2.0/src/inspect_steward/_worker/__init__.py +124 -0
  116. inspect_steward-0.2.0/src/inspect_steward/_worker/acp.py +29 -0
  117. inspect_steward-0.2.0/src/inspect_steward/_worker/ctl.py +458 -0
  118. inspect_steward-0.2.0/src/inspect_steward/_worker/inflight.py +367 -0
  119. inspect_steward-0.2.0/src/inspect_steward/_worker/interim.py +131 -0
  120. inspect_steward-0.2.0/src/inspect_steward/_worker/live.py +912 -0
  121. inspect_steward-0.2.0/src/inspect_steward/_worker/spawn.py +387 -0
  122. inspect_steward-0.2.0/src/inspect_steward/_worker/stop.py +269 -0
  123. inspect_steward-0.2.0/src/inspect_steward/_worker/usage.py +95 -0
  124. inspect_steward-0.2.0/src/inspect_steward/_workspace/__init__.py +209 -0
  125. inspect_steward-0.2.0/src/inspect_steward/_workspace/claim.py +373 -0
  126. inspect_steward-0.2.0/src/inspect_steward/_workspace/create.py +258 -0
  127. inspect_steward-0.2.0/src/inspect_steward/_workspace/directives.py +883 -0
  128. inspect_steward-0.2.0/src/inspect_steward/_workspace/journal.py +846 -0
  129. inspect_steward-0.2.0/src/inspect_steward/_workspace/layout.py +397 -0
  130. inspect_steward-0.2.0/src/inspect_steward/_workspace/log.py +83 -0
  131. inspect_steward-0.2.0/src/inspect_steward/_workspace/operator.py +37 -0
  132. inspect_steward-0.2.0/src/inspect_steward/_workspace/overrides.py +196 -0
  133. inspect_steward-0.2.0/src/inspect_steward/_workspace/sync.py +450 -0
  134. inspect_steward-0.2.0/src/inspect_steward/_workspace/templates/_steward.yaml +2 -0
  135. inspect_steward-0.2.0/src/inspect_steward/_workspace/templates/agents.md +59 -0
  136. inspect_steward-0.2.0/src/inspect_steward/_workspace/templates/evalset.txt +9 -0
  137. inspect_steward-0.2.0/src/inspect_steward/_workspace/templates/gitignore.txt +4 -0
  138. inspect_steward-0.2.0/src/inspect_steward/_workspace/templates/runbook.md +313 -0
@@ -0,0 +1,225 @@
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
+ # Jupyter Notebook
75
+ .ipynb_checkpoints
76
+
77
+ # IPython
78
+ profile_default/
79
+ ipython_config.py
80
+
81
+ # pyenv
82
+ # For a library or package, you might want to ignore these files since the code is
83
+ # intended to run in multiple environments; otherwise, check them in:
84
+ # .python-version
85
+
86
+ # pipenv
87
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
88
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
89
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
90
+ # install all needed dependencies.
91
+ #Pipfile.lock
92
+
93
+ # UV
94
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
95
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
96
+ # commonly ignored for libraries.
97
+ #uv.lock
98
+
99
+ # poetry
100
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
101
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
102
+ # commonly ignored for libraries.
103
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
104
+ #poetry.lock
105
+ #poetry.toml
106
+
107
+ # pdm
108
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
109
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
110
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
111
+ #pdm.lock
112
+ #pdm.toml
113
+ .pdm-python
114
+ .pdm-build/
115
+
116
+ # pixi
117
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
118
+ #pixi.lock
119
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
120
+ # in the .venv directory. It is recommended not to include this directory in version control.
121
+ .pixi
122
+
123
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
124
+ __pypackages__/
125
+
126
+ # Celery stuff
127
+ celerybeat-schedule
128
+ celerybeat.pid
129
+
130
+ # SageMath parsed files
131
+ *.sage.py
132
+
133
+ # Environments
134
+ .env
135
+ .envrc
136
+ .venv*
137
+ env/
138
+ venv/
139
+ ENV/
140
+ env.bak/
141
+ venv.bak/
142
+
143
+ # Spyder project settings
144
+ .spyderproject
145
+ .spyproject
146
+
147
+ # Rope project settings
148
+ .ropeproject
149
+
150
+ # mkdocs documentation
151
+ /site
152
+
153
+ # pyright
154
+ .pyright/
155
+
156
+ # Pyre type checker
157
+ .pyre/
158
+
159
+ # pytype static type analyzer
160
+ .pytype/
161
+
162
+ # mypy type checker
163
+ .mypy_cache/
164
+
165
+ # Cython debug symbols
166
+ cython_debug/
167
+
168
+ # PyCharm
169
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
170
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
171
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
172
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
173
+ #.idea/
174
+
175
+ # Abstra
176
+ # Abstra is an AI-powered process automation framework.
177
+ # Ignore directories containing user credentials, local state, and settings.
178
+ # Learn more at https://abstra.io/docs
179
+ .abstra/
180
+
181
+ # Visual Studio Code
182
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
183
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
184
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
185
+ # you could uncomment the following to ignore the entire vscode folder
186
+ # .vscode/
187
+
188
+ # Ruff stuff:
189
+ .ruff_cache/
190
+
191
+ # PyPI configuration file
192
+ .pypirc
193
+
194
+ # Cursor
195
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
196
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
197
+ # refer to https://docs.cursor.com/context/ignore-files
198
+ .cursorignore
199
+ .cursorindexingignore
200
+
201
+ # Marimo
202
+ marimo/_static/
203
+ marimo/_lsp/
204
+ __marimo__/
205
+
206
+ # Dynamic version
207
+ src/inspect_steward/_version.py
208
+
209
+ # Inspect logs and scans
210
+ /logs/
211
+ /logs-*/
212
+ /runs/
213
+ /scans/
214
+ /transcripts/
215
+
216
+ # MacOS
217
+ .DS_Store
218
+
219
+ # Claude Code
220
+ **/.claude/settings.local.json
221
+ .claude
222
+
223
+ # Quarto Docs
224
+ /.luarc.json
225
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Meridian Labs
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.
@@ -0,0 +1,54 @@
1
+ Metadata-Version: 2.5
2
+ Name: inspect_steward
3
+ Version: 0.2.0
4
+ Summary: An agent that supervises evaluations, monitoring progress, diagnosing problems, and adjusting runtime state on your behalf.
5
+ Project-URL: Source Code, https://github.com/meridianlabs-ai/inspect_steward
6
+ Project-URL: Issue Tracker, https://github.com/meridianlabs-ai/inspect_steward/issues
7
+ Author: Meridian Labs
8
+ License: MIT License
9
+ License-File: LICENSE
10
+ Classifier: Operating System :: MacOS
11
+ Classifier: Operating System :: POSIX :: Linux
12
+ Requires-Python: >=3.12
13
+ Requires-Dist: apprise>=1.9
14
+ Requires-Dist: click>=8.0
15
+ Requires-Dist: httpx>=0.27
16
+ Requires-Dist: inspect-ai>=0.3.263
17
+ Requires-Dist: inspect-scout>=0.5.0
18
+ Requires-Dist: platformdirs>=4.0
19
+ Requires-Dist: psutil>=5.9
20
+ Requires-Dist: python-dotenv>=1.0
21
+ Requires-Dist: pyyaml>=6.0
22
+ Provides-Extra: flow
23
+ Requires-Dist: inspect-flow>=0.12.0; extra == 'flow'
24
+ Provides-Extra: hawk
25
+ Requires-Dist: hawk[cli,runner]>=2.4.0; (python_version >= '3.13') and extra == 'hawk'
26
+ Requires-Dist: uv>=0.5; (python_version >= '3.13') and extra == 'hawk'
27
+ Description-Content-Type: text/markdown
28
+
29
+ # Inspect Steward
30
+
31
+ Welcome to Inspect Steward, an agent that supervises evaluations on your behalf.
32
+
33
+ Steward plays the role of the human sitting in front of a running eval. It:
34
+
35
+ - Watches progress as a run unfolds
36
+ - Diagnoses problems as they surface
37
+ - Adjusts runtime state in response
38
+
39
+ A steward acts on behalf of someone who isn't there. That's the relationship this package models: you start a run and step away, and the steward minds it.
40
+
41
+ Concretely, Steward runs each task of an eval set in its own process — so one crash costs one task rather than the run, and CPU-bound work actually runs in parallel — and reconciles the log directory against what your definition asks for on a schedule. A timer guarantees that happens with nobody watching; what needs judgement waits for someone who can exercise it.
42
+
43
+ ```bash
44
+ pip install inspect-steward
45
+
46
+ steward init my-sweep # create a workspace
47
+ steward tasks evalset.py # see what a definition resolves to, before running it
48
+ steward launch # start it, arm the timer, and return
49
+ steward status # ask how it's going, whenever you like
50
+ ```
51
+
52
+ Steward runs on macOS and Linux. Windows is not supported: a run has to outlive the process that started it, and the detached-process, control-socket, and process-table mechanisms that achieve it are POSIX-only.
53
+
54
+ Learn more about using Steward at <https://meridianlabs-ai.github.io/inspect_steward>.
@@ -0,0 +1,26 @@
1
+ # Inspect Steward
2
+
3
+ Welcome to Inspect Steward, an agent that supervises evaluations on your behalf.
4
+
5
+ Steward plays the role of the human sitting in front of a running eval. It:
6
+
7
+ - Watches progress as a run unfolds
8
+ - Diagnoses problems as they surface
9
+ - Adjusts runtime state in response
10
+
11
+ A steward acts on behalf of someone who isn't there. That's the relationship this package models: you start a run and step away, and the steward minds it.
12
+
13
+ Concretely, Steward runs each task of an eval set in its own process — so one crash costs one task rather than the run, and CPU-bound work actually runs in parallel — and reconciles the log directory against what your definition asks for on a schedule. A timer guarantees that happens with nobody watching; what needs judgement waits for someone who can exercise it.
14
+
15
+ ```bash
16
+ pip install inspect-steward
17
+
18
+ steward init my-sweep # create a workspace
19
+ steward tasks evalset.py # see what a definition resolves to, before running it
20
+ steward launch # start it, arm the timer, and return
21
+ steward status # ask how it's going, whenever you like
22
+ ```
23
+
24
+ Steward runs on macOS and Linux. Windows is not supported: a run has to outlive the process that started it, and the detached-process, control-socket, and process-table mechanisms that achieve it are POSIX-only.
25
+
26
+ Learn more about using Steward at <https://meridianlabs-ai.github.io/inspect_steward>.
@@ -0,0 +1,239 @@
1
+ [project]
2
+ name = "inspect_steward"
3
+ dynamic = ["version"]
4
+ description = "An agent that supervises evaluations, monitoring progress, diagnosing problems, and adjusting runtime state on your behalf."
5
+ authors = [{ name = "Meridian Labs" }]
6
+ readme = "README.md"
7
+ requires-python = ">=3.12"
8
+ license = { text = "MIT License" }
9
+ # POSIX only, and deliberately so: Steward's central requirement is that a run
10
+ # outlives the process that started it, which it achieves by spawning workers
11
+ # into their own session. Windows has no equivalent that `subprocess` reaches
12
+ # the same way, and the rest of the design leans the same direction (AF_UNIX
13
+ # control sockets, process-table identification). Supporting it would be a
14
+ # second execution model rather than a flag, so it is declined rather than
15
+ # deferred. Classifiers are metadata, not enforcement — pip will still install
16
+ # here; nothing pretends the guarantee holds.
17
+ classifiers = [
18
+ "Operating System :: POSIX :: Linux",
19
+ "Operating System :: MacOS",
20
+ ]
21
+ dependencies = [
22
+ # the released wheels carry what this project needs since 2026-09-04 --
23
+ # record-only selection scanning, the ambient scan-model default, the
24
+ # `log_dir` default for `eval_set()`, scout's unique summary tmp names --
25
+ # so these floors are the whole story; only `inspect-harbor` still resolves
26
+ # through `[tool.uv.sources]` below, for the reason given there
27
+ "inspect-ai>=0.3.263",
28
+ "inspect-scout>=0.5.0",
29
+ "click>=8.0",
30
+ "pyyaml>=6.0",
31
+ # the process table is how Steward finds a worker that has not yet reached
32
+ # its eval, and so has no log and no control-discovery entry. inspect-ai
33
+ # depends on psutil too, but this is a direct import and a transitive
34
+ # dependency is not a promise.
35
+ "psutil>=5.9",
36
+ # a worker's control server is HTTP over an AF_UNIX socket, and reading a
37
+ # running fleet for `status` goes to it directly rather than through
38
+ # `inspect ctl` (see _worker/live.py). inspect-ai depends on httpx too, but
39
+ # this is a direct import and a transitive dependency is not a promise.
40
+ "httpx>=0.27",
41
+ # arming a timer checks which credentials a workspace's `.env` really
42
+ # defines, and only the resolved value answers that -- `KEY=""` and
43
+ # `KEY=${UNSET}` both look like assignments and both arrive as nothing. Read
44
+ # with the same parser inspect will use so the two cannot disagree.
45
+ # inspect-ai depends on python-dotenv too, but this is a direct import and a
46
+ # transitive dependency is not a promise.
47
+ "python-dotenv>=1.0",
48
+ # notification is the gate on autonomy rather than a nicety (workflow.md
49
+ # §11): an unattended run that cannot reach a person is the failure the
50
+ # whole design exists to prevent. inspect-ai makes apprise optional because
51
+ # an eval that never asks a human needs no channel; a supervisor always
52
+ # might, so a workspace must not be able to configure a channel Steward
53
+ # then cannot reach.
54
+ "apprise>=1.9",
55
+ # `log_store: auto` names the machine's own store, which is a per-platform
56
+ # data directory rather than a path Steward could hardcode. inspect-flow
57
+ # depends on platformdirs too — and resolving `auto` through *flow* would
58
+ # make the common case pay the `[flow]` extra to find out where it is
59
+ # pointing, which is the whole thing the directory implementation exists to
60
+ # avoid. A direct import, and a transitive dependency is not a promise.
61
+ "platformdirs>=4.0",
62
+ ]
63
+
64
+ [project.optional-dependencies]
65
+ flow = ["inspect_flow>=0.12.0"]
66
+ # cli: the `python -m hawk` click entry point Steward invokes.
67
+ # runner: hawk.runner.run_eval_set imports k8s_sandbox at module scope.
68
+ # uv: hawk shells out to `uv pip install` on every invocation but does not
69
+ # declare it, so without this the extra installs and then fails at the first
70
+ # read with FileNotFoundError. Ours to carry until hawk declares it.
71
+ # Declaring it is necessary but not sufficient: pip puts the binary beside
72
+ # the interpreter, and hawk resolves a bare `uv` through PATH, which only
73
+ # contains that directory when the venv happens to be activated. The hawk
74
+ # branch of `definition_command` prepends it for the child process.
75
+ #
76
+ # Marker-gated because hawk requires Python 3.13 and inspect_steward does not.
77
+ # An extra is opt-in, so hawk's floor binds only those who ask for hawk: on
78
+ # 3.12 the extra resolves to nothing and hawk support is simply unavailable.
79
+ #
80
+ # No upper bound, but note the coupling it leaves open: the hawk test fixture
81
+ # names `hawk/e2e_hello`, hawk's own internal smoke-test task, because
82
+ # `--direct` installs nothing new and it is the only registered task available
83
+ # without one. A hawk release that renames or drops it breaks that fixture with
84
+ # no change on our side.
85
+ hawk = [
86
+ "hawk[cli,runner]>=2.4.0; python_version >= '3.13'",
87
+ "uv>=0.5; python_version >= '3.13'",
88
+ ]
89
+
90
+ [project.urls]
91
+ "Source Code" = "https://github.com/meridianlabs-ai/inspect_steward"
92
+ "Issue Tracker" = "https://github.com/meridianlabs-ai/inspect_steward/issues"
93
+
94
+ [build-system]
95
+ requires = ["hatchling", "hatch-vcs"]
96
+ build-backend = "hatchling.build"
97
+
98
+ [project.entry-points.inspect_ai]
99
+ inspect_steward = "inspect_steward._registry"
100
+
101
+ [project.scripts]
102
+ steward = "inspect_steward._cli.main:main"
103
+
104
+
105
+ [dependency-groups]
106
+ dev = [
107
+ "ruff",
108
+ "pytest",
109
+ "pyright",
110
+ "pytest-xdist",
111
+ "pytest-dotenv",
112
+ "pytest-timeout>=2.4.0",
113
+ "types-psutil", # psutil ships no inline types and pyright runs strict
114
+ "inspect_flow>=0.12.0", # for the flow definition tests
115
+ # for the hawk definition tests; 3.13+ only, so those tests skip on 3.12
116
+ "hawk[cli,runner]>=2.4.0; python_version >= '3.13'",
117
+ "uv>=0.5; python_version >= '3.13'",
118
+ # the eval-set definitions under runs/ import inspect_harbor and name
119
+ # openai/ and anthropic/ models. inspect-ai makes provider SDKs optional
120
+ # because an eval that never calls a provider needs none, so nothing else
121
+ # here pulls them in and a `uv sync` takes them back out again — which is
122
+ # how a workspace that ran clean an hour ago comes back
123
+ # ModuleNotFoundError. The floors are inspect's own gates
124
+ # (`validate_openai_client`, `validate_anthropic_client`), not guesses.
125
+ "openai>=3.1.0",
126
+ "anthropic>=1.0.0",
127
+ "inspect_harbor",
128
+ "inspect-sandboxes",
129
+ {include-group = "doc"},
130
+ ]
131
+ doc = [
132
+ "jupyter",
133
+ "panflute",
134
+ "markdown",
135
+ "griffe>=2",
136
+ "rich",
137
+ "pyyaml",
138
+ "types-PyYAML",
139
+ "quarto-cli>=1.9.36",
140
+ ]
141
+ dist = ["twine", "build"]
142
+
143
+ [tool.hatch.build]
144
+ only-packages = true
145
+ exclude = ["docs/", "tests/"]
146
+ artifacts = ["src/**/*.yaml", "src/**/*.md", "src/**/*.txt"]
147
+
148
+ [tool.hatch.version]
149
+ source = "vcs"
150
+
151
+ [tool.hatch.build.hooks.vcs]
152
+ version-file = "src/inspect_steward/_version.py"
153
+
154
+ [tool.hatch.version.raw-options]
155
+ local_scheme = "no-local-version" # Important for PyPI compatibility
156
+
157
+ [tool.hatch.metadata]
158
+ allow-direct-references = true
159
+
160
+ [tool.uv]
161
+ managed = true
162
+ # openai, for a conflict that has no satisfying resolution: harbor depends on
163
+ # litellm, which caps `openai>=2.20.0,<3.0.0`, while inspect-ai's OpenAI
164
+ # provider gates on `openai>=3.1.0`. Left alone uv resolves it the only way it
165
+ # can — by walking inspect-harbor back to 0.4.17 and harbor to 0.2.0, which
166
+ # predate the registry tasks the runs/ definitions name, so the lock "succeeds"
167
+ # and the eval set then fails to import its own tasks. The override says take
168
+ # inspect's floor and let litellm's cap go unmet. That is a real claim, not a
169
+ # formality: it ships a combination litellm declares unsupported. It holds
170
+ # because nothing on the inspect path calls litellm — harbor's use of it is in
171
+ # its own orchestrators, which Steward's runs never enter. Revisit when litellm
172
+ # widens the cap; the pin can go the day `litellm` accepts openai 3.x.
173
+ override-dependencies = ["openai"]
174
+
175
+ [tool.uv.sources]
176
+
177
+ # inspect-harbor from git rather than PyPI, because the registry tasks the
178
+ # runs/ definitions name (cais/swebenchpro, datacurve/deep-swe) reach the
179
+ # generated `_tasks.py` ahead of a release: the logs of the last clean run
180
+ # record `inspect_harbor: 0.7.6.dev1`, a commit past the 0.7.5 wheel. A run
181
+ # resolved to the wheel is a different eval, and the task identifier hash says
182
+ # so.
183
+ inspect-harbor = { git = "https://github.com/meridianlabs-ai/inspect_harbor", branch = "main" }
184
+
185
+ [tool.ruff]
186
+ extend-exclude = ["docs"]
187
+ src = ["."]
188
+
189
+ [tool.ruff.lint]
190
+ select = [
191
+ "E", # pycodestyle errors
192
+ "W", # pycodestyle warnings
193
+ "F", # flake8
194
+ "D", # pydocstyle
195
+ "I", # isort
196
+ "B", # flake8-bugbear
197
+ "SIM101", # duplicate isinstance
198
+ # "RET", # flake8-return
199
+ # "RUF", # ruff rules
200
+ ]
201
+ ignore = ["E203", "E501", "D10", "D212", "D415"]
202
+
203
+ [tool.ruff.lint.pydocstyle]
204
+ convention = "google"
205
+
206
+ [tool.pytest.ini_options]
207
+ pythonpath = ["src"]
208
+ testpaths = ["tests"]
209
+ # `not network` by default, and the reason is isolation rather than speed:
210
+ # hawk's CLI runs `uv pip install` into the *running interpreter*, which
211
+ # uninstalls this project's editable inspect-ai and rewrites the package tree
212
+ # from hawk's own git pin. Two consequences, both observed. Concurrently, a
213
+ # sibling xdist worker importing inspect_ai mid-rewrite dies with a bare
214
+ # ModuleNotFoundError nowhere near its own subject. Afterwards, the venv is
215
+ # left pointing at hawk's snapshot, so every later run -- and every `steward`
216
+ # invocation -- silently tests a different inspect than the checkout.
217
+ # Opt in with `pytest -m network -n0`, and `uv sync` when it is done.
218
+ addopts = "-n auto -m 'not network'"
219
+ markers = [
220
+ # Requires network and the `uv` binary. Hawk's CLI runs `uv pip install`
221
+ # into the running interpreter on every invocation, resolving inspect-ai
222
+ # from a pinned git commit, so a hawk definition cannot be read offline
223
+ # -- and cannot be read without replacing what is installed. Deselected by
224
+ # default (see addopts above).
225
+ "network: needs network access, an external tool on PATH, and sole use of the environment",
226
+ # A marking run's real, detached runner. Every other test has the launch
227
+ # stood in for and applies the run in-process (see tests/conftest.py).
228
+ "runner: starts a real marking runner process",
229
+ ]
230
+
231
+ [tool.pyright]
232
+ include = ["src", "tests"]
233
+ typeCheckingMode = "strict"
234
+ pythonPlatform = "All"
235
+
236
+ # tests may exercise private helpers directly
237
+ [[tool.pyright.executionEnvironments]]
238
+ root = "tests"
239
+ reportPrivateUsage = false
@@ -0,0 +1,21 @@
1
+ from ._evalset.manifest import (
2
+ Manifest,
3
+ ManifestSource,
4
+ ManifestTask,
5
+ )
6
+ from ._evalset.read import ReadEvalSetError, read_eval_set
7
+
8
+ try:
9
+ from ._version import __version__
10
+ except ImportError:
11
+ __version__ = "unknown"
12
+
13
+
14
+ __all__ = [
15
+ "Manifest",
16
+ "ManifestSource",
17
+ "ManifestTask",
18
+ "ReadEvalSetError",
19
+ "read_eval_set",
20
+ "__version__",
21
+ ]
@@ -0,0 +1,9 @@
1
+ """`python -m inspect_steward` — the entry point a scheduler uses.
2
+
3
+ The console script would be shorter, but it lives in a venv's `bin/` that a stripped cron or launchd environment has no reason to have on `PATH`. An absolute interpreter and a module name need no `PATH` at all, and a crontab line is read by people.
4
+ """
5
+
6
+ from ._cli.main import main
7
+
8
+ if __name__ == "__main__":
9
+ main()