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.
@@ -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.
@@ -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