treadstone 0.1.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 (236) hide show
  1. treadstone-0.1.1/.agents/skills/database-migration/SKILL.md +211 -0
  2. treadstone-0.1.1/.agents/skills/dev-lifecycle/SKILL.md +113 -0
  3. treadstone-0.1.1/.agents/skills/dev-setup/SKILL.md +102 -0
  4. treadstone-0.1.1/.agents/skills/neon-postgres/SKILL.md +186 -0
  5. treadstone-0.1.1/.env.example +36 -0
  6. treadstone-0.1.1/.githooks/pre-commit +22 -0
  7. treadstone-0.1.1/.githooks/pre-push +17 -0
  8. treadstone-0.1.1/.github/workflows/cd.yml +57 -0
  9. treadstone-0.1.1/.github/workflows/ci.yml +59 -0
  10. treadstone-0.1.1/.github/workflows/project.yml +16 -0
  11. treadstone-0.1.1/.github/workflows/release.yml +226 -0
  12. treadstone-0.1.1/.gitignore +34 -0
  13. treadstone-0.1.1/.python-version +1 -0
  14. treadstone-0.1.1/AGENTS.md +128 -0
  15. treadstone-0.1.1/Dockerfile +16 -0
  16. treadstone-0.1.1/LICENSE +199 -0
  17. treadstone-0.1.1/Makefile +166 -0
  18. treadstone-0.1.1/PKG-INFO +199 -0
  19. treadstone-0.1.1/README.md +178 -0
  20. treadstone-0.1.1/alembic/README +1 -0
  21. treadstone-0.1.1/alembic/env.py +74 -0
  22. treadstone-0.1.1/alembic/script.py.mako +28 -0
  23. treadstone-0.1.1/alembic/versions/0049d56201ad_add_k8s_claim_name_and_make_image_.py +40 -0
  24. treadstone-0.1.1/alembic/versions/7d32ba24d363_add_sandbox_table.py +60 -0
  25. treadstone-0.1.1/alembic/versions/a30f8dfeb16e_add_user_oauth_account_invitation_api_.py +93 -0
  26. treadstone-0.1.1/alembic/versions/a54ae0733978_rename_k8s_claim_name_to_k8s_sandbox_.py +32 -0
  27. treadstone-0.1.1/alembic/versions/bc37bfeef9ac_add_provision_mode_persist_storage_size_.py +36 -0
  28. treadstone-0.1.1/alembic.ini +149 -0
  29. treadstone-0.1.1/deploy/README.md +251 -0
  30. treadstone-0.1.1/deploy/agent-sandbox/Chart.yaml +6 -0
  31. treadstone-0.1.1/deploy/agent-sandbox/README.md +39 -0
  32. treadstone-0.1.1/deploy/agent-sandbox/templates/_helpers.tpl +16 -0
  33. treadstone-0.1.1/deploy/agent-sandbox/templates/upstream-resources.yaml +15 -0
  34. treadstone-0.1.1/deploy/agent-sandbox/upstream/VERSION +1 -0
  35. treadstone-0.1.1/deploy/agent-sandbox/upstream/extensions.yaml +4305 -0
  36. treadstone-0.1.1/deploy/agent-sandbox/upstream/manifest.yaml +4147 -0
  37. treadstone-0.1.1/deploy/agent-sandbox/values-demo.yaml +13 -0
  38. treadstone-0.1.1/deploy/agent-sandbox/values-local.yaml +13 -0
  39. treadstone-0.1.1/deploy/agent-sandbox/values-prod.yaml +13 -0
  40. treadstone-0.1.1/deploy/agent-sandbox/values.yaml +13 -0
  41. treadstone-0.1.1/deploy/kind/kind-config.yaml +20 -0
  42. treadstone-0.1.1/deploy/sandbox-runtime/Chart.yaml +6 -0
  43. treadstone-0.1.1/deploy/sandbox-runtime/templates/_helpers.tpl +14 -0
  44. treadstone-0.1.1/deploy/sandbox-runtime/templates/sandbox-templates.yaml +39 -0
  45. treadstone-0.1.1/deploy/sandbox-runtime/templates/sandbox-warmpool.yaml +16 -0
  46. treadstone-0.1.1/deploy/sandbox-runtime/values-demo.yaml +38 -0
  47. treadstone-0.1.1/deploy/sandbox-runtime/values-local.yaml +38 -0
  48. treadstone-0.1.1/deploy/sandbox-runtime/values-prod.yaml +38 -0
  49. treadstone-0.1.1/deploy/sandbox-runtime/values.yaml +38 -0
  50. treadstone-0.1.1/deploy/treadstone/Chart.yaml +6 -0
  51. treadstone-0.1.1/deploy/treadstone/templates/_helpers.tpl +28 -0
  52. treadstone-0.1.1/deploy/treadstone/templates/clusterrole.yaml +57 -0
  53. treadstone-0.1.1/deploy/treadstone/templates/clusterrolebinding.yaml +16 -0
  54. treadstone-0.1.1/deploy/treadstone/templates/deployment.yaml +40 -0
  55. treadstone-0.1.1/deploy/treadstone/templates/ingress.yaml +36 -0
  56. treadstone-0.1.1/deploy/treadstone/templates/migration-job.yaml +31 -0
  57. treadstone-0.1.1/deploy/treadstone/templates/service.yaml +16 -0
  58. treadstone-0.1.1/deploy/treadstone/templates/serviceaccount.yaml +9 -0
  59. treadstone-0.1.1/deploy/treadstone/values-demo.yaml +32 -0
  60. treadstone-0.1.1/deploy/treadstone/values-local.yaml +31 -0
  61. treadstone-0.1.1/deploy/treadstone/values-prod.yaml +39 -0
  62. treadstone-0.1.1/deploy/treadstone/values.yaml +44 -0
  63. treadstone-0.1.1/docs/zh-CN/design/2026-03-17-phase0-scaffolding.md +605 -0
  64. treadstone-0.1.1/docs/zh-CN/design/2026-03-17-phase1-auth.md +1130 -0
  65. treadstone-0.1.1/docs/zh-CN/design/2026-03-17-phase2-sandbox-orchestration.md +799 -0
  66. treadstone-0.1.1/docs/zh-CN/design/2026-03-17-phase3-billing.md +78 -0
  67. treadstone-0.1.1/docs/zh-CN/design/2026-03-17-phase4-marketplace.md +105 -0
  68. treadstone-0.1.1/docs/zh-CN/design/2026-03-17-treadstone-design.md +80 -0
  69. treadstone-0.1.1/docs/zh-CN/design/2026-03-17-treadstone-roadmap.md +77 -0
  70. treadstone-0.1.1/docs/zh-CN/design/2026-03-18-deployment-strategy-design.md +224 -0
  71. treadstone-0.1.1/docs/zh-CN/design/2026-03-18-testing-ci-and-make-ship.md +544 -0
  72. treadstone-0.1.1/docs/zh-CN/design/2026-03-19-phase2-sandbox-api-implementation.md +609 -0
  73. treadstone-0.1.1/docs/zh-CN/design/2026-03-21-dual-path-sandbox-design.md +147 -0
  74. treadstone-0.1.1/docs/zh-CN/design/2026-03-21-sandbox-templates-design.md +223 -0
  75. treadstone-0.1.1/docs/zh-CN/design/2026-03-22-phase3-sdk-cli.md +418 -0
  76. treadstone-0.1.1/docs/zh-CN/plans/2026-03-21-sandbox-templates-implementation.md +566 -0
  77. treadstone-0.1.1/docs/zh-CN/plans/2026-03-22-phase3-sdk-cli-implementation.md +207 -0
  78. treadstone-0.1.1/openapi-client-config.yaml +5 -0
  79. treadstone-0.1.1/pyproject.toml +60 -0
  80. treadstone-0.1.1/sandbox.md +769 -0
  81. treadstone-0.1.1/scripts/down.sh +18 -0
  82. treadstone-0.1.1/scripts/e2e-test.sh +57 -0
  83. treadstone-0.1.1/scripts/export_openapi.py +29 -0
  84. treadstone-0.1.1/scripts/kind-setup.sh +83 -0
  85. treadstone-0.1.1/scripts/up.sh +29 -0
  86. treadstone-0.1.1/sdk/python/.gitignore +23 -0
  87. treadstone-0.1.1/sdk/python/README.md +124 -0
  88. treadstone-0.1.1/sdk/python/pyproject.toml +26 -0
  89. treadstone-0.1.1/sdk/python/treadstone_sdk/__init__.py +8 -0
  90. treadstone-0.1.1/sdk/python/treadstone_sdk/api/__init__.py +1 -0
  91. treadstone-0.1.1/sdk/python/treadstone_sdk/api/auth/__init__.py +1 -0
  92. treadstone-0.1.1/sdk/python/treadstone_sdk/api/auth/auth_change_password.py +186 -0
  93. treadstone-0.1.1/sdk/python/treadstone_sdk/api/auth/auth_create_api_key.py +186 -0
  94. treadstone-0.1.1/sdk/python/treadstone_sdk/api/auth/auth_delete_api_key.py +179 -0
  95. treadstone-0.1.1/sdk/python/treadstone_sdk/api/auth/auth_delete_user.py +179 -0
  96. treadstone-0.1.1/sdk/python/treadstone_sdk/api/auth/auth_get_user.py +165 -0
  97. treadstone-0.1.1/sdk/python/treadstone_sdk/api/auth/auth_invite.py +186 -0
  98. treadstone-0.1.1/sdk/python/treadstone_sdk/api/auth/auth_list_api_keys.py +165 -0
  99. treadstone-0.1.1/sdk/python/treadstone_sdk/api/auth/auth_list_users.py +195 -0
  100. treadstone-0.1.1/sdk/python/treadstone_sdk/api/auth/auth_login.py +174 -0
  101. treadstone-0.1.1/sdk/python/treadstone_sdk/api/auth/auth_logout.py +131 -0
  102. treadstone-0.1.1/sdk/python/treadstone_sdk/api/auth/auth_register.py +166 -0
  103. treadstone-0.1.1/sdk/python/treadstone_sdk/api/config/__init__.py +1 -0
  104. treadstone-0.1.1/sdk/python/treadstone_sdk/api/config/config_get_config.py +123 -0
  105. treadstone-0.1.1/sdk/python/treadstone_sdk/api/sandbox_templates/__init__.py +1 -0
  106. treadstone-0.1.1/sdk/python/treadstone_sdk/api/sandbox_templates/sandbox_templates_list_sandbox_templates.py +165 -0
  107. treadstone-0.1.1/sdk/python/treadstone_sdk/api/sandboxes/__init__.py +1 -0
  108. treadstone-0.1.1/sdk/python/treadstone_sdk/api/sandboxes/sandboxes_create_sandbox.py +186 -0
  109. treadstone-0.1.1/sdk/python/treadstone_sdk/api/sandboxes/sandboxes_create_sandbox_token_endpoint.py +202 -0
  110. treadstone-0.1.1/sdk/python/treadstone_sdk/api/sandboxes/sandboxes_delete_sandbox.py +179 -0
  111. treadstone-0.1.1/sdk/python/treadstone_sdk/api/sandboxes/sandboxes_get_sandbox.py +181 -0
  112. treadstone-0.1.1/sdk/python/treadstone_sdk/api/sandboxes/sandboxes_list_sandboxes.py +214 -0
  113. treadstone-0.1.1/sdk/python/treadstone_sdk/api/sandboxes/sandboxes_start_sandbox.py +181 -0
  114. treadstone-0.1.1/sdk/python/treadstone_sdk/api/sandboxes/sandboxes_stop_sandbox.py +181 -0
  115. treadstone-0.1.1/sdk/python/treadstone_sdk/api/system/__init__.py +1 -0
  116. treadstone-0.1.1/sdk/python/treadstone_sdk/api/system/system_health.py +123 -0
  117. treadstone-0.1.1/sdk/python/treadstone_sdk/client.py +268 -0
  118. treadstone-0.1.1/sdk/python/treadstone_sdk/errors.py +16 -0
  119. treadstone-0.1.1/sdk/python/treadstone_sdk/models/__init__.py +79 -0
  120. treadstone-0.1.1/sdk/python/treadstone_sdk/models/api_key_list_response.py +75 -0
  121. treadstone-0.1.1/sdk/python/treadstone_sdk/models/api_key_response.py +119 -0
  122. treadstone-0.1.1/sdk/python/treadstone_sdk/models/api_key_summary.py +119 -0
  123. treadstone-0.1.1/sdk/python/treadstone_sdk/models/auth_0_config.py +69 -0
  124. treadstone-0.1.1/sdk/python/treadstone_sdk/models/auth_config.py +175 -0
  125. treadstone-0.1.1/sdk/python/treadstone_sdk/models/authing_config.py +69 -0
  126. treadstone-0.1.1/sdk/python/treadstone_sdk/models/change_password_request.py +69 -0
  127. treadstone-0.1.1/sdk/python/treadstone_sdk/models/config_response.py +67 -0
  128. treadstone-0.1.1/sdk/python/treadstone_sdk/models/create_api_key_request.py +81 -0
  129. treadstone-0.1.1/sdk/python/treadstone_sdk/models/create_sandbox_request.py +143 -0
  130. treadstone-0.1.1/sdk/python/treadstone_sdk/models/create_sandbox_request_labels.py +46 -0
  131. treadstone-0.1.1/sdk/python/treadstone_sdk/models/create_sandbox_token_request.py +61 -0
  132. treadstone-0.1.1/sdk/python/treadstone_sdk/models/health_response.py +61 -0
  133. treadstone-0.1.1/sdk/python/treadstone_sdk/models/http_validation_error.py +79 -0
  134. treadstone-0.1.1/sdk/python/treadstone_sdk/models/invite_request.py +72 -0
  135. treadstone-0.1.1/sdk/python/treadstone_sdk/models/invite_response.py +79 -0
  136. treadstone-0.1.1/sdk/python/treadstone_sdk/models/login_request.py +69 -0
  137. treadstone-0.1.1/sdk/python/treadstone_sdk/models/login_response.py +61 -0
  138. treadstone-0.1.1/sdk/python/treadstone_sdk/models/logto_config.py +69 -0
  139. treadstone-0.1.1/sdk/python/treadstone_sdk/models/message_response.py +61 -0
  140. treadstone-0.1.1/sdk/python/treadstone_sdk/models/register_request.py +91 -0
  141. treadstone-0.1.1/sdk/python/treadstone_sdk/models/register_response.py +77 -0
  142. treadstone-0.1.1/sdk/python/treadstone_sdk/models/resource_spec.py +69 -0
  143. treadstone-0.1.1/sdk/python/treadstone_sdk/models/sandbox_detail_response.py +274 -0
  144. treadstone-0.1.1/sdk/python/treadstone_sdk/models/sandbox_detail_response_labels.py +46 -0
  145. treadstone-0.1.1/sdk/python/treadstone_sdk/models/sandbox_list_response.py +83 -0
  146. treadstone-0.1.1/sdk/python/treadstone_sdk/models/sandbox_response.py +145 -0
  147. treadstone-0.1.1/sdk/python/treadstone_sdk/models/sandbox_response_labels.py +46 -0
  148. treadstone-0.1.1/sdk/python/treadstone_sdk/models/sandbox_template_list_response.py +75 -0
  149. treadstone-0.1.1/sdk/python/treadstone_sdk/models/sandbox_template_response.py +99 -0
  150. treadstone-0.1.1/sdk/python/treadstone_sdk/models/sandbox_token_response.py +79 -0
  151. treadstone-0.1.1/sdk/python/treadstone_sdk/models/sandbox_urls.py +83 -0
  152. treadstone-0.1.1/sdk/python/treadstone_sdk/models/user_detail_response.py +107 -0
  153. treadstone-0.1.1/sdk/python/treadstone_sdk/models/user_list_response.py +83 -0
  154. treadstone-0.1.1/sdk/python/treadstone_sdk/models/user_response.py +77 -0
  155. treadstone-0.1.1/sdk/python/treadstone_sdk/models/validation_error.py +123 -0
  156. treadstone-0.1.1/sdk/python/treadstone_sdk/models/validation_error_context.py +46 -0
  157. treadstone-0.1.1/sdk/python/treadstone_sdk/py.typed +1 -0
  158. treadstone-0.1.1/sdk/python/treadstone_sdk/types.py +54 -0
  159. treadstone-0.1.1/skills-lock.json +10 -0
  160. treadstone-0.1.1/tests/__init__.py +0 -0
  161. treadstone-0.1.1/tests/api/__init__.py +0 -0
  162. treadstone-0.1.1/tests/api/test_api_key_api.py +83 -0
  163. treadstone-0.1.1/tests/api/test_auth_api.py +93 -0
  164. treadstone-0.1.1/tests/api/test_config_api.py +23 -0
  165. treadstone-0.1.1/tests/api/test_deps.py +18 -0
  166. treadstone-0.1.1/tests/api/test_health.py +10 -0
  167. treadstone-0.1.1/tests/api/test_sandbox_proxy_api.py +131 -0
  168. treadstone-0.1.1/tests/api/test_sandbox_subdomain_api.py +143 -0
  169. treadstone-0.1.1/tests/api/test_sandbox_templates_api.py +76 -0
  170. treadstone-0.1.1/tests/api/test_sandbox_token_api.py +128 -0
  171. treadstone-0.1.1/tests/api/test_sandboxes_api.py +166 -0
  172. treadstone-0.1.1/tests/conftest.py +19 -0
  173. treadstone-0.1.1/tests/e2e/01-auth-flow.hurl +47 -0
  174. treadstone-0.1.1/tests/e2e/02-api-key.hurl +57 -0
  175. treadstone-0.1.1/tests/e2e/03-sandbox-crud.hurl +91 -0
  176. treadstone-0.1.1/tests/e2e/04-password-change.hurl +46 -0
  177. treadstone-0.1.1/tests/e2e/05-sandbox-dual-path.hurl +129 -0
  178. treadstone-0.1.1/tests/integration/.env.test.example +5 -0
  179. treadstone-0.1.1/tests/integration/README.md +58 -0
  180. treadstone-0.1.1/tests/integration/__init__.py +0 -0
  181. treadstone-0.1.1/tests/integration/conftest.py +37 -0
  182. treadstone-0.1.1/tests/integration/test_auth_integration.py +152 -0
  183. treadstone-0.1.1/tests/integration/test_db.py +32 -0
  184. treadstone-0.1.1/tests/unit/__init__.py +0 -0
  185. treadstone-0.1.1/tests/unit/test_api_key_model.py +14 -0
  186. treadstone-0.1.1/tests/unit/test_config.py +33 -0
  187. treadstone-0.1.1/tests/unit/test_errors.py +50 -0
  188. treadstone-0.1.1/tests/unit/test_k8s_client.py +163 -0
  189. treadstone-0.1.1/tests/unit/test_k8s_sync.py +177 -0
  190. treadstone-0.1.1/tests/unit/test_oidc_verifier.py +24 -0
  191. treadstone-0.1.1/tests/unit/test_sandbox_model.py +81 -0
  192. treadstone-0.1.1/tests/unit/test_sandbox_proxy.py +132 -0
  193. treadstone-0.1.1/tests/unit/test_sandbox_service.py +327 -0
  194. treadstone-0.1.1/tests/unit/test_sandbox_subdomain.py +32 -0
  195. treadstone-0.1.1/tests/unit/test_sandbox_token.py +42 -0
  196. treadstone-0.1.1/tests/unit/test_user_manager.py +29 -0
  197. treadstone-0.1.1/tests/unit/test_user_model.py +55 -0
  198. treadstone-0.1.1/treadstone/__init__.py +0 -0
  199. treadstone-0.1.1/treadstone/api/__init__.py +0 -0
  200. treadstone-0.1.1/treadstone/api/auth.py +281 -0
  201. treadstone-0.1.1/treadstone/api/config.py +27 -0
  202. treadstone-0.1.1/treadstone/api/deps.py +100 -0
  203. treadstone-0.1.1/treadstone/api/sandbox_proxy.py +94 -0
  204. treadstone-0.1.1/treadstone/api/sandbox_templates.py +18 -0
  205. treadstone-0.1.1/treadstone/api/sandboxes.py +183 -0
  206. treadstone-0.1.1/treadstone/api/schemas.py +222 -0
  207. treadstone-0.1.1/treadstone/auth/__init__.py +27 -0
  208. treadstone-0.1.1/treadstone/cli/__init__.py +0 -0
  209. treadstone-0.1.1/treadstone/cli/__main__.py +6 -0
  210. treadstone-0.1.1/treadstone/cli/_client.py +56 -0
  211. treadstone-0.1.1/treadstone/cli/_output.py +52 -0
  212. treadstone-0.1.1/treadstone/cli/api_keys.py +61 -0
  213. treadstone-0.1.1/treadstone/cli/auth.py +138 -0
  214. treadstone-0.1.1/treadstone/cli/config_cmd.py +27 -0
  215. treadstone-0.1.1/treadstone/cli/main.py +58 -0
  216. treadstone-0.1.1/treadstone/cli/sandboxes.py +143 -0
  217. treadstone-0.1.1/treadstone/cli/templates.py +32 -0
  218. treadstone-0.1.1/treadstone/config.py +43 -0
  219. treadstone-0.1.1/treadstone/core/__init__.py +0 -0
  220. treadstone-0.1.1/treadstone/core/database.py +31 -0
  221. treadstone-0.1.1/treadstone/core/errors.py +120 -0
  222. treadstone-0.1.1/treadstone/core/users.py +96 -0
  223. treadstone-0.1.1/treadstone/main.py +120 -0
  224. treadstone-0.1.1/treadstone/middleware/__init__.py +0 -0
  225. treadstone-0.1.1/treadstone/middleware/sandbox_subdomain.py +142 -0
  226. treadstone-0.1.1/treadstone/models/__init__.py +5 -0
  227. treadstone-0.1.1/treadstone/models/api_key.py +24 -0
  228. treadstone-0.1.1/treadstone/models/sandbox.py +73 -0
  229. treadstone-0.1.1/treadstone/models/user.py +67 -0
  230. treadstone-0.1.1/treadstone/services/__init__.py +0 -0
  231. treadstone-0.1.1/treadstone/services/k8s_client.py +433 -0
  232. treadstone-0.1.1/treadstone/services/k8s_sync.py +254 -0
  233. treadstone-0.1.1/treadstone/services/sandbox_proxy.py +195 -0
  234. treadstone-0.1.1/treadstone/services/sandbox_service.py +272 -0
  235. treadstone-0.1.1/treadstone/services/sandbox_token.py +38 -0
  236. treadstone-0.1.1/uv.lock +2244 -0
@@ -0,0 +1,211 @@
1
+ ---
2
+ name: database-migration
3
+ description: Database model design and Alembic migration workflow for Treadstone. Use whenever adding or modifying SQLAlchemy models, generating Alembic migrations, or applying schema changes to Neon. Also use when the user mentions "migration", "add table", "add column", "schema change", "database model", or any task involving treadstone/models/.
4
+ ---
5
+
6
+ # Database Model & Migration Workflow
7
+
8
+ All schema changes flow through this pipeline — never modify a production database by hand:
9
+
10
+ ```
11
+ SQLAlchemy model → Alembic autogenerate → review migration → apply to test branch → verify → apply to production
12
+ ```
13
+
14
+ Quick reference:
15
+
16
+ ```bash
17
+ make migration MSG="add example table" # Generate migration
18
+ make migrate # Apply to DB
19
+ make downgrade # Rollback last migration
20
+ ```
21
+
22
+ ---
23
+
24
+ ## Step 1: Design the Model
25
+
26
+ Create or modify files in `treadstone/models/`.
27
+
28
+ ```
29
+ treadstone/models/
30
+ ├── __init__.py # Re-exports all models (critical for Alembic)
31
+ ├── user.py # User, OAuthAccount, Invitation
32
+ ├── api_key.py # ApiKey
33
+ └── <new_model>.py # Your new model
34
+ ```
35
+
36
+ ### Model Template
37
+
38
+ ```python
39
+ from datetime import datetime
40
+
41
+ from sqlalchemy import DateTime, ForeignKey, String
42
+ from sqlalchemy.orm import Mapped, mapped_column
43
+
44
+ from treadstone.core.database import Base
45
+ from treadstone.models.user import random_id, utc_now
46
+
47
+
48
+ class Example(Base):
49
+ __tablename__ = "example"
50
+
51
+ id: Mapped[str] = mapped_column(
52
+ String(24), primary_key=True, default=lambda: "ex" + random_id()
53
+ )
54
+ name: Mapped[str] = mapped_column(String(256), nullable=False)
55
+ owner_id: Mapped[str] = mapped_column(
56
+ String(24), ForeignKey("user.id", ondelete="cascade"), nullable=False
57
+ )
58
+ gmt_created: Mapped[datetime] = mapped_column(
59
+ DateTime(timezone=True), default=utc_now, nullable=False
60
+ )
61
+ gmt_deleted: Mapped[datetime | None] = mapped_column(
62
+ DateTime(timezone=True), nullable=True
63
+ )
64
+ ```
65
+
66
+ ### Conventions
67
+
68
+ | Convention | Rationale |
69
+ |-----------|-----------|
70
+ | `String(24)` PK with prefix (`"user"`, `"key"`, `"ex"`) | Human-readable IDs, no UUID overhead |
71
+ | `gmt_created` / `gmt_updated` / `gmt_deleted` timestamps | Consistent audit trail, soft-delete support |
72
+ | `ForeignKey(..., ondelete="cascade")` | Prevent orphan rows |
73
+ | `DateTime(timezone=True)` | Always store timezone-aware timestamps |
74
+ | `Mapped[...]` + `mapped_column()` | Modern SQLAlchemy 2.0 style with type safety |
75
+ | `StrEnum` (not `str, Enum`) | Python 3.12+ idiomatic, passes ruff UP042 |
76
+ | Soft-delete via `gmt_deleted` | Prefer soft-delete over hard-delete for important data |
77
+
78
+ ### Joined Eager Loading Gotcha
79
+
80
+ Models with `relationship(..., lazy="joined")` (e.g. `User.oauth_accounts`) require `.unique()` before extracting results, otherwise SQLAlchemy raises `InvalidRequestError`:
81
+
82
+ ```python
83
+ result = await session.execute(select(User))
84
+ users = result.unique().scalars().all() # .unique() required!
85
+ ```
86
+
87
+ ---
88
+
89
+ ## Step 2: Register the Model
90
+
91
+ Every new model **must** be imported in `treadstone/models/__init__.py`. Alembic autogenerate only detects models registered with `Base.metadata` at import time.
92
+
93
+ ```python
94
+ # treadstone/models/__init__.py
95
+ from treadstone.models.api_key import ApiKey
96
+ from treadstone.models.example import Example # <-- add
97
+ from treadstone.models.user import Invitation, OAuthAccount, Role, User
98
+
99
+ __all__ = ["User", "OAuthAccount", "Invitation", "Role", "ApiKey", "Example"]
100
+ ```
101
+
102
+ If you skip this, `alembic revision --autogenerate` generates an empty migration.
103
+
104
+ ---
105
+
106
+ ## Step 3: Write a Test for the Model
107
+
108
+ ```python
109
+ # tests/unit/test_example_model.py
110
+ from treadstone.models.example import Example
111
+
112
+ def test_example_fields_exist():
113
+ e = Example()
114
+ assert hasattr(e, "id")
115
+ assert hasattr(e, "name")
116
+ assert hasattr(e, "owner_id")
117
+ ```
118
+
119
+ ```bash
120
+ make test
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Step 4: Generate and Review the Migration
126
+
127
+ ```bash
128
+ make migration MSG="add example table"
129
+ ```
130
+
131
+ Open the generated file in `alembic/versions/` and verify:
132
+
133
+ - Correct table name and columns
134
+ - Foreign keys point to the right tables
135
+ - Indexes on frequently queried columns
136
+ - `nullable` settings match intent
137
+ - `downgrade()` correctly reverses changes
138
+ - No unintended changes to existing tables
139
+
140
+ ### Common Pitfalls
141
+
142
+ | Pitfall | Symptom | Fix |
143
+ |---------|---------|-----|
144
+ | Model not in `__init__.py` | Empty migration | Add import to `treadstone/models/__init__.py` |
145
+ | Pooled connection string | Intermittent migration errors | Use direct (non-pooled) connection for Alembic |
146
+ | `+asyncpg` in Alembic URL | `RuntimeError: cannot use async engine` | `env.py` strips it automatically — don't add it back |
147
+ | Enum value changes | Alembic doesn't detect them | Handle enum migrations manually |
148
+ | Column rename | Autogenerate sees drop + add | Write manual migration with `op.alter_column()` |
149
+
150
+ ---
151
+
152
+ ## Step 5: Apply to Neon Test Branch First
153
+
154
+ Never migrate production directly. Neon branches are instant, copy-on-write clones — use one as a staging environment.
155
+
156
+ ```
157
+ Production (main branch)
158
+ └── Test branch (fork, apply migration here first)
159
+ ```
160
+
161
+ 1. Create a test branch via Neon Console or CLI (if not already existing)
162
+ 2. Apply migration to the test branch:
163
+ ```bash
164
+ TREADSTONE_DATABASE_URL="<test-branch-url>" make migrate
165
+ ```
166
+ 3. Run integration tests:
167
+ ```bash
168
+ make test-all
169
+ ```
170
+ 4. If tests pass, apply to production:
171
+ ```bash
172
+ make migrate # with .env pointing to production
173
+ ```
174
+ 5. If tests fail, fix and retry. Use `make downgrade` or reset the branch via Neon Console.
175
+
176
+ ---
177
+
178
+ ## Step 6: Commit
179
+
180
+ Commit the model, migration file, and tests together as one logical unit:
181
+
182
+ ```bash
183
+ git add treadstone/models/ alembic/versions/ tests/
184
+ git commit -m "feat: add example model and migration"
185
+ ```
186
+
187
+ ---
188
+
189
+ ## Rollback
190
+
191
+ ```bash
192
+ make downgrade # Rollback last migration
193
+ uv run alembic downgrade -2 # Rollback 2 steps
194
+ uv run alembic downgrade base # Rollback to empty
195
+ ```
196
+
197
+ To reset a Neon test branch entirely, use the Neon Console "Reset from parent" feature.
198
+
199
+ ---
200
+
201
+ ## Checklist
202
+
203
+ - [ ] Model defined in `treadstone/models/<name>.py` with type hints
204
+ - [ ] Model imported in `treadstone/models/__init__.py`
205
+ - [ ] Unit test written and passing
206
+ - [ ] Migration generated with `make migration MSG="..."`
207
+ - [ ] Migration file reviewed manually
208
+ - [ ] Migration applied to Neon test branch
209
+ - [ ] Integration tests passing (`make test-all`)
210
+ - [ ] Migration applied to production
211
+ - [ ] Committed together: model + migration + tests
@@ -0,0 +1,113 @@
1
+ ---
2
+ name: dev-lifecycle
3
+ description: Treadstone daily development lifecycle — the step-by-step loop from creating a branch to merging a PR. Use this skill every time you develop a new feature, fix a bug, refactor code, or make any code change that will be shipped. Covers branching, TDD cycle, shipping, PR creation, CI monitoring, and merging. If the user says "add feature X", "fix bug Y", "implement Z", or anything that implies writing and shipping code, this skill applies.
4
+ ---
5
+
6
+ # Development Lifecycle
7
+
8
+ Never push directly to main. All code merges go through Pull Requests — this includes AI Agents.
9
+
10
+ ## The Loop
11
+
12
+ ```
13
+ branch → TDD (write test → fail → implement → pass → refactor) → ship → PR → CI → merge
14
+ ```
15
+
16
+ ## Step 1: Create a Feature Branch
17
+
18
+ ```bash
19
+ git checkout main && git pull
20
+ git checkout -b feat/descriptive-name
21
+ ```
22
+
23
+ Branch naming: `feat/`, `fix/`, `chore/`, `refactor/`, `docs/`, `test/`.
24
+
25
+ ## Step 2: TDD Cycle
26
+
27
+ Repeat per unit of work — keep iterations small.
28
+
29
+ 1. **Write a failing test** in the appropriate directory (`tests/unit/`, `tests/api/`, or `tests/integration/`). See the Testing section in `AGENTS.md` for which directory to use.
30
+
31
+ 2. **Confirm it fails:**
32
+ ```bash
33
+ make test
34
+ ```
35
+
36
+ 3. **Write the minimal implementation** to make the test pass — nothing more.
37
+
38
+ 4. **Confirm it passes:**
39
+ ```bash
40
+ make test
41
+ ```
42
+
43
+ 5. **Refactor** if needed, re-run `make test` to confirm nothing broke.
44
+
45
+ ## Step 3: Ship to Feature Branch
46
+
47
+ ```bash
48
+ make ship MSG="feat: add user registration endpoint"
49
+ ```
50
+
51
+ This runs `git add -A && git commit && git push` on the current feature branch.
52
+
53
+ Verify you are NOT on main before shipping: `git branch --show-current`.
54
+
55
+ Commit messages follow Conventional Commits format (`feat:`, `fix:`, `test:`, `refactor:`, `chore:`, `docs:`). Keep commits small — one logical unit each. See `AGENTS.md` Git Workflow section for full conventions.
56
+
57
+ All GitHub-visible content (commit messages, PR titles/bodies, review comments) must be in English.
58
+
59
+ ## Step 4: Create a Pull Request
60
+
61
+ ```bash
62
+ gh pr create --title "feat: add user registration" --body "$(cat <<'EOF'
63
+ ## Summary
64
+ - Implement user registration and login
65
+ - Support email/password + Cookie session
66
+
67
+ ## Test Plan
68
+ - [x] make test
69
+ - [x] make lint
70
+ EOF
71
+ )"
72
+ ```
73
+
74
+ Use HEREDOC for the body to avoid quote escaping issues.
75
+
76
+ ## Step 5: Monitor CI
77
+
78
+ ```bash
79
+ gh run watch
80
+ ```
81
+
82
+ If CI fails:
83
+
84
+ ```bash
85
+ gh run view <run-id> --log-failed # inspect failure
86
+ make test # reproduce locally
87
+ make lint # check formatting
88
+ ```
89
+
90
+ Fix, then `make ship MSG="fix: ..."` to push the fix.
91
+
92
+ ## Step 6: Merge
93
+
94
+ Once CI is green:
95
+
96
+ ```bash
97
+ gh pr merge --squash
98
+ git checkout main && git pull
99
+ ```
100
+
101
+ ## K8s Verification (When Needed)
102
+
103
+ If the change affects sandbox orchestration or deployment, verify on a local Kind cluster before merging. Follow `deploy/README.md` for the full workflow:
104
+
105
+ ```bash
106
+ make up # build + deploy to Kind
107
+ make test-e2e # run E2E tests against the cluster
108
+ make down # tear down when done
109
+ ```
110
+
111
+ ## Quick Reference
112
+
113
+ Run `make help` for the full command list.
@@ -0,0 +1,102 @@
1
+ ---
2
+ name: dev-setup
3
+ description: First-time Treadstone local development environment setup. Run once after cloning the repo and before starting any development. Covers system dependency installation, Python environment, Neon database connection, migrations, and environment verification. Use this skill when the user/agent just entered the project, needs to rebuild the environment, or encounters setup-related issues like missing dependencies, broken .env, or failed migrations.
4
+ ---
5
+
6
+ # First-Time Dev Environment Setup
7
+
8
+ Run this once. After completion, switch to the `dev-lifecycle` skill for daily development.
9
+
10
+ ## 1. System Dependencies
11
+
12
+ Verify these tools are installed:
13
+
14
+ ```bash
15
+ python3 --version # 3.12+
16
+ uv --version # Python package manager
17
+ gh --version # GitHub CLI (optional, for PR/issue ops)
18
+ docker --version # Container builds + Kind cluster
19
+ kind --version # Local K8s cluster (sandbox dev only)
20
+ kubectl version --client # K8s CLI
21
+ helm version --short # Helm chart deployment
22
+ hurl --version # E2E testing (HTTP request runner)
23
+ ```
24
+
25
+ Install missing tools (macOS):
26
+
27
+ ```bash
28
+ curl -LsSf https://astral.sh/uv/install.sh | sh
29
+ brew install kind kubectl helm hurl
30
+ ```
31
+
32
+ ## 2. Install Python Dependencies
33
+
34
+ ```bash
35
+ make install
36
+ ```
37
+
38
+ This runs `uv sync` (creates `.venv`, installs all deps) and configures git hooks.
39
+
40
+ ## 3. Configure Database (Neon)
41
+
42
+ The project uses [Neon](https://neon.tech) Serverless PostgreSQL — no local Postgres needed.
43
+
44
+ Get the connection string from https://console.neon.tech, then:
45
+
46
+ ```bash
47
+ cp .env.example .env
48
+ ```
49
+
50
+ Edit `.env` and set the connection string in asyncpg format:
51
+
52
+ ```
53
+ TREADSTONE_DATABASE_URL=postgresql+asyncpg://neondb_owner:xxx@ep-xxx.ap-southeast-1.aws.neon.tech/neondb?sslmode=require
54
+ TREADSTONE_DEBUG=true
55
+ ```
56
+
57
+ The URL scheme must be `postgresql+asyncpg://` (not `postgresql://`). Keep `?sslmode=require`.
58
+
59
+ ## 4. Apply Database Migrations
60
+
61
+ ```bash
62
+ make migrate
63
+ ```
64
+
65
+ Expected: `INFO [alembic.runtime.migration] Context impl PostgresqlImpl.` with migration details listed.
66
+
67
+ ## 5. Verify Environment
68
+
69
+ ```bash
70
+ make test
71
+ ```
72
+
73
+ Expected: all tests pass (integration tests are excluded by default). If tests pass, the environment is ready.
74
+
75
+ ## 6. Local K8s Cluster (Sandbox Development)
76
+
77
+ For sandbox-related features that require a real Kubernetes cluster, follow `deploy/README.md` — it covers Kind cluster creation, image building, Helm deployment, and smoke testing end-to-end.
78
+
79
+ Quick start:
80
+
81
+ ```bash
82
+ make up # One-command: Kind cluster + build + deploy
83
+ ```
84
+
85
+ Pure API development (`make dev`) does not require a K8s cluster.
86
+
87
+ ---
88
+
89
+ ## Troubleshooting
90
+
91
+ **`uv sync` fails:**
92
+ - Confirm Python 3.12+: `python3 --version`
93
+ - Try: `uv python install 3.12`
94
+
95
+ **Database connection fails (`could not connect`):**
96
+ - Check the connection string in `.env`
97
+ - Confirm the URL uses `postgresql+asyncpg://` not `postgresql://`
98
+ - Neon free-tier projects auto-suspend; first connection may be slow (~1s cold start)
99
+
100
+ **`alembic upgrade head` reports `authentication failed`:**
101
+ - Confirm `.env` exists in the project root
102
+ - URL-encode special characters in the password
@@ -0,0 +1,186 @@
1
+ ---
2
+ name: neon-postgres
3
+ description: Guides and best practices for working with Neon Serverless Postgres. Covers getting started, local development with Neon, choosing a connection method, Neon features, authentication (@neondatabase/auth), PostgREST-style data API (@neondatabase/neon-js), Neon CLI, and Neon's Platform API/SDKs. Use for any Neon-related questions.
4
+ ---
5
+
6
+ # Neon Serverless Postgres
7
+
8
+ Neon is a serverless Postgres platform that separates compute and storage to offer autoscaling, branching, instant restore, and scale-to-zero. It's fully compatible with Postgres and works with any language, framework, or ORM that supports Postgres.
9
+
10
+ ## Neon Documentation
11
+
12
+ The Neon documentation is the source of truth for all Neon-related information. Always verify claims against the official docs before responding. Neon features and APIs evolve, so prefer fetching current docs over relying on training data.
13
+
14
+ ### Fetching Docs as Markdown
15
+
16
+ Any Neon doc page can be fetched as markdown in two ways:
17
+
18
+ 1. **Append `.md` to the URL** (simplest): https://neon.com/docs/introduction/branching.md
19
+ 2. **Request `text/markdown`** on the standard URL: `curl -H "Accept: text/markdown" https://neon.com/docs/introduction/branching`
20
+
21
+ Both return the same markdown content. Use whichever method your tools support.
22
+
23
+ ### Finding the Right Page
24
+
25
+ The docs index lists every available page with its URL and a short description:
26
+
27
+ ```
28
+ https://neon.com/docs/llms.txt
29
+ ```
30
+
31
+ Common doc URLs are organized in the topic links below. If you need a page not listed here, search the docs index: https://neon.com/docs/llms.txt — don't guess URLs.
32
+
33
+ ## What Is Neon
34
+
35
+ Use this for architecture explanations and terminology (organizations, projects, branches, endpoints) before giving implementation advice.
36
+
37
+ Link: https://neon.com/docs/ai/skills/neon-postgres/references/what-is-neon.md
38
+
39
+ ## Getting Started
40
+
41
+ Use this for first-time setup: org/project selection, connection strings, driver installation, optional auth, and initial schema setup.
42
+
43
+ Link: https://neon.com/docs/ai/skills/neon-postgres/references/getting-started.md
44
+
45
+ ## Connection Methods & Drivers
46
+
47
+ Use this when you need to pick the correct transport and driver based on runtime constraints (TCP, HTTP, WebSocket, edge, serverless, long-running).
48
+
49
+ Link: https://neon.com/docs/ai/skills/neon-postgres/references/connection-methods.md
50
+
51
+ ### Serverless Driver
52
+
53
+ Use this for `@neondatabase/serverless` patterns, including HTTP queries, WebSocket transactions, and runtime-specific optimizations.
54
+
55
+ Link: https://neon.com/docs/ai/skills/neon-postgres/references/neon-serverless.md
56
+
57
+ ### Neon JS SDK
58
+
59
+ Use this for combined Neon Auth + Data API workflows with PostgREST-style querying and typed client setup.
60
+
61
+ Link: https://neon.com/docs/ai/skills/neon-postgres/references/neon-js.md
62
+
63
+ ## Developer Tools
64
+
65
+ Use this for local development enablement with `npx neonctl@latest init`, VSCode extension setup, and Neon MCP server configuration.
66
+
67
+ Link: https://neon.com/docs/ai/skills/neon-postgres/references/devtools.md
68
+
69
+ ### Neon CLI
70
+
71
+ Use this for terminal-first workflows, scripts, and CI/CD automation with `neonctl`.
72
+
73
+ Link: https://neon.com/docs/ai/skills/neon-postgres/references/neon-cli.md
74
+
75
+ ## Neon Admin API
76
+
77
+ The Neon Admin API can be used to manage Neon resources programmatically. It is used behind the scenes by the Neon CLI and MCP server, but can also be used directly for more complex automation workflows or when embedding Neon in other applications.
78
+
79
+ ### Neon REST API
80
+
81
+ Use this for direct HTTP automation, endpoint-level control, API key auth, rate-limit handling, and operation polling.
82
+
83
+ Link: https://neon.com/docs/ai/skills/neon-postgres/references/neon-rest-api.md
84
+
85
+ ### Neon TypeScript SDK
86
+
87
+ Use this when implementing typed programmatic control of Neon resources in TypeScript via `@neondatabase/api-client`.
88
+
89
+ Link: https://neon.com/docs/ai/skills/neon-postgres/references/neon-typescript-sdk.md
90
+
91
+ ### Neon Python SDK
92
+
93
+ Use this when implementing programmatic Neon management in Python with the `neon-api` package.
94
+
95
+ Link: https://neon.com/docs/ai/skills/neon-postgres/references/neon-python-sdk.md
96
+
97
+ ## Neon Auth
98
+
99
+ Use this for managed user authentication setup, UI components, auth methods, and Neon Auth integration pitfalls in Next.js and React apps.
100
+
101
+ Link: https://neon.com/docs/ai/skills/neon-postgres/references/neon-auth.md
102
+
103
+ Neon Auth is also embedded in the Neon JS SDK - so depending on your use case, you may want to use the Neon JS SDK instead of Neon Auth. See https://neon.com/docs/ai/skills/neon-postgres/references/connection-methods.md for more details.
104
+
105
+ ## Branching
106
+
107
+ Use this when the user is planning isolated environments, schema migration testing, preview deployments, or branch lifecycle automation.
108
+
109
+ Key points:
110
+
111
+ - Branches are instant, copy-on-write clones (no full data copy).
112
+ - Each branch has its own compute endpoint.
113
+ - Use the neonctl CLI or MCP server to create, inspect, and compare branches.
114
+
115
+ Link: https://neon.com/docs/ai/skills/neon-postgres/references/branching.md
116
+
117
+ ## Autoscaling
118
+
119
+ Use this when the user needs compute to scale automatically with workload and wants guidance on CU sizing and runtime behavior.
120
+
121
+ Link: https://neon.com/docs/introduction/autoscaling.md
122
+
123
+ ## Scale to Zero
124
+
125
+ Use this when optimizing idle costs and discussing suspend/resume behavior, including cold-start trade-offs.
126
+
127
+ Key points:
128
+
129
+ - Idle computes suspend automatically (default 5 minutes, configurable) (unless disabled - launch & scale plan only)
130
+ - First query after suspend typically has a cold-start penalty (around hundreds of ms)
131
+ - Storage remains active while compute is suspended.
132
+
133
+ Link: https://neon.com/docs/introduction/scale-to-zero.md
134
+
135
+ ## Instant Restore
136
+
137
+ Use this when the user needs point-in-time recovery or wants to restore data state without traditional backup restore workflows.
138
+
139
+ Key points:
140
+
141
+ - Restore windows depend on plan limits.
142
+ - Users can create branches from historical points-in-time.
143
+ - Time Travel queries can be used for historical inspection workflows.
144
+
145
+ Link: https://neon.com/docs/introduction/branch-restore.md
146
+
147
+ ## Read Replicas
148
+
149
+ Use this for read-heavy workloads where the user needs dedicated read-only compute without duplicating storage.
150
+
151
+ Key points:
152
+
153
+ - Replicas are read-only compute endpoints sharing the same storage.
154
+ - Creation is fast and scaling is independent from primary compute.
155
+ - Typical use cases: analytics, reporting, and read-heavy APIs.
156
+
157
+ Link: https://neon.com/docs/introduction/read-replicas.md
158
+
159
+ ## Connection Pooling
160
+
161
+ Use this when the user is in serverless or high-concurrency environments and needs safe, scalable Postgres connection management.
162
+
163
+ Key points:
164
+
165
+ - Neon pooling uses PgBouncer.
166
+ - Add `-pooler` to endpoint hostnames to use pooled connections.
167
+ - Pooling is especially important in serverless runtimes with bursty concurrency.
168
+
169
+ Link: https://neon.com/docs/connect/connection-pooling.md
170
+
171
+ ## IP Allow Lists
172
+
173
+ Use this when the user needs to restrict database access by trusted networks, IPs, or CIDR ranges.
174
+
175
+ Link: https://neon.com/docs/introduction/ip-allow.md
176
+
177
+ ## Logical Replication
178
+
179
+ Use this when integrating CDC pipelines, external Postgres sync, or replication-based data movement.
180
+
181
+ Key points:
182
+
183
+ - Neon supports native logical replication workflows.
184
+ - Useful for replicating to/from external Postgres systems.
185
+
186
+ Link: https://neon.com/docs/guides/logical-replication-guide.md
@@ -0,0 +1,36 @@
1
+ # === Database ===
2
+ # Get connection string from Neon Console: https://console.neon.tech
3
+ TREADSTONE_DATABASE_URL=postgresql+asyncpg://user:password@ep-xxx.region.aws.neon.tech/neondb?sslmode=require
4
+
5
+ # === App ===
6
+ TREADSTONE_DEBUG=false
7
+ TREADSTONE_AUTH_TYPE=cookie
8
+ TREADSTONE_REGISTER_MODE=unlimited
9
+
10
+ # === Auth Secrets ===
11
+ TREADSTONE_JWT_SECRET=CHANGE_ME_IN_PROD
12
+ TREADSTONE_OAUTH_REDIRECT_URL=http://localhost:3000/auth/callback
13
+
14
+ # === OAuth Social (leave empty to disable) ===
15
+ TREADSTONE_GOOGLE_OAUTH_CLIENT_ID=
16
+ TREADSTONE_GOOGLE_OAUTH_CLIENT_SECRET=
17
+ TREADSTONE_GITHUB_OAUTH_CLIENT_ID=
18
+ TREADSTONE_GITHUB_OAUTH_CLIENT_SECRET=
19
+
20
+ # === Auth0 / Authing / Logto (leave empty to disable) ===
21
+ TREADSTONE_AUTH0_DOMAIN=
22
+ TREADSTONE_AUTH0_CLIENT_ID=
23
+ TREADSTONE_AUTHING_DOMAIN=
24
+ TREADSTONE_AUTHING_APP_ID=
25
+ TREADSTONE_LOGTO_DOMAIN=
26
+ TREADSTONE_LOGTO_APP_ID=
27
+
28
+ # === Sandbox ===
29
+ # Subdomain-based sandbox routing (for browser Web UI access)
30
+ # Dev: "sandbox.localhost" -> {sandbox_id}.sandbox.localhost:8000
31
+ # Prod: "sandbox.example.com" -> {sandbox_id}.sandbox.example.com
32
+ # Empty string disables subdomain routing.
33
+ TREADSTONE_SANDBOX_DOMAIN=
34
+ TREADSTONE_SANDBOX_NAMESPACE=treadstone
35
+ TREADSTONE_SANDBOX_PORT=8080
36
+ TREADSTONE_SANDBOX_PROXY_TIMEOUT=180.0
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ echo "=== pre-commit: format + lint ==="
5
+
6
+ uv run ruff check --fix treadstone/ tests/
7
+ uv run ruff format treadstone/ tests/
8
+
9
+ # Re-stage files that were auto-formatted
10
+ git diff --name-only | xargs -r git add
11
+
12
+ if ! uv run ruff check treadstone/ tests/; then
13
+ echo "ERROR: Lint check failed. Fix issues above, then commit again."
14
+ exit 1
15
+ fi
16
+
17
+ if ! uv run ruff format --check treadstone/ tests/; then
18
+ echo "ERROR: Format check failed."
19
+ exit 1
20
+ fi
21
+
22
+ echo "pre-commit checks passed."
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Prevent direct pushes to the remote `main` branch.
4
+ # All branch updates to main must go through Pull Requests.
5
+ #
6
+ # Tag pushes (e.g. git push origin v0.1.1) are allowed from any local branch.
7
+
8
+ while read -r local_ref local_sha remote_ref remote_sha; do
9
+ [ -z "$remote_ref" ] && continue
10
+ if [[ "$remote_ref" == "refs/heads/main" ]]; then
11
+ echo ""
12
+ echo "ERROR: Direct push to remote 'main' is not allowed."
13
+ echo " Please create a feature branch and open a Pull Request."
14
+ echo ""
15
+ exit 1
16
+ fi
17
+ done