Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
218 commits
Select commit Hold shift + click to select a range
fcbd476
chore(deps): bump docker/login-action from 3 to 4
dependabot[bot] Apr 21, 2026
874bf3d
chore(deps): bump actions/download-artifact from 4 to 8
dependabot[bot] Apr 21, 2026
3bb3de7
chore(deps): bump docker/setup-buildx-action from 3 to 4
dependabot[bot] Apr 21, 2026
247b183
chore(deps): bump docker/build-push-action from 5 to 7
dependabot[bot] Apr 21, 2026
1c36caa
chore(deps): bump sse-starlette from 2.1.0 to 3.3.4 in /backend
dependabot[bot] Apr 21, 2026
8de865a
chore(deps): bump python-dotenv from 1.0.1 to 1.2.2 in /backend
dependabot[bot] May 12, 2026
5a894b4
chore(deps-dev): bump prettier from 3.8.1 to 3.8.3 in /frontend
dependabot[bot] May 12, 2026
22e72fe
chore(deps): bump fastapi from 0.115.0 to 0.136.1 in /backend
dependabot[bot] May 12, 2026
a7aaef6
chore(deps): bump python-multipart from 0.0.12 to 0.0.28 in /backend
dependabot[bot] May 12, 2026
1f330ec
chore(deps-dev): bump postcss from 8.5.8 to 8.5.14 in /frontend
dependabot[bot] May 12, 2026
7bc9c0b
chore(deps): bump react-resizable-panels in /frontend
dependabot[bot] May 12, 2026
ea8937e
chore(deps): bump react-syntax-highlighter in /frontend
dependabot[bot] May 12, 2026
e5d5aca
chore(deps): bump react-markdown from 9.1.0 to 10.1.0 in /frontend
dependabot[bot] May 12, 2026
5d4f99f
chore(deps): bump sqlalchemy from 2.0.35 to 2.0.49 in /backend
dependabot[bot] May 12, 2026
f0e4ae9
feat(download): bulk workspace export — session + project zip endpoints
lucastononro May 12, 2026
7dc0d1b
fix: harden workspace exports
lucastononro May 13, 2026
8cfc952
fix: mark partial workspace export reads
lucastononro May 14, 2026
1659a10
docs(cli): update README for v0.0.4 multi-provider behavior
Dodothereal Jul 17, 2026
90e21d1
docs: fix broken issue-tracker link (trainable-monorepo -> trainable)…
Jul 19, 2026
a99bae5
fix(frontend): use relative /api URLs instead of hardcoded http://hos…
Jul 19, 2026
facd3ba
fix(cli): chmod 0600 the generated ~/.trainable/.env secrets file (#127)
Jul 19, 2026
57181cc
chore(dev): add .pre-commit-config.yaml matching CONTRIBUTING (#122)
Jul 19, 2026
5161fa9
fix(compose): require operator secrets + stop publicly exposing datas…
Jul 19, 2026
7e65878
chore(lint): add explicit ruff config in backend/pyproject.toml (#124)
Jul 19, 2026
511a806
refactor(compute): provider abstraction over sandbox/kernel/storage/s…
Jul 19, 2026
9b7fb6d
feat(backend): opt-in bearer-token auth for /api/* (API_AUTH_TOKEN)
Jul 19, 2026
ef068aa
perf(backend): offload DuckDB/pandas work off the event loop (#93)
Jul 19, 2026
67f6157
fix(backend): restrict CORS — configurable origins, never wildcard+cr…
Jul 19, 2026
8c25d28
fix(s3): bound /api/s3/upload memory and validate bucket/key targets
Jul 19, 2026
57b29ee
fix(backend): enforce wall-clock timeout on provider LLM calls (#95)
Jul 19, 2026
0dad7d7
perf(s3): offload blocking boto3 calls to worker threads
Jul 19, 2026
2c7a815
feat(backend): real readiness probe (/api/readyz) + compose healthchecks
Jul 19, 2026
1196537
feat(compute): RunPod provider — execution, kernels, storage, serving
Jul 19, 2026
fe9341c
fix(experiments): bound memory in the multi-file upload endpoint
Jul 19, 2026
49a9927
fix(frontend): dedupe EventSource — share one session SSE stream
Jul 19, 2026
417283e
ci: add pytest-cov coverage measurement and gate to backend-test
Jul 19, 2026
1f4c600
perf(frontend): memoize chat item rendering to stop re-parsing markdo…
Jul 19, 2026
451c18f
fix(backend): capture unhandled + background-task errors in Sentry (#…
Jul 19, 2026
b8ec20c
fix(frontend): stop auto-scroll from hijacking scrollback during stre…
Jul 19, 2026
33c847e
refactor(db): introduce Alembic migrations (replace boot-time _run_mi…
Jul 19, 2026
586302f
ci: run backend tests against Postgres in CI, not only in-memory SQLite
Jul 19, 2026
1a809a9
test(backend): cover agent orchestration + sandbox lifecycle (#115)
Jul 19, 2026
f578a08
ci: add advisory dependency and container image vulnerability scanning
Jul 19, 2026
13e17ca
refactor(frontend): replace SSE/event any-typing with a discriminated…
Jul 19, 2026
b32094c
test(frontend): add Vitest + Testing Library and a frontend-test CI job
Jul 19, 2026
121ce37
fix(frontend): add error boundaries so one render throw doesn't blank…
Jul 19, 2026
8b728fa
feat(frontend): comparison leaderboard consuming the /compare endpoint
Jul 19, 2026
3017c28
feat: add "Reproduce" action that replays a snapshot and diffs metric…
lucastononro Jul 19, 2026
553e8f9
feat(models): in-app prediction playground on the model card (#109)
lucastononro Jul 19, 2026
ae8d05d
feat(training): pre-flight training controls — metric, model families…
lucastononro Jul 19, 2026
a42d0d0
feat(budget): enforce per-project cost budgets with a hard-stop guard…
lucastononro Jul 19, 2026
213c9ff
refactor(frontend): split the 4345-line page.tsx monolith (#97)
lucastononro Jul 19, 2026
bdf190f
docs(design): multi-user auth + ownership design note (#113)
lucastononro Jul 19, 2026
890ebce
feat(data): raw dataset preview + quick-profile on upload
lucastononro Jul 19, 2026
a879e39
feat: surface sample datasets with a guided first-run gallery
lucastononro Jul 19, 2026
1c2ab35
feat: resume / re-run for aborted and failed sessions (#106)
lucastononro Jul 19, 2026
f98768f
feat: human-in-the-loop approval checkpoints before expensive stages …
lucastononro Jul 19, 2026
808dc2f
feat: turn EDA findings into one-click-to-prep action cards (#111)
lucastononro Jul 19, 2026
b4a59ef
test(db): cover the deployments provider-columns migration on legacy DBs
lucastononro Jul 19, 2026
39d82b0
feat(agent): agent-selectable GPU/CPU per execute-code call with proj…
Jul 19, 2026
3020b76
fix(review): address Greptile findings on #135
lucastononro Jul 20, 2026
2e313f8
fix(review): address Greptile findings on #136
lucastononro Jul 20, 2026
4259bdf
fix(review): address Greptile findings on #134
lucastononro Jul 20, 2026
b2488b4
fix(review): address Greptile findings on #133
lucastononro Jul 20, 2026
6936b64
fix(review): address Greptile findings on #139
lucastononro Jul 20, 2026
eab79ba
fix(review): address Greptile findings on #138
lucastononro Jul 20, 2026
ed82a07
fix(review): address Greptile findings on #141
lucastononro Jul 20, 2026
029859c
fix(review): address Greptile findings on #144
lucastononro Jul 20, 2026
3f336df
fix(review): address Greptile findings on #140
lucastononro Jul 20, 2026
39929e6
fix(review): address Greptile findings on #142
lucastononro Jul 20, 2026
8391323
fix(review): address Greptile findings on #147
lucastononro Jul 20, 2026
6f9e2a8
fix(review): address Greptile findings on #143
lucastononro Jul 20, 2026
b37907e
fix(review): address Greptile findings on #150
lucastononro Jul 20, 2026
05cb539
fix(review): address Greptile findings on #152
lucastononro Jul 20, 2026
382db8f
fix(review): address Greptile findings on #151
lucastononro Jul 20, 2026
3f73570
fix(review): address Greptile findings on #148
lucastononro Jul 20, 2026
cd58511
fix(review): address Greptile findings on #149
lucastononro Jul 20, 2026
7dfaf43
fix(review): address Greptile findings on #153
lucastononro Jul 20, 2026
67017cc
fix(review): address Greptile findings on #158
lucastononro Jul 20, 2026
4a0ca9b
fix(review): address Greptile findings on #156
lucastononro Jul 20, 2026
11a197e
fix(review): address Greptile findings on #159
lucastononro Jul 20, 2026
c8a1bba
fix(review): address Greptile findings on #157
lucastononro Jul 20, 2026
befc75f
fix(review): address Greptile findings on #155
lucastononro Jul 20, 2026
de197b8
fix(review): address Greptile findings on #154
lucastononro Jul 20, 2026
a86a93f
fix(review): address Greptile findings on #161
lucastononro Jul 20, 2026
09a7284
fix(review): address Greptile findings on #163
lucastononro Jul 20, 2026
b4aaeaf
fix(review): address Greptile findings on #166
lucastononro Jul 20, 2026
c57f596
fix(review): address Greptile findings on #162
lucastononro Jul 20, 2026
4e5a0ed
fix(review): address Greptile findings on #164
lucastononro Jul 20, 2026
1bfed27
fix(review): address Greptile findings on #165
lucastononro Jul 20, 2026
7f6394e
chore(staging): open staging-v0.0.5 merge ledger
lucastononro Jul 29, 2026
4b970ca
merge(pr-132): docs: fix broken issue-tracker link
lucastononro Jul 29, 2026
7c7ed13
merge(pr-129): docs(cli): update stale README for v0.0.4 multi-provid…
lucastononro Jul 29, 2026
69ce961
merge(pr-137): chore(lint): add explicit ruff config in backend/pypro…
lucastononro Jul 29, 2026
8476718
merge(pr-135): chore(dev): add .pre-commit-config.yaml matching CONTR…
lucastononro Jul 29, 2026
a18cd6e
fix(review): address Greptile findings on #167
lucastononro Jul 29, 2026
5775313
merge(pr-167): docs(design): multi-user auth + ownership design note
lucastononro Jul 29, 2026
fe73312
chore(staging): ledger — wave 1 (pr 132, 129, 137, 135, 167)
lucastononro Jul 29, 2026
24f1900
fix(review): address Greptile P1 on #151 — await task after wait_for …
lucastononro Jul 29, 2026
c91b669
merge(pr-151): fix(backend): capture unhandled + background-task erro…
lucastononro Jul 29, 2026
453e978
merge(pr-155): test(backend): cover agent orchestration + sandbox lif…
lucastononro Jul 29, 2026
cb817e8
merge(pr-139): perf(backend): offload DuckDB/pandas work off the even…
lucastononro Jul 29, 2026
8155755
merge(pr-134): fix(cli): chmod 0600 the generated ~/.trainable/.env s…
lucastononro Jul 29, 2026
3280854
merge(pr-136): fix(compose): require operator secrets + stop publicly…
lucastononro Jul 29, 2026
1308ba3
merge(pr-142): fix(backend): enforce wall-clock timeout on provider L…
lucastononro Jul 29, 2026
a34f34f
chore(staging): ledger — wave 2 (pr 151, 155, 139, 134, 136, 142)
lucastononro Jul 29, 2026
aa06255
merge(pr-133): fix(frontend): use relative /api URLs, drop hardcoded …
lucastononro Jul 29, 2026
a565010
merge(pr-138): opt-in bearer-token auth for /api/* via API_AUTH_TOKEN…
lucastononro Jul 29, 2026
2c384da
merge(pr-140): restrict CORS — configurable origins, never wildcard+c…
lucastononro Jul 29, 2026
d415817
merge(pr-144): real readiness probe /api/readyz + compose healthcheck…
lucastononro Jul 29, 2026
c793d77
chore(staging): ledger — wave 3 (pr 133, 138, 140, 144)
lucastononro Jul 29, 2026
6684446
merge(pr-141): bound /api/s3/upload memory + validate bucket/key targ…
lucastononro Jul 29, 2026
f2c3c0f
merge staging-v0.0.5 into fix/92-offload-boto3
lucastononro Jul 29, 2026
c81651e
merge(pr-143): offload blocking boto3 S3 calls out of the async event…
lucastononro Jul 29, 2026
0bdfc38
Merge branch 'staging-v0.0.5' into fix/94-upload-memory
lucastononro Jul 29, 2026
2198d27
fix(review): stream attach_data file uploads through temp files
lucastononro Jul 29, 2026
b25d8db
merge(pr-147): bound memory in the multi-file experiment upload endpo…
lucastononro Jul 29, 2026
74afce1
chore(staging): ledger — wave 4 (pr 141, 143, 147)
lucastononro Jul 29, 2026
dd98199
merge: PR #149 — ci: coverage measurement + gate on backend-test (clo…
lucastononro Jul 29, 2026
57dafb8
merge: PR #154 — ci: run backend tests against Postgres (closes #117)
lucastononro Jul 29, 2026
1ba405c
merge: PR #156 — ci: advisory dependency + container image vulnerabil…
lucastononro Jul 29, 2026
7fe06d7
fix(review): batch-mode SQLite migrations + ruff format on #153
lucastononro Jul 29, 2026
29bcc0e
merge: PR #153 — refactor(db): introduce Alembic migrations (closes #…
lucastononro Jul 29, 2026
7b4b03d
chore(staging): ledger — wave 5 (pr 149, 154, 156, 153)
lucastononro Jul 29, 2026
fe831f0
merge: PR #161 — feat(frontend): comparison leaderboard UI (closes #105)
lucastononro Jul 29, 2026
3f9a7ee
style: prettier format frontend/src/components/experiments/SnapshotRe…
lucastononro Jul 29, 2026
3abe262
merge: PR #162 — feat: "Reproduce" action — replay a snapshot and dif…
lucastononro Jul 29, 2026
e59549a
style: prettier format frontend/src/app/models/page.tsx
lucastononro Jul 29, 2026
a479866
merge: PR #163 — feat: in-app prediction playground for deployed mode…
lucastononro Jul 29, 2026
102e88d
fix(review): address Greptile findings on #168 + prettier format
lucastononro Jul 29, 2026
a38d930
merge: PR #168 — feat(data): raw dataset preview + quick-profile on u…
lucastononro Jul 29, 2026
719088a
fix(review): address Greptile findings on #169 + format fixes
lucastononro Jul 29, 2026
c4176cf
merge: PR #169 — feat: sample datasets gallery + guided first-run (cl…
lucastononro Jul 29, 2026
23d54e1
chore(staging): ledger — wave 6 (pr 161, 162, 163, 168, 169)
lucastononro Jul 29, 2026
565ec01
merge: PR #164 — feat(training): pre-flight training controls — metri…
lucastononro Jul 29, 2026
712e37f
Merge branch 'staging-v0.0.5' into fix/107-cost-budget
lucastononro Jul 29, 2026
f045d4a
merge: PR #165 — feat(budget): per-project cost budgets with hard-sto…
lucastononro Jul 29, 2026
1f6ad6d
fix(review): materialize y_true/y_pred once in log_confusion_matrix (…
lucastononro Jul 29, 2026
f80d7f4
style: f-strings in trainable_runtime (ruff UP031, pinned config)
lucastononro Jul 29, 2026
2f0ba6d
merge: PR #87 — feat(download): bulk workspace export — session + pro…
lucastononro Jul 29, 2026
f313653
chore: drop accidentally committed node_modules symlink
lucastononro Jul 29, 2026
582c078
merge: PR #87 follow-up — drop accidentally committed node_modules sy…
lucastononro Jul 29, 2026
34c91bf
chore(staging): ledger — wave 7 (pr 164, 165, 87)
lucastononro Jul 29, 2026
cfbfb40
fix(review): isolate SSE bus listener failures (Greptile P1 on #148)
lucastononro Jul 29, 2026
8f74aab
merge: staging-v0.0.5 into fix/100-dedupe-eventsource (repair #148)
lucastononro Jul 29, 2026
aceebec
merge: PR #148 — dedupe EventSource, share one session SSE stream via…
lucastononro Jul 29, 2026
3e48748
Merge branch 'staging-v0.0.5' into fix/98-memoize-chat
lucastononro Jul 29, 2026
4a4fbc9
chore(staging): ledger row — PR #148
lucastononro Jul 29, 2026
449260b
merge: PR #150 — memoize chat items, stop re-parsing markdown per tok…
lucastononro Jul 29, 2026
caf4423
chore(staging): ledger row — PR #150
lucastononro Jul 29, 2026
8ca8e96
merge: staging-v0.0.5 into fix/99-autoscroll (repair #152)
lucastononro Jul 29, 2026
73c9b25
merge: PR #152 — stop auto-scroll hijacking scrollback during streami…
lucastononro Jul 29, 2026
1db97bc
chore(staging): ledger row — PR #152
lucastononro Jul 29, 2026
ba33265
merge: staging-v0.0.5 into fix/101-typed-sse (repair #157)
lucastononro Jul 29, 2026
9a1681e
merge: PR #157 — type the SSE event layer with a discriminated union …
lucastononro Jul 29, 2026
6ec0868
chore(staging): ledger row — PR #157
lucastononro Jul 29, 2026
a71d33e
fix(review): key FileViewer's markdown ErrorBoundary by filePath (Gre…
lucastononro Jul 29, 2026
e21700b
style: prettier --write page.tsx (branch predates CI format gate)
lucastononro Jul 29, 2026
f55645b
merge: staging-v0.0.5 into fix/102-error-boundary (repair #159)
lucastononro Jul 29, 2026
41a56a2
merge: PR #159 — error boundaries so one render throw doesn't blank t…
lucastononro Jul 29, 2026
6cae3ea
chore(staging): ledger row — PR #159
lucastononro Jul 29, 2026
3466c5a
merge: staging-v0.0.5 into fix/114-frontend-tests (repair #158)
lucastononro Jul 29, 2026
8283171
merge: PR #158 — frontend Vitest suite + frontend-test CI job (closes…
lucastononro Jul 29, 2026
9238629
chore(staging): ledger — wave 8 (pr 148, 150, 152, 157, 159, 158)
lucastononro Jul 29, 2026
84a6dbb
Merge branch 'staging-v0.0.5' into fix/97-split-page-tsx
lucastononro Jul 29, 2026
f79bfd8
merge: PR #166 — split the page.tsx monolith into useSessionStream + …
lucastononro Jul 29, 2026
d71d0af
fix(review): address Greptile findings on #170
lucastononro Jul 29, 2026
da2430e
Merge branch 'staging-v0.0.5' into fix/106-resume-sessions
lucastononro Jul 29, 2026
07b0296
merge: PR #170 — resume / re-run for aborted and failed sessions (clo…
lucastononro Jul 29, 2026
6454aee
fix(review): address Greptile findings on #171
lucastononro Jul 29, 2026
4275527
fix(review): address Greptile findings on #172
lucastononro Jul 29, 2026
ae6f1f8
Merge branch 'staging-v0.0.5' into fix/108-hitl-approvals
lucastononro Jul 29, 2026
5f613ac
merge: PR #171 — human-in-the-loop approval checkpoints before expens…
lucastononro Jul 29, 2026
27b8959
Merge branch 'staging-v0.0.5' into fix/111-eda-action-cards
lucastononro Jul 29, 2026
12ceb7c
merge: PR #172 — EDA findings → one-click-to-prep action cards (close…
lucastononro Jul 29, 2026
58bf5c0
chore(staging): ledger — wave 9 (pr 166, 170, 171, 172)
lucastononro Jul 29, 2026
4b03bf1
fix(compute): RunPod review follow-ups — bootstrap deadlock, ARG_MAX,…
lucastononro Jul 29, 2026
ea777f4
Merge branch 'staging-v0.0.5' into feat/runpod-provider
lucastononro Jul 29, 2026
d6c4bc9
merge: PR #145 — RunPod as an alternative compute provider to Modal (…
lucastononro Jul 29, 2026
7175a56
fix(agent): gpu-choice review follow-ups — tool event order, owner ti…
lucastononro Jul 29, 2026
f7b9287
Merge branch 'staging-v0.0.5' into feat/agent-gpu-choice
lucastononro Jul 29, 2026
b5e30c9
merge: PR #160 — agent-selectable GPU/CPU per execute-code call with …
lucastononro Jul 29, 2026
3b55528
chore(staging): ledger — wave 10 (pr 145, 160)
lucastononro Jul 29, 2026
5df3251
Merge branch 'staging-v0.0.5' into dependabot/pip/backend/python-mult…
lucastononro Jul 29, 2026
d46aa13
Merge branch 'dependabot/pip/backend/python-multipart-0.0.26' into st…
lucastononro Jul 29, 2026
3a1eea2
Merge branch 'staging-v0.0.5' into dependabot/pip/backend/fastapi-0.1…
lucastononro Jul 29, 2026
45b3464
Merge branch 'dependabot/pip/backend/fastapi-0.136.0' into staging-v0…
lucastononro Jul 29, 2026
f2c1ddb
Merge branch 'staging-v0.0.5' into dependabot/pip/backend/sqlalchemy-…
lucastononro Jul 29, 2026
635dea3
Merge branch 'dependabot/pip/backend/sqlalchemy-2.0.49' into staging-…
lucastononro Jul 29, 2026
492929a
Merge branch 'staging-v0.0.5' into dependabot/pip/backend/sse-starlet…
lucastononro Jul 29, 2026
c295124
Merge branch 'dependabot/pip/backend/sse-starlette-3.3.4' into stagin…
lucastononro Jul 29, 2026
580ddbf
Merge branch 'staging-v0.0.5' into dependabot/npm_and_yarn/frontend/p…
lucastononro Jul 29, 2026
b759478
Merge branch 'dependabot/npm_and_yarn/frontend/postcss-8.5.12' into s…
lucastononro Jul 29, 2026
f7156f4
Merge branch 'staging-v0.0.5' into dependabot/npm_and_yarn/frontend/r…
lucastononro Jul 29, 2026
b99b052
Merge branch 'dependabot/npm_and_yarn/frontend/react-syntax-highlight…
lucastononro Jul 29, 2026
9dff46e
Merge branch 'staging-v0.0.5' into dependabot/npm_and_yarn/frontend/r…
lucastononro Jul 29, 2026
5ebd907
Merge branch 'dependabot/npm_and_yarn/frontend/react-markdown-10.1.0'…
lucastononro Jul 29, 2026
e106c70
chore(staging): ledger — wave 11 (dependabot)
lucastononro Jul 29, 2026
3f33992
Merge pull request #11: bump python-dotenv 1.0.1 -> 1.2.2 in /backend
lucastononro Jul 29, 2026
9b48f16
Merge pull request #12: bump prettier 3.8.1 -> 3.8.3 in /frontend
lucastononro Jul 29, 2026
f9dbc7f
Merge pull request #7: bump docker/login-action 3 -> 4
lucastononro Jul 29, 2026
40acde7
Merge pull request #8: bump actions/download-artifact 4 -> 8
lucastononro Jul 29, 2026
e45791e
Merge pull request #9: bump docker/setup-buildx-action 3 -> 4
lucastononro Jul 29, 2026
d40ebc2
Merge pull request #10: bump docker/build-push-action 5 -> 7
lucastononro Jul 29, 2026
fabaadd
Merge pull request #24: bump react-resizable-panels 2.1.9 -> 4.11.0 i…
lucastononro Jul 29, 2026
c08dbfc
chore(staging): ledger — wave 12 (remaining prs)
lucastononro Jul 29, 2026
5548e87
feat(backend): hashed requirements.lock for reproducible builds (clos…
lucastononro Jul 29, 2026
db11781
merge: hashed backend requirements.lock for reproducible builds (clos…
lucastononro Jul 29, 2026
006f1c9
feat(cli): docker daemon preflight + status/logs/--version (closes #126)
lucastononro Jul 29, 2026
f3cfde6
merge: CLI docker preflight + status/logs/--version (closes #126)
lucastononro Jul 29, 2026
1714037
style(cli): ruff format (0.15.22) on the #126 files
lucastononro Jul 29, 2026
b0deab9
chore(staging): ledger — wave 13 (issues 128, 126)
lucastononro Jul 29, 2026
1038059
feat(backend): split file authoring from code execution — write-file …
lucastononro Jul 29, 2026
bc45dff
merge: file-authoring skills — write/edit/run-file + notebook cell ed…
lucastononro Jul 29, 2026
531a3c6
chore(staging): ledger — wave 14 (issue 85)
lucastononro Jul 29, 2026
6e24afd
docs(agents): merge-to-staging-always rule in the PR workflow
lucastononro Jul 29, 2026
8977c33
chore: move integration branch staging-v0.0.5 -> release/v0.0.5
lucastononro Jul 30, 2026
c36d345
docs(release): v0.0.5 changelog + evidence review
lucastononro Jul 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 88 additions & 8 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,41 @@


# ============================================================
# Sandbox compute (Modal) — REQUIRED for any agent that runs code
# Sandbox compute — REQUIRED for any agent that runs code
# ============================================================
# Modal powers `execute_code` (the data-science sandbox). Without
# these the agent can still chat but can't run notebooks/scripts.
# Get them from https://modal.com/settings/tokens — click
# The compute provider powers `execute_code` (the data-science
# sandbox), notebook kernels and model-serving deployments. Without
# credentials the agent can still chat but can't run notebooks or
# scripts. Pick ONE provider:
# modal (default) — needs MODAL_TOKEN_*
# runpod — needs the RUNPOD_* block below
COMPUTE_PROVIDER=modal

# ---- Modal (COMPUTE_PROVIDER=modal) ------------------------
# Get tokens from https://modal.com/settings/tokens — click
# "New Token" and copy both halves.
MODAL_TOKEN_ID=ak-xxxxxxxxxxxxxxxxxxxxxx
MODAL_TOKEN_SECRET=as-xxxxxxxxxxxxxxxxxxxxxx

# ---- RunPod (COMPUTE_PROVIDER=runpod) ----------------------
# Two key pairs from https://console.runpod.io:
# API key — Settings → API Keys
# S3 API key — Settings → S3 API Keys (network-volume access)
# The datacenter hosts the network volume AND all workers; it must
# support the S3 API (e.g. US-KS-2, EU-RO-1, EU-CZ-1, EUR-IS-1).
# See docs/compute-providers.md for the full setup walkthrough
# (including publishing the worker image).
# RUNPOD_API_KEY=rpa_xxxxxxxxxxxxxxxxxxxxxx
# RUNPOD_S3_ACCESS_KEY_ID=user_xxxxxxxxxxxx
# RUNPOD_S3_SECRET_ACCESS_KEY=rps_xxxxxxxxxxxxxxxxxxxxxx
# RUNPOD_DATACENTER_ID=US-KS-2
# Auto-created on first use when unset; pin after the first run.
# RUNPOD_NETWORK_VOLUME_ID=
# RUNPOD_NETWORK_VOLUME_SIZE_GB=100
# Override to your own registry copy of docker/runpod-worker.
# RUNPOD_WORKER_IMAGE=ghcr.io/lucastononro/trainable-runpod-worker:latest
# RUNPOD_MAX_WORKERS=3


# ============================================================
# LLM provider auth — pick at least one
Expand Down Expand Up @@ -80,6 +106,35 @@ CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-xxxxxxxxxxxx
# BACKEND_PORT=8001


# ============================================================
# Optional — security
# ============================================================
# Opt-in bearer-token auth for the API. Unset (default) = every
# endpoint stays open, exactly as before — fine for localhost dev.
# When set, all /api/* requests must send
# Authorization: Bearer <token>
# Exempt: /api/health, /api/readyz, and CORS preflight. The SSE
# stream endpoint (/api/sessions/<id>/stream) also accepts
# ?token=<token>, since the browser EventSource API cannot send
# an Authorization header. Set this whenever the backend is
# exposed beyond localhost (e.g. docker-compose.prod.yml).
#
# NOTE: ?token= is part of the URL, so uvicorn/nginx/proxy access
# logs record it verbatim. If the stream endpoint is used behind
# such a component, redact the token query parameter from access
# logs (custom uvicorn access-log format, nginx log masking) or
# restrict log access.
# API_AUTH_TOKEN=change-me-to-a-long-random-string

# Allowed browser origins for CORS, comma-separated. Defaults to
# the local frontend (http://localhost:3000, http://127.0.0.1:3000).
# The frontend normally proxies /api through Next.js (same-origin),
# so you only need this when a browser calls the backend origin
# directly. A `*` entry is honored but credentials are then
# disabled — never both.
# CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000


# ============================================================
# Optional — observability
# ============================================================
Expand All @@ -94,11 +149,36 @@ CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-xxxxxxxxxxxx
# SENTRY_ENVIRONMENT=local


# ============================================================
# Datastore secrets — REQUIRED by docker-compose.prod.yml
# ============================================================
# Prod has NO built-in defaults: docker-compose.prod.yml fails fast
# (`config`/`up` errors out) if any of these are unset. The backend's
# DATABASE_URL and AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY are derived
# from these values, so the app credentials always match the datastores.
# Replace the placeholders below with strong, unique secrets.
#
# Postgres superuser/database (postgres service + backend DATABASE_URL):
POSTGRES_USER=trainable
POSTGRES_PASSWORD=change-me-strong-db-password
POSTGRES_DB=trainable
#
# MinIO root credentials (minio service + backend AWS_ACCESS_KEY_ID/SECRET):
MINIO_ROOT_USER=change-me-minio-user
MINIO_ROOT_PASSWORD=change-me-strong-minio-password
#
# Container image tags for the prebuilt prod images (default: latest):
# TRAINABLE_BACKEND_TAG=latest
# TRAINABLE_FRONTEND_TAG=latest


# ============================================================
# Advanced — overridden by docker-compose.prod.yml
# ============================================================
# Don't set these unless you're running outside docker-compose.
# DATABASE_URL=postgresql+asyncpg://trainable:trainable@postgres:5432/trainable
# docker-compose.prod.yml sets these for the backend container from the
# datastore secrets above; only set them by hand when running the
# backend OUTSIDE docker-compose (docker-compose.yml uses fixed dev creds).
# DATABASE_URL=postgresql+asyncpg://<POSTGRES_USER>:<POSTGRES_PASSWORD>@postgres:5432/<POSTGRES_DB>
# S3_ENDPOINT=http://minio:9000
# AWS_ACCESS_KEY_ID=minioadmin
# AWS_SECRET_ACCESS_KEY=minioadmin
# AWS_ACCESS_KEY_ID=<same as MINIO_ROOT_USER>
# AWS_SECRET_ACCESS_KEY=<same as MINIO_ROOT_PASSWORD>
153 changes: 151 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ jobs:
with:
python-version: "3.11"
cache: pip
- run: pip install ruff
# Keep in sync with the ruff-pre-commit rev in .pre-commit-config.yaml.
- run: pip install "ruff==0.15.22"
- run: ruff check .
- run: ruff format --check .

Expand All @@ -33,13 +34,59 @@ jobs:
defaults:
run:
working-directory: backend
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: trainable_test
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 5s
--health-timeout 5s
--health-retries 10
env:
TEST_DATABASE_URL: postgresql+asyncpg://postgres:postgres@localhost:5432/trainable_test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
- run: pip install -r requirements.txt
# Install from the hashed lockfile so CI resolves exactly what ships
# in the Docker image (#128). requirements.txt stays the edited input.
- run: pip install --require-hashes -r requirements.lock
# Coverage is scoped to production code: backend/.coveragerc omits
# tests/ so the gate reflects untested application code (with tests
# included the total was ~66%; production-only it is ~51%).
- run: |
pytest tests/ -v --tb=short \
--cov=. \
--cov-report=xml \
--cov-report=term-missing \
--cov-fail-under=50
- uses: actions/upload-artifact@v4
if: always()
with:
name: backend-coverage
path: backend/coverage.xml

cli-test:
name: CLI Tests
runs-on: ubuntu-latest
defaults:
run:
working-directory: cli
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
- run: pip install pytest .
- run: pytest tests/ -v --tb=short

backend-security:
Expand All @@ -58,6 +105,91 @@ jobs:
- run: bandit -r . -x ./tests --severity-level medium -f json -o bandit-report.json || true
- run: bandit -r . -x ./tests --severity-level high

backend-vuln-scan:
name: Backend Dependency Vulnerability Scan (advisory)
runs-on: ubuntu-latest
defaults:
run:
working-directory: backend
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
# Match backend/Dockerfile (python:3.13-slim) so the audited
# dependency resolution mirrors what actually ships.
python-version: "3.13"
cache: pip
# Install from the hashed lockfile (#128) so the audit covers exactly
# what ships in the Docker image; pip-audit itself is installed
# separately (it isn't part of the locked application tree).
- run: |
pip install --require-hashes -r requirements.lock
pip install pip-audit
# Advisory only: known advisories (e.g. transitive starlette/mcp/
# python-multipart CVEs) already exist in the dependency tree today,
# and shouldn't block CI. Flip this to blocking (drop
# continue-on-error) once those are triaged and cleared.
- name: pip-audit
run: pip-audit
continue-on-error: true

frontend-vuln-scan:
name: Frontend Dependency Vulnerability Scan (advisory)
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
cache-dependency-path: frontend/package-lock.json
- run: npm ci
# Advisory only: known advisories (next/glob/prismjs/postcss/js-yaml)
# already exist in the dependency tree today, and shouldn't block CI.
# Flip this to blocking (drop continue-on-error) once those are
# triaged and cleared.
- name: npm audit
run: npm audit
continue-on-error: true

image-scan:
name: Container Image Vulnerability Scan (advisory)
runs-on: ubuntu-latest
strategy:
matrix:
include:
- image: trainable-backend
context: ./backend
- image: trainable-frontend
context: ./frontend
target: runner
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v4
- name: Build ${{ matrix.image }} image (local only, not pushed)
uses: docker/build-push-action@v7
with:
context: ${{ matrix.context }}
target: ${{ matrix.target || '' }}
push: false
load: true
tags: ${{ matrix.image }}:ci-scan
# Advisory only: base-image and OS-package advisories aren't triaged
# yet and shouldn't block CI. Flip to blocking (drop
# continue-on-error, or set exit-code back to 1 without the wrapper)
# once they are.
- name: Trivy scan
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
continue-on-error: true
with:
image-ref: ${{ matrix.image }}:ci-scan
format: table
severity: "CRITICAL,HIGH"
exit-code: "1"

frontend-lint:
name: Frontend Lint & Typecheck
runs-on: ubuntu-latest
Expand All @@ -75,6 +207,23 @@ jobs:
- run: npx next lint
- run: npx tsc --noEmit
- run: npx prettier --check 'src/**/*.{ts,tsx,css}'
- run: npm test

frontend-test:
name: Frontend Tests
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
cache-dependency-path: frontend/package-lock.json
- run: npm ci
- run: npm test

frontend-build:
name: Frontend Build
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/publish-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: docker/login-action@v3
- uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
Expand All @@ -43,9 +43,9 @@ jobs:

- uses: docker/setup-qemu-action@v3

- uses: docker/setup-buildx-action@v3
- uses: docker/setup-buildx-action@v4

- uses: docker/build-push-action@v5
- uses: docker/build-push-action@v7
with:
context: ${{ matrix.context }}
target: ${{ matrix.target || '' }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
working-directory: cli
run: python -m build

- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: dist
path: cli/dist/
Expand All @@ -33,7 +33,7 @@ jobs:
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v8
with:
name: dist
path: dist/
Expand Down
32 changes: 32 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Pre-commit hooks for Trainable. See CONTRIBUTING.md.
# Install: pip install pre-commit && pre-commit install
# Run manually: pre-commit run --all-files
# Generated / vendored artifacts: not hand-edited, so keep the hooks off them.
exclude: |
(?x)^(
package-lock\.json|
frontend/package-lock\.json|
frontend/tsconfig\.tsbuildinfo|
.*\.excalidraw|
sample-data/.*
)$

repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Keep in sync with the pinned ruff version in .github/workflows/ci.yml.
rev: v0.15.22
hooks:
# Lint (with autofix) the backend Python code using backend/pyproject.toml.
- id: ruff
args: [--fix]
files: ^backend/
# Format the backend Python code.
- id: ruff-format
files: ^backend/

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: detect-private-key
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ frontend (Next.js) ─ SSE ─► backend (FastAPI) ──► Modal sandboxe

## How to contribute (PR workflow)

1. **Branch from `main`** (or the current release branch if a release is in flight). Branch name uses `feat/`, `fix/`, `refactor/`, `docs/`, `test/`, `ci/` prefixes.
0. **Merge to the integration branch, always.** Integration happens on the current release/integration branch (`release/v0.0.5`), never directly on `main`. Branch from it, open PRs with it as base, and record each merge in the ledger (`STAGING-v0.0.5.md` on that branch) so the consolidation stays backtrackable. `main` only moves when the integration branch is promoted as a release.
1. **Branch from the integration branch** (per rule 0). Branch name uses `feat/`, `fix/`, `refactor/`, `docs/`, `test/`, `ci/` prefixes.
2. **Open an issue first** for anything beyond a small fix. The issue is where scope gets pinned; the PR is where code lands. We've burned weeks on PRs whose scope drifted because no issue anchored it.
3. **Keep PRs reviewable.** Soft cap: <500 lines diff, single concern. If you're at 1000+ lines or touching unrelated areas, split.
4. **Commit message uses conventional commits** (`feat:`, `fix:`, `refactor:`, etc.). The body explains the *why*, not the *what*.
Expand Down
Loading
Loading