robert-ai 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- robert_ai-0.1.0/LICENSE +21 -0
- robert_ai-0.1.0/PKG-INFO +213 -0
- robert_ai-0.1.0/README.md +187 -0
- robert_ai-0.1.0/pyproject.toml +48 -0
- robert_ai-0.1.0/robert/__init__.py +13 -0
- robert_ai-0.1.0/robert/adapters.py +97 -0
- robert_ai-0.1.0/robert/checks.py +133 -0
- robert_ai-0.1.0/robert/cli.py +108 -0
- robert_ai-0.1.0/robert/contracts.py +108 -0
- robert_ai-0.1.0/robert/deps.py +245 -0
- robert_ai-0.1.0/robert/engine.py +159 -0
- robert_ai-0.1.0/robert/graph.py +168 -0
- robert_ai-0.1.0/robert/loop.py +675 -0
- robert_ai-0.1.0/robert/mcp_server.py +114 -0
- robert_ai-0.1.0/robert/outputs.py +114 -0
- robert_ai-0.1.0/robert/project.py +167 -0
- robert_ai-0.1.0/robert/scaffold.py +98 -0
- robert_ai-0.1.0/robert/setup.py +69 -0
- robert_ai-0.1.0/robert/stochadex.json +19 -0
- robert_ai-0.1.0/robert/support.py +196 -0
- robert_ai-0.1.0/robert/tools.py +186 -0
- robert_ai-0.1.0/robert_ai.egg-info/PKG-INFO +213 -0
- robert_ai-0.1.0/robert_ai.egg-info/SOURCES.txt +30 -0
- robert_ai-0.1.0/robert_ai.egg-info/dependency_links.txt +1 -0
- robert_ai-0.1.0/robert_ai.egg-info/entry_points.txt +2 -0
- robert_ai-0.1.0/robert_ai.egg-info/requires.txt +11 -0
- robert_ai-0.1.0/robert_ai.egg-info/top_level.txt +1 -0
- robert_ai-0.1.0/setup.cfg +4 -0
- robert_ai-0.1.0/tests/test_deps.py +127 -0
- robert_ai-0.1.0/tests/test_interfaces.py +109 -0
- robert_ai-0.1.0/tests/test_loop.py +77 -0
- robert_ai-0.1.0/tests/test_method_files.py +78 -0
robert_ai-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Robert J. Hardwick
|
|
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.
|
robert_ai-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: robert-ai
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The AI simulation scientist: a method CLI and MCP server that drives stochadex projects through the discovery-and-warrant loop.
|
|
5
|
+
Author-email: umbralcalc <umbralcalc@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/umbralcalc/robert
|
|
8
|
+
Project-URL: Changelog, https://github.com/umbralcalc/robert/blob/main/CHANGELOG.md
|
|
9
|
+
Keywords: simulation,stochadex,scientific-method,mcp,agents
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Topic :: Scientific/Engineering
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Requires-Python: >=3.11
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: pyyaml>=6
|
|
17
|
+
Requires-Dist: mcp<3,>=2.3
|
|
18
|
+
Requires-Dist: uvicorn>=0.30
|
|
19
|
+
Requires-Dist: httpx>=0.27
|
|
20
|
+
Provides-Extra: arrow
|
|
21
|
+
Requires-Dist: pyarrow>=15; extra == "arrow"
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
24
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# robert
|
|
28
|
+
|
|
29
|
+
The AI scientific research developer powered by simulations.
|
|
30
|
+
|
|
31
|
+
robert is the method layer of an AI simulation scientist. It packages what a
|
|
32
|
+
simulation scientist does as tools that any coding agent can call, and it leaves the
|
|
33
|
+
simulation itself to [stochadex](https://github.com/umbralcalc/stochadex). The agent
|
|
34
|
+
does the implementation, and the experienced user supplies judgment where the work
|
|
35
|
+
is new. Every point where the user had to step in is logged.
|
|
36
|
+
|
|
37
|
+
It is built to test one claim: how far can simulation science be automated?
|
|
38
|
+
The [design doc](https://claude.ai/artifact/XXXKh76eufzP1Jidwmq1mo) has the full
|
|
39
|
+
argument.
|
|
40
|
+
|
|
41
|
+
## The loop
|
|
42
|
+
|
|
43
|
+
```mermaid
|
|
44
|
+
flowchart LR
|
|
45
|
+
pose --> conjecture --> confront --> test
|
|
46
|
+
test -- fails --> discover --> confront
|
|
47
|
+
test -- holds --> compress --> test
|
|
48
|
+
compress --> warrant --> query --> revise --> pose
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
| Step | Writes | Gate before moving on |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| `init` | repo skeleton, `domain.yaml` | Domain interview complete |
|
|
54
|
+
| `pose` | `claim.yaml` | Question, claim, intended use and conditions named |
|
|
55
|
+
| `conjecture` | `model/partitions.yaml`, lineage root | `stochadex --check`; twice-run harness; a role and hypothesis per partition; observables mapped; input licences |
|
|
56
|
+
| `confront` | `ledger/beliefs.jsonl` | Posterior converged; weak identifiability flagged |
|
|
57
|
+
| `test` | `tests.yaml` verdicts | Every structural partition passed; a backtest ran |
|
|
58
|
+
| `discover` | a variant in `model/lineage.yaml` | Beats its parent on held-out prediction; ladder rule for learned partitions |
|
|
59
|
+
| `compress` | a smaller variant | Claim metric unchanged within tolerance; generalisation |
|
|
60
|
+
| `warrant` | `ledger/warrants.jsonl` | Current variant tested and passed; limits stated |
|
|
61
|
+
| `query` | `queries/<id>.yaml` | The warrant reaches the mode's rung |
|
|
62
|
+
| `revise` | `revise.yaml` | Monitors watch partitions and name their action |
|
|
63
|
+
|
|
64
|
+
The supporting commands are `run`, `graph`, `plot`, `status`, `explain`, `intervene`
|
|
65
|
+
and `doctor`. Every command is also an MCP tool with the same arguments, so a
|
|
66
|
+
project driven through chat leaves the same trail as one driven by hand.
|
|
67
|
+
|
|
68
|
+
## Install
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
curl -fsSL https://raw.githubusercontent.com/umbralcalc/robert/main/install.sh | sh
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The installer puts the `robert-ai` package in an isolated tool environment, using uv
|
|
75
|
+
if you have it, then pipx, and otherwise it installs uv first. It then runs
|
|
76
|
+
`robert setup`, which:
|
|
77
|
+
|
|
78
|
+
- downloads the stochadex release robert locks into `~/.robert/stochadex/<version>/`
|
|
79
|
+
and checks it against the SHA-256 recorded in `robert/stochadex.json`;
|
|
80
|
+
- installs the Claude Code plugin (both skills and the MCP server) when `claude` is
|
|
81
|
+
on PATH, and adds the MCP server to `~/.cursor/mcp.json` when Cursor is installed.
|
|
82
|
+
|
|
83
|
+
Run `robert doctor` at any time to check the toolchain. Re-running `robert setup`
|
|
84
|
+
repairs or upgrades the install, and `robert setup --accelerated` swaps in the BLAS +
|
|
85
|
+
DuckDB build of stochadex. Set `ROBERT_VERSION=0.2.0` to install a specific release,
|
|
86
|
+
or `ROBERT_NO_AGENTS=1` to skip agent registration.
|
|
87
|
+
|
|
88
|
+
Until the first PyPI release is out, install from GitHub instead:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
curl -fsSL https://raw.githubusercontent.com/umbralcalc/robert/main/install.sh | ROBERT_SOURCE=git+https://github.com/umbralcalc/robert sh
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### How robert depends on stochadex
|
|
95
|
+
|
|
96
|
+
robert never bundles stochadex. It locks one release and declares the range it
|
|
97
|
+
supports, in [robert/stochadex.json](robert/stochadex.json):
|
|
98
|
+
|
|
99
|
+
| Rule | Effect |
|
|
100
|
+
| --- | --- |
|
|
101
|
+
| Resolution order | `STOCHADEX_BIN`, then the managed install of the wanted version, then PATH |
|
|
102
|
+
| Version range | Any binary outside the supported range is refused, with the fix |
|
|
103
|
+
| Checksums | A download that doesn't match the lock (or the release's `SHA256SUMS`) is never installed |
|
|
104
|
+
| Project pin | Each project records the stochadex version it was created with; `doctor` flags drift |
|
|
105
|
+
| Updates | A weekly workflow moves the lock to the newest release, tests it, and opens a PR |
|
|
106
|
+
|
|
107
|
+
robert needs stochadex v0.24 or later: it renders the partition graph with
|
|
108
|
+
`stochadex graph`, and checks its skills against `stochadex catalogue`, the JSON list
|
|
109
|
+
of everything a build can run.
|
|
110
|
+
|
|
111
|
+
## Connect an agent
|
|
112
|
+
|
|
113
|
+
`robert setup` already registers Claude Code and Cursor. To do it by hand:
|
|
114
|
+
|
|
115
|
+
| Agent | How |
|
|
116
|
+
| --- | --- |
|
|
117
|
+
| Claude Code | `claude plugin marketplace add umbralcalc/robert`, then `claude plugin install robert@robert`. This adds both skills and the MCP server. |
|
|
118
|
+
| Cursor | Add `adapters/cursor/mcp.json` to `~/.cursor/mcp.json`, and copy `adapters/cursor/rules/` into a project's `.cursor/rules/`. |
|
|
119
|
+
| Anything else | Point it at `adapters/agents/AGENTS.md` and run `robert mcp` as a stdio MCP server. |
|
|
120
|
+
|
|
121
|
+
Every project that `robert init` creates also contains its own `.mcp.json`,
|
|
122
|
+
`.cursor/mcp.json`, `AGENTS.md` and `.devcontainer/`, so any agent opened in it
|
|
123
|
+
finds the tools.
|
|
124
|
+
|
|
125
|
+
The skills in `skills/` are the single source of method content. After you edit
|
|
126
|
+
one, run `robert adapters` to regenerate the Cursor rules, `AGENTS.md` and the
|
|
127
|
+
plugin manifest. CI fails if they drift.
|
|
128
|
+
|
|
129
|
+
## In the cloud
|
|
130
|
+
|
|
131
|
+
| Route | How |
|
|
132
|
+
| --- | --- |
|
|
133
|
+
| Image | `ghcr.io/umbralcalc/robert:<version>` contains robert, the locked stochadex (accelerated build), Python and git. Run `docker run --rm -it -v "$PWD:/work" ghcr.io/umbralcalc/robert status`. |
|
|
134
|
+
| Dev container / Codespaces | Projects from `robert init` open in the robert image. For any other repo, add the feature `"ghcr.io/umbralcalc/robert/robert:0": {}` to its `devcontainer.json`. |
|
|
135
|
+
| Cloud coding agents | Use the one-line installer with `ROBERT_NO_AGENTS=1` as the environment's setup script, or start the agent in the robert image. |
|
|
136
|
+
| MCP over the network | `robert mcp --http` serves streamable HTTP at `http://127.0.0.1:8765/mcp`. Binding to anything else requires a bearer token: `ROBERT_MCP_TOKEN=... robert mcp --http --host 0.0.0.0`. |
|
|
137
|
+
|
|
138
|
+
## Releases
|
|
139
|
+
|
|
140
|
+
Versions follow SemVer, pre-1.0, so a minor bump may break the CLI, the tool
|
|
141
|
+
schemas or the file contracts. [CHANGELOG.md](CHANGELOG.md) has the policy.
|
|
142
|
+
`robert/__init__.py` holds the only version number; the package, the plugin
|
|
143
|
+
manifests and every project's recorded skills version all read it.
|
|
144
|
+
|
|
145
|
+
To release, run the **Prepare release PR** workflow with the new version. It turns
|
|
146
|
+
the `[Unreleased]` changelog section into the release and bumps the version. Review
|
|
147
|
+
and merge that PR. `tag-release.yml` then tags the merge commit, and `release.yml`
|
|
148
|
+
tests and publishes:
|
|
149
|
+
|
|
150
|
+
- the `robert-ai` package to PyPI, through a trusted publisher;
|
|
151
|
+
- the GitHub Release, with the changelog section as its notes;
|
|
152
|
+
- the image to GHCR, for amd64 and arm64;
|
|
153
|
+
- the Dev Container Feature.
|
|
154
|
+
|
|
155
|
+
## Worked example
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
examples/logistic-growth/walkthrough.sh /tmp/logistic-demo
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
This runs the whole loop against real stochadex runs:
|
|
162
|
+
|
|
163
|
+
1. Unconstrained growth fails its backtest and its density-dependence process check.
|
|
164
|
+
2. The user's redirect is logged.
|
|
165
|
+
3. `discover` adds a carrying capacity, which beats its parent on held-out years.
|
|
166
|
+
4. `compress` removes a seasonal nuisance without moving the claim.
|
|
167
|
+
5. A forecast is warranted and queried.
|
|
168
|
+
6. A `decide` query is refused, because no model-part swap was tested on the action path.
|
|
169
|
+
|
|
170
|
+
## Design principles
|
|
171
|
+
|
|
172
|
+
- **One hard boundary.** Determinism is enforced at the stochadex run. The agent
|
|
173
|
+
is free in everything it writes above it, and restriction comes from checks,
|
|
174
|
+
not templates.
|
|
175
|
+
- **Build on stochadex, not beside it.** `model/sim.yaml` is a pure stochadex
|
|
176
|
+
config. Validation, I/O manifests, provenance and the partition graph all come
|
|
177
|
+
from the stochadex CLI. robert adds only the claim, the per-partition roles and
|
|
178
|
+
hypotheses, the lineage, the tests, the ledger and the gates.
|
|
179
|
+
- **The agent never produces a number.** Every figure traces back to a config, a
|
|
180
|
+
seed and a provenance sidecar.
|
|
181
|
+
- **Mechanism first.** Learned (ONNX) components must earn their place through
|
|
182
|
+
`discover`, after mechanistic variants have failed and the user has approved.
|
|
183
|
+
- **Gates live in the MCP server, never in agent hooks**, so every agent is held
|
|
184
|
+
to the same standard.
|
|
185
|
+
|
|
186
|
+
## Repository layout
|
|
187
|
+
|
|
188
|
+
| Path | What |
|
|
189
|
+
| --- | --- |
|
|
190
|
+
| `robert/` | The method CLI and MCP server (`tools.py` is the single registry) |
|
|
191
|
+
| `robert/stochadex.json`, `robert/deps.py` | The stochadex lock, resolver and installer |
|
|
192
|
+
| `install.sh`, `Dockerfile`, `devcontainer-features/` | Install routes: one line, image, dev container |
|
|
193
|
+
| `skills/simulation-scientist/` | The method skill |
|
|
194
|
+
| `skills/stochadex-model/` | The model-authoring skill, moved from stochadex v0.23.0 |
|
|
195
|
+
| `adapters/`, `.claude-plugin/` | Generated per-agent adapters |
|
|
196
|
+
| `examples/logistic-growth/` | The end-to-end worked example |
|
|
197
|
+
| `tests/` | Unit tests, plus the whole loop against a real stochadex |
|
|
198
|
+
|
|
199
|
+
## Testing
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
pip install -e '.[dev]'
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
robert setup --no-agents
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
pytest
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The loop and recipe tests skip when no supported stochadex is installed.
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# robert
|
|
2
|
+
|
|
3
|
+
The AI scientific research developer powered by simulations.
|
|
4
|
+
|
|
5
|
+
robert is the method layer of an AI simulation scientist. It packages what a
|
|
6
|
+
simulation scientist does as tools that any coding agent can call, and it leaves the
|
|
7
|
+
simulation itself to [stochadex](https://github.com/umbralcalc/stochadex). The agent
|
|
8
|
+
does the implementation, and the experienced user supplies judgment where the work
|
|
9
|
+
is new. Every point where the user had to step in is logged.
|
|
10
|
+
|
|
11
|
+
It is built to test one claim: how far can simulation science be automated?
|
|
12
|
+
The [design doc](https://claude.ai/artifact/XXXKh76eufzP1Jidwmq1mo) has the full
|
|
13
|
+
argument.
|
|
14
|
+
|
|
15
|
+
## The loop
|
|
16
|
+
|
|
17
|
+
```mermaid
|
|
18
|
+
flowchart LR
|
|
19
|
+
pose --> conjecture --> confront --> test
|
|
20
|
+
test -- fails --> discover --> confront
|
|
21
|
+
test -- holds --> compress --> test
|
|
22
|
+
compress --> warrant --> query --> revise --> pose
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
| Step | Writes | Gate before moving on |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| `init` | repo skeleton, `domain.yaml` | Domain interview complete |
|
|
28
|
+
| `pose` | `claim.yaml` | Question, claim, intended use and conditions named |
|
|
29
|
+
| `conjecture` | `model/partitions.yaml`, lineage root | `stochadex --check`; twice-run harness; a role and hypothesis per partition; observables mapped; input licences |
|
|
30
|
+
| `confront` | `ledger/beliefs.jsonl` | Posterior converged; weak identifiability flagged |
|
|
31
|
+
| `test` | `tests.yaml` verdicts | Every structural partition passed; a backtest ran |
|
|
32
|
+
| `discover` | a variant in `model/lineage.yaml` | Beats its parent on held-out prediction; ladder rule for learned partitions |
|
|
33
|
+
| `compress` | a smaller variant | Claim metric unchanged within tolerance; generalisation |
|
|
34
|
+
| `warrant` | `ledger/warrants.jsonl` | Current variant tested and passed; limits stated |
|
|
35
|
+
| `query` | `queries/<id>.yaml` | The warrant reaches the mode's rung |
|
|
36
|
+
| `revise` | `revise.yaml` | Monitors watch partitions and name their action |
|
|
37
|
+
|
|
38
|
+
The supporting commands are `run`, `graph`, `plot`, `status`, `explain`, `intervene`
|
|
39
|
+
and `doctor`. Every command is also an MCP tool with the same arguments, so a
|
|
40
|
+
project driven through chat leaves the same trail as one driven by hand.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
curl -fsSL https://raw.githubusercontent.com/umbralcalc/robert/main/install.sh | sh
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The installer puts the `robert-ai` package in an isolated tool environment, using uv
|
|
49
|
+
if you have it, then pipx, and otherwise it installs uv first. It then runs
|
|
50
|
+
`robert setup`, which:
|
|
51
|
+
|
|
52
|
+
- downloads the stochadex release robert locks into `~/.robert/stochadex/<version>/`
|
|
53
|
+
and checks it against the SHA-256 recorded in `robert/stochadex.json`;
|
|
54
|
+
- installs the Claude Code plugin (both skills and the MCP server) when `claude` is
|
|
55
|
+
on PATH, and adds the MCP server to `~/.cursor/mcp.json` when Cursor is installed.
|
|
56
|
+
|
|
57
|
+
Run `robert doctor` at any time to check the toolchain. Re-running `robert setup`
|
|
58
|
+
repairs or upgrades the install, and `robert setup --accelerated` swaps in the BLAS +
|
|
59
|
+
DuckDB build of stochadex. Set `ROBERT_VERSION=0.2.0` to install a specific release,
|
|
60
|
+
or `ROBERT_NO_AGENTS=1` to skip agent registration.
|
|
61
|
+
|
|
62
|
+
Until the first PyPI release is out, install from GitHub instead:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
curl -fsSL https://raw.githubusercontent.com/umbralcalc/robert/main/install.sh | ROBERT_SOURCE=git+https://github.com/umbralcalc/robert sh
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### How robert depends on stochadex
|
|
69
|
+
|
|
70
|
+
robert never bundles stochadex. It locks one release and declares the range it
|
|
71
|
+
supports, in [robert/stochadex.json](robert/stochadex.json):
|
|
72
|
+
|
|
73
|
+
| Rule | Effect |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| Resolution order | `STOCHADEX_BIN`, then the managed install of the wanted version, then PATH |
|
|
76
|
+
| Version range | Any binary outside the supported range is refused, with the fix |
|
|
77
|
+
| Checksums | A download that doesn't match the lock (or the release's `SHA256SUMS`) is never installed |
|
|
78
|
+
| Project pin | Each project records the stochadex version it was created with; `doctor` flags drift |
|
|
79
|
+
| Updates | A weekly workflow moves the lock to the newest release, tests it, and opens a PR |
|
|
80
|
+
|
|
81
|
+
robert needs stochadex v0.24 or later: it renders the partition graph with
|
|
82
|
+
`stochadex graph`, and checks its skills against `stochadex catalogue`, the JSON list
|
|
83
|
+
of everything a build can run.
|
|
84
|
+
|
|
85
|
+
## Connect an agent
|
|
86
|
+
|
|
87
|
+
`robert setup` already registers Claude Code and Cursor. To do it by hand:
|
|
88
|
+
|
|
89
|
+
| Agent | How |
|
|
90
|
+
| --- | --- |
|
|
91
|
+
| Claude Code | `claude plugin marketplace add umbralcalc/robert`, then `claude plugin install robert@robert`. This adds both skills and the MCP server. |
|
|
92
|
+
| Cursor | Add `adapters/cursor/mcp.json` to `~/.cursor/mcp.json`, and copy `adapters/cursor/rules/` into a project's `.cursor/rules/`. |
|
|
93
|
+
| Anything else | Point it at `adapters/agents/AGENTS.md` and run `robert mcp` as a stdio MCP server. |
|
|
94
|
+
|
|
95
|
+
Every project that `robert init` creates also contains its own `.mcp.json`,
|
|
96
|
+
`.cursor/mcp.json`, `AGENTS.md` and `.devcontainer/`, so any agent opened in it
|
|
97
|
+
finds the tools.
|
|
98
|
+
|
|
99
|
+
The skills in `skills/` are the single source of method content. After you edit
|
|
100
|
+
one, run `robert adapters` to regenerate the Cursor rules, `AGENTS.md` and the
|
|
101
|
+
plugin manifest. CI fails if they drift.
|
|
102
|
+
|
|
103
|
+
## In the cloud
|
|
104
|
+
|
|
105
|
+
| Route | How |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| Image | `ghcr.io/umbralcalc/robert:<version>` contains robert, the locked stochadex (accelerated build), Python and git. Run `docker run --rm -it -v "$PWD:/work" ghcr.io/umbralcalc/robert status`. |
|
|
108
|
+
| Dev container / Codespaces | Projects from `robert init` open in the robert image. For any other repo, add the feature `"ghcr.io/umbralcalc/robert/robert:0": {}` to its `devcontainer.json`. |
|
|
109
|
+
| Cloud coding agents | Use the one-line installer with `ROBERT_NO_AGENTS=1` as the environment's setup script, or start the agent in the robert image. |
|
|
110
|
+
| MCP over the network | `robert mcp --http` serves streamable HTTP at `http://127.0.0.1:8765/mcp`. Binding to anything else requires a bearer token: `ROBERT_MCP_TOKEN=... robert mcp --http --host 0.0.0.0`. |
|
|
111
|
+
|
|
112
|
+
## Releases
|
|
113
|
+
|
|
114
|
+
Versions follow SemVer, pre-1.0, so a minor bump may break the CLI, the tool
|
|
115
|
+
schemas or the file contracts. [CHANGELOG.md](CHANGELOG.md) has the policy.
|
|
116
|
+
`robert/__init__.py` holds the only version number; the package, the plugin
|
|
117
|
+
manifests and every project's recorded skills version all read it.
|
|
118
|
+
|
|
119
|
+
To release, run the **Prepare release PR** workflow with the new version. It turns
|
|
120
|
+
the `[Unreleased]` changelog section into the release and bumps the version. Review
|
|
121
|
+
and merge that PR. `tag-release.yml` then tags the merge commit, and `release.yml`
|
|
122
|
+
tests and publishes:
|
|
123
|
+
|
|
124
|
+
- the `robert-ai` package to PyPI, through a trusted publisher;
|
|
125
|
+
- the GitHub Release, with the changelog section as its notes;
|
|
126
|
+
- the image to GHCR, for amd64 and arm64;
|
|
127
|
+
- the Dev Container Feature.
|
|
128
|
+
|
|
129
|
+
## Worked example
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
examples/logistic-growth/walkthrough.sh /tmp/logistic-demo
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
This runs the whole loop against real stochadex runs:
|
|
136
|
+
|
|
137
|
+
1. Unconstrained growth fails its backtest and its density-dependence process check.
|
|
138
|
+
2. The user's redirect is logged.
|
|
139
|
+
3. `discover` adds a carrying capacity, which beats its parent on held-out years.
|
|
140
|
+
4. `compress` removes a seasonal nuisance without moving the claim.
|
|
141
|
+
5. A forecast is warranted and queried.
|
|
142
|
+
6. A `decide` query is refused, because no model-part swap was tested on the action path.
|
|
143
|
+
|
|
144
|
+
## Design principles
|
|
145
|
+
|
|
146
|
+
- **One hard boundary.** Determinism is enforced at the stochadex run. The agent
|
|
147
|
+
is free in everything it writes above it, and restriction comes from checks,
|
|
148
|
+
not templates.
|
|
149
|
+
- **Build on stochadex, not beside it.** `model/sim.yaml` is a pure stochadex
|
|
150
|
+
config. Validation, I/O manifests, provenance and the partition graph all come
|
|
151
|
+
from the stochadex CLI. robert adds only the claim, the per-partition roles and
|
|
152
|
+
hypotheses, the lineage, the tests, the ledger and the gates.
|
|
153
|
+
- **The agent never produces a number.** Every figure traces back to a config, a
|
|
154
|
+
seed and a provenance sidecar.
|
|
155
|
+
- **Mechanism first.** Learned (ONNX) components must earn their place through
|
|
156
|
+
`discover`, after mechanistic variants have failed and the user has approved.
|
|
157
|
+
- **Gates live in the MCP server, never in agent hooks**, so every agent is held
|
|
158
|
+
to the same standard.
|
|
159
|
+
|
|
160
|
+
## Repository layout
|
|
161
|
+
|
|
162
|
+
| Path | What |
|
|
163
|
+
| --- | --- |
|
|
164
|
+
| `robert/` | The method CLI and MCP server (`tools.py` is the single registry) |
|
|
165
|
+
| `robert/stochadex.json`, `robert/deps.py` | The stochadex lock, resolver and installer |
|
|
166
|
+
| `install.sh`, `Dockerfile`, `devcontainer-features/` | Install routes: one line, image, dev container |
|
|
167
|
+
| `skills/simulation-scientist/` | The method skill |
|
|
168
|
+
| `skills/stochadex-model/` | The model-authoring skill, moved from stochadex v0.23.0 |
|
|
169
|
+
| `adapters/`, `.claude-plugin/` | Generated per-agent adapters |
|
|
170
|
+
| `examples/logistic-growth/` | The end-to-end worked example |
|
|
171
|
+
| `tests/` | Unit tests, plus the whole loop against a real stochadex |
|
|
172
|
+
|
|
173
|
+
## Testing
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
pip install -e '.[dev]'
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
robert setup --no-agents
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
pytest
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The loop and recipe tests skip when no supported stochadex is installed.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=69"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
# `robert` is taken on PyPI; the command is still `robert`.
|
|
7
|
+
name = "robert-ai"
|
|
8
|
+
dynamic = ["version"]
|
|
9
|
+
description = "The AI simulation scientist: a method CLI and MCP server that drives stochadex projects through the discovery-and-warrant loop."
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
requires-python = ">=3.11"
|
|
13
|
+
authors = [{ name = "umbralcalc", email = "umbralcalc@gmail.com" }]
|
|
14
|
+
keywords = ["simulation", "stochadex", "scientific-method", "mcp", "agents"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Topic :: Scientific/Engineering",
|
|
18
|
+
"Environment :: Console",
|
|
19
|
+
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"pyyaml>=6",
|
|
22
|
+
"mcp>=2.3,<3",
|
|
23
|
+
"uvicorn>=0.30",
|
|
24
|
+
"httpx>=0.27",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
arrow = ["pyarrow>=15"]
|
|
29
|
+
dev = ["pytest>=8", "build>=1.2"]
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://github.com/umbralcalc/robert"
|
|
33
|
+
Changelog = "https://github.com/umbralcalc/robert/blob/main/CHANGELOG.md"
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
robert = "robert.cli:main"
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.dynamic]
|
|
39
|
+
version = { attr = "robert.__version__" }
|
|
40
|
+
|
|
41
|
+
[tool.setuptools.packages.find]
|
|
42
|
+
include = ["robert*"]
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.package-data]
|
|
45
|
+
robert = ["stochadex.json"]
|
|
46
|
+
|
|
47
|
+
[tool.pytest.ini_options]
|
|
48
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""robert: the AI simulation scientist.
|
|
2
|
+
|
|
3
|
+
A thin method layer over the stochadex engine. It owns the method files and the
|
|
4
|
+
gates of the discovery-and-warrant loop, and delegates every simulation action to
|
|
5
|
+
the stochadex binary. The same tool registry drives the CLI and the MCP server, so
|
|
6
|
+
a chat-driven project and a hand-driven one leave the same trail in the repo.
|
|
7
|
+
|
|
8
|
+
The version below is the single source: the package metadata, the plugin manifest
|
|
9
|
+
and the skills version every project records all read it. The stochadex version
|
|
10
|
+
robert supports lives in `stochadex.json`.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Render per-agent adapters from the one source of method content in skills/.
|
|
2
|
+
|
|
3
|
+
Method content has one source. These thin adapters only change its packaging: a
|
|
4
|
+
Claude Code plugin, Cursor rules plus MCP config, and an AGENTS.md for anything
|
|
5
|
+
else. Correctness never lives here; it lives in the MCP tools every adapter calls.
|
|
6
|
+
`tests/test_adapters.py` fails when a committed adapter drifts from its source.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import re
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
from . import __version__
|
|
16
|
+
from .scaffold import MCP_SERVER
|
|
17
|
+
from .tools import TOOLS
|
|
18
|
+
|
|
19
|
+
REPO = Path(__file__).resolve().parents[1]
|
|
20
|
+
AUTHOR = {"name": "umbralcalc", "email": "umbralcalc@gmail.com",
|
|
21
|
+
"url": "https://github.com/umbralcalc/robert"}
|
|
22
|
+
DESCRIPTION = ("The AI simulation scientist: drives stochadex projects through the "
|
|
23
|
+
"discovery-and-warrant loop, with every gate enforced by the robert MCP server.")
|
|
24
|
+
HEADER = "<!-- Generated by `robert adapters` from skills/. Do not edit by hand. -->\n"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def skills(repo: Path = REPO) -> list[tuple[dict[str, str], str]]:
|
|
28
|
+
out = []
|
|
29
|
+
for path in sorted((repo / "skills").glob("*/SKILL.md")):
|
|
30
|
+
_, front, body = path.read_text().split("---", 2)
|
|
31
|
+
# Skill frontmatter is `key: value` lines, not strict YAML (descriptions
|
|
32
|
+
# may contain `{type: ...}`), so split each line at its first colon.
|
|
33
|
+
meta = dict(line.split(":", 1) for line in front.strip().splitlines())
|
|
34
|
+
out.append(({k.strip(): v.strip() for k, v in meta.items()}, body.strip() + "\n"))
|
|
35
|
+
return out
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _nest_headings(body: str) -> str:
|
|
39
|
+
"""Push a skill's headings two levels down, leaving code blocks alone."""
|
|
40
|
+
lines, fenced = [], False
|
|
41
|
+
for line in body.splitlines(keepends=True):
|
|
42
|
+
if line.startswith("```"):
|
|
43
|
+
fenced = not fenced
|
|
44
|
+
elif not fenced and re.match(r"#+ ", line):
|
|
45
|
+
line = "##" + line
|
|
46
|
+
lines.append(line)
|
|
47
|
+
return "".join(lines)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def outputs(repo: Path = REPO) -> dict[str, str]:
|
|
51
|
+
"""Every adapter file, keyed by path relative to the repo."""
|
|
52
|
+
files: dict[str, str] = {}
|
|
53
|
+
files[".claude-plugin/plugin.json"] = json.dumps({
|
|
54
|
+
"name": "robert",
|
|
55
|
+
"description": DESCRIPTION,
|
|
56
|
+
"version": __version__,
|
|
57
|
+
"author": AUTHOR,
|
|
58
|
+
"repository": AUTHOR["url"],
|
|
59
|
+
"license": "MIT",
|
|
60
|
+
"keywords": ["simulation", "stochadex", "scientific-method", "agent-skill"],
|
|
61
|
+
"skills": "./skills/",
|
|
62
|
+
"mcpServers": {"robert": MCP_SERVER},
|
|
63
|
+
}, indent=2) + "\n"
|
|
64
|
+
files[".claude-plugin/marketplace.json"] = json.dumps({
|
|
65
|
+
"name": "robert",
|
|
66
|
+
"owner": AUTHOR,
|
|
67
|
+
"metadata": {"description": DESCRIPTION, "version": __version__},
|
|
68
|
+
"plugins": [{"name": "robert", "source": ".", "description": DESCRIPTION,
|
|
69
|
+
"category": "modeling",
|
|
70
|
+
"keywords": ["simulation", "stochadex", "scientific-method"]}],
|
|
71
|
+
}, indent=2) + "\n"
|
|
72
|
+
files["adapters/cursor/mcp.json"] = json.dumps(
|
|
73
|
+
{"mcpServers": {"robert": MCP_SERVER}}, indent=2) + "\n"
|
|
74
|
+
|
|
75
|
+
agents = [HEADER, "# robert: the simulation scientist\n\n",
|
|
76
|
+
"Connect the `robert` MCP server (`robert mcp`, stdio) and follow the "
|
|
77
|
+
"skills below. The tools enforce the gates; these notes explain them.\n\n",
|
|
78
|
+
"## Tools\n\n"]
|
|
79
|
+
agents += [f"- `{t.name}`: {t.description}\n" for t in TOOLS]
|
|
80
|
+
for front, body in skills(repo):
|
|
81
|
+
files[f"adapters/cursor/rules/{front['name']}.mdc"] = (
|
|
82
|
+
f"---\ndescription: {json.dumps(front['description'], ensure_ascii=False)}\n"
|
|
83
|
+
"alwaysApply: false\n---\n"
|
|
84
|
+
+ HEADER + body)
|
|
85
|
+
agents += [f"\n## Skill: {front['name']}\n\n", _nest_headings(body)]
|
|
86
|
+
files["adapters/agents/AGENTS.md"] = "".join(agents)
|
|
87
|
+
return files
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def render(repo: Path = REPO) -> list[str]:
|
|
91
|
+
written = []
|
|
92
|
+
for rel, text in outputs(repo).items():
|
|
93
|
+
p = repo / rel
|
|
94
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
95
|
+
p.write_text(text)
|
|
96
|
+
written.append(rel)
|
|
97
|
+
return written
|