rhylthyme-cli-runner 0.2.0a0__tar.gz → 0.2.3a0__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.
- {rhylthyme_cli_runner-0.2.0a0/src/rhylthyme_cli_runner.egg-info → rhylthyme_cli_runner-0.2.3a0}/PKG-INFO +266 -3
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/README.md +265 -2
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/setup.py +1 -1
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/__init__.py +1 -1
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/cli.py +4 -1
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/llm.py +191 -4
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/program_planner.py +20 -4
- rhylthyme_cli_runner-0.2.3a0/src/rhylthyme_cli_runner/remote/checks.py +663 -0
- rhylthyme_cli_runner-0.2.3a0/src/rhylthyme_cli_runner/remote/cli.py +644 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/remote/mcp_client.py +69 -16
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0/src/rhylthyme_cli_runner.egg-info}/PKG-INFO +266 -3
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner.egg-info/SOURCES.txt +5 -0
- rhylthyme_cli_runner-0.2.3a0/tests/test_eval_providers.py +292 -0
- rhylthyme_cli_runner-0.2.3a0/tests/test_mcp_checks.py +441 -0
- rhylthyme_cli_runner-0.2.3a0/tests/test_planner_time_strings.py +20 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_remote.py +150 -0
- rhylthyme_cli_runner-0.2.3a0/tests/test_skill.py +82 -0
- rhylthyme_cli_runner-0.2.0a0/src/rhylthyme_cli_runner/remote/cli.py +0 -282
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/LICENSE +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/pyproject.toml +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/setup.cfg +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/cli.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/environment_icons.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/environment_loader.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/environment_schemas.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/__init__.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/compare.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/gold.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/harness.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/matcher.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/metrics.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/patterns/__init__.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/patterns/authoring_guide.md +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/patterns/baseline.md +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/patterns/baseline.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/patterns/extract.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/patterns/four_turn.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/report.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/expand_replicates.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/__init__.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/calibrate.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/calibrate_cli.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/cli.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/evaluate.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/evaluate_cli.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/factors.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/hash.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/predict.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/recorder.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/render.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/replay.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/report.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/report_cli.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/store.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/synth.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/history/usable.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/instance_checks.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/program_runner.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/remote/__init__.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/remote/auth.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/validate_program.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner.egg-info/dependency_links.txt +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner.egg-info/entry_points.txt +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner.egg-info/requires.txt +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner.egg-info/top_level.txt +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_calibrate.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_cli.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_eval_baseline.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_eval_harness.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_eval_scorer.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_evaluate.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_example_validation.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_examples_integration.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_expand_replicates.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_hash_parity.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_history_report.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_predict.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_program_runner.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_replay.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_run_recorder.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_synth.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_usable.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_validate_examples_ci.py +0 -0
- {rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/tests/test_validate_program.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rhylthyme-cli-runner
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3a0
|
|
4
4
|
Summary: CLI runner for Rhylthyme real-time program schedules
|
|
5
5
|
Home-page: https://github.com/rhylthyme/rhylthyme-cli-runner
|
|
6
6
|
Author: Rhylthyme Team
|
|
@@ -69,6 +69,106 @@ rhylthyme login
|
|
|
69
69
|
rhylthyme generate "roast chicken, potatoes and green beans for 6" -e kitchen --by 19:00 --with "one oven"
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
## A timeline in five commands: a birthday party
|
|
73
|
+
|
|
74
|
+
Parents collect at 4:00. Working backwards from that: when does the cake go in
|
|
75
|
+
the oven, when do the balloons go up, and do the pizzas and the cake ever want
|
|
76
|
+
the oven at the same time?
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install rhylthyme-cli-runner
|
|
80
|
+
|
|
81
|
+
# 1. a program: the party, the kitchen and the setup crew, 13 steps
|
|
82
|
+
curl -sO https://raw.githubusercontent.com/rhylthyme/rhylthyme-cli-runner/main/examples/recipe/birthday-party.json
|
|
83
|
+
|
|
84
|
+
# 2. is it well formed?
|
|
85
|
+
rhylthyme validate birthday-party.json --strict
|
|
86
|
+
|
|
87
|
+
# 3. any clashes, and what time does everything start if we finish at 4?
|
|
88
|
+
rhylthyme analyze birthday-party.json --finish-at 16:00
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
**Makespan:** 3h 10m across 3 tracks, 13 steps.
|
|
93
|
+
**Critical path:** Guests arrive → Party games → Pizza → Candles and cake → Piñata, until it breaks → Party bags and goodbyes
|
|
94
|
+
**Binding constraints:** step dependencies only — no resource or in-flight limit gates the critical path.
|
|
95
|
+
**Peak concurrency:** 2 steps at 10:00.
|
|
96
|
+
**Resource conflicts:** none.
|
|
97
|
+
|
|
98
|
+
**Tracks that finish early:** Kitchen (1h 10m early), Setup crew (50m early)
|
|
99
|
+
|
|
100
|
+
Start Sat 12:50, finish Sat 16:00 (local time)
|
|
101
|
+
Sat 12:50 Bake the cake
|
|
102
|
+
Sat 13:00 Balloons and banner
|
|
103
|
+
Sat 13:25 Cake cools
|
|
104
|
+
Sat 13:30 Hang the piñata
|
|
105
|
+
Sat 13:50 Guests arrive
|
|
106
|
+
Sat 14:05 Frost and decorate
|
|
107
|
+
Sat 14:20 Party games
|
|
108
|
+
Sat 14:35 Pizzas in the oven
|
|
109
|
+
Sat 14:50 Fill party bags
|
|
110
|
+
Sat 14:50 Pizza
|
|
111
|
+
Sat 15:15 Candles and cake
|
|
112
|
+
Sat 15:30 Piñata, until it breaks
|
|
113
|
+
Sat 15:45 Party bags and goodbyes
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# 4. a live timeline for the fridge door (or a phone): timers, cues, and you end the piñata when it breaks
|
|
118
|
+
rhylthyme publish birthday-party.json --open --image party-preview.png
|
|
119
|
+
|
|
120
|
+
# 5. a picture for the group chat, on the wall clock (needs Node; nothing to install)
|
|
121
|
+
npx -y github:rhylthyme/rhylthyme-timeline birthday-party.json -o birthday-party.png \
|
|
122
|
+
--style web --palette vivid --label-overflow outside --start-at "$(date +%F)T12:50:00"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+

|
|
126
|
+
|
|
127
|
+
The pizzas go in 15 minutes after the games *start*, so they come out as the
|
|
128
|
+
games end; the party bags get filled while everyone is eating. Try
|
|
129
|
+
`--finish-at 17:30`, or turn the cake into a two-hour fruitcake (`"seconds": "2h"`
|
|
130
|
+
on `bake`) and `analyze` reports the clash: `oven needs 2 but max is 1 from
|
|
131
|
+
1:45:00 to 2:00:00 (bake, heat-pizza)`. `rhylthyme run birthday-party.json --time-scale 60` rehearses
|
|
132
|
+
the whole afternoon in the terminal at a minute per second.
|
|
133
|
+
|
|
134
|
+
## This repository and rhylthyme-mcp
|
|
135
|
+
|
|
136
|
+
Two repositories do related things and are easy to confuse. This one is the
|
|
137
|
+
**command a person types**. [rhylthyme-mcp](https://github.com/rhylthyme/rhylthyme-mcp)
|
|
138
|
+
is the **server an AI assistant talks to**.
|
|
139
|
+
|
|
140
|
+
| | [rhylthyme-mcp](https://github.com/rhylthyme/rhylthyme-mcp) | [rhylthyme-cli-runner](https://github.com/rhylthyme/rhylthyme-cli-runner) |
|
|
141
|
+
|---|---|---|
|
|
142
|
+
| What it is | The MCP **server**: the tools an AI assistant calls | A command-line **program**: the `rhylthyme` command |
|
|
143
|
+
| Who uses it | Claude, ChatGPT, Cursor or any MCP client, on a person's behalf | A person at a terminal, a script, or CI |
|
|
144
|
+
| Where it runs | Hosted at `mcp.rhylthyme.com`; nothing to install | On your machine: `pip install rhylthyme-cli-runner` |
|
|
145
|
+
| Language | JavaScript (Node 20+) | Python 3.12+ |
|
|
146
|
+
| Input | A program the assistant builds in conversation | A program file on disk (JSON or YAML) |
|
|
147
|
+
| Validate a program | `validate_program` | `rhylthyme validate` (works offline) |
|
|
148
|
+
| Timing, conflicts, deadlines | `analyze_schedule` | `rhylthyme analyze` (asks the server) |
|
|
149
|
+
| Publish a live timeline | `visualize_schedule` | `rhylthyme publish` (asks the server) |
|
|
150
|
+
| Run a schedule with timers | no: it hands back a link to the web timeline | `rhylthyme run`, an interactive terminal runner |
|
|
151
|
+
| Recorded runs, calibration | reads runs saved to an account | records runs locally; `rhylthyme runs`, `rhylthyme calibrate` |
|
|
152
|
+
| Catalog search, imports, account library | yes | no |
|
|
153
|
+
| Also in the repository | the `rhylthyme-mcp` PyPI package (a stdio bridge to the hosted server), the Claude plugin marketplace | the Claude skill's source, the prompt-evaluation harness and its results, `rhylthyme mcp-test` |
|
|
154
|
+
|
|
155
|
+
How they fit together: this tool is one of the MCP server's clients.
|
|
156
|
+
`rhylthyme analyze`, `publish`, `generate` and `mcp-test` are MCP calls to
|
|
157
|
+
`mcp.rhylthyme.com`; `rhylthyme validate`, `run`, `runs` and `calibrate` never
|
|
158
|
+
touch the network. Each has its own validator for the same program schema
|
|
159
|
+
(Python here, JavaScript there), so a program is checked again when it is
|
|
160
|
+
published.
|
|
161
|
+
|
|
162
|
+
Use this repository if you have a program file and a terminal, want timers in
|
|
163
|
+
the terminal, or keep run records. Use rhylthyme-mcp to connect Claude, ChatGPT
|
|
164
|
+
or another assistant, or to read or self-host the server.
|
|
165
|
+
|
|
166
|
+
Two names to keep apart: `rhylthyme-cli-runner` on PyPI is this tool (command
|
|
167
|
+
`rhylthyme`); `rhylthyme-mcp` on PyPI is the server's stdio bridge (command
|
|
168
|
+
`rhylthyme-mcp`). The program format itself is defined in
|
|
169
|
+
[rhylthyme-spec](https://github.com/rhylthyme/rhylthyme-spec), with examples in
|
|
170
|
+
[rhylthyme-examples](https://github.com/rhylthyme/rhylthyme-examples).
|
|
171
|
+
|
|
72
172
|
## Installation
|
|
73
173
|
|
|
74
174
|
### From Source
|
|
@@ -197,9 +297,30 @@ rhylthyme run examples/programs/breakfast_schedule.json --environment kitchen
|
|
|
197
297
|
rhylthyme run examples/programs/breakfast_schedule.json --no-validate
|
|
198
298
|
```
|
|
199
299
|
|
|
300
|
+
### Analyze and Publish a Program
|
|
301
|
+
|
|
302
|
+
Neither needs an account; both are computed by the hosted MCP server.
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
# Total length, critical path, resource conflicts
|
|
306
|
+
rhylthyme analyze examples/programs/breakfast_schedule.json
|
|
307
|
+
|
|
308
|
+
# When does each step start if breakfast is at 8:30?
|
|
309
|
+
rhylthyme analyze examples/programs/breakfast_schedule.json --finish-at 8:30am
|
|
310
|
+
|
|
311
|
+
# A live, shareable timeline with timers; prints the URL
|
|
312
|
+
rhylthyme publish examples/programs/breakfast_schedule.json
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
`validate` checks structure only. Two steps that want the only oven at the
|
|
316
|
+
same time pass validation; `analyze` reports them, and `--strict` makes that
|
|
317
|
+
a non-zero exit.
|
|
318
|
+
|
|
200
319
|
### Optimize a Program
|
|
201
320
|
|
|
202
|
-
|
|
321
|
+
`plan` is an older stagger heuristic that reads the pre-0.2 program format; on
|
|
322
|
+
programs written with `stepId` and `task` (all current examples) it writes the
|
|
323
|
+
program back unchanged. Use `analyze` to find contention.
|
|
203
324
|
|
|
204
325
|
```bash
|
|
205
326
|
# Optimize a program and save to new file
|
|
@@ -227,6 +348,39 @@ rhylthyme validate-environments
|
|
|
227
348
|
rhylthyme environment-info kitchen
|
|
228
349
|
```
|
|
229
350
|
|
|
351
|
+
## Claude Skill
|
|
352
|
+
|
|
353
|
+
[`skills/rhylthyme`](skills/rhylthyme) is an [Agent Skill](https://docs.claude.com/en/docs/agents-and-tools/agent-skills/overview)
|
|
354
|
+
that teaches Claude (Claude Code, the Claude apps, the Agent SDK) to turn a
|
|
355
|
+
protocol, recipe or run sheet into a validated program with this CLI, check
|
|
356
|
+
it for conflicts, and hand back a live timeline. It follows the layout of
|
|
357
|
+
[K-Dense scientific skills](https://github.com/K-Dense-AI/claude-scientific-skills):
|
|
358
|
+
a `SKILL.md` plus `references/`.
|
|
359
|
+
|
|
360
|
+
The easiest install is the Claude Code plugin, which also connects the hosted
|
|
361
|
+
MCP server:
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
/plugin marketplace add rhylthyme/rhylthyme-mcp
|
|
365
|
+
/plugin install rhylthyme@rhylthyme
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
Or copy the skill by hand:
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
# Claude Code, for one user
|
|
372
|
+
mkdir -p ~/.claude/skills
|
|
373
|
+
cp -r skills/rhylthyme ~/.claude/skills/
|
|
374
|
+
|
|
375
|
+
# or for one project
|
|
376
|
+
mkdir -p .claude/skills && cp -r skills/rhylthyme .claude/skills/
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Then ask, for example, "time a Western blot so imaging is at 4 pm" or "two PCR
|
|
380
|
+
protocols, one thermocycler: when do I start each?". `tests/test_skill.py`
|
|
381
|
+
validates every program in the skill and checks that every command it names
|
|
382
|
+
exists.
|
|
383
|
+
|
|
230
384
|
## Program File Examples
|
|
231
385
|
|
|
232
386
|
### Simple Breakfast Schedule
|
|
@@ -305,6 +459,39 @@ Environment: `RHYLTHYME_TOKEN` (access token, overrides the stored session),
|
|
|
305
459
|
`RHYLTHYME_MCP_URL` (default `https://mcp.rhylthyme.com/mcp`),
|
|
306
460
|
`RHYLTHYME_SITE_URL` (default `https://www.rhylthyme.com`).
|
|
307
461
|
|
|
462
|
+
### `rhylthyme mcp-test`
|
|
463
|
+
|
|
464
|
+
Smoke-tests a Rhylthyme MCP server and exits 1 if any check fails. By
|
|
465
|
+
default it runs the read-only checks against all five hosted endpoints
|
|
466
|
+
(`/mcp`, `/kitchen/mcp`, `/lab/mcp`, `/events/mcp`, `/gym/mcp`):
|
|
467
|
+
|
|
468
|
+
| Check | What it proves |
|
|
469
|
+
|---|---|
|
|
470
|
+
| `initialize` | server name, protocol version, tools/resources/prompts capabilities, instructions |
|
|
471
|
+
| `tools` | core tools and the endpoint's one-shot tools are listed, each with a description and schema |
|
|
472
|
+
| `validate-good` / `validate-bad` | a valid program passes (including a `type: "compound"` trigger); a dangling step reference is rejected with a fix hint |
|
|
473
|
+
| `analyze` | makespan, critical path and wall-clock itinerary for a known program |
|
|
474
|
+
| `resources` / `prompts` | schema and guides are readable, a bundled example validates, `plan_schedule` substitutes its arguments |
|
|
475
|
+
| `json-accept` | clients that do not accept SSE (`*/*`, `application/json`) get JSON, not 406 |
|
|
476
|
+
| `bad-requests` | unknown method gives -32601, unknown tool gives an error, never a 5xx |
|
|
477
|
+
| `login-gate` | account tools refuse without a token and point at `login` |
|
|
478
|
+
| `catalog` | public search returns entries that load with a URL (empty catalog = warning) |
|
|
479
|
+
| `publish` (`--publish`) | `visualize_schedule` returns a URL on the right site; the page and PNG load |
|
|
480
|
+
| `generate` (`--generate`) | the model-backed `import_text` returns a program that validates (needs `login`) |
|
|
481
|
+
|
|
482
|
+
```bash
|
|
483
|
+
rhylthyme mcp-test # everything read-only
|
|
484
|
+
rhylthyme mcp-test -e lab --publish # one endpoint, plus a real share
|
|
485
|
+
rhylthyme mcp-test -k catalog -k tools # only some checks
|
|
486
|
+
rhylthyme mcp-test --url http://localhost:3000/mcp -e generic
|
|
487
|
+
rhylthyme mcp-test --json --strict # cron / CI: warnings fail too
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
Requests carry `mcp-test` in the User-Agent so the hosted server logs the
|
|
491
|
+
errors these checks provoke without alerting anyone. The same suite is
|
|
492
|
+
importable (`rhylthyme_cli_runner.remote.checks.run_suite`), and
|
|
493
|
+
`RHYLTHYME_MCP_LIVE=1 pytest tests/test_mcp_checks.py` runs it live.
|
|
494
|
+
|
|
308
495
|
### `rhylthyme login` / `logout` / `whoami`
|
|
309
496
|
|
|
310
497
|
`login` opens the rhylthyme.com sign-in page and receives the session on a
|
|
@@ -331,9 +518,35 @@ Runs programs with interactive terminal UI.
|
|
|
331
518
|
- `--validate / --no-validate`: Validate before running (default: True)
|
|
332
519
|
- `--auto-start`: Automatically start without manual trigger
|
|
333
520
|
|
|
521
|
+
### `rhylthyme analyze`
|
|
522
|
+
|
|
523
|
+
Total length, critical path, what gates each link of it, resource conflicts
|
|
524
|
+
and tracks that finish early. No sign-in; nothing is published.
|
|
525
|
+
|
|
526
|
+
**Options:**
|
|
527
|
+
- `--finish-at TEXT`: when everything must be finished (`19:00`, `7:30pm` or ISO 8601); prints local clock times per step
|
|
528
|
+
- `--start-at TEXT`: when the program starts; ignored with `--finish-at`
|
|
529
|
+
- `--strict`: exit non-zero when there are resource conflicts
|
|
530
|
+
- `--json`: the full analysis
|
|
531
|
+
|
|
532
|
+
### `rhylthyme publish`
|
|
533
|
+
|
|
534
|
+
Publishes a program (a file, an http(s) URL, or `-` for standard input) as a
|
|
535
|
+
live timeline and prints its URL. No sign-in.
|
|
536
|
+
A published timeline is reachable by anyone who has the link.
|
|
537
|
+
|
|
538
|
+
**Options:**
|
|
539
|
+
- `-e, --env`: `generic`, `kitchen`, `lab`, `events`, `gym` (default: from `environmentType`)
|
|
540
|
+
- `-q, --quiet`: print only the URL
|
|
541
|
+
- `--json`: `url`, `shareId`, `imageUrl`, `makespanSeconds`, `warnings`
|
|
542
|
+
- `--image PATH`: also save a PNG of the timeline
|
|
543
|
+
- `--open`: open it in a browser
|
|
544
|
+
|
|
334
545
|
### `rhylthyme plan`
|
|
335
546
|
|
|
336
|
-
|
|
547
|
+
An older stagger heuristic. It reads the pre-0.2 program format and leaves
|
|
548
|
+
programs written with `stepId` and `task` unchanged; use `analyze` to find
|
|
549
|
+
contention and edit the triggers.
|
|
337
550
|
|
|
338
551
|
**Options:**
|
|
339
552
|
- `--verbose, -v`: Show detailed planning information
|
|
@@ -614,6 +827,56 @@ make test-unit # excludes llm
|
|
|
614
827
|
RHYLTHYME_EVAL_LIVE=1 pytest -m llm # one real call, opt in
|
|
615
828
|
```
|
|
616
829
|
|
|
830
|
+
|
|
831
|
+
### Other models and a spending cap
|
|
832
|
+
|
|
833
|
+
`--model` also accepts models served through an OpenAI-compatible API. The
|
|
834
|
+
provider is picked from the model id and the key is read from the
|
|
835
|
+
environment:
|
|
836
|
+
|
|
837
|
+
| Model id | Provider | Key |
|
|
838
|
+
|---|---|---|
|
|
839
|
+
| `claude-*` | Anthropic | `ANTHROPIC_API_KEY` |
|
|
840
|
+
| `deepseek-*` (e.g. `deepseek-flash`, `deepseek-v4-pro`) | api.deepseek.com | `DEEPSEEK_API_KEY` |
|
|
841
|
+
| `qwen*` | Alibaba DashScope (international) | `DASHSCOPE_API_KEY` |
|
|
842
|
+
| `kimi-*`, `moonshot-*` | Moonshot | `MOONSHOT_API_KEY` |
|
|
843
|
+
| `glm-*` | Z.ai | `ZAI_API_KEY` |
|
|
844
|
+
| anything with a slash, e.g. `deepseek/deepseek-flash` | OpenRouter | `OPENROUTER_API_KEY` |
|
|
845
|
+
| any id, with `RHYLTHYME_EVAL_BASE_URL` set | that endpoint (vLLM, Ollama, ...) | `RHYLTHYME_EVAL_API_KEY`, optional for localhost |
|
|
846
|
+
|
|
847
|
+
Costs come from the price table in `eval/llm.py` (DeepSeek at its peak
|
|
848
|
+
rates, so estimates are upper bounds). For a model the table does not know,
|
|
849
|
+
set `RHYLTHYME_EVAL_PRICE_IN` and `RHYLTHYME_EVAL_PRICE_OUT` in USD per
|
|
850
|
+
million tokens.
|
|
851
|
+
|
|
852
|
+
`eval/run_model_comparison.py` runs a model under a hard budget. It runs one
|
|
853
|
+
gold program at a time, both prompts per program, records each program's
|
|
854
|
+
cost in `eval/models/spend-ledger.json`, and stops before the next program
|
|
855
|
+
could cross `--cap`. The ledger is cumulative across models and
|
|
856
|
+
invocations, and the script refuses a model with no known price (it would
|
|
857
|
+
be recorded as $0 and the cap would never trip).
|
|
858
|
+
|
|
859
|
+
One OpenRouter key reaches OpenAI, Qwen and Meta models (ids with a vendor
|
|
860
|
+
prefix). Run the cheapest first and raise the cumulative cap as you go, so
|
|
861
|
+
no single model can spend the whole allowance. Reasoning models need a
|
|
862
|
+
higher per-call output ceiling than the default 16,000 tokens:
|
|
863
|
+
|
|
864
|
+
```bash
|
|
865
|
+
export OPENROUTER_API_KEY=...
|
|
866
|
+
L=eval/models/spend-ledger-openrouter.json
|
|
867
|
+
python eval/run_model_comparison.py --ledger $L --model meta-llama/llama-4-maverick --cap 0.80 --first-guess 0.05
|
|
868
|
+
python eval/run_model_comparison.py --ledger $L --model qwen/qwen3.8-flash --cap 2.00 --first-guess 0.08 --max-tokens 64000
|
|
869
|
+
python eval/run_model_comparison.py --ledger $L --model openai/gpt-5.6-luna --cap 4.50 --first-guess 0.15 --max-tokens 64000
|
|
870
|
+
python eval/compare_models.py
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
```bash
|
|
874
|
+
export DEEPSEEK_API_KEY=...
|
|
875
|
+
python eval/run_model_comparison.py --model deepseek-flash --cap 6.70 --dry-run
|
|
876
|
+
python eval/run_model_comparison.py --model deepseek-flash --cap 6.70
|
|
877
|
+
python eval/compare_models.py # like-for-like table across every model run so far
|
|
878
|
+
```
|
|
879
|
+
|
|
617
880
|
## Development
|
|
618
881
|
|
|
619
882
|
1. Clone the repository
|
|
@@ -9,6 +9,106 @@ rhylthyme login
|
|
|
9
9
|
rhylthyme generate "roast chicken, potatoes and green beans for 6" -e kitchen --by 19:00 --with "one oven"
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
+
## A timeline in five commands: a birthday party
|
|
13
|
+
|
|
14
|
+
Parents collect at 4:00. Working backwards from that: when does the cake go in
|
|
15
|
+
the oven, when do the balloons go up, and do the pizzas and the cake ever want
|
|
16
|
+
the oven at the same time?
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install rhylthyme-cli-runner
|
|
20
|
+
|
|
21
|
+
# 1. a program: the party, the kitchen and the setup crew, 13 steps
|
|
22
|
+
curl -sO https://raw.githubusercontent.com/rhylthyme/rhylthyme-cli-runner/main/examples/recipe/birthday-party.json
|
|
23
|
+
|
|
24
|
+
# 2. is it well formed?
|
|
25
|
+
rhylthyme validate birthday-party.json --strict
|
|
26
|
+
|
|
27
|
+
# 3. any clashes, and what time does everything start if we finish at 4?
|
|
28
|
+
rhylthyme analyze birthday-party.json --finish-at 16:00
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
**Makespan:** 3h 10m across 3 tracks, 13 steps.
|
|
33
|
+
**Critical path:** Guests arrive → Party games → Pizza → Candles and cake → Piñata, until it breaks → Party bags and goodbyes
|
|
34
|
+
**Binding constraints:** step dependencies only — no resource or in-flight limit gates the critical path.
|
|
35
|
+
**Peak concurrency:** 2 steps at 10:00.
|
|
36
|
+
**Resource conflicts:** none.
|
|
37
|
+
|
|
38
|
+
**Tracks that finish early:** Kitchen (1h 10m early), Setup crew (50m early)
|
|
39
|
+
|
|
40
|
+
Start Sat 12:50, finish Sat 16:00 (local time)
|
|
41
|
+
Sat 12:50 Bake the cake
|
|
42
|
+
Sat 13:00 Balloons and banner
|
|
43
|
+
Sat 13:25 Cake cools
|
|
44
|
+
Sat 13:30 Hang the piñata
|
|
45
|
+
Sat 13:50 Guests arrive
|
|
46
|
+
Sat 14:05 Frost and decorate
|
|
47
|
+
Sat 14:20 Party games
|
|
48
|
+
Sat 14:35 Pizzas in the oven
|
|
49
|
+
Sat 14:50 Fill party bags
|
|
50
|
+
Sat 14:50 Pizza
|
|
51
|
+
Sat 15:15 Candles and cake
|
|
52
|
+
Sat 15:30 Piñata, until it breaks
|
|
53
|
+
Sat 15:45 Party bags and goodbyes
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# 4. a live timeline for the fridge door (or a phone): timers, cues, and you end the piñata when it breaks
|
|
58
|
+
rhylthyme publish birthday-party.json --open --image party-preview.png
|
|
59
|
+
|
|
60
|
+
# 5. a picture for the group chat, on the wall clock (needs Node; nothing to install)
|
|
61
|
+
npx -y github:rhylthyme/rhylthyme-timeline birthday-party.json -o birthday-party.png \
|
|
62
|
+
--style web --palette vivid --label-overflow outside --start-at "$(date +%F)T12:50:00"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+

|
|
66
|
+
|
|
67
|
+
The pizzas go in 15 minutes after the games *start*, so they come out as the
|
|
68
|
+
games end; the party bags get filled while everyone is eating. Try
|
|
69
|
+
`--finish-at 17:30`, or turn the cake into a two-hour fruitcake (`"seconds": "2h"`
|
|
70
|
+
on `bake`) and `analyze` reports the clash: `oven needs 2 but max is 1 from
|
|
71
|
+
1:45:00 to 2:00:00 (bake, heat-pizza)`. `rhylthyme run birthday-party.json --time-scale 60` rehearses
|
|
72
|
+
the whole afternoon in the terminal at a minute per second.
|
|
73
|
+
|
|
74
|
+
## This repository and rhylthyme-mcp
|
|
75
|
+
|
|
76
|
+
Two repositories do related things and are easy to confuse. This one is the
|
|
77
|
+
**command a person types**. [rhylthyme-mcp](https://github.com/rhylthyme/rhylthyme-mcp)
|
|
78
|
+
is the **server an AI assistant talks to**.
|
|
79
|
+
|
|
80
|
+
| | [rhylthyme-mcp](https://github.com/rhylthyme/rhylthyme-mcp) | [rhylthyme-cli-runner](https://github.com/rhylthyme/rhylthyme-cli-runner) |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| What it is | The MCP **server**: the tools an AI assistant calls | A command-line **program**: the `rhylthyme` command |
|
|
83
|
+
| Who uses it | Claude, ChatGPT, Cursor or any MCP client, on a person's behalf | A person at a terminal, a script, or CI |
|
|
84
|
+
| Where it runs | Hosted at `mcp.rhylthyme.com`; nothing to install | On your machine: `pip install rhylthyme-cli-runner` |
|
|
85
|
+
| Language | JavaScript (Node 20+) | Python 3.12+ |
|
|
86
|
+
| Input | A program the assistant builds in conversation | A program file on disk (JSON or YAML) |
|
|
87
|
+
| Validate a program | `validate_program` | `rhylthyme validate` (works offline) |
|
|
88
|
+
| Timing, conflicts, deadlines | `analyze_schedule` | `rhylthyme analyze` (asks the server) |
|
|
89
|
+
| Publish a live timeline | `visualize_schedule` | `rhylthyme publish` (asks the server) |
|
|
90
|
+
| Run a schedule with timers | no: it hands back a link to the web timeline | `rhylthyme run`, an interactive terminal runner |
|
|
91
|
+
| Recorded runs, calibration | reads runs saved to an account | records runs locally; `rhylthyme runs`, `rhylthyme calibrate` |
|
|
92
|
+
| Catalog search, imports, account library | yes | no |
|
|
93
|
+
| Also in the repository | the `rhylthyme-mcp` PyPI package (a stdio bridge to the hosted server), the Claude plugin marketplace | the Claude skill's source, the prompt-evaluation harness and its results, `rhylthyme mcp-test` |
|
|
94
|
+
|
|
95
|
+
How they fit together: this tool is one of the MCP server's clients.
|
|
96
|
+
`rhylthyme analyze`, `publish`, `generate` and `mcp-test` are MCP calls to
|
|
97
|
+
`mcp.rhylthyme.com`; `rhylthyme validate`, `run`, `runs` and `calibrate` never
|
|
98
|
+
touch the network. Each has its own validator for the same program schema
|
|
99
|
+
(Python here, JavaScript there), so a program is checked again when it is
|
|
100
|
+
published.
|
|
101
|
+
|
|
102
|
+
Use this repository if you have a program file and a terminal, want timers in
|
|
103
|
+
the terminal, or keep run records. Use rhylthyme-mcp to connect Claude, ChatGPT
|
|
104
|
+
or another assistant, or to read or self-host the server.
|
|
105
|
+
|
|
106
|
+
Two names to keep apart: `rhylthyme-cli-runner` on PyPI is this tool (command
|
|
107
|
+
`rhylthyme`); `rhylthyme-mcp` on PyPI is the server's stdio bridge (command
|
|
108
|
+
`rhylthyme-mcp`). The program format itself is defined in
|
|
109
|
+
[rhylthyme-spec](https://github.com/rhylthyme/rhylthyme-spec), with examples in
|
|
110
|
+
[rhylthyme-examples](https://github.com/rhylthyme/rhylthyme-examples).
|
|
111
|
+
|
|
12
112
|
## Installation
|
|
13
113
|
|
|
14
114
|
### From Source
|
|
@@ -137,9 +237,30 @@ rhylthyme run examples/programs/breakfast_schedule.json --environment kitchen
|
|
|
137
237
|
rhylthyme run examples/programs/breakfast_schedule.json --no-validate
|
|
138
238
|
```
|
|
139
239
|
|
|
240
|
+
### Analyze and Publish a Program
|
|
241
|
+
|
|
242
|
+
Neither needs an account; both are computed by the hosted MCP server.
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
# Total length, critical path, resource conflicts
|
|
246
|
+
rhylthyme analyze examples/programs/breakfast_schedule.json
|
|
247
|
+
|
|
248
|
+
# When does each step start if breakfast is at 8:30?
|
|
249
|
+
rhylthyme analyze examples/programs/breakfast_schedule.json --finish-at 8:30am
|
|
250
|
+
|
|
251
|
+
# A live, shareable timeline with timers; prints the URL
|
|
252
|
+
rhylthyme publish examples/programs/breakfast_schedule.json
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
`validate` checks structure only. Two steps that want the only oven at the
|
|
256
|
+
same time pass validation; `analyze` reports them, and `--strict` makes that
|
|
257
|
+
a non-zero exit.
|
|
258
|
+
|
|
140
259
|
### Optimize a Program
|
|
141
260
|
|
|
142
|
-
|
|
261
|
+
`plan` is an older stagger heuristic that reads the pre-0.2 program format; on
|
|
262
|
+
programs written with `stepId` and `task` (all current examples) it writes the
|
|
263
|
+
program back unchanged. Use `analyze` to find contention.
|
|
143
264
|
|
|
144
265
|
```bash
|
|
145
266
|
# Optimize a program and save to new file
|
|
@@ -167,6 +288,39 @@ rhylthyme validate-environments
|
|
|
167
288
|
rhylthyme environment-info kitchen
|
|
168
289
|
```
|
|
169
290
|
|
|
291
|
+
## Claude Skill
|
|
292
|
+
|
|
293
|
+
[`skills/rhylthyme`](skills/rhylthyme) is an [Agent Skill](https://docs.claude.com/en/docs/agents-and-tools/agent-skills/overview)
|
|
294
|
+
that teaches Claude (Claude Code, the Claude apps, the Agent SDK) to turn a
|
|
295
|
+
protocol, recipe or run sheet into a validated program with this CLI, check
|
|
296
|
+
it for conflicts, and hand back a live timeline. It follows the layout of
|
|
297
|
+
[K-Dense scientific skills](https://github.com/K-Dense-AI/claude-scientific-skills):
|
|
298
|
+
a `SKILL.md` plus `references/`.
|
|
299
|
+
|
|
300
|
+
The easiest install is the Claude Code plugin, which also connects the hosted
|
|
301
|
+
MCP server:
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
/plugin marketplace add rhylthyme/rhylthyme-mcp
|
|
305
|
+
/plugin install rhylthyme@rhylthyme
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Or copy the skill by hand:
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
# Claude Code, for one user
|
|
312
|
+
mkdir -p ~/.claude/skills
|
|
313
|
+
cp -r skills/rhylthyme ~/.claude/skills/
|
|
314
|
+
|
|
315
|
+
# or for one project
|
|
316
|
+
mkdir -p .claude/skills && cp -r skills/rhylthyme .claude/skills/
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Then ask, for example, "time a Western blot so imaging is at 4 pm" or "two PCR
|
|
320
|
+
protocols, one thermocycler: when do I start each?". `tests/test_skill.py`
|
|
321
|
+
validates every program in the skill and checks that every command it names
|
|
322
|
+
exists.
|
|
323
|
+
|
|
170
324
|
## Program File Examples
|
|
171
325
|
|
|
172
326
|
### Simple Breakfast Schedule
|
|
@@ -245,6 +399,39 @@ Environment: `RHYLTHYME_TOKEN` (access token, overrides the stored session),
|
|
|
245
399
|
`RHYLTHYME_MCP_URL` (default `https://mcp.rhylthyme.com/mcp`),
|
|
246
400
|
`RHYLTHYME_SITE_URL` (default `https://www.rhylthyme.com`).
|
|
247
401
|
|
|
402
|
+
### `rhylthyme mcp-test`
|
|
403
|
+
|
|
404
|
+
Smoke-tests a Rhylthyme MCP server and exits 1 if any check fails. By
|
|
405
|
+
default it runs the read-only checks against all five hosted endpoints
|
|
406
|
+
(`/mcp`, `/kitchen/mcp`, `/lab/mcp`, `/events/mcp`, `/gym/mcp`):
|
|
407
|
+
|
|
408
|
+
| Check | What it proves |
|
|
409
|
+
|---|---|
|
|
410
|
+
| `initialize` | server name, protocol version, tools/resources/prompts capabilities, instructions |
|
|
411
|
+
| `tools` | core tools and the endpoint's one-shot tools are listed, each with a description and schema |
|
|
412
|
+
| `validate-good` / `validate-bad` | a valid program passes (including a `type: "compound"` trigger); a dangling step reference is rejected with a fix hint |
|
|
413
|
+
| `analyze` | makespan, critical path and wall-clock itinerary for a known program |
|
|
414
|
+
| `resources` / `prompts` | schema and guides are readable, a bundled example validates, `plan_schedule` substitutes its arguments |
|
|
415
|
+
| `json-accept` | clients that do not accept SSE (`*/*`, `application/json`) get JSON, not 406 |
|
|
416
|
+
| `bad-requests` | unknown method gives -32601, unknown tool gives an error, never a 5xx |
|
|
417
|
+
| `login-gate` | account tools refuse without a token and point at `login` |
|
|
418
|
+
| `catalog` | public search returns entries that load with a URL (empty catalog = warning) |
|
|
419
|
+
| `publish` (`--publish`) | `visualize_schedule` returns a URL on the right site; the page and PNG load |
|
|
420
|
+
| `generate` (`--generate`) | the model-backed `import_text` returns a program that validates (needs `login`) |
|
|
421
|
+
|
|
422
|
+
```bash
|
|
423
|
+
rhylthyme mcp-test # everything read-only
|
|
424
|
+
rhylthyme mcp-test -e lab --publish # one endpoint, plus a real share
|
|
425
|
+
rhylthyme mcp-test -k catalog -k tools # only some checks
|
|
426
|
+
rhylthyme mcp-test --url http://localhost:3000/mcp -e generic
|
|
427
|
+
rhylthyme mcp-test --json --strict # cron / CI: warnings fail too
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Requests carry `mcp-test` in the User-Agent so the hosted server logs the
|
|
431
|
+
errors these checks provoke without alerting anyone. The same suite is
|
|
432
|
+
importable (`rhylthyme_cli_runner.remote.checks.run_suite`), and
|
|
433
|
+
`RHYLTHYME_MCP_LIVE=1 pytest tests/test_mcp_checks.py` runs it live.
|
|
434
|
+
|
|
248
435
|
### `rhylthyme login` / `logout` / `whoami`
|
|
249
436
|
|
|
250
437
|
`login` opens the rhylthyme.com sign-in page and receives the session on a
|
|
@@ -271,9 +458,35 @@ Runs programs with interactive terminal UI.
|
|
|
271
458
|
- `--validate / --no-validate`: Validate before running (default: True)
|
|
272
459
|
- `--auto-start`: Automatically start without manual trigger
|
|
273
460
|
|
|
461
|
+
### `rhylthyme analyze`
|
|
462
|
+
|
|
463
|
+
Total length, critical path, what gates each link of it, resource conflicts
|
|
464
|
+
and tracks that finish early. No sign-in; nothing is published.
|
|
465
|
+
|
|
466
|
+
**Options:**
|
|
467
|
+
- `--finish-at TEXT`: when everything must be finished (`19:00`, `7:30pm` or ISO 8601); prints local clock times per step
|
|
468
|
+
- `--start-at TEXT`: when the program starts; ignored with `--finish-at`
|
|
469
|
+
- `--strict`: exit non-zero when there are resource conflicts
|
|
470
|
+
- `--json`: the full analysis
|
|
471
|
+
|
|
472
|
+
### `rhylthyme publish`
|
|
473
|
+
|
|
474
|
+
Publishes a program (a file, an http(s) URL, or `-` for standard input) as a
|
|
475
|
+
live timeline and prints its URL. No sign-in.
|
|
476
|
+
A published timeline is reachable by anyone who has the link.
|
|
477
|
+
|
|
478
|
+
**Options:**
|
|
479
|
+
- `-e, --env`: `generic`, `kitchen`, `lab`, `events`, `gym` (default: from `environmentType`)
|
|
480
|
+
- `-q, --quiet`: print only the URL
|
|
481
|
+
- `--json`: `url`, `shareId`, `imageUrl`, `makespanSeconds`, `warnings`
|
|
482
|
+
- `--image PATH`: also save a PNG of the timeline
|
|
483
|
+
- `--open`: open it in a browser
|
|
484
|
+
|
|
274
485
|
### `rhylthyme plan`
|
|
275
486
|
|
|
276
|
-
|
|
487
|
+
An older stagger heuristic. It reads the pre-0.2 program format and leaves
|
|
488
|
+
programs written with `stepId` and `task` unchanged; use `analyze` to find
|
|
489
|
+
contention and edit the triggers.
|
|
277
490
|
|
|
278
491
|
**Options:**
|
|
279
492
|
- `--verbose, -v`: Show detailed planning information
|
|
@@ -554,6 +767,56 @@ make test-unit # excludes llm
|
|
|
554
767
|
RHYLTHYME_EVAL_LIVE=1 pytest -m llm # one real call, opt in
|
|
555
768
|
```
|
|
556
769
|
|
|
770
|
+
|
|
771
|
+
### Other models and a spending cap
|
|
772
|
+
|
|
773
|
+
`--model` also accepts models served through an OpenAI-compatible API. The
|
|
774
|
+
provider is picked from the model id and the key is read from the
|
|
775
|
+
environment:
|
|
776
|
+
|
|
777
|
+
| Model id | Provider | Key |
|
|
778
|
+
|---|---|---|
|
|
779
|
+
| `claude-*` | Anthropic | `ANTHROPIC_API_KEY` |
|
|
780
|
+
| `deepseek-*` (e.g. `deepseek-flash`, `deepseek-v4-pro`) | api.deepseek.com | `DEEPSEEK_API_KEY` |
|
|
781
|
+
| `qwen*` | Alibaba DashScope (international) | `DASHSCOPE_API_KEY` |
|
|
782
|
+
| `kimi-*`, `moonshot-*` | Moonshot | `MOONSHOT_API_KEY` |
|
|
783
|
+
| `glm-*` | Z.ai | `ZAI_API_KEY` |
|
|
784
|
+
| anything with a slash, e.g. `deepseek/deepseek-flash` | OpenRouter | `OPENROUTER_API_KEY` |
|
|
785
|
+
| any id, with `RHYLTHYME_EVAL_BASE_URL` set | that endpoint (vLLM, Ollama, ...) | `RHYLTHYME_EVAL_API_KEY`, optional for localhost |
|
|
786
|
+
|
|
787
|
+
Costs come from the price table in `eval/llm.py` (DeepSeek at its peak
|
|
788
|
+
rates, so estimates are upper bounds). For a model the table does not know,
|
|
789
|
+
set `RHYLTHYME_EVAL_PRICE_IN` and `RHYLTHYME_EVAL_PRICE_OUT` in USD per
|
|
790
|
+
million tokens.
|
|
791
|
+
|
|
792
|
+
`eval/run_model_comparison.py` runs a model under a hard budget. It runs one
|
|
793
|
+
gold program at a time, both prompts per program, records each program's
|
|
794
|
+
cost in `eval/models/spend-ledger.json`, and stops before the next program
|
|
795
|
+
could cross `--cap`. The ledger is cumulative across models and
|
|
796
|
+
invocations, and the script refuses a model with no known price (it would
|
|
797
|
+
be recorded as $0 and the cap would never trip).
|
|
798
|
+
|
|
799
|
+
One OpenRouter key reaches OpenAI, Qwen and Meta models (ids with a vendor
|
|
800
|
+
prefix). Run the cheapest first and raise the cumulative cap as you go, so
|
|
801
|
+
no single model can spend the whole allowance. Reasoning models need a
|
|
802
|
+
higher per-call output ceiling than the default 16,000 tokens:
|
|
803
|
+
|
|
804
|
+
```bash
|
|
805
|
+
export OPENROUTER_API_KEY=...
|
|
806
|
+
L=eval/models/spend-ledger-openrouter.json
|
|
807
|
+
python eval/run_model_comparison.py --ledger $L --model meta-llama/llama-4-maverick --cap 0.80 --first-guess 0.05
|
|
808
|
+
python eval/run_model_comparison.py --ledger $L --model qwen/qwen3.8-flash --cap 2.00 --first-guess 0.08 --max-tokens 64000
|
|
809
|
+
python eval/run_model_comparison.py --ledger $L --model openai/gpt-5.6-luna --cap 4.50 --first-guess 0.15 --max-tokens 64000
|
|
810
|
+
python eval/compare_models.py
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
```bash
|
|
814
|
+
export DEEPSEEK_API_KEY=...
|
|
815
|
+
python eval/run_model_comparison.py --model deepseek-flash --cap 6.70 --dry-run
|
|
816
|
+
python eval/run_model_comparison.py --model deepseek-flash --cap 6.70
|
|
817
|
+
python eval/compare_models.py # like-for-like table across every model run so far
|
|
818
|
+
```
|
|
819
|
+
|
|
557
820
|
## Development
|
|
558
821
|
|
|
559
822
|
1. Clone the repository
|
|
@@ -19,7 +19,7 @@ def read_readme():
|
|
|
19
19
|
|
|
20
20
|
setup(
|
|
21
21
|
name="rhylthyme-cli-runner",
|
|
22
|
-
version="0.2.
|
|
22
|
+
version="0.2.3a0",
|
|
23
23
|
description="CLI runner for Rhylthyme real-time program schedules",
|
|
24
24
|
long_description=read_readme(),
|
|
25
25
|
long_description_content_type="text/markdown",
|
{rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/__init__.py
RENAMED
|
@@ -6,7 +6,7 @@ This package provides the command-line interface for running and validating
|
|
|
6
6
|
Rhylthyme real-time program schedules.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
__version__ = "0.2.
|
|
9
|
+
__version__ = "0.2.3a0"
|
|
10
10
|
__author__ = "Rhylthyme Team"
|
|
11
11
|
__description__ = "CLI runner for Rhylthyme real-time program schedules"
|
|
12
12
|
|
{rhylthyme_cli_runner-0.2.0a0 → rhylthyme_cli_runner-0.2.3a0}/src/rhylthyme_cli_runner/eval/cli.py
RENAMED
|
@@ -321,7 +321,10 @@ def _live(
|
|
|
321
321
|
if fake_client_path:
|
|
322
322
|
with open(fake_client_path, "r", encoding="utf-8") as handle:
|
|
323
323
|
fake_responses = json.load(handle)
|
|
324
|
-
|
|
324
|
+
try:
|
|
325
|
+
client = make_client(fake_responses, model=model)
|
|
326
|
+
except RuntimeError as exc:
|
|
327
|
+
raise click.UsageError(str(exc))
|
|
325
328
|
|
|
326
329
|
gold_set = _load_gold(gold_dir)
|
|
327
330
|
out_root = Path(out_dir)
|