cursorfleet 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. cursorfleet-0.1.0/.cursor/rules/privacy-and-hooks.mdc +12 -0
  2. cursorfleet-0.1.0/.cursor/rules/python-conventions.mdc +12 -0
  3. cursorfleet-0.1.0/.github/workflows/ci.yml +95 -0
  4. cursorfleet-0.1.0/.github/workflows/pages.yml +56 -0
  5. cursorfleet-0.1.0/.github/workflows/release.yml +106 -0
  6. cursorfleet-0.1.0/.gitignore +34 -0
  7. cursorfleet-0.1.0/AGENTS.md +22 -0
  8. cursorfleet-0.1.0/CHANGELOG.md +121 -0
  9. cursorfleet-0.1.0/CONTRIBUTING.md +58 -0
  10. cursorfleet-0.1.0/LICENSE +21 -0
  11. cursorfleet-0.1.0/PKG-INFO +161 -0
  12. cursorfleet-0.1.0/README.md +123 -0
  13. cursorfleet-0.1.0/SECURITY.md +54 -0
  14. cursorfleet-0.1.0/docs/.gitkeep +0 -0
  15. cursorfleet-0.1.0/docs/adr/0000-template.md +93 -0
  16. cursorfleet-0.1.0/docs/adr/0001-cursor-capabilities.md +554 -0
  17. cursorfleet-0.1.0/docs/adr/0002-storage-layout-and-runtime-directory.md +333 -0
  18. cursorfleet-0.1.0/docs/adr/0003-event-model-and-sanitization.md +307 -0
  19. cursorfleet-0.1.0/docs/adr/0004-no-chain-of-thought-and-hook-policy.md +77 -0
  20. cursorfleet-0.1.0/docs/adr/0005-naming-and-trademark.md +80 -0
  21. cursorfleet-0.1.0/docs/adr/0006-agent-declared-events.md +167 -0
  22. cursorfleet-0.1.0/docs/adr/0007-narrower-v01-hook-policy.md +183 -0
  23. cursorfleet-0.1.0/docs/adr/0008-enforcement-boundaries.md +97 -0
  24. cursorfleet-0.1.0/docs/adr/0009-install-uninstall-ownership.md +277 -0
  25. cursorfleet-0.1.0/docs/adr/0010-reducer-state-semantics.md +139 -0
  26. cursorfleet-0.1.0/docs/adr/0011-evidence-trust-model.md +104 -0
  27. cursorfleet-0.1.0/docs/adr/0012-roster-and-worktree-ownership.md +108 -0
  28. cursorfleet-0.1.0/docs/adr/0013-run-metadata-and-association.md +34 -0
  29. cursorfleet-0.1.0/docs/adr/README.md +99 -0
  30. cursorfleet-0.1.0/docs/architecture.md +118 -0
  31. cursorfleet-0.1.0/docs/demo.md +87 -0
  32. cursorfleet-0.1.0/docs/docs-site-plan.md +252 -0
  33. cursorfleet-0.1.0/docs/empirical-test-plan.md +1559 -0
  34. cursorfleet-0.1.0/docs/evidence/a2-contract-decision-matrix.md +92 -0
  35. cursorfleet-0.1.0/docs/evidence/a2-hook-matrix.md +17 -0
  36. cursorfleet-0.1.0/docs/evidence/adr-0005-naming-gate.md +16 -0
  37. cursorfleet-0.1.0/docs/evidence/b0-live-validation-2026-10-12.md +31 -0
  38. cursorfleet-0.1.0/docs/evidence/b0-run-association-spike.md +52 -0
  39. cursorfleet-0.1.0/docs/evidence/b1-prototype-signoff.md +19 -0
  40. cursorfleet-0.1.0/docs/evidence/dogfood-week.md +10 -0
  41. cursorfleet-0.1.0/docs/evidence/external-alpha-results.md +15 -0
  42. cursorfleet-0.1.0/docs/evidence/latency-13b-linux-ide.md +27 -0
  43. cursorfleet-0.1.0/docs/evidence/live-validation-index.md +58 -0
  44. cursorfleet-0.1.0/docs/evidence/product-hunt-gate.md +12 -0
  45. cursorfleet-0.1.0/docs/evidence/pypi-trusted-publishing-setup.md +30 -0
  46. cursorfleet-0.1.0/docs/evidence/so01-permission-hooks.md +21 -0
  47. cursorfleet-0.1.0/docs/evidence/v0.1.1-backlog.md +7 -0
  48. cursorfleet-0.1.0/docs/evidence/v01-adr-truth-table.md +21 -0
  49. cursorfleet-0.1.0/docs/evidence/v01-doc-allowlist.json +25 -0
  50. cursorfleet-0.1.0/docs/evidence/v01-release-baseline.md +14 -0
  51. cursorfleet-0.1.0/docs/evidence/v01-release-ready.md +28 -0
  52. cursorfleet-0.1.0/docs/external-alpha.md +17 -0
  53. cursorfleet-0.1.0/docs/follow-ups.md +293 -0
  54. cursorfleet-0.1.0/docs/governance.md +101 -0
  55. cursorfleet-0.1.0/docs/hook-latency.md +77 -0
  56. cursorfleet-0.1.0/docs/kit.md +154 -0
  57. cursorfleet-0.1.0/docs/platform-support.md +82 -0
  58. cursorfleet-0.1.0/docs/privacy.md +102 -0
  59. cursorfleet-0.1.0/docs/product-contract.md +152 -0
  60. cursorfleet-0.1.0/docs/quickstart.md +157 -0
  61. cursorfleet-0.1.0/docs/release-checklist.md +127 -0
  62. cursorfleet-0.1.0/docs/security-review-v0.1.md +202 -0
  63. cursorfleet-0.1.0/docs/spike-prep.md +126 -0
  64. cursorfleet-0.1.0/docs/status-json.md +118 -0
  65. cursorfleet-0.1.0/docs/status.md +42 -0
  66. cursorfleet-0.1.0/docs/threat-model.md +135 -0
  67. cursorfleet-0.1.0/docs/tui.md +179 -0
  68. cursorfleet-0.1.0/public-docs/.meta.yml +5 -0
  69. cursorfleet-0.1.0/public-docs/assets/apple-touch-icon.png +0 -0
  70. cursorfleet-0.1.0/public-docs/assets/cursorfleet-icon-source.png +0 -0
  71. cursorfleet-0.1.0/public-docs/assets/cursorfleet-wordmark.png +0 -0
  72. cursorfleet-0.1.0/public-docs/assets/favicon-32.png +0 -0
  73. cursorfleet-0.1.0/public-docs/assets/logo-circle.png +0 -0
  74. cursorfleet-0.1.0/public-docs/assets/og-card.png +0 -0
  75. cursorfleet-0.1.0/public-docs/changelog.md +50 -0
  76. cursorfleet-0.1.0/public-docs/cli/doctor.md +64 -0
  77. cursorfleet-0.1.0/public-docs/cli/init.md +72 -0
  78. cursorfleet-0.1.0/public-docs/cli/status.md +55 -0
  79. cursorfleet-0.1.0/public-docs/cli/validate.md +42 -0
  80. cursorfleet-0.1.0/public-docs/concepts/agents-and-events.md +69 -0
  81. cursorfleet-0.1.0/public-docs/concepts/sessions.md +44 -0
  82. cursorfleet-0.1.0/public-docs/concepts/worktrees.md +51 -0
  83. cursorfleet-0.1.0/public-docs/contributing.md +88 -0
  84. cursorfleet-0.1.0/public-docs/getting-started/installation.md +65 -0
  85. cursorfleet-0.1.0/public-docs/getting-started/quickstart.md +116 -0
  86. cursorfleet-0.1.0/public-docs/index.md +62 -0
  87. cursorfleet-0.1.0/public-docs/known-limitations.md +82 -0
  88. cursorfleet-0.1.0/public-docs/overrides/main.html +66 -0
  89. cursorfleet-0.1.0/public-docs/privacy-and-security.md +79 -0
  90. cursorfleet-0.1.0/public-docs/stylesheets/site-brand.css +40 -0
  91. cursorfleet-0.1.0/public-docs/tui/current-status.md +30 -0
  92. cursorfleet-0.1.0/public-docs/tui/overview.md +81 -0
  93. cursorfleet-0.1.0/pyproject.toml +108 -0
  94. cursorfleet-0.1.0/schemas/.gitkeep +0 -0
  95. cursorfleet-0.1.0/schemas/config.schema.json +201 -0
  96. cursorfleet-0.1.0/schemas/event.schema.json +653 -0
  97. cursorfleet-0.1.0/schemas/policy.schema.json +10 -0
  98. cursorfleet-0.1.0/schemas/roster.schema.json +174 -0
  99. cursorfleet-0.1.0/scripts/bench_hook.py +156 -0
  100. cursorfleet-0.1.0/scripts/check_dist.py +96 -0
  101. cursorfleet-0.1.0/scripts/demo.py +278 -0
  102. cursorfleet-0.1.0/scripts/demo.sh +10 -0
  103. cursorfleet-0.1.0/scripts/gen_schemas.py +12 -0
  104. cursorfleet-0.1.0/scripts/smoke_wheel.py +178 -0
  105. cursorfleet-0.1.0/spike/README.md +270 -0
  106. cursorfleet-0.1.0/spike/analyze.py +1025 -0
  107. cursorfleet-0.1.0/spike/bench_latency.py +120 -0
  108. cursorfleet-0.1.0/spike/capture_hook.py +797 -0
  109. cursorfleet-0.1.0/spike/doc_examples/README.md +21 -0
  110. cursorfleet-0.1.0/spike/doc_examples/afterFileEdit.doc-derived.json +35 -0
  111. cursorfleet-0.1.0/spike/doc_examples/afterShellExecution.doc-derived.json +32 -0
  112. cursorfleet-0.1.0/spike/doc_examples/beforeShellExecution.doc-derived.json +31 -0
  113. cursorfleet-0.1.0/spike/doc_examples/postToolUse.doc-derived.json +36 -0
  114. cursorfleet-0.1.0/spike/doc_examples/postToolUseFailure.doc-derived.json +38 -0
  115. cursorfleet-0.1.0/spike/doc_examples/preCompact.doc-derived.json +35 -0
  116. cursorfleet-0.1.0/spike/doc_examples/preToolUse.doc-derived.json +36 -0
  117. cursorfleet-0.1.0/spike/doc_examples/sessionEnd.doc-derived.json +33 -0
  118. cursorfleet-0.1.0/spike/doc_examples/sessionStart.doc-derived.json +31 -0
  119. cursorfleet-0.1.0/spike/doc_examples/stop.doc-derived.json +30 -0
  120. cursorfleet-0.1.0/spike/doc_examples/subagentStart.doc-derived.json +36 -0
  121. cursorfleet-0.1.0/spike/doc_examples/subagentStop.doc-derived.json +41 -0
  122. cursorfleet-0.1.0/spike/hooks.json.example +77 -0
  123. cursorfleet-0.1.0/spike/hooks.windows.json.example +77 -0
  124. cursorfleet-0.1.0/spike/questions.md +157 -0
  125. cursorfleet-0.1.0/spike/results/latency-linux.json +54 -0
  126. cursorfleet-0.1.0/src/cursorfleet/__init__.py +9 -0
  127. cursorfleet-0.1.0/src/cursorfleet/adapters/__init__.py +0 -0
  128. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/__init__.py +0 -0
  129. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/blocks.py +104 -0
  130. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/diagnostics.py +547 -0
  131. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/fsutil.py +156 -0
  132. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/hook_main.py +428 -0
  133. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/hook_normalize.py +527 -0
  134. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/hook_policy.py +76 -0
  135. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/hook_sanitize.py +474 -0
  136. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/hooksjson.py +305 -0
  137. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/installer.py +626 -0
  138. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/kit.py +210 -0
  139. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/kit_probe.py +54 -0
  140. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/lock.py +145 -0
  141. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/templates.py +60 -0
  142. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/validation.py +365 -0
  143. cursorfleet-0.1.0/src/cursorfleet/adapters/cursor/workspace.py +80 -0
  144. cursorfleet-0.1.0/src/cursorfleet/cli/__init__.py +0 -0
  145. cursorfleet-0.1.0/src/cursorfleet/cli/commands/__init__.py +1 -0
  146. cursorfleet-0.1.0/src/cursorfleet/cli/commands/_common.py +82 -0
  147. cursorfleet-0.1.0/src/cursorfleet/cli/commands/_resolution.py +56 -0
  148. cursorfleet-0.1.0/src/cursorfleet/cli/commands/doctor.py +81 -0
  149. cursorfleet-0.1.0/src/cursorfleet/cli/commands/events.py +197 -0
  150. cursorfleet-0.1.0/src/cursorfleet/cli/commands/index.py +55 -0
  151. cursorfleet-0.1.0/src/cursorfleet/cli/commands/init.py +71 -0
  152. cursorfleet-0.1.0/src/cursorfleet/cli/commands/migrate.py +43 -0
  153. cursorfleet-0.1.0/src/cursorfleet/cli/commands/replay.py +76 -0
  154. cursorfleet-0.1.0/src/cursorfleet/cli/commands/run.py +97 -0
  155. cursorfleet-0.1.0/src/cursorfleet/cli/commands/status.py +210 -0
  156. cursorfleet-0.1.0/src/cursorfleet/cli/commands/tui.py +47 -0
  157. cursorfleet-0.1.0/src/cursorfleet/cli/commands/uninstall.py +73 -0
  158. cursorfleet-0.1.0/src/cursorfleet/cli/commands/validate.py +69 -0
  159. cursorfleet-0.1.0/src/cursorfleet/cli/main.py +81 -0
  160. cursorfleet-0.1.0/src/cursorfleet/config/__init__.py +44 -0
  161. cursorfleet-0.1.0/src/cursorfleet/config/io.py +27 -0
  162. cursorfleet-0.1.0/src/cursorfleet/config/models.py +154 -0
  163. cursorfleet-0.1.0/src/cursorfleet/config/roster.py +245 -0
  164. cursorfleet-0.1.0/src/cursorfleet/events/__init__.py +39 -0
  165. cursorfleet-0.1.0/src/cursorfleet/events/forbidden.py +45 -0
  166. cursorfleet-0.1.0/src/cursorfleet/events/ids.py +109 -0
  167. cursorfleet-0.1.0/src/cursorfleet/events/kinds.py +132 -0
  168. cursorfleet-0.1.0/src/cursorfleet/events/models.py +213 -0
  169. cursorfleet-0.1.0/src/cursorfleet/events/pathcheck.py +45 -0
  170. cursorfleet-0.1.0/src/cursorfleet/git/__init__.py +0 -0
  171. cursorfleet-0.1.0/src/cursorfleet/git/collector.py +226 -0
  172. cursorfleet-0.1.0/src/cursorfleet/git/runner.py +135 -0
  173. cursorfleet-0.1.0/src/cursorfleet/git/worktrees.py +71 -0
  174. cursorfleet-0.1.0/src/cursorfleet/policy/__init__.py +0 -0
  175. cursorfleet-0.1.0/src/cursorfleet/py.typed +0 -0
  176. cursorfleet-0.1.0/src/cursorfleet/safeexe.py +70 -0
  177. cursorfleet-0.1.0/src/cursorfleet/schema_gen.py +73 -0
  178. cursorfleet-0.1.0/src/cursorfleet/state/__init__.py +0 -0
  179. cursorfleet-0.1.0/src/cursorfleet/state/artifact_scan.py +309 -0
  180. cursorfleet-0.1.0/src/cursorfleet/state/context.py +38 -0
  181. cursorfleet-0.1.0/src/cursorfleet/state/event_store.py +227 -0
  182. cursorfleet-0.1.0/src/cursorfleet/state/indexer.py +443 -0
  183. cursorfleet-0.1.0/src/cursorfleet/state/lock.py +74 -0
  184. cursorfleet-0.1.0/src/cursorfleet/state/models.py +268 -0
  185. cursorfleet-0.1.0/src/cursorfleet/state/reducer.py +588 -0
  186. cursorfleet-0.1.0/src/cursorfleet/state/retention.py +218 -0
  187. cursorfleet-0.1.0/src/cursorfleet/state/run_builder.py +136 -0
  188. cursorfleet-0.1.0/src/cursorfleet/state/run_model.py +43 -0
  189. cursorfleet-0.1.0/src/cursorfleet/state/run_store.py +95 -0
  190. cursorfleet-0.1.0/src/cursorfleet/state/runtime.py +645 -0
  191. cursorfleet-0.1.0/src/cursorfleet/state/spool.py +186 -0
  192. cursorfleet-0.1.0/src/cursorfleet/state/spool_read.py +242 -0
  193. cursorfleet-0.1.0/src/cursorfleet/state/status_doc.py +293 -0
  194. cursorfleet-0.1.0/src/cursorfleet/tui/__init__.py +0 -0
  195. cursorfleet-0.1.0/src/cursorfleet/tui/app.py +581 -0
  196. cursorfleet-0.1.0/src/cursorfleet/tui/data.py +545 -0
  197. cursorfleet-0.1.0/src/cursorfleet/tui/filters.py +82 -0
  198. cursorfleet-0.1.0/src/cursorfleet/tui/gates.py +255 -0
  199. cursorfleet-0.1.0/src/cursorfleet/tui/help.py +101 -0
  200. cursorfleet-0.1.0/src/cursorfleet/tui/layout.py +26 -0
  201. cursorfleet-0.1.0/src/cursorfleet/tui/theme.py +176 -0
  202. cursorfleet-0.1.0/src/cursorfleet/tui/views.py +1077 -0
  203. cursorfleet-0.1.0/src/cursorfleet/tui/watch.py +33 -0
  204. cursorfleet-0.1.0/src/cursorfleet/workflow/__init__.py +0 -0
  205. cursorfleet-0.1.0/src/cursorfleet/workflow/artifacts.py +148 -0
  206. cursorfleet-0.1.0/src/cursorfleet/workflow/frontmatter.py +232 -0
  207. cursorfleet-0.1.0/templates/cursor/agents/architect.md +18 -0
  208. cursorfleet-0.1.0/templates/cursor/agents/implementer.md +20 -0
  209. cursorfleet-0.1.0/templates/cursor/agents/patcher.md +17 -0
  210. cursorfleet-0.1.0/templates/cursor/agents/qa.md +21 -0
  211. cursorfleet-0.1.0/templates/cursor/agents/reviewer.md +20 -0
  212. cursorfleet-0.1.0/templates/cursor/agents/scout.md +17 -0
  213. cursorfleet-0.1.0/templates/cursor/agents/tester.md +20 -0
  214. cursorfleet-0.1.0/templates/cursor/agents-md/root.md +7 -0
  215. cursorfleet-0.1.0/templates/cursor/agents-md/work.md +7 -0
  216. cursorfleet-0.1.0/templates/cursor/config/config.toml +47 -0
  217. cursorfleet-0.1.0/templates/cursor/hooks/entry.json +4 -0
  218. cursorfleet-0.1.0/templates/cursor/rules/cursorfleet-core.mdc +10 -0
  219. cursorfleet-0.1.0/templates/cursor/rules/cursorfleet-handoff.mdc +15 -0
  220. cursorfleet-0.1.0/templates/cursor/skills/cursorfleet-artifacts/SKILL.md +57 -0
  221. cursorfleet-0.1.0/templates/cursor/skills/cursorfleet-coordinator/SKILL.md +35 -0
  222. cursorfleet-0.1.0/tests/conftest.py +3 -0
  223. cursorfleet-0.1.0/tests/event_factory.py +45 -0
  224. cursorfleet-0.1.0/tests/fixtures/cursor/.gitkeep +0 -0
  225. cursorfleet-0.1.0/tests/fixtures/cursor/legacy_test_completed.jsonl +1 -0
  226. cursorfleet-0.1.0/tests/fixtures/cursor/post_m25_verification_observed.jsonl +1 -0
  227. cursorfleet-0.1.0/tests/fixtures/status/status.v1.golden.json +275 -0
  228. cursorfleet-0.1.0/tests/integration/test_cli_state.py +295 -0
  229. cursorfleet-0.1.0/tests/integration/test_doctor_validate_resolution.py +282 -0
  230. cursorfleet-0.1.0/tests/integration/test_git_collector.py +293 -0
  231. cursorfleet-0.1.0/tests/integration/test_hook_main.py +299 -0
  232. cursorfleet-0.1.0/tests/integration/test_kit_doctor_validate.py +406 -0
  233. cursorfleet-0.1.0/tests/integration/test_kit_init_uninstall.py +442 -0
  234. cursorfleet-0.1.0/tests/integration/test_runtime_inheritance.py +318 -0
  235. cursorfleet-0.1.0/tests/integration/test_runtime_resolution.py +110 -0
  236. cursorfleet-0.1.0/tests/integration/test_spool_migration.py +75 -0
  237. cursorfleet-0.1.0/tests/kit_helpers.py +44 -0
  238. cursorfleet-0.1.0/tests/m2_helpers.py +214 -0
  239. cursorfleet-0.1.0/tests/m2_strategies.py +99 -0
  240. cursorfleet-0.1.0/tests/perf/test_hook_benchmark.py +49 -0
  241. cursorfleet-0.1.0/tests/security/test_event_privacy.py +186 -0
  242. cursorfleet-0.1.0/tests/security/test_hook_policy.py +66 -0
  243. cursorfleet-0.1.0/tests/security/test_hook_privacy.py +432 -0
  244. cursorfleet-0.1.0/tests/security/test_hook_redos.py +96 -0
  245. cursorfleet-0.1.0/tests/security/test_hostile_repo.py +312 -0
  246. cursorfleet-0.1.0/tests/security/test_kit_installer_policy.py +124 -0
  247. cursorfleet-0.1.0/tests/security/test_no_network.py +161 -0
  248. cursorfleet-0.1.0/tests/security/test_runtime_trust.py +108 -0
  249. cursorfleet-0.1.0/tests/security/test_terminal_injection.py +86 -0
  250. cursorfleet-0.1.0/tests/tui/test_tui_app.py +670 -0
  251. cursorfleet-0.1.0/tests/tui/test_tui_cli.py +104 -0
  252. cursorfleet-0.1.0/tests/tui/test_tui_data.py +354 -0
  253. cursorfleet-0.1.0/tests/tui/test_tui_gates.py +158 -0
  254. cursorfleet-0.1.0/tests/tui/test_tui_privacy.py +214 -0
  255. cursorfleet-0.1.0/tests/tui_helpers.py +189 -0
  256. cursorfleet-0.1.0/tests/unit/test_artifact_scan.py +205 -0
  257. cursorfleet-0.1.0/tests/unit/test_cli.py +22 -0
  258. cursorfleet-0.1.0/tests/unit/test_config_models.py +66 -0
  259. cursorfleet-0.1.0/tests/unit/test_event_models.py +239 -0
  260. cursorfleet-0.1.0/tests/unit/test_event_store.py +90 -0
  261. cursorfleet-0.1.0/tests/unit/test_fs_names.py +60 -0
  262. cursorfleet-0.1.0/tests/unit/test_hook_normalize.py +240 -0
  263. cursorfleet-0.1.0/tests/unit/test_hook_sanitize.py +232 -0
  264. cursorfleet-0.1.0/tests/unit/test_ids.py +43 -0
  265. cursorfleet-0.1.0/tests/unit/test_indexer.py +273 -0
  266. cursorfleet-0.1.0/tests/unit/test_kit_blocks.py +51 -0
  267. cursorfleet-0.1.0/tests/unit/test_kit_frontmatter.py +104 -0
  268. cursorfleet-0.1.0/tests/unit/test_kit_hooksjson.py +134 -0
  269. cursorfleet-0.1.0/tests/unit/test_kit_probe.py +39 -0
  270. cursorfleet-0.1.0/tests/unit/test_kit_templates.py +85 -0
  271. cursorfleet-0.1.0/tests/unit/test_reducer.py +372 -0
  272. cursorfleet-0.1.0/tests/unit/test_retention.py +158 -0
  273. cursorfleet-0.1.0/tests/unit/test_roster.py +103 -0
  274. cursorfleet-0.1.0/tests/unit/test_run_builder.py +122 -0
  275. cursorfleet-0.1.0/tests/unit/test_run_store.py +14 -0
  276. cursorfleet-0.1.0/tests/unit/test_schemas.py +46 -0
  277. cursorfleet-0.1.0/tests/unit/test_spike_analyze.py +1111 -0
  278. cursorfleet-0.1.0/tests/unit/test_spool.py +351 -0
  279. cursorfleet-0.1.0/uv.lock +1288 -0
  280. cursorfleet-0.1.0/zensical.toml +92 -0
