touchstone-bench 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.
- touchstone_bench-0.1.0/.github/workflows/ci.yml +13 -0
- touchstone_bench-0.1.0/.github/workflows/release.yml +19 -0
- touchstone_bench-0.1.0/.gitignore +17 -0
- touchstone_bench-0.1.0/.python-version +1 -0
- touchstone_bench-0.1.0/LICENSE +21 -0
- touchstone_bench-0.1.0/PKG-INFO +170 -0
- touchstone_bench-0.1.0/README.md +148 -0
- touchstone_bench-0.1.0/benchmarks/survey/2026-09-25.json +44 -0
- touchstone_bench-0.1.0/benchmarks/survey/2026-09-25.md +9 -0
- touchstone_bench-0.1.0/benchmarks/survey/targets.toml +21 -0
- touchstone_bench-0.1.0/docs/DESIGN.md +193 -0
- touchstone_bench-0.1.0/plans/v2-contracts-2026-09-23.md +23 -0
- touchstone_bench-0.1.0/plans/v3-stage1-2026-09-24.md +35 -0
- touchstone_bench-0.1.0/plans/v3-stage11-2026-09-25.md +58 -0
- touchstone_bench-0.1.0/plans/v3-stage2-2026-09-25.md +46 -0
- touchstone_bench-0.1.0/plans/v3-stage3a-2026-09-25.md +87 -0
- touchstone_bench-0.1.0/plans/v3-stage3b-2026-09-25.md +91 -0
- touchstone_bench-0.1.0/plans/v3-stage4-2026-09-25.md +143 -0
- touchstone_bench-0.1.0/plans/v3-stage5-2026-09-25.md +56 -0
- touchstone_bench-0.1.0/plans/v3-stage6-2026-09-25.md +79 -0
- touchstone_bench-0.1.0/plans/v3-stage7-2026-09-25.md +101 -0
- touchstone_bench-0.1.0/plans/v3-stage8-2026-09-25.md +79 -0
- touchstone_bench-0.1.0/plans/v3-stage9-2026-09-25.md +110 -0
- touchstone_bench-0.1.0/pyproject.toml +58 -0
- touchstone_bench-0.1.0/scripts/harbor-mini.sh +12 -0
- touchstone_bench-0.1.0/tests/_fakes.py +48 -0
- touchstone_bench-0.1.0/tests/conftest.py +52 -0
- touchstone_bench-0.1.0/tests/test_acp_server.py +106 -0
- touchstone_bench-0.1.0/tests/test_anthropic.py +155 -0
- touchstone_bench-0.1.0/tests/test_atif.py +178 -0
- touchstone_bench-0.1.0/tests/test_capture_matrix.py +363 -0
- touchstone_bench-0.1.0/tests/test_capture_never_raises.py +47 -0
- touchstone_bench-0.1.0/tests/test_cli.py +159 -0
- touchstone_bench-0.1.0/tests/test_cli_bench.py +114 -0
- touchstone_bench-0.1.0/tests/test_cli_providers.py +188 -0
- touchstone_bench-0.1.0/tests/test_cli_retry.py +51 -0
- touchstone_bench-0.1.0/tests/test_cli_survey.py +33 -0
- touchstone_bench-0.1.0/tests/test_cli_train.py +127 -0
- touchstone_bench-0.1.0/tests/test_config_agent_provider.py +96 -0
- touchstone_bench-0.1.0/tests/test_context.py +137 -0
- touchstone_bench-0.1.0/tests/test_harbor_agent.py +231 -0
- touchstone_bench-0.1.0/tests/test_harbor_dataset.py +41 -0
- touchstone_bench-0.1.0/tests/test_harbor_jobs.py +76 -0
- touchstone_bench-0.1.0/tests/test_harbor_rewardkit.py +78 -0
- touchstone_bench-0.1.0/tests/test_harbor_run.py +255 -0
- touchstone_bench-0.1.0/tests/test_ids.py +13 -0
- touchstone_bench-0.1.0/tests/test_interview_realtime.py +286 -0
- touchstone_bench-0.1.0/tests/test_interview_rooms.py +59 -0
- touchstone_bench-0.1.0/tests/test_interview_speech.py +138 -0
- touchstone_bench-0.1.0/tests/test_keychain.py +63 -0
- touchstone_bench-0.1.0/tests/test_live_realtime.py +54 -0
- touchstone_bench-0.1.0/tests/test_live_smoke.py +78 -0
- touchstone_bench-0.1.0/tests/test_messages.py +317 -0
- touchstone_bench-0.1.0/tests/test_model_override.py +129 -0
- touchstone_bench-0.1.0/tests/test_openai_compat.py +197 -0
- touchstone_bench-0.1.0/tests/test_openinference.py +82 -0
- touchstone_bench-0.1.0/tests/test_overview.py +22 -0
- touchstone_bench-0.1.0/tests/test_patch_anthropic.py +124 -0
- touchstone_bench-0.1.0/tests/test_patch_openai.py +199 -0
- touchstone_bench-0.1.0/tests/test_patch_responses.py +141 -0
- touchstone_bench-0.1.0/tests/test_prompt.py +98 -0
- touchstone_bench-0.1.0/tests/test_review_agent.py +403 -0
- touchstone_bench-0.1.0/tests/test_review_changes.py +196 -0
- touchstone_bench-0.1.0/tests/test_review_regrade.py +100 -0
- touchstone_bench-0.1.0/tests/test_review_trials.py +162 -0
- touchstone_bench-0.1.0/tests/test_scripted.py +86 -0
- touchstone_bench-0.1.0/tests/test_server.py +302 -0
- touchstone_bench-0.1.0/tests/test_server_api.py +128 -0
- touchstone_bench-0.1.0/tests/test_server_pages.py +210 -0
- touchstone_bench-0.1.0/tests/test_store.py +167 -0
- touchstone_bench-0.1.0/tests/test_survey_baseline.py +119 -0
- touchstone_bench-0.1.0/tests/test_survey_baseline_skip.py +26 -0
- touchstone_bench-0.1.0/tests/test_survey_benchmark.py +83 -0
- touchstone_bench-0.1.0/tests/test_survey_cli.py +13 -0
- touchstone_bench-0.1.0/tests/test_survey_criteria.py +196 -0
- touchstone_bench-0.1.0/tests/test_survey_environment.py +174 -0
- touchstone_bench-0.1.0/tests/test_survey_fidelity.py +48 -0
- touchstone_bench-0.1.0/tests/test_survey_gate.py +166 -0
- touchstone_bench-0.1.0/tests/test_survey_group.py +158 -0
- touchstone_bench-0.1.0/tests/test_survey_invoke.py +100 -0
- touchstone_bench-0.1.0/tests/test_survey_map.py +83 -0
- touchstone_bench-0.1.0/tests/test_survey_minted_ids.py +48 -0
- touchstone_bench-0.1.0/tests/test_survey_netshim.py +92 -0
- touchstone_bench-0.1.0/tests/test_survey_orchestrator.py +155 -0
- touchstone_bench-0.1.0/tests/test_survey_package.py +168 -0
- touchstone_bench-0.1.0/tests/test_survey_provider.py +26 -0
- touchstone_bench-0.1.0/tests/test_survey_recordings.py +74 -0
- touchstone_bench-0.1.0/tests/test_survey_replay.py +78 -0
- touchstone_bench-0.1.0/tests/test_survey_report.py +113 -0
- touchstone_bench-0.1.0/tests/test_survey_scrub.py +65 -0
- touchstone_bench-0.1.0/tests/test_survey_simulate.py +477 -0
- touchstone_bench-0.1.0/tests/test_survey_sort.py +30 -0
- touchstone_bench-0.1.0/tests/test_survey_subproc.py +62 -0
- touchstone_bench-0.1.0/tests/test_survey_tasks.py +478 -0
- touchstone_bench-0.1.0/tests/test_trace.py +29 -0
- touchstone_bench-0.1.0/tests/test_train_datasets.py +87 -0
- touchstone_bench-0.1.0/tests/test_train_plugin.py +61 -0
- touchstone_bench-0.1.0/tests/test_train_write.py +115 -0
- touchstone_bench-0.1.0/touchstone/__init__.py +106 -0
- touchstone_bench-0.1.0/touchstone/capture/__init__.py +21 -0
- touchstone_bench-0.1.0/touchstone/capture/context.py +241 -0
- touchstone_bench-0.1.0/touchstone/capture/litellm.py +95 -0
- touchstone_bench-0.1.0/touchstone/capture/openinference.py +169 -0
- touchstone_bench-0.1.0/touchstone/capture/patch_anthropic.py +215 -0
- touchstone_bench-0.1.0/touchstone/capture/patch_openai.py +232 -0
- touchstone_bench-0.1.0/touchstone/capture/pricing.py +40 -0
- touchstone_bench-0.1.0/touchstone/capture/spans.py +223 -0
- touchstone_bench-0.1.0/touchstone/cli/__init__.py +199 -0
- touchstone_bench-0.1.0/touchstone/cli/_common.py +52 -0
- touchstone_bench-0.1.0/touchstone/cli/bench.py +81 -0
- touchstone_bench-0.1.0/touchstone/cli/review.py +52 -0
- touchstone_bench-0.1.0/touchstone/cli/survey.py +47 -0
- touchstone_bench-0.1.0/touchstone/cli/train.py +87 -0
- touchstone_bench-0.1.0/touchstone/config.py +146 -0
- touchstone_bench-0.1.0/touchstone/demo.py +115 -0
- touchstone_bench-0.1.0/touchstone/harbor/__init__.py +2 -0
- touchstone_bench-0.1.0/touchstone/harbor/acp_server.py +160 -0
- touchstone_bench-0.1.0/touchstone/harbor/agent.py +288 -0
- touchstone_bench-0.1.0/touchstone/harbor/atif.py +308 -0
- touchstone_bench-0.1.0/touchstone/harbor/atif_import.py +77 -0
- touchstone_bench-0.1.0/touchstone/harbor/conversation.py +113 -0
- touchstone_bench-0.1.0/touchstone/harbor/dataset.py +69 -0
- touchstone_bench-0.1.0/touchstone/harbor/jobs.py +130 -0
- touchstone_bench-0.1.0/touchstone/harbor/keys.py +21 -0
- touchstone_bench-0.1.0/touchstone/harbor/remote.py +73 -0
- touchstone_bench-0.1.0/touchstone/harbor/rewardkit.py +116 -0
- touchstone_bench-0.1.0/touchstone/harbor/run.py +295 -0
- touchstone_bench-0.1.0/touchstone/ids.py +31 -0
- touchstone_bench-0.1.0/touchstone/interview/__init__.py +17 -0
- touchstone_bench-0.1.0/touchstone/interview/realtime.py +301 -0
- touchstone_bench-0.1.0/touchstone/interview/rooms.py +73 -0
- touchstone_bench-0.1.0/touchstone/interview/speech.py +304 -0
- touchstone_bench-0.1.0/touchstone/llm/__init__.py +19 -0
- touchstone_bench-0.1.0/touchstone/llm/_cli.py +90 -0
- touchstone_bench-0.1.0/touchstone/llm/_http.py +135 -0
- touchstone_bench-0.1.0/touchstone/llm/anthropic.py +139 -0
- touchstone_bench-0.1.0/touchstone/llm/base.py +33 -0
- touchstone_bench-0.1.0/touchstone/llm/claude_cli.py +71 -0
- touchstone_bench-0.1.0/touchstone/llm/codex_cli.py +65 -0
- touchstone_bench-0.1.0/touchstone/llm/keychain.py +43 -0
- touchstone_bench-0.1.0/touchstone/llm/nop.py +23 -0
- touchstone_bench-0.1.0/touchstone/llm/openai_compat.py +112 -0
- touchstone_bench-0.1.0/touchstone/llm/prompt.py +181 -0
- touchstone_bench-0.1.0/touchstone/llm/reference.py +31 -0
- touchstone_bench-0.1.0/touchstone/llm/registry.py +177 -0
- touchstone_bench-0.1.0/touchstone/llm/scripted.py +74 -0
- touchstone_bench-0.1.0/touchstone/messages.py +319 -0
- touchstone_bench-0.1.0/touchstone/messages_wire.py +139 -0
- touchstone_bench-0.1.0/touchstone/overview.py +24 -0
- touchstone_bench-0.1.0/touchstone/review/__init__.py +7 -0
- touchstone_bench-0.1.0/touchstone/review/agent.py +316 -0
- touchstone_bench-0.1.0/touchstone/review/changes.py +291 -0
- touchstone_bench-0.1.0/touchstone/review/facts.py +122 -0
- touchstone_bench-0.1.0/touchstone/review/prompt.py +84 -0
- touchstone_bench-0.1.0/touchstone/review/readback.py +51 -0
- touchstone_bench-0.1.0/touchstone/review/regrade.py +71 -0
- touchstone_bench-0.1.0/touchstone/review/replies.py +107 -0
- touchstone_bench-0.1.0/touchstone/review/scratch.py +20 -0
- touchstone_bench-0.1.0/touchstone/review/snapshot.py +20 -0
- touchstone_bench-0.1.0/touchstone/review/trials.py +316 -0
- touchstone_bench-0.1.0/touchstone/server/__init__.py +3 -0
- touchstone_bench-0.1.0/touchstone/server/app.py +108 -0
- touchstone_bench-0.1.0/touchstone/server/pagedata.py +68 -0
- touchstone_bench-0.1.0/touchstone/server/pages.py +304 -0
- touchstone_bench-0.1.0/touchstone/server/routes/__init__.py +12 -0
- touchstone_bench-0.1.0/touchstone/server/routes/_deps.py +31 -0
- touchstone_bench-0.1.0/touchstone/server/routes/episodes.py +33 -0
- touchstone_bench-0.1.0/touchstone/server/routes/overview.py +27 -0
- touchstone_bench-0.1.0/touchstone/server/routes/pages.py +57 -0
- touchstone_bench-0.1.0/touchstone/server/routes/rooms.py +309 -0
- touchstone_bench-0.1.0/touchstone/server/static/app.css +345 -0
- touchstone_bench-0.1.0/touchstone/server/static/app.js +377 -0
- touchstone_bench-0.1.0/touchstone/server/static/index.html +24 -0
- touchstone_bench-0.1.0/touchstone/server/static/room.html +62 -0
- touchstone_bench-0.1.0/touchstone/server/static/room.js +342 -0
- touchstone_bench-0.1.0/touchstone/store.py +294 -0
- touchstone_bench-0.1.0/touchstone/store_models.py +78 -0
- touchstone_bench-0.1.0/touchstone/survey/__init__.py +5 -0
- touchstone_bench-0.1.0/touchstone/survey/baseline.py +93 -0
- touchstone_bench-0.1.0/touchstone/survey/benchmark.py +161 -0
- touchstone_bench-0.1.0/touchstone/survey/criteria.py +251 -0
- touchstone_bench-0.1.0/touchstone/survey/descriptions.py +118 -0
- touchstone_bench-0.1.0/touchstone/survey/environment.py +255 -0
- touchstone_bench-0.1.0/touchstone/survey/envs.py +35 -0
- touchstone_bench-0.1.0/touchstone/survey/fidelity.py +294 -0
- touchstone_bench-0.1.0/touchstone/survey/fidelity_db.py +42 -0
- touchstone_bench-0.1.0/touchstone/survey/fidelity_mask.py +48 -0
- touchstone_bench-0.1.0/touchstone/survey/gate.py +138 -0
- touchstone_bench-0.1.0/touchstone/survey/group.py +199 -0
- touchstone_bench-0.1.0/touchstone/survey/invoke.py +139 -0
- touchstone_bench-0.1.0/touchstone/survey/map.py +141 -0
- touchstone_bench-0.1.0/touchstone/survey/minted_ids.py +73 -0
- touchstone_bench-0.1.0/touchstone/survey/netshim.py +114 -0
- touchstone_bench-0.1.0/touchstone/survey/package.py +145 -0
- touchstone_bench-0.1.0/touchstone/survey/package_entry.py +195 -0
- touchstone_bench-0.1.0/touchstone/survey/package_spans.py +49 -0
- touchstone_bench-0.1.0/touchstone/survey/provider.py +98 -0
- touchstone_bench-0.1.0/touchstone/survey/recordings.py +114 -0
- touchstone_bench-0.1.0/touchstone/survey/replay.py +151 -0
- touchstone_bench-0.1.0/touchstone/survey/report.py +230 -0
- touchstone_bench-0.1.0/touchstone/survey/scrub.py +64 -0
- touchstone_bench-0.1.0/touchstone/survey/simulate.py +308 -0
- touchstone_bench-0.1.0/touchstone/survey/sort.py +24 -0
- touchstone_bench-0.1.0/touchstone/survey/subproc.py +52 -0
- touchstone_bench-0.1.0/touchstone/survey/survey.py +180 -0
- touchstone_bench-0.1.0/touchstone/survey/task_files.py +154 -0
- touchstone_bench-0.1.0/touchstone/survey/task_text.py +146 -0
- touchstone_bench-0.1.0/touchstone/survey/tasks.py +271 -0
- touchstone_bench-0.1.0/touchstone/survey/tool_reads.py +55 -0
- touchstone_bench-0.1.0/touchstone/survey/writes.py +25 -0
- touchstone_bench-0.1.0/touchstone/train/__init__.py +5 -0
- touchstone_bench-0.1.0/touchstone/train/datasets.py +121 -0
- touchstone_bench-0.1.0/touchstone/train/plugin.py +52 -0
- touchstone_bench-0.1.0/touchstone/train/write.py +113 -0
- touchstone_bench-0.1.0/uv.lock +1557 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
on: [push, pull_request]
|
|
3
|
+
jobs:
|
|
4
|
+
test:
|
|
5
|
+
runs-on: ubuntu-latest
|
|
6
|
+
steps:
|
|
7
|
+
- uses: actions/checkout@v4
|
|
8
|
+
- uses: astral-sh/setup-uv@v5
|
|
9
|
+
- run: uv python install 3.13
|
|
10
|
+
- run: uv sync --group dev
|
|
11
|
+
- run: uv run ruff check .
|
|
12
|
+
- run: uv run complexipy --max-complexity-allowed 8 touchstone
|
|
13
|
+
- run: uv run pytest -q
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
tags: ["v*"]
|
|
5
|
+
jobs:
|
|
6
|
+
publish:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
environment: pypi
|
|
9
|
+
permissions:
|
|
10
|
+
id-token: write # PyPI trusted publishing, no token to store
|
|
11
|
+
contents: write
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: astral-sh/setup-uv@v5
|
|
15
|
+
- run: uv build
|
|
16
|
+
- run: uv publish
|
|
17
|
+
- uses: softprops/action-gh-release@v2
|
|
18
|
+
with:
|
|
19
|
+
files: dist/*
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
.touchstone/
|
|
5
|
+
*.db
|
|
6
|
+
*.db-wal
|
|
7
|
+
*.db-shm
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
dist/
|
|
11
|
+
harbor-tasks/
|
|
12
|
+
*.egg-info/
|
|
13
|
+
.DS_Store
|
|
14
|
+
touchstone.toml
|
|
15
|
+
|
|
16
|
+
# Harbor job directories belong under the dataset root, never in the repo
|
|
17
|
+
jobs/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pebble ML
|
|
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,170 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: touchstone-bench
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Turn a company's running AI agent into a Harbor benchmark of its own work — capture, survey, review, train.
|
|
5
|
+
Author-email: Sam Larson <sam@pebbleml.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.12
|
|
9
|
+
Requires-Dist: fastapi>=0.110
|
|
10
|
+
Requires-Dist: httpx>=0.27
|
|
11
|
+
Requires-Dist: jsonschema>=4.21
|
|
12
|
+
Requires-Dist: python-multipart>=0.0.9
|
|
13
|
+
Requires-Dist: tomli-w>=1.2.0
|
|
14
|
+
Requires-Dist: typer>=0.12
|
|
15
|
+
Requires-Dist: uvicorn>=0.29
|
|
16
|
+
Requires-Dist: websockets>=12
|
|
17
|
+
Provides-Extra: otel
|
|
18
|
+
Requires-Dist: opentelemetry-sdk>=1.20; extra == 'otel'
|
|
19
|
+
Provides-Extra: whisper
|
|
20
|
+
Requires-Dist: faster-whisper>=1.0; extra == 'whisper'
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# Touchstone
|
|
24
|
+
|
|
25
|
+
A touchstone is the black stone assayers rubbed gold against to prove its purity before anyone paid
|
|
26
|
+
for it. Touchstone does that for AI agents: it turns a company's running agent into a
|
|
27
|
+
[Harbor](https://github.com/harbor-framework/harbor) benchmark of its own work, lets the people who
|
|
28
|
+
know the product review that benchmark by voice, and turns the results into training data.
|
|
29
|
+
|
|
30
|
+
Harbor is the middle of the product, unchanged. Touchstone is four extensions around it:
|
|
31
|
+
|
|
32
|
+
1. **Capture** — one line of code records what the production agent does.
|
|
33
|
+
2. **Survey** — a read-only agent reads the recordings and the code, copies the system into a Harbor
|
|
34
|
+
environment, and writes Harbor tasks against it.
|
|
35
|
+
3. **Review** — a voice/text room where product people look at finished trials and correct the
|
|
36
|
+
verifiers; Harbor regrades after every correction.
|
|
37
|
+
4. **Train** — turns finished jobs into distillation and RL datasets.
|
|
38
|
+
|
|
39
|
+
Everything Touchstone produces is a plain Harbor dataset the customer owns and can run without us.
|
|
40
|
+
Local-first: it runs on the customer's machine with their own Claude or Codex login — no Touchstone
|
|
41
|
+
account, no Touchstone servers. Open source. By Pebble ML.
|
|
42
|
+
|
|
43
|
+
Horizontal by design: nothing in `touchstone/harbor/` knows about any one customer, product, or
|
|
44
|
+
domain.
|
|
45
|
+
|
|
46
|
+
## The five commands
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
touchstone init # write touchstone.toml + the .touchstone/ db
|
|
50
|
+
touchstone demo # run the built-in agent and capture episodes (zero-key)
|
|
51
|
+
touchstone survey <repo> # read-only: map the code, simulate its services, score fidelity
|
|
52
|
+
touchstone bench -m <provider/model> # run a model over the dataset; print pass rate per task
|
|
53
|
+
touchstone jobs # list Harbor job dirs with their pass rate per task
|
|
54
|
+
touchstone serve / touchstone review # open the review room (voice or text)
|
|
55
|
+
touchstone train # turn finished jobs into distill + RL datasets
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`touchstone survey` reads the recordings and the code with a read-only coding agent
|
|
59
|
+
(`[survey] provider`, default `claude-cli`; the customer's login pays), maps the tools and their
|
|
60
|
+
network boundaries, generates a SQLite-backed simulator per service, and replays every recorded call
|
|
61
|
+
through the real tools to score each simulator's fidelity. It is idempotent — outputs are reused
|
|
62
|
+
unless `--force` — and touches nothing outside `touchstone/` in the target repo.
|
|
63
|
+
|
|
64
|
+
`touchstone bench` also takes `--agent packaged|replica`, `--dataset <dir>`, and
|
|
65
|
+
`--against <job_dir>` (a per-task comparison against a previous run). `touchstone doctor` reports the
|
|
66
|
+
environment. Capture is one line in your own app:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
import touchstone
|
|
70
|
+
touchstone.trace() # records every model + tool call to .touchstone/touchstone.db
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Run your real agent on a different model with one env var: set `TOUCHSTONE_MODEL` and capture rewrites
|
|
74
|
+
the `model=` keyword on every openai/anthropic/litellm call before it goes through — same SDK, same
|
|
75
|
+
code path. (A model passed positionally is left untouched.) This is how the packaged agent under test
|
|
76
|
+
is benched against a candidate model without editing the customer's code.
|
|
77
|
+
|
|
78
|
+
## The dataset
|
|
79
|
+
|
|
80
|
+
A survey produces a `touchstone/` directory in the customer's repo — a plain Harbor dataset they own
|
|
81
|
+
and version:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
touchstone/
|
|
85
|
+
dataset.toml the Harbor dataset manifest (metadata; tasks run as the implicit tasks/ dataset)
|
|
86
|
+
tasks/<name>/ one Harbor task per directory (instruction.md, task.toml, environment/,
|
|
87
|
+
solution/, tests/)
|
|
88
|
+
environment/ the customer's system, copied to run in a sandbox
|
|
89
|
+
agent/ the agent under test as a Harbor custom agent (agent.toml, tools.py, entry.py)
|
|
90
|
+
simulators/ a small local service per network boundary
|
|
91
|
+
baseline.json what the current setup passes today (the first-five-minutes sentence)
|
|
92
|
+
report.md what was mapped, simulated, and left open
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The agent under test runs in one of two modes, chosen automatically and recorded in `agent/agent.toml`:
|
|
96
|
+
|
|
97
|
+
- **packaged** (highest fidelity): the survey generates `agent/entry.py` — a `run(user_message)`
|
|
98
|
+
that drives the customer's *real* agent loop for one message, importing their own modules. The
|
|
99
|
+
Harbor agent runs `bash /app/agent/run.sh` in the sandbox with the model as a setting
|
|
100
|
+
(`TOUCHSTONE_MODEL`) and imports the trajectory the customer's own capture wrote. An adapter check
|
|
101
|
+
proves entry.py runs and calls a tool before this mode is chosen.
|
|
102
|
+
- **replica** (fallback when the code will not run): `touchstone.harbor.agent:TouchstoneAgent` runs
|
|
103
|
+
an OpenAI-compatible tool-calling loop whose system prompt comes from `agent/agent.toml` and whose
|
|
104
|
+
tool schemas + dispatch come from `agent/tools.py`.
|
|
105
|
+
|
|
106
|
+
Either way it records an ATIF `trajectory.json`, and `touchstone bench -m <candidate>` re-runs it on
|
|
107
|
+
any model without touching the customer's code.
|
|
108
|
+
|
|
109
|
+
## The review room
|
|
110
|
+
|
|
111
|
+
`touchstone serve` then `touchstone review` opens a room (voice or text) where a product person walks
|
|
112
|
+
the finished trials with an AI. It opens from the product's goal (the job labels and the baseline
|
|
113
|
+
pass count), then picks trials in order — verifier unsure, models disagree, never reviewed, then
|
|
114
|
+
gate failures — and for each reads the instruction, the trajectory in plain words, and every
|
|
115
|
+
criterion's score, and asks "do you agree it passed?". Agreement records trust (the share of
|
|
116
|
+
reviewed trials where the human agreed with the verifier, shown live). On a disagreement the agent
|
|
117
|
+
drafts a criterion change — edit/add/remove a rewardkit check, a dimension weight, a judge line, or
|
|
118
|
+
the instruction wording — reads it back, and on "yes" writes the `tests/` file and runs
|
|
119
|
+
`harbor job regrade` (the tasks are authored with a separate verifier so grading reruns from the
|
|
120
|
+
recorded artifacts, no agent), then reads out the new reward and any other trials that moved.
|
|
121
|
+
"Always" applies the same criterion to every task with the same job. Everything the room decides is
|
|
122
|
+
a row in `reviews` and a file change under `touchstone/` — nothing else.
|
|
123
|
+
|
|
124
|
+
## Training data
|
|
125
|
+
|
|
126
|
+
`touchstone train` reads the Harbor job directories (`trajectory.json` + `reward.json` per trial)
|
|
127
|
+
and writes, under `touchstone/train/`, `distill.jsonl` (full trajectories from trials that scored at
|
|
128
|
+
or above the threshold, for a student to copy), `rl_tasks.toml` (tasks in the learnability band —
|
|
129
|
+
pass rate strictly between 0 and 1 — with the verifier as the reward), and `manifest.json` (per-task
|
|
130
|
+
pass rate per model and where each task went). `touchstone train --teacher <spec>` runs the teacher
|
|
131
|
+
job first. Training itself stops at the exact GPU command; Touchstone produces the data, not the run.
|
|
132
|
+
|
|
133
|
+
## Storage
|
|
134
|
+
|
|
135
|
+
Only what is captured lives in SQLite (`.touchstone/touchstone.db`): `episodes`, `spans`, `rooms`,
|
|
136
|
+
`room_messages`, and `reviews` (what a review room decided about a task's trial). Harbor's own
|
|
137
|
+
`jobs/` directories are the run record — Touchstone reads them, it has no runs table.
|
|
138
|
+
|
|
139
|
+
## Running Harbor (remote Docker note)
|
|
140
|
+
|
|
141
|
+
Harbor bind-mounts local directories, so it must run where a Docker daemon lives. A laptop without a
|
|
142
|
+
daemon can offload to a host: set
|
|
143
|
+
|
|
144
|
+
```toml
|
|
145
|
+
[harbor]
|
|
146
|
+
host = "harbor-host.example" # an SSH host with Docker + harbor
|
|
147
|
+
remote_root = "/srv/touchstone"
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
and `touchstone bench` (via `touchstone/harbor/run.py`) rsyncs the dataset to that host, runs Harbor
|
|
151
|
+
there over SSH, and rsyncs the job directory back. `scripts/harbor-mini.sh` is a thin wrapper for the
|
|
152
|
+
same path. With a local Docker daemon, everything runs locally and these settings are ignored.
|
|
153
|
+
|
|
154
|
+
## Install
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
uv tool install --from git+ssh://git@github.com/saml212/touchstone touchstone-bench
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
or, in a checkout, `uv run touchstone …`. Requires [Harbor](https://docs.harborframework.com)
|
|
161
|
+
(`uv tool install harbor`) and a Docker daemon to run benchmarks.
|
|
162
|
+
|
|
163
|
+
## Develop
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
uv run pytest -q
|
|
167
|
+
uv run ruff check .
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Commits are small and sequential; see `docs/DESIGN.md` for the full v3 design.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Touchstone
|
|
2
|
+
|
|
3
|
+
A touchstone is the black stone assayers rubbed gold against to prove its purity before anyone paid
|
|
4
|
+
for it. Touchstone does that for AI agents: it turns a company's running agent into a
|
|
5
|
+
[Harbor](https://github.com/harbor-framework/harbor) benchmark of its own work, lets the people who
|
|
6
|
+
know the product review that benchmark by voice, and turns the results into training data.
|
|
7
|
+
|
|
8
|
+
Harbor is the middle of the product, unchanged. Touchstone is four extensions around it:
|
|
9
|
+
|
|
10
|
+
1. **Capture** — one line of code records what the production agent does.
|
|
11
|
+
2. **Survey** — a read-only agent reads the recordings and the code, copies the system into a Harbor
|
|
12
|
+
environment, and writes Harbor tasks against it.
|
|
13
|
+
3. **Review** — a voice/text room where product people look at finished trials and correct the
|
|
14
|
+
verifiers; Harbor regrades after every correction.
|
|
15
|
+
4. **Train** — turns finished jobs into distillation and RL datasets.
|
|
16
|
+
|
|
17
|
+
Everything Touchstone produces is a plain Harbor dataset the customer owns and can run without us.
|
|
18
|
+
Local-first: it runs on the customer's machine with their own Claude or Codex login — no Touchstone
|
|
19
|
+
account, no Touchstone servers. Open source. By Pebble ML.
|
|
20
|
+
|
|
21
|
+
Horizontal by design: nothing in `touchstone/harbor/` knows about any one customer, product, or
|
|
22
|
+
domain.
|
|
23
|
+
|
|
24
|
+
## The five commands
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
touchstone init # write touchstone.toml + the .touchstone/ db
|
|
28
|
+
touchstone demo # run the built-in agent and capture episodes (zero-key)
|
|
29
|
+
touchstone survey <repo> # read-only: map the code, simulate its services, score fidelity
|
|
30
|
+
touchstone bench -m <provider/model> # run a model over the dataset; print pass rate per task
|
|
31
|
+
touchstone jobs # list Harbor job dirs with their pass rate per task
|
|
32
|
+
touchstone serve / touchstone review # open the review room (voice or text)
|
|
33
|
+
touchstone train # turn finished jobs into distill + RL datasets
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`touchstone survey` reads the recordings and the code with a read-only coding agent
|
|
37
|
+
(`[survey] provider`, default `claude-cli`; the customer's login pays), maps the tools and their
|
|
38
|
+
network boundaries, generates a SQLite-backed simulator per service, and replays every recorded call
|
|
39
|
+
through the real tools to score each simulator's fidelity. It is idempotent — outputs are reused
|
|
40
|
+
unless `--force` — and touches nothing outside `touchstone/` in the target repo.
|
|
41
|
+
|
|
42
|
+
`touchstone bench` also takes `--agent packaged|replica`, `--dataset <dir>`, and
|
|
43
|
+
`--against <job_dir>` (a per-task comparison against a previous run). `touchstone doctor` reports the
|
|
44
|
+
environment. Capture is one line in your own app:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
import touchstone
|
|
48
|
+
touchstone.trace() # records every model + tool call to .touchstone/touchstone.db
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Run your real agent on a different model with one env var: set `TOUCHSTONE_MODEL` and capture rewrites
|
|
52
|
+
the `model=` keyword on every openai/anthropic/litellm call before it goes through — same SDK, same
|
|
53
|
+
code path. (A model passed positionally is left untouched.) This is how the packaged agent under test
|
|
54
|
+
is benched against a candidate model without editing the customer's code.
|
|
55
|
+
|
|
56
|
+
## The dataset
|
|
57
|
+
|
|
58
|
+
A survey produces a `touchstone/` directory in the customer's repo — a plain Harbor dataset they own
|
|
59
|
+
and version:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
touchstone/
|
|
63
|
+
dataset.toml the Harbor dataset manifest (metadata; tasks run as the implicit tasks/ dataset)
|
|
64
|
+
tasks/<name>/ one Harbor task per directory (instruction.md, task.toml, environment/,
|
|
65
|
+
solution/, tests/)
|
|
66
|
+
environment/ the customer's system, copied to run in a sandbox
|
|
67
|
+
agent/ the agent under test as a Harbor custom agent (agent.toml, tools.py, entry.py)
|
|
68
|
+
simulators/ a small local service per network boundary
|
|
69
|
+
baseline.json what the current setup passes today (the first-five-minutes sentence)
|
|
70
|
+
report.md what was mapped, simulated, and left open
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The agent under test runs in one of two modes, chosen automatically and recorded in `agent/agent.toml`:
|
|
74
|
+
|
|
75
|
+
- **packaged** (highest fidelity): the survey generates `agent/entry.py` — a `run(user_message)`
|
|
76
|
+
that drives the customer's *real* agent loop for one message, importing their own modules. The
|
|
77
|
+
Harbor agent runs `bash /app/agent/run.sh` in the sandbox with the model as a setting
|
|
78
|
+
(`TOUCHSTONE_MODEL`) and imports the trajectory the customer's own capture wrote. An adapter check
|
|
79
|
+
proves entry.py runs and calls a tool before this mode is chosen.
|
|
80
|
+
- **replica** (fallback when the code will not run): `touchstone.harbor.agent:TouchstoneAgent` runs
|
|
81
|
+
an OpenAI-compatible tool-calling loop whose system prompt comes from `agent/agent.toml` and whose
|
|
82
|
+
tool schemas + dispatch come from `agent/tools.py`.
|
|
83
|
+
|
|
84
|
+
Either way it records an ATIF `trajectory.json`, and `touchstone bench -m <candidate>` re-runs it on
|
|
85
|
+
any model without touching the customer's code.
|
|
86
|
+
|
|
87
|
+
## The review room
|
|
88
|
+
|
|
89
|
+
`touchstone serve` then `touchstone review` opens a room (voice or text) where a product person walks
|
|
90
|
+
the finished trials with an AI. It opens from the product's goal (the job labels and the baseline
|
|
91
|
+
pass count), then picks trials in order — verifier unsure, models disagree, never reviewed, then
|
|
92
|
+
gate failures — and for each reads the instruction, the trajectory in plain words, and every
|
|
93
|
+
criterion's score, and asks "do you agree it passed?". Agreement records trust (the share of
|
|
94
|
+
reviewed trials where the human agreed with the verifier, shown live). On a disagreement the agent
|
|
95
|
+
drafts a criterion change — edit/add/remove a rewardkit check, a dimension weight, a judge line, or
|
|
96
|
+
the instruction wording — reads it back, and on "yes" writes the `tests/` file and runs
|
|
97
|
+
`harbor job regrade` (the tasks are authored with a separate verifier so grading reruns from the
|
|
98
|
+
recorded artifacts, no agent), then reads out the new reward and any other trials that moved.
|
|
99
|
+
"Always" applies the same criterion to every task with the same job. Everything the room decides is
|
|
100
|
+
a row in `reviews` and a file change under `touchstone/` — nothing else.
|
|
101
|
+
|
|
102
|
+
## Training data
|
|
103
|
+
|
|
104
|
+
`touchstone train` reads the Harbor job directories (`trajectory.json` + `reward.json` per trial)
|
|
105
|
+
and writes, under `touchstone/train/`, `distill.jsonl` (full trajectories from trials that scored at
|
|
106
|
+
or above the threshold, for a student to copy), `rl_tasks.toml` (tasks in the learnability band —
|
|
107
|
+
pass rate strictly between 0 and 1 — with the verifier as the reward), and `manifest.json` (per-task
|
|
108
|
+
pass rate per model and where each task went). `touchstone train --teacher <spec>` runs the teacher
|
|
109
|
+
job first. Training itself stops at the exact GPU command; Touchstone produces the data, not the run.
|
|
110
|
+
|
|
111
|
+
## Storage
|
|
112
|
+
|
|
113
|
+
Only what is captured lives in SQLite (`.touchstone/touchstone.db`): `episodes`, `spans`, `rooms`,
|
|
114
|
+
`room_messages`, and `reviews` (what a review room decided about a task's trial). Harbor's own
|
|
115
|
+
`jobs/` directories are the run record — Touchstone reads them, it has no runs table.
|
|
116
|
+
|
|
117
|
+
## Running Harbor (remote Docker note)
|
|
118
|
+
|
|
119
|
+
Harbor bind-mounts local directories, so it must run where a Docker daemon lives. A laptop without a
|
|
120
|
+
daemon can offload to a host: set
|
|
121
|
+
|
|
122
|
+
```toml
|
|
123
|
+
[harbor]
|
|
124
|
+
host = "harbor-host.example" # an SSH host with Docker + harbor
|
|
125
|
+
remote_root = "/srv/touchstone"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
and `touchstone bench` (via `touchstone/harbor/run.py`) rsyncs the dataset to that host, runs Harbor
|
|
129
|
+
there over SSH, and rsyncs the job directory back. `scripts/harbor-mini.sh` is a thin wrapper for the
|
|
130
|
+
same path. With a local Docker daemon, everything runs locally and these settings are ignored.
|
|
131
|
+
|
|
132
|
+
## Install
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
uv tool install --from git+ssh://git@github.com/saml212/touchstone touchstone-bench
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
or, in a checkout, `uv run touchstone …`. Requires [Harbor](https://docs.harborframework.com)
|
|
139
|
+
(`uv tool install harbor`) and a Docker daemon to run benchmarks.
|
|
140
|
+
|
|
141
|
+
## Develop
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
uv run pytest -q
|
|
145
|
+
uv run ruff check .
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Commits are small and sequential; see `docs/DESIGN.md` for the full v3 design.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"generated_at": "2026-09-25T18:08:01.407612+00:00",
|
|
3
|
+
"targets": [
|
|
4
|
+
{
|
|
5
|
+
"name": "touchstone-example",
|
|
6
|
+
"repo": "/Users/samuellarson/Pebble/Github/touchstone-example",
|
|
7
|
+
"run": "python demo-style capture already shipped with the example (httpx, ORDERS_URL env base)",
|
|
8
|
+
"services": {
|
|
9
|
+
"orders_service": 1.0
|
|
10
|
+
},
|
|
11
|
+
"fidelity_min": 1.0,
|
|
12
|
+
"written": 7,
|
|
13
|
+
"gated": 7,
|
|
14
|
+
"baseline_pass": 1.0,
|
|
15
|
+
"agreement": 1.0
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "weather-gpt-assistant",
|
|
19
|
+
"repo": "/Users/samuellarson/Pebble/Github/survey-targets/weather-gpt-assistant",
|
|
20
|
+
"run": "python scripts/record.py against a local WeatherAPI fake (requests, hardcoded host via net shim)",
|
|
21
|
+
"services": {
|
|
22
|
+
"WeatherAPI": 1.0
|
|
23
|
+
},
|
|
24
|
+
"fidelity_min": 1.0,
|
|
25
|
+
"written": 6,
|
|
26
|
+
"gated": 6,
|
|
27
|
+
"baseline_pass": 1.0,
|
|
28
|
+
"agreement": 1.0
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "book-flight-llm",
|
|
32
|
+
"repo": "/Users/samuellarson/Pebble/Github/survey-targets/book-flight-llm",
|
|
33
|
+
"run": "python scripts/record.py against a local flight-backend fake (requests, FLIGHT_API_BASE_URL env)",
|
|
34
|
+
"services": {
|
|
35
|
+
"flight-booking-api": 1.0
|
|
36
|
+
},
|
|
37
|
+
"fidelity_min": 1.0,
|
|
38
|
+
"written": 4,
|
|
39
|
+
"gated": 4,
|
|
40
|
+
"baseline_pass": 1.0,
|
|
41
|
+
"agreement": 1.0
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Survey benchmark
|
|
2
|
+
|
|
3
|
+
Generated 2026-09-25T18:08:01.407612+00:00. Each target was recorded, then surveyed; this scores the outputs.
|
|
4
|
+
|
|
5
|
+
| target | services (fidelity) | tasks written/gated | baseline pass | agreement |
|
|
6
|
+
|---|---|---|---|---|
|
|
7
|
+
| touchstone-example | orders_service 100% | 7/7 | 100% | 100% |
|
|
8
|
+
| weather-gpt-assistant | WeatherAPI 100% | 6/6 | 100% | 100% |
|
|
9
|
+
| book-flight-llm | flight-booking-api 100% | 4/4 | 100% | 100% |
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# The survey agent's benchmark targets. Each was recorded against a local fake of its external
|
|
2
|
+
# service (with openai/gpt-4o-mini) so .touchstone/ holds real conversations, then surveyed with
|
|
3
|
+
# `touchstone survey <repo>`. `touchstone survey-bench <this file>` scores the resulting outputs.
|
|
4
|
+
# `run` documents how each target's conversations were recorded (not executed by survey-bench).
|
|
5
|
+
# The two open-source clones live under ~/Pebble/Github/survey-targets/ as gitignored scratch and
|
|
6
|
+
# are never redistributed; book-flight-llm ships no license, so it is a private test target only.
|
|
7
|
+
|
|
8
|
+
[[target]]
|
|
9
|
+
name = "touchstone-example"
|
|
10
|
+
repo = "~/Pebble/Github/touchstone-example"
|
|
11
|
+
run = "python demo-style capture already shipped with the example (httpx, ORDERS_URL env base)"
|
|
12
|
+
|
|
13
|
+
[[target]]
|
|
14
|
+
name = "weather-gpt-assistant"
|
|
15
|
+
repo = "~/Pebble/Github/survey-targets/weather-gpt-assistant"
|
|
16
|
+
run = "python scripts/record.py against a local WeatherAPI fake (requests, hardcoded host via net shim)"
|
|
17
|
+
|
|
18
|
+
[[target]]
|
|
19
|
+
name = "book-flight-llm"
|
|
20
|
+
repo = "~/Pebble/Github/survey-targets/book-flight-llm"
|
|
21
|
+
run = "python scripts/record.py against a local flight-backend fake (requests, FLIGHT_API_BASE_URL env)"
|