quickstarted 0.2.0__tar.gz → 0.3.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.
- {quickstarted-0.2.0 → quickstarted-0.3.0}/.gitignore +3 -0
- quickstarted-0.3.0/CHANGELOG.md +145 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/CONTRIBUTING.md +6 -6
- {quickstarted-0.2.0 → quickstarted-0.3.0}/DESIGN.md +5 -5
- {quickstarted-0.2.0 → quickstarted-0.3.0}/PKG-INFO +109 -69
- {quickstarted-0.2.0 → quickstarted-0.3.0}/README.md +108 -68
- {quickstarted-0.2.0 → quickstarted-0.3.0}/RELEASING.md +4 -17
- {quickstarted-0.2.0 → quickstarted-0.3.0}/SECURITY.md +5 -5
- {quickstarted-0.2.0 → quickstarted-0.3.0}/docs/explanation/proxy.md +3 -2
- {quickstarted-0.2.0 → quickstarted-0.3.0}/docs/explanation/scoring.md +1 -1
- {quickstarted-0.2.0 → quickstarted-0.3.0}/docs/getting-started/agent-mode.md +14 -44
- quickstarted-0.3.0/docs/getting-started/first-run.md +138 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/docs/getting-started/install.md +13 -9
- {quickstarted-0.2.0 → quickstarted-0.3.0}/docs/guides/affordances.md +4 -4
- {quickstarted-0.2.0 → quickstarted-0.3.0}/docs/guides/ci.md +8 -8
- {quickstarted-0.2.0 → quickstarted-0.3.0}/docs/guides/cost.md +3 -3
- {quickstarted-0.2.0 → quickstarted-0.3.0}/docs/guides/pass-rates.md +28 -20
- quickstarted-0.3.0/docs/guides/replay-mode.md +83 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/docs/guides/sandboxing.md +14 -9
- quickstarted-0.3.0/docs/guides/writing-tasks.md +237 -0
- quickstarted-0.3.0/docs/index.md +110 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/docs/reference/cli.md +13 -13
- {quickstarted-0.2.0 → quickstarted-0.3.0}/docs/reference/environment.md +15 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/docs/reference/results.md +46 -24
- quickstarted-0.2.0/docs/reference/journey-schema.md → quickstarted-0.3.0/docs/reference/task-schema.md +40 -6
- {quickstarted-0.2.0 → quickstarted-0.3.0}/docs/reference/trace.md +16 -3
- {quickstarted-0.2.0 → quickstarted-0.3.0}/docs_hooks.py +1 -1
- {quickstarted-0.2.0 → quickstarted-0.3.0}/mkdocs.yml +6 -3
- {quickstarted-0.2.0 → quickstarted-0.3.0}/pyproject.toml +2 -2
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/__init__.py +7 -7
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/_version.py +1 -1
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/agents/base.py +18 -9
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/agents/claude.py +56 -9
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/agents/gemini_agent.py +5 -5
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/agents/openai_agent.py +6 -6
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/agents/prompt.py +8 -8
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/agents/replay.py +8 -8
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/cli.py +59 -26
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/docs.py +61 -6
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/exec/base.py +18 -9
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/exec/docker.py +150 -22
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/exec/local.py +1 -1
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/exec/seatbelt.py +16 -11
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/net/proxy.py +20 -6
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/report.py +15 -14
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/results.py +11 -8
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/run.py +34 -27
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/suite.py +22 -22
- quickstarted-0.2.0/src/quickstarted/journey.py → quickstarted-0.3.0/src/quickstarted/task.py +43 -20
- quickstarted-0.3.0/tasks/README.md +65 -0
- quickstarted-0.3.0/tasks/django-quickstart.yaml +77 -0
- quickstarted-0.3.0/tasks/fastapi-quickstart.yaml +83 -0
- {quickstarted-0.2.0/journeys → quickstarted-0.3.0/tasks}/httpx-quickstart.yaml +2 -2
- quickstarted-0.3.0/tasks/prefect-quickstart.yaml +55 -0
- quickstarted-0.3.0/tasks/prisma-quickstart.yaml +77 -0
- {quickstarted-0.2.0/journeys → quickstarted-0.3.0/tasks}/quickstarted-quickstart.yaml +2 -2
- {quickstarted-0.2.0/journeys → quickstarted-0.3.0/tasks}/streamlit-quickstart.yaml +20 -7
- quickstarted-0.3.0/tasks/tailwind-quickstart.yaml +45 -0
- quickstarted-0.3.0/tasks/uv-quickstart.yaml +42 -0
- quickstarted-0.3.0/tasks/vite-quickstart.yaml +29 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/tests/test_agents.py +37 -17
- {quickstarted-0.2.0 → quickstarted-0.3.0}/tests/test_claude_credentials.py +3 -3
- {quickstarted-0.2.0 → quickstarted-0.3.0}/tests/test_cli.py +30 -5
- {quickstarted-0.2.0 → quickstarted-0.3.0}/tests/test_docker_backend.py +38 -3
- {quickstarted-0.2.0 → quickstarted-0.3.0}/tests/test_docs.py +84 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/tests/test_exec.py +29 -2
- {quickstarted-0.2.0 → quickstarted-0.3.0}/tests/test_run.py +20 -20
- {quickstarted-0.2.0 → quickstarted-0.3.0}/tests/test_sandbox.py +20 -1
- {quickstarted-0.2.0 → quickstarted-0.3.0}/tests/test_suite.py +43 -43
- quickstarted-0.2.0/tests/test_journey.py → quickstarted-0.3.0/tests/test_task.py +52 -20
- quickstarted-0.2.0/CHANGELOG.md +0 -72
- quickstarted-0.2.0/docs/getting-started/first-run.md +0 -97
- quickstarted-0.2.0/docs/guides/writing-journeys.md +0 -132
- quickstarted-0.2.0/docs/index.md +0 -73
- quickstarted-0.2.0/journeys/fastapi-quickstart.yaml +0 -52
- {quickstarted-0.2.0 → quickstarted-0.3.0}/LICENSE +0 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/docs/explanation/comparison.md +0 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/agents/__init__.py +0 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/agents/registry.py +0 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/exec/__init__.py +0 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/net/__init__.py +0 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/net/proxy_main.py +0 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/pricing.py +0 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/sandbox.py +0 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/trace.py +0 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/src/quickstarted/transport.py +0 -0
- {quickstarted-0.2.0/journeys → quickstarted-0.3.0/tasks}/bottomtime-quickstart.yaml +0 -0
- {quickstarted-0.2.0/journeys → quickstarted-0.3.0/tasks}/duckdb-quickstart.yaml +0 -0
- {quickstarted-0.2.0/journeys → quickstarted-0.3.0/tasks}/pnf-quickstart.yaml +0 -0
- {quickstarted-0.2.0/journeys → quickstarted-0.3.0/tasks}/polars-quickstart.yaml +0 -0
- {quickstarted-0.2.0 → quickstarted-0.3.0}/tests/test_proxy.py +0 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. This project follows
|
|
4
|
+
[Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## [0.3.0] - 2026-07-26
|
|
7
|
+
|
|
8
|
+
Breaking, and deliberately early. The unit of testing is now a **task**, not a
|
|
9
|
+
journey.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **`journey` is now `task`**, everywhere: the `journeys/` directory is
|
|
14
|
+
`tasks/`, `load_journey` is `load_task`, `run_journey` is `run_task`, the
|
|
15
|
+
`Journey` dataclass is `Task`, and `JourneyError` is `TaskError`.
|
|
16
|
+
"Journey" came from analytics funnels and describes the wrong shape. A task
|
|
17
|
+
is a goal plus one exit code, and "can an agent complete this task from your
|
|
18
|
+
docs" is the claim the tool actually tests.
|
|
19
|
+
- **`results.json` is schema 2.0**: the `journey` and `journeys` keys are now
|
|
20
|
+
`task` and `tasks`. Nothing else about the document changed, so a 1.0
|
|
21
|
+
consumer needs only that substitution.
|
|
22
|
+
- `quickstarted validate` and `quickstarted run` still accept paths under
|
|
23
|
+
`journeys/` and read the matching file in `tasks/`, printing a warning. That
|
|
24
|
+
fallback is removed in 0.4.0.
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- **Per-task container image** (`image:` in a task file). The default
|
|
29
|
+
`python:3.12-slim` has no Node, so a suite could not mix a Python quickstart
|
|
30
|
+
with a JavaScript one; `--image` is one flag for a whole invocation.
|
|
31
|
+
Precedence is task, then `--image`, then the default. The resolved image is
|
|
32
|
+
recorded in `results.json` and printed beside the backend, because a pass
|
|
33
|
+
rate is not comparable across base images.
|
|
34
|
+
- `validate` warns when a success script calls `npm`, `npx`, `node`, `pnpm`,
|
|
35
|
+
`yarn`, or `bun` while no image is set, since that check would fail for a
|
|
36
|
+
reason unrelated to the documentation.
|
|
37
|
+
- **Six more tasks**, doubling the set to 14 and covering both runtimes: `uv`,
|
|
38
|
+
`django`, `prefect` (Python) and `vite`, `prisma`, `tailwind` (Node).
|
|
39
|
+
- Four hosts added to the default network allowlist:
|
|
40
|
+
`release-assets.githubusercontent.com`, where npm packages with prebuilt
|
|
41
|
+
native binaries fetch during install, and the Debian and Ubuntu mirrors, so a
|
|
42
|
+
quickstart that opens with `apt-get install` works. `raw.githubusercontent.com`
|
|
43
|
+
stays out on purpose: projects serve READMEs from it, and a documentation host
|
|
44
|
+
the shell can reach is an attribution hole.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- **Client-side redirects are followed.** DuckDB answers its own versioned doc
|
|
49
|
+
URLs with 938 bytes of HTML that render as 73 characters of "Redirecting...",
|
|
50
|
+
naming the real page in a `<meta http-equiv="refresh">`. The fetcher handed
|
|
51
|
+
those 73 characters to the agent as though they were documentation, so the
|
|
52
|
+
duckdb task was measuring recovery from an empty page. A browser follows the
|
|
53
|
+
refresh, so an agent with one reads the docs and an agent without reads
|
|
54
|
+
nothing; following it keeps the two comparable. The hop is taken only within
|
|
55
|
+
the same host, since a stub pointing elsewhere would read a page the task
|
|
56
|
+
never allowlisted, and both URLs land in the trace as
|
|
57
|
+
`docs_redirect_followed`. The same entrypoint now yields 21,659 characters.
|
|
58
|
+
- **Docker workspaces no longer leak into the VM (macOS).** The sandbox root
|
|
59
|
+
came from `tempfile.mkdtemp()`, which on macOS returns a path under
|
|
60
|
+
`/var/folders`. That is not shared with the Docker VM, so `-v` created a
|
|
61
|
+
directory of the same name *inside* the VM and mounted that instead. Runs
|
|
62
|
+
passed, but the host saw an empty workspace, `--keep-sandbox` handed back
|
|
63
|
+
nothing, and cleanup freed no bytes. Found by filling a 19 GB Colima disk with
|
|
64
|
+
132 orphaned workspaces, after which every run failed with `no space left on
|
|
65
|
+
device` and was correctly classified `harness_error`. The root now defaults to
|
|
66
|
+
`~/.quickstarted/sandboxes` on macOS, overridable with
|
|
67
|
+
`QUICKSTARTED_SANDBOX_DIR`, and the mount is probed in both directions at
|
|
68
|
+
startup so a path the daemon cannot see is refused immediately.
|
|
69
|
+
- **The workspace starts empty.** `HOME` and `TMPDIR` used to point inside the
|
|
70
|
+
workspace, so `.npm`, `.cache` and `tmp/` were there before the agent ran a
|
|
71
|
+
single command, and every scaffolding tool that requires an empty directory
|
|
72
|
+
refused: `npm create vite@latest .`, `django-admin startproject .`,
|
|
73
|
+
`cargo new`. An agent had to notice and work around a mess the harness made,
|
|
74
|
+
which is measurement noise dressed up as a documentation problem. Under
|
|
75
|
+
`docker` both now live on the container's own filesystem; under `seatbelt` and
|
|
76
|
+
`local` they are siblings of the workspace inside the same sandbox, so the
|
|
77
|
+
kernel policy is unchanged.
|
|
78
|
+
|
|
79
|
+
## [0.2.0] - 2026-07-26
|
|
80
|
+
|
|
81
|
+
The v0.1 harness could be talked out of its own guarantees: the docs allowlist
|
|
82
|
+
lived in the `read_docs` tool, so any agent that ran `curl` read pages the
|
|
83
|
+
trace never saw, and commands ran unconfined on the host. This release makes
|
|
84
|
+
the boundary real and makes the output publishable.
|
|
85
|
+
|
|
86
|
+
### Added
|
|
87
|
+
|
|
88
|
+
- **Execution backends** (`quickstarted.exec`): `docker`, `seatbelt` (macOS), and
|
|
89
|
+
`local`. `auto` prefers an enforced backend. `quickstarted run` refuses the
|
|
90
|
+
unenforced one unless `--allow-unenforced` is given. Both enforced backends
|
|
91
|
+
are verified against live daemons, including tests asserting that a direct
|
|
92
|
+
connection bypassing the proxy fails.
|
|
93
|
+
- **Egress proxy** (`quickstarted.net`): all shell traffic leaves through a
|
|
94
|
+
harness-owned proxy. Documentation hosts are unreachable from the shell, so
|
|
95
|
+
the recorded set of pages read is complete; attempts to bypass are counted.
|
|
96
|
+
`network.allow` in a journey names hosts a shell may reach for installs.
|
|
97
|
+
- **Run classification**: `passed`, `docs_gap`, `budget_exhausted`,
|
|
98
|
+
`infra_error`, `harness_error`, `agent_refusal`. Only the first two are
|
|
99
|
+
evidence about documentation. The rest are excluded from pass rates, and
|
|
100
|
+
reported separately.
|
|
101
|
+
- **Pass rates**: `--repeat N` and `--workers N`. A single run is one sample,
|
|
102
|
+
and the rate over several is the number worth reading.
|
|
103
|
+
- **Affordance policy**: `--affordances all|none` withholds `llms.txt` and
|
|
104
|
+
`.md` variants so the same journey can be run both ways and the difference
|
|
105
|
+
measured. `--probe-affordances` records what exists. Never scored.
|
|
106
|
+
- **Docs cache and politeness**: `--cache-dir`, `--refresh` (flags content
|
|
107
|
+
that changed between runs), `--offline`, `--rate-limit`, `--ignore-robots`.
|
|
108
|
+
Truthful User-Agent, robots.txt honoured by default.
|
|
109
|
+
- **Machine-readable output**: versioned `results.json` (schema 1.0) and
|
|
110
|
+
`--junit` XML, where a docs gap is a failure and an infrastructure problem is
|
|
111
|
+
an error.
|
|
112
|
+
- **More agents**: `openai` and `gemini` adapters alongside `claude`, sharing
|
|
113
|
+
one prompt so cross-model numbers compare like with like. Neither assumes a
|
|
114
|
+
default model. Token counts are normalised across vendors: OpenAI and Google
|
|
115
|
+
report a prompt total that includes cached tokens while Anthropic excludes
|
|
116
|
+
them, so adapters subtract the overlap and the four counters never bill the
|
|
117
|
+
same token twice.
|
|
118
|
+
- **Retries** with exponential backoff on transient upstream faults. Every wait
|
|
119
|
+
lands in the trace instead of being absorbed silently by the SDK.
|
|
120
|
+
- **Token budgets** (`budgets.max_tokens`) and optional cost estimation from a
|
|
121
|
+
price book you supply (`--prices`). No prices ship with the tool.
|
|
122
|
+
- `quickstarted doctor`, reporting what this machine can enforce.
|
|
123
|
+
- Tests: proxy policy, Seatbelt confinement, classification, statistics,
|
|
124
|
+
caching, robots, and the affordance ablation.
|
|
125
|
+
|
|
126
|
+
### Changed
|
|
127
|
+
|
|
128
|
+
- Cached prompt tokens are counted. Previously a run costing ~120k cache-read
|
|
129
|
+
tokens reported "22 in" and looked free.
|
|
130
|
+
- The Claude adapter defaults to `claude-opus-5` and records the exact model
|
|
131
|
+
the API served, since an alias can change under a benchmark.
|
|
132
|
+
- Agents are told what `setup` already did, so they stop rebuilding a
|
|
133
|
+
virtualenv that exists.
|
|
134
|
+
- Journeys no longer list package registries under `docs.allow`; `validate`
|
|
135
|
+
warns when they do, because the proxy will refuse `pip`.
|
|
136
|
+
|
|
137
|
+
### Fixed
|
|
138
|
+
|
|
139
|
+
- `Trace` is thread-safe; the proxy appends from its own threads.
|
|
140
|
+
|
|
141
|
+
## [0.1.0] - 2026-07-24
|
|
142
|
+
|
|
143
|
+
Initial release: journey spec, replay and Claude agent modes, sandboxed
|
|
144
|
+
execution, docs fetch with attribution, deterministic scoring, CLI and
|
|
145
|
+
GitHub Action.
|
|
@@ -13,14 +13,14 @@ python3 -m venv .venv
|
|
|
13
13
|
Tests that touch the network are skipped unless `QUICKSTARTED_NETWORK_TESTS=1`
|
|
14
14
|
is set. No test needs an API key.
|
|
15
15
|
|
|
16
|
-
## Writing a
|
|
16
|
+
## Writing a task
|
|
17
17
|
|
|
18
|
-
A good
|
|
18
|
+
A good task asserts an outcome the documentation actually promises, and
|
|
19
19
|
nothing else.
|
|
20
20
|
|
|
21
21
|
- **Assert the data.** Check that `out.csv` holds the right rows. Do not check
|
|
22
22
|
which function the agent called; any correct route should pass.
|
|
23
|
-
- **Do not assert incidental paths.** An early
|
|
23
|
+
- **Do not assert incidental paths.** An early task checked for a `.venv`
|
|
24
24
|
the docs never mention; an agent that made `venv/` "failed" for no reason.
|
|
25
25
|
If `setup` creates something, the agent is told, and the check may rely on
|
|
26
26
|
it.
|
|
@@ -31,12 +31,12 @@ nothing else.
|
|
|
31
31
|
through `read_docs`; a shell cannot reach them. Putting `pypi.org` there
|
|
32
32
|
stops `pip` working. `quickstarted validate` warns about this.
|
|
33
33
|
|
|
34
|
-
Run `quickstarted run <
|
|
35
|
-
commands do not pass, the
|
|
34
|
+
Run `quickstarted run <task> --agent replay` first. If the documented
|
|
35
|
+
commands do not pass, the task is not ready for agent mode.
|
|
36
36
|
|
|
37
37
|
## Adding an agent adapter
|
|
38
38
|
|
|
39
|
-
Implement `run(
|
|
39
|
+
Implement `run(task, toolbelt, deadline) -> AgentOutcome` and act only
|
|
40
40
|
through the toolbelt: never touch the filesystem or network directly, or the
|
|
41
41
|
run loses the attribution and enforcement the whole tool depends on.
|
|
42
42
|
|
|
@@ -8,7 +8,7 @@ verdict. LLM judges may eventually classify WHY a run failed; they will never
|
|
|
8
8
|
decide WHETHER it failed. This keeps the tool falsifiable and keeps vendors
|
|
9
9
|
(including Anthropic) out of the scoring path.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Every page read goes through a tool the agent cannot bypass
|
|
12
12
|
|
|
13
13
|
Agents act only through the Toolbelt (`bash` + `read_docs`), so every page read
|
|
14
14
|
is recorded and failures attribute to a page.
|
|
@@ -26,7 +26,7 @@ pages the agent read.
|
|
|
26
26
|
This creates one deliberate asymmetry: `docs.allow` hosts are readable only via
|
|
27
27
|
`read_docs`, and `network.allow` hosts (package registries) are reachable only
|
|
28
28
|
from the shell. When a host is genuinely both, PyPI being the obvious case, the
|
|
29
|
-
|
|
29
|
+
task says so explicitly and installs win. The resulting gap in attribution
|
|
30
30
|
is reported alongside the result.
|
|
31
31
|
|
|
32
32
|
## Backends, and saying which one ran
|
|
@@ -65,7 +65,7 @@ measurement of the affordance itself.
|
|
|
65
65
|
That question is currently argued without data. This is the only shape of tool
|
|
66
66
|
that can answer it, because answering it requires running the task.
|
|
67
67
|
|
|
68
|
-
## Replay mode is
|
|
68
|
+
## Replay mode is a precondition
|
|
69
69
|
|
|
70
70
|
Replay (documented commands verbatim, no LLM) is free, deterministic and
|
|
71
71
|
CI-friendly, and it defines a floor: if replay fails, agent mode is noise. It
|
|
@@ -97,8 +97,8 @@ would quietly misreport what a sweep costs.
|
|
|
97
97
|
out at all, so the isolation does not depend on name resolution.
|
|
98
98
|
- HTML-to-text is a crude tag stripper, so markdown-native docs read better.
|
|
99
99
|
That is itself a finding worth publishing.
|
|
100
|
-
- Concurrency is per-attempt threads
|
|
101
|
-
|
|
100
|
+
- Concurrency is per-attempt threads. Hosts are rate-limited individually, and
|
|
101
|
+
there is no global budget governor.
|
|
102
102
|
- No pip/npm cache; every run cold-installs.
|
|
103
103
|
- The Gemini adapter is written against the same Toolbelt contract but has not
|
|
104
104
|
been run live; Claude and OpenAI have.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quickstarted
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Test whether an AI agent can actually complete your quickstart by following your docs
|
|
5
5
|
Project-URL: Homepage, https://github.com/snehankekre/quickstarted
|
|
6
6
|
Project-URL: Issues, https://github.com/snehankekre/quickstarted/issues
|
|
@@ -66,84 +66,106 @@ Full documentation: **https://snehankekre.com/quickstarted/**
|
|
|
66
66
|
|
|
67
67
|
## How it works
|
|
68
68
|
|
|
69
|
-
You write a
|
|
69
|
+
You write a task, in YAML. This one points at Streamlit's documentation:
|
|
70
70
|
|
|
71
71
|
```yaml
|
|
72
|
-
name:
|
|
72
|
+
name: streamlit-quickstart
|
|
73
73
|
goal: >
|
|
74
|
-
Install
|
|
75
|
-
|
|
74
|
+
Install Streamlit into the virtualenv in this workspace and build a small app
|
|
75
|
+
in app.py that shows a title and a slider whose value is displayed on the
|
|
76
|
+
page. Do not start a long-running server yourself; just leave app.py ready to
|
|
77
|
+
run and confirm streamlit is installed.
|
|
76
78
|
docs:
|
|
77
|
-
entrypoint: https://
|
|
79
|
+
entrypoint: https://docs.streamlit.io/get-started
|
|
78
80
|
allow:
|
|
79
|
-
-
|
|
81
|
+
- docs.streamlit.io
|
|
82
|
+
- streamlit.io
|
|
80
83
|
setup:
|
|
81
84
|
- python3 -m venv .venv
|
|
82
85
|
success:
|
|
83
86
|
script: |
|
|
84
87
|
set -e
|
|
85
|
-
|
|
86
|
-
.venv/bin/python
|
|
87
|
-
replay:
|
|
88
|
-
- .venv/bin/pip install pnf
|
|
89
|
-
- printf 'import pnf\nprint(pnf.decode.__name__)\n' > demo.py
|
|
90
|
-
- .venv/bin/python demo.py
|
|
88
|
+
test -f app.py
|
|
89
|
+
.venv/bin/python -c "import streamlit"
|
|
91
90
|
```
|
|
92
91
|
|
|
93
|
-
|
|
94
|
-
`bash`, and `read_docs`, which is the only way it can read documentation.
|
|
95
|
-
|
|
96
|
-
The harness enforces that. All shell traffic leaves through a proxy it owns,
|
|
97
|
-
and documentation hosts are unreachable from the shell, so an agent that tries
|
|
98
|
-
`curl https://docs.example.com/...` is refused and the attempt is recorded.
|
|
99
|
-
The pages listed in a report are therefore the pages the agent really read.
|
|
100
|
-
When a run fails, the last page it read is a fact you can act on.
|
|
101
|
-
|
|
102
|
-
When the agent stops, the harness runs your `success.script` in the workspace.
|
|
103
|
-
Exit code 0 is a pass. Nothing else is. The agent's own claim of success is
|
|
104
|
-
recorded and never trusted; there is no LLM judge anywhere in scoring.
|
|
105
|
-
|
|
106
|
-
## Two modes
|
|
107
|
-
|
|
108
|
-
**Replay mode** (free, no LLM, no API key) runs your `replay` commands, the
|
|
109
|
-
literal commands your docs tell users to type, and stops at the first failure.
|
|
110
|
-
Treat it as a precondition. If the documented commands break, no reader stands
|
|
111
|
-
a chance, and agent mode only adds noise.
|
|
92
|
+
Then you run an agent against it:
|
|
112
93
|
|
|
113
94
|
```
|
|
114
|
-
|
|
95
|
+
pip install "quickstarted[claude]"
|
|
96
|
+
export QUICKSTARTED_ANTHROPIC_API_KEY=...
|
|
97
|
+
quickstarted run tasks/streamlit-quickstart.yaml --agent claude
|
|
115
98
|
```
|
|
116
99
|
|
|
117
|
-
**Agent mode** has an LLM follow your docs to the goal. This catches what
|
|
118
|
-
replay cannot: ambiguity, missing steps, wrong ordering, docs that assume
|
|
119
|
-
context a newcomer does not have.
|
|
120
|
-
|
|
121
100
|
```
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
101
|
+
[PASS] streamlit-quickstart (claude:claude-opus-5)
|
|
102
|
+
classification: passed
|
|
103
|
+
turns: 6, duration: 63.5s
|
|
104
|
+
backend: docker
|
|
105
|
+
tokens: 12 in / 1150 out, cache 11204 written / 33181 read
|
|
106
|
+
docs pages read: 4
|
|
125
107
|
```
|
|
126
108
|
|
|
109
|
+
The agent works in a throwaway workspace with two tools: a sandboxed `bash`,
|
|
110
|
+
and `read_docs`, which is the only way it can read documentation. It gets no
|
|
111
|
+
browser, no search engine, and no network of its own. The system prompt also
|
|
112
|
+
forbids leaning on prior knowledge of the project under test, because a model
|
|
113
|
+
that already knows Streamlit would sail through docs that teach a newcomer
|
|
114
|
+
nothing.
|
|
115
|
+
|
|
116
|
+
The harness enforces the boundary rather than requesting it. All shell traffic
|
|
117
|
+
leaves through a proxy the harness owns, and documentation hosts are
|
|
118
|
+
unreachable from the shell, so an agent that tries
|
|
119
|
+
`curl https://docs.streamlit.io/...` is refused and the attempt is recorded.
|
|
120
|
+
The pages in a report are therefore the pages the agent really read, and when a
|
|
121
|
+
run fails, the last page it read is a fact rather than a guess.
|
|
122
|
+
|
|
127
123
|
Keys are read from `QUICKSTARTED_*` names first so they can sit in your shell
|
|
128
124
|
without other tooling on the same machine picking them up and spending them.
|
|
129
125
|
The vendor-standard names still work as a fallback, which is what CI sets.
|
|
130
126
|
|
|
127
|
+
## The success script is the whole verdict
|
|
128
|
+
|
|
129
|
+
When the agent stops, the harness runs your `success.script` in the same
|
|
130
|
+
workspace. Exit code 0 is a pass. Nothing else is. The agent's own claim of
|
|
131
|
+
success is recorded and never trusted, and there is no LLM judge anywhere in
|
|
132
|
+
scoring, because a model asked to grade its own work will tell you the app is
|
|
133
|
+
ready when `app.py` does not parse.
|
|
134
|
+
|
|
135
|
+
Most checks are the size of the one above. You are asserting whatever your
|
|
136
|
+
tutorial already promises the reader: the file exists, the import works, the
|
|
137
|
+
command runs, the output contains the number on the page. If your quickstart
|
|
138
|
+
ends with "you should see `200`", the check is `grep -q 200`.
|
|
139
|
+
|
|
140
|
+
You can go stricter when it is worth it.
|
|
141
|
+
[tasks/streamlit-quickstart.yaml](tasks/streamlit-quickstart.yaml) boots
|
|
142
|
+
the app headless and polls Streamlit's own health endpoint, which is about
|
|
143
|
+
fifteen more lines and proves the app actually serves. That is optional. Start
|
|
144
|
+
with the two-line version.
|
|
145
|
+
|
|
146
|
+
## Replay mode, the free precondition
|
|
147
|
+
|
|
148
|
+
`--agent replay` runs your `replay` commands, the literal commands your docs
|
|
149
|
+
tell a reader to type, and stops at the first failure. No model, no API key, no
|
|
150
|
+
cost.
|
|
151
|
+
|
|
131
152
|
```
|
|
132
|
-
|
|
133
|
-
classification: passed
|
|
134
|
-
turns: 12, duration: 70.7s
|
|
135
|
-
backend: seatbelt
|
|
136
|
-
tokens: 24 in / 4616 out, cache 16812 written / 104148 read
|
|
137
|
-
docs pages read: 2
|
|
153
|
+
quickstarted run tasks/streamlit-quickstart.yaml --agent replay
|
|
138
154
|
```
|
|
139
155
|
|
|
156
|
+
Treat it as a floor to check on every push. If the documented commands are
|
|
157
|
+
broken, no reader stands a chance and an agent run only adds noise on top of a
|
|
158
|
+
failure you already know about. It cannot tell you whether a reader could have
|
|
159
|
+
*found* those commands, understood their order, or guessed the prerequisite you
|
|
160
|
+
left out. That is what agent mode is for.
|
|
161
|
+
|
|
140
162
|
## Pass rates
|
|
141
163
|
|
|
142
164
|
The same docs and the same model can pass at 10:00 and fail at 10:05. One run
|
|
143
165
|
is a sample. Use `--repeat` and read the rate:
|
|
144
166
|
|
|
145
167
|
```
|
|
146
|
-
quickstarted run
|
|
168
|
+
quickstarted run tasks/*.yaml --agent claude --repeat 5 --workers 3
|
|
147
169
|
```
|
|
148
170
|
|
|
149
171
|
Every run is classified, and only two classifications say anything about your
|
|
@@ -155,7 +177,7 @@ documentation:
|
|
|
155
177
|
| `docs_gap` | the agent finished, the check failed | yes |
|
|
156
178
|
| `budget_exhausted` | out of turns, time, or tokens | no |
|
|
157
179
|
| `infra_error` | rate limit, upstream 5xx, network failure | no |
|
|
158
|
-
| `harness_error` | misconfigured
|
|
180
|
+
| `harness_error` | misconfigured task, our bug | no |
|
|
159
181
|
| `agent_refusal` | model declined | no |
|
|
160
182
|
|
|
161
183
|
Runs that produced no evidence are excluded from the numerator *and* the
|
|
@@ -169,11 +191,11 @@ scoring it would be the proxy metric this tool exists to replace. So
|
|
|
169
191
|
quickstarted never scores affordances. It measures them:
|
|
170
192
|
|
|
171
193
|
```
|
|
172
|
-
quickstarted run
|
|
173
|
-
quickstarted run
|
|
194
|
+
quickstarted run tasks/streamlit-quickstart.yaml --agent claude --repeat 10
|
|
195
|
+
quickstarted run tasks/streamlit-quickstart.yaml --agent claude --repeat 10 --affordances none
|
|
174
196
|
```
|
|
175
197
|
|
|
176
|
-
Same prompt, same
|
|
198
|
+
Same prompt, same task, same model. The only difference is whether the
|
|
177
199
|
agent could read `llms.txt` and `.md` variants. The difference in pass rate is
|
|
178
200
|
a measurement of the affordance itself.
|
|
179
201
|
|
|
@@ -199,9 +221,9 @@ can enforce. Details in [SECURITY.md](SECURITY.md).
|
|
|
199
221
|
## Install
|
|
200
222
|
|
|
201
223
|
```
|
|
202
|
-
pip install quickstarted
|
|
203
|
-
pip install "quickstarted[claude]" # + Claude
|
|
224
|
+
pip install "quickstarted[claude]" # agent mode with Claude
|
|
204
225
|
pip install "quickstarted[all-agents]" # + OpenAI and Gemini
|
|
226
|
+
pip install quickstarted # replay mode only, no SDK
|
|
205
227
|
```
|
|
206
228
|
|
|
207
229
|
Python 3.9+. One runtime dependency: PyYAML. Every adapter is a plain tool-use
|
|
@@ -210,25 +232,43 @@ cross-model numbers compare like with like.
|
|
|
210
232
|
|
|
211
233
|
## CI
|
|
212
234
|
|
|
235
|
+
Two jobs, on two schedules. Replay on every push, because it is free:
|
|
236
|
+
|
|
213
237
|
```yaml
|
|
214
|
-
- uses: actions/checkout@v4
|
|
215
|
-
- uses: actions/setup-python@v5
|
|
216
|
-
with:
|
|
217
|
-
python-version: "3.12"
|
|
218
238
|
- run: pip install quickstarted
|
|
219
|
-
- run: quickstarted run
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
239
|
+
- run: quickstarted run tasks/*.yaml --agent replay --junit junit.xml
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Agent mode on a schedule, or when a model ships, because it costs real tokens:
|
|
243
|
+
|
|
244
|
+
```yaml
|
|
245
|
+
on:
|
|
246
|
+
schedule:
|
|
247
|
+
- cron: "0 6 * * 1"
|
|
248
|
+
workflow_dispatch:
|
|
249
|
+
jobs:
|
|
250
|
+
agent:
|
|
251
|
+
steps:
|
|
252
|
+
- uses: actions/checkout@v4
|
|
253
|
+
- uses: actions/setup-python@v5
|
|
254
|
+
with:
|
|
255
|
+
python-version: "3.12"
|
|
256
|
+
- run: pip install "quickstarted[claude]"
|
|
257
|
+
- run: quickstarted run tasks/*.yaml --agent claude --repeat 3
|
|
258
|
+
--out results --junit junit.xml
|
|
259
|
+
env:
|
|
260
|
+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
261
|
+
- uses: actions/upload-artifact@v4
|
|
262
|
+
if: always()
|
|
263
|
+
with:
|
|
264
|
+
name: quickstarted-results
|
|
265
|
+
path: results/
|
|
225
266
|
```
|
|
226
267
|
|
|
227
|
-
`quickstarted run` exits 1 when any
|
|
228
|
-
`results.json` is versioned (schema 1.0). JUnit XML reports a docs gap
|
|
229
|
-
failure and infrastructure trouble as an error, so a rate limit does not
|
|
230
|
-
as a broken quickstart.
|
|
231
|
-
Every push is too often, because agent runs cost real tokens.
|
|
268
|
+
`quickstarted run` exits 1 when any task fails, so either job can gate
|
|
269
|
+
merges. `results.json` is versioned (schema 1.0). JUnit XML reports a docs gap
|
|
270
|
+
as a failure and infrastructure trouble as an error, so a rate limit does not
|
|
271
|
+
read as a broken quickstart.
|
|
232
272
|
|
|
233
273
|
## Fetching other people's docs
|
|
234
274
|
|
|
@@ -243,7 +283,7 @@ last run, which is a finding in its own right.
|
|
|
243
283
|
It tells you whether a given model, on a given day, could get from your docs to
|
|
244
284
|
a working result, and where it was reading when it could not. That is a lower
|
|
245
285
|
bound on documentation quality. Nothing here measures whether your docs are
|
|
246
|
-
pleasant, complete, or accurate beyond the
|
|
286
|
+
pleasant, complete, or accurate beyond the task you wrote, and there is no
|
|
247
287
|
UI testing at all: if your product's button moved, this will not notice.
|
|
248
288
|
[Doc Detective](https://github.com/doc-detective/doc-detective) is the tool for
|
|
249
289
|
that, and the two answer different questions.
|