@@ -0,0 +1,12 @@
1
+ ---
2
+ description: Privacy and hook hot-path constraints; apply when touching events, adapters or hooks
3
+ globs: src/cursorfleet/events/**,src/cursorfleet/adapters/**,templates/cursor/hooks/**
4
+ alwaysApply: false
5
+ ---
6
+
7
+ - Hook entrypoint code is **stdlib-only** with lazy imports and must always fail open (exit 0; print `{"permission":"allow"}` for permission hooks, `{}` for the rest).
8
+ - Parse hook payloads through an allowlist at the boundary. Never persist prompts, thinking or response text, file contents, command output, env, `user_email` or `transcript_path`.
9
+ - Do not register `beforeSubmitPrompt`, `afterAgentThought`, `afterAgentResponse` or `beforeReadFile` in v0.1; keep a test that generated hook config never contains them.
10
+ - Hooks only append to per-session JSONL spools; only the indexer writes SQLite.
11
+ - Runtime dir is `<git-common-dir>/cursorfleet/` with 0700 dirs and 0600 files.
12
+ - No network calls anywhere in the hook path.
@@ -0,0 +1,12 @@
1
+ ---
2
+ description: Python style and typing conventions for CursorFleet source and tests
3
+ globs: src/**/*.py,tests/**/*.py
4
+ alwaysApply: false
5
+ ---
6
+
7
+ - Python >=3.11, fully typed (`mypy --strict`), formatted/linted with ruff (line length 100).
8
+ - Use `from __future__ import annotations` in new modules.
9
+ - Subprocess calls: argv list, explicit `timeout=`, never `shell=True`.
10
+ - Tests: no `time.sleep`; prefer deterministic fakes, `tmp_path`, and Textual `run_test()` for TUI.
11
+ - Tests live in `tests/{unit,integration,tui,security}`; fixtures in `tests/fixtures/cursor` must be sanitized.
12
+ - CLI command groups: one module per group in `src/cursorfleet/cli/commands/` exposing `register(app)`.
@@ -0,0 +1,95 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ # Least privilege: every job only reads the repository. No job has a token that can write.
10
+ permissions:
11
+ contents: read
12
+
13
+ concurrency:
14
+ group: ci-${{ github.workflow }}-${{ github.ref }}
15
+ cancel-in-progress: true
16
+
17
+ # Third-party actions are pinned by major version. Pinning them to full commit SHAs (with
18
+ # Dependabot to bump them) is a documented follow-up: docs/security-review-v0.1.md (SO-02).
19
+
20
+ jobs:
21
+ lint:
22
+ name: lint, format, types
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - uses: astral-sh/setup-uv@v5
27
+ with:
28
+ python-version: "3.12"
29
+ enable-cache: true
30
+ - run: uv sync --locked --all-extras
31
+ - run: uv run ruff check .
32
+ - run: uv run ruff format --check .
33
+ - run: uv run mypy src
34
+
35
+ test:
36
+ name: test ${{ matrix.os }} / py${{ matrix.python-version }}
37
+ runs-on: ${{ matrix.os }}
38
+ strategy:
39
+ fail-fast: false
40
+ matrix:
41
+ os: [ubuntu-latest, macos-latest, windows-latest]
42
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
43
+ steps:
44
+ - uses: actions/checkout@v4
45
+ - uses: astral-sh/setup-uv@v5
46
+ with:
47
+ python-version: ${{ matrix.python-version }}
48
+ enable-cache: true
49
+ - run: uv sync --locked --all-extras
50
+ # Benchmark-marked tests are excluded by default (pyproject addopts).
51
+ - run: uv run pytest --cov=cursorfleet --cov-report=term-missing --cov-report=xml
52
+ - name: Hook benchmark smoke (records timings, no assertions on speed)
53
+ if: matrix.python-version == '3.12'
54
+ continue-on-error: true
55
+ run: uv run pytest -m benchmark -q
56
+ - uses: actions/upload-artifact@v4
57
+ if: matrix.python-version == '3.12'
58
+ with:
59
+ name: coverage-${{ matrix.os }}
60
+ path: coverage.xml
61
+ if-no-files-found: ignore
62
+
63
+ package:
64
+ name: build and smoke-test the wheel on ${{ matrix.os }}
65
+ runs-on: ${{ matrix.os }}
66
+ needs: lint
67
+ strategy:
68
+ fail-fast: false
69
+ matrix:
70
+ os: [ubuntu-latest, macos-latest, windows-latest]
71
+ defaults:
72
+ run:
73
+ shell: bash
74
+ steps:
75
+ - uses: actions/checkout@v4
76
+ - uses: astral-sh/setup-uv@v5
77
+ with:
78
+ python-version: "3.12"
79
+ enable-cache: true
80
+ - name: Build sdist and wheel
81
+ run: uv build
82
+ - name: Verify the distributions (templates, scripts, license, long description)
83
+ run: uv run --no-project python scripts/check_dist.py dist
84
+ - name: Install the wheel into a clean venv outside the checkout
85
+ run: |
86
+ uv venv "$RUNNER_TEMP/smoke-venv"
87
+ uv pip install --python "$RUNNER_TEMP/smoke-venv" dist/*.whl
88
+ - name: Smoke test the installed scripts (synthetic payloads; Cursor is never started)
89
+ run: uv run --no-project python scripts/smoke_wheel.py "$RUNNER_TEMP/smoke-venv"
90
+ - uses: actions/upload-artifact@v4
91
+ if: matrix.os == 'ubuntu-latest'
92
+ with:
93
+ name: dist
94
+ path: dist/
95
+ if-no-files-found: error
@@ -0,0 +1,56 @@
1
+ # Public docs site (Zensical → GitHub Pages).
2
+ #
3
+ # Build runs on pull requests and on main. Deploy is off by default so a push
4
+ # cannot publish. The owner must later: (1) enable Pages with source
5
+ # "GitHub Actions", (2) set the repository variable PAGES_ENABLED=true.
6
+ # Official Pages actions: https://docs.github.com/en/pages/getting-started-with-github-pages/using-custom-workflows-with-github-pages
7
+ # Zensical build: https://zensical.org/docs/publish-your-site/
8
+
9
+ name: Pages
10
+
11
+ on:
12
+ push:
13
+ branches: [main]
14
+ pull_request:
15
+ workflow_dispatch:
16
+
17
+ # Least privilege: every job starts read-only. Only deploy elevates.
18
+ permissions:
19
+ contents: read
20
+
21
+ concurrency:
22
+ group: pages-${{ github.workflow }}-${{ github.ref }}
23
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
24
+
25
+ jobs:
26
+ build:
27
+ name: build docs site
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: astral-sh/setup-uv@v5
32
+ with:
33
+ python-version: "3.12"
34
+ enable-cache: true
35
+ - run: uv sync --locked --all-extras
36
+ - run: uv run zensical build --clean
37
+ - uses: actions/configure-pages@v6
38
+ - uses: actions/upload-pages-artifact@v5
39
+ with:
40
+ path: site
41
+
42
+ deploy:
43
+ name: deploy to GitHub Pages
44
+ # Kill switch: unset/false keeps this workflow build-only.
45
+ if: github.event_name != 'pull_request' && vars.PAGES_ENABLED == 'true'
46
+ needs: build
47
+ runs-on: ubuntu-latest
48
+ environment:
49
+ name: github-pages
50
+ url: ${{ steps.deployment.outputs.page_url }}
51
+ permissions:
52
+ pages: write
53
+ id-token: write
54
+ steps:
55
+ - uses: actions/deploy-pages@v5
56
+ id: deployment
@@ -0,0 +1,106 @@
1
+ name: Release
2
+
3
+ # INACTIVE until the owner acts: this workflow only runs when a tag named v* is pushed, and
4
+ # the PyPI publish job additionally requires the repository variable RELEASE_ENABLED=true and
5
+ # the protected `pypi` environment. Nothing here has ever been run. See
6
+ # docs/release-checklist.md for the exact owner steps (and which are blocking).
7
+
8
+ on:
9
+ push:
10
+ tags: ["v*"]
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ # Third-party actions are pinned by major version; SHA pinning is a documented follow-up
16
+ # (docs/security-review-v0.1.md, SO-02).
17
+
18
+ jobs:
19
+ checks:
20
+ name: checks ${{ matrix.os }} / py${{ matrix.python-version }}
21
+ runs-on: ${{ matrix.os }}
22
+ strategy:
23
+ fail-fast: true
24
+ matrix:
25
+ os: [ubuntu-latest, macos-latest, windows-latest]
26
+ python-version: ["3.11", "3.14"]
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ - uses: astral-sh/setup-uv@v5
30
+ with:
31
+ python-version: ${{ matrix.python-version }}
32
+ enable-cache: true
33
+ - run: uv sync --locked --all-extras
34
+ - run: uv run ruff check .
35
+ - run: uv run ruff format --check .
36
+ - run: uv run mypy src
37
+ - run: uv run pytest
38
+
39
+ build:
40
+ name: build distributions
41
+ runs-on: ubuntu-latest
42
+ needs: checks
43
+ steps:
44
+ - uses: actions/checkout@v4
45
+ - uses: astral-sh/setup-uv@v5
46
+ with:
47
+ python-version: "3.12"
48
+ - name: The tag must match the version in pyproject.toml
49
+ run: |
50
+ version="$(uv run --no-project python -c "import tomllib;print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")"
51
+ if [ "v${version}" != "${GITHUB_REF_NAME}" ]; then
52
+ echo "tag ${GITHUB_REF_NAME} does not match pyproject version ${version}" >&2
53
+ exit 1
54
+ fi
55
+ - run: uv build
56
+ - run: uv run --no-project python scripts/check_dist.py dist
57
+ - name: Smoke test the wheel in a clean venv
58
+ run: |
59
+ uv venv "$RUNNER_TEMP/smoke-venv"
60
+ uv pip install --python "$RUNNER_TEMP/smoke-venv" dist/*.whl
61
+ uv run --no-project python scripts/smoke_wheel.py "$RUNNER_TEMP/smoke-venv"
62
+ - uses: actions/upload-artifact@v4
63
+ with:
64
+ name: dist
65
+ path: dist/
66
+ if-no-files-found: error
67
+
68
+ github-release:
69
+ name: draft GitHub release
70
+ runs-on: ubuntu-latest
71
+ needs: build
72
+ permissions:
73
+ contents: write # only this job can create the (draft) release
74
+ steps:
75
+ - uses: actions/checkout@v4
76
+ - uses: actions/download-artifact@v4
77
+ with:
78
+ name: dist
79
+ path: dist/
80
+ # A DRAFT: the owner reviews the notes and publishes it by hand.
81
+ - name: Create the draft release with the sdist and wheel attached
82
+ env:
83
+ GH_TOKEN: ${{ github.token }}
84
+ run: |
85
+ gh release create "${GITHUB_REF_NAME}" dist/* \
86
+ --draft --verify-tag \
87
+ --title "CursorFleet ${GITHUB_REF_NAME}" \
88
+ --notes "Draft. Copy the matching section of CHANGELOG.md here before publishing. Unofficial: not affiliated with or endorsed by Anysphere or Cursor."
89
+
90
+ publish-pypi:
91
+ name: publish to PyPI (Trusted Publishing)
92
+ runs-on: ubuntu-latest
93
+ needs: build
94
+ # Kill switch: set the repository variable RELEASE_ENABLED=true to allow publishing.
95
+ if: vars.RELEASE_ENABLED == 'true'
96
+ environment:
97
+ name: pypi # protected environment: configure required reviewers in the repository settings
98
+ url: https://pypi.org/project/cursorfleet/
99
+ permissions:
100
+ id-token: write # OIDC token for Trusted Publishing; granted to this job only
101
+ steps:
102
+ - uses: actions/download-artifact@v4
103
+ with:
104
+ name: dist
105
+ path: dist/
106
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,34 @@
1
+ # Generated public docs site (zensical.toml site_dir)
2
+ site/
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.py[cod]
7
+ *.egg-info/
8
+ .eggs/
9
+ build/
10
+ dist/
11
+ .pytest_cache/
12
+ .mypy_cache/
13
+ .ruff_cache/
14
+ .hypothesis/
15
+ .coverage
16
+ coverage.xml
17
+ htmlcov/
18
+
19
+ # Environments
20
+ .venv/
21
+ venv/
22
+ .env
23
+
24
+ # CursorFleet runtime state (committed config in .cursorfleet/ is config.toml, roster.toml, work/)
25
+ .cursorfleet/runtime/
26
+ .cursorfleet/*.sqlite*
27
+ .cursorfleet/*.jsonl
28
+ .cursorfleet/*.lock
29
+
30
+ # OS / editor
31
+ .DS_Store
32
+ Thumbs.db
33
+ .idea/
34
+ .vscode/
@@ -0,0 +1,22 @@
1
+ # CursorFleet: developer conventions
2
+
3
+ CursorFleet is a local TUI and workflow harness for Cursor agent teams. v0.1 is **Observe** only: no enforcement, no forced approvals, no cloud-agent visibility. Cursor is the only officially supported IDE; keep internals adapter-ready (`cursorfleet.adapters.*`, normalized events).
4
+
5
+ ## Layout
6
+ - `src/cursorfleet/`: package (`cli`, `config`, `adapters/cursor`, `events`, `state`, `git`, `policy`, `workflow`, `tui`).
7
+ - `tests/{unit,integration,tui,security}`, `tests/fixtures/cursor` (sanitized real payloads only).
8
+ - `schemas/` JSON Schemas, `templates/cursor/` generated-kit templates, `docs/` documentation.
9
+ - Committed config: `.cursorfleet/`. Runtime state lives under `<git-common-dir>/cursorfleet/`, never in the working tree.
10
+
11
+ ## Commands
12
+ - `uv sync` then `uv run ruff check .`, `uv run mypy src`, `uv run pytest`.
13
+
14
+ ## Rules
15
+ - **Hook hot path is stdlib-only.** No pydantic/typer/textual imports (even transitively) in hook entrypoints; lazy-import everything else. Hooks must fail open: always exit 0 on any internal error, printing the right reply for the hook type: `{"permission":"allow"}` for permission hooks (`preToolUse`, `subagentStart`, `beforeShellExecution`, and `beforeMCPExecution`/`beforeReadFile` should they ever be wired), `{}` for all others (see `hook_policy.fail_open_response` and ADR 0004). An invalid reply from a permission hook blocks the action.
16
+ - **Every subprocess** uses an argv list (never `shell=True`) and an explicit `timeout=`.
17
+ - **Never persist** prompts, thinking/response text, file contents, command output, env vars, user emails or transcript paths. Drop them at the parser boundary using an allowlist. Never register `beforeSubmitPrompt`, `afterAgentThought`, `afterAgentResponse` or `beforeReadFile` hooks in v0.1.
18
+ - Paths stored are workspace-relative; anything outside workspace roots becomes `<external>`.
19
+ - **No sleeps in tests.** Use events, polling with deadlines on fakes, or Textual `run_test()` pilots.
20
+ - New CLI command groups go in their own module under `cli/commands/` exposing `register(app)`; do not edit `cli/main.py`.
21
+ - Rules in `.cursor/rules/` must be `.mdc` with frontmatter and under 500 lines.
22
+ - Python >=3.11; type-annotate everything (`mypy --strict`); keep Windows/macOS/Linux parity.
@@ -0,0 +1,121 @@
1
+ # Changelog
2
+
3
+ All notable changes to CursorFleet are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project intends to follow
5
+ [Semantic Versioning](https://semver.org/) once a first release exists.
6
+
7
+ CursorFleet is an unofficial tool: it is not affiliated with or endorsed by Anysphere or Cursor.
8
+
9
+ ## [Unreleased]
10
+
11
+ Development version `0.1.1.dev0` (post-v0.1.0). Planned: TUI attach picker, external alpha metrics.
12
+
13
+ ## [0.1.0] - 2026-10-12
14
+
15
+ First public pre-alpha on PyPI (when `RELEASE_ENABLED` is approved). **Observe-only:** no
16
+ enforcement, no cloud-agent visibility. External user validation and B0 live scenarios 1/2/5
17
+ remain documented in [docs/evidence/v01-release-ready.md](docs/evidence/v01-release-ready.md).
18
+
19
+ ### Added
20
+
21
+ - **Active run TUI** (default): participant groups/instances, runs list (`u`), sessions archive (`o`).
22
+ - **`cursorfleet run`** start/list/attach/archive; run files under git common dir ([ADR 0013](docs/adr/0013-run-metadata-and-association.md)).
23
+ - **`status --json` `runs[]`** when telemetry exists (`cursorfleet.status/0.2`).
24
+ - Legacy spool **`test.completed`** fixture + migration integration test; sanitized corpus under `tests/fixtures/cursor/`.
25
+
26
+ ### Process
27
+
28
+ - **M2.5 charter (2026-10-05).** Task-centric local observer work is active; M0a capture kit
29
+ and product hooks are tracked separately ([docs/evidence/live-validation-index.md](docs/evidence/live-validation-index.md)).
30
+ Linux Cursor IDE 3.22.7 product-hook smoke confirmed telemetry; Q1/Q2 remain OPEN.
31
+ See [docs/status.md](docs/status.md).
32
+ - **M0a freeze (2026-10-04, superseded for product direction).** Formal ADR 0001 matrix and
33
+ spike kit remain for Q1–Q6; see [spike/README.md](spike/README.md).
34
+
35
+ ### Documentation
36
+
37
+ - ADR process and template accepted as ADR 0000, with required fields on every ADR
38
+ (supersession, related ADRs, implementation status, review trigger, release gate) and an
39
+ indexed list of release gates in [docs/adr/README.md](docs/adr/README.md).
40
+ - New ADRs: 0007 narrower v0.1 hook policy (supersedes 0004; nine hooks), 0008 enforcement
41
+ boundaries, 0009 install and uninstall ownership, 0010 reducer state semantics, 0011
42
+ evidence trust model, 0012 roster and worktree ownership.
43
+ - Decisions recorded that the code does **not** yet follow (tracked in
44
+ [docs/follow-ups.md](docs/follow-ups.md), to be done after the spike): nine registered
45
+ hooks, event schema version `0.1`, `verification.observed` instead of `test.completed`,
46
+ command display off by default, BLAKE2s segment fingerprints, HMAC worktree ids, a
47
+ maintenance lock, TOML artifact frontmatter, no gate derived from heuristic events, and
48
+ `init`/`uninstall` repository-root preconditions (exit 2; no `--allow-non-git`), and
49
+ runtime inheritance of an initialized enclosing repository for nested non-Git directories
50
+ (ADR 0002; `init` still refuses ordinary subdirectories).
51
+ - ADR 0001 stays provisional and now carries an empirical test matrix; the local Cursor IDE
52
+ (desktop) is the only supported v0.1 surface, and the CLI, Agents Window and worktrees are
53
+ not claimed. See [docs/empirical-test-plan.md](docs/empirical-test-plan.md).
54
+ - ADR 0005: `CursorFleet` is a working name; the public name, registry availability and a
55
+ trademark review are release gates. `fleet-for-cursor` is withdrawn as a fallback because
56
+ it still contains the Cursor mark.
57
+ - Docs-site plan only ([docs/docs-site-plan.md](docs/docs-site-plan.md)); no site, workflow or
58
+ dependency was added.
59
+ - ADR 0002 / 0009: a nested non-Git directory inherits an already initialized enclosing
60
+ repository for runtime event attribution; `init` from an ordinary subdirectory still
61
+ exits 2 (documentation only).
62
+
63
+ ### Added
64
+
65
+ - **M0 foundations:** project scaffold, ADRs 0001 to 0006, product contract, threat model,
66
+ privacy statement, JSON Schemas for events, config, roster and policy (reserved), a throwaway
67
+ capture kit under `spike/` and a Linux hook-latency benchmark (27.7 ms steady-state p95).
68
+ - **M1 kit:** `cursorfleet init --cursor`, `uninstall`, `doctor` and `validate`. Deterministic
69
+ generation of subagent files, rules, skills, `AGENTS.md` blocks and a merged
70
+ `.cursor/hooks.json` of twelve passive hooks (ADR 0007 later narrowed this to nine; code not yet changed), with a visible diff, confirmation, an install
71
+ lockfile and byte-for-byte uninstall.
72
+ - **M2 observer:** a stdlib-only, fail-open hook entry point (`cursorfleet-hook`) with an
73
+ allowlist parser, command and path sanitizer, per-writer append-only JSONL spool with CRC and
74
+ size caps, a single-writer SQLite projection with quarantine and rebuild, deterministic
75
+ reducer and `replay`, a read-only git/worktree collector, retention and `events export` /
76
+ `events purge`, and `status --json` (`cursorfleet.status/1`).
77
+ - **M3 dashboard:** the Textual TUI (`cursorfleet tui`) with overview, agent detail, timeline,
78
+ worktrees, gates (display-only), evidence and tiles views, filtering, pinning, and a degraded
79
+ mode for missing telemetry.
80
+ - **M4 release preparation:**
81
+ - security and privacy review ([docs/security-review-v0.1.md](docs/security-review-v0.1.md))
82
+ with regression tests, including a no-network test;
83
+ - cross-platform CI (Linux, macOS, Windows; Python 3.11 to 3.14) with lint, format, types,
84
+ coverage, and a wheel build-and-smoke-test job; inactive release workflow
85
+ (`.github/workflows/release.yml`) using PyPI Trusted Publishing and a draft GitHub release;
86
+ - `docs/quickstart.md`, `governance.md`, `demo.md`, `platform-support.md`,
87
+ `release-checklist.md` and a reproducible synthetic demo (`scripts/demo.sh`).
88
+
89
+ ### Security
90
+
91
+ - Bounded redaction window removes a regular-expression denial of service in the hook's command
92
+ and text redaction (SR-01).
93
+ - The runtime directory is refused when it is a symlink, a reparse point, owned by another user
94
+ or group/other-writable (SR-02).
95
+ - Tools (`git`, `cursor`) are resolved from absolute `PATH` entries only, never the current
96
+ directory (SR-03); NTFS junctions count as links (SR-04); the workspace resolver uses the same
97
+ hostile-repository git hardening as the collector (SR-05); paths inside `.git` are rejected in
98
+ config and lockfile (SR-06).
99
+ - Lower-severity hardening: planted-database recovery, no local variables in tracebacks,
100
+ escaped terminal control characters in error and doctor output, `O_NOFOLLOW` artifact reads,
101
+ non-blocking spool open, drive-letter refs refused, attached `mysql -p` passwords redacted.
102
+
103
+ ### Known limitations (0.1.0)
104
+
105
+ - Run association requires explicit `cursorfleet run` / env attach; TUI picker planned for 0.1.1.
106
+ - Observations screen is non-authoritative (ADR 0011); artifacts are self-reported (ADR 0006 amendment).
107
+ - Twelve passive observe hooks (ADR 0007 amendment 2026-10-12).
108
+ - ADR 0001 Q1/Q2 OPEN; end-to-end latency 13B may be OPEN — see evidence index.
109
+ - SO-01 live permission-hook confirmation may be pending — see [so01-permission-hooks.md](docs/evidence/so01-permission-hooks.md).
110
+
111
+ ### Known limitations (historical pre-0.1.0 notes)
112
+
113
+ - The TUI derives PASS/FAIL gate tiles from heuristic command classification. This is
114
+ non-authoritative and contradicts ADR 0003 rule R1; fix pending after the spike.
115
+ - The code registers twelve hooks; ADR 0007 decides nine.
116
+ - Hook payload shapes come from documentation, not captures. Agent attribution on tool events,
117
+ custom subagent names, CLI and Agents Window behaviour, and macOS/Windows hook latency are
118
+ unverified (see [docs/platform-support.md](docs/platform-support.md)).
119
+ - Windows ACLs are not set on the runtime directory.
120
+ - GitHub Actions are pinned by major version, not by commit SHA.
121
+ - `cursorfleet emit` (ADR 0006 fallback) is not implemented.
@@ -0,0 +1,58 @@
1
+ # Contributing to CursorFleet
2
+
3
+ CursorFleet is pre-alpha and unofficial. Issues and small PRs are welcome; for larger changes
4
+ please open an issue first. For security problems do **not** open a public issue: see
5
+ [SECURITY.md](SECURITY.md).
6
+
7
+ ## Setup
8
+
9
+ ```bash
10
+ uv sync --all-extras
11
+ uv run cursorfleet --version
12
+ ```
13
+
14
+ ## Checks (must pass before a PR)
15
+
16
+ ```bash
17
+ uv run ruff check .
18
+ uv run ruff format --check . # `uv run ruff format .` fixes it
19
+ uv run mypy src
20
+ uv run pytest # benchmark-marked tests are excluded by default
21
+ ```
22
+
23
+ CI runs the same on Linux, macOS and Windows with Python 3.11 to 3.14, plus a job that builds
24
+ the wheel and smoke-tests it in a clean venv. To reproduce that locally:
25
+
26
+ ```bash
27
+ uv build && python scripts/check_dist.py dist
28
+ uv venv /tmp/cf-venv && uv pip install --python /tmp/cf-venv dist/*.whl
29
+ python scripts/smoke_wheel.py /tmp/cf-venv
30
+ python scripts/demo.py --venv /tmp/cf-venv # synthetic demo, no Cursor
31
+ ```
32
+
33
+ Coverage: `uv run pytest --cov=cursorfleet --cov-report=term-missing`. Hook timings:
34
+ `uv run pytest -m benchmark` or `uv run python scripts/bench_hook.py`.
35
+
36
+ Without uv: `python -m venv .venv && .venv/bin/pip install -e ".[watch]" --group dev` (pip >= 25.1),
37
+ then run the tools from `.venv/bin`.
38
+
39
+ ## Conventions
40
+
41
+ Read [`AGENTS.md`](AGENTS.md). Highlights:
42
+
43
+ - the hook hot path is stdlib-only and fails open (exit 0 with the right reply);
44
+ - every subprocess uses an argv list and an explicit `timeout=`; resolve tools with
45
+ `cursorfleet.safeexe.find_executable`, never from the current directory;
46
+ - never persist prompts, thinking, file contents, command output, env, emails or transcript
47
+ paths; drop them at the parser boundary with an allowlist;
48
+ - no sleeps in tests; keep Windows, macOS and Linux behaviour in step and skip a test only with
49
+ an explicit `reason=`;
50
+ - security-relevant changes get a regression test under `tests/security/`;
51
+ - documentation must stay honest: mark anything that depends on unverified Cursor behaviour
52
+ as PROVISIONAL, and do not claim enforcement.
53
+
54
+ Do not commit real Cursor payloads. Fixtures under `tests/fixtures/cursor` must be captured,
55
+ reviewed and sanitized, with the Cursor version recorded; doc-derived examples live in
56
+ `spike/doc_examples` and are not fixtures.
57
+
58
+ By contributing you agree your work is licensed under the MIT License.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mounir Al-Suroji
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.