bathos 0.3.0__tar.gz → 0.3.1__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.
Files changed (101) hide show
  1. {bathos-0.3.0 → bathos-0.3.1}/CHANGELOG.md +10 -0
  2. {bathos-0.3.0 → bathos-0.3.1}/CLAUDE.md +40 -25
  3. {bathos-0.3.0 → bathos-0.3.1}/PKG-INFO +42 -3
  4. {bathos-0.3.0 → bathos-0.3.1}/README.md +41 -2
  5. {bathos-0.3.0 → bathos-0.3.1}/agent_assets/docs/claude-code-integration.md +7 -3
  6. {bathos-0.3.0 → bathos-0.3.1}/agent_assets/using_bathos/SKILL.md +2 -2
  7. {bathos-0.3.0 → bathos-0.3.1}/pyproject.toml +1 -1
  8. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/schema.py +3 -0
  9. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/sync.py +18 -3
  10. {bathos-0.3.0 → bathos-0.3.1}/tests/test_cluster_workflow.py +1 -1
  11. {bathos-0.3.0 → bathos-0.3.1}/tests/test_sync.py +47 -2
  12. {bathos-0.3.0 → bathos-0.3.1}/uv.lock +1 -1
  13. {bathos-0.3.0 → bathos-0.3.1}/.agent/workspace.id +0 -0
  14. {bathos-0.3.0 → bathos-0.3.1}/.bth.toml +0 -0
  15. {bathos-0.3.0 → bathos-0.3.1}/.coverage +0 -0
  16. {bathos-0.3.0 → bathos-0.3.1}/.github/SECRETS.md +0 -0
  17. {bathos-0.3.0 → bathos-0.3.1}/.github/workflows/publish.yml +0 -0
  18. {bathos-0.3.0 → bathos-0.3.1}/.github/workflows/test.yml +0 -0
  19. {bathos-0.3.0 → bathos-0.3.1}/.gitignore +0 -0
  20. {bathos-0.3.0 → bathos-0.3.1}/.python-version +0 -0
  21. {bathos-0.3.0 → bathos-0.3.1}/.readthedocs.yaml +0 -0
  22. {bathos-0.3.0 → bathos-0.3.1}/LICENSE +0 -0
  23. {bathos-0.3.0 → bathos-0.3.1}/agent_assets/docs/gemini-cli-integration.md +0 -0
  24. {bathos-0.3.0 → bathos-0.3.1}/docs/Makefile +0 -0
  25. {bathos-0.3.0 → bathos-0.3.1}/docs/source/api.rst +0 -0
  26. {bathos-0.3.0 → bathos-0.3.1}/docs/source/architecture.rst +0 -0
  27. {bathos-0.3.0 → bathos-0.3.1}/docs/source/conf.py +0 -0
  28. {bathos-0.3.0 → bathos-0.3.1}/docs/source/contributing.rst +0 -0
  29. {bathos-0.3.0 → bathos-0.3.1}/docs/source/index.rst +0 -0
  30. {bathos-0.3.0 → bathos-0.3.1}/docs/source/slurm-integration.rst +0 -0
  31. {bathos-0.3.0 → bathos-0.3.1}/docs/source/user-guide.rst +0 -0
  32. {bathos-0.3.0 → bathos-0.3.1}/docs/superpowers/plans/2026-05-15-bathos-v01-core.md +0 -0
  33. {bathos-0.3.0 → bathos-0.3.1}/docs/superpowers/plans/2026-05-19-agent-onboarding-export.md +0 -0
  34. {bathos-0.3.0 → bathos-0.3.1}/docs/superpowers/plans/2026-05-19-decorator.md +0 -0
  35. {bathos-0.3.0 → bathos-0.3.1}/docs/superpowers/plans/2026-05-19-historical-migration.md +0 -0
  36. {bathos-0.3.0 → bathos-0.3.1}/docs/superpowers/plans/2026-05-19-linter.md +0 -0
  37. {bathos-0.3.0 → bathos-0.3.1}/docs/superpowers/plans/2026-05-19-remote-management.md +0 -0
  38. {bathos-0.3.0 → bathos-0.3.1}/docs/superpowers/plans/2026-05-19-schema-versioning.md +0 -0
  39. {bathos-0.3.0 → bathos-0.3.1}/docs/superpowers/plans/2026-05-19-skill-and-export-mcp.md +0 -0
  40. {bathos-0.3.0 → bathos-0.3.1}/docs/superpowers/plans/2026-05-19-v02-feature-wiring.md +0 -0
  41. {bathos-0.3.0 → bathos-0.3.1}/docs/superpowers/plans/2026-05-20-agentic-integrity-design.md +0 -0
  42. {bathos-0.3.0 → bathos-0.3.1}/docs/superpowers/plans/2026-05-20-agentic-integrity-impl-plan.md +0 -0
  43. {bathos-0.3.0 → bathos-0.3.1}/docs/superpowers/specs/2026-05-15-bathos-design.md +0 -0
  44. {bathos-0.3.0 → bathos-0.3.1}/inventory.txt +0 -0
  45. {bathos-0.3.0 → bathos-0.3.1}/main.py +0 -0
  46. {bathos-0.3.0 → bathos-0.3.1}/praxia.toml +0 -0
  47. {bathos-0.3.0 → bathos-0.3.1}/scripts/benchmarks/.bth.toml +0 -0
  48. {bathos-0.3.0 → bathos-0.3.1}/scripts/experiments/.bth.toml +0 -0
  49. {bathos-0.3.0 → bathos-0.3.1}/scripts/slurm/_bth_env.sh +0 -0
  50. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/__init__.py +0 -0
  51. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/archive.py +0 -0
  52. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/campaigns.py +0 -0
  53. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/catalog.py +0 -0
  54. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/checker.py +0 -0
  55. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/cli.py +0 -0
  56. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/compact.py +0 -0
  57. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/config.py +0 -0
  58. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/decorators.py +0 -0
  59. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/export.py +0 -0
  60. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/git.py +0 -0
  61. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/init.py +0 -0
  62. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/linter.py +0 -0
  63. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/mcp.py +0 -0
  64. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/migrate.py +0 -0
  65. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/new_experiment.py +0 -0
  66. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/prereg.py +0 -0
  67. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/query.py +0 -0
  68. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/remote.py +0 -0
  69. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/runner.py +0 -0
  70. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/sidecar.py +0 -0
  71. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/sprint_audit.py +0 -0
  72. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/templates/_bth_env.sh +0 -0
  73. {bathos-0.3.0 → bathos-0.3.1}/src/bathos/validate.py +0 -0
  74. {bathos-0.3.0 → bathos-0.3.1}/tests/__init__.py +0 -0
  75. {bathos-0.3.0 → bathos-0.3.1}/tests/conftest.py +0 -0
  76. {bathos-0.3.0 → bathos-0.3.1}/tests/test_archive.py +0 -0
  77. {bathos-0.3.0 → bathos-0.3.1}/tests/test_campaigns.py +0 -0
  78. {bathos-0.3.0 → bathos-0.3.1}/tests/test_catalog.py +0 -0
  79. {bathos-0.3.0 → bathos-0.3.1}/tests/test_checker.py +0 -0
  80. {bathos-0.3.0 → bathos-0.3.1}/tests/test_cli.py +0 -0
  81. {bathos-0.3.0 → bathos-0.3.1}/tests/test_compact.py +0 -0
  82. {bathos-0.3.0 → bathos-0.3.1}/tests/test_config.py +0 -0
  83. {bathos-0.3.0 → bathos-0.3.1}/tests/test_decorators.py +0 -0
  84. {bathos-0.3.0 → bathos-0.3.1}/tests/test_export.py +0 -0
  85. {bathos-0.3.0 → bathos-0.3.1}/tests/test_git.py +0 -0
  86. {bathos-0.3.0 → bathos-0.3.1}/tests/test_init.py +0 -0
  87. {bathos-0.3.0 → bathos-0.3.1}/tests/test_integration.py +0 -0
  88. {bathos-0.3.0 → bathos-0.3.1}/tests/test_linter.py +0 -0
  89. {bathos-0.3.0 → bathos-0.3.1}/tests/test_mcp_integration.py +0 -0
  90. {bathos-0.3.0 → bathos-0.3.1}/tests/test_mcp_server.py +0 -0
  91. {bathos-0.3.0 → bathos-0.3.1}/tests/test_migrate.py +0 -0
  92. {bathos-0.3.0 → bathos-0.3.1}/tests/test_new_experiment.py +0 -0
  93. {bathos-0.3.0 → bathos-0.3.1}/tests/test_prereg.py +0 -0
  94. {bathos-0.3.0 → bathos-0.3.1}/tests/test_query.py +0 -0
  95. {bathos-0.3.0 → bathos-0.3.1}/tests/test_remote.py +0 -0
  96. {bathos-0.3.0 → bathos-0.3.1}/tests/test_runner.py +0 -0
  97. {bathos-0.3.0 → bathos-0.3.1}/tests/test_schema.py +0 -0
  98. {bathos-0.3.0 → bathos-0.3.1}/tests/test_sidecar.py +0 -0
  99. {bathos-0.3.0 → bathos-0.3.1}/tests/test_slurm_integration.py +0 -0
  100. {bathos-0.3.0 → bathos-0.3.1}/tests/test_sprint_audit.py +0 -0
  101. {bathos-0.3.0 → bathos-0.3.1}/tests/test_validate.py +0 -0
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ### Fixed
11
+
12
+ - **`bth sync` indefinite hang** — `sync_catalog()` now passes SSH options (`ConnectTimeout=10`, `BatchMode=yes`) to rsync so unreachable hosts fail in ≤10 s instead of blocking forever; adds `subprocess.run(timeout=120)` as a safety net; raises `RuntimeError` with actionable message on timeout; drops silent `--progress` flag (output was captured, not displayed)
13
+
14
+ - **Parquet timestamp timezone-aware fix** — Ensure timestamps loaded from Parquet are timezone-aware (UTC) to avoid comparisons between naive and aware datetimes in query functions; prevents TypeError and incorrect filtering.
15
+
16
+ ---
17
+
8
18
  ## [0.3.0] - 2026-05-20
9
19
 
10
20
  ### Added
@@ -10,15 +10,19 @@ bathos is a standalone experiment tracking CLI for a single researcher across 10
10
10
 
11
11
  ---
12
12
 
13
- ## Current Status (as of 2026-05-15)
13
+ ## Current Status (as of 2026-05-20)
14
14
 
15
- **v0.1: complete and merged to main.** 44 tests passing.
15
+ **v0.3.0: complete and merged to main.** 254 tests passing.
16
16
 
17
17
  - Full design spec: `.praxia/specs/bathos-design.md`
18
18
  - v0.1 implementation plan: `.praxia/specs/bathos-v01-plan.md`
19
- - Backlog: items #124–139 in praxia DB (see below); #124–127 done
19
+ - Backlog: items #124–142 in praxia DB (see below); #124–141 done
20
20
 
21
- **Next sprint candidates (P2):** #128 (FastMCP), #130 (bth check) + #128 unblocked once 130 done, #138 (bth sync), #139 (bth compact / warm tier), #131 (SLURM integration), #132 (bth new-experiment).
21
+ **Shipped in v0.2:** FastMCP server (#128), `@bth.experiment` decorator (#129), `bth check` (#130), SLURM `_bth_env.sh` (#131), `bth new-experiment` (#132), `uv tool` packaging (#133), `bth lint` (#134), `bth migrate` (#135), `bth sync` (#138), schema versioning v2 (#140), `bth archive` (#141), `bth remote` subcommands, `bth export`, `bth catalog-version`.
22
+
23
+ **Shipped in v0.3:** Agentic integrity gate (`--agent-mode`, `--no-sidecar`, `--derived-from`), lineage tracking (`bth lineage`), campaigns (`bth campaign` subcommands + MCP tools), sprint audit (`bth sprint-audit`), Tier-2 lint checks, schema v3 with campaign/lineage/integrity fields, `--campaign` flag on `bth run`.
24
+
25
+ **Remaining backlog:** #136 (bth-migrate praxia workflow), #137 (global instruction portability), #142 (results management design).
22
26
 
23
27
  ---
24
28
 
@@ -52,7 +56,7 @@ Cool schema is intentionally minimal (13 provenance fields). Warm adds `metadata
52
56
 
53
57
  ### Pre-Registration Schemas (per script directory)
54
58
 
55
- Every script in `scripts/experiments/` and `scripts/benchmarks/` must have a companion sidecar **`<script-stem>.bth.toml`** declaring its hypothesis, expected outcomes, and result schema before `bth run` will execute it.
59
+ Every script in `scripts/experiments/` and `scripts/benchmarks/` should have a companion sidecar **`<script-stem>.bth.toml`** declaring its hypothesis, expected outcomes, and result schema. In v0.2+, `bth run` enforces this by default; pass `--no-sidecar` to bypass.
56
60
 
57
61
  **Sidecar format (experiments):**
58
62
  ```toml
@@ -118,7 +122,7 @@ fix = "str"
118
122
  | Catalog storage | **DuckDB + Parquet** (not pyiceberg) | pyiceberg is for distributed data lakes; DuckDB+Parquet is simpler, no overhead |
119
123
  | FastMCP | Mirror CLI tool-for-tool | `cli.py` and `mcp.py` both thin layers over same core modules |
120
124
 
121
- ### Source Layout (planned)
125
+ ### Source Layout
122
126
 
123
127
  ```
124
128
  src/bathos/
@@ -133,8 +137,20 @@ src/bathos/
133
137
  init.py # bth init logic
134
138
  runner.py # bth run subprocess wrapper
135
139
  query.py # list_runs, get_run, find_runs, run_sql
136
- checker.py # bth check — git-drift validity (v0.2)
137
- sidecar.py # .bth.toml sidecar parse, content-hash, outcome eval (v0.2)
140
+ checker.py # bth check — git-drift freshness gate
141
+ sidecar.py # .bth.toml sidecar parse, content-hash, outcome eval
142
+ campaigns.py # bth campaign subcommands + Campaign dataclass
143
+ sprint_audit.py # bth sprint-audit cross-project audit
144
+ linter.py # bth lint — Tier-1 and Tier-2 checks
145
+ migrate.py # bth migrate — schema version upgrades
146
+ new_experiment.py # bth new-experiment scaffold
147
+ export.py # bth export — skill + MCP registration
148
+ validate.py # sidecar structural validation
149
+ remote.py # bth remote subcommands
150
+ sync.py # bth sync rsync wrapper
151
+ archive.py # bth archive warm→cold export
152
+ prereg.py # agentic integrity pre-registration gate
153
+ decorators.py # @bth.experiment provenance decorator
138
154
  templates/
139
155
  _bth_env.sh # SLURM env helper template
140
156
  experiment.py # bth new-experiment script skeleton
@@ -150,25 +166,24 @@ src/bathos/
150
166
  | 125 | `bth init` — dirs, .bth.toml, catalog bootstrap, SLURM config | P1 | 124 |
151
167
  | 126 | `bth run` — CLI wrapper, provenance capture | P1 | 124 |
152
168
  | 127 | `bth ls` / `show` / `find` / `sql` — query interface | P1 | 126 |
153
- | 128 | FastMCP server — mirrors CLI tool-for-tool | P1 | 126, 127, 130 |
154
- | 129 | `@bth.experiment` — provenance decorator for Typer scripts | P2 | 124 |
155
- | 130 | `bth check` — freshness/validity vs git HEAD | P2 | 126 |
156
- | 131 | SLURM `_bth_env.sh` integration | P2 | 125, 126 |
157
- | 132 | `bth new-experiment` — Typer + sidecar scaffold | P2 | 125 |
158
- | 133 | `uv tool` packaging + release | P3 | 126–130 |
159
- | 134 | Script convention linter | P3 | — |
160
- | 135 | `bth migrate` — Phase 1 mechanical (existing projects) | P2 | 125 |
161
- | 136 | `bth-migrate` praxia workflow — agentic classification + git mv plan | P2 | 135 |
162
- | 137 | Global instruction portability (separate design session needed) | P2 | — |
163
- | 138 | `bth sync` — rsync cool-tier catalog to/from cluster remote | P2 | 125, v0.1 done |
164
- | 139 | `bth compact` + warm-tier DuckDB (`bth sql` catalog queries) | P2 | v0.1 done |
165
- | 140 | Schema versioning + extended provenance (hostname, slurm_job_id, metadata JSON, migrations) | P2 | 139 |
166
- | 141 | `bth archive` — warm→cold partitioned Parquet export | P3 | 139, 140 |
167
- | 142 | Results management — output convention, file-count utilities, direct management interface design | P2 | 139 |
169
+ | 128 | FastMCP server — mirrors CLI tool-for-tool | P1 ✓ done (v0.2) | 126, 127, 130 |
170
+ | 129 | `@bth.experiment` — provenance decorator for Typer scripts | P2 ✓ done (v0.2) | 124 |
171
+ | 130 | `bth check` — freshness/validity vs git HEAD | P2 ✓ done (v0.1/v0.2) | 126 |
172
+ | 131 | SLURM `_bth_env.sh` integration | P2 ✓ done (v0.1) | 125, 126 |
173
+ | 132 | `bth new-experiment` — Typer + sidecar scaffold | P2 ✓ done (v0.2) | 125 |
174
+ | 133 | `uv tool` packaging + release | P3 ✓ done (v0.2) | 126–130 |
175
+ | 134 | Script convention linter | P3 ✓ done (v0.2) | — |
176
+ | 135 | `bth migrate` — Phase 1 mechanical (existing projects) | P2 ✓ done (v0.2) | 125 |
177
+ | 136 | `bth-migrate` praxia workflow — agentic classification + git mv plan | P2 (not started) | 135 |
178
+ | 137 | Global instruction portability (separate design session needed) | P2 (not started) | — |
179
+ | 138 | `bth sync` — rsync cool-tier catalog to/from cluster remote | P2 ✓ done (v0.2) | 125, v0.1 done |
180
+ | 139 | `bth compact` + warm-tier DuckDB (`bth sql` catalog queries) | P2 ✓ done (v0.1) | v0.1 done |
181
+ | 140 | Schema versioning + extended provenance (hostname, slurm_job_id, metadata JSON, migrations) | P2 ✓ done (v0.2) | 139 |
182
+ | 141 | `bth archive` — warm→cold partitioned Parquet export | P3 ✓ done (v0.2) | 139, 140 |
183
+ | 142 | Results management — output convention, file-count utilities, direct management interface design | P2 (not started) | 139 |
168
184
 
169
185
  **Not yet backlogged:**
170
- - Sidecar pre-registration enforcement in `bth run` (add as P2, depends on 126)
171
- - Outcome evaluation + `runs.outcome` column in warm DuckDB (add as P2, depends on 139)
186
+ - *(none — sidecar enforcement and outcome evaluation shipped in v0.2/v0.3)*
172
187
 
173
188
  ---
174
189
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bathos
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: Local-first, zero-server experiment tracking for researchers
5
5
  Project-URL: Homepage, https://github.com/mariellerossi/bathos
6
6
  Project-URL: Documentation, https://bathos.readthedocs.io
@@ -66,13 +66,52 @@ bth run scripts/experiments/benchmark_tip3p.py -- --n-steps 1000 --out outputs/r
66
66
  bth ls --since 7d
67
67
  bth show <run-id>
68
68
 
69
- # Check if a result is still valid (compares recorded git hash to HEAD)
70
- bth check outputs/run1.parquet
69
+ # Check catalog runs for git-drift freshness
70
+ bth check [--status <status>] [--check-outputs]
71
71
 
72
72
  # Escape hatch: raw DuckDB SQL against the catalog
73
73
  bth sql "SELECT project_slug, count(*) FROM runs GROUP BY 1"
74
74
  ```
75
75
 
76
+ ### `bth run` flags
77
+
78
+ **v0.3+ flags:**
79
+ - `--agent-mode collaborative|autonomous` — declare whether this run is agent-driven
80
+ - `--derived-from <run-id>` — record parent run for lineage tracking
81
+ - `--campaign <campaign-id>` — associate this run with a campaign
82
+ - `--no-sidecar` — bypass sidecar enforcement (use for ad-hoc runs)
83
+
84
+ ## CLI Reference
85
+
86
+ **Core commands:**
87
+ - `bth init` — initialize bathos in a project
88
+ - `bth run` — execute and track an experiment
89
+ - `bth ls` — list recent runs
90
+ - `bth show <run-id>` — display run details
91
+ - `bth find` — search runs by criteria
92
+ - `bth sql` — raw DuckDB query against catalog
93
+ - `bth check` — check catalog runs for git-drift freshness
94
+ - `bth lineage <run-id>` — show ancestor chain following parent_run_id links
95
+ - `bth sprint-audit [--hours N]` — audit recent runs across all registered projects
96
+ - `bth lint [--project-root PATH]` — check scripts/ for naming conventions and missing sidecars
97
+ - `bth new-experiment <name>` — scaffold a new experiment script and sidecar
98
+ - `bth migrate` — upgrade cool-tier Parquet fragments to current schema version
99
+ - `bth export` — export the using-bathos skill and register MCP server
100
+
101
+ **`bth remote`** — Manage sync remotes
102
+ - `bth remote add <name> <url>` — add an SSH remote for catalog sync
103
+ - `bth remote list` — list configured remotes
104
+ - `bth remote remove <name>` — remove a remote
105
+ - `bth remote test <name>` — test SSH connectivity to a remote
106
+
107
+ **`bth campaign`** — Manage experiment campaigns (v0.3+)
108
+ - `bth campaign create <id> --hypothesis <text>` — create a new campaign
109
+ - `bth campaign add <run-id> --campaign <id>` — associate a run with a campaign
110
+ - `bth campaign ls` — list campaigns
111
+ - `bth campaign show <id>` — show campaign details and runs
112
+ - `bth campaign review <id>` — statistical summary and anomaly detection
113
+ - `bth campaign conclude <id> --outcome <label>` — close campaign with outcome
114
+
76
115
  ## Script conventions
77
116
 
78
117
  `bth init` scaffolds the following structure in your project:
@@ -30,13 +30,52 @@ bth run scripts/experiments/benchmark_tip3p.py -- --n-steps 1000 --out outputs/r
30
30
  bth ls --since 7d
31
31
  bth show <run-id>
32
32
 
33
- # Check if a result is still valid (compares recorded git hash to HEAD)
34
- bth check outputs/run1.parquet
33
+ # Check catalog runs for git-drift freshness
34
+ bth check [--status <status>] [--check-outputs]
35
35
 
36
36
  # Escape hatch: raw DuckDB SQL against the catalog
37
37
  bth sql "SELECT project_slug, count(*) FROM runs GROUP BY 1"
38
38
  ```
39
39
 
40
+ ### `bth run` flags
41
+
42
+ **v0.3+ flags:**
43
+ - `--agent-mode collaborative|autonomous` — declare whether this run is agent-driven
44
+ - `--derived-from <run-id>` — record parent run for lineage tracking
45
+ - `--campaign <campaign-id>` — associate this run with a campaign
46
+ - `--no-sidecar` — bypass sidecar enforcement (use for ad-hoc runs)
47
+
48
+ ## CLI Reference
49
+
50
+ **Core commands:**
51
+ - `bth init` — initialize bathos in a project
52
+ - `bth run` — execute and track an experiment
53
+ - `bth ls` — list recent runs
54
+ - `bth show <run-id>` — display run details
55
+ - `bth find` — search runs by criteria
56
+ - `bth sql` — raw DuckDB query against catalog
57
+ - `bth check` — check catalog runs for git-drift freshness
58
+ - `bth lineage <run-id>` — show ancestor chain following parent_run_id links
59
+ - `bth sprint-audit [--hours N]` — audit recent runs across all registered projects
60
+ - `bth lint [--project-root PATH]` — check scripts/ for naming conventions and missing sidecars
61
+ - `bth new-experiment <name>` — scaffold a new experiment script and sidecar
62
+ - `bth migrate` — upgrade cool-tier Parquet fragments to current schema version
63
+ - `bth export` — export the using-bathos skill and register MCP server
64
+
65
+ **`bth remote`** — Manage sync remotes
66
+ - `bth remote add <name> <url>` — add an SSH remote for catalog sync
67
+ - `bth remote list` — list configured remotes
68
+ - `bth remote remove <name>` — remove a remote
69
+ - `bth remote test <name>` — test SSH connectivity to a remote
70
+
71
+ **`bth campaign`** — Manage experiment campaigns (v0.3+)
72
+ - `bth campaign create <id> --hypothesis <text>` — create a new campaign
73
+ - `bth campaign add <run-id> --campaign <id>` — associate a run with a campaign
74
+ - `bth campaign ls` — list campaigns
75
+ - `bth campaign show <id>` — show campaign details and runs
76
+ - `bth campaign review <id>` — statistical summary and anomaly detection
77
+ - `bth campaign conclude <id> --outcome <label>` — close campaign with outcome
78
+
40
79
  ## Script conventions
41
80
 
42
81
  `bth init` scaffolds the following structure in your project:
@@ -38,14 +38,18 @@ The skill is loaded automatically at session start in Claude Code. In a new sess
38
38
 
39
39
  | MCP Tool | CLI equivalent | Status |
40
40
  |----------|---------------|--------|
41
- | `run_script` | `bth run` | ✅ Available |
41
+ | `run` | `bth run` | ✅ Available |
42
42
  | `list_runs` | `bth ls` | ✅ Available |
43
43
  | `get_run` | `bth show <id>` | ✅ Available |
44
44
  | `find_runs` | `bth find` | ✅ Available |
45
45
  | `run_sql` | `bth sql` | ✅ Available |
46
46
  | `compact_catalog` | `bth compact` | ✅ Available |
47
- | `check_runs` | `bth check` | 🔜 Coming in v0.2 |
48
- | `archive_runs` | `bth archive` | 🔜 Coming in v0.2 |
47
+ | `check` | `bth check` | ✅ Available |
48
+ | `archive` | `bth archive` | ✅ Available |
49
+ | `campaign_create` | `bth campaign create` | ✅ Available |
50
+ | `campaign_list` | `bth campaign ls` | ✅ Available |
51
+ | `campaign_review` | `bth campaign review` | ✅ Available |
52
+ | `campaign_conclude` | `bth campaign conclude` | ✅ Available |
49
53
 
50
54
  ## Update
51
55
 
@@ -13,7 +13,7 @@ description: "Use when working in any bathos-tracked research project — experi
13
13
 
14
14
  **Scope:** Single researcher, 10+ projects, SLURM cluster integration.
15
15
 
16
- **Status:** ✅ v0.2 shipped — 207 tests passing. Full CLI + MCP server available.
16
+ **Status:** ✅ v0.3.0 shipped — 254 tests passing. Full CLI + MCP server available, including campaigns and agentic integrity gates.
17
17
 
18
18
  ---
19
19
 
@@ -34,7 +34,7 @@ description: "Use when working in any bathos-tracked research project — experi
34
34
  | Command | Arguments | Status | Notes |
35
35
  |---------|-----------|--------|-------|
36
36
  | bth init | --slug, --remote, --slurm-partition | ✅ | Project initialization |
37
- | bth run | <script> [-- args], --tag, --out, --campaign, --agent-mode, --no-sidecar | ✅ | Execute + provenance capture |
37
+ | bth run | <script> [-- args], --tag, --out, --campaign, --agent-mode, --derived-from, --no-sidecar | ✅ | Execute + provenance capture; v0.3: `--agent-mode` (collaborative/autonomous), `--derived-from` (lineage), `--campaign` (campaign association), `--no-sidecar` (bypass enforcement) |
38
38
  | bth ls | --since, --status, --limit, --project | ✅ | List recent runs + OUTCOME column |
39
39
  | bth show | <run-id> | ✅ | Full run details + git state |
40
40
  | bth find | --project, --since, --status, --tag, --output-file | ✅ | Flexible filtered query |
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "bathos"
7
- version = "0.3.0"
7
+ version = "0.3.1"
8
8
  description = "Local-first, zero-server experiment tracking for researchers"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -137,6 +137,9 @@ class Run:
137
137
  ts = pydict["timestamp"][i]
138
138
  if not isinstance(ts, datetime):
139
139
  ts = ts.as_py()
140
+ # Ensure timestamp is timezone-aware in UTC for internal comparisons
141
+ if ts.tzinfo is None:
142
+ ts = ts.replace(tzinfo=UTC)
140
143
  return cls(
141
144
  id=pydict["id"][i],
142
145
  project_slug=pydict["project_slug"][i],
@@ -7,6 +7,8 @@ from pathlib import Path
7
7
 
8
8
  from bathos.config import ProjectConfig
9
9
 
10
+ _SYNC_TIMEOUT_S = 120 # rsync kill switch: fail if no completion within 2 minutes
11
+
10
12
 
11
13
  @dataclass
12
14
  class SyncResult:
@@ -53,17 +55,30 @@ def sync_catalog(
53
55
  src = str(local_runs) + "/"
54
56
  dst = remote_runs
55
57
 
56
- # Construct rsync command
58
+ # ConnectTimeout=10: fail in 10s if host is unreachable rather than hanging
59
+ # BatchMode=yes: never prompt for a password — fail immediately instead
60
+ ssh_opts = "ssh -o ConnectTimeout=10 -o BatchMode=yes"
61
+
57
62
  cmd = [
58
63
  "rsync",
59
- "-azP",
64
+ "-az",
65
+ "--partial",
66
+ f"-e{ssh_opts}",
60
67
  "--ignore-existing",
61
68
  src,
62
69
  dst,
63
70
  ]
64
71
 
65
72
  start_time = time.time()
66
- result = subprocess.run(cmd, capture_output=True, text=True)
73
+ try:
74
+ result = subprocess.run(
75
+ cmd, capture_output=True, text=True, timeout=_SYNC_TIMEOUT_S
76
+ )
77
+ except subprocess.TimeoutExpired:
78
+ raise RuntimeError(
79
+ f"bth sync timed out after {_SYNC_TIMEOUT_S}s — "
80
+ "check that the remote host is reachable and SSH keys are configured"
81
+ )
67
82
  duration_s = time.time() - start_time
68
83
 
69
84
  if result.returncode != 0:
@@ -177,7 +177,7 @@ remote_root = "~/projects/testproj"
177
177
 
178
178
  # Verify rsync command structure
179
179
  assert cmd[0] == "rsync"
180
- assert "-azP" in cmd
180
+ assert "-az" in cmd
181
181
  assert "--ignore-existing" in cmd
182
182
  # Should have source and destination with runs/ directories
183
183
  assert any("runs/" in str(arg) for arg in cmd)
@@ -40,14 +40,59 @@ def test_sync_constructs_correct_rsync_command_push(tmp_path: Path):
40
40
 
41
41
  # Should be rsync command
42
42
  assert cmd[0] == "rsync"
43
- # Should have -azP flags
44
- assert "-azP" in cmd
43
+ # Should have -az flags (no -P: progress is useless when output is captured)
44
+ assert "-az" in cmd
45
+ # Should pass SSH options for fast failure: ConnectTimeout + BatchMode
46
+ assert any("ConnectTimeout" in str(a) for a in cmd)
47
+ assert any("BatchMode=yes" in str(a) for a in cmd)
45
48
  # Should have --ignore-existing flag
46
49
  assert "--ignore-existing" in cmd
47
50
  # Should reference runs directories
48
51
  assert any("runs/" in str(arg) for arg in cmd)
49
52
 
50
53
 
54
+ def test_sync_passes_timeout_to_subprocess(tmp_path: Path):
55
+ """sync_catalog passes a timeout to subprocess.run so it cannot hang forever."""
56
+ config = ProjectConfig(
57
+ slug="test",
58
+ root=Path("/home/user/test"),
59
+ remotes={"engaging": {"host": "engaging", "remote_root": "~/projects/test"}},
60
+ )
61
+ catalog_dir = tmp_path / "catalog"
62
+ catalog_dir.mkdir()
63
+ (catalog_dir / "runs").mkdir()
64
+
65
+ with patch("bathos.sync.subprocess.run") as mock_run:
66
+ mock_run.return_value.returncode = 0
67
+ mock_run.return_value.stdout = ""
68
+
69
+ sync_catalog("engaging", config, catalog_dir, pull=False)
70
+
71
+ call_kwargs = mock_run.call_args[1]
72
+ assert "timeout" in call_kwargs, "subprocess.run must have a timeout to prevent indefinite hangs"
73
+ assert call_kwargs["timeout"] > 0
74
+
75
+
76
+ def test_sync_raises_on_timeout(tmp_path: Path):
77
+ """sync_catalog raises RuntimeError with clear message when rsync times out."""
78
+ import subprocess as _subprocess
79
+
80
+ config = ProjectConfig(
81
+ slug="test",
82
+ root=Path("/home/user/test"),
83
+ remotes={"engaging": {"host": "engaging", "remote_root": "~/projects/test"}},
84
+ )
85
+ catalog_dir = tmp_path / "catalog"
86
+ catalog_dir.mkdir()
87
+ (catalog_dir / "runs").mkdir()
88
+
89
+ with patch("bathos.sync.subprocess.run") as mock_run:
90
+ mock_run.side_effect = _subprocess.TimeoutExpired(cmd=["rsync"], timeout=120)
91
+
92
+ with pytest.raises(RuntimeError, match="timed out"):
93
+ sync_catalog("engaging", config, catalog_dir, pull=False)
94
+
95
+
51
96
  def test_sync_pull_reverses_direction(tmp_path: Path):
52
97
  """sync_catalog pulls from remote when pull=True."""
53
98
  config = ProjectConfig(
@@ -57,7 +57,7 @@ wheels = [
57
57
 
58
58
  [[package]]
59
59
  name = "bathos"
60
- version = "0.3.0"
60
+ version = "0.3.1"
61
61
  source = { editable = "." }
62
62
  dependencies = [
63
63
  { name = "duckdb" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes