claude-code-swarm 0.3.7 → 0.3.8

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 (1357) hide show
  1. package/.claude/settings.json +1 -0
  2. package/.claude-plugin/marketplace.json +1 -1
  3. package/.claude-plugin/plugin.json +1 -1
  4. package/CLAUDE.md +44 -1
  5. package/package.json +4 -1
  6. package/scripts/bootstrap-bg.mjs +31 -0
  7. package/scripts/bootstrap.mjs +30 -4
  8. package/scripts/dev-link.mjs +179 -0
  9. package/scripts/map-hook.mjs +30 -44
  10. package/scripts/map-sidecar.mjs +156 -27
  11. package/src/__tests__/bootstrap.test.mjs +227 -237
  12. package/src/__tests__/config.test.mjs +275 -1
  13. package/src/__tests__/e2e-reconnection.test.mjs +537 -0
  14. package/src/__tests__/helpers.mjs +6 -0
  15. package/src/__tests__/index.test.mjs +4 -0
  16. package/src/__tests__/log.test.mjs +510 -0
  17. package/src/__tests__/map-connection.test.mjs +7 -0
  18. package/src/__tests__/paths.test.mjs +1 -1
  19. package/src/bootstrap.mjs +129 -94
  20. package/src/config.mjs +36 -9
  21. package/src/index.mjs +4 -0
  22. package/src/log.mjs +152 -0
  23. package/src/map-connection.mjs +40 -9
  24. package/src/mesh-connection.mjs +8 -12
  25. package/src/opentasks-client.mjs +5 -2
  26. package/src/paths.mjs +11 -8
  27. package/src/roles.mjs +4 -3
  28. package/src/sessionlog.mjs +38 -2
  29. package/src/sidecar-client.mjs +13 -2
  30. package/src/sidecar-server.mjs +16 -26
  31. package/src/skilltree-client.mjs +4 -1
  32. package/src/swarmkit-resolver.mjs +17 -1
  33. package/src/template.mjs +4 -1
  34. package/vitest.config.mjs +4 -0
  35. package/references/agent-inbox/CLAUDE.md +0 -151
  36. package/references/agent-inbox/README.md +0 -238
  37. package/references/agent-inbox/docs/CLAUDE-CODE-SWARM-PROPOSAL.md +0 -137
  38. package/references/agent-inbox/docs/DESIGN.md +0 -1156
  39. package/references/agent-inbox/hooks/inbox-hook.mjs +0 -119
  40. package/references/agent-inbox/hooks/register-hook.mjs +0 -69
  41. package/references/agent-inbox/package-lock.json +0 -3347
  42. package/references/agent-inbox/package.json +0 -58
  43. package/references/agent-inbox/rules/agent-inbox.md +0 -78
  44. package/references/agent-inbox/src/federation/address.ts +0 -61
  45. package/references/agent-inbox/src/federation/connection-manager.ts +0 -573
  46. package/references/agent-inbox/src/federation/delivery-queue.ts +0 -222
  47. package/references/agent-inbox/src/federation/index.ts +0 -6
  48. package/references/agent-inbox/src/federation/routing-engine.ts +0 -188
  49. package/references/agent-inbox/src/federation/trust.ts +0 -71
  50. package/references/agent-inbox/src/index.ts +0 -404
  51. package/references/agent-inbox/src/ipc/ipc-server.ts +0 -265
  52. package/references/agent-inbox/src/jsonrpc/mail-server.ts +0 -382
  53. package/references/agent-inbox/src/map/map-client.ts +0 -414
  54. package/references/agent-inbox/src/mcp/mcp-proxy.ts +0 -326
  55. package/references/agent-inbox/src/mcp/mcp-server.ts +0 -272
  56. package/references/agent-inbox/src/mesh/delivery-bridge.ts +0 -110
  57. package/references/agent-inbox/src/mesh/mesh-connector.ts +0 -41
  58. package/references/agent-inbox/src/mesh/mesh-transport.ts +0 -157
  59. package/references/agent-inbox/src/mesh/type-mapper.ts +0 -239
  60. package/references/agent-inbox/src/push/notifier.ts +0 -233
  61. package/references/agent-inbox/src/registry/warm-registry.ts +0 -255
  62. package/references/agent-inbox/src/router/message-router.ts +0 -175
  63. package/references/agent-inbox/src/storage/interface.ts +0 -48
  64. package/references/agent-inbox/src/storage/memory.ts +0 -145
  65. package/references/agent-inbox/src/storage/sqlite.ts +0 -671
  66. package/references/agent-inbox/src/traceability/traceability.ts +0 -183
  67. package/references/agent-inbox/src/types.ts +0 -329
  68. package/references/agent-inbox/test/federation/address.test.ts +0 -101
  69. package/references/agent-inbox/test/federation/connection-manager.test.ts +0 -546
  70. package/references/agent-inbox/test/federation/delivery-queue.test.ts +0 -159
  71. package/references/agent-inbox/test/federation/integration.test.ts +0 -857
  72. package/references/agent-inbox/test/federation/routing-engine.test.ts +0 -117
  73. package/references/agent-inbox/test/federation/sdk-integration.test.ts +0 -744
  74. package/references/agent-inbox/test/federation/trust.test.ts +0 -89
  75. package/references/agent-inbox/test/ipc-jsonrpc.test.ts +0 -113
  76. package/references/agent-inbox/test/ipc-new-commands.test.ts +0 -200
  77. package/references/agent-inbox/test/ipc-server.test.ts +0 -197
  78. package/references/agent-inbox/test/mail-server.test.ts +0 -285
  79. package/references/agent-inbox/test/map-client.test.ts +0 -408
  80. package/references/agent-inbox/test/mcp-proxy.test.ts +0 -191
  81. package/references/agent-inbox/test/mesh/delivery-bridge.test.ts +0 -178
  82. package/references/agent-inbox/test/mesh/e2e-mesh.test.ts +0 -527
  83. package/references/agent-inbox/test/mesh/e2e-real-meshpeer.test.ts +0 -629
  84. package/references/agent-inbox/test/mesh/federation-mesh.test.ts +0 -269
  85. package/references/agent-inbox/test/mesh/mesh-connector.test.ts +0 -66
  86. package/references/agent-inbox/test/mesh/mesh-transport.test.ts +0 -191
  87. package/references/agent-inbox/test/mesh/meshpeer-integration.test.ts +0 -442
  88. package/references/agent-inbox/test/mesh/mock-mesh.ts +0 -125
  89. package/references/agent-inbox/test/mesh/mock-meshpeer.ts +0 -266
  90. package/references/agent-inbox/test/mesh/type-mapper.test.ts +0 -226
  91. package/references/agent-inbox/test/message-router.test.ts +0 -184
  92. package/references/agent-inbox/test/push-notifier.test.ts +0 -139
  93. package/references/agent-inbox/test/registry/warm-registry.test.ts +0 -171
  94. package/references/agent-inbox/test/sqlite-prefix.test.ts +0 -192
  95. package/references/agent-inbox/test/sqlite-storage.test.ts +0 -243
  96. package/references/agent-inbox/test/storage.test.ts +0 -196
  97. package/references/agent-inbox/test/traceability.test.ts +0 -123
  98. package/references/agent-inbox/test/wake.test.ts +0 -330
  99. package/references/agent-inbox/tsconfig.json +0 -20
  100. package/references/agent-inbox/tsup.config.ts +0 -10
  101. package/references/agent-inbox/vitest.config.ts +0 -8
  102. package/references/minimem/.claude/settings.json +0 -7
  103. package/references/minimem/.sudocode/issues.jsonl +0 -18
  104. package/references/minimem/.sudocode/specs.jsonl +0 -1
  105. package/references/minimem/CLAUDE.md +0 -329
  106. package/references/minimem/README.md +0 -565
  107. package/references/minimem/claude-plugin/.claude-plugin/plugin.json +0 -10
  108. package/references/minimem/claude-plugin/.mcp.json +0 -7
  109. package/references/minimem/claude-plugin/README.md +0 -158
  110. package/references/minimem/claude-plugin/commands/recall.md +0 -47
  111. package/references/minimem/claude-plugin/commands/remember.md +0 -41
  112. package/references/minimem/claude-plugin/hooks/__tests__/hooks.test.ts +0 -272
  113. package/references/minimem/claude-plugin/hooks/hooks.json +0 -27
  114. package/references/minimem/claude-plugin/hooks/session-end.sh +0 -86
  115. package/references/minimem/claude-plugin/hooks/session-start.sh +0 -85
  116. package/references/minimem/claude-plugin/skills/memory/SKILL.md +0 -108
  117. package/references/minimem/media/banner.png +0 -0
  118. package/references/minimem/package-lock.json +0 -5373
  119. package/references/minimem/package.json +0 -76
  120. package/references/minimem/scripts/postbuild.js +0 -49
  121. package/references/minimem/src/__tests__/edge-cases.test.ts +0 -371
  122. package/references/minimem/src/__tests__/errors.test.ts +0 -265
  123. package/references/minimem/src/__tests__/helpers.ts +0 -199
  124. package/references/minimem/src/__tests__/internal.test.ts +0 -407
  125. package/references/minimem/src/__tests__/knowledge-frontmatter.test.ts +0 -148
  126. package/references/minimem/src/__tests__/knowledge.test.ts +0 -148
  127. package/references/minimem/src/__tests__/minimem.integration.test.ts +0 -1127
  128. package/references/minimem/src/__tests__/session.test.ts +0 -190
  129. package/references/minimem/src/cli/__tests__/commands.test.ts +0 -760
  130. package/references/minimem/src/cli/__tests__/contained-layout.test.ts +0 -286
  131. package/references/minimem/src/cli/commands/__tests__/conflicts.test.ts +0 -141
  132. package/references/minimem/src/cli/commands/append.ts +0 -76
  133. package/references/minimem/src/cli/commands/config.ts +0 -262
  134. package/references/minimem/src/cli/commands/conflicts.ts +0 -415
  135. package/references/minimem/src/cli/commands/daemon.ts +0 -169
  136. package/references/minimem/src/cli/commands/index.ts +0 -12
  137. package/references/minimem/src/cli/commands/init.ts +0 -166
  138. package/references/minimem/src/cli/commands/mcp.ts +0 -221
  139. package/references/minimem/src/cli/commands/push-pull.ts +0 -213
  140. package/references/minimem/src/cli/commands/search.ts +0 -223
  141. package/references/minimem/src/cli/commands/status.ts +0 -84
  142. package/references/minimem/src/cli/commands/store.ts +0 -189
  143. package/references/minimem/src/cli/commands/sync-init.ts +0 -290
  144. package/references/minimem/src/cli/commands/sync.ts +0 -70
  145. package/references/minimem/src/cli/commands/upsert.ts +0 -197
  146. package/references/minimem/src/cli/config.ts +0 -611
  147. package/references/minimem/src/cli/index.ts +0 -299
  148. package/references/minimem/src/cli/shared.ts +0 -189
  149. package/references/minimem/src/cli/sync/__tests__/central.test.ts +0 -152
  150. package/references/minimem/src/cli/sync/__tests__/conflicts.test.ts +0 -209
  151. package/references/minimem/src/cli/sync/__tests__/daemon.test.ts +0 -118
  152. package/references/minimem/src/cli/sync/__tests__/detection.test.ts +0 -207
  153. package/references/minimem/src/cli/sync/__tests__/integration.test.ts +0 -476
  154. package/references/minimem/src/cli/sync/__tests__/registry.test.ts +0 -363
  155. package/references/minimem/src/cli/sync/__tests__/state.test.ts +0 -255
  156. package/references/minimem/src/cli/sync/__tests__/validation.test.ts +0 -193
  157. package/references/minimem/src/cli/sync/__tests__/watcher.test.ts +0 -178
  158. package/references/minimem/src/cli/sync/central.ts +0 -292
  159. package/references/minimem/src/cli/sync/conflicts.ts +0 -205
  160. package/references/minimem/src/cli/sync/daemon.ts +0 -407
  161. package/references/minimem/src/cli/sync/detection.ts +0 -138
  162. package/references/minimem/src/cli/sync/index.ts +0 -107
  163. package/references/minimem/src/cli/sync/operations.ts +0 -373
  164. package/references/minimem/src/cli/sync/registry.ts +0 -279
  165. package/references/minimem/src/cli/sync/state.ts +0 -358
  166. package/references/minimem/src/cli/sync/validation.ts +0 -206
  167. package/references/minimem/src/cli/sync/watcher.ts +0 -237
  168. package/references/minimem/src/cli/version.ts +0 -34
  169. package/references/minimem/src/core/index.ts +0 -9
  170. package/references/minimem/src/core/indexer.ts +0 -628
  171. package/references/minimem/src/core/searcher.ts +0 -221
  172. package/references/minimem/src/db/schema.ts +0 -183
  173. package/references/minimem/src/db/sqlite-vec.ts +0 -24
  174. package/references/minimem/src/embeddings/__tests__/embeddings.test.ts +0 -431
  175. package/references/minimem/src/embeddings/batch-gemini.ts +0 -392
  176. package/references/minimem/src/embeddings/batch-openai.ts +0 -409
  177. package/references/minimem/src/embeddings/embeddings.ts +0 -434
  178. package/references/minimem/src/index.ts +0 -132
  179. package/references/minimem/src/internal.ts +0 -299
  180. package/references/minimem/src/minimem.ts +0 -1291
  181. package/references/minimem/src/search/__tests__/hybrid.test.ts +0 -247
  182. package/references/minimem/src/search/graph.ts +0 -234
  183. package/references/minimem/src/search/hybrid.ts +0 -151
  184. package/references/minimem/src/search/search.ts +0 -256
  185. package/references/minimem/src/server/__tests__/mcp.test.ts +0 -347
  186. package/references/minimem/src/server/__tests__/tools.test.ts +0 -364
  187. package/references/minimem/src/server/mcp.ts +0 -326
  188. package/references/minimem/src/server/tools.ts +0 -720
  189. package/references/minimem/src/session.ts +0 -460
  190. package/references/minimem/src/store/__tests__/manifest.test.ts +0 -177
  191. package/references/minimem/src/store/__tests__/materialize.test.ts +0 -52
  192. package/references/minimem/src/store/__tests__/store-graph.test.ts +0 -228
  193. package/references/minimem/src/store/index.ts +0 -27
  194. package/references/minimem/src/store/manifest.ts +0 -203
  195. package/references/minimem/src/store/materialize.ts +0 -185
  196. package/references/minimem/src/store/store-graph.ts +0 -252
  197. package/references/minimem/tsconfig.json +0 -19
  198. package/references/minimem/tsup.config.ts +0 -26
  199. package/references/minimem/vitest.config.ts +0 -29
  200. package/references/multi-agent-protocol/.sudocode/issues.jsonl +0 -120
  201. package/references/multi-agent-protocol/.sudocode/specs.jsonl +0 -15
  202. package/references/multi-agent-protocol/LICENSE +0 -21
  203. package/references/multi-agent-protocol/README.md +0 -113
  204. package/references/multi-agent-protocol/docs/00-design-specification.md +0 -496
  205. package/references/multi-agent-protocol/docs/01-open-questions.md +0 -1050
  206. package/references/multi-agent-protocol/docs/02-wire-protocol.md +0 -296
  207. package/references/multi-agent-protocol/docs/03-streaming-semantics.md +0 -252
  208. package/references/multi-agent-protocol/docs/04-error-handling.md +0 -231
  209. package/references/multi-agent-protocol/docs/05-connection-model.md +0 -244
  210. package/references/multi-agent-protocol/docs/06-visibility-permissions.md +0 -243
  211. package/references/multi-agent-protocol/docs/07-federation.md +0 -335
  212. package/references/multi-agent-protocol/docs/08-macro-agent-migration.md +0 -253
  213. package/references/multi-agent-protocol/docs/09-authentication.md +0 -748
  214. package/references/multi-agent-protocol/docs/10-environment-awareness.md +0 -242
  215. package/references/multi-agent-protocol/docs/10-mail-protocol.md +0 -553
  216. package/references/multi-agent-protocol/docs/11-anp-inspired-improvements.md +0 -1079
  217. package/references/multi-agent-protocol/docs/11-trajectory-protocol.md +0 -292
  218. package/references/multi-agent-protocol/docs/12-anp-implementation-plan.md +0 -641
  219. package/references/multi-agent-protocol/docs/agent-iam-integration.md +0 -877
  220. package/references/multi-agent-protocol/docs/agentic-mesh-integration-draft.md +0 -459
  221. package/references/multi-agent-protocol/docs/git-transport-draft.md +0 -251
  222. package/references/multi-agent-protocol/docs-site/Gemfile +0 -22
  223. package/references/multi-agent-protocol/docs-site/README.md +0 -82
  224. package/references/multi-agent-protocol/docs-site/_config.yml +0 -91
  225. package/references/multi-agent-protocol/docs-site/_includes/head_custom.html +0 -20
  226. package/references/multi-agent-protocol/docs-site/_sass/color_schemes/map.scss +0 -42
  227. package/references/multi-agent-protocol/docs-site/_sass/custom/custom.scss +0 -34
  228. package/references/multi-agent-protocol/docs-site/examples/full-integration.md +0 -510
  229. package/references/multi-agent-protocol/docs-site/examples/index.md +0 -138
  230. package/references/multi-agent-protocol/docs-site/examples/simple-chat.md +0 -282
  231. package/references/multi-agent-protocol/docs-site/examples/task-queue.md +0 -399
  232. package/references/multi-agent-protocol/docs-site/getting-started/index.md +0 -98
  233. package/references/multi-agent-protocol/docs-site/getting-started/installation.md +0 -219
  234. package/references/multi-agent-protocol/docs-site/getting-started/overview.md +0 -172
  235. package/references/multi-agent-protocol/docs-site/getting-started/quickstart.md +0 -237
  236. package/references/multi-agent-protocol/docs-site/index.md +0 -136
  237. package/references/multi-agent-protocol/docs-site/protocol/authentication.md +0 -391
  238. package/references/multi-agent-protocol/docs-site/protocol/connection-model.md +0 -376
  239. package/references/multi-agent-protocol/docs-site/protocol/design.md +0 -284
  240. package/references/multi-agent-protocol/docs-site/protocol/error-handling.md +0 -312
  241. package/references/multi-agent-protocol/docs-site/protocol/federation.md +0 -449
  242. package/references/multi-agent-protocol/docs-site/protocol/index.md +0 -129
  243. package/references/multi-agent-protocol/docs-site/protocol/permissions.md +0 -398
  244. package/references/multi-agent-protocol/docs-site/protocol/streaming.md +0 -353
  245. package/references/multi-agent-protocol/docs-site/protocol/wire-protocol.md +0 -369
  246. package/references/multi-agent-protocol/docs-site/sdk/api/agent.md +0 -357
  247. package/references/multi-agent-protocol/docs-site/sdk/api/client.md +0 -380
  248. package/references/multi-agent-protocol/docs-site/sdk/api/index.md +0 -62
  249. package/references/multi-agent-protocol/docs-site/sdk/api/server.md +0 -453
  250. package/references/multi-agent-protocol/docs-site/sdk/api/types.md +0 -468
  251. package/references/multi-agent-protocol/docs-site/sdk/guides/agent.md +0 -375
  252. package/references/multi-agent-protocol/docs-site/sdk/guides/authentication.md +0 -405
  253. package/references/multi-agent-protocol/docs-site/sdk/guides/client.md +0 -352
  254. package/references/multi-agent-protocol/docs-site/sdk/guides/index.md +0 -89
  255. package/references/multi-agent-protocol/docs-site/sdk/guides/server.md +0 -360
  256. package/references/multi-agent-protocol/docs-site/sdk/guides/testing.md +0 -446
  257. package/references/multi-agent-protocol/docs-site/sdk/guides/transports.md +0 -363
  258. package/references/multi-agent-protocol/docs-site/sdk/index.md +0 -206
  259. package/references/multi-agent-protocol/package-lock.json +0 -4230
  260. package/references/multi-agent-protocol/package.json +0 -56
  261. package/references/multi-agent-protocol/schema/meta.json +0 -584
  262. package/references/multi-agent-protocol/schema/schema.json +0 -3067
  263. package/references/openhive/.claude/settings.json +0 -6
  264. package/references/openhive/.dockerignore +0 -54
  265. package/references/openhive/.github/workflows/docker.yml +0 -52
  266. package/references/openhive/.sudocode/issues.jsonl +0 -24
  267. package/references/openhive/.sudocode/specs.jsonl +0 -4
  268. package/references/openhive/CLAUDE.md +0 -88
  269. package/references/openhive/Dockerfile +0 -105
  270. package/references/openhive/README.md +0 -745
  271. package/references/openhive/bin/openhive.js +0 -6
  272. package/references/openhive/cloudbuild.yaml +0 -80
  273. package/references/openhive/deploy/cloud-run.sh +0 -106
  274. package/references/openhive/deploy/openhive.env.example +0 -80
  275. package/references/openhive/deploy/openhive.service +0 -91
  276. package/references/openhive/docker-compose.yml +0 -67
  277. package/references/openhive/docker-entrypoint.sh +0 -117
  278. package/references/openhive/docs/API_MIGRATION.md +0 -176
  279. package/references/openhive/docs/DEPLOYMENT.md +0 -847
  280. package/references/openhive/docs/DESIGN_v1.md +0 -489
  281. package/references/openhive/docs/DESIGN_v2.md +0 -564
  282. package/references/openhive/docs/HEADSCALE_HOSTING_SPEC.md +0 -513
  283. package/references/openhive/docs/HIVE_SYNC_DESIGN.md +0 -2362
  284. package/references/openhive/docs/HIVE_SYNC_IMPLEMENTATION_PLAN.md +0 -1169
  285. package/references/openhive/docs/HOSTING.md +0 -601
  286. package/references/openhive/docs/IMPLEMENTATION_PLAN.md +0 -428
  287. package/references/openhive/docs/LOCAL_SETUP.md +0 -506
  288. package/references/openhive/docs/MACRO_AGENT_ATLAS_EXTENSION.md +0 -351
  289. package/references/openhive/docs/MEMORY_BANK_SYNC_SPEC.md +0 -909
  290. package/references/openhive/docs/PLAN_v1.md +0 -471
  291. package/references/openhive/docs/PLAN_v2.md +0 -623
  292. package/references/openhive/docs/WEBSOCKET.md +0 -267
  293. package/references/openhive/docs/openswarm-bootstrap-token-spec.md +0 -240
  294. package/references/openhive/ecosystem.config.cjs +0 -76
  295. package/references/openhive/fly.toml +0 -63
  296. package/references/openhive/package-lock.json +0 -17640
  297. package/references/openhive/package.json +0 -128
  298. package/references/openhive/packages/openhive-types/package-lock.json +0 -1473
  299. package/references/openhive/packages/openhive-types/package.json +0 -42
  300. package/references/openhive/packages/openhive-types/src/index.ts +0 -36
  301. package/references/openhive/packages/openhive-types/src/map-coordination.ts +0 -92
  302. package/references/openhive/packages/openhive-types/src/map-session-sync.ts +0 -50
  303. package/references/openhive/packages/openhive-types/src/map-sync.ts +0 -68
  304. package/references/openhive/packages/openhive-types/tsconfig.json +0 -15
  305. package/references/openhive/packages/openhive-types/tsconfig.tsbuildinfo +0 -1
  306. package/references/openhive/packages/openhive-types/tsup.config.ts +0 -12
  307. package/references/openhive/railway.json +0 -13
  308. package/references/openhive/railway.toml +0 -24
  309. package/references/openhive/render.yaml +0 -51
  310. package/references/openhive/src/__tests__/auth.test.ts +0 -148
  311. package/references/openhive/src/__tests__/bridge/credentials.test.ts +0 -65
  312. package/references/openhive/src/__tests__/bridge/dal.test.ts +0 -279
  313. package/references/openhive/src/__tests__/bridge/inbound.test.ts +0 -349
  314. package/references/openhive/src/__tests__/bridge/manager.test.ts +0 -419
  315. package/references/openhive/src/__tests__/bridge/mentions.test.ts +0 -83
  316. package/references/openhive/src/__tests__/bridge/outbound.test.ts +0 -209
  317. package/references/openhive/src/__tests__/bridge/slack-adapter.test.ts +0 -276
  318. package/references/openhive/src/__tests__/cli.test.ts +0 -342
  319. package/references/openhive/src/__tests__/config.test.ts +0 -205
  320. package/references/openhive/src/__tests__/coordination/coordination.test.ts +0 -1072
  321. package/references/openhive/src/__tests__/coordination/cross-instance.test.ts +0 -540
  322. package/references/openhive/src/__tests__/coordination/e2e.test.ts +0 -780
  323. package/references/openhive/src/__tests__/data-dir.test.ts +0 -332
  324. package/references/openhive/src/__tests__/db.test.ts +0 -258
  325. package/references/openhive/src/__tests__/discovery.test.ts +0 -288
  326. package/references/openhive/src/__tests__/events/dal.test.ts +0 -371
  327. package/references/openhive/src/__tests__/events/dispatch.test.ts +0 -202
  328. package/references/openhive/src/__tests__/events/e2e.test.ts +0 -528
  329. package/references/openhive/src/__tests__/events/normalizers.test.ts +0 -263
  330. package/references/openhive/src/__tests__/events/router.test.ts +0 -314
  331. package/references/openhive/src/__tests__/events/routes.test.ts +0 -407
  332. package/references/openhive/src/__tests__/follows.test.ts +0 -328
  333. package/references/openhive/src/__tests__/helpers/test-dirs.ts +0 -44
  334. package/references/openhive/src/__tests__/ingest-keys.test.ts +0 -925
  335. package/references/openhive/src/__tests__/map/sync-client-content.test.ts +0 -288
  336. package/references/openhive/src/__tests__/map/sync-client.test.ts +0 -500
  337. package/references/openhive/src/__tests__/map/sync-listener.test.ts +0 -504
  338. package/references/openhive/src/__tests__/middleware/hostname-guard.test.ts +0 -73
  339. package/references/openhive/src/__tests__/migrations.test.ts +0 -260
  340. package/references/openhive/src/__tests__/opentasks/client.test.ts +0 -497
  341. package/references/openhive/src/__tests__/opentasks/discovery.test.ts +0 -283
  342. package/references/openhive/src/__tests__/opentasks/e2e.test.ts +0 -767
  343. package/references/openhive/src/__tests__/routes/agents.test.ts +0 -417
  344. package/references/openhive/src/__tests__/routes/opentasks-content.test.ts +0 -493
  345. package/references/openhive/src/__tests__/routes/resource-content.test.ts +0 -1741
  346. package/references/openhive/src/__tests__/sessions/adapters.test.ts +0 -524
  347. package/references/openhive/src/__tests__/sessions/routes.test.ts +0 -1053
  348. package/references/openhive/src/__tests__/sessions/storage.test.ts +0 -545
  349. package/references/openhive/src/__tests__/sessions/trajectory-checkpoints.test.ts +0 -349
  350. package/references/openhive/src/__tests__/sessions/trajectory-routes.test.ts +0 -290
  351. package/references/openhive/src/__tests__/swarm/config.test.ts +0 -125
  352. package/references/openhive/src/__tests__/swarm/credentials.test.ts +0 -254
  353. package/references/openhive/src/__tests__/swarm/dal.test.ts +0 -290
  354. package/references/openhive/src/__tests__/swarm/e2e.test.ts +0 -827
  355. package/references/openhive/src/__tests__/swarm/fixtures/exit-immediately.js +0 -3
  356. package/references/openhive/src/__tests__/swarm/fixtures/map-server.js +0 -147
  357. package/references/openhive/src/__tests__/swarm/fixtures/sleep-server.js +0 -52
  358. package/references/openhive/src/__tests__/swarm/local-provider.test.ts +0 -279
  359. package/references/openhive/src/__tests__/swarm/manager.test.ts +0 -305
  360. package/references/openhive/src/__tests__/swarm/routes.test.ts +0 -396
  361. package/references/openhive/src/__tests__/swarm/workspace.test.ts +0 -257
  362. package/references/openhive/src/__tests__/swarmhub/client.test.ts +0 -324
  363. package/references/openhive/src/__tests__/swarmhub/config.test.ts +0 -213
  364. package/references/openhive/src/__tests__/swarmhub/connector.test.ts +0 -581
  365. package/references/openhive/src/__tests__/swarmhub/routes.test.ts +0 -639
  366. package/references/openhive/src/__tests__/swarmhub/slack-client.test.ts +0 -164
  367. package/references/openhive/src/__tests__/swarmhub/slack-connector.test.ts +0 -164
  368. package/references/openhive/src/__tests__/swarmhub/slack-routes.test.ts +0 -373
  369. package/references/openhive/src/__tests__/swarmhub/webhook-handler.test.ts +0 -295
  370. package/references/openhive/src/__tests__/sync/resource-sync.test.ts +0 -1418
  371. package/references/openhive/src/__tests__/sync/sync.test.ts +0 -800
  372. package/references/openhive/src/api/index.ts +0 -65
  373. package/references/openhive/src/api/middleware/auth.ts +0 -227
  374. package/references/openhive/src/api/middleware/hostname-guard.ts +0 -38
  375. package/references/openhive/src/api/routes/admin.ts +0 -366
  376. package/references/openhive/src/api/routes/agents.ts +0 -223
  377. package/references/openhive/src/api/routes/auth.ts +0 -164
  378. package/references/openhive/src/api/routes/bridges.ts +0 -384
  379. package/references/openhive/src/api/routes/comments.ts +0 -294
  380. package/references/openhive/src/api/routes/coordination.ts +0 -312
  381. package/references/openhive/src/api/routes/events.ts +0 -158
  382. package/references/openhive/src/api/routes/federation.ts +0 -367
  383. package/references/openhive/src/api/routes/feed.ts +0 -212
  384. package/references/openhive/src/api/routes/hives.ts +0 -264
  385. package/references/openhive/src/api/routes/map.ts +0 -674
  386. package/references/openhive/src/api/routes/memory-banks.ts +0 -971
  387. package/references/openhive/src/api/routes/posts.ts +0 -342
  388. package/references/openhive/src/api/routes/resource-content.ts +0 -727
  389. package/references/openhive/src/api/routes/resources.ts +0 -1013
  390. package/references/openhive/src/api/routes/search.ts +0 -45
  391. package/references/openhive/src/api/routes/sessions.ts +0 -1187
  392. package/references/openhive/src/api/routes/swarm-hosting.ts +0 -313
  393. package/references/openhive/src/api/routes/sync-protocol.ts +0 -168
  394. package/references/openhive/src/api/routes/sync.ts +0 -279
  395. package/references/openhive/src/api/routes/uploads.ts +0 -174
  396. package/references/openhive/src/api/routes/webhooks.ts +0 -603
  397. package/references/openhive/src/api/schemas/agents.ts +0 -26
  398. package/references/openhive/src/api/schemas/comments.ts +0 -22
  399. package/references/openhive/src/api/schemas/hives.ts +0 -33
  400. package/references/openhive/src/api/schemas/posts.ts +0 -37
  401. package/references/openhive/src/api/schemas/sync.ts +0 -56
  402. package/references/openhive/src/auth/index.ts +0 -2
  403. package/references/openhive/src/auth/jwks.ts +0 -58
  404. package/references/openhive/src/bridge/adapters/slack.ts +0 -306
  405. package/references/openhive/src/bridge/credentials.ts +0 -72
  406. package/references/openhive/src/bridge/inbound.ts +0 -288
  407. package/references/openhive/src/bridge/index.ts +0 -42
  408. package/references/openhive/src/bridge/manager.ts +0 -425
  409. package/references/openhive/src/bridge/mentions.ts +0 -42
  410. package/references/openhive/src/bridge/outbound.ts +0 -103
  411. package/references/openhive/src/bridge/schema.ts +0 -82
  412. package/references/openhive/src/bridge/types.ts +0 -238
  413. package/references/openhive/src/cli/network.ts +0 -480
  414. package/references/openhive/src/cli.ts +0 -620
  415. package/references/openhive/src/config.ts +0 -611
  416. package/references/openhive/src/coordination/index.ts +0 -43
  417. package/references/openhive/src/coordination/listener.ts +0 -92
  418. package/references/openhive/src/coordination/schema.ts +0 -79
  419. package/references/openhive/src/coordination/service.ts +0 -233
  420. package/references/openhive/src/coordination/types.ts +0 -177
  421. package/references/openhive/src/data-dir.ts +0 -105
  422. package/references/openhive/src/db/adapters/index.ts +0 -21
  423. package/references/openhive/src/db/adapters/postgres.ts +0 -310
  424. package/references/openhive/src/db/adapters/sqlite.ts +0 -56
  425. package/references/openhive/src/db/adapters/types.ts +0 -65
  426. package/references/openhive/src/db/dal/agents.ts +0 -430
  427. package/references/openhive/src/db/dal/bridge.ts +0 -336
  428. package/references/openhive/src/db/dal/comments.ts +0 -213
  429. package/references/openhive/src/db/dal/coordination.ts +0 -361
  430. package/references/openhive/src/db/dal/events.ts +0 -381
  431. package/references/openhive/src/db/dal/follows.ts +0 -96
  432. package/references/openhive/src/db/dal/hives.ts +0 -198
  433. package/references/openhive/src/db/dal/ingest-keys.ts +0 -176
  434. package/references/openhive/src/db/dal/instances.ts +0 -196
  435. package/references/openhive/src/db/dal/invites.ts +0 -123
  436. package/references/openhive/src/db/dal/map.ts +0 -750
  437. package/references/openhive/src/db/dal/posts.ts +0 -274
  438. package/references/openhive/src/db/dal/remote-agents.ts +0 -56
  439. package/references/openhive/src/db/dal/search.ts +0 -238
  440. package/references/openhive/src/db/dal/sync-events.ts +0 -160
  441. package/references/openhive/src/db/dal/sync-groups.ts +0 -100
  442. package/references/openhive/src/db/dal/sync-peer-configs.ts +0 -216
  443. package/references/openhive/src/db/dal/sync-peers.ts +0 -145
  444. package/references/openhive/src/db/dal/syncable-resources.ts +0 -888
  445. package/references/openhive/src/db/dal/trajectory-checkpoints.ts +0 -291
  446. package/references/openhive/src/db/dal/uploads.ts +0 -124
  447. package/references/openhive/src/db/dal/votes.ts +0 -124
  448. package/references/openhive/src/db/index.ts +0 -293
  449. package/references/openhive/src/db/providers/index.ts +0 -75
  450. package/references/openhive/src/db/providers/postgres.ts +0 -529
  451. package/references/openhive/src/db/providers/sqlite.ts +0 -1383
  452. package/references/openhive/src/db/providers/turso.ts +0 -1360
  453. package/references/openhive/src/db/providers/types.ts +0 -516
  454. package/references/openhive/src/db/schema.ts +0 -641
  455. package/references/openhive/src/discovery/index.ts +0 -403
  456. package/references/openhive/src/events/dispatch.ts +0 -106
  457. package/references/openhive/src/events/index.ts +0 -17
  458. package/references/openhive/src/events/normalizers/github.ts +0 -133
  459. package/references/openhive/src/events/normalizers/index.ts +0 -62
  460. package/references/openhive/src/events/normalizers/slack.ts +0 -50
  461. package/references/openhive/src/events/router.ts +0 -156
  462. package/references/openhive/src/events/schema.ts +0 -66
  463. package/references/openhive/src/events/types.ts +0 -130
  464. package/references/openhive/src/federation/index.ts +0 -1
  465. package/references/openhive/src/federation/service.ts +0 -776
  466. package/references/openhive/src/headscale/client.ts +0 -256
  467. package/references/openhive/src/headscale/config.ts +0 -212
  468. package/references/openhive/src/headscale/index.ts +0 -23
  469. package/references/openhive/src/headscale/manager.ts +0 -249
  470. package/references/openhive/src/headscale/sync.ts +0 -272
  471. package/references/openhive/src/headscale/types.ts +0 -231
  472. package/references/openhive/src/index.ts +0 -225
  473. package/references/openhive/src/map/client-entry.ts +0 -26
  474. package/references/openhive/src/map/index.ts +0 -76
  475. package/references/openhive/src/map/schema.ts +0 -119
  476. package/references/openhive/src/map/service.ts +0 -323
  477. package/references/openhive/src/map/sync-client.ts +0 -696
  478. package/references/openhive/src/map/sync-listener.ts +0 -409
  479. package/references/openhive/src/map/types.ts +0 -290
  480. package/references/openhive/src/network/factory.ts +0 -118
  481. package/references/openhive/src/network/headscale-provider.ts +0 -437
  482. package/references/openhive/src/network/index.ts +0 -43
  483. package/references/openhive/src/network/tailscale-client.ts +0 -289
  484. package/references/openhive/src/network/tailscale-provider.ts +0 -287
  485. package/references/openhive/src/network/types.ts +0 -178
  486. package/references/openhive/src/opentasks-client/client.ts +0 -374
  487. package/references/openhive/src/opentasks-client/index.ts +0 -7
  488. package/references/openhive/src/realtime/index.ts +0 -282
  489. package/references/openhive/src/server.ts +0 -1069
  490. package/references/openhive/src/services/email.ts +0 -177
  491. package/references/openhive/src/services/sitemap.ts +0 -135
  492. package/references/openhive/src/sessions/adapters/claude.ts +0 -466
  493. package/references/openhive/src/sessions/adapters/codex.ts +0 -265
  494. package/references/openhive/src/sessions/adapters/index.ts +0 -263
  495. package/references/openhive/src/sessions/adapters/raw.ts +0 -144
  496. package/references/openhive/src/sessions/adapters/types.ts +0 -83
  497. package/references/openhive/src/sessions/index.ts +0 -50
  498. package/references/openhive/src/sessions/storage/adapters/gcs.ts +0 -277
  499. package/references/openhive/src/sessions/storage/adapters/local.ts +0 -240
  500. package/references/openhive/src/sessions/storage/adapters/s3.ts +0 -321
  501. package/references/openhive/src/sessions/storage/index.ts +0 -231
  502. package/references/openhive/src/sessions/storage/types.ts +0 -189
  503. package/references/openhive/src/sessions/types.ts +0 -415
  504. package/references/openhive/src/shared/types/index.ts +0 -45
  505. package/references/openhive/src/shared/types/map-coordination.ts +0 -92
  506. package/references/openhive/src/shared/types/map-session-sync.ts +0 -170
  507. package/references/openhive/src/shared/types/map-sync.ts +0 -68
  508. package/references/openhive/src/skill.ts +0 -203
  509. package/references/openhive/src/storage/adapters/local.ts +0 -169
  510. package/references/openhive/src/storage/adapters/s3.ts +0 -195
  511. package/references/openhive/src/storage/index.ts +0 -64
  512. package/references/openhive/src/storage/types.ts +0 -69
  513. package/references/openhive/src/swarm/credentials.ts +0 -98
  514. package/references/openhive/src/swarm/dal.ts +0 -206
  515. package/references/openhive/src/swarm/index.ts +0 -28
  516. package/references/openhive/src/swarm/manager.ts +0 -917
  517. package/references/openhive/src/swarm/providers/local.ts +0 -338
  518. package/references/openhive/src/swarm/providers/sandboxed-local.ts +0 -478
  519. package/references/openhive/src/swarm/providers/workspace.ts +0 -52
  520. package/references/openhive/src/swarm/schema.ts +0 -43
  521. package/references/openhive/src/swarm/types.ts +0 -333
  522. package/references/openhive/src/swarmhub/client.ts +0 -279
  523. package/references/openhive/src/swarmhub/connector.ts +0 -463
  524. package/references/openhive/src/swarmhub/index.ts +0 -43
  525. package/references/openhive/src/swarmhub/routes.ts +0 -296
  526. package/references/openhive/src/swarmhub/types.ts +0 -213
  527. package/references/openhive/src/swarmhub/webhook-handler.ts +0 -126
  528. package/references/openhive/src/sync/compaction.ts +0 -193
  529. package/references/openhive/src/sync/coordination-hooks.ts +0 -154
  530. package/references/openhive/src/sync/crypto.ts +0 -79
  531. package/references/openhive/src/sync/gossip.ts +0 -136
  532. package/references/openhive/src/sync/hooks.ts +0 -202
  533. package/references/openhive/src/sync/materializer-repo.ts +0 -256
  534. package/references/openhive/src/sync/materializer.ts +0 -682
  535. package/references/openhive/src/sync/middleware.ts +0 -140
  536. package/references/openhive/src/sync/peer-resolver.ts +0 -157
  537. package/references/openhive/src/sync/resource-hooks.ts +0 -161
  538. package/references/openhive/src/sync/schema.ts +0 -158
  539. package/references/openhive/src/sync/service.ts +0 -990
  540. package/references/openhive/src/sync/types.ts +0 -369
  541. package/references/openhive/src/terminal/index.ts +0 -4
  542. package/references/openhive/src/terminal/pty-manager.ts +0 -337
  543. package/references/openhive/src/terminal/resolve-tui.ts +0 -44
  544. package/references/openhive/src/terminal/terminal-ws.ts +0 -251
  545. package/references/openhive/src/types.ts +0 -442
  546. package/references/openhive/src/utils/git-remote.ts +0 -329
  547. package/references/openhive/src/web/App.tsx +0 -77
  548. package/references/openhive/src/web/__tests__/components/dashboard/RecentActivity.test.tsx +0 -77
  549. package/references/openhive/src/web/__tests__/components/dashboard/StatsOverview.test.tsx +0 -62
  550. package/references/openhive/src/web/__tests__/components/dashboard/SwarmStatusSummary.test.tsx +0 -122
  551. package/references/openhive/src/web/__tests__/components/dashboard/SyncResourcesStatus.test.tsx +0 -104
  552. package/references/openhive/src/web/__tests__/components/layout/Sidebar.test.tsx +0 -110
  553. package/references/openhive/src/web/__tests__/components/swarm/StatusBadges.test.tsx +0 -65
  554. package/references/openhive/src/web/__tests__/components/terminal/query-responses.test.ts +0 -143
  555. package/references/openhive/src/web/__tests__/components/terminal/terminal-mouse.test.ts +0 -509
  556. package/references/openhive/src/web/__tests__/hooks/useEventsApi.test.ts +0 -378
  557. package/references/openhive/src/web/__tests__/pages/Dashboard.test.tsx +0 -57
  558. package/references/openhive/src/web/__tests__/pages/Events.test.tsx +0 -886
  559. package/references/openhive/src/web/__tests__/pages/Explore.test.tsx +0 -63
  560. package/references/openhive/src/web/__tests__/routing.test.tsx +0 -79
  561. package/references/openhive/src/web/__tests__/setup.ts +0 -37
  562. package/references/openhive/src/web/__tests__/stores/dashboard.test.ts +0 -49
  563. package/references/openhive/src/web/components/common/AgentBadge.tsx +0 -58
  564. package/references/openhive/src/web/components/common/Avatar.tsx +0 -78
  565. package/references/openhive/src/web/components/common/ErrorBoundary.tsx +0 -76
  566. package/references/openhive/src/web/components/common/Highlight.tsx +0 -79
  567. package/references/openhive/src/web/components/common/ImageUpload.tsx +0 -209
  568. package/references/openhive/src/web/components/common/LoadingSpinner.tsx +0 -37
  569. package/references/openhive/src/web/components/common/Logo.tsx +0 -21
  570. package/references/openhive/src/web/components/common/Markdown.tsx +0 -53
  571. package/references/openhive/src/web/components/common/ProtectedRoute.tsx +0 -18
  572. package/references/openhive/src/web/components/common/ThemeToggle.tsx +0 -38
  573. package/references/openhive/src/web/components/common/TimeAgo.tsx +0 -17
  574. package/references/openhive/src/web/components/common/Toast.tsx +0 -70
  575. package/references/openhive/src/web/components/common/VoteButtons.tsx +0 -100
  576. package/references/openhive/src/web/components/dashboard/RecentActivity.tsx +0 -100
  577. package/references/openhive/src/web/components/dashboard/StatsOverview.tsx +0 -40
  578. package/references/openhive/src/web/components/dashboard/SwarmStatusSummary.tsx +0 -89
  579. package/references/openhive/src/web/components/dashboard/SyncResourcesStatus.tsx +0 -81
  580. package/references/openhive/src/web/components/feed/FeedControls.tsx +0 -38
  581. package/references/openhive/src/web/components/feed/NewPostsIndicator.tsx +0 -75
  582. package/references/openhive/src/web/components/feed/PostCard.tsx +0 -129
  583. package/references/openhive/src/web/components/feed/PostList.tsx +0 -83
  584. package/references/openhive/src/web/components/layout/Footer.tsx +0 -5
  585. package/references/openhive/src/web/components/layout/Layout.tsx +0 -29
  586. package/references/openhive/src/web/components/layout/Sidebar.tsx +0 -348
  587. package/references/openhive/src/web/components/post/CommentForm.tsx +0 -59
  588. package/references/openhive/src/web/components/post/CommentTree.tsx +0 -145
  589. package/references/openhive/src/web/components/resources/MemoryBrowser.tsx +0 -208
  590. package/references/openhive/src/web/components/resources/OpenTasksSummary.tsx +0 -138
  591. package/references/openhive/src/web/components/resources/SkillBrowser.tsx +0 -284
  592. package/references/openhive/src/web/components/swarm/StatusBadges.tsx +0 -56
  593. package/references/openhive/src/web/components/terminal/TerminalPanel.tsx +0 -485
  594. package/references/openhive/src/web/components/terminal/index.ts +0 -2
  595. package/references/openhive/src/web/components/terminal/query-responses.ts +0 -70
  596. package/references/openhive/src/web/components/terminal/terminal-mouse.ts +0 -222
  597. package/references/openhive/src/web/hooks/useApi.ts +0 -740
  598. package/references/openhive/src/web/hooks/useDocumentTitle.ts +0 -49
  599. package/references/openhive/src/web/hooks/useInfiniteScroll.ts +0 -58
  600. package/references/openhive/src/web/hooks/useRealtimeUpdates.ts +0 -154
  601. package/references/openhive/src/web/hooks/useWebSocket.ts +0 -225
  602. package/references/openhive/src/web/index.html +0 -73
  603. package/references/openhive/src/web/lib/api.ts +0 -518
  604. package/references/openhive/src/web/main.tsx +0 -32
  605. package/references/openhive/src/web/pages/About.tsx +0 -131
  606. package/references/openhive/src/web/pages/Agent.tsx +0 -130
  607. package/references/openhive/src/web/pages/Agents.tsx +0 -69
  608. package/references/openhive/src/web/pages/AuthCallback.tsx +0 -75
  609. package/references/openhive/src/web/pages/Dashboard.tsx +0 -41
  610. package/references/openhive/src/web/pages/Events.tsx +0 -1025
  611. package/references/openhive/src/web/pages/Explore.tsx +0 -43
  612. package/references/openhive/src/web/pages/Hive.tsx +0 -134
  613. package/references/openhive/src/web/pages/Hives.tsx +0 -64
  614. package/references/openhive/src/web/pages/Home.tsx +0 -43
  615. package/references/openhive/src/web/pages/Login.tsx +0 -122
  616. package/references/openhive/src/web/pages/Post.tsx +0 -216
  617. package/references/openhive/src/web/pages/ResourceDetail.tsx +0 -426
  618. package/references/openhive/src/web/pages/Resources.tsx +0 -276
  619. package/references/openhive/src/web/pages/Search.tsx +0 -234
  620. package/references/openhive/src/web/pages/SessionDetail.tsx +0 -703
  621. package/references/openhive/src/web/pages/Sessions.tsx +0 -129
  622. package/references/openhive/src/web/pages/Settings.tsx +0 -826
  623. package/references/openhive/src/web/pages/SwarmCraft.tsx +0 -16
  624. package/references/openhive/src/web/pages/Swarms.tsx +0 -981
  625. package/references/openhive/src/web/pages/Terminal.tsx +0 -69
  626. package/references/openhive/src/web/postcss.config.js +0 -5
  627. package/references/openhive/src/web/public/favicon.svg +0 -11
  628. package/references/openhive/src/web/public/manifest.json +0 -21
  629. package/references/openhive/src/web/stores/auth.ts +0 -207
  630. package/references/openhive/src/web/stores/dashboard.ts +0 -23
  631. package/references/openhive/src/web/stores/realtime.ts +0 -90
  632. package/references/openhive/src/web/stores/theme.ts +0 -70
  633. package/references/openhive/src/web/stores/toast.ts +0 -63
  634. package/references/openhive/src/web/styles/globals.css +0 -503
  635. package/references/openhive/src/web/sw.ts +0 -228
  636. package/references/openhive/src/web/utils/serviceWorker.ts +0 -86
  637. package/references/openhive/src/web/vite.config.ts +0 -81
  638. package/references/openhive/tsconfig.json +0 -32
  639. package/references/openhive/tsup.config.ts +0 -17
  640. package/references/openhive/vitest.config.ts +0 -30
  641. package/references/openhive/vitest.web.config.ts +0 -20
  642. package/references/opentasks/.claude/settings.json +0 -6
  643. package/references/opentasks/.claude-plugin/plugin.json +0 -20
  644. package/references/opentasks/.lintstagedrc.json +0 -4
  645. package/references/opentasks/.prettierignore +0 -4
  646. package/references/opentasks/.prettierrc.json +0 -11
  647. package/references/opentasks/.sudocode/issues.jsonl +0 -89
  648. package/references/opentasks/.sudocode/specs.jsonl +0 -24
  649. package/references/opentasks/README.md +0 -401
  650. package/references/opentasks/docs/ARCHITECTURE.md +0 -841
  651. package/references/opentasks/docs/DESIGN.md +0 -689
  652. package/references/opentasks/docs/INTERFACE.md +0 -670
  653. package/references/opentasks/docs/PERSISTENCE.md +0 -1638
  654. package/references/opentasks/docs/PROVIDERS.md +0 -1412
  655. package/references/opentasks/docs/SCHEMA.md +0 -815
  656. package/references/opentasks/docs/TESTING.md +0 -1081
  657. package/references/opentasks/eslint.config.js +0 -58
  658. package/references/opentasks/package-lock.json +0 -4348
  659. package/references/opentasks/package.json +0 -81
  660. package/references/opentasks/skills/opentasks/SKILL.md +0 -139
  661. package/references/opentasks/skills/opentasks/dependency-management.md +0 -119
  662. package/references/opentasks/skills/opentasks/feedback-and-review.md +0 -100
  663. package/references/opentasks/skills/opentasks/linking-external-data.md +0 -103
  664. package/references/opentasks/skills/opentasks/spec-to-implementation.md +0 -98
  665. package/references/opentasks/src/__tests__/cli-tools.test.ts +0 -800
  666. package/references/opentasks/src/__tests__/cli.test.ts +0 -97
  667. package/references/opentasks/src/__tests__/p1-p3-gaps.test.ts +0 -635
  668. package/references/opentasks/src/cli.ts +0 -929
  669. package/references/opentasks/src/client/__tests__/client-crud.test.ts +0 -546
  670. package/references/opentasks/src/client/__tests__/client.test.ts +0 -658
  671. package/references/opentasks/src/client/__tests__/socket-discovery.test.ts +0 -122
  672. package/references/opentasks/src/client/client.ts +0 -560
  673. package/references/opentasks/src/client/index.ts +0 -32
  674. package/references/opentasks/src/config/__tests__/defaults.test.ts +0 -66
  675. package/references/opentasks/src/config/__tests__/env.test.ts +0 -155
  676. package/references/opentasks/src/config/__tests__/index.test.ts +0 -148
  677. package/references/opentasks/src/config/__tests__/loader.test.ts +0 -173
  678. package/references/opentasks/src/config/__tests__/merge.test.ts +0 -121
  679. package/references/opentasks/src/config/__tests__/schema.test.ts +0 -446
  680. package/references/opentasks/src/config/defaults.ts +0 -18
  681. package/references/opentasks/src/config/env.ts +0 -170
  682. package/references/opentasks/src/config/errors.ts +0 -33
  683. package/references/opentasks/src/config/index.ts +0 -63
  684. package/references/opentasks/src/config/loader.ts +0 -90
  685. package/references/opentasks/src/config/merge.ts +0 -64
  686. package/references/opentasks/src/config/schema.ts +0 -767
  687. package/references/opentasks/src/core/__tests__/conditional-redirects.test.ts +0 -116
  688. package/references/opentasks/src/core/__tests__/connections.test.ts +0 -194
  689. package/references/opentasks/src/core/__tests__/hash.test.ts +0 -161
  690. package/references/opentasks/src/core/__tests__/id.test.ts +0 -175
  691. package/references/opentasks/src/core/__tests__/init.test.ts +0 -115
  692. package/references/opentasks/src/core/__tests__/location.test.ts +0 -94
  693. package/references/opentasks/src/core/__tests__/merge-driver.test.ts +0 -300
  694. package/references/opentasks/src/core/__tests__/redirects.test.ts +0 -169
  695. package/references/opentasks/src/core/__tests__/resolve-location-target.test.ts +0 -468
  696. package/references/opentasks/src/core/__tests__/uri.test.ts +0 -228
  697. package/references/opentasks/src/core/__tests__/worktree.test.ts +0 -160
  698. package/references/opentasks/src/core/conditional-redirects.ts +0 -100
  699. package/references/opentasks/src/core/connections.ts +0 -217
  700. package/references/opentasks/src/core/discover.ts +0 -195
  701. package/references/opentasks/src/core/hash.ts +0 -74
  702. package/references/opentasks/src/core/id.ts +0 -174
  703. package/references/opentasks/src/core/index.ts +0 -108
  704. package/references/opentasks/src/core/init.ts +0 -66
  705. package/references/opentasks/src/core/location.ts +0 -139
  706. package/references/opentasks/src/core/merge-driver.ts +0 -280
  707. package/references/opentasks/src/core/redirects.ts +0 -182
  708. package/references/opentasks/src/core/uri.ts +0 -270
  709. package/references/opentasks/src/core/worktree.ts +0 -504
  710. package/references/opentasks/src/daemon/__tests__/e2e-live-agent.test.ts +0 -344
  711. package/references/opentasks/src/daemon/__tests__/e2e-session-pipeline.test.ts +0 -447
  712. package/references/opentasks/src/daemon/__tests__/e2e-watch.test.ts +0 -279
  713. package/references/opentasks/src/daemon/__tests__/entire-linker.test.ts +0 -1074
  714. package/references/opentasks/src/daemon/__tests__/entire-watcher.test.ts +0 -659
  715. package/references/opentasks/src/daemon/__tests__/flush.test.ts +0 -306
  716. package/references/opentasks/src/daemon/__tests__/integration.test.ts +0 -338
  717. package/references/opentasks/src/daemon/__tests__/ipc.test.ts +0 -406
  718. package/references/opentasks/src/daemon/__tests__/lifecycle.test.ts +0 -378
  719. package/references/opentasks/src/daemon/__tests__/lock.test.ts +0 -240
  720. package/references/opentasks/src/daemon/__tests__/methods/graph.test.ts +0 -372
  721. package/references/opentasks/src/daemon/__tests__/methods/provider.test.ts +0 -238
  722. package/references/opentasks/src/daemon/__tests__/methods/tools.test.ts +0 -690
  723. package/references/opentasks/src/daemon/__tests__/multi-location.test.ts +0 -945
  724. package/references/opentasks/src/daemon/__tests__/registry.test.ts +0 -268
  725. package/references/opentasks/src/daemon/__tests__/watcher.test.ts +0 -329
  726. package/references/opentasks/src/daemon/entire-linker.ts +0 -615
  727. package/references/opentasks/src/daemon/entire-watcher.ts +0 -415
  728. package/references/opentasks/src/daemon/factory.ts +0 -133
  729. package/references/opentasks/src/daemon/flush.ts +0 -168
  730. package/references/opentasks/src/daemon/index.ts +0 -120
  731. package/references/opentasks/src/daemon/ipc.ts +0 -491
  732. package/references/opentasks/src/daemon/lifecycle.ts +0 -1106
  733. package/references/opentasks/src/daemon/location-state.ts +0 -481
  734. package/references/opentasks/src/daemon/lock.ts +0 -168
  735. package/references/opentasks/src/daemon/methods/__tests__/graph.test.ts +0 -359
  736. package/references/opentasks/src/daemon/methods/__tests__/provider.test.ts +0 -227
  737. package/references/opentasks/src/daemon/methods/__tests__/tools.test.ts +0 -360
  738. package/references/opentasks/src/daemon/methods/__tests__/watch.test.ts +0 -656
  739. package/references/opentasks/src/daemon/methods/archive.ts +0 -193
  740. package/references/opentasks/src/daemon/methods/graph.ts +0 -274
  741. package/references/opentasks/src/daemon/methods/lifecycle.ts +0 -112
  742. package/references/opentasks/src/daemon/methods/location.ts +0 -118
  743. package/references/opentasks/src/daemon/methods/provider.ts +0 -159
  744. package/references/opentasks/src/daemon/methods/tools.ts +0 -221
  745. package/references/opentasks/src/daemon/methods/watch.ts +0 -206
  746. package/references/opentasks/src/daemon/registry.ts +0 -244
  747. package/references/opentasks/src/daemon/types.ts +0 -163
  748. package/references/opentasks/src/daemon/watcher.ts +0 -248
  749. package/references/opentasks/src/entire/__tests__/agent-registry.test.ts +0 -127
  750. package/references/opentasks/src/entire/__tests__/claude-generator.test.ts +0 -49
  751. package/references/opentasks/src/entire/__tests__/commit-msg.test.ts +0 -89
  752. package/references/opentasks/src/entire/__tests__/cursor-agent.test.ts +0 -224
  753. package/references/opentasks/src/entire/__tests__/flush-sentinel.test.ts +0 -93
  754. package/references/opentasks/src/entire/__tests__/gemini-agent.test.ts +0 -375
  755. package/references/opentasks/src/entire/__tests__/git-hooks.test.ts +0 -85
  756. package/references/opentasks/src/entire/__tests__/hook-managers.test.ts +0 -128
  757. package/references/opentasks/src/entire/__tests__/opencode-agent.test.ts +0 -329
  758. package/references/opentasks/src/entire/__tests__/redaction.test.ts +0 -143
  759. package/references/opentasks/src/entire/__tests__/session-store.test.ts +0 -83
  760. package/references/opentasks/src/entire/__tests__/summarize.test.ts +0 -346
  761. package/references/opentasks/src/entire/__tests__/transcript-timestamp.test.ts +0 -127
  762. package/references/opentasks/src/entire/__tests__/types.test.ts +0 -112
  763. package/references/opentasks/src/entire/__tests__/utils.test.ts +0 -296
  764. package/references/opentasks/src/entire/__tests__/validation.test.ts +0 -103
  765. package/references/opentasks/src/entire/__tests__/worktree.test.ts +0 -66
  766. package/references/opentasks/src/entire/agent/registry.ts +0 -143
  767. package/references/opentasks/src/entire/agent/session-types.ts +0 -117
  768. package/references/opentasks/src/entire/agent/types.ts +0 -217
  769. package/references/opentasks/src/entire/commands/clean.ts +0 -134
  770. package/references/opentasks/src/entire/commands/disable.ts +0 -85
  771. package/references/opentasks/src/entire/commands/doctor.ts +0 -152
  772. package/references/opentasks/src/entire/commands/enable.ts +0 -149
  773. package/references/opentasks/src/entire/commands/explain.ts +0 -271
  774. package/references/opentasks/src/entire/commands/reset.ts +0 -105
  775. package/references/opentasks/src/entire/commands/resume.ts +0 -194
  776. package/references/opentasks/src/entire/commands/rewind.ts +0 -204
  777. package/references/opentasks/src/entire/commands/status.ts +0 -150
  778. package/references/opentasks/src/entire/config.ts +0 -153
  779. package/references/opentasks/src/entire/git-operations.ts +0 -485
  780. package/references/opentasks/src/entire/hooks/git-hooks.ts +0 -171
  781. package/references/opentasks/src/entire/hooks/lifecycle.ts +0 -224
  782. package/references/opentasks/src/entire/index.ts +0 -644
  783. package/references/opentasks/src/entire/security/redaction.ts +0 -263
  784. package/references/opentasks/src/entire/session/state-machine.ts +0 -463
  785. package/references/opentasks/src/entire/store/checkpoint-store.ts +0 -489
  786. package/references/opentasks/src/entire/store/native-store.ts +0 -178
  787. package/references/opentasks/src/entire/store/provider-types.ts +0 -99
  788. package/references/opentasks/src/entire/store/session-store.ts +0 -233
  789. package/references/opentasks/src/entire/strategy/attribution.ts +0 -300
  790. package/references/opentasks/src/entire/strategy/common.ts +0 -222
  791. package/references/opentasks/src/entire/strategy/content-overlap.ts +0 -242
  792. package/references/opentasks/src/entire/strategy/manual-commit.ts +0 -1008
  793. package/references/opentasks/src/entire/strategy/types.ts +0 -285
  794. package/references/opentasks/src/entire/summarize/claude-generator.ts +0 -119
  795. package/references/opentasks/src/entire/summarize/summarize.ts +0 -432
  796. package/references/opentasks/src/entire/types.ts +0 -408
  797. package/references/opentasks/src/entire/utils/chunk-files.ts +0 -49
  798. package/references/opentasks/src/entire/utils/commit-message.ts +0 -65
  799. package/references/opentasks/src/entire/utils/detect-agent.ts +0 -36
  800. package/references/opentasks/src/entire/utils/hook-managers.ts +0 -118
  801. package/references/opentasks/src/entire/utils/ide-tags.ts +0 -32
  802. package/references/opentasks/src/entire/utils/paths.ts +0 -59
  803. package/references/opentasks/src/entire/utils/preview-rewind.ts +0 -86
  804. package/references/opentasks/src/entire/utils/rewind-conflict.ts +0 -121
  805. package/references/opentasks/src/entire/utils/shadow-branch.ts +0 -113
  806. package/references/opentasks/src/entire/utils/string-utils.ts +0 -46
  807. package/references/opentasks/src/entire/utils/todo-extract.ts +0 -193
  808. package/references/opentasks/src/entire/utils/trailers.ts +0 -190
  809. package/references/opentasks/src/entire/utils/transcript-parse.ts +0 -177
  810. package/references/opentasks/src/entire/utils/transcript-timestamp.ts +0 -61
  811. package/references/opentasks/src/entire/utils/tree-ops.ts +0 -227
  812. package/references/opentasks/src/entire/utils/tty.ts +0 -72
  813. package/references/opentasks/src/entire/utils/validation.ts +0 -67
  814. package/references/opentasks/src/entire/utils/worktree.ts +0 -58
  815. package/references/opentasks/src/graph/EdgeTypeRegistry.ts +0 -330
  816. package/references/opentasks/src/graph/FederatedGraph.ts +0 -796
  817. package/references/opentasks/src/graph/GraphologyAdapter.ts +0 -374
  818. package/references/opentasks/src/graph/HydratingFederatedGraph.ts +0 -533
  819. package/references/opentasks/src/graph/__tests__/EdgeTypeRegistry.test.ts +0 -263
  820. package/references/opentasks/src/graph/__tests__/FederatedGraph.test.ts +0 -821
  821. package/references/opentasks/src/graph/__tests__/GraphologyAdapter.test.ts +0 -408
  822. package/references/opentasks/src/graph/__tests__/HydratingFederatedGraph.test.ts +0 -735
  823. package/references/opentasks/src/graph/__tests__/debounce.test.ts +0 -276
  824. package/references/opentasks/src/graph/__tests__/e2e-store-roundtrip.test.ts +0 -349
  825. package/references/opentasks/src/graph/__tests__/edge-cases.test.ts +0 -595
  826. package/references/opentasks/src/graph/__tests__/expansion.test.ts +0 -304
  827. package/references/opentasks/src/graph/__tests__/git-graph-syncer.test.ts +0 -572
  828. package/references/opentasks/src/graph/__tests__/provider-store.test.ts +0 -1091
  829. package/references/opentasks/src/graph/__tests__/query.test.ts +0 -991
  830. package/references/opentasks/src/graph/__tests__/store.test.ts +0 -998
  831. package/references/opentasks/src/graph/__tests__/sync.test.ts +0 -178
  832. package/references/opentasks/src/graph/__tests__/validation.test.ts +0 -657
  833. package/references/opentasks/src/graph/coordination.ts +0 -454
  834. package/references/opentasks/src/graph/debounce.ts +0 -154
  835. package/references/opentasks/src/graph/expansion.ts +0 -364
  836. package/references/opentasks/src/graph/git-graph-syncer.ts +0 -321
  837. package/references/opentasks/src/graph/history.ts +0 -438
  838. package/references/opentasks/src/graph/index.ts +0 -145
  839. package/references/opentasks/src/graph/provider-store.ts +0 -1077
  840. package/references/opentasks/src/graph/query.ts +0 -651
  841. package/references/opentasks/src/graph/store.ts +0 -861
  842. package/references/opentasks/src/graph/sync.ts +0 -116
  843. package/references/opentasks/src/graph/types.ts +0 -420
  844. package/references/opentasks/src/graph/validation.ts +0 -520
  845. package/references/opentasks/src/index.ts +0 -270
  846. package/references/opentasks/src/materialization/CLAUDE.md +0 -88
  847. package/references/opentasks/src/materialization/README.md +0 -187
  848. package/references/opentasks/src/materialization/__tests__/archive-methods.test.ts +0 -194
  849. package/references/opentasks/src/materialization/__tests__/archiver.test.ts +0 -528
  850. package/references/opentasks/src/materialization/__tests__/config.test.ts +0 -123
  851. package/references/opentasks/src/materialization/__tests__/git-remote-store.test.ts +0 -533
  852. package/references/opentasks/src/materialization/__tests__/graph-id.test.ts +0 -82
  853. package/references/opentasks/src/materialization/__tests__/http-remote-store.test.ts +0 -263
  854. package/references/opentasks/src/materialization/__tests__/materialize-before-archive.test.ts +0 -246
  855. package/references/opentasks/src/materialization/__tests__/remote-store-factory.test.ts +0 -152
  856. package/references/opentasks/src/materialization/__tests__/snapshot.test.ts +0 -209
  857. package/references/opentasks/src/materialization/archiver.ts +0 -318
  858. package/references/opentasks/src/materialization/git-archive-store.ts +0 -568
  859. package/references/opentasks/src/materialization/git-remote-store.ts +0 -551
  860. package/references/opentasks/src/materialization/graph-id.ts +0 -173
  861. package/references/opentasks/src/materialization/http-remote-store.ts +0 -190
  862. package/references/opentasks/src/materialization/index.ts +0 -62
  863. package/references/opentasks/src/materialization/remote-store-factory.ts +0 -55
  864. package/references/opentasks/src/materialization/snapshot.ts +0 -230
  865. package/references/opentasks/src/materialization/types.ts +0 -410
  866. package/references/opentasks/src/providers/__tests__/beads.test.ts +0 -752
  867. package/references/opentasks/src/providers/__tests__/claude-tasks.test.ts +0 -485
  868. package/references/opentasks/src/providers/__tests__/entire-e2e.test.ts +0 -692
  869. package/references/opentasks/src/providers/__tests__/entire-sessionlog-e2e.test.ts +0 -1113
  870. package/references/opentasks/src/providers/__tests__/entire.test.ts +0 -1016
  871. package/references/opentasks/src/providers/__tests__/from-config.test.ts +0 -183
  872. package/references/opentasks/src/providers/__tests__/global.test.ts +0 -515
  873. package/references/opentasks/src/providers/__tests__/materialization.test.ts +0 -567
  874. package/references/opentasks/src/providers/__tests__/native.test.ts +0 -693
  875. package/references/opentasks/src/providers/__tests__/registry.test.ts +0 -232
  876. package/references/opentasks/src/providers/beads.ts +0 -1155
  877. package/references/opentasks/src/providers/claude-tasks.ts +0 -402
  878. package/references/opentasks/src/providers/entire.ts +0 -608
  879. package/references/opentasks/src/providers/from-config.ts +0 -210
  880. package/references/opentasks/src/providers/global.ts +0 -460
  881. package/references/opentasks/src/providers/index.ts +0 -147
  882. package/references/opentasks/src/providers/location.ts +0 -237
  883. package/references/opentasks/src/providers/materialization.ts +0 -346
  884. package/references/opentasks/src/providers/native.ts +0 -725
  885. package/references/opentasks/src/providers/registry.ts +0 -114
  886. package/references/opentasks/src/providers/sudocode.ts +0 -1292
  887. package/references/opentasks/src/providers/sync.ts +0 -485
  888. package/references/opentasks/src/providers/traits/RelationshipQueryable.ts +0 -169
  889. package/references/opentasks/src/providers/traits/TaskManageable.ts +0 -211
  890. package/references/opentasks/src/providers/traits/Watchable.ts +0 -260
  891. package/references/opentasks/src/providers/traits/__tests__/RelationshipQueryable.test.ts +0 -217
  892. package/references/opentasks/src/providers/traits/__tests__/TaskManageable.test.ts +0 -241
  893. package/references/opentasks/src/providers/traits/index.ts +0 -42
  894. package/references/opentasks/src/providers/types.ts +0 -439
  895. package/references/opentasks/src/schema/__tests__/validation.test.ts +0 -283
  896. package/references/opentasks/src/schema/base.ts +0 -88
  897. package/references/opentasks/src/schema/edges.ts +0 -78
  898. package/references/opentasks/src/schema/index.ts +0 -37
  899. package/references/opentasks/src/schema/nodes.ts +0 -119
  900. package/references/opentasks/src/schema/storage.ts +0 -130
  901. package/references/opentasks/src/schema/validation.ts +0 -209
  902. package/references/opentasks/src/storage/__tests__/atomic-write.test.ts +0 -227
  903. package/references/opentasks/src/storage/__tests__/file-lock.test.ts +0 -120
  904. package/references/opentasks/src/storage/__tests__/jsonl.test.ts +0 -267
  905. package/references/opentasks/src/storage/__tests__/locked-writer.test.ts +0 -134
  906. package/references/opentasks/src/storage/__tests__/sqlite.test.ts +0 -572
  907. package/references/opentasks/src/storage/atomic-write.ts +0 -86
  908. package/references/opentasks/src/storage/file-lock.ts +0 -215
  909. package/references/opentasks/src/storage/index.ts +0 -24
  910. package/references/opentasks/src/storage/interface.ts +0 -289
  911. package/references/opentasks/src/storage/jsonl.ts +0 -264
  912. package/references/opentasks/src/storage/locked-writer.ts +0 -140
  913. package/references/opentasks/src/storage/sqlite-schema.ts +0 -177
  914. package/references/opentasks/src/storage/sqlite.ts +0 -791
  915. package/references/opentasks/src/tools/__tests__/annotate.test.ts +0 -381
  916. package/references/opentasks/src/tools/__tests__/link.test.ts +0 -299
  917. package/references/opentasks/src/tools/__tests__/query.test.ts +0 -350
  918. package/references/opentasks/src/tools/__tests__/task.test.ts +0 -218
  919. package/references/opentasks/src/tools/annotate.ts +0 -277
  920. package/references/opentasks/src/tools/index.ts +0 -57
  921. package/references/opentasks/src/tools/link.ts +0 -163
  922. package/references/opentasks/src/tools/query.ts +0 -468
  923. package/references/opentasks/src/tools/task.ts +0 -213
  924. package/references/opentasks/src/tools/types.ts +0 -451
  925. package/references/opentasks/src/tracking/__tests__/claude-tool-categorizer.test.ts +0 -223
  926. package/references/opentasks/src/tracking/__tests__/transcript-extractor.test.ts +0 -262
  927. package/references/opentasks/src/tracking/claude-tool-categorizer.ts +0 -155
  928. package/references/opentasks/src/tracking/index.ts +0 -32
  929. package/references/opentasks/src/tracking/skill-tracker.ts +0 -322
  930. package/references/opentasks/src/tracking/transcript-extractor.ts +0 -225
  931. package/references/opentasks/tests/e2e/helpers/assertions.ts +0 -211
  932. package/references/opentasks/tests/e2e/helpers/beads-helpers.ts +0 -487
  933. package/references/opentasks/tests/e2e/helpers/fixtures.ts +0 -236
  934. package/references/opentasks/tests/e2e/helpers/index.ts +0 -122
  935. package/references/opentasks/tests/e2e/helpers/sudocode-helpers.ts +0 -341
  936. package/references/opentasks/tests/e2e/helpers/system-setup.ts +0 -504
  937. package/references/opentasks/tests/e2e/helpers/test-agent.ts +0 -504
  938. package/references/opentasks/tests/e2e/infrastructure.e2e.test.ts +0 -521
  939. package/references/opentasks/tests/e2e/skill-tracking.e2e.test.ts +0 -625
  940. package/references/opentasks/tests/e2e/workflows/feedback-loop.e2e.test.ts +0 -279
  941. package/references/opentasks/tests/e2e/workflows/multi-agent.e2e.test.ts +0 -304
  942. package/references/opentasks/tests/e2e/workflows/provider-sync/background-sync.e2e.test.ts +0 -292
  943. package/references/opentasks/tests/e2e/workflows/provider-sync/beads-provider-compat.e2e.test.ts +0 -249
  944. package/references/opentasks/tests/e2e/workflows/provider-sync/cross-provider-edges.e2e.test.ts +0 -407
  945. package/references/opentasks/tests/e2e/workflows/provider-sync/federated-ready.e2e.test.ts +0 -504
  946. package/references/opentasks/tests/e2e/workflows/provider-sync/hydration.e2e.test.ts +0 -340
  947. package/references/opentasks/tests/e2e/workflows/provider-sync/materialization.e2e.test.ts +0 -370
  948. package/references/opentasks/tests/e2e/workflows/provider-sync/sudocode-provider-compat.e2e.test.ts +0 -683
  949. package/references/opentasks/tests/e2e/workflows/provider-sync/watchable-beads.e2e.test.ts +0 -573
  950. package/references/opentasks/tests/e2e/workflows/spec-driven.e2e.test.ts +0 -244
  951. package/references/opentasks/tests/e2e/worktree-location.e2e.test.ts +0 -699
  952. package/references/opentasks/tests/integration/daemon/helpers.ts +0 -147
  953. package/references/opentasks/tests/integration/daemon/ipc.integration.test.ts +0 -343
  954. package/references/opentasks/tests/integration/daemon/lifecycle.integration.test.ts +0 -407
  955. package/references/opentasks/tests/integration/graph/federated-graph.integration.test.ts +0 -660
  956. package/references/opentasks/tests/integration/helpers/flags.ts +0 -28
  957. package/references/opentasks/tests/integration/helpers/index.ts +0 -47
  958. package/references/opentasks/tests/integration/helpers/process.ts +0 -133
  959. package/references/opentasks/tests/integration/helpers/temp.ts +0 -105
  960. package/references/opentasks/tests/integration/helpers/wait.ts +0 -133
  961. package/references/opentasks/tests/integration/helpers.test.ts +0 -120
  962. package/references/opentasks/tests/integration/providers/beads-task-manageable.integration.test.ts +0 -450
  963. package/references/opentasks/tests/integration/providers/beads.integration.test.ts +0 -388
  964. package/references/opentasks/tests/integration/providers/native-task-manageable.integration.test.ts +0 -667
  965. package/references/opentasks/tests/integration/providers/sudocode-task-manageable.integration.test.ts +0 -406
  966. package/references/opentasks/tests/integration/providers/sudocode.integration.test.ts +0 -342
  967. package/references/opentasks/tests/integration/storage/jsonl-durability.integration.test.ts +0 -390
  968. package/references/opentasks/tests/integration/storage/sqlite-durability.integration.test.ts +0 -527
  969. package/references/opentasks/tests/integration/worktree/redirect-location-resolution.integration.test.ts +0 -578
  970. package/references/opentasks/tests/integration/worktree/worktree-flow.integration.test.ts +0 -656
  971. package/references/opentasks/tsconfig.json +0 -18
  972. package/references/opentasks/vitest.config.ts +0 -27
  973. package/references/opentasks/vitest.e2e.config.ts +0 -35
  974. package/references/opentasks/vitest.integration.config.ts +0 -19
  975. package/references/openteams/.claude/settings.json +0 -6
  976. package/references/openteams/CLAUDE.md +0 -98
  977. package/references/openteams/README.md +0 -508
  978. package/references/openteams/SKILL.md +0 -198
  979. package/references/openteams/design.md +0 -250
  980. package/references/openteams/docs/visual-editor-design.md +0 -1225
  981. package/references/openteams/editor/index.html +0 -15
  982. package/references/openteams/editor/package.json +0 -39
  983. package/references/openteams/editor/src/App.tsx +0 -48
  984. package/references/openteams/editor/src/components/canvas/Canvas.tsx +0 -131
  985. package/references/openteams/editor/src/components/canvas/QuickAddMenu.tsx +0 -134
  986. package/references/openteams/editor/src/components/edges/PeerRouteEdge.tsx +0 -82
  987. package/references/openteams/editor/src/components/edges/SignalFlowEdge.tsx +0 -77
  988. package/references/openteams/editor/src/components/edges/SpawnEdge.tsx +0 -54
  989. package/references/openteams/editor/src/components/inspector/ChannelInspector.tsx +0 -158
  990. package/references/openteams/editor/src/components/inspector/EdgeInspector.tsx +0 -168
  991. package/references/openteams/editor/src/components/inspector/Inspector.tsx +0 -46
  992. package/references/openteams/editor/src/components/inspector/RoleInspector.tsx +0 -508
  993. package/references/openteams/editor/src/components/inspector/TeamInspector.tsx +0 -126
  994. package/references/openteams/editor/src/components/nodes/ChannelNode.tsx +0 -103
  995. package/references/openteams/editor/src/components/nodes/RoleNode.tsx +0 -157
  996. package/references/openteams/editor/src/components/nodes/node-styles.ts +0 -101
  997. package/references/openteams/editor/src/components/sidebar/Sidebar.tsx +0 -227
  998. package/references/openteams/editor/src/components/toolbar/ExportModal.tsx +0 -110
  999. package/references/openteams/editor/src/components/toolbar/ImportModal.tsx +0 -139
  1000. package/references/openteams/editor/src/components/toolbar/Toolbar.tsx +0 -190
  1001. package/references/openteams/editor/src/hooks/use-autosave.ts +0 -126
  1002. package/references/openteams/editor/src/hooks/use-keyboard.ts +0 -106
  1003. package/references/openteams/editor/src/hooks/use-validation.ts +0 -45
  1004. package/references/openteams/editor/src/index.css +0 -245
  1005. package/references/openteams/editor/src/lib/auto-layout.ts +0 -51
  1006. package/references/openteams/editor/src/lib/bundled-templates.ts +0 -42
  1007. package/references/openteams/editor/src/lib/compiler.ts +0 -75
  1008. package/references/openteams/editor/src/lib/load-template.ts +0 -103
  1009. package/references/openteams/editor/src/lib/rebuild-edges.ts +0 -104
  1010. package/references/openteams/editor/src/lib/serializer.ts +0 -408
  1011. package/references/openteams/editor/src/lib/signal-catalog.ts +0 -50
  1012. package/references/openteams/editor/src/lib/validator.ts +0 -172
  1013. package/references/openteams/editor/src/main.tsx +0 -10
  1014. package/references/openteams/editor/src/stores/canvas-store.ts +0 -80
  1015. package/references/openteams/editor/src/stores/config-store.ts +0 -243
  1016. package/references/openteams/editor/src/stores/history-store.ts +0 -143
  1017. package/references/openteams/editor/src/stores/theme-store.ts +0 -66
  1018. package/references/openteams/editor/src/stores/ui-store.ts +0 -46
  1019. package/references/openteams/editor/src/stores/validation-store.ts +0 -27
  1020. package/references/openteams/editor/src/types/editor.ts +0 -74
  1021. package/references/openteams/editor/src/vite-env.d.ts +0 -1
  1022. package/references/openteams/editor/tests/compiler.test.ts +0 -151
  1023. package/references/openteams/editor/tests/e2e-add-remove.test.ts +0 -386
  1024. package/references/openteams/editor/tests/e2e-components.test.tsx +0 -424
  1025. package/references/openteams/editor/tests/e2e-export-roundtrip.test.ts +0 -299
  1026. package/references/openteams/editor/tests/e2e-template-load.test.ts +0 -204
  1027. package/references/openteams/editor/tests/e2e-ui-store.test.ts +0 -126
  1028. package/references/openteams/editor/tests/e2e-undo-redo.test.ts +0 -203
  1029. package/references/openteams/editor/tests/e2e-validation.test.ts +0 -307
  1030. package/references/openteams/editor/tests/serializer.test.ts +0 -142
  1031. package/references/openteams/editor/tests/setup.ts +0 -52
  1032. package/references/openteams/editor/tests/validator.test.ts +0 -92
  1033. package/references/openteams/editor/tsconfig.json +0 -21
  1034. package/references/openteams/editor/tsconfig.tsbuildinfo +0 -1
  1035. package/references/openteams/editor/vite.config.ts +0 -28
  1036. package/references/openteams/examples/bmad-method/prompts/analyst/ROLE.md +0 -16
  1037. package/references/openteams/examples/bmad-method/prompts/analyst/SOUL.md +0 -5
  1038. package/references/openteams/examples/bmad-method/prompts/architect/ROLE.md +0 -24
  1039. package/references/openteams/examples/bmad-method/prompts/architect/SOUL.md +0 -5
  1040. package/references/openteams/examples/bmad-method/prompts/developer/ROLE.md +0 -25
  1041. package/references/openteams/examples/bmad-method/prompts/developer/SOUL.md +0 -5
  1042. package/references/openteams/examples/bmad-method/prompts/master/ROLE.md +0 -21
  1043. package/references/openteams/examples/bmad-method/prompts/master/SOUL.md +0 -5
  1044. package/references/openteams/examples/bmad-method/prompts/pm/ROLE.md +0 -20
  1045. package/references/openteams/examples/bmad-method/prompts/pm/SOUL.md +0 -5
  1046. package/references/openteams/examples/bmad-method/prompts/qa/ROLE.md +0 -17
  1047. package/references/openteams/examples/bmad-method/prompts/qa/SOUL.md +0 -5
  1048. package/references/openteams/examples/bmad-method/prompts/quick-flow-dev/ROLE.md +0 -23
  1049. package/references/openteams/examples/bmad-method/prompts/quick-flow-dev/SOUL.md +0 -5
  1050. package/references/openteams/examples/bmad-method/prompts/scrum-master/ROLE.md +0 -27
  1051. package/references/openteams/examples/bmad-method/prompts/scrum-master/SOUL.md +0 -5
  1052. package/references/openteams/examples/bmad-method/prompts/tech-writer/ROLE.md +0 -21
  1053. package/references/openteams/examples/bmad-method/prompts/tech-writer/SOUL.md +0 -5
  1054. package/references/openteams/examples/bmad-method/prompts/ux-designer/ROLE.md +0 -16
  1055. package/references/openteams/examples/bmad-method/prompts/ux-designer/SOUL.md +0 -5
  1056. package/references/openteams/examples/bmad-method/roles/analyst.yaml +0 -9
  1057. package/references/openteams/examples/bmad-method/roles/architect.yaml +0 -9
  1058. package/references/openteams/examples/bmad-method/roles/developer.yaml +0 -8
  1059. package/references/openteams/examples/bmad-method/roles/master.yaml +0 -8
  1060. package/references/openteams/examples/bmad-method/roles/pm.yaml +0 -9
  1061. package/references/openteams/examples/bmad-method/roles/qa.yaml +0 -8
  1062. package/references/openteams/examples/bmad-method/roles/quick-flow-dev.yaml +0 -8
  1063. package/references/openteams/examples/bmad-method/roles/scrum-master.yaml +0 -9
  1064. package/references/openteams/examples/bmad-method/roles/tech-writer.yaml +0 -8
  1065. package/references/openteams/examples/bmad-method/roles/ux-designer.yaml +0 -8
  1066. package/references/openteams/examples/bmad-method/team.yaml +0 -161
  1067. package/references/openteams/examples/bug-fix-pipeline/roles/fixer.yaml +0 -9
  1068. package/references/openteams/examples/bug-fix-pipeline/roles/investigator.yaml +0 -8
  1069. package/references/openteams/examples/bug-fix-pipeline/roles/pr-creator.yaml +0 -6
  1070. package/references/openteams/examples/bug-fix-pipeline/roles/triager.yaml +0 -7
  1071. package/references/openteams/examples/bug-fix-pipeline/roles/verifier.yaml +0 -8
  1072. package/references/openteams/examples/bug-fix-pipeline/team.yaml +0 -88
  1073. package/references/openteams/examples/codebase-migration/roles/assessor.yaml +0 -7
  1074. package/references/openteams/examples/codebase-migration/roles/migrator.yaml +0 -9
  1075. package/references/openteams/examples/codebase-migration/roles/planner.yaml +0 -5
  1076. package/references/openteams/examples/codebase-migration/roles/test-extractor.yaml +0 -9
  1077. package/references/openteams/examples/codebase-migration/roles/validator.yaml +0 -7
  1078. package/references/openteams/examples/codebase-migration/team.yaml +0 -81
  1079. package/references/openteams/examples/docs-sync/roles/adr-writer.yaml +0 -7
  1080. package/references/openteams/examples/docs-sync/roles/api-doc-writer.yaml +0 -7
  1081. package/references/openteams/examples/docs-sync/roles/change-detector.yaml +0 -7
  1082. package/references/openteams/examples/docs-sync/roles/doc-reviewer.yaml +0 -7
  1083. package/references/openteams/examples/docs-sync/roles/guide-writer.yaml +0 -7
  1084. package/references/openteams/examples/docs-sync/team.yaml +0 -84
  1085. package/references/openteams/examples/gsd/prompts/codebase-mapper/ROLE.md +0 -17
  1086. package/references/openteams/examples/gsd/prompts/codebase-mapper/SOUL.md +0 -5
  1087. package/references/openteams/examples/gsd/prompts/debugger/ROLE.md +0 -25
  1088. package/references/openteams/examples/gsd/prompts/debugger/SOUL.md +0 -5
  1089. package/references/openteams/examples/gsd/prompts/executor/ROLE.md +0 -34
  1090. package/references/openteams/examples/gsd/prompts/executor/SOUL.md +0 -5
  1091. package/references/openteams/examples/gsd/prompts/integration-checker/ROLE.md +0 -18
  1092. package/references/openteams/examples/gsd/prompts/integration-checker/SOUL.md +0 -3
  1093. package/references/openteams/examples/gsd/prompts/orchestrator/ROLE.md +0 -42
  1094. package/references/openteams/examples/gsd/prompts/orchestrator/SOUL.md +0 -5
  1095. package/references/openteams/examples/gsd/prompts/phase-researcher/ROLE.md +0 -15
  1096. package/references/openteams/examples/gsd/prompts/phase-researcher/SOUL.md +0 -3
  1097. package/references/openteams/examples/gsd/prompts/plan-checker/ROLE.md +0 -17
  1098. package/references/openteams/examples/gsd/prompts/plan-checker/SOUL.md +0 -3
  1099. package/references/openteams/examples/gsd/prompts/planner/ROLE.md +0 -28
  1100. package/references/openteams/examples/gsd/prompts/planner/SOUL.md +0 -5
  1101. package/references/openteams/examples/gsd/prompts/project-researcher/ROLE.md +0 -16
  1102. package/references/openteams/examples/gsd/prompts/project-researcher/SOUL.md +0 -3
  1103. package/references/openteams/examples/gsd/prompts/research-synthesizer/ROLE.md +0 -13
  1104. package/references/openteams/examples/gsd/prompts/research-synthesizer/SOUL.md +0 -3
  1105. package/references/openteams/examples/gsd/prompts/roadmapper/ROLE.md +0 -14
  1106. package/references/openteams/examples/gsd/prompts/roadmapper/SOUL.md +0 -3
  1107. package/references/openteams/examples/gsd/prompts/verifier/ROLE.md +0 -19
  1108. package/references/openteams/examples/gsd/prompts/verifier/SOUL.md +0 -5
  1109. package/references/openteams/examples/gsd/roles/codebase-mapper.yaml +0 -8
  1110. package/references/openteams/examples/gsd/roles/debugger.yaml +0 -8
  1111. package/references/openteams/examples/gsd/roles/executor.yaml +0 -8
  1112. package/references/openteams/examples/gsd/roles/integration-checker.yaml +0 -8
  1113. package/references/openteams/examples/gsd/roles/orchestrator.yaml +0 -9
  1114. package/references/openteams/examples/gsd/roles/phase-researcher.yaml +0 -7
  1115. package/references/openteams/examples/gsd/roles/plan-checker.yaml +0 -8
  1116. package/references/openteams/examples/gsd/roles/planner.yaml +0 -8
  1117. package/references/openteams/examples/gsd/roles/project-researcher.yaml +0 -8
  1118. package/references/openteams/examples/gsd/roles/research-synthesizer.yaml +0 -7
  1119. package/references/openteams/examples/gsd/roles/roadmapper.yaml +0 -7
  1120. package/references/openteams/examples/gsd/roles/verifier.yaml +0 -8
  1121. package/references/openteams/examples/gsd/team.yaml +0 -154
  1122. package/references/openteams/examples/incident-response/roles/communicator.yaml +0 -5
  1123. package/references/openteams/examples/incident-response/roles/fix-proposer.yaml +0 -7
  1124. package/references/openteams/examples/incident-response/roles/incident-triager.yaml +0 -8
  1125. package/references/openteams/examples/incident-response/roles/investigator.yaml +0 -8
  1126. package/references/openteams/examples/incident-response/team.yaml +0 -68
  1127. package/references/openteams/examples/pr-review-checks/roles/code-reviewer.yaml +0 -7
  1128. package/references/openteams/examples/pr-review-checks/roles/security-scanner.yaml +0 -6
  1129. package/references/openteams/examples/pr-review-checks/roles/summarizer.yaml +0 -6
  1130. package/references/openteams/examples/pr-review-checks/roles/test-checker.yaml +0 -8
  1131. package/references/openteams/examples/pr-review-checks/team.yaml +0 -64
  1132. package/references/openteams/examples/security-audit/roles/code-analyzer.yaml +0 -6
  1133. package/references/openteams/examples/security-audit/roles/dep-scanner.yaml +0 -7
  1134. package/references/openteams/examples/security-audit/roles/fixer.yaml +0 -9
  1135. package/references/openteams/examples/security-audit/roles/pr-creator.yaml +0 -6
  1136. package/references/openteams/examples/security-audit/roles/prioritizer.yaml +0 -6
  1137. package/references/openteams/examples/security-audit/roles/secrets-scanner.yaml +0 -6
  1138. package/references/openteams/examples/security-audit/roles/verifier.yaml +0 -8
  1139. package/references/openteams/examples/security-audit/team.yaml +0 -102
  1140. package/references/openteams/media/banner.png +0 -0
  1141. package/references/openteams/media/editor.png +0 -0
  1142. package/references/openteams/package-lock.json +0 -4804
  1143. package/references/openteams/package.json +0 -58
  1144. package/references/openteams/schema/role.schema.json +0 -147
  1145. package/references/openteams/schema/team.schema.json +0 -311
  1146. package/references/openteams/src/cli/editor.ts +0 -170
  1147. package/references/openteams/src/cli/generate.test.ts +0 -191
  1148. package/references/openteams/src/cli/generate.ts +0 -242
  1149. package/references/openteams/src/cli/prompt-utils.ts +0 -42
  1150. package/references/openteams/src/cli/template.test.ts +0 -365
  1151. package/references/openteams/src/cli/template.ts +0 -205
  1152. package/references/openteams/src/cli.ts +0 -22
  1153. package/references/openteams/src/generators/agent-prompt-generator.test.ts +0 -426
  1154. package/references/openteams/src/generators/agent-prompt-generator.ts +0 -556
  1155. package/references/openteams/src/generators/package-generator.test.ts +0 -129
  1156. package/references/openteams/src/generators/package-generator.ts +0 -110
  1157. package/references/openteams/src/generators/skill-generator.test.ts +0 -274
  1158. package/references/openteams/src/generators/skill-generator.ts +0 -394
  1159. package/references/openteams/src/index.ts +0 -84
  1160. package/references/openteams/src/template/builtins.test.ts +0 -74
  1161. package/references/openteams/src/template/builtins.ts +0 -108
  1162. package/references/openteams/src/template/install-service.test.ts +0 -452
  1163. package/references/openteams/src/template/install-service.ts +0 -332
  1164. package/references/openteams/src/template/loader.test.ts +0 -1696
  1165. package/references/openteams/src/template/loader.ts +0 -804
  1166. package/references/openteams/src/template/resolver.test.ts +0 -304
  1167. package/references/openteams/src/template/resolver.ts +0 -251
  1168. package/references/openteams/src/template/types.ts +0 -229
  1169. package/references/openteams/tsconfig.cjs.json +0 -7
  1170. package/references/openteams/tsconfig.esm.json +0 -8
  1171. package/references/openteams/tsconfig.json +0 -16
  1172. package/references/openteams/vitest.config.ts +0 -9
  1173. package/references/sessionlog/.husky/pre-commit +0 -1
  1174. package/references/sessionlog/.lintstagedrc.json +0 -4
  1175. package/references/sessionlog/.prettierignore +0 -4
  1176. package/references/sessionlog/.prettierrc.json +0 -11
  1177. package/references/sessionlog/LICENSE +0 -21
  1178. package/references/sessionlog/README.md +0 -453
  1179. package/references/sessionlog/eslint.config.js +0 -58
  1180. package/references/sessionlog/package-lock.json +0 -3672
  1181. package/references/sessionlog/package.json +0 -65
  1182. package/references/sessionlog/src/__tests__/agent-hooks.test.ts +0 -570
  1183. package/references/sessionlog/src/__tests__/agent-registry.test.ts +0 -127
  1184. package/references/sessionlog/src/__tests__/claude-code-hooks.test.ts +0 -225
  1185. package/references/sessionlog/src/__tests__/claude-generator.test.ts +0 -46
  1186. package/references/sessionlog/src/__tests__/commit-msg.test.ts +0 -86
  1187. package/references/sessionlog/src/__tests__/cursor-agent.test.ts +0 -224
  1188. package/references/sessionlog/src/__tests__/e2e-live.test.ts +0 -890
  1189. package/references/sessionlog/src/__tests__/event-log.test.ts +0 -183
  1190. package/references/sessionlog/src/__tests__/flush-sentinel.test.ts +0 -105
  1191. package/references/sessionlog/src/__tests__/gemini-agent.test.ts +0 -375
  1192. package/references/sessionlog/src/__tests__/git-hooks.test.ts +0 -78
  1193. package/references/sessionlog/src/__tests__/hook-managers.test.ts +0 -121
  1194. package/references/sessionlog/src/__tests__/lifecycle-tasks.test.ts +0 -759
  1195. package/references/sessionlog/src/__tests__/opencode-agent.test.ts +0 -338
  1196. package/references/sessionlog/src/__tests__/redaction.test.ts +0 -136
  1197. package/references/sessionlog/src/__tests__/session-repo.test.ts +0 -353
  1198. package/references/sessionlog/src/__tests__/session-store.test.ts +0 -166
  1199. package/references/sessionlog/src/__tests__/setup-ccweb.test.ts +0 -466
  1200. package/references/sessionlog/src/__tests__/skill-live.test.ts +0 -461
  1201. package/references/sessionlog/src/__tests__/summarize.test.ts +0 -348
  1202. package/references/sessionlog/src/__tests__/task-plan-e2e.test.ts +0 -610
  1203. package/references/sessionlog/src/__tests__/task-plan-live.test.ts +0 -632
  1204. package/references/sessionlog/src/__tests__/transcript-timestamp.test.ts +0 -121
  1205. package/references/sessionlog/src/__tests__/types.test.ts +0 -166
  1206. package/references/sessionlog/src/__tests__/utils.test.ts +0 -333
  1207. package/references/sessionlog/src/__tests__/validation.test.ts +0 -103
  1208. package/references/sessionlog/src/__tests__/worktree.test.ts +0 -57
  1209. package/references/sessionlog/src/agent/registry.ts +0 -143
  1210. package/references/sessionlog/src/agent/session-types.ts +0 -113
  1211. package/references/sessionlog/src/agent/types.ts +0 -220
  1212. package/references/sessionlog/src/cli.ts +0 -597
  1213. package/references/sessionlog/src/commands/clean.ts +0 -133
  1214. package/references/sessionlog/src/commands/disable.ts +0 -84
  1215. package/references/sessionlog/src/commands/doctor.ts +0 -145
  1216. package/references/sessionlog/src/commands/enable.ts +0 -202
  1217. package/references/sessionlog/src/commands/explain.ts +0 -261
  1218. package/references/sessionlog/src/commands/reset.ts +0 -105
  1219. package/references/sessionlog/src/commands/resume.ts +0 -180
  1220. package/references/sessionlog/src/commands/rewind.ts +0 -195
  1221. package/references/sessionlog/src/commands/setup-ccweb.ts +0 -275
  1222. package/references/sessionlog/src/commands/status.ts +0 -172
  1223. package/references/sessionlog/src/config.ts +0 -165
  1224. package/references/sessionlog/src/events/event-log.ts +0 -126
  1225. package/references/sessionlog/src/git-operations.ts +0 -558
  1226. package/references/sessionlog/src/hooks/git-hooks.ts +0 -165
  1227. package/references/sessionlog/src/hooks/lifecycle.ts +0 -391
  1228. package/references/sessionlog/src/index.ts +0 -650
  1229. package/references/sessionlog/src/security/redaction.ts +0 -283
  1230. package/references/sessionlog/src/session/state-machine.ts +0 -452
  1231. package/references/sessionlog/src/store/checkpoint-store.ts +0 -509
  1232. package/references/sessionlog/src/store/native-store.ts +0 -173
  1233. package/references/sessionlog/src/store/provider-types.ts +0 -99
  1234. package/references/sessionlog/src/store/session-store.ts +0 -266
  1235. package/references/sessionlog/src/strategy/attribution.ts +0 -296
  1236. package/references/sessionlog/src/strategy/common.ts +0 -207
  1237. package/references/sessionlog/src/strategy/content-overlap.ts +0 -228
  1238. package/references/sessionlog/src/strategy/manual-commit.ts +0 -988
  1239. package/references/sessionlog/src/strategy/types.ts +0 -279
  1240. package/references/sessionlog/src/summarize/claude-generator.ts +0 -115
  1241. package/references/sessionlog/src/summarize/summarize.ts +0 -432
  1242. package/references/sessionlog/src/types.ts +0 -508
  1243. package/references/sessionlog/src/utils/chunk-files.ts +0 -49
  1244. package/references/sessionlog/src/utils/commit-message.ts +0 -65
  1245. package/references/sessionlog/src/utils/detect-agent.ts +0 -36
  1246. package/references/sessionlog/src/utils/hook-managers.ts +0 -125
  1247. package/references/sessionlog/src/utils/ide-tags.ts +0 -32
  1248. package/references/sessionlog/src/utils/paths.ts +0 -79
  1249. package/references/sessionlog/src/utils/preview-rewind.ts +0 -80
  1250. package/references/sessionlog/src/utils/rewind-conflict.ts +0 -121
  1251. package/references/sessionlog/src/utils/shadow-branch.ts +0 -109
  1252. package/references/sessionlog/src/utils/string-utils.ts +0 -46
  1253. package/references/sessionlog/src/utils/todo-extract.ts +0 -188
  1254. package/references/sessionlog/src/utils/trailers.ts +0 -187
  1255. package/references/sessionlog/src/utils/transcript-parse.ts +0 -177
  1256. package/references/sessionlog/src/utils/transcript-timestamp.ts +0 -59
  1257. package/references/sessionlog/src/utils/tree-ops.ts +0 -219
  1258. package/references/sessionlog/src/utils/tty.ts +0 -72
  1259. package/references/sessionlog/src/utils/validation.ts +0 -65
  1260. package/references/sessionlog/src/utils/worktree.ts +0 -58
  1261. package/references/sessionlog/src/wire-types.ts +0 -59
  1262. package/references/sessionlog/templates/setup-env.sh +0 -153
  1263. package/references/sessionlog/tsconfig.json +0 -18
  1264. package/references/sessionlog/vitest.config.ts +0 -12
  1265. package/references/skill-tree/.claude/settings.json +0 -6
  1266. package/references/skill-tree/.sudocode/issues.jsonl +0 -19
  1267. package/references/skill-tree/.sudocode/specs.jsonl +0 -3
  1268. package/references/skill-tree/CLAUDE.md +0 -132
  1269. package/references/skill-tree/README.md +0 -396
  1270. package/references/skill-tree/docs/GAPS_v1.md +0 -221
  1271. package/references/skill-tree/docs/INTEGRATION_PLAN.md +0 -467
  1272. package/references/skill-tree/docs/TODOS.md +0 -91
  1273. package/references/skill-tree/docs/anthropic_skill_guide.md +0 -1364
  1274. package/references/skill-tree/docs/design/federated-skill-trees.md +0 -524
  1275. package/references/skill-tree/docs/design/multi-agent-sync.md +0 -759
  1276. package/references/skill-tree/docs/scraper/BRAINSTORM.md +0 -583
  1277. package/references/skill-tree/docs/scraper/POC_PLAN.md +0 -420
  1278. package/references/skill-tree/docs/scraper/README.md +0 -170
  1279. package/references/skill-tree/examples/basic-usage.ts +0 -157
  1280. package/references/skill-tree/package-lock.json +0 -1852
  1281. package/references/skill-tree/package.json +0 -66
  1282. package/references/skill-tree/plan.md +0 -78
  1283. package/references/skill-tree/scraper/README.md +0 -123
  1284. package/references/skill-tree/scraper/docs/DESIGN.md +0 -683
  1285. package/references/skill-tree/scraper/docs/PLAN.md +0 -336
  1286. package/references/skill-tree/scraper/drizzle.config.ts +0 -10
  1287. package/references/skill-tree/scraper/package-lock.json +0 -6329
  1288. package/references/skill-tree/scraper/package.json +0 -68
  1289. package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-description.md +0 -7
  1290. package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-name.md +0 -7
  1291. package/references/skill-tree/scraper/test/fixtures/minimal-skill/SKILL.md +0 -27
  1292. package/references/skill-tree/scraper/test/fixtures/skill-json/SKILL.json +0 -21
  1293. package/references/skill-tree/scraper/test/fixtures/skill-with-meta/SKILL.md +0 -54
  1294. package/references/skill-tree/scraper/test/fixtures/skill-with-meta/_meta.json +0 -24
  1295. package/references/skill-tree/scraper/test/fixtures/valid-skill/SKILL.md +0 -93
  1296. package/references/skill-tree/scraper/test/fixtures/valid-skill/_meta.json +0 -22
  1297. package/references/skill-tree/scraper/tsup.config.ts +0 -14
  1298. package/references/skill-tree/scraper/vitest.config.ts +0 -17
  1299. package/references/skill-tree/scripts/convert-to-vitest.ts +0 -166
  1300. package/references/skill-tree/skills/skill-writer/SKILL.md +0 -339
  1301. package/references/skill-tree/skills/skill-writer/references/examples.md +0 -326
  1302. package/references/skill-tree/skills/skill-writer/references/patterns.md +0 -210
  1303. package/references/skill-tree/skills/skill-writer/references/quality-checklist.md +0 -123
  1304. package/references/skill-tree/test/run-all.ts +0 -106
  1305. package/references/skill-tree/test/utils.ts +0 -128
  1306. package/references/skill-tree/vitest.config.ts +0 -16
  1307. package/references/swarmkit/LICENSE +0 -21
  1308. package/references/swarmkit/README.md +0 -130
  1309. package/references/swarmkit/docs/design.md +0 -453
  1310. package/references/swarmkit/docs/package-setup-reference.md +0 -519
  1311. package/references/swarmkit/package-lock.json +0 -1938
  1312. package/references/swarmkit/package.json +0 -43
  1313. package/references/swarmkit/src/cli.ts +0 -41
  1314. package/references/swarmkit/src/commands/add.ts +0 -126
  1315. package/references/swarmkit/src/commands/doctor.ts +0 -117
  1316. package/references/swarmkit/src/commands/hive.ts +0 -279
  1317. package/references/swarmkit/src/commands/init/phases/configure.ts +0 -74
  1318. package/references/swarmkit/src/commands/init/phases/global-setup.ts +0 -104
  1319. package/references/swarmkit/src/commands/init/phases/packages.ts +0 -44
  1320. package/references/swarmkit/src/commands/init/phases/project.ts +0 -81
  1321. package/references/swarmkit/src/commands/init/phases/use-case.ts +0 -47
  1322. package/references/swarmkit/src/commands/init/state.test.ts +0 -23
  1323. package/references/swarmkit/src/commands/init/state.ts +0 -22
  1324. package/references/swarmkit/src/commands/init/wizard.ts +0 -160
  1325. package/references/swarmkit/src/commands/init.ts +0 -17
  1326. package/references/swarmkit/src/commands/login.ts +0 -106
  1327. package/references/swarmkit/src/commands/logout.ts +0 -22
  1328. package/references/swarmkit/src/commands/remove.ts +0 -72
  1329. package/references/swarmkit/src/commands/status.ts +0 -101
  1330. package/references/swarmkit/src/commands/update.ts +0 -62
  1331. package/references/swarmkit/src/commands/whoami.ts +0 -41
  1332. package/references/swarmkit/src/config/global.test.ts +0 -258
  1333. package/references/swarmkit/src/config/global.ts +0 -141
  1334. package/references/swarmkit/src/config/keys.test.ts +0 -109
  1335. package/references/swarmkit/src/config/keys.ts +0 -49
  1336. package/references/swarmkit/src/doctor/checks.test.ts +0 -366
  1337. package/references/swarmkit/src/doctor/checks.ts +0 -292
  1338. package/references/swarmkit/src/doctor/types.ts +0 -33
  1339. package/references/swarmkit/src/hub/auth-flow.test.ts +0 -127
  1340. package/references/swarmkit/src/hub/auth-flow.ts +0 -144
  1341. package/references/swarmkit/src/hub/client.test.ts +0 -224
  1342. package/references/swarmkit/src/hub/client.ts +0 -185
  1343. package/references/swarmkit/src/hub/credentials.test.ts +0 -132
  1344. package/references/swarmkit/src/hub/credentials.ts +0 -51
  1345. package/references/swarmkit/src/index.ts +0 -116
  1346. package/references/swarmkit/src/packages/installer.test.ts +0 -365
  1347. package/references/swarmkit/src/packages/installer.ts +0 -206
  1348. package/references/swarmkit/src/packages/plugin.test.ts +0 -141
  1349. package/references/swarmkit/src/packages/plugin.ts +0 -46
  1350. package/references/swarmkit/src/packages/registry.test.ts +0 -235
  1351. package/references/swarmkit/src/packages/registry.ts +0 -209
  1352. package/references/swarmkit/src/packages/setup.test.ts +0 -1395
  1353. package/references/swarmkit/src/packages/setup.ts +0 -671
  1354. package/references/swarmkit/src/utils/ui.test.ts +0 -115
  1355. package/references/swarmkit/src/utils/ui.ts +0 -62
  1356. package/references/swarmkit/tsconfig.json +0 -17
  1357. package/references/swarmkit/vitest.config.ts +0 -9
@@ -1,24 +0,0 @@
1
- {"id":"s-7u8f","uuid":"605bb90c-778e-4a77-95b8-f136577f4f67","title":"OpenTasks Implementation Plan","file_path":"specs/s-7u8f_opentasks_implementation_plan.md","content":"# OpenTasks Implementation Plan\n\nThis spec outlines the phased implementation approach for OpenTasks - a universal work graph data structure.\n\n## Overview\n\nOpenTasks provides:\n1. **Persistent task tracking** - Replaces Claude's ephemeral tasks with git-friendly persistence\n2. **Unified abstraction** - Works over beads/sudocode/other task systems\n3. **External integration** - Bridges to Jira, Linear, GitHub Issues\n\n## Architecture Summary\n\n- **4 Node Types**: Spec (intent), Issue (work), Feedback (comments), External (references)\n- **Graph-Native**: Edges are first-class (blocks, implements, references)\n- **Hierarchical Locations**: `~/.opentasks/` → workspace → project → subproject\n- **Daemon Per Location**: IPC, file watching, flush coordination\n- **Federated Providers**: OpenTasks owns graph; providers own content\n\n## Implementation Phases\n\n### Phase 1: Core Data Layer\n**Goal**: Establish foundational types and persistence\n\n| Component | Description | Key Files |\n|-----------|-------------|-----------|\n| Schema/Types | TypeScript types for nodes, edges, storage | `src/schema/` |\n| ID Generation | Hash-based IDs with adaptive length | `src/core/id.ts` |\n| JSONL Persister | Read/write graph.jsonl with atomic writes | `src/persistence/jsonl.ts` |\n| SQLite Persister | Query cache, indexes, views | `src/persistence/sqlite.ts` |\n\n**Deliverables**:\n- [ ] `StoredNode`, `Node`, `Edge` types\n- [ ] `generateId()` with collision-resistant hashing\n- [ ] `JSONLPersister` with atomic writes\n- [ ] `SQLitePersister` with query indexes\n\n### Phase 2: Graph Operations\n**Goal**: CRUD and query capabilities\n\n| Component | Description | Key Files |\n|-----------|-------------|-----------|\n| Graph Store | Node/edge CRUD, transaction support | `src/graph/store.ts` |\n| Query Engine | Filter, traverse, ready computation | `src/graph/query.ts` |\n| Validation | Type-specific validation rules | `src/graph/validation.ts` |\n\n**Deliverables**:\n- [ ] `GraphStore` with create/read/update/delete\n- [ ] `QueryEngine` with filter and traversal\n- [ ] `ready()` computation (no active blockers)\n- [ ] Node validation per type\n\n### Phase 3: Daemon & IPC\n**Goal**: Background process for coordination\n\n| Component | Description | Key Files |\n|-----------|-------------|-----------|\n| Daemon Lifecycle | Start, stop, lock, signal handling | `src/daemon/lifecycle.ts` |\n| IPC Server | Unix socket, JSON-RPC protocol | `src/daemon/ipc.ts` |\n| Flush Manager | Debounced writes, dirty tracking | `src/daemon/flush.ts` |\n| File Watcher | Detect external JSONL/markdown changes | `src/daemon/watcher.ts` |\n\n**Deliverables**:\n- [ ] Daemon with PID file and lock\n- [ ] Unix socket IPC server\n- [ ] Debounced flush with max delay\n- [ ] File watcher with change detection\n\n### Phase 4: Agent Interface\n**Goal**: 3-tool API for agents\n\n| Component | Description | Key Files |\n|-----------|-------------|-----------|\n| link | Create/remove relationships | `src/tools/link.ts` |\n| query | Query graph, blockers, ready | `src/tools/query.ts` |\n| annotate | Add feedback, tags, metadata | `src/tools/annotate.ts` |\n| Client Library | Connect to daemon, make requests | `src/client/` |\n\n**Deliverables**:\n- [ ] `link()` tool implementation\n- [ ] `query()` tool with all query types\n- [ ] `annotate()` tool with routing logic\n- [ ] `OpenTasksClient` class\n\n### Phase 5: Providers\n**Goal**: External system integration\n\n| Component | Description | Key Files |\n|-----------|-------------|-----------|\n| Provider Interface | Base contract for all providers | `src/providers/interface.ts` |\n| Native Providers | Fallback spec/issue storage | `src/providers/native.ts` |\n| Beads Provider | Integration with beads CLI | `src/providers/beads.ts` |\n| Taskmaster Provider | Integration with taskmaster | `src/providers/taskmaster.ts` |\n\n**Deliverables**:\n- [ ] `ContentProvider` interface\n- [ ] `NativeSpecProvider` and `NativeIssueProvider`\n- [ ] `BeadsProvider` with CLI integration\n- [ ] `TaskmasterProvider` with file parsing\n\n### Phase 6: Advanced Features\n**Goal**: Full feature set\n\n| Component | Description | Key Files |\n|-----------|-------------|-----------|\n| Cross-Location | URI resolution, daemon discovery | `src/location/` |\n| Markdown Sync | Bidirectional JSONL ↔ markdown | `src/persistence/markdown.ts` |\n| Compaction | Tiered cleanup, tombstone management | `src/persistence/compaction.ts` |\n\n**Deliverables**:\n- [ ] `LocationResolver` with URI parsing\n- [ ] `MarkdownPersister` with sync\n- [ ] `Compactor` with tiered cleanup\n- [ ] Global daemon registry\n\n## Dependency Graph\n\n```\nPhase 1 ──────────────────────────────────────────┐\n │ │\n ▼ │\nPhase 2 ──────────────────────────────────────────┤\n │ │\n ├────────────────┐ │\n ▼ ▼ │\nPhase 3 Phase 4 (partial - types only) │\n │ │ │\n └────────┬───────┘ │\n ▼ │\n Phase 4 (full - needs daemon) │\n │ │\n ▼ │\n Phase 5 ────────────────────────────────────┤\n │ │\n ▼ │\n Phase 6 ◄───────────────────────────────────┘\n```\n\n## Tech Stack\n\n- **Language**: TypeScript\n- **Runtime**: Node.js\n- **Storage**: JSONL (source of truth) + SQLite (cache)\n- **IPC**: Unix domain sockets, JSON-RPC\n- **Testing**: Vitest\n- **Build**: tsup or esbuild\n\n## Open Questions\n\n- [ ] Package structure: monorepo or single package?\n- [ ] CLI interface beyond MCP tools?\n- [ ] Which provider to implement first beyond native?\n\n## References\n\n- [DESIGN.md](./docs/DESIGN.md) - Design rationale\n- [SCHEMA.md](./docs/SCHEMA.md) - Data model\n- [ARCHITECTURE.md](./docs/ARCHITECTURE.md) - Daemon, locations\n- [PERSISTENCE.md](./docs/PERSISTENCE.md) - Storage layer\n- [PROVIDERS.md](./docs/PROVIDERS.md) - Provider integration\n- [INTERFACE.md](./docs/INTERFACE.md) - 3-tool API\n","priority":0,"archived":0,"archived_at":null,"created_at":"2026-01-27 10:10:03","updated_at":"2026-01-27 10:10:03","parent_id":null,"parent_uuid":null,"relationships":[],"tags":["architecture","implementation","opentasks"]}
2
- {"id":"s-4l4m","uuid":"2142456d-a492-4e5c-b078-4891b533fea7","title":"Phase 1: Core Data Layer","file_path":"specs/s-4l4m_phase_1_core_data_layer.md","content":"# Phase 1: Core Data Layer\n\nFoundation layer for OpenTasks. Establishes types, ID generation, and persistence.\n\n**Key Decisions (following beads patterns):**\n- Join table for tags (not JSON array)\n- Edge direction: `from` blocks `to`\n- Custom Storage interface (not TinyBase)\n- Permissive storage, strict application validation\n\n## Overview\n\nThis phase delivers:\n1. **TypeScript Schema** - Node types, edges, storage format\n2. **ID Generation** - Hash-based, collision-resistant IDs\n3. **JSONL Persister** - Git-friendly source of truth\n4. **SQLite Persister** - Fast query cache with join tables\n\n## 1. TypeScript Schema\n\n### File Structure\n\n```\nsrc/\n├── schema/\n│ ├── index.ts # Re-exports\n│ ├── base.ts # BaseNode, common types\n│ ├── nodes.ts # Spec, Issue, Feedback, ExternalNode\n│ ├── edges.ts # Edge types\n│ ├── storage.ts # StoredNode (flexible JSONL format)\n│ └── validation.ts # Type guards, validators\n```\n\n### Core Design Decisions\n\n**Decision 1: Hybrid Storage/Application Model**\n\n- **Storage layer**: Permissive - unknown fields preserved, forward compatible\n- **Application layer**: Strict - type guards validate required fields\n\n```typescript\n// Storage: flexible for JSONL (permissive)\ninterface StoredNode {\n id: string\n uuid: string\n type: string\n title: string\n created_at: string\n updated_at: string\n [key: string]: unknown // preserve unknown fields\n}\n\n// Application: strict discriminated union\ntype Node = Spec | Issue | Feedback | ExternalNode\n```\n\n**Decision 2: ID Format**\n\nPrefix indicates type, hash provides uniqueness:\n- `s-` Spec (e.g., `s-a2b3`)\n- `i-` Issue (e.g., `i-x7k9`)\n- `f-` Feedback (e.g., `f-m4n5`)\n- `e-` External (e.g., `e-p6q7`)\n- `x-` Edge (e.g., `x-r8s9`)\n\n**Decision 3: Edge Direction**\n\n`from` blocks `to` - the source node must complete before target can start:\n```typescript\n// i-123 must complete before i-456 can start\n{ from_id: \"i-123\", to_id: \"i-456\", type: \"blocks\" }\n```\n\n**Decision 4: Timestamps as ISO 8601 strings**\n\nStrings are JSON-native and git-diff friendly. Parse to Date when needed.\n\n### Node Types\n\n#### BaseNode (shared fields)\n\n```typescript\ninterface BaseNode {\n // Identity\n id: string // hash-based: prefix + base36\n uuid: string // UUID v4 for distributed sync\n\n // Core\n title: string\n content?: string // markdown body\n content_hash?: string // SHA256 for dedup\n\n // Timestamps\n created_at: string // ISO 8601\n updated_at: string\n\n // Organization\n priority?: number // 0 (highest) to 4 (lowest)\n tags?: string[] // NOTE: stored in join table in SQLite\n parent_id?: string // hierarchy support\n\n // Context\n location?: string // opentasks:// URI\n branch?: string // git branch\n source?: string // origin: \"local\" | provider name\n\n // Coordination\n claimed_by?: string // agent/user ID\n claimed_at?: string\n lock_until?: string // soft lock expiry\n\n // Lifecycle\n archived?: boolean\n archived_at?: string\n\n // Extensibility\n metadata?: Record<string, unknown>\n}\n```\n\n#### Spec\n\n```typescript\ninterface Spec extends BaseNode {\n type: 'spec'\n status?: 'draft' | 'active' | 'archived' | string\n}\n```\n\n#### Issue\n\n```typescript\ninterface Issue extends BaseNode {\n type: 'issue'\n status: 'open' | 'in_progress' | 'blocked' | 'closed' | string // required\n assignee?: string\n closed_at?: string\n}\n```\n\n#### Feedback\n\n```typescript\ninterface Feedback extends BaseNode {\n type: 'feedback'\n target_id: string // required: what this is about\n target_anchor?: Anchor // optional: location in target\n feedback_type: 'comment' | 'suggestion' | 'request' | string // required\n thread_id?: string\n reply_to_id?: string\n resolved?: boolean\n resolved_at?: string\n dismissed?: boolean\n dismissed_at?: string\n}\n\ninterface Anchor {\n line?: number // 1-indexed\n text?: string // fuzzy match if line moves\n section?: string // heading\n context_before?: string\n context_after?: string\n anchor_status?: 'valid' | 'relocated' | 'stale'\n}\n```\n\n#### ExternalNode\n\n```typescript\ninterface ExternalNode extends BaseNode {\n type: 'external'\n uri: string // required: canonical URI\n source: string // required: provider name\n materialized: boolean // has data been fetched?\n cached_at?: string\n stale?: boolean\n external_status?: string // provider's status\n external_data?: Record<string, unknown>\n}\n```\n\n#### Node Union & Type Guards\n\n```typescript\ntype Node = Spec | Issue | Feedback | ExternalNode\n\nfunction isSpec(node: Node): node is Spec { return node.type === 'spec' }\nfunction isIssue(node: Node): node is Issue { return node.type === 'issue' }\nfunction isFeedback(node: Node): node is Feedback { return node.type === 'feedback' }\nfunction isExternal(node: Node): node is ExternalNode { return node.type === 'external' }\n```\n\n### Edge Types\n\n```typescript\ninterface Edge {\n id: string // x-xxxx\n uuid: string\n from_id: string // source node ID or URI\n to_id: string // target node ID or URI\n type: EdgeType\n created_at: string\n created_by?: string\n source?: string // origin system\n metadata?: Record<string, unknown>\n}\n\n// Edge semantics: from -> to\n// \"blocks\": from must complete before to can start\n// \"implements\": from (issue) implements to (spec)\n\ntype CoreEdgeType =\n | 'blocks' // from blocks to (dependency)\n | 'implements' // issue implements spec\n | 'references' // general reference\n | 'related' // loose association\n\ntype ExtendedEdgeType =\n | 'parent-of'\n | 'child-of'\n | 'duplicates'\n | 'supersedes'\n | 'depends-on'\n | 'discovered-from'\n\ntype EdgeType = CoreEdgeType | ExtendedEdgeType | string\n```\n\n## 2. ID Generation\n\n### Algorithm (following beads)\n\n```typescript\nfunction generateId(type: NodeType, existingCount: number): { id: string; uuid: string } {\n // 1. Generate UUID v4\n const uuid = crypto.randomUUID()\n \n // 2. SHA256 hash the UUID\n const hash = sha256(uuid)\n \n // 3. Convert to base36 (0-9, a-z)\n const base36 = toBase36(hash)\n \n // 4. Adaptive length based on collision probability\n const length = adaptiveLength(existingCount)\n \n // 5. Prepend type prefix\n const prefix = typePrefix(type)\n \n return {\n id: `${prefix}-${base36.slice(0, length)}`,\n uuid\n }\n}\n\nfunction adaptiveLength(count: number): number {\n // Birthday paradox: ~1% collision probability\n if (count < 980) return 4 // s-a2b3\n if (count < 5900) return 5 // s-a2b3f\n if (count < 35000) return 6 // s-a2b3fg\n if (count < 212000) return 7 // s-a2b3fgh\n return 8 // s-a2b3fghi\n}\n\nfunction typePrefix(type: string): string {\n const prefixes: Record<string, string> = {\n spec: 's', issue: 'i', feedback: 'f', external: 'e', edge: 'x'\n }\n return prefixes[type] || 'n'\n}\n```\n\n### Content Hashing (for dedup on merge)\n\n```typescript\nfunction computeContentHash(node: StoredNode): string {\n // Only substantive fields (excludes id, uuid, timestamps, coordination)\n const substantive = {\n type: node.type,\n title: node.title,\n content: node.content,\n status: node.status,\n priority: node.priority,\n tags: node.tags?.sort(),\n parent_id: node.parent_id,\n // Type-specific\n ...(node.type === 'issue' && { assignee: node.assignee }),\n ...(node.type === 'feedback' && {\n target_id: node.target_id,\n feedback_type: node.feedback_type,\n }),\n ...(node.type === 'external' && { uri: node.uri, source: node.source }),\n }\n \n return sha256(JSON.stringify(substantive, Object.keys(substantive).sort()))\n}\n```\n\n## 3. Storage Interface (beads pattern)\n\n### Core Interface\n\n```typescript\n/**\n * Storage interface following beads pattern.\n * Domain-driven, not generic table operations.\n */\ninterface Storage {\n // === Nodes ===\n createNode(node: StoredNode, actor?: string): Promise<void>\n getNode(id: string): Promise<StoredNode | null>\n updateNode(id: string, updates: Partial<StoredNode>, actor?: string): Promise<void>\n deleteNode(id: string, actor?: string): Promise<void>\n queryNodes(filter: NodeFilter): Promise<StoredNode[]>\n \n // === Edges ===\n createEdge(edge: Edge, actor?: string): Promise<void>\n getEdge(id: string): Promise<Edge | null>\n deleteEdge(id: string, actor?: string): Promise<void>\n getEdgesFrom(nodeId: string, type?: EdgeType): Promise<Edge[]>\n getEdgesTo(nodeId: string, type?: EdgeType): Promise<Edge[]>\n \n // === Tags (join table) ===\n addTag(nodeId: string, tag: string, actor?: string): Promise<void>\n removeTag(nodeId: string, tag: string, actor?: string): Promise<void>\n getTags(nodeId: string): Promise<string[]>\n getTagsForNodes(nodeIds: string[]): Promise<Map<string, string[]>>\n getNodesByTag(tag: string): Promise<StoredNode[]>\n \n // === Queries ===\n getReady(): Promise<StoredNode[]> // issues with no active blockers\n \n // === Transactions ===\n runInTransaction<T>(fn: (tx: Transaction) => Promise<T>): Promise<T>\n \n // === Dirty Tracking ===\n markDirty(nodeId: string): Promise<void>\n getDirtyNodes(): Promise<string[]>\n clearDirty(nodeIds: string[]): Promise<void>\n \n // === Lifecycle ===\n close(): Promise<void>\n}\n\ninterface Transaction {\n createNode(node: StoredNode, actor?: string): Promise<void>\n updateNode(id: string, updates: Partial<StoredNode>, actor?: string): Promise<void>\n createEdge(edge: Edge, actor?: string): Promise<void>\n addTag(nodeId: string, tag: string, actor?: string): Promise<void>\n}\n\ninterface NodeFilter {\n type?: string | string[]\n status?: string | string[]\n tags?: string[] // AND semantics\n parent_id?: string\n archived?: boolean\n search?: string // title/content search\n limit?: number\n offset?: number\n}\n```\n\n## 4. JSONL Persister\n\n### File Format\n\n```\n.opentasks/\n├── graph.jsonl # Nodes + edges (source of truth)\n├── tombstones.jsonl # Soft deletes (optional gitignore)\n└── config.json # Location config\n```\n\n**graph.jsonl format:**\n```jsonl\n{\"id\":\"s-a2b3\",\"uuid\":\"...\",\"type\":\"spec\",\"title\":\"Auth requirements\",\"tags\":[\"auth\"],...}\n{\"id\":\"i-x7k9\",\"uuid\":\"...\",\"type\":\"issue\",\"title\":\"Implement login\",\"status\":\"open\",...}\n{\"id\":\"x-r8s9\",\"uuid\":\"...\",\"from_id\":\"i-x7k9\",\"to_id\":\"s-a2b3\",\"type\":\"implements\",...}\n```\n\nNote: Tags are stored inline in JSONL but in a join table in SQLite.\n\n### Implementation\n\n```typescript\ninterface JSONLPersisterConfig {\n path: string // e.g., \".opentasks/graph.jsonl\"\n tombstonesPath?: string // e.g., \".opentasks/tombstones.jsonl\"\n atomicWrite?: boolean // default: true\n}\n\nclass JSONLPersister {\n async load(): Promise<{ nodes: StoredNode[]; edges: Edge[] }>\n async save(nodes: StoredNode[], edges: Edge[]): Promise<void>\n async append(entry: StoredNode | Edge): Promise<void>\n watch(callback: () => void): () => void // returns unsubscribe\n}\n\nasync function atomicWrite(path: string, content: string): Promise<void> {\n const tempPath = `${path}.${process.pid}.tmp`\n await fs.writeFile(tempPath, content)\n await fs.rename(tempPath, path)\n}\n```\n\n## 5. SQLite Persister\n\n### Schema (with join table for tags)\n\n```sql\n-- Nodes table\nCREATE TABLE nodes (\n id TEXT PRIMARY KEY,\n uuid TEXT UNIQUE NOT NULL,\n type TEXT NOT NULL,\n title TEXT NOT NULL,\n content TEXT,\n content_hash TEXT,\n status TEXT,\n priority INTEGER,\n assignee TEXT,\n parent_id TEXT,\n source TEXT,\n archived INTEGER DEFAULT 0,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n \n -- Feedback fields\n target_id TEXT,\n feedback_type TEXT,\n \n -- External fields\n uri TEXT,\n materialized INTEGER,\n \n FOREIGN KEY (parent_id) REFERENCES nodes(id)\n);\n\n-- Tags join table (following beads pattern)\nCREATE TABLE node_tags (\n node_id TEXT NOT NULL,\n tag TEXT NOT NULL,\n PRIMARY KEY (node_id, tag),\n FOREIGN KEY (node_id) REFERENCES nodes(id) ON DELETE CASCADE\n);\nCREATE INDEX idx_node_tags_tag ON node_tags(tag);\n\n-- Edges table\nCREATE TABLE edges (\n id TEXT PRIMARY KEY,\n uuid TEXT UNIQUE NOT NULL,\n from_id TEXT NOT NULL,\n to_id TEXT NOT NULL,\n type TEXT NOT NULL,\n created_at TEXT NOT NULL,\n created_by TEXT,\n source TEXT\n);\n\n-- Indexes\nCREATE INDEX idx_nodes_type ON nodes(type);\nCREATE INDEX idx_nodes_status ON nodes(status);\nCREATE INDEX idx_nodes_parent ON nodes(parent_id);\nCREATE INDEX idx_nodes_archived ON nodes(archived);\nCREATE INDEX idx_edges_from ON edges(from_id);\nCREATE INDEX idx_edges_to ON edges(to_id);\nCREATE INDEX idx_edges_type ON edges(type);\n\n-- Ready issues view (no active blockers)\nCREATE VIEW ready_issues AS\nSELECT n.* FROM nodes n\nWHERE n.type = 'issue'\n AND n.status = 'open'\n AND n.archived = 0\n AND NOT EXISTS (\n SELECT 1 FROM edges e\n JOIN nodes blocker ON e.from_id = blocker.id\n WHERE e.to_id = n.id\n AND e.type = 'blocks'\n AND blocker.status != 'closed'\n AND blocker.archived = 0\n );\n\n-- Dirty tracking (for incremental export)\nCREATE TABLE dirty_nodes (\n node_id TEXT PRIMARY KEY,\n marked_at TEXT NOT NULL\n);\n\n-- Export hashes (for content-based change detection)\nCREATE TABLE export_hashes (\n node_id TEXT PRIMARY KEY,\n content_hash TEXT NOT NULL\n);\n```\n\n### Implementation\n\n```typescript\ninterface SQLitePersisterConfig {\n path: string // e.g., \".opentasks/cache.db\"\n walMode?: boolean // default: true (better concurrency)\n}\n\nclass SQLitePersister implements Storage {\n private db: Database // better-sqlite3\n \n // Rebuild cache from JSONL\n async rebuildFromJsonl(jsonlPath: string): Promise<void>\n \n // Tag operations use join table\n async addTag(nodeId: string, tag: string): Promise<void> {\n this.db.prepare(`\n INSERT OR IGNORE INTO node_tags (node_id, tag) VALUES (?, ?)\n `).run(nodeId, tag)\n await this.markDirty(nodeId)\n }\n \n async getNodesByTag(tag: string): Promise<StoredNode[]> {\n return this.db.prepare(`\n SELECT n.* FROM nodes n\n JOIN node_tags t ON n.id = t.node_id\n WHERE t.tag = ?\n `).all(tag)\n }\n \n async getReady(): Promise<StoredNode[]> {\n return this.db.prepare('SELECT * FROM ready_issues').all()\n }\n}\n```\n\n## Deliverables Checklist\n\n- [ ] `src/schema/base.ts` - BaseNode interface\n- [ ] `src/schema/nodes.ts` - Spec, Issue, Feedback, ExternalNode\n- [ ] `src/schema/edges.ts` - Edge interface and types\n- [ ] `src/schema/storage.ts` - StoredNode (flexible format)\n- [ ] `src/schema/validation.ts` - Type guards and validators\n- [ ] `src/schema/index.ts` - Re-exports\n- [ ] `src/core/id.ts` - generateId, computeContentHash\n- [ ] `src/storage/interface.ts` - Storage interface\n- [ ] `src/storage/jsonl.ts` - JSONLPersister\n- [ ] `src/storage/sqlite.ts` - SQLitePersister (with better-sqlite3)\n- [ ] `src/storage/index.ts` - Re-exports\n- [ ] Tests for all modules\n\n## Resolved Decisions\n\n| Question | Decision | Rationale |\n|----------|----------|-----------|\n| Tags storage | Join table `node_tags(node_id, tag)` | Follows beads, fast queries by tag |\n| Edge direction | `from` blocks `to` | Intuitive: source must complete first |\n| Storage abstraction | Custom Storage interface | Follows beads, simpler than TinyBase |\n| SQLite library | `better-sqlite3` | Sync API, fast, well-maintained |\n| Validation | Permissive storage, strict app | Forward compatible, type-safe usage |\n\n## References\n\n- [[s-7u8f|OpenTasks Implementation Plan]]\n- [SCHEMA.md](../docs/SCHEMA.md)\n- [PERSISTENCE.md](../docs/PERSISTENCE.md)\n- Beads reference: `references/beads/internal/storage/`\n","priority":0,"archived":0,"archived_at":null,"created_at":"2026-01-27 10:18:37","updated_at":"2026-01-27 20:04:29","parent_id":"s-7u8f","parent_uuid":"605bb90c-778e-4a77-95b8-f136577f4f67","relationships":[],"tags":["opentasks","persistence","phase-1","schema"]}
3
- {"id":"s-9jju","uuid":"50f4aa8e-9378-4238-909d-4e1a117452fb","title":"OpenTasks Core Architecture","file_path":"specs/s-9jju_opentasks_core_architecture.md","content":"# OpenTasks Core Architecture\n\n## Overview\n\nOpenTasks is a **graph connector** that links heterogeneous task and spec systems. It does not replace existing tools — each keeps its own interface, storage, and semantics. OpenTasks provides the **relationship layer** that existing tools lack.\n\n### What OpenTasks Is\n- A graph layer over existing tools (Claude Tasks, Beads, Taskmaster, Jira, etc.)\n- Cross-system edges that span system boundaries\n- Unified queries for blockers, ready items, and dependencies across all connected systems\n- Optional native storage for lightweight specs/issues when external providers aren't needed\n\n### What OpenTasks Is NOT\n- Not a replacement for Claude's built-in tasks (use `TaskCreate`/`TaskUpdate` directly)\n- Not a replacement for Beads (use `bd` CLI directly)\n- Not a unified CRUD API (each system keeps its own interface)\n\n---\n\n## Core Concepts\n\n### Node Types\n\n| Type | Purpose | Storage |\n|------|---------|---------|\n| `spec` | User intent, requirements, context | Native (graph.jsonl) or provider |\n| `issue` | Actionable work items | Native (graph.jsonl) or provider |\n| `feedback` | Comments, suggestions, anchored discussion | Native (graph.jsonl) |\n| `external` | Cached references to external systems | Native (graph.jsonl) |\n\n### Edges\n\nEdges are the primary value of OpenTasks. They connect nodes across system boundaries:\n\n```\nclaude://current/t-abc ──implements──▶ beads://./bd-x7k9\nbeads://./bd-x7k9 ──blocks──▶ jira://PROJ-123\ntaskmaster://./prd ◀──discovered-from── beads://./bd-y8z0\n```\n\n**Core edge types**: `blocks`, `implements`, `references`, `related`\n**Extended types**: `parent-of`, `child-of`, `duplicates`, `supersedes`, `depends-on`, `discovered-from`\n\n### The 3-Tool Interface\n\nAgents use native tools for CRUD (TaskCreate, bd new, etc.). OpenTasks provides 3 tools for the graph layer:\n\n| Tool | Purpose |\n|------|---------|\n| `link()` | Create/remove edges between any nodes |\n| `query()` | Find relationships, blockers, ready items |\n| `annotate()` | Add cross-system feedback |\n\n---\n\n## URI Schemes\n\n### Provider URIs\n\nReference nodes in external systems:\n\n```\nclaude://[session]/[task-id] # Claude Code task\nbeads://[workspace]/[id] # Beads issue \ntaskmaster://[project]/[id] # Taskmaster PRD/task\nlinear://[team]/[id] # Linear issue\njira://[project]/[key] # Jira issue\ngithub://[owner]/[repo]/[num] # GitHub issue\nnative://[type]/[id] # OpenTasks native node\n```\n\n**Relative notation**: `beads://./bd-123` means current workspace\n**Implicit current**: `beads://bd-123` equivalent to `beads://./bd-123`\n\n### OpenTasks URIs (Phase 2+)\n\nReference nodes in other OpenTasks locations:\n\n```\nopentasks://./i-x7k9 # Current location\nopentasks://~/.opentasks/s-a2b3 # User-level location\nopentasks://../.opentasks/i-e6f7 # Parent directory\nopentasks:///abs/path/.opentasks/s-g8h9 # Absolute path\n```\n\n---\n\n## Cross-Location Model\n\n### Location Hierarchy\n\n```\n~/.opentasks/ # User level\n~/projects/.opentasks/ # Workspace level\n~/projects/myapp/.opentasks/ # Project level\n~/projects/myapp/packages/core/.opentasks/ # Subproject level\n```\n\n### Isolation by Default\n\nEach location is **isolated by default**:\n- Queries only return nodes from the current location\n- No automatic inheritance from parent locations\n- No automatic discovery of child locations\n- Explicit connectivity via edges with URIs\n\n### Worktree Model\n\nFor agent swarms in git worktrees:\n\n```\nrepo/\n├── .git/\n├── main-worktree/\n│ └── .opentasks/ # Manager agent's graph\n├── feature-a-worktree/\n│ └── .opentasks/ # Worker A's graph (cloned, with redirect)\n│ └── config.json # redirect → main-worktree\n└── feature-b-worktree/\n └── .opentasks/ # Worker B's graph (cloned, with redirect)\n └── config.json # redirect → main-worktree\n```\n\n**Redirect Rules**:\n- Sub-agents get their own cloned `.opentasks/` directory\n- Config contains redirect rules pointing to manager's location\n- Manager can update worker's config during worktree setup\n- Supports chained redirects (worker → manager → orchestrator)\n\n```json\n{\n \"redirects\": [\n {\n \"operations\": [\"read\", \"write\"],\n \"pattern\": \"*\",\n \"target\": \"opentasks://../main-worktree/.opentasks/\"\n }\n ]\n}\n```\n\n---\n\n## Storage Design\n\n### File Structure\n\n```\n.opentasks/\n├── graph.jsonl # Nodes + edges (source of truth)\n├── tombstones.jsonl # Soft deletes (configurable gitignore)\n├── cache.db # SQLite (queries, indexes) - gitignored\n├── config.json # Configuration, redirects\n├── specs/ # Optional: markdown expansion\n├── issues/ # Optional: markdown expansion\n└── daemon.sock # Daemon socket (when running)\n```\n\n### Edge Storage Format (Option C)\n\nShort IDs for local nodes, full URIs for external:\n\n```jsonl\n{\"id\":\"x-r8s9\",\"from_id\":\"i-x7k9\",\"to_id\":\"s-a2b3\",\"type\":\"implements\",...}\n{\"id\":\"x-t1u2\",\"from_id\":\"i-x7k9\",\"to_id\":\"beads://./bd-123\",\"type\":\"blocks\",...}\n{\"id\":\"x-v3w4\",\"from_id\":\"i-x7k9\",\"to_id\":\"opentasks://../other/.opentasks/i-y8z0\",\"type\":\"references\",...}\n```\n\n### ID Generation\n\nHash-based IDs for collision resistance in multi-agent scenarios:\n- Prefix indicates type: `s-` (spec), `i-` (issue), `f-` (feedback), `e-` (external), `x-` (edge)\n- Adaptive length based on entity count (4-8 chars)\n- Example: `i-x7k9`, `s-a2b3f`\n\n---\n\n## Implementation Phases\n\n### Phase 1 / L2: Single-Location + Provider URIs (v1)\n\n**Scope**:\n- One `.opentasks/` directory per working context\n- Edges reference provider URIs: `beads://`, `claude://`, `jira://`, etc.\n- Native provider for optional local specs/issues (toggleable)\n- Direct file access (no daemon)\n- No `opentasks://` URIs to other locations\n- No cross-location queries\n\n**Deliverables**:\n- [ ] Core schema (nodes, edges) with TypeScript types\n- [ ] JSONL persister (read/write graph.jsonl)\n- [ ] SQLite cache persister (indexes, queries)\n- [ ] 3-tool interface: link, query, annotate\n- [ ] Native provider for specs/issues\n- [ ] Provider registry and URI resolution\n- [ ] Basic provider implementations (Beads, Claude Tasks stubs)\n\n**Schema preparation for future phases**:\n- Store location metadata in config.json\n- Design edge schema to support full URIs\n- Include `source` field on nodes for provider tracking\n\n### Phase 2 / L3: Cross-Location References (v2)\n\n**Scope**:\n- `opentasks://` URIs for referencing other locations\n- URI resolution (relative paths, absolute paths, `~` expansion)\n- Daemon per location (auto-start on first operation)\n- Global registry for daemon discovery (`~/.opentasks/registry.json`)\n- Redirect rules (basic: single target per location)\n\n**Deliverables**:\n- [ ] opentasks:// URI parser and resolver\n- [ ] Daemon architecture (socket, IPC protocol)\n- [ ] Global daemon registry\n- [ ] Redirect configuration and resolution\n- [ ] Cross-location node resolution (follow URIs to other daemons)\n\n### Phase 3 / L4-L5: Multi-Location Queries (v3)\n\n**Scope**:\n- Location discovery (find .opentasks/ in ancestors/descendants)\n- Query expansion modes: `follow-refs`, `ancestors`, `descendants`, `siblings`, `all`\n- Advanced redirect rules (conditional, pattern-based)\n- Cross-location `ready()` queries\n- Worktree detection and automatic redirect setup\n\n**Deliverables**:\n- [ ] Location discovery service\n- [ ] Expansion mode implementation\n- [ ] Conditional redirect rules\n- [ ] Cross-daemon query coordination\n- [ ] Worktree context detection\n\n---\n\n## Design Decisions\n\n| Decision | Choice | Rationale |\n|----------|--------|-----------|\n| Core identity | Graph connector | Existing tools handle CRUD; OpenTasks adds relationships |\n| Interface | 3 tools (link, query, annotate) | Providers have their own CRUD; OpenTasks is additive |\n| Edge storage | Option C (short local, URI external) | Simple common case, explicit for cross-boundary |\n| Worktree model | Clone + redirect | Sub-agents get isolation with configurable routing |\n| Daemon | Required for multi-agent (Phase 2+) | Coordination, caching, cross-location resolution |\n| Native provider | Optional, toggleable | Lightweight use without external dependencies |\n\n---\n\n## Open Questions\n\n### For Phase 1\n- [ ] Exact provider interface for Beads, Claude Tasks\n- [ ] How to handle `claude://current/` session scoping\n- [ ] Feedback routing rules (native vs provider comments)\n\n### For Phase 2+\n- [ ] Daemon auto-start behavior and lifecycle\n- [ ] Registry cleanup for stale daemons\n- [ ] Authentication for cross-location access\n\n### Deferred\n- [ ] Remote repository locations (`opentasks://github.com/...`)\n- [ ] P2P sync between locations\n- [ ] Compaction and archival strategies\n","priority":0,"archived":0,"archived_at":null,"created_at":"2026-01-27 19:09:25","updated_at":"2026-01-27 19:09:25","parent_id":null,"parent_uuid":null,"relationships":[],"tags":["architecture","core","cross-location","multi-agent"]}
4
- {"id":"s-9hf5","uuid":"9d1db0e3-f66b-40d3-a4df-45a09ba8dda8","title":"Phase 1: Single-Location + Provider URIs","file_path":"specs/s-9hf5_phase_1_single_location_provider_uris.md","content":"# Phase 1: Single-Location + Provider URIs\n\n**Parent**: [[s-9jju]] OpenTasks Core Architecture\n\n## Scope\n\nThe minimal viable OpenTasks that provides the core graph connector value:\n- One `.opentasks/` directory per working context\n- Edges that reference provider URIs (`beads://`, `claude://`, `jira://`, etc.)\n- Optional native specs/issues for lightweight use\n- Direct file access (no daemon)\n\n## What's Included\n\n### Core Data Layer\n- Node types: `spec`, `issue`, `feedback`, `external`\n- Edge types: `blocks`, `implements`, `references`, `related`, etc.\n- JSONL storage (`graph.jsonl`) as source of truth\n- SQLite cache (`cache.db`) for fast queries\n\n### Provider System\n- Provider registry with URI scheme routing\n- Native provider (optional, toggleable) for local specs/issues\n- Provider interface for external systems\n- Stub implementations for Beads, Claude Tasks\n\n### 3-Tool Interface\n- `link(from, to, type)` — create/remove edges\n- `query(find, node?, filters)` — query graph relationships\n- `annotate(target, feedback)` — add feedback to nodes\n\n### Storage Format\n\n**graph.jsonl** — Nodes and edges:\n```jsonl\n{\"id\":\"s-a2b3\",\"uuid\":\"...\",\"type\":\"spec\",\"title\":\"Auth requirements\",\"content\":\"...\",\"created_at\":\"...\",\"updated_at\":\"...\"}\n{\"id\":\"i-x7k9\",\"uuid\":\"...\",\"type\":\"issue\",\"title\":\"Implement login\",\"status\":\"open\",\"created_at\":\"...\",\"updated_at\":\"...\"}\n{\"id\":\"x-r8s9\",\"uuid\":\"...\",\"from_id\":\"i-x7k9\",\"to_id\":\"s-a2b3\",\"type\":\"implements\",\"created_at\":\"...\"}\n{\"id\":\"x-t1u2\",\"uuid\":\"...\",\"from_id\":\"i-x7k9\",\"to_id\":\"beads://./bd-123\",\"type\":\"blocks\",\"created_at\":\"...\"}\n```\n\n**config.json** — Location configuration:\n```json\n{\n \"version\": \"1.0\",\n \"location\": {\n \"name\": \"myapp\",\n \"uri\": \"opentasks:///Users/alex/projects/myapp/.opentasks/\"\n },\n \"providers\": {\n \"native\": { \"enabled\": true },\n \"beads\": { \"workspace\": \".\" }\n }\n}\n```\n\n## What's NOT Included (Phase 2+)\n\n- `opentasks://` URIs to other locations\n- Cross-location queries\n- Daemon architecture\n- Redirect rules\n- Location discovery\n- Global registry\n\n## Schema Preparation for Future\n\nEven though we're not implementing cross-location yet, the schema should support it:\n\n1. **Location URI in config** — Store canonical location URI\n2. **Full URI support in edges** — Parser handles `opentasks://` even if not resolved\n3. **Source tracking on nodes** — Know where nodes came from\n\n## Deliverables\n\n### Core Package (`@opentasks/core`)\n- [ ] TypeScript types for all node/edge types\n- [ ] ID generation (hash-based, prefix by type)\n- [ ] Content hashing for dedup\n- [ ] Validation functions\n\n### Storage Package (`@opentasks/storage`)\n- [ ] Persister interface (TinyBase-inspired)\n- [ ] JSONL persister\n- [ ] SQLite persister (cache/index)\n- [ ] Persistence manager (coordinates persisters)\n\n### Graph Package (`@opentasks/graph`)\n- [ ] Graph data structure (nodes + edges)\n- [ ] Query engine (filters, traversal)\n- [ ] Mutation handlers (create, update, delete, archive)\n\n### Interface Package (`@opentasks/interface`)\n- [ ] `link()` implementation\n- [ ] `query()` implementation \n- [ ] `annotate()` implementation\n- [ ] Error types and handling\n\n### Provider Package (`@opentasks/providers`)\n- [ ] Provider interface\n- [ ] Provider registry\n- [ ] Native provider (specs, issues)\n- [ ] External node management (phantom → materialized)\n- [ ] Beads provider stub\n- [ ] Claude Tasks provider stub\n\n### CLI (`@opentasks/cli`)\n- [ ] `opentasks init` — Initialize .opentasks/ directory\n- [ ] `opentasks link` — Create edges\n- [ ] `opentasks query` — Query graph\n- [ ] `opentasks show` — Show node details\n\n## Technical Decisions\n\n### URI Parsing\n```typescript\ninterface ParsedURI {\n scheme: string // \"beads\", \"claude\", \"opentasks\", etc.\n path: string // \"./bd-123\", \"current/t-abc\", etc.\n nodeId: string // \"bd-123\", \"t-abc\", etc.\n isRelative: boolean // true for \"./\", false for absolute\n}\n\nfunction parseURI(uri: string): ParsedURI\nfunction isLocalId(ref: string): boolean // \"i-x7k9\" vs \"beads://...\"\nfunction toCanonicalURI(ref: string, location: string): string\n```\n\n### Query Types\n```typescript\ntype QueryType =\n | 'edges' // Get edges for a node\n | 'blockers' // What blocks this node?\n | 'blocking' // What does this node block?\n | 'ready' // What's ready to work on?\n | 'implementers' // Issues implementing a spec\n | 'specs' // Specs that an issue implements\n | 'children' // Child nodes\n | 'parents' // Parent nodes\n | 'resolve' // Get node metadata by URI\n```\n\n### Provider Interface\n```typescript\ninterface Provider {\n name: string\n schemes: string[]\n capabilities: { read, write, search, watch, ready }\n \n get(id: string): Promise<ProviderNode | null>\n list(filter?: Filter): Promise<ProviderNode[]>\n create?(input: CreateInput): Promise<ProviderNode>\n update?(id: string, updates: Updates): Promise<ProviderNode>\n}\n```\n\n## Success Criteria\n\nPhase 1 is complete when:\n1. Can initialize `.opentasks/` in a directory\n2. Can create native specs and issues\n3. Can create edges between native nodes\n4. Can create edges to provider URIs (e.g., `beads://./bd-123`)\n5. Can query blockers, ready items across the graph\n6. Can add feedback/annotations to nodes\n7. Storage persists correctly to JSONL and rebuilds SQLite cache\n","priority":1,"archived":0,"archived_at":null,"created_at":"2026-01-27 19:10:37","updated_at":"2026-01-27 19:10:37","parent_id":null,"parent_uuid":null,"relationships":[{"from":"s-9hf5","from_type":"spec","to":"s-9jju","to_type":"spec","type":"implements"}],"tags":["implementation","phase-1","v1"]}
5
- {"id":"s-2qms","uuid":"dbe26ed7-8169-4818-a84e-89ddb0071aff","title":"Phase 3: Multi-Location Queries","file_path":"specs/s-2qms_phase_3_multi_location_queries.md","content":"# Phase 3: Multi-Location Queries\n\n**Parent**: [[s-9jju]] OpenTasks Core Architecture\n\n## Scope\n\nEnable queries that span multiple OpenTasks locations, with automatic discovery and expansion.\n\n## Prerequisites\n\n- [[s-ph1]] Phase 1 complete\n- [[s-ph2]] Phase 2 complete (daemon, cross-location URIs)\n\n## What's Included\n\n### Location Discovery\n\nFind `.opentasks/` directories in the filesystem:\n```typescript\ninterface DiscoveryOptions {\n from: string // Starting path\n direction: 'ancestors' | 'descendants' | 'siblings' | 'all'\n maxDepth?: number // Default: 10\n includeInactive?: boolean // Include locations without running daemon\n skip?: string[] // Default: ['node_modules', '.git', 'vendor']\n}\n\nconst locations = await discover({\n from: '~/projects/myapp/.opentasks/',\n direction: 'ancestors'\n})\n// Returns:\n// - opentasks://~/projects/.opentasks/\n// - opentasks://~/.opentasks/\n```\n\n### Query Expansion Modes\n\n```typescript\ntype ExpansionMode =\n | 'none' // Only current location (default)\n | 'follow-refs' // Follow outbound edge references\n | 'ancestors' // Include parent locations (upward)\n | 'descendants' // Include child locations (downward)\n | 'siblings' // Include sibling locations\n | 'all' // Full hierarchy traversal\n```\n\n**Usage**:\n```typescript\n// Default: isolated query\nconst issues = await query({ find: 'ready' })\n\n// Expand to follow references (resolve external URIs)\nconst issues = await query({ find: 'ready' }, { expand: 'follow-refs' })\n\n// Expand to include ancestor locations\nconst specs = await query({ find: 'specs' }, { expand: 'ancestors' })\n```\n\n### Conditional Redirect Rules\n\nAdvanced redirect configuration:\n```json\n{\n \"redirects\": [\n {\n \"operations\": [\"write\"],\n \"pattern\": \"i-*\",\n \"target\": \"opentasks://../main-worktree/.opentasks/\",\n \"when\": {\n \"branch\": \"feature-*\",\n \"worktree\": true\n }\n },\n {\n \"operations\": [\"read\"],\n \"pattern\": \"s-*\",\n \"target\": \"opentasks://~/.opentasks/\",\n \"when\": {\n \"agent\": \"sub-agent-*\"\n }\n }\n ]\n}\n```\n\n### Cross-Location Ready Query\n\nFind ready items across multiple locations:\n```typescript\nconst ready = await query(\n { find: 'ready' },\n { expand: 'descendants' } // Check all child locations\n)\n\n// Returns nodes from:\n// - Current location\n// - All discovered child locations\n// - With blockers resolved across locations\n```\n\n### Worktree Detection\n\nAutomatic detection of git worktree context:\n```typescript\ninterface WorktreeContext {\n isWorktree: boolean\n mainWorktreePath?: string\n worktreeName?: string\n branch?: string\n}\n\nfunction detectWorktreeContext(): WorktreeContext\n```\n\n## Deliverables\n\n### Discovery Package (`@opentasks/discovery`)\n- [ ] Location scanner (filesystem traversal)\n- [ ] Worktree detection\n- [ ] Location hierarchy builder\n- [ ] Connection detection (which locations have edges to current)\n\n### Expansion Package (`@opentasks/expansion`)\n- [ ] Expansion mode handler\n- [ ] Multi-daemon query coordinator\n- [ ] Result aggregation and deduplication\n\n### Advanced Redirects\n- [ ] Conditional rule matching\n- [ ] Pattern-based redirects\n- [ ] Agent/branch/worktree conditions\n\n## Technical Design\n\n### Multi-Daemon Query Flow\n```\n1. Query with expand: 'descendants'\n2. Discover child locations via filesystem scan\n3. For each location:\n a. Find/start daemon\n b. Send query via IPC\n c. Collect results\n4. Aggregate results\n5. Resolve cross-location blockers\n6. Return unified result set\n```\n\n### Expansion Result Format\n```typescript\ninterface ExpandedResult {\n local: Node[] // Results from current location\n external: Map<string, Node[]> // Results by location URI\n crossLocationEdges: Edge[] // Edges spanning locations\n queriedLocations: string[] // All locations queried\n}\n```\n\n## Success Criteria\n\nPhase 3 is complete when:\n1. Location discovery finds .opentasks/ in ancestors/descendants/siblings\n2. Queries with expansion modes return results from multiple locations\n3. Cross-location blockers are correctly resolved in ready queries\n4. Conditional redirect rules match on branch/worktree/agent\n5. Worktree context is automatically detected\n","priority":3,"archived":0,"archived_at":null,"created_at":"2026-01-27 19:10:38","updated_at":"2026-01-27 19:10:38","parent_id":null,"parent_uuid":null,"relationships":[{"from":"s-2qms","from_type":"spec","to":"s-7es6","to_type":"spec","type":"depends-on"},{"from":"s-2qms","from_type":"spec","to":"s-9jju","to_type":"spec","type":"implements"}],"tags":["discovery","expansion","phase-3","v3"]}
6
- {"id":"s-7es6","uuid":"68f28048-f30c-423b-82aa-25fed31ab614","title":"Phase 2: Cross-Location References","file_path":"specs/s-7es6_phase_2_cross_location_references.md","content":"# Phase 2: Cross-Location References\n\n**Parent**: [[s-9jju]] OpenTasks Core Architecture\n\n## Scope\n\nAdd the ability to reference nodes in other OpenTasks locations, enabling multi-repo and multi-worktree scenarios.\n\n## Prerequisites\n\n- [[s-ph1]] Phase 1 complete (single-location + provider URIs)\n\n## What's Included\n\n### opentasks:// URI Resolution\n```\nopentasks://./i-x7k9 # Current location\nopentasks://~/.opentasks/s-a2b3 # User-level location\nopentasks://../.opentasks/i-e6f7 # Parent directory\nopentasks://../other-repo/.opentasks/s-g8h9 # Sibling directory\nopentasks:///abs/path/.opentasks/i-j0k1 # Absolute path\n```\n\n### Daemon Architecture\n\nOne daemon per `.opentasks/` location:\n- Auto-starts on first operation (configurable)\n- Unix socket for IPC (`.opentasks/daemon.sock`)\n- JSON-RPC protocol\n- Graceful shutdown with final flush\n\n**Lifecycle**:\n```\nSTART → acquire lock → init persistence → start socket → register in global registry\nRUNNING → handle IPC requests → watch files → flush changes\nSTOP → flush → unregister → cleanup socket/lock\n```\n\n### Global Registry\n\nCentral tracking of all running daemons (`~/.opentasks/registry.json`):\n```json\n{\n \"daemons\": [\n {\n \"workspacePath\": \"/Users/alex/projects/myapp/.opentasks\",\n \"socketPath\": \"/Users/alex/projects/myapp/.opentasks/daemon.sock\",\n \"pid\": 12345,\n \"version\": \"1.0.0\",\n \"startedAt\": \"2025-01-27T10:00:00Z\"\n }\n ]\n}\n```\n\n### Redirect Rules\n\nConfiguration for routing operations to another location:\n```json\n{\n \"redirects\": [\n {\n \"operations\": [\"read\", \"write\"],\n \"pattern\": \"*\",\n \"target\": \"opentasks://../main-worktree/.opentasks/\"\n }\n ]\n}\n```\n\n**Use case**: Manager agent spawns worker in worktree, configures worker's `.opentasks/` to redirect to manager's location.\n\n**Chained redirects**: Worker → Manager → Orchestrator (each hop resolves)\n\n## What's NOT Included (Phase 3)\n\n- Location discovery (find .opentasks/ in ancestors/descendants)\n- Query expansion modes (follow-refs, ancestors, descendants)\n- Conditional redirect rules\n- Cross-location aggregated queries\n\n## Deliverables\n\n### Daemon Package (`@opentasks/daemon`)\n- [ ] Daemon process with socket server\n- [ ] Lock file management\n- [ ] IPC protocol (JSON-RPC over Unix socket)\n- [ ] Auto-start behavior\n- [ ] Graceful shutdown\n- [ ] Health monitoring\n\n### Registry Package (`@opentasks/registry`)\n- [ ] Global registry read/write\n- [ ] Daemon registration/unregistration\n- [ ] Stale entry cleanup (dead PIDs)\n- [ ] Find daemon for path\n\n### URI Resolution (`@opentasks/uri`)\n- [ ] opentasks:// URI parser\n- [ ] Relative path resolution\n- [ ] Tilde (~) expansion\n- [ ] Cross-location node fetching (via daemon IPC)\n\n### Redirect System\n- [ ] Redirect rule configuration\n- [ ] Redirect resolution logic\n- [ ] Chained redirect support\n\n## Technical Design\n\n### Daemon IPC Protocol\n```typescript\n// Request\n{ \"id\": \"uuid\", \"method\": \"graph.query\", \"params\": { \"find\": \"ready\" } }\n\n// Response\n{ \"id\": \"uuid\", \"result\": { \"nodes\": [...] } }\n// or\n{ \"id\": \"uuid\", \"error\": { \"code\": -32000, \"message\": \"...\" } }\n```\n\n**Methods**:\n- Lifecycle: `ping`, `health`, `status`, `shutdown`\n- Graph: `query`, `get`, `create`, `update`, `delete`\n- Sync: `flush`, `import`, `export`\n- Discovery: `resolve-uri`\n\n### Cross-Location Resolution Flow\n```\n1. Parse URI: opentasks://../other/.opentasks/i-x7k9\n2. Resolve path: /Users/alex/projects/other/.opentasks/\n3. Find daemon in registry (or start if auto-start enabled)\n4. Send IPC request to that daemon\n5. Return resolved node\n```\n\n### Redirect Resolution Flow\n```\n1. Operation requested on local location\n2. Check config.json for matching redirect rule\n3. If redirect found, resolve target location\n4. Forward operation to target location\n5. Handle chained redirects (max depth)\n```\n\n## Success Criteria\n\nPhase 2 is complete when:\n1. Can create edges referencing `opentasks://` URIs in other locations\n2. Daemon starts automatically and handles IPC requests\n3. Global registry tracks all running daemons\n4. Can query a node in another location via URI\n5. Redirect rules route operations to configured target\n6. Chained redirects work (worker → manager → orchestrator)\n","priority":2,"archived":0,"archived_at":null,"created_at":"2026-01-27 19:10:38","updated_at":"2026-01-27 19:10:38","parent_id":null,"parent_uuid":null,"relationships":[{"from":"s-7es6","from_type":"spec","to":"s-9hf5","to_type":"spec","type":"depends-on"},{"from":"s-7es6","from_type":"spec","to":"s-9jju","to_type":"spec","type":"implements"}],"tags":["cross-location","daemon","phase-2","v2"]}
7
- {"id":"s-zm8l","uuid":"ddb42b28-6aca-4da9-805b-6b637203c26d","title":"Phase 2: Graph Operations","file_path":"specs/s-zm8l_phase_2_graph_operations.md","content":"# Phase 2: Graph Operations\n\nBuild the graph layer on top of Phase 1's persistence layer. Provides unified CRUD, rich queries, and business logic validation.\n\n## Overview\n\nPhase 2 creates the **application layer** that sits between the raw persistence (JSONL/SQLite) and the eventual agent interface (Phase 4's 3-tool API).\n\n```\n┌─────────────────────────────────────────────────────────┐\n│ Agent Interface │\n│ (Phase 4: link, query, annotate) │\n└─────────────────────────────────────────────────────────┘\n │\n ▼\n┌─────────────────────────────────────────────────────────┐\n│ Phase 2: Graph Layer │\n│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │\n│ │ GraphStore │ │QueryEngine │ │ Validation │ │\n│ │ │ │ │ │ │ │\n│ │ • CRUD │ │ • Filter │ │ • Type rules │ │\n│ │ • Sync │ │ • Traverse │ │ • Cycle detect │ │\n│ │ • Txn │ │ • Ready │ │ • Edge rules │ │\n│ └─────────────┘ └─────────────┘ └─────────────────┘ │\n└─────────────────────────────────────────────────────────┘\n │\n ▼\n┌─────────────────────────────────────────────────────────┐\n│ Phase 1: Persistence │\n│ JSONLPersister ◄──► SQLitePersister │\n└─────────────────────────────────────────────────────────┘\n```\n\n## Components\n\n### 1. GraphStore (`src/graph/store.ts`)\n\nUnified API coordinating JSONL (source of truth) and SQLite (query cache).\n\n```typescript\ninterface GraphStoreConfig {\n /** Base path for .opentasks directory */\n basePath: string\n \n /** Auto-initialize if not exists */\n autoInit?: boolean\n \n /** Flush strategy */\n flush?: {\n /** Debounce delay in ms (default: 5000) */\n debounceMs?: number\n /** Max delay before forced flush (default: 30000) */\n maxDelayMs?: number\n }\n}\n\ninterface GraphStore {\n // === Lifecycle ===\n \n /** Initialize store (create files, load data) */\n initialize(): Promise<void>\n \n /** Close store (flush pending, close connections) */\n close(): Promise<void>\n \n /** Force flush pending changes to JSONL */\n flush(): Promise<void>\n \n // === Node Operations ===\n \n /** Create a new node */\n createNode(input: CreateNodeInput): Promise<Node>\n \n /** Get node by ID */\n getNode(id: string): Promise<Node | null>\n \n /** Update node fields */\n updateNode(id: string, updates: UpdateNodeInput): Promise<Node>\n \n /** Delete node (soft delete by default) */\n deleteNode(id: string, options?: DeleteOptions): Promise<void>\n \n /** Restore archived node */\n restoreNode(id: string): Promise<Node>\n \n // === Edge Operations ===\n \n /** Create edge between nodes */\n createEdge(input: CreateEdgeInput): Promise<Edge>\n \n /** Get edge by ID */\n getEdge(id: string): Promise<Edge | null>\n \n /** Delete edge */\n deleteEdge(id: string): Promise<void>\n \n // === Tag Operations ===\n \n /** Add tags to node */\n addTags(nodeId: string, tags: string[]): Promise<void>\n \n /** Remove tags from node */\n removeTags(nodeId: string, tags: string[]): Promise<void>\n \n /** Set tags (replace all) */\n setTags(nodeId: string, tags: string[]): Promise<void>\n \n // === Query (delegated to QueryEngine) ===\n \n /** Access query engine */\n query: QueryEngine\n \n // === Transactions ===\n \n /** Run operations in a transaction */\n transaction<T>(fn: (tx: GraphTransaction) => Promise<T>): Promise<T>\n}\n```\n\n#### Input/Output Types\n\n```typescript\ninterface CreateNodeInput {\n type: 'spec' | 'issue' | 'feedback' | 'external'\n title: string\n content?: string\n \n // Common optional\n priority?: number\n tags?: string[]\n parent_id?: string\n \n // Issue-specific\n status?: string\n assignee?: string\n \n // Feedback-specific\n target_id?: string\n target_anchor?: Anchor\n feedback_type?: 'comment' | 'suggestion' | 'request'\n \n // External-specific\n uri?: string\n source?: string\n \n // Metadata\n metadata?: Record<string, unknown>\n}\n\ninterface UpdateNodeInput {\n title?: string\n content?: string\n priority?: number\n status?: string\n assignee?: string\n archived?: boolean\n // ... other updatable fields\n}\n\ninterface CreateEdgeInput {\n from_id: string\n to_id: string\n type: EdgeType\n metadata?: Record<string, unknown>\n}\n\ninterface DeleteOptions {\n /** Hard delete (default: false = archive) */\n hard?: boolean\n}\n```\n\n#### Sync Strategy\n\nThe GraphStore coordinates between JSONL and SQLite:\n\n```\nWrite Path:\n1. Validate input\n2. Generate ID (if new)\n3. Write to SQLite (immediate, for queries)\n4. Mark dirty for JSONL sync\n5. Debounced flush to JSONL\n\nRead Path:\n1. Query SQLite (fast)\n2. Return result\n\nFlush:\n1. Get dirty node IDs\n2. Read current JSONL\n3. Apply changes (upsert/delete)\n4. Atomic write new JSONL\n5. Clear dirty flags\n```\n\n### 2. QueryEngine (`src/graph/query.ts`)\n\nRich query capabilities for graph traversal and filtering.\n\n```typescript\ninterface QueryEngine {\n // === Basic Queries ===\n \n /** Query nodes with filters */\n nodes(filter: NodeFilter): Promise<Node[]>\n \n /** Query edges with filters */\n edges(filter: EdgeFilter): Promise<Edge[]>\n \n // === Relationship Queries ===\n \n /** Get edges from a node */\n edgesFrom(nodeId: string, type?: EdgeType): Promise<Edge[]>\n \n /** Get edges to a node */\n edgesTo(nodeId: string, type?: EdgeType): Promise<Edge[]>\n \n /** Get all edges for a node (both directions) */\n edgesFor(nodeId: string, type?: EdgeType): Promise<Edge[]>\n \n // === Dependency Queries ===\n \n /** What blocks this node? */\n blockers(nodeId: string, options?: BlockerOptions): Promise<Node[]>\n \n /** What does this node block? */\n blocking(nodeId: string, options?: BlockerOptions): Promise<Node[]>\n \n /** Is there a path from A blocking B? */\n isBlocking(fromId: string, toId: string): Promise<boolean>\n \n // === Spec/Issue Queries ===\n \n /** Issues that implement a spec */\n implementers(specId: string): Promise<Issue[]>\n \n /** Specs that an issue implements */\n specs(issueId: string): Promise<Spec[]>\n \n // === Hierarchy Queries ===\n \n /** Get children of a node */\n children(nodeId: string): Promise<Node[]>\n \n /** Get parent of a node */\n parent(nodeId: string): Promise<Node | null>\n \n /** Get all ancestors */\n ancestors(nodeId: string): Promise<Node[]>\n \n /** Get all descendants */\n descendants(nodeId: string): Promise<Node[]>\n \n // === Ready Query ===\n \n /** Get issues ready to work on (no active blockers) */\n ready(options?: ReadyOptions): Promise<Issue[]>\n \n // === Feedback Queries ===\n \n /** Get feedback on a node */\n feedback(targetId: string, options?: FeedbackOptions): Promise<Feedback[]>\n \n /** Get unresolved feedback */\n unresolvedFeedback(targetId?: string): Promise<Feedback[]>\n}\n```\n\n#### Filter Types\n\n```typescript\ninterface NodeFilter {\n /** Filter by type(s) */\n type?: NodeType | NodeType[]\n \n /** Filter by status(es) */\n status?: string | string[]\n \n /** Filter by tags (AND semantics) */\n tags?: string[]\n \n /** Filter by parent */\n parent_id?: string\n \n /** Filter by archived status */\n archived?: boolean | null // null = include all\n \n /** Text search in title/content */\n search?: string\n \n /** Filter by priority range */\n priority?: number | { min?: number; max?: number }\n \n /** Filter by assignee */\n assignee?: string\n \n /** Pagination */\n limit?: number\n offset?: number\n \n /** Sort */\n orderBy?: 'created_at' | 'updated_at' | 'priority' | 'title'\n orderDirection?: 'asc' | 'desc'\n}\n\ninterface EdgeFilter {\n /** Filter by type(s) */\n type?: EdgeType | EdgeType[]\n \n /** Filter by source node */\n from_id?: string\n \n /** Filter by target node */\n to_id?: string\n \n /** Pagination */\n limit?: number\n offset?: number\n}\n\ninterface BlockerOptions {\n /** Include transitive blockers (blockers of blockers) */\n transitive?: boolean\n \n /** Only include active (non-closed) blockers */\n activeOnly?: boolean\n \n /** Max depth for transitive queries */\n maxDepth?: number\n}\n\ninterface ReadyOptions {\n /** Filter by type (default: 'issue') */\n type?: 'issue' | 'spec'\n \n /** Filter by tags */\n tags?: string[]\n \n /** Filter by priority */\n priority?: number | { min?: number; max?: number }\n \n /** Filter by assignee */\n assignee?: string\n \n /** Limit results */\n limit?: number\n}\n\ninterface FeedbackOptions {\n /** Filter by feedback type */\n type?: 'comment' | 'suggestion' | 'request'\n \n /** Filter by resolution status */\n resolved?: boolean\n \n /** Include dismissed */\n includeDismissed?: boolean\n}\n```\n\n#### Ready Computation\n\n```typescript\n/**\n * Ready = open issues with no active (non-closed) blockers\n * \n * Algorithm:\n * 1. Get all open, non-archived issues\n * 2. For each, check incoming 'blocks' edges\n * 3. Filter out edges where blocker is closed or archived\n * 4. Issue is ready if no active blockers remain\n * \n * Optimization: Use SQLite view (already created in Phase 1)\n */\nasync function ready(options?: ReadyOptions): Promise<Issue[]> {\n // Primary: use ready_issues view\n let results = await sqlite.getReady()\n \n // Apply additional filters\n if (options?.tags) {\n results = results.filter(r => \n options.tags!.every(t => r.tags?.includes(t))\n )\n }\n // ... other filters\n \n return results.map(parseNode).filter(isIssue)\n}\n```\n\n### 3. Validation (`src/graph/validation.ts`)\n\nBusiness rule validation beyond basic schema validation.\n\n```typescript\ninterface ValidationService {\n /** Validate node creation */\n validateCreate(input: CreateNodeInput): ValidationResult\n \n /** Validate node update */\n validateUpdate(id: string, updates: UpdateNodeInput): Promise<ValidationResult>\n \n /** Validate edge creation */\n validateEdge(input: CreateEdgeInput): Promise<ValidationResult>\n \n /** Check for cycles in blocks graph */\n detectCycle(fromId: string, toId: string): Promise<CycleResult>\n}\n\ninterface ValidationResult {\n valid: boolean\n errors: ValidationError[]\n warnings: ValidationWarning[]\n}\n\ninterface ValidationError {\n code: string\n field?: string\n message: string\n}\n\ninterface ValidationWarning {\n code: string\n field?: string\n message: string\n}\n\ninterface CycleResult {\n hasCycle: boolean\n cycle?: string[] // Path if cycle detected\n}\n```\n\n#### Validation Rules\n\n```typescript\n// === Node Validation ===\n\nconst NODE_RULES = {\n // All nodes\n common: [\n { field: 'title', rule: 'required' },\n { field: 'title', rule: 'maxLength', value: 500 },\n { field: 'content', rule: 'maxLength', value: 100000 },\n { field: 'priority', rule: 'range', min: 0, max: 4 },\n ],\n \n // Issue-specific\n issue: [\n { field: 'status', rule: 'required' },\n { field: 'status', rule: 'enum', values: ['open', 'in_progress', 'blocked', 'closed'] },\n ],\n \n // Feedback-specific\n feedback: [\n { field: 'target_id', rule: 'required' },\n { field: 'target_id', rule: 'exists' }, // Target must exist\n { field: 'feedback_type', rule: 'required' },\n { field: 'feedback_type', rule: 'enum', values: ['comment', 'suggestion', 'request'] },\n ],\n \n // External-specific\n external: [\n { field: 'uri', rule: 'required' },\n { field: 'uri', rule: 'validUri' },\n { field: 'source', rule: 'required' },\n ],\n}\n\n// === Edge Validation ===\n\nconst EDGE_RULES = {\n common: [\n { rule: 'noSelfReference' }, // from_id !== to_id\n { rule: 'noDuplicate' }, // No duplicate edges\n ],\n \n blocks: [\n { rule: 'noCycle' }, // No circular dependencies\n { rule: 'validBlocker' }, // from must be issue/spec\n ],\n \n implements: [\n { rule: 'fromIsIssue' }, // from must be issue\n { rule: 'toIsSpec' }, // to must be spec\n ],\n}\n```\n\n#### Cycle Detection\n\n```typescript\n/**\n * Detect cycles in the blocks graph using DFS\n * \n * @param fromId - Source node (would block toId)\n * @param toId - Target node (would be blocked by fromId)\n * @returns Whether adding edge would create a cycle\n */\nasync function detectCycle(fromId: string, toId: string): Promise<CycleResult> {\n // If toId already blocks fromId (directly or transitively),\n // adding fromId → toId would create a cycle\n \n const visited = new Set<string>()\n const path: string[] = []\n \n async function dfs(current: string): Promise<boolean> {\n if (current === fromId) {\n path.push(current)\n return true // Found cycle\n }\n \n if (visited.has(current)) {\n return false\n }\n \n visited.add(current)\n path.push(current)\n \n // Get nodes that 'current' blocks\n const edges = await query.edgesFrom(current, 'blocks')\n \n for (const edge of edges) {\n if (await dfs(edge.to_id)) {\n return true\n }\n }\n \n path.pop()\n return false\n }\n \n const hasCycle = await dfs(toId)\n \n return {\n hasCycle,\n cycle: hasCycle ? [...path, fromId] : undefined,\n }\n}\n```\n\n## File Structure\n\n```\nsrc/graph/\n├── store.ts # GraphStore implementation\n├── query.ts # QueryEngine implementation\n├── validation.ts # Validation rules and cycle detection\n├── types.ts # Input/output types\n├── sync.ts # JSONL ↔ SQLite sync logic\n├── index.ts # Public exports\n└── __tests__/\n ├── store.test.ts\n ├── query.test.ts\n ├── validation.test.ts\n └── sync.test.ts\n```\n\n## Implementation Issues\n\n### Issue 1: Define Graph Types\n- Input/output types for all operations\n- Filter types\n- Validation types\n\n### Issue 2: Implement GraphStore\n- Lifecycle (init, close, flush)\n- Node CRUD operations\n- Edge operations\n- Tag operations\n- Coordinate JSONL/SQLite\n\n### Issue 3: Implement QueryEngine\n- Basic node/edge queries\n- Relationship queries (edgesFrom, edgesTo)\n- Dependency queries (blockers, blocking)\n- Ready computation\n- Hierarchy queries\n\n### Issue 4: Implement Validation\n- Node validation rules\n- Edge validation rules\n- Cycle detection algorithm\n\n### Issue 5: Implement Sync\n- Dirty tracking\n- Debounced flush\n- JSONL ↔ SQLite coordination\n\n### Issue 6: Add Tests\n- Unit tests for each component\n- Integration tests for full workflows\n- Edge cases (cycles, transactions, concurrent access)\n\n## Dependencies\n\n- **Phase 1 complete**: Schema types, ID generation, JSONL persister, SQLite persister\n- **From Phase 1**: `Storage` interface, `StoredNode`, `StoredEdge`, persisters\n\n## Acceptance Criteria\n\n- [ ] `GraphStore` provides unified CRUD over both persisters\n- [ ] `QueryEngine` supports all query types from INTERFACE.md\n- [ ] `ready()` correctly identifies unblocked issues\n- [ ] Cycle detection prevents circular `blocks` dependencies\n- [ ] Validation catches invalid inputs with helpful errors\n- [ ] Changes are durably persisted (flush on close)\n- [ ] 90%+ test coverage for graph layer\n\n## Open Questions\n\n1. **Flush trigger**: Should flush happen on every write, or debounced?\n - Recommendation: Debounced with max delay (like beads)\n\n2. **Transaction semantics**: What happens if transaction fails mid-way?\n - Recommendation: Rollback SQLite, don't write to JSONL\n\n3. **Concurrent access**: Multiple processes writing?\n - Recommendation: Phase 3 daemon handles this; for now, single-writer assumption\n\n4. **Soft delete cascading**: When archiving a node, archive its edges too?\n - Recommendation: Keep edges, filter in queries\n\n## References\n\n- [[s-7u8f|OpenTasks Implementation Plan]]\n- [[s-4l4m|Phase 1: Core Data Layer]]\n- [INTERFACE.md](./docs/INTERFACE.md) - Query types for the 3-tool API\n- [SCHEMA.md](./docs/SCHEMA.md) - Node and edge types\n","priority":1,"archived":0,"archived_at":null,"created_at":"2026-01-28 01:36:15","updated_at":"2026-01-28 01:36:15","parent_id":"s-7u8f","parent_uuid":"605bb90c-778e-4a77-95b8-f136577f4f67","relationships":[{"from":"s-zm8l","from_type":"spec","to":"s-4l4m","to_type":"spec","type":"depends-on"}],"tags":["graph","implementation","phase-2","query"]}
8
- {"id":"s-9r97","uuid":"ae3aa08b-dcb3-4645-93ef-4e5dd28cf797","title":"Phase 3: Daemon & IPC","file_path":"specs/s-9r97_phase_3_daemon_ipc.md","content":"# Phase 3: Daemon & IPC\n\nBackground daemon for coordination, IPC, file watching, and flush management.\n\n## Overview\n\nEach `.opentasks/` location has its own daemon process that:\n- Handles IPC requests via Unix socket\n- Coordinates writes with debounced flush\n- Watches for external file changes\n- Registers in global registry for discovery\n\n## Components\n\n### 3.1 Refactored SyncManager\n\n**Decision:** Refactor existing SyncManager to decouple from Storage, making it reusable by both GraphStore and daemon FlushManager.\n\n#### Current State (Phase 2)\n```typescript\n// Coupled to Storage\nfunction createSyncManager(\n config: SyncConfig,\n storage: Storage, // ← coupling\n onFlush: FlushCallback\n): SyncManager\n```\n\n#### Refactored Design\n```typescript\n// Core timing utility - no external dependencies\ninterface DebouncedFlusher {\n /** Mark that changes exist */\n markDirty(): void\n \n /** Schedule debounced flush */\n schedule(): void\n \n /** Force immediate flush */\n flush(): Promise<void>\n \n /** Cancel pending flush */\n cancel(): void\n \n /** Check if flush pending */\n hasPending(): boolean\n}\n\nfunction createDebouncedFlusher(\n config: { debounceMs: number; maxDelayMs: number },\n onFlush: () => Promise<void>\n): DebouncedFlusher\n```\n\nGraphStore and daemon FlushManager both compose this utility.\n\n### 3.2 Daemon Lifecycle\n\n#### Files\n- `src/daemon/lifecycle.ts` - Start, stop, lock management\n- `src/daemon/lock.ts` - Lock file operations\n- `src/daemon/registry.ts` - Global registry operations\n\n#### Lock File Format\n```typescript\n// .opentasks/daemon.lock\ninterface DaemonLock {\n pid: number\n parentPid: number\n version: string\n startedAt: string // ISO timestamp\n socketPath: string\n databasePath: string\n}\n```\n\n#### Startup Sequence\n```\n1. Check for existing daemon (lock file exists + process alive)\n2. If existing daemon running → return socket path (or error)\n3. Acquire exclusive flock on .opentasks/daemon.lock\n4. Write lock file contents (PID, metadata)\n5. Initialize GraphStore (loads from JSONL → SQLite)\n6. Start IPC server on .opentasks/daemon.sock\n7. Register in global registry (~/.opentasks/registry.json)\n8. Start file watchers\n9. Start flush manager\n10. Ready to accept connections\n```\n\n#### Shutdown Sequence\n```\n1. Stop accepting new connections\n2. Finish in-flight requests (2s timeout)\n3. Stop file watchers\n4. Final flush to JSONL\n5. Unregister from global registry\n6. Close IPC server\n7. Remove socket file\n8. Release lock file\n```\n\n#### Graceful Shutdown Triggers\n- IPC `shutdown` request\n- SIGTERM signal\n- SIGINT signal (Ctrl+C)\n\n### 3.3 Global Registry\n\n#### Location\n`~/.opentasks/registry.json`\n\n#### Auto-initialization\n- **Global location (`~/.opentasks/`)**: Auto-created when first daemon starts\n - Creates directory if missing\n - Creates `registry.json`\n - Does NOT initialize as full OpenTasks location (no graph.jsonl, cache.db)\n- **Project/workspace locations**: User-triggered only (explicit init command)\n\n#### Registry Format\n```typescript\ninterface DaemonRegistry {\n version: string\n daemons: DaemonEntry[]\n}\n\ninterface DaemonEntry {\n /** Absolute path to .opentasks/ directory */\n locationPath: string\n \n /** Socket path for IPC */\n socketPath: string\n \n /** Process ID */\n pid: number\n \n /** OpenTasks version */\n version: string\n \n /** When daemon started */\n startedAt: string\n \n /** Last activity timestamp */\n lastActivity: string\n}\n```\n\n#### Registry Operations\n```typescript\ninterface RegistryManager {\n /** Register daemon on startup */\n register(entry: DaemonEntry): Promise<void>\n \n /** Unregister daemon on shutdown */\n unregister(locationPath: string): Promise<void>\n \n /** Find daemon for a location */\n find(locationPath: string): Promise<DaemonEntry | null>\n \n /** List all registered daemons */\n list(): Promise<DaemonEntry[]>\n \n /** Remove stale entries (dead PIDs) */\n cleanup(): Promise<number>\n}\n```\n\n### 3.4 IPC Server\n\n#### Transport\n- Unix domain socket: `.opentasks/daemon.sock`\n- Line-based JSON-RPC 2.0\n\n#### Protocol\n```\nRequest: {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"ping\",\"params\":{}}\\n\nResponse: {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"pong\":true}}\\n\nError: {\"jsonrpc\":\"2.0\",\"id\":1,\"error\":{\"code\":-32600,\"message\":\"...\"}}\\n\n```\n\n#### Phase 3a Methods (Lifecycle - implement first)\n| Method | Description |\n|--------|-------------|\n| `ping` | Health check, returns `{pong: true}` |\n| `health` | Detailed health status |\n| `status` | Daemon status and stats |\n| `shutdown` | Graceful shutdown |\n\n#### Phase 3b Methods (Graph operations - implement later)\n| Method | Description |\n|--------|-------------|\n| `graph.query` | Query nodes/edges |\n| `graph.get` | Get node by ID |\n| `graph.create` | Create node |\n| `graph.update` | Update node |\n| `graph.delete` | Delete node |\n| `graph.createEdge` | Create edge |\n| `graph.deleteEdge` | Delete edge |\n| `flush` | Force immediate flush |\n\n#### IPC Types\n```typescript\ninterface IPCServer {\n /** Start listening on socket */\n start(): Promise<void>\n \n /** Stop accepting connections */\n stop(): Promise<void>\n \n /** Register method handler */\n handle<P, R>(method: string, handler: (params: P) => Promise<R>): void\n}\n\ninterface IPCRequest {\n jsonrpc: '2.0'\n id: string | number\n method: string\n params?: unknown\n}\n\ninterface IPCResponse {\n jsonrpc: '2.0'\n id: string | number\n result?: unknown\n error?: {\n code: number\n message: string\n data?: unknown\n }\n}\n```\n\n### 3.5 File Watcher\n\n#### Watched Files\n1. `graph.jsonl` - Source of truth, detect external edits\n2. `specs/*.md` - Markdown files (if expansion enabled)\n3. `issues/*.md` - Markdown files (if expansion enabled)\n4. `config.json` - Configuration changes\n\n#### Behavior\n```typescript\ninterface FileWatcher {\n /** Start watching */\n start(): void\n \n /** Stop watching */\n stop(): void\n \n /** Pause during internal writes */\n pause(): void\n \n /** Resume after internal writes */\n resume(): void\n}\n```\n\n#### Change Detection Flow\n```\nExternal edit detected:\n1. Pause flush manager (prevent write conflicts)\n2. Reload affected data from file\n3. Merge with in-memory state (or replace if conflict)\n4. Mark as dirty for next flush cycle\n5. Resume flush manager\n```\n\n### 3.6 Daemon Flush Manager\n\nWraps `DebouncedFlusher` with daemon-specific coordination.\n\n```typescript\ninterface DaemonFlushManager {\n /** Mark node as dirty */\n markDirty(nodeId: string): void\n \n /** Schedule debounced flush */\n schedule(): void\n \n /** Force immediate flush */\n flush(): Promise<void>\n \n /** Pause flushing (for file watcher) */\n pause(): void\n \n /** Resume flushing */\n resume(): void\n \n /** Final flush on shutdown */\n finalFlush(): Promise<void>\n}\n```\n\n## File Structure\n\n```\nsrc/daemon/\n├── index.ts # Module exports\n├── lifecycle.ts # Daemon start/stop\n├── lock.ts # Lock file operations \n├── registry.ts # Global registry\n├── ipc.ts # IPC server\n├── methods/ # IPC method handlers\n│ ├── lifecycle.ts # ping, health, status, shutdown\n│ └── graph.ts # graph.* methods\n├── watcher.ts # File watcher\n├── flush.ts # Flush manager\n└── __tests__/\n ├── lifecycle.test.ts\n ├── lock.test.ts\n ├── registry.test.ts\n ├── ipc.test.ts\n └── watcher.test.ts\n```\n\n## Deferred Items\n\n### Parent Process Monitoring\n- Daemon should exit if parent process dies (prevents orphans)\n- **Deferred**: Note in code, implement in future iteration\n\n### Cross-Platform Support\n- Unix domain sockets are Linux/macOS only\n- Windows would need named pipes\n- **Deferred**: Note in code, implement when needed\n\n## Dependencies\n\n- Phase 2 complete (GraphStore, QueryEngine, ValidationService)\n- Refactored SyncManager → DebouncedFlusher\n\n## Implementation Order\n\n1. Refactor SyncManager → extract DebouncedFlusher\n2. Lock file operations (`lock.ts`)\n3. Global registry (`registry.ts`)\n4. Basic daemon lifecycle (`lifecycle.ts`)\n5. IPC server with lifecycle methods (`ipc.ts`, `methods/lifecycle.ts`)\n6. File watcher (`watcher.ts`)\n7. Daemon flush manager (`flush.ts`)\n8. IPC graph methods (`methods/graph.ts`)\n\n## References\n\n- [[s-7u8f|OpenTasks Implementation Plan]]\n- [[s-zm8l|Phase 2: Graph Operations]]\n- [ARCHITECTURE.md](./docs/ARCHITECTURE.md) - Daemon design\n","priority":0,"archived":0,"archived_at":null,"created_at":"2026-01-28 05:57:09","updated_at":"2026-01-28 05:57:09","parent_id":null,"parent_uuid":null,"relationships":[{"from":"s-9r97","from_type":"spec","to":"s-7u8f","to_type":"spec","type":"references"},{"from":"s-9r97","from_type":"spec","to":"s-zm8l","to_type":"spec","type":"depends-on"}],"tags":["architecture","daemon","ipc","phase-3"]}
9
- {"id":"s-4dv1","uuid":"6bba5bd4-f329-4d3a-8e74-21eeddab877e","title":"Phase 4: Agent Interface","file_path":"specs/s-4dv1_phase_4_agent_interface.md","content":"# Phase 4: Agent Interface\n\n## Overview\n\nPhase 4 implements the **3-tool MCP interface** for agents to interact with the OpenTasks graph. These tools provide the relationship layer over existing task systems - agents use native tools (TaskCreate, bd new, etc.) for CRUD, and OpenTasks provides graph operations.\n\n## Design Decisions\n\n| Decision | Choice | Rationale |\n|----------|--------|-----------|\n| Interface | 3 MCP tools (link, query, annotate) | Agents use native CRUD; OpenTasks adds relationships |\n| Node CRUD | Deferred to Phase 5 (Providers) | Native storage CRUD comes via provider interface |\n| Node validation | Validate existence before edge creation | Prevents dangling edges in graph |\n| Query results | Reduced by default, verbose flag available | Context economy for agents |\n| Annotate scope | All feedback operations | Complete feedback lifecycle |\n| Client design | Smart client with caching/batching | Expand if needed |\n| URI validation | Deferred to Phase 5 | Store URIs as strings, validate later |\n\n## The 3-Tool Interface\n\n### 1. `link` Tool\n\nCreate and remove edges between nodes.\n\n```typescript\ninterface LinkParams {\n from_id: string // Source node ID or provider URI\n to_id: string // Target node ID or provider URI\n type: EdgeType // blocks, implements, references, etc.\n remove?: boolean // true to remove edge (default: false)\n metadata?: Record<string, unknown>\n}\n\ninterface LinkResult {\n success: boolean\n edge_id?: string // ID of created edge (if not removing)\n error?: string\n}\n```\n\n**Behavior:**\n- Validates that both `from_id` and `to_id` reference existing nodes\n- For provider URIs (e.g., `beads://./bd-123`), validation deferred to Phase 5\n- Returns error if nodes don't exist (for local IDs)\n- Idempotent: creating existing edge succeeds, removing non-existent edge succeeds\n\n**Edge Types:**\n- `blocks` - Hard dependency (to_id blocks from_id)\n- `implements` - Issue implements spec\n- `references` - Soft reference\n- `depends-on` - General dependency\n- `discovered-from` - Work discovered during implementation\n- `related` - Related entities\n\n### 2. `query` Tool\n\nUnified query interface for graph traversal.\n\n```typescript\ninterface QueryParams {\n // Query type (exactly one required)\n nodes?: NodeFilter // Query nodes\n edges?: EdgeFilter // Query edges\n ready?: ReadyOptions // Get unblocked work\n blockers?: BlockerParams // Get what blocks a node\n blocking?: BlockerParams // Get what a node blocks\n feedback?: FeedbackParams // Get feedback on a node\n \n // Output control\n verbose?: boolean // Return full objects (default: false)\n limit?: number // Max results (default: 50)\n offset?: number // Pagination offset\n}\n\n// Reduced format (verbose=false)\ninterface NodeSummary {\n id: string\n type: NodeType\n title: string\n status?: string // For issues\n priority?: number\n archived: boolean\n}\n\n// Reduced format for edges\ninterface EdgeSummary {\n id: string\n from_id: string\n to_id: string\n type: EdgeType\n}\n\ninterface QueryResult {\n items: NodeSummary[] | EdgeSummary[] | Node[] | Edge[]\n total?: number // Total count (if available)\n has_more: boolean\n}\n```\n\n**Query Types:**\n\n| Type | Purpose | Returns |\n|------|---------|---------|\n| `nodes` | Filter nodes by type, status, tags, etc. | Node summaries/objects |\n| `edges` | Filter edges by type, from/to | Edge summaries/objects |\n| `ready` | Get unblocked issues ready to work on | Issue summaries/objects |\n| `blockers` | Get nodes blocking a specific node | Node summaries/objects |\n| `blocking` | Get nodes blocked by a specific node | Node summaries/objects |\n| `feedback` | Get feedback on a node | Feedback summaries/objects |\n\n### 3. `annotate` Tool\n\nComplete feedback lifecycle management.\n\n```typescript\ninterface AnnotateParams {\n // Target specification\n target_id: string // Node receiving annotation\n \n // Operation (exactly one required)\n create?: CreateFeedback // Create new feedback\n resolve?: string // Resolve feedback by ID\n dismiss?: string // Dismiss feedback by ID\n reopen?: string // Reopen resolved/dismissed feedback\n \n // Optional: from which issue\n from_id?: string // Issue providing feedback\n}\n\ninterface CreateFeedback {\n content: string // Feedback content (markdown)\n type?: FeedbackType // comment, suggestion, request (default: comment)\n anchor?: FeedbackAnchor // Line/text anchor in target\n}\n\ninterface FeedbackAnchor {\n line?: number // Line number in target content\n text?: string // Text snippet to anchor to\n}\n\ninterface AnnotateResult {\n success: boolean\n feedback_id?: string // ID of created/modified feedback\n error?: string\n}\n```\n\n**Operations:**\n- `create` - Create new feedback node linked to target\n- `resolve` - Mark feedback as resolved\n- `dismiss` - Dismiss feedback (won't fix)\n- `reopen` - Reopen previously resolved/dismissed feedback\n\n## Client Library\n\n### OpenTasksClient\n\nSmart client with connection management and convenience methods.\n\n```typescript\nclass OpenTasksClient {\n constructor(options?: ClientOptions)\n \n // Connection lifecycle\n connect(): Promise<void>\n disconnect(): void\n readonly connected: boolean\n \n // The 3 tools\n link(params: LinkParams): Promise<LinkResult>\n query(params: QueryParams): Promise<QueryResult>\n annotate(params: AnnotateParams): Promise<AnnotateResult>\n \n // Convenience methods (built on query)\n ready(options?: ReadyOptions): Promise<NodeSummary[]>\n blockers(nodeId: string): Promise<NodeSummary[]>\n blocking(nodeId: string): Promise<NodeSummary[]>\n feedback(nodeId: string): Promise<FeedbackSummary[]>\n}\n\ninterface ClientOptions {\n socketPath?: string // Custom socket path\n autoConnect?: boolean // Connect on instantiation (default: true)\n timeout?: number // Request timeout (default: 30000)\n}\n```\n\n**Features:**\n- Auto-connects to daemon on first request\n- Caches connection for reuse\n- Request timeout handling\n- Graceful disconnect\n\n## File Structure\n\n```\nsrc/\n├── tools/\n│ ├── index.ts # Tool exports\n│ ├── link.ts # link tool implementation\n│ ├── query.ts # query tool implementation\n│ ├── annotate.ts # annotate tool implementation\n│ └── types.ts # Tool parameter/result types\n├── client/\n│ ├── index.ts # Client exports\n│ └── client.ts # OpenTasksClient class\n└── daemon/\n └── methods/\n └── tools.ts # IPC handlers for 3 tools\n```\n\n## IPC Protocol\n\nTools register as IPC methods:\n\n| Method | Params | Returns |\n|--------|--------|---------|\n| `tools.link` | LinkParams | LinkResult |\n| `tools.query` | QueryParams | QueryResult |\n| `tools.annotate` | AnnotateParams | AnnotateResult |\n\n## Implementation Notes\n\n### Node Validation (link tool)\n\nFor local node IDs (s-xxx, i-xxx, f-xxx, e-xxx):\n- Validate existence via `store.getNode(id)`\n- Return error if node not found\n\nFor provider URIs (beads://, claude://, jira://):\n- Accept as-is (validation deferred to Phase 5)\n- Store URI string directly in edge\n\n### Reduced vs Verbose Output (query tool)\n\n**Reduced (default):** Minimal fields for context economy\n- Nodes: id, type, title, status, priority, archived\n- Edges: id, from_id, to_id, type\n\n**Verbose:** Full objects from storage\n- Nodes: All fields including content, timestamps, tags\n- Edges: All fields including metadata, created_at\n\n### Feedback Anchoring (annotate tool)\n\nWhen creating feedback with anchor:\n- `line` - Direct line number reference\n- `text` - Search for text in target content, extract line\n\nAnchor stored in feedback node's `target_anchor` field.\n\n## Dependencies\n\n- [[s-9r97|Phase 3: Daemon & IPC]] - IPC server, flush manager\n- [[s-zm8l|Phase 2: Graph Operations]] - GraphStore, QueryEngine\n\n## Acceptance Criteria\n\n- [ ] `link` tool creates/removes edges with validation\n- [ ] `query` tool supports all query types with reduced/verbose output\n- [ ] `annotate` tool manages full feedback lifecycle\n- [ ] `OpenTasksClient` connects to daemon and exposes tools\n- [ ] IPC handlers registered for all 3 tools\n- [ ] Tests for each tool and client\n- [ ] Error handling for missing nodes, invalid params\n","priority":0,"archived":0,"archived_at":null,"created_at":"2026-01-28 07:04:16","updated_at":"2026-01-28 07:04:16","parent_id":null,"parent_uuid":null,"relationships":[{"from":"s-4dv1","from_type":"spec","to":"s-7u8f","to_type":"spec","type":"implements"}],"tags":["agent-interface","mcp","opentasks","phase-4"]}
10
- {"id":"s-9x15","uuid":"5088681a-e9a6-45d3-ba25-f8155c9c6873","title":"Phase 5: Providers","file_path":"specs/s-9x15_phase_5_providers.md","content":"# Phase 5: Providers\n\n**Parent**: [[s-7u8f]] OpenTasks Implementation Plan\n\n## Overview\n\nPhase 5 adds the provider layer that enables OpenTasks to connect heterogeneous task systems. Providers own node content while GraphStore owns relationships (edges). This maintains OpenTasks' identity as a \"graph connector\" rather than a replacement for existing tools.\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│ GraphStore │\n│ ┌─────────────────────────────────────────────────────────┐ │\n│ │ Edge Operations (Source of Truth) │ │\n│ │ createEdge(), deleteEdge(), getEdge() │ │\n│ │ query.edges(), query.blockers(), query.ready() │ │\n│ └─────────────────────────────────────────────────────────┘ │\n│ │ │\n│ routes node ops via │\n│ ▼ │\n│ ┌─────────────────────────────────────────────────────────┐ │\n│ │ Provider Registry │ │\n│ │ resolveNode(idOrUri) → routes to appropriate provider │ │\n│ │ │ │\n│ │ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ │\n│ │ │ Native │ │ Beads │ │ Claude Tasks │ │ │\n│ │ │ Provider │ │ Provider │ │ Provider │ │ │\n│ │ │ (wraps │ │ (bd CLI) │ │ (TaskCreate/ │ │ │\n│ │ │ existing)│ │ │ │ TaskUpdate) │ │ │\n│ │ └──────────┘ └──────────┘ └──────────────────┘ │ │\n│ └─────────────────────────────────────────────────────────┘ │\n└─────────────────────────────────────────────────────────────┘\n```\n\n### Key Principles\n\n1. **GraphStore owns edges** - All OpenTasks relationships stored in SQLite/JSONL\n2. **Providers own node content** - Each provider is source of truth for its nodes\n3. **NativeProvider wraps existing** - No breaking changes to Phase 1-4 code\n4. **Full CRUD on providers** - Providers support create, read, update, delete\n5. **URI parsing per provider** - Each provider implements its own scheme parsing\n\n### Data Flow\n\n**Local node operations** (e.g., `s-abc1`, `i-xyz2`):\n```\nstore.getNode('s-abc1') \n → registry.resolve('s-abc1')\n → NativeProvider.get('s-abc1')\n → existing SQLite/JSONL storage\n```\n\n**External node resolution** (e.g., `beads://./bd-123`):\n```\nstore.resolveNode('beads://./bd-123')\n → registry.resolve('beads://./bd-123')\n → BeadsProvider.get('bd-123')\n → bd show bd-123 (CLI)\n → creates/updates ExternalNode in GraphStore\n```\n\n## Provider Interface\n\n### Core Interface\n\n```typescript\ninterface Provider {\n /** Provider identifier */\n readonly name: string\n \n /** URI schemes this provider handles (e.g., ['beads', 'bd']) */\n readonly schemes: string[]\n \n /** What operations this provider supports */\n readonly capabilities: ProviderCapabilities\n \n // URI Parsing (each provider implements its own)\n parseUri(uri: string): ParsedUri | null\n buildUri(id: string, options?: UriOptions): string\n isValidUri(uri: string): boolean\n \n // CRUD Operations\n get(id: string): Promise<ProviderNode | null>\n list(filter?: ProviderFilter): Promise<ProviderNode[]>\n create(input: ProviderCreateInput): Promise<ProviderNode>\n update(id: string, updates: ProviderUpdateInput): Promise<ProviderNode>\n delete(id: string): Promise<void>\n \n // Optional: Search\n search?(query: string, options?: SearchOptions): Promise<ProviderNode[]>\n \n // Optional: Watch for changes (for background sync)\n watch?(callback: WatchCallback): Unsubscribe\n}\n\ninterface ProviderCapabilities {\n read: boolean\n write: boolean\n search: boolean\n watch: boolean\n}\n\ninterface ParsedUri {\n scheme: string // 'beads', 'claude', 'native'\n workspace?: string // '.', 'current', absolute path\n id: string // 'bd-123', 't-abc'\n isRelative: boolean\n}\n```\n\n### Provider Node\n\n```typescript\ninterface ProviderNode {\n /** ID in provider's format */\n id: string\n \n /** Canonical URI */\n uri: string\n \n /** Node type equivalent */\n type: 'spec' | 'issue' | 'task' | 'external'\n \n /** Display title */\n title: string\n \n /** Content/description */\n content?: string\n \n /** Provider-specific status */\n status?: string\n \n /** Priority (normalized 0-4) */\n priority?: number\n \n /** Raw data from provider */\n rawData?: Record<string, unknown>\n \n /** When this data was fetched */\n fetchedAt: string\n}\n```\n\n## Provider Registry\n\n```typescript\ninterface ProviderRegistry {\n /** Register a provider */\n register(provider: Provider): void\n \n /** Unregister a provider */\n unregister(name: string): void\n \n /** Get provider by name */\n get(name: string): Provider | undefined\n \n /** Find provider for a URI or ID */\n resolveProvider(idOrUri: string): Provider | null\n \n /** List all registered providers */\n list(): Provider[]\n \n /** Check if a URI/ID can be resolved */\n canResolve(idOrUri: string): boolean\n}\n```\n\n## Materialization Strategy\n\nExternal nodes can be materialized (cached in GraphStore) with configurable strategy:\n\n```typescript\ninterface MaterializationConfig {\n /** Default strategy */\n default: 'on-demand' | 'lazy' | 'eager'\n \n /** Per-provider overrides */\n providers?: Record<string, MaterializationStrategy>\n \n /** Background sync interval (ms), 0 to disable */\n backgroundSyncInterval?: number\n \n /** How long before cached data is considered stale (ms) */\n staleAfter?: number\n}\n\ntype MaterializationStrategy = \n | 'on-demand' // Only when explicitly requested\n | 'lazy' // On first access\n | 'eager' // When edge is created\n | 'none' // Never materialize, always fetch\n```\n\n### Materialization Flow\n\n```typescript\n// On-demand (default)\nawait store.resolveNode('beads://./bd-123', { materialize: true })\n\n// Lazy (on access)\nconst edge = await store.getEdge('x-abc1') // edge.to_id = 'beads://./bd-123'\nconst node = await store.resolveNode(edge.to_id) // auto-materializes\n\n// Background sync\nstore.startBackgroundSync({ interval: 60000 }) // refresh every minute\n```\n\n## Implementations\n\n### NativeProvider\n\nWraps existing GraphStore node operations. No separate storage needed.\n\n```typescript\nclass NativeProvider implements Provider {\n readonly name = 'native'\n readonly schemes = ['native', 'opentasks']\n readonly capabilities = { read: true, write: true, search: true, watch: false }\n \n constructor(private store: GraphStore) {}\n \n parseUri(uri: string): ParsedUri | null {\n // native://spec/s-abc1 or just s-abc1\n const match = uri.match(/^(?:native:\\/\\/)?(\\w+\\/)?([sifex]-[a-z0-9]+)$/)\n if (!match) return null\n return { scheme: 'native', id: match[2], isRelative: false }\n }\n \n buildUri(id: string): string {\n return `native://${id}`\n }\n \n async get(id: string): Promise<ProviderNode | null> {\n const node = await this.store.getNode(id)\n if (!node) return null\n return this.toProviderNode(node)\n }\n \n async create(input: ProviderCreateInput): Promise<ProviderNode> {\n const node = await this.store.createNode(input)\n return this.toProviderNode(node)\n }\n \n // ... delegates to existing GraphStore methods\n}\n```\n\n### BeadsProvider\n\nIntegrates with Beads via CLI (`bd` command).\n\n```typescript\nclass BeadsProvider implements Provider {\n readonly name = 'beads'\n readonly schemes = ['beads', 'bd']\n readonly capabilities = { read: true, write: true, search: true, watch: false }\n \n constructor(private config: BeadsConfig) {}\n \n parseUri(uri: string): ParsedUri | null {\n // beads://./bd-123 or beads://workspace/bd-123\n const match = uri.match(/^beads:\\/\\/([^/]+)\\/(.+)$/)\n if (!match) return null\n return {\n scheme: 'beads',\n workspace: match[1],\n id: match[2],\n isRelative: match[1] === '.'\n }\n }\n \n async get(id: string): Promise<ProviderNode | null> {\n const result = await this.exec(['show', id, '--json'])\n if (!result) return null\n return this.parseBeadsIssue(result)\n }\n \n async create(input: ProviderCreateInput): Promise<ProviderNode> {\n const args = ['create', input.title]\n if (input.content) args.push('--description', input.content)\n const result = await this.exec(args)\n return this.parseBeadsIssue(result)\n }\n \n private async exec(args: string[]): Promise<any> {\n // Execute bd CLI command\n }\n}\n```\n\n### ClaudeTasksProvider\n\nIntegrates with Claude Code's native task system.\n\n```typescript\nclass ClaudeTasksProvider implements Provider {\n readonly name = 'claude'\n readonly schemes = ['claude', 'task']\n readonly capabilities = { read: true, write: true, search: false, watch: false }\n \n parseUri(uri: string): ParsedUri | null {\n // claude://current/t-abc or claude://session-id/t-abc\n const match = uri.match(/^claude:\\/\\/([^/]+)\\/(.+)$/)\n if (!match) return null\n return {\n scheme: 'claude',\n workspace: match[1], // 'current' or session ID\n id: match[2],\n isRelative: match[1] === 'current'\n }\n }\n \n // Implementation uses TaskCreate/TaskUpdate/TaskList internally\n // This bridges Claude's ephemeral tasks with OpenTasks persistence\n}\n```\n\n## GraphStore Integration\n\n### New Methods\n\n```typescript\ninterface GraphStore {\n // Existing methods unchanged...\n \n /** Provider registry */\n readonly providers: ProviderRegistry\n \n /** Resolve any node by ID or URI */\n resolveNode(\n idOrUri: string, \n options?: ResolveOptions\n ): Promise<Node | ExternalNode | null>\n \n /** Materialize an external node */\n materializeNode(uri: string): Promise<ExternalNode>\n \n /** Refresh a materialized node */\n refreshNode(id: string): Promise<ExternalNode>\n \n /** Start background sync for external nodes */\n startBackgroundSync(config?: BackgroundSyncConfig): void\n \n /** Stop background sync */\n stopBackgroundSync(): void\n}\n\ninterface ResolveOptions {\n /** Force fresh fetch (ignore cache) */\n refresh?: boolean\n \n /** Materialize if external */\n materialize?: boolean\n \n /** Include raw provider data */\n includeRawData?: boolean\n}\n```\n\n### Resolution Logic\n\n```typescript\nasync function resolveNode(idOrUri: string, options?: ResolveOptions) {\n // 1. Check if it's a local ID\n if (isLocalId(idOrUri)) {\n return this.getNode(idOrUri)\n }\n \n // 2. Check if already materialized\n const existing = await this.findExternalNode(idOrUri)\n if (existing && !options?.refresh && !isStale(existing)) {\n return existing\n }\n \n // 3. Find provider and fetch\n const provider = this.providers.resolveProvider(idOrUri)\n if (!provider) {\n throw new Error(`No provider for: ${idOrUri}`)\n }\n \n const parsed = provider.parseUri(idOrUri)\n const providerNode = await provider.get(parsed.id)\n \n // 4. Materialize if requested\n if (options?.materialize && providerNode) {\n return this.materializeNode(idOrUri, providerNode)\n }\n \n return providerNode\n}\n```\n\n## File Structure\n\n```\nsrc/providers/\n├── index.ts # Module exports\n├── types.ts # Provider interfaces and types\n├── registry.ts # ProviderRegistry implementation\n├── materialization.ts # Materialization logic\n├── native.ts # NativeProvider\n├── beads.ts # BeadsProvider \n├── claude-tasks.ts # ClaudeTasksProvider\n└── __tests__/\n ├── registry.test.ts\n ├── native.test.ts\n ├── beads.test.ts\n └── claude-tasks.test.ts\n```\n\n## Deliverables\n\n### Provider Types (`src/providers/types.ts`)\n- [ ] `Provider` interface with full CRUD\n- [ ] `ProviderCapabilities` type\n- [ ] `ProviderNode` type\n- [ ] `ParsedUri` type\n- [ ] `MaterializationConfig` type\n- [ ] `ProviderCreateInput`, `ProviderUpdateInput`, `ProviderFilter` types\n\n### Provider Registry (`src/providers/registry.ts`)\n- [ ] `ProviderRegistry` implementation\n- [ ] URI/ID routing logic\n- [ ] Provider registration/lookup\n\n### Native Provider (`src/providers/native.ts`)\n- [ ] Wraps existing GraphStore node operations\n- [ ] URI parsing for `native://` and local IDs\n- [ ] Full CRUD delegation\n\n### Beads Provider (`src/providers/beads.ts`)\n- [ ] CLI integration (`bd` command execution)\n- [ ] URI parsing for `beads://` scheme\n- [ ] Issue CRUD via CLI\n- [ ] Response parsing\n\n### Claude Tasks Provider (`src/providers/claude-tasks.ts`)\n- [ ] Integration with Claude's task system\n- [ ] URI parsing for `claude://` scheme\n- [ ] Task CRUD mapping\n\n### Materialization (`src/providers/materialization.ts`)\n- [ ] On-demand materialization\n- [ ] Lazy materialization on access\n- [ ] Background sync with configurable interval\n- [ ] Stale detection and refresh\n\n### GraphStore Integration\n- [ ] Add `providers` registry to GraphStore\n- [ ] Add `resolveNode()` method\n- [ ] Add `materializeNode()` method\n- [ ] Add background sync methods\n\n### Tests\n- [ ] Provider interface compliance tests\n- [ ] Registry routing tests\n- [ ] NativeProvider delegation tests\n- [ ] BeadsProvider CLI integration tests\n- [ ] ClaudeTasksProvider tests\n- [ ] Materialization strategy tests\n- [ ] Background sync tests\n\n## Dependencies\n\n- Phase 1-4 complete (GraphStore, edges, tools)\n- `bd` CLI available for BeadsProvider tests\n- Claude Code environment for ClaudeTasksProvider\n\n## Success Criteria\n\n1. Can register multiple providers with GraphStore\n2. `resolveNode()` correctly routes to appropriate provider\n3. NativeProvider passes all existing node operation tests\n4. BeadsProvider can CRUD beads issues via CLI\n5. ClaudeTasksProvider can bridge Claude's task system\n6. Materialization works with all three strategies\n7. Background sync refreshes stale external nodes\n8. All providers implement URI parsing correctly\n\n## Open Questions (Resolved)\n\n| Question | Decision |\n|----------|----------|\n| Provider CRUD scope | Full CRUD |\n| GraphStore vs Provider | GraphStore routes to providers, owns edges |\n| Materialization default | On-demand, with lazy and background sync available |\n| Registry location | Per-GraphStore |\n| Integration method | Per-provider (CLI for Beads) |\n| Which providers | Native + Beads + Claude Tasks |\n| URI parsing | Part of provider interface |\n","priority":0,"archived":0,"archived_at":null,"created_at":"2026-01-28 08:02:10","updated_at":"2026-01-28 08:02:10","parent_id":null,"parent_uuid":null,"relationships":[{"from":"s-9x15","from_type":"spec","to":"s-7u8f","to_type":"spec","type":"implements"}],"tags":["implementation","phase-5","providers"]}
11
- {"id":"s-1pai","uuid":"740c1fb7-69e1-404f-b671-dfc1fd8f331c","title":"Provider Interface Enhancement - Dependency & Relationship Support","file_path":"specs/s-1pai_provider_interface_enhancement_dependency_relation.md","content":"# Provider Interface Enhancement - Typed Extensions & Relationship Queries\n\n**Parent**: [[s-9x15]] Phase 5: Providers\n**Related**: [[s-4lv6]] Federated Graph Architecture\n\n## Overview\n\nThis spec defines how providers expose their full capabilities through typed extensions rather than a bloated base interface. Each provider defines its own node type and optional traits for features like relationship queries.\n\n## Design Principles\n\nBased on architectural discussions, we've established these principles:\n\n1. **Providers own their data** - OpenTasks queries providers for their internal relationships, not sync them\n2. **Materialization preserves everything** - External nodes store full provider data in `rawData`\n3. **Typed extensions over optional fields** - Each provider defines its own typed interface\n4. **Capabilities via traits** - Providers implement optional traits for features they support\n5. **Query, don't sync** - Use `RelationshipQueryable` to ask providers about their edges\n\n## What This Spec Does NOT Cover\n\n- Federated traversal API (see [[s-4lv6]])\n- Graphology integration (see [[s-4lv6]])\n- Schema changes for cached edges (see [[s-4lv6]])\n\n---\n\n## Base Interface (Unchanged)\n\nThe base `Provider` interface from [[s-9x15]] remains minimal:\n\n```typescript\ninterface Provider {\n readonly name: string\n readonly schemes: string[]\n readonly capabilities: ProviderCapabilities\n \n // URI operations\n parseUri(uri: string): ParsedUri | null\n buildUri(id: string, options?: UriOptions): string\n isValidUri(uri: string): boolean\n \n // CRUD\n get(id: string): Promise<ProviderNode | null>\n list(filter?: ProviderFilter): Promise<ProviderNode[]>\n create(input: ProviderCreateInput): Promise<ProviderNode>\n update(id: string, updates: ProviderUpdateInput): Promise<ProviderNode>\n delete(id: string): Promise<void>\n \n // Optional\n search?(query: string, options?: SearchOptions): Promise<ProviderNode[]>\n watch?(callback: WatchCallback): Unsubscribe\n}\n```\n\n---\n\n## Provider-Specific Extensions\n\nInstead of adding optional fields to base `ProviderNode`, each provider defines typed extensions.\n\n### BeadsProvider\n\n```typescript\n// Beads-specific node type with full type safety\ninterface BeadsNode extends ProviderNode {\n // Override with more specific return type\n type: 'spec' | 'issue' // Mapped from Beads\n \n // Beads-specific fields (not optional - Beads always has these)\n issueType: 'bug' | 'feature' | 'task' | 'epic' | 'chore'\n labels: string[]\n \n // Relationship data (from bd show --json)\n blockedBy: string[] // Local Beads IDs\n blocks: string[] // Local Beads IDs\n parent?: string // Parent issue ID\n children?: string[] // Child issue IDs\n \n // Beads-specific metadata\n assignee?: string\n closedAt?: string\n}\n\n// Beads-specific create input\ninterface BeadsCreateInput extends ProviderCreateInput {\n issueType?: 'bug' | 'feature' | 'task' | 'epic' | 'chore'\n labels?: string[]\n blockedBy?: string[] // Initial blockers\n parent?: string // Parent issue\n}\n\n// Beads-specific filter\ninterface BeadsFilter extends ProviderFilter {\n issueType?: string\n labels?: string[]\n labelAny?: string[] // OR semantics\n assignee?: string\n}\n\n// Full BeadsProvider interface\ninterface BeadsProvider extends Provider, RelationshipQueryable {\n readonly name: 'beads'\n \n // Typed overrides\n get(id: string): Promise<BeadsNode | null>\n list(filter?: BeadsFilter): Promise<BeadsNode[]>\n create(input: BeadsCreateInput): Promise<BeadsNode>\n \n // Beads-specific methods\n getReady(options?: BeadsReadyOptions): Promise<BeadsNode[]>\n \n // Relationship modifications\n addDependency(from: string, to: string, type: BeadsDependencyType): Promise<void>\n removeDependency(from: string, to: string): Promise<void>\n \n // Label management\n addLabel(id: string, label: string): Promise<void>\n removeLabel(id: string, label: string): Promise<void>\n}\n\ntype BeadsDependencyType = 'blocks' | 'related' | 'parent-child' | 'discovered-from'\n\ninterface BeadsReadyOptions {\n priority?: number\n issueType?: string\n labels?: string[]\n limit?: number\n}\n```\n\n### JiraProvider (Future Example)\n\n```typescript\ninterface JiraNode extends ProviderNode {\n issueType: 'story' | 'bug' | 'task' | 'epic' | 'subtask'\n labels: string[]\n components: string[]\n sprint?: string\n epicLink?: string\n \n // Jira link types\n blocks: string[]\n isBlockedBy: string[]\n relatesTo: string[]\n}\n\ninterface JiraProvider extends Provider, RelationshipQueryable {\n readonly name: 'jira'\n \n get(id: string): Promise<JiraNode | null>\n // ... Jira-specific methods\n}\n```\n\n---\n\n## RelationshipQueryable Trait\n\nProviders that track relationships implement this trait:\n\n```typescript\n/**\n * Trait for providers that can answer relationship queries.\n * Used by FederatedGraph to traverse across provider boundaries.\n */\ninterface RelationshipQueryable {\n /**\n * Query edges for a node.\n * Returns edges in provider's local ID format.\n */\n queryEdges(\n nodeId: string,\n options?: EdgeQueryOptions\n ): Promise<ProviderEdge[]>\n \n /**\n * What edge types does this provider support?\n */\n supportedEdgeTypes(): EdgeTypeSupport[]\n}\n\ninterface EdgeQueryOptions {\n type?: string | string[] // Filter by edge type\n direction?: 'in' | 'out' | 'both'\n}\n\ninterface ProviderEdge {\n from: string // Local ID (e.g., 'bd-123')\n to: string // Local ID (e.g., 'bd-456')\n type: string // Edge type ('blocks', 'parent-child', etc.)\n metadata?: Record<string, unknown>\n}\n\ninterface EdgeTypeSupport {\n type: string // 'blocks', 'parent-child', etc.\n canQuery: boolean // Can read existing edges\n canCreate: boolean // Can create new edges\n canDelete: boolean // Can delete edges\n affectsReady: boolean // Does this edge type affect ready status?\n}\n```\n\n### Implementation in BeadsProvider\n\n```typescript\nclass BeadsProviderImpl implements BeadsProvider, RelationshipQueryable {\n \n async queryEdges(nodeId: string, options?: EdgeQueryOptions): Promise<ProviderEdge[]> {\n // Fetch node with relationships\n const node = await this.get(nodeId)\n if (!node) return []\n \n const edges: ProviderEdge[] = []\n const direction = options?.direction ?? 'both'\n const typeFilter = options?.type \n ? (Array.isArray(options.type) ? options.type : [options.type])\n : null\n \n // Outgoing edges (this node blocks others)\n if (direction === 'out' || direction === 'both') {\n if (!typeFilter || typeFilter.includes('blocks')) {\n for (const targetId of node.blocks) {\n edges.push({ from: nodeId, to: targetId, type: 'blocks' })\n }\n }\n if (!typeFilter || typeFilter.includes('parent-child')) {\n for (const childId of node.children ?? []) {\n edges.push({ from: nodeId, to: childId, type: 'parent-child' })\n }\n }\n }\n \n // Incoming edges (others block this node)\n if (direction === 'in' || direction === 'both') {\n if (!typeFilter || typeFilter.includes('blocks')) {\n for (const sourceId of node.blockedBy) {\n edges.push({ from: sourceId, to: nodeId, type: 'blocks' })\n }\n }\n if (!typeFilter || typeFilter.includes('parent-child')) {\n if (node.parent) {\n edges.push({ from: node.parent, to: nodeId, type: 'parent-child' })\n }\n }\n }\n \n return edges\n }\n \n supportedEdgeTypes(): EdgeTypeSupport[] {\n return [\n { type: 'blocks', canQuery: true, canCreate: true, canDelete: true, affectsReady: true },\n { type: 'parent-child', canQuery: true, canCreate: true, canDelete: true, affectsReady: false },\n { type: 'discovered-from', canQuery: true, canCreate: true, canDelete: true, affectsReady: false },\n { type: 'related', canQuery: true, canCreate: true, canDelete: true, affectsReady: false },\n ]\n }\n}\n```\n\n---\n\n## Capability Discovery\n\nUpdate `ProviderCapabilities` to expose what each provider supports:\n\n```typescript\ninterface ProviderCapabilities {\n // Existing\n read: boolean\n write: boolean\n search: boolean\n watch: boolean\n \n // NEW: Relationship capabilities\n relationships: boolean // Implements RelationshipQueryable\n \n // NEW: Feature flags (provider-specific features)\n features: {\n labels?: boolean // Supports labels/tags\n hierarchy?: boolean // Supports parent-child\n nativeTypes?: boolean // Has multiple issue types\n ready?: boolean // Has native ready query\n }\n}\n```\n\n### Type Guards for Runtime Checks\n\n```typescript\nfunction isRelationshipQueryable(provider: Provider): provider is Provider & RelationshipQueryable {\n return provider.capabilities.relationships === true\n}\n\nfunction isBeadsProvider(provider: Provider): provider is BeadsProvider {\n return provider.name === 'beads'\n}\n\n// Usage\nconst provider = registry.resolveProvider(uri)\nif (isRelationshipQueryable(provider)) {\n const edges = await provider.queryEdges(id, { type: 'blocks' })\n}\n\nif (isBeadsProvider(provider)) {\n const ready = await provider.getReady({ priority: 1 })\n}\n```\n\n---\n\n## Data Flow: Materialization\n\nWhen an external node is materialized, all provider data is preserved:\n\n```typescript\n// Materializing beads://./bd-123\nconst beadsNode: BeadsNode = await beadsProvider.get('bd-123')\n\n// Stored as ExternalNode\nconst externalNode: ExternalNode = {\n id: 'x-abc1',\n type: 'external',\n uri: 'beads://./bd-123',\n source: 'beads',\n materialized: true,\n cached_at: new Date().toISOString(),\n \n // Mapped fields for display\n title: beadsNode.title,\n content: beadsNode.content,\n priority: beadsNode.priority,\n \n // FULL provider data preserved\n external_data: {\n issueType: 'bug',\n labels: ['urgent', 'backend'],\n blockedBy: ['bd-456'],\n blocks: [],\n assignee: 'alice',\n // ... everything from BeadsNode\n }\n}\n```\n\nTo access provider-specific data:\n\n```typescript\n// Option 1: Access rawData directly (untyped)\nconst issueType = externalNode.external_data?.issueType\n\n// Option 2: Re-fetch from provider (typed)\nconst beadsNode = await beadsProvider.get('bd-123')\nconsole.log(beadsNode.issueType) // Type-safe: 'bug' | 'feature' | ...\n\n// Option 3: Cast rawData (if you know the type)\nconst beadsData = externalNode.external_data as BeadsNode\nconsole.log(beadsData.labels) // ['urgent', 'backend']\n```\n\n---\n\n## Relationship with [[s-4lv6]]\n\n| Concern | Handled By |\n|---------|------------|\n| `RelationshipQueryable` trait definition | **This spec (s-1pai)** |\n| Provider-specific types (`BeadsNode`, etc.) | **This spec (s-1pai)** |\n| How `FederatedGraph` uses `RelationshipQueryable` | [[s-4lv6]] |\n| Graphology integration | [[s-4lv6]] |\n| Cached edge storage/schema | [[s-4lv6]] |\n| Cross-provider traversal | [[s-4lv6]] |\n\n---\n\n## Implementation Phases\n\n### Phase 1: Provider Type Extensions\n- [ ] Define `BeadsNode` interface\n- [ ] Define `BeadsCreateInput`, `BeadsFilter`\n- [ ] Update `BeadsProvider` interface\n- [ ] Add type guards (`isBeadsProvider`, etc.)\n\n### Phase 2: RelationshipQueryable Trait\n- [ ] Define `RelationshipQueryable` interface\n- [ ] Define `ProviderEdge`, `EdgeTypeSupport`\n- [ ] Implement in `BeadsProvider`\n- [ ] Implement in `NativeProvider`\n\n### Phase 3: Capability Updates\n- [ ] Add `relationships` to `ProviderCapabilities`\n- [ ] Add `features` object to `ProviderCapabilities`\n- [ ] Update provider implementations\n\n### Phase 4: Beads CLI Integration\n- [ ] Implement `queryEdges()` using `bd show --json`\n- [ ] Implement `addDependency()` using `bd dep add`\n- [ ] Implement `removeDependency()` using `bd dep remove`\n- [ ] Implement `getReady()` using `bd ready --json`\n\n---\n\n## Success Criteria\n\n1. ✅ `BeadsProvider` returns typed `BeadsNode` with `issueType`, `labels`, `blockedBy`, etc.\n2. ✅ `BeadsProvider` implements `RelationshipQueryable`\n3. ✅ Can query Beads relationships without syncing them to OpenTasks\n4. ✅ Materialized nodes preserve all provider data in `external_data`\n5. ✅ Type guards work correctly for runtime capability checks\n6. ✅ `FederatedGraph` (from [[s-4lv6]]) can use `queryEdges()` for traversal\n\n---\n\n## Beads CLI Commands Reference\n\n| Operation | Command | Used By |\n|-----------|---------|---------|\n| Get node with relationships | `bd show <id> --json` | `get()`, `queryEdges()` |\n| Create with dependencies | `bd create \"Title\" --deps blocks:<id> --json` | `create()` |\n| Add dependency | `bd dep add <from> <to> --type <type>` | `addDependency()` |\n| Remove dependency | `bd dep remove <from> <to>` | `removeDependency()` |\n| Get ready issues | `bd ready --json` | `getReady()` |\n| Add label | `bd label add <id> <label> --json` | `addLabel()` |\n| Remove label | `bd label remove <id> <label> --json` | `removeLabel()` |\n\n---\n\n## Original Gaps Analysis (Revised)\n\n| Original Gap | Resolution |\n|--------------|------------|\n| No dependency support in ProviderNode | Providers expose via typed extensions (`BeadsNode.blockedBy`) |\n| Type system mismatch | Providers define their own types (`BeadsNode.issueType`) |\n| No tags support | Providers expose via typed extensions (`BeadsNode.labels`) |\n| Create/Update can't express relationships | Provider-specific inputs (`BeadsCreateInput.blockedBy`) |\n| No ready query | Provider-specific method (`BeadsProvider.getReady()`) |\n\nThe key insight: **These aren't gaps in the base interface - they're provider-specific features that should be expressed through typed extensions, not optional fields on a bloated base type.**\n","priority":0,"archived":0,"archived_at":null,"created_at":"2026-01-29 00:20:07","updated_at":"2026-01-29 06:00:19","parent_id":null,"parent_uuid":null,"relationships":[{"from":"s-1pai","from_type":"spec","to":"s-4lv6","to_type":"spec","type":"related"},{"from":"s-1pai","from_type":"spec","to":"s-9x15","to_type":"spec","type":"depends-on"}],"tags":["dependencies","enhancement","integration","providers"]}
12
- {"id":"s-4lv6","uuid":"6c0db039-4d7a-4bea-9e6b-713521a2f8ed","title":"Federated Graph Architecture","file_path":"specs/s-4lv6_federated_graph_architecture.md","content":"# Federated Graph Architecture\n\n**Parent**: [[s-9x15]] Phase 5: Providers\n**Related**: [[s-1pai]] Provider Interface Enhancement\n\n## Overview\n\nThis spec defines the architecture for a federated graph system that enables OpenTasks to query relationships across multiple providers (Native, Beads, Jira, etc.) through a unified traversal API. The design uses Graphology as an in-memory graph layer over the existing SQLite persistence.\n\n## Goals\n\n1. **Unified traversal API** - Query relationships without knowing which provider owns them\n2. **Provider autonomy** - Each provider owns its internal relationships; OpenTasks owns cross-provider edges\n3. **Minimal schema changes** - Extend existing SQLite schema, don't replace it\n4. **Performance at scale** - Fast in-memory queries for ~1K nodes, lazy hydration for external data\n5. **Extensible edge types** - Register new relationship types without code changes\n\n## Non-Goals\n\n- Full graph query language (Cypher, SPARQL, GraphQL)\n- Real-time sync with external providers\n- Conflict resolution for bidirectional sync\n\n---\n\n## Architecture\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│ FederatedGraph │\n│ ┌────────────────────────────────────────────────────────────┐ │\n│ │ Graphology (in-memory) │ │\n│ │ - All native nodes (s-xxx, i-xxx, f-xxx) │ │\n│ │ - Materialized external nodes (x-xxx) │ │\n│ │ - All edges (native + cached from providers) │ │\n│ └────────────────────────────────────────────────────────────┘ │\n│ │ │\n│ ┌────────────────────────────────────────────────────────────┐ │\n│ │ Edge Registry │ │\n│ │ - Registered edge types with metadata │ │\n│ │ - Inverse relationships (blocks ↔ blocked-by) │ │\n│ │ - Ready-affecting edges (only 'blocks') │ │\n│ └────────────────────────────────────────────────────────────┘ │\n│ │ │\n│ ┌────────────────────────────────────────────────────────────┐ │\n│ │ Traversal API │ │\n│ │ traverse(start, pattern) → AsyncIterable<Result> │ │\n│ │ related(uri, edgeType, direction) → Promise<URI[]> │ │\n│ │ reachable(uri, edgeType, direction) → Promise<URI[]> │ │\n│ │ ready(options) → Promise<URI[]> │ │\n│ └────────────────────────────────────────────────────────────┘ │\n│ │ │\n│ ┌────────────────────────────────────────────────────────────┐ │\n│ │ Provider Federation │ │\n│ │ - Routes URI to correct provider │ │\n│ │ - Caches provider responses (nodes + edges) │ │\n│ │ - Hydrates graph on-demand │ │\n│ └────────────────────────────────────────────────────────────┘ │\n└──────────────────────────────────────────────────────────────────┘\n │\n ┌────────────────────┼────────────────────┐\n ▼ ▼ ▼\n ┌──────────┐ ┌──────────┐ ┌──────────┐\n │ Native │ │ Beads │ │ Jira │\n │ Provider │ │ Provider │ │ Provider │\n └──────────┘ └──────────┘ └──────────┘\n```\n\n### Key Principles\n\n1. **URIs as universal identifiers** - Every node has a URI (`native://s-abc`, `beads://./bd-123`)\n2. **OpenTasks owns cross-provider edges** - e.g., `bd-123` blocks `s-abc` stored in OpenTasks\n3. **Providers own intra-provider edges** - e.g., `bd-123` blocks `bd-456` queried from Beads\n4. **Lazy hydration** - External nodes/edges fetched on-demand, cached in SQLite\n5. **Graphology for traversal** - All queries run against in-memory graph\n\n---\n\n## Data Ownership Model\n\n| Data | Owner | Storage | Refresh |\n|------|-------|---------|---------|\n| Native nodes (s-, i-, f-) | OpenTasks | SQLite (authoritative) | N/A |\n| External nodes (x-) | Provider | SQLite (cache) | On-demand or TTL |\n| Cross-provider edges | OpenTasks | SQLite (authoritative) | N/A |\n| Intra-provider edges | Provider | SQLite (cache) | On hydration |\n\n### Edge Source Semantics\n\n```typescript\n// Edge.source field values:\nsource = null | 'local' → Created in OpenTasks (authoritative)\nsource = 'beads' → Cached from Beads (can be refreshed)\nsource = 'jira' → Cached from Jira (can be refreshed)\n```\n\n---\n\n## Schema Changes (Minimal)\n\n### Edge Table Additions\n\n```sql\n-- Add to existing edges table\nALTER TABLE edges ADD COLUMN metadata TEXT; -- JSON for relationship attributes\nALTER TABLE edges ADD COLUMN cached_at TEXT; -- When fetched from provider (ISO 8601)\n\n-- Index for cache management\nCREATE INDEX idx_edges_source ON edges(source);\nCREATE INDEX idx_edges_cached_at ON edges(cached_at);\n```\n\n### Edge Schema (Updated)\n\n```typescript\ninterface StoredEdge {\n id: string // 'x-xxxx'\n uuid: string // UUID v4\n from_id: string // Node ID or external URI\n to_id: string // Node ID or external URI\n type: string // 'blocks', 'implements', etc.\n created_at: string // ISO 8601\n created_by?: string // Actor\n source?: string // 'local' | 'beads' | 'jira' | null\n cached_at?: string // When cached from provider (ISO 8601)\n metadata?: Record<string, unknown> // NEW: Relationship attributes\n}\n```\n\n### No Changes Needed\n\n- **Nodes table** - Already supports ExternalNode with `uri`, `materialized`, `cached_at`, `external_data`\n- **Tags table** - Works as-is\n- **JSONL format** - Already flexible with `[key: string]: unknown`\n\n---\n\n## Edge Type Registry\n\nEdge types are registered, not hardcoded. Providers can contribute custom types.\n\n```typescript\ninterface EdgeTypeDefinition {\n name: string // 'blocks', 'implements', 'parent-of'\n description: string // Human-readable description\n inverseOf?: string // 'blocks' ↔ 'blocked-by' (virtual)\n affectsReady: boolean // Does this edge type affect ready status?\n direction: 'directed' | 'undirected'\n providers: string[] // Which providers support this type\n}\n\n// Built-in edge types\nconst BUILTIN_EDGE_TYPES: EdgeTypeDefinition[] = [\n {\n name: 'blocks',\n description: 'Source must complete before target can start',\n inverseOf: 'blocked-by',\n affectsReady: true,\n direction: 'directed',\n providers: ['native', 'beads']\n },\n {\n name: 'implements',\n description: 'Issue implements a spec',\n affectsReady: false,\n direction: 'directed',\n providers: ['native']\n },\n {\n name: 'parent-of',\n description: 'Hierarchical parent relationship',\n inverseOf: 'child-of',\n affectsReady: false,\n direction: 'directed',\n providers: ['native', 'beads']\n },\n {\n name: 'discovered-from',\n description: 'Found while working on another node',\n affectsReady: false,\n direction: 'directed',\n providers: ['native', 'beads']\n },\n {\n name: 'related',\n description: 'Loosely associated nodes',\n affectsReady: false,\n direction: 'undirected',\n providers: ['native', 'beads']\n },\n {\n name: 'references',\n description: 'General reference link',\n affectsReady: false,\n direction: 'directed',\n providers: ['native']\n }\n]\n```\n\n---\n\n## Traversal API\n\n### Core Interface\n\n```typescript\ntype NodeURI = string // 'native://s-abc', 'beads://./bd-123'\n\ninterface FederatedGraph {\n // === Traversal ===\n \n /**\n * Generic traversal with pattern matching\n * Crosses provider boundaries transparently\n */\n traverse(\n start: NodeURI | NodeURI[],\n pattern: TraversalPattern\n ): AsyncIterable<TraversalResult>\n \n /**\n * Get directly related nodes (single hop)\n */\n related(\n uri: NodeURI,\n edgeType: string,\n direction: 'in' | 'out' | 'both'\n ): Promise<NodeURI[]>\n \n /**\n * Get transitively reachable nodes\n */\n reachable(\n uri: NodeURI,\n edgeType: string,\n direction: 'in' | 'out'\n ): Promise<NodeURI[]>\n \n /**\n * Find shortest path between nodes\n */\n shortestPath(\n from: NodeURI,\n to: NodeURI,\n edgeTypes?: string[]\n ): Promise<NodeURI[] | null>\n \n // === Ready Query ===\n \n /**\n * Get nodes ready for work (no active blockers)\n * Considers full graph including external blockers\n */\n ready(options?: ReadyOptions): Promise<NodeURI[]>\n \n // === Resolution ===\n \n /**\n * Resolve URI to full node data\n * Fetches from provider if not cached\n */\n resolve(uri: NodeURI): Promise<ResolvedNode | null>\n \n /**\n * Batch resolve for efficiency\n */\n resolveAll(uris: NodeURI[]): Promise<Map<NodeURI, ResolvedNode>>\n \n // === Hydration ===\n \n /**\n * Ensure node and its edges are in the graph\n * Fetches from provider if needed\n */\n hydrate(uri: NodeURI): Promise<void>\n \n /**\n * Invalidate cached data for a provider\n */\n invalidateCache(provider: string): Promise<void>\n \n // === Introspection ===\n \n /**\n * Get registered edge types\n */\n edgeTypes(): EdgeTypeDefinition[]\n \n /**\n * Get graph capabilities\n */\n capabilities(): GraphCapabilities\n}\n\ninterface TraversalPattern {\n steps: EdgeStep[]\n filter?: NodePredicate\n limit?: number\n}\n\ninterface EdgeStep {\n type: string | string[] // Edge type(s) to follow\n direction: 'in' | 'out' | 'both'\n minHops?: number // Default: 1\n maxHops?: number // Default: 1, Infinity for transitive\n}\n\ninterface TraversalResult {\n uri: NodeURI\n depth: number // Hops from start\n path: NodeURI[] // Path taken to reach this node\n edge?: { // Edge that led here\n type: string\n from: NodeURI\n to: NodeURI\n }\n}\n\ninterface ReadyOptions {\n type?: string | string[] // Node type filter\n status?: string | string[] // Status filter\n tags?: string[] // Tag filter\n providers?: string[] // Limit to these providers\n limit?: number\n}\n\ninterface ResolvedNode {\n uri: NodeURI\n provider: string\n data: StoredNode // Full node data\n edges: { // Known edges\n incoming: StoredEdge[]\n outgoing: StoredEdge[]\n }\n cached: boolean // Was this from cache?\n cachedAt?: string // When cached\n}\n```\n\n### Usage Examples\n\n```typescript\nconst graph = createFederatedGraph(storage, registry)\n\n// Direct blockers (single hop)\nconst blockers = await graph.related('native://s-abc', 'blocks', 'in')\n// → ['beads://./bd-123']\n\n// Transitive blockers (follows the chain)\nconst allBlockers = await graph.reachable('native://s-abc', 'blocks', 'in')\n// → ['beads://./bd-123', 'beads://./bd-456']\n\n// Complex pattern: specs → implementing issues → their blockers\nfor await (const result of graph.traverse(['native://s-abc'], {\n steps: [\n { type: 'implements', direction: 'in' },\n { type: 'blocks', direction: 'in', maxHops: Infinity }\n ],\n filter: { status: { $ne: 'closed' } }\n})) {\n console.log(`${result.uri} at depth ${result.depth}`)\n}\n\n// Ready across all providers\nconst readyWork = await graph.ready({\n type: 'issue',\n status: 'open',\n providers: ['native', 'beads']\n})\n\n// dbt-style selectors (convenience methods)\nconst upstream = await graph.select('+native://s-abc') // Blockers\nconst downstream = await graph.select('native://s-abc+') // What this blocks\n```\n\n---\n\n## Provider Interface Extensions\n\nProviders that support relationships implement an optional trait:\n\n```typescript\n/**\n * Trait for providers that track relationships\n */\ninterface RelationshipQueryable {\n /**\n * Query edges from this provider\n * Returns edges in provider's local ID format\n */\n queryEdges(\n nodeId: string,\n edgeType?: string,\n direction?: 'in' | 'out' | 'both'\n ): Promise<ProviderEdge[]>\n \n /**\n * What edge types does this provider support?\n */\n supportedEdgeTypes(): EdgeTypeSupport[]\n}\n\ninterface ProviderEdge {\n from: string // Local ID (e.g., 'bd-123')\n to: string // Local ID (e.g., 'bd-456')\n type: string // Edge type\n metadata?: Record<string, unknown>\n}\n\ninterface EdgeTypeSupport {\n type: string\n canQuery: boolean // Can query existing edges\n canCreate: boolean // Can create edges via provider\n canDelete: boolean // Can delete edges via provider\n}\n\n// BeadsProvider implements this\ninterface BeadsProvider extends Provider, RelationshipQueryable {\n // Beads-specific methods...\n \n queryEdges(nodeId: string, edgeType?: string, direction?: 'in' | 'out'): Promise<ProviderEdge[]> {\n // Uses: bd show <id> --json (returns blockedBy, blocks, etc.)\n // Or: bd dep tree <id> --json\n }\n \n supportedEdgeTypes(): EdgeTypeSupport[] {\n return [\n { type: 'blocks', canQuery: true, canCreate: true, canDelete: true },\n { type: 'parent-child', canQuery: true, canCreate: true, canDelete: true },\n { type: 'discovered-from', canQuery: true, canCreate: true, canDelete: true },\n { type: 'related', canQuery: true, canCreate: true, canDelete: true }\n ]\n }\n}\n```\n\n---\n\n## Graphology Integration\n\n### Adapter Layer\n\n```typescript\nimport Graph from 'graphology'\nimport { bfsFromNode } from 'graphology-traversal'\n\ninterface GraphologyAdapter {\n readonly graph: Graph\n \n // Load from SQLite on startup\n loadFromStorage(storage: Storage): Promise<void>\n \n // Sync mutations (called after Storage writes)\n onNodeCreated(node: StoredNode): void\n onNodeUpdated(id: string, updates: Partial<StoredNode>): void\n onNodeDeleted(id: string): void\n onEdgeCreated(edge: StoredEdge): void\n onEdgeDeleted(id: string): void\n \n // Hydration (add external data to graph)\n hydrateNode(uri: NodeURI, node: StoredNode): void\n hydrateEdges(uri: NodeURI, edges: StoredEdge[]): void\n}\n\nclass GraphologyAdapterImpl implements GraphologyAdapter {\n readonly graph = new Graph({ multi: true, type: 'directed' })\n \n async loadFromStorage(storage: Storage): Promise<void> {\n // Load all nodes\n const nodes = await storage.queryNodes({})\n for (const node of nodes) {\n const uri = this.nodeToUri(node)\n this.graph.addNode(uri, { ...node })\n }\n \n // Load all edges\n const edges = await storage.getAllEdges()\n for (const edge of edges) {\n this.graph.addEdge(edge.from_id, edge.to_id, {\n id: edge.id,\n type: edge.type,\n source: edge.source,\n ...edge.metadata\n })\n }\n }\n \n private nodeToUri(node: StoredNode): NodeURI {\n if (node.type === 'external' && node.uri) {\n return node.uri\n }\n return `native://${node.id}`\n }\n}\n```\n\n### Traversal Implementation\n\n```typescript\nclass FederatedGraphImpl implements FederatedGraph {\n constructor(\n private adapter: GraphologyAdapter,\n private storage: Storage,\n private registry: ProviderRegistry,\n private cache: ProviderCache\n ) {}\n \n async related(uri: NodeURI, edgeType: string, direction: 'in' | 'out' | 'both'): Promise<NodeURI[]> {\n // Ensure node is hydrated\n await this.hydrate(uri)\n \n const results: NodeURI[] = []\n const graph = this.adapter.graph\n \n if (direction === 'in' || direction === 'both') {\n for (const edge of graph.inEdges(uri)) {\n if (graph.getEdgeAttribute(edge, 'type') === edgeType) {\n results.push(graph.source(edge))\n }\n }\n }\n \n if (direction === 'out' || direction === 'both') {\n for (const edge of graph.outEdges(uri)) {\n if (graph.getEdgeAttribute(edge, 'type') === edgeType) {\n results.push(graph.target(edge))\n }\n }\n }\n \n return results\n }\n \n async reachable(uri: NodeURI, edgeType: string, direction: 'in' | 'out'): Promise<NodeURI[]> {\n const results: NodeURI[] = []\n const visited = new Set<NodeURI>()\n \n const traverse = async (current: NodeURI): Promise<void> => {\n if (visited.has(current)) return\n visited.add(current)\n \n await this.hydrate(current)\n \n const neighbors = await this.related(current, edgeType, direction)\n for (const neighbor of neighbors) {\n results.push(neighbor)\n await traverse(neighbor)\n }\n }\n \n await traverse(uri)\n return results\n }\n \n async hydrate(uri: NodeURI): Promise<void> {\n // Check if already in graph and fresh\n if (this.adapter.graph.hasNode(uri)) {\n const cachedAt = this.adapter.graph.getNodeAttribute(uri, 'cached_at')\n if (cachedAt && !this.isStale(cachedAt)) {\n return // Already hydrated and fresh\n }\n }\n \n // Determine provider\n const provider = this.registry.resolveProvider(uri)\n if (!provider) return\n \n // Fetch node data\n const parsed = provider.parseUri(uri)\n if (!parsed) return\n \n const node = await this.cache.getOrFetch(uri, () => provider.get(parsed.id))\n if (!node) return\n \n // Add to graph\n this.adapter.hydrateNode(uri, this.toStoredNode(uri, node))\n \n // If provider supports edges, fetch those too\n if ('queryEdges' in provider) {\n const edges = await (provider as RelationshipQueryable).queryEdges(parsed.id)\n const storedEdges = edges.map(e => this.toStoredEdge(uri, e, provider.name))\n this.adapter.hydrateEdges(uri, storedEdges)\n \n // Persist to SQLite cache\n for (const edge of storedEdges) {\n await this.storage.createCachedEdge(edge)\n }\n }\n }\n}\n```\n\n---\n\n## Data Flow\n\n### Startup\n\n```\n1. Open SQLite database\n2. Create Graphology graph\n3. Load all nodes from SQLite → Graphology\n4. Load all edges from SQLite → Graphology\n5. Ready for queries\n```\n\n### Read Operations\n\n```\nQuery → Check Graphology\n ├─ Node exists & fresh → Return immediately\n └─ Node missing or stale → Hydrate\n ├─ Fetch from Provider\n ├─ Cache to SQLite\n ├─ Update Graphology\n └─ Continue traversal\n```\n\n### Write Operations (Native)\n\n```\nMutation → SQLite (authoritative)\n → Graphology (sync)\n → JSONL export (async)\n```\n\n### Write Operations (External Provider)\n\n```\nUser creates edge: bd-123 blocks s-abc\n → SQLite edges table (source='local', authoritative)\n → Graphology\n \nSystem caches edge from Beads: bd-123 blocks bd-456\n → SQLite edges table (source='beads', cached_at=now)\n → Graphology\n```\n\n---\n\n## Caching Strategy\n\n### Cache Invalidation\n\n```typescript\ninterface CacheConfig {\n defaultTTL: number // Default: 5 minutes\n staleWhileRevalidate: boolean // Return stale, refresh in background\n providerTTL: { // Per-provider overrides\n [provider: string]: number\n }\n}\n\n// Example\nconst cacheConfig: CacheConfig = {\n defaultTTL: 5 * 60 * 1000, // 5 minutes\n staleWhileRevalidate: true,\n providerTTL: {\n beads: 2 * 60 * 1000, // 2 minutes for Beads (fast CLI)\n jira: 10 * 60 * 1000 // 10 minutes for Jira (slow API)\n }\n}\n```\n\n### Staleness Check\n\n```typescript\nfunction isStale(cachedAt: string, provider: string, config: CacheConfig): boolean {\n const ttl = config.providerTTL[provider] ?? config.defaultTTL\n const age = Date.now() - new Date(cachedAt).getTime()\n return age > ttl\n}\n```\n\n---\n\n## Ready Calculation\n\nReady status must consider the **full graph**, including external blockers:\n\n```typescript\nasync ready(options?: ReadyOptions): Promise<NodeURI[]> {\n // 1. Get candidate nodes (native issues that are open)\n const candidates = await this.storage.queryNodes({\n type: 'issue',\n status: 'open',\n archived: false\n })\n \n const readyNodes: NodeURI[] = []\n \n for (const node of candidates) {\n const uri = `native://${node.id}`\n \n // 2. Get all blockers (including external)\n const blockers = await this.related(uri, 'blocks', 'in')\n \n // 3. Check if any blocker is active\n let hasActiveBlocker = false\n for (const blockerUri of blockers) {\n const blocker = await this.resolve(blockerUri)\n if (blocker && !this.isClosed(blocker)) {\n hasActiveBlocker = true\n break\n }\n }\n \n if (!hasActiveBlocker) {\n readyNodes.push(uri)\n }\n }\n \n return readyNodes\n}\n\nprivate isClosed(node: ResolvedNode): boolean {\n const status = node.data.status ?? node.data.external_status\n return status === 'closed' || status === 'done' || status === 'resolved'\n}\n```\n\n---\n\n## Performance Considerations\n\n### At ~1K Nodes\n\n| Operation | Complexity | Expected Time |\n|-----------|------------|---------------|\n| BFS traversal | O(V + E) | < 1ms |\n| Transitive closure | O(V × E) | < 5ms |\n| Graph load from SQLite | O(V + E) | < 50ms |\n| External node hydration | Network-bound | 100-500ms |\n\n**Conclusion:** Graph operations are instant. Network latency to providers dominates.\n\n### Optimizations\n\n1. **Batch hydration** - Fetch multiple nodes in one provider call\n2. **Stale-while-revalidate** - Return cached data, refresh in background\n3. **Lazy edge loading** - Only fetch edges when traversal needs them\n4. **Index on `source`** - Fast lookup of cached edges by provider\n\n---\n\n## Implementation Phases\n\n### Phase 1: Schema & Edge Registry\n- [ ] Add `metadata` and `cached_at` columns to edges table\n- [ ] Create edge type registry with built-in types\n- [ ] Add `source` index to edges table\n\n### Phase 2: Graphology Integration\n- [ ] Add `graphology` dependency\n- [ ] Implement GraphologyAdapter\n- [ ] Load graph from SQLite on startup\n- [ ] Sync mutations to graph\n\n### Phase 3: Federated Graph Core\n- [ ] Implement FederatedGraph interface\n- [ ] Implement `related()` and `reachable()`\n- [ ] Implement `hydrate()` with provider fetch\n- [ ] Implement caching layer\n\n### Phase 4: Provider Extensions\n- [ ] Define RelationshipQueryable trait\n- [ ] Implement in BeadsProvider (using `bd show --json`)\n- [ ] Implement in NativeProvider (using GraphStore edges)\n\n### Phase 5: Ready Query\n- [ ] Implement federated `ready()` query\n- [ ] Consider external blockers in calculation\n- [ ] Update existing ready view for compatibility\n\n### Phase 6: Advanced Traversal\n- [ ] Implement `traverse()` with patterns\n- [ ] Implement `shortestPath()`\n- [ ] Add selector syntax (`+uri`, `uri+`, `@uri`)\n\n---\n\n## Decisions Log\n\n| Decision | Options Considered | Chosen | Rationale |\n|----------|-------------------|--------|-----------|\n| Graph library | Graphology, ngraph, LevelGraph, custom | Graphology | Best algorithm library, TypeScript support, active maintenance |\n| Schema changes | Minimal additions, dedicated cache table, new graph DB | Minimal additions | Current schema is 90% compatible, least disruption |\n| Edge ownership | All edges in OpenTasks, provider-only edges, split | Split (cross-provider = OpenTasks, intra-provider = cached) | Clear ownership, single source of truth |\n| Query interface | Hardcoded methods, GraphQL, generic traversal | Generic traversal | Flexible, extensible, no query language overhead |\n| Cache strategy | TTL-based, manual invalidation, no cache | TTL with stale-while-revalidate | Balance freshness and performance |\n| Ready calculation | SQL view only, full graph traversal | Full graph traversal | Must consider external blockers |\n\n---\n\n## Open Questions\n\n| Question | Status | Notes |\n|----------|--------|-------|\n| Should `traverse()` use async iterators or return arrays? | **Decided: AsyncIterable** | Allows lazy evaluation for large traversals |\n| How to handle cycles in traversal? | **Decided: visited set** | Standard BFS/DFS cycle detection |\n| Should we support GraphQL as query layer? | Deferred | Can add later if needed for external clients |\n| How to handle provider rate limits? | TODO | Need backoff/retry strategy |\n\n---\n\n## Success Criteria\n\n1. ✅ Can traverse from native node to external node and back\n2. ✅ Cross-provider edges stored in OpenTasks (authoritative)\n3. ✅ Intra-provider edges cached and refreshable\n4. ✅ Ready query considers full graph (including external blockers)\n5. ✅ < 100ms for typical traversal (excluding network)\n6. ✅ Edge types are extensible without code changes\n7. ✅ Minimal schema migration (2 columns added)\n\n---\n\n## Dependencies\n\n- [[s-9x15]] Phase 5: Providers - Provider interface and registry\n- [[s-1pai]] Provider Interface Enhancement - Extended provider types\n- `graphology` npm package (MIT license)\n- `graphology-traversal` for BFS/DFS algorithms\n\n## References\n\n- [Graphology documentation](https://graphology.github.io/)\n- [Apollo Federation](https://www.apollographql.com/docs/federation/) - Inspiration for federated queries\n- [dbt selector syntax](https://docs.getdbt.com/reference/node-selection/syntax) - Inspiration for `+node`, `node+`\n","priority":0,"archived":0,"archived_at":null,"created_at":"2026-01-29 05:53:58","updated_at":"2026-01-29 05:53:58","parent_id":null,"parent_uuid":null,"relationships":[{"from":"s-4lv6","from_type":"spec","to":"s-1pai","to_type":"spec","type":"related"},{"from":"s-4lv6","from_type":"spec","to":"s-9x15","to_type":"spec","type":"depends-on"}],"tags":["architecture","federation","graph","graphology","traversal"]}
13
- {"id":"s-1nsc","uuid":"5094c46c-8d14-46d6-a166-305bb1eb37a5","title":"Configuration System","file_path":"specs/s-1nsc_configuration_system.md","content":"# Configuration System\n\n**Priority:** High\n\n## Overview\n\nImplement a configuration system that allows users to customize OpenTasks behavior. Currently there's no way to configure storage paths, provider settings, daemon behavior, or other options.\n\n## Goals\n\n1. Provide sensible defaults that work out of the box\n2. Allow customization via config file\n3. Support environment variable overrides\n4. Validate configuration on load\n\n## Design Decisions (v1 Scope)\n\n### Simplified v1 Approach\n- **Local config only** - `.opentasks/config.json` (no global `~/.opentasks/` for v1)\n- **Hybrid storage only** - No `type` field; always uses JSONL + SQLite\n- **Minimal logging config** - Level and file path only (no rotation)\n- **No CLI commands** - Programmatic API only for v1\n- **No JSON schema** - Defer IDE autocomplete support\n\n### Provider Auto-Detection\n- Providers enabled by default (`enabled: true`)\n- If executable not found, provider silently skips (no error)\n- Explicit `enabled: false` disables provider entirely\n\n## Configuration Hierarchy (v1)\n\nConfiguration is merged in order (later overrides earlier):\n\n1. **Built-in defaults** (in code)\n2. **Local config** (`.opentasks/config.json`)\n3. **Environment variables** (`OPENTASKS_*`)\n\n## Configuration Schema (v1)\n\n```typescript\ninterface OpenTasksConfig {\n storage: {\n /** JSONL file path (relative to .opentasks/) */\n jsonlPath: string // default: 'graph.jsonl'\n \n /** SQLite database path (relative to .opentasks/) */\n sqlitePath: string // default: 'cache.db'\n \n /** Auto-compact JSONL when ratio exceeds threshold */\n autoCompactRatio: number // default: 2.0\n }\n\n daemon: {\n /** Socket path (relative to .opentasks/) */\n socketPath: string // default: 'daemon.sock'\n \n /** Auto-start daemon on first operation */\n autoStart: boolean // default: true\n \n /** Flush interval (ms) */\n flushInterval: number // default: 1000\n }\n\n providers: {\n beads: {\n /** Enable beads provider (auto-detects executable) */\n enabled: boolean // default: true\n \n /** Path to bd executable */\n executable: string // default: 'bd'\n \n /** Command timeout (ms) */\n timeout: number // default: 30000\n }\n \n claudeTasks: {\n /** Enable Claude Tasks provider */\n enabled: boolean // default: true\n }\n }\n\n logging: {\n /** Log level */\n level: 'debug' | 'info' | 'warn' | 'error' // default: 'info'\n \n /** Log file path (relative to .opentasks/, null = no file) */\n file: string | null // default: null\n }\n}\n```\n\n## Environment Variables\n\nAll config keys map to environment variables:\n\n```bash\nOPENTASKS_STORAGE_JSONL_PATH=custom.jsonl\nOPENTASKS_STORAGE_SQLITE_PATH=custom.db\nOPENTASKS_DAEMON_AUTO_START=false\nOPENTASKS_DAEMON_FLUSH_INTERVAL=2000\nOPENTASKS_PROVIDERS_BEADS_ENABLED=false\nOPENTASKS_PROVIDERS_BEADS_EXECUTABLE=/usr/local/bin/bd\nOPENTASKS_LOGGING_LEVEL=debug\nOPENTASKS_LOGGING_FILE=logs/debug.log\n```\n\nMapping rules:\n- Nested keys use underscore: `storage.jsonlPath` → `OPENTASKS_STORAGE_JSONL_PATH`\n- camelCase converts to SCREAMING_SNAKE_CASE\n- Booleans: `true`, `false`, `1`, `0`\n- `null` values: empty string or literal `null`\n\n## Technical Design\n\n### File Structure\n```\nsrc/config/\n├── index.ts # Public exports\n├── schema.ts # Zod schema & types\n├── defaults.ts # Default values\n├── loader.ts # Config file loader\n├── env.ts # Environment variable parser\n├── merge.ts # Config merger\n└── __tests__/\n ├── schema.test.ts\n ├── loader.test.ts\n ├── env.test.ts\n └── merge.test.ts\n```\n\n### Config Loading API\n```typescript\n// src/config/index.ts\n\n/** Load merged configuration for a location */\nexport async function loadConfig(location?: string): Promise<OpenTasksConfig>\n\n/** Get default configuration */\nexport function getDefaults(): OpenTasksConfig\n\n/** Validate a config object */\nexport function validateConfig(config: unknown): ValidationResult\n\n/** Parse environment variables into partial config */\nexport function parseEnvConfig(): Partial<OpenTasksConfig>\n```\n\n### Zod Schema\n```typescript\n// src/config/schema.ts\nimport { z } from 'zod'\n\nexport const StorageConfigSchema = z.object({\n jsonlPath: z.string().default('graph.jsonl'),\n sqlitePath: z.string().default('cache.db'),\n autoCompactRatio: z.number().min(1).default(2.0),\n})\n\nexport const DaemonConfigSchema = z.object({\n socketPath: z.string().default('daemon.sock'),\n autoStart: z.boolean().default(true),\n flushInterval: z.number().min(100).default(1000),\n})\n\nexport const BeadsProviderConfigSchema = z.object({\n enabled: z.boolean().default(true),\n executable: z.string().default('bd'),\n timeout: z.number().min(1000).default(30000),\n})\n\nexport const ClaudeTasksProviderConfigSchema = z.object({\n enabled: z.boolean().default(true),\n})\n\nexport const ProvidersConfigSchema = z.object({\n beads: BeadsProviderConfigSchema.default({}),\n claudeTasks: ClaudeTasksProviderConfigSchema.default({}),\n})\n\nexport const LoggingConfigSchema = z.object({\n level: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n file: z.string().nullable().default(null),\n})\n\nexport const OpenTasksConfigSchema = z.object({\n storage: StorageConfigSchema.default({}),\n daemon: DaemonConfigSchema.default({}),\n providers: ProvidersConfigSchema.default({}),\n logging: LoggingConfigSchema.default({}),\n})\n\nexport type OpenTasksConfig = z.infer<typeof OpenTasksConfigSchema>\n```\n\n### Config File Format\n```json\n{\n \"storage\": {\n \"jsonlPath\": \"graph.jsonl\",\n \"sqlitePath\": \"cache.db\"\n },\n \"daemon\": {\n \"autoStart\": true,\n \"flushInterval\": 1000\n },\n \"providers\": {\n \"beads\": {\n \"enabled\": true\n }\n },\n \"logging\": {\n \"level\": \"info\"\n }\n}\n```\n\n### Integration Points\n\n1. **Daemon startup** - Load config before initializing storage/providers\n2. **Provider registry** - Check `providers.*.enabled` before loading\n3. **Storage creation** - Use `storage.*Path` values\n4. **Future logging** - Use `logging.level` and `logging.file`\n\n## Deliverables (v1)\n\n- [ ] Config schema with Zod validation (`src/config/schema.ts`)\n- [ ] Default configuration values (`src/config/defaults.ts`)\n- [ ] Config file loader (`src/config/loader.ts`)\n- [ ] Environment variable parser (`src/config/env.ts`)\n- [ ] Config merger (`src/config/merge.ts`)\n- [ ] Public API exports (`src/config/index.ts`)\n- [ ] Unit tests for all modules\n- [ ] Integration with daemon startup\n- [ ] Integration with provider registry\n\n## Deferred to v2\n\n- Global config (`~/.opentasks/config.json`)\n- `opentasks config` CLI commands\n- JSON schema for IDE autocomplete\n- Config migration for schema changes\n- Log rotation (`maxSize`, `maxFiles`)\n- Additional daemon options (`idleTimeout`, `maxConnections`)\n\n## Success Criteria\n\n1. Works out of the box with zero configuration\n2. Config file is human-readable and editable\n3. Environment variables override file config\n4. Invalid config produces helpful error messages\n5. Tests can override config programmatically\n\n## Dependencies\n\n- [[s-6w1s]] CLI Implementation (will use config for future commands)\n- [[s-7toh]] Logging System (will consume logging config)","priority":1,"archived":0,"archived_at":null,"created_at":"2026-01-29 18:52:47","updated_at":"2026-02-03 07:46:40","parent_id":null,"parent_uuid":null,"relationships":[],"tags":["config","infrastructure","production"]}
14
- {"id":"s-6w1s","uuid":"4ac3fbea-d196-4da5-8f21-0f15c1bc8ae4","title":"CLI Implementation","file_path":"specs/s-6w1s_cli_implementation.md","content":"# CLI Implementation\n\n**Priority:** Critical (Blocking)\n\n## Overview\n\nImplement a full-featured command-line interface for OpenTasks. Currently, only `help` works. Users cannot interact with the system without a functional CLI.\n\n## Goals\n\n1. Enable users to manage the daemon lifecycle\n2. Provide CRUD operations for specs, issues, and edges\n3. Support querying (ready, blockers, search)\n4. Enable data backup and restore\n5. Provide initialization and configuration commands\n\n## Commands\n\n### Initialization\n```bash\nopentasks init [--force]\n```\n- Creates `.opentasks/` directory structure\n- Initializes empty graph.jsonl and cache.db\n- Creates default config.json\n- Optionally overwrites existing (--force)\n\n### Daemon Management\n```bash\nopentasks daemon start [--foreground]\nopentasks daemon stop\nopentasks daemon status\nopentasks daemon restart\n```\n- `start`: Start daemon (background by default, --foreground for debug)\n- `stop`: Graceful shutdown with flush\n- `status`: Show PID, uptime, connection count, graph stats\n- `restart`: Stop then start\n\n### Node Operations\n```bash\nopentasks create <type> --title <title> [--content <content>] [--status <status>] [--priority <0-4>]\nopentasks get <id>\nopentasks list [type] [--status <status>] [--limit <n>] [--format json|table]\nopentasks update <id> [--title <title>] [--status <status>] [--content <content>]\nopentasks delete <id> [--force]\n```\n- `type`: spec | issue | feedback\n- Default output format: table (human-readable)\n- JSON output for scripting: `--format json`\n\n### Edge Operations\n```bash\nopentasks link <from> <to> --type <edge-type>\nopentasks unlink <from> <to> [--type <edge-type>]\nopentasks edges <id> [--direction in|out|both] [--type <edge-type>]\n```\n- Edge types: blocks, implements, parent-of, related, etc.\n\n### Query Operations\n```bash\nopentasks ready [--type <type>] [--limit <n>]\nopentasks blockers <id>\nopentasks blocked-by <id>\nopentasks search <query> [--type <type>]\nopentasks path <from> <to>\n```\n\n### Data Operations\n```bash\nopentasks export [--output <file>] [--format json|jsonl]\nopentasks import <file> [--merge|--replace]\nopentasks compact\nopentasks stats\n```\n- `export`: Full graph dump\n- `import`: Restore from backup\n- `compact`: Compact JSONL file\n- `stats`: Node/edge counts, storage sizes\n\n### Configuration\n```bash\nopentasks config get [key]\nopentasks config set <key> <value>\nopentasks config list\nopentasks config reset [key]\n```\n\n## Technical Design\n\n### Argument Parsing\nUse a lightweight argument parser. Options:\n- Native `process.argv` parsing (no deps)\n- `commander` (popular, typed)\n- `yargs` (feature-rich)\n\n**Recommendation:** Start with native parsing for simplicity, add library if complexity grows.\n\n### Command Structure\n```typescript\n// src/cli/index.ts\ninterface Command {\n name: string\n description: string\n options: Option[]\n run(args: ParsedArgs): Promise<number> // Exit code\n}\n\n// src/cli/commands/\n// ├── init.ts\n// ├── daemon.ts\n// ├── create.ts\n// ├── get.ts\n// ├── list.ts\n// ├── update.ts\n// ├── delete.ts\n// ├── link.ts\n// ├── query.ts\n// ├── export.ts\n// ├── import.ts\n// ├── config.ts\n// └── index.ts\n```\n\n### Client Integration\nCommands connect to daemon via existing `OpenTasksClient`:\n```typescript\nimport { createClient } from '../client/index.js'\n\nasync function run() {\n const client = createClient()\n await client.connect()\n // ... execute command\n await client.disconnect()\n}\n```\n\n### Output Formatting\n```typescript\ninterface OutputFormatter {\n table(rows: Record<string, unknown>[], columns?: string[]): string\n json(data: unknown): string\n error(message: string, details?: unknown): string\n success(message: string): string\n}\n```\n\n### Error Handling\n- Exit code 0: Success\n- Exit code 1: User error (invalid args, not found)\n- Exit code 2: System error (daemon not running, connection failed)\n- Helpful error messages with suggestions\n\n## Deliverables\n\n- [ ] Argument parser and command router\n- [ ] `init` command\n- [ ] `daemon start/stop/status/restart` commands\n- [ ] `create/get/list/update/delete` commands\n- [ ] `link/unlink/edges` commands\n- [ ] `ready/blockers/blocked-by/search/path` commands\n- [ ] `export/import/compact/stats` commands\n- [ ] `config get/set/list/reset` commands\n- [ ] Output formatters (table, JSON)\n- [ ] Error handling with exit codes\n- [ ] `--help` for each command\n- [ ] Shell completion scripts (bash, zsh)\n\n## Success Criteria\n\n1. All commands work end-to-end with running daemon\n2. Helpful error messages when daemon not running\n3. JSON output works for all commands (scriptable)\n4. Exit codes are consistent and documented\n5. `--help` provides useful guidance for each command\n6. Can complete full workflow: init → daemon start → create → query → export\n\n## Dependencies\n\n- [[s-config]] Configuration System (for `config` commands)\n- [[s-backup]] Backup & Export (for `export/import` commands)\n","priority":0,"archived":0,"archived_at":null,"created_at":"2026-01-29 18:52:47","updated_at":"2026-01-29 18:52:47","parent_id":null,"parent_uuid":null,"relationships":[{"from":"s-6w1s","from_type":"spec","to":"s-1nsc","to_type":"spec","type":"depends-on"},{"from":"s-6w1s","from_type":"spec","to":"s-2oag","to_type":"spec","type":"depends-on"}],"tags":["cli","critical","production","user-facing"]}
15
- {"id":"s-7toh","uuid":"df6ad6b9-e28e-418a-8b11-2563b3f30fe0","title":"Logging System","file_path":"specs/s-7toh_logging_system.md","content":"# Logging System\n\n**Priority:** High\n\n## Overview\n\nImplement structured logging for OpenTasks. Currently there's no logging - users and operators cannot debug issues or understand system behavior.\n\n## Goals\n\n1. Provide structured, parseable logs\n2. Support multiple output targets (file, stderr)\n3. Enable log levels for filtering\n4. Include context (timestamps, component, request IDs)\n5. Support log rotation to prevent disk exhaustion\n\n## Log Levels\n\n| Level | Use Case | Example |\n|-------|----------|---------|\n| `debug` | Detailed debugging info | \"Parsing node i-x7k9\", \"Cache hit for URI\" |\n| `info` | Normal operations | \"Daemon started\", \"Created node i-x7k9\" |\n| `warn` | Recoverable issues | \"Retrying connection\", \"Stale cache entry\" |\n| `error` | Failures | \"Failed to connect to daemon\", \"Invalid node ID\" |\n\n## Log Format\n\n### Structured JSON (file output)\n```json\n{\n \"timestamp\": \"2025-01-29T10:30:00.123Z\",\n \"level\": \"info\",\n \"component\": \"daemon\",\n \"message\": \"Client connected\",\n \"context\": {\n \"clientId\": \"abc123\",\n \"socketPath\": \"/path/to/.opentasks/daemon.sock\"\n }\n}\n```\n\n### Human-readable (stderr output)\n```\n2025-01-29 10:30:00.123 [INFO] daemon: Client connected clientId=abc123\n2025-01-29 10:30:01.456 [DEBUG] graph: Node created id=i-x7k9 type=issue\n2025-01-29 10:30:02.789 [ERROR] provider: Beads command failed code=1 cmd=\"bd show\"\n```\n\n## Technical Design\n\n### Logger Interface\n```typescript\n// src/logging/index.ts\n\ninterface Logger {\n debug(message: string, context?: Record<string, unknown>): void\n info(message: string, context?: Record<string, unknown>): void\n warn(message: string, context?: Record<string, unknown>): void\n error(message: string, context?: Record<string, unknown>): void\n \n /** Create child logger with preset context */\n child(context: Record<string, unknown>): Logger\n \n /** Create child logger for a component */\n forComponent(name: string): Logger\n}\n\n// Usage\nconst logger = createLogger(config.logging)\nconst daemonLogger = logger.forComponent('daemon')\n\ndaemonLogger.info('Client connected', { clientId: 'abc123' })\n// Output: 2025-01-29 10:30:00 [INFO] daemon: Client connected clientId=abc123\n```\n\n### Component Loggers\nEach major component gets its own logger:\n```typescript\n// In daemon\nconst log = logger.forComponent('daemon')\n\n// In graph store\nconst log = logger.forComponent('graph')\n\n// In provider\nconst log = logger.forComponent('provider.beads')\n\n// In CLI\nconst log = logger.forComponent('cli')\n```\n\n### Request Context\nFor tracing requests through the system:\n```typescript\ninterface RequestContext {\n requestId: string\n clientId?: string\n method?: string\n}\n\n// Automatically included in all logs within request scope\nconst reqLogger = logger.child({ requestId: 'req-123', method: 'createNode' })\nreqLogger.info('Processing request')\n// Output includes: requestId=req-123 method=createNode\n```\n\n### Log Rotation\n```typescript\ninterface RotationConfig {\n maxSize: number // Max file size in bytes (default: 10MB)\n maxFiles: number // Number of files to keep (default: 5)\n compress: boolean // Gzip old files (default: true)\n}\n\n// Results in:\n// .opentasks/logs/\n// ├── opentasks.log (current)\n// ├── opentasks.1.log.gz (previous)\n// ├── opentasks.2.log.gz\n// └── ...\n```\n\n### Output Targets\n```typescript\ntype LogTarget = \n | { type: 'file'; path: string; rotation?: RotationConfig }\n | { type: 'stderr' }\n | { type: 'null' } // Disable logging\n\n// Config supports multiple targets\nconst config = {\n logging: {\n level: 'info',\n targets: [\n { type: 'file', path: 'logs/opentasks.log' },\n { type: 'stderr' } // Also log to console\n ]\n }\n}\n```\n\n## Integration Points\n\n### Daemon\n```typescript\n// On startup\nlog.info('Daemon starting', { socketPath, pid: process.pid })\n\n// On client connect\nlog.info('Client connected', { clientId })\n\n// On request\nlog.debug('Handling request', { method, params })\n\n// On error\nlog.error('Request failed', { method, error: err.message })\n\n// On shutdown\nlog.info('Daemon shutting down', { reason: 'SIGTERM' })\n```\n\n### Graph Operations\n```typescript\n// On node create\nlog.debug('Node created', { id, type })\n\n// On validation error\nlog.warn('Validation failed', { nodeId, errors })\n\n// On cycle detected\nlog.warn('Cycle detected', { path })\n```\n\n### Providers\n```typescript\n// On external call\nlog.debug('Calling provider', { provider: 'beads', command: 'show', args })\n\n// On timeout\nlog.warn('Provider timeout', { provider: 'beads', timeout: 30000 })\n\n// On error\nlog.error('Provider failed', { provider: 'beads', error: err.message })\n```\n\n### CLI\n```typescript\n// On command start\nlog.debug('Executing command', { command: 'create', args })\n\n// On success\nlog.info('Command completed', { command: 'create', nodeId: 'i-x7k9' })\n\n// On error\nlog.error('Command failed', { command: 'create', error: err.message })\n```\n\n## Deliverables\n\n- [ ] Logger interface and factory\n- [ ] JSON formatter for file output\n- [ ] Human-readable formatter for stderr\n- [ ] Log rotation implementation\n- [ ] Component logger factory\n- [ ] Request context propagation\n- [ ] Integration with daemon\n- [ ] Integration with graph operations\n- [ ] Integration with providers\n- [ ] Integration with CLI\n- [ ] Log level filtering\n- [ ] Environment variable override (`OPENTASKS_LOG_LEVEL`)\n\n## Success Criteria\n\n1. All major operations produce log entries\n2. Logs are structured and parseable\n3. Log rotation prevents disk exhaustion\n4. Debug level provides enough detail to diagnose issues\n5. Info level shows normal operation without noise\n6. Request IDs allow tracing requests through system\n7. No performance impact when logging disabled\n\n## Dependencies\n\n- [[s-config]] Configuration System (for logging config)\n","priority":1,"archived":0,"archived_at":null,"created_at":"2026-01-29 18:52:47","updated_at":"2026-01-29 18:52:47","parent_id":null,"parent_uuid":null,"relationships":[{"from":"s-7toh","from_type":"spec","to":"s-1nsc","to_type":"spec","type":"depends-on"}],"tags":["infrastructure","logging","observability","production"]}
16
- {"id":"s-2oag","uuid":"fe3f41ec-6dab-4be2-8cfa-8bf57d7149d2","title":"Backup & Data Recovery","file_path":"specs/s-2oag_backup_data_recovery.md","content":"# Backup & Data Recovery\n\n**Priority:** High\n\n## Overview\n\nImplement backup, export, import, and data recovery capabilities. Currently, if data is lost or corrupted, it's unrecoverable. Users need confidence their work is safe.\n\n## Goals\n\n1. Enable full data export for backup\n2. Support import/restore from backup\n3. Provide data integrity verification\n4. Enable recovery from corruption\n5. Support migration between storage formats\n\n## Export Formats\n\n### JSON (default, human-readable)\n```json\n{\n \"version\": \"1.0\",\n \"exportedAt\": \"2025-01-29T10:30:00Z\",\n \"location\": \"/path/to/.opentasks\",\n \"stats\": {\n \"nodes\": 150,\n \"edges\": 87\n },\n \"nodes\": [\n {\n \"id\": \"s-abc1\",\n \"uuid\": \"...\",\n \"type\": \"spec\",\n \"title\": \"My Spec\",\n \"content\": \"...\",\n \"created_at\": \"...\",\n \"updated_at\": \"...\"\n }\n ],\n \"edges\": [\n {\n \"id\": \"e-xyz9\",\n \"from_id\": \"i-def2\",\n \"to_id\": \"s-abc1\",\n \"type\": \"implements\"\n }\n ]\n}\n```\n\n### JSONL (streaming, large datasets)\n```jsonl\n{\"type\":\"meta\",\"version\":\"1.0\",\"exportedAt\":\"2025-01-29T10:30:00Z\"}\n{\"type\":\"node\",\"data\":{\"id\":\"s-abc1\",\"type\":\"spec\",...}}\n{\"type\":\"node\",\"data\":{\"id\":\"i-def2\",\"type\":\"issue\",...}}\n{\"type\":\"edge\",\"data\":{\"id\":\"e-xyz9\",\"from_id\":\"i-def2\",\"to_id\":\"s-abc1\",...}}\n```\n\n## Commands\n\n### Export\n```bash\n# Export to stdout (default: JSON)\nopentasks export\n\n# Export to file\nopentasks export --output backup.json\n\n# Export as JSONL (for large graphs)\nopentasks export --format jsonl --output backup.jsonl\n\n# Export specific types\nopentasks export --types spec,issue\n\n# Export with compression\nopentasks export --output backup.json.gz --compress\n```\n\n### Import\n```bash\n# Import from file (merge mode - add new, skip existing)\nopentasks import backup.json\n\n# Import with replace mode (clear existing, then import)\nopentasks import backup.json --replace\n\n# Import with update mode (update existing, add new)\nopentasks import backup.json --update\n\n# Dry run (show what would happen)\nopentasks import backup.json --dry-run\n\n# Import from stdin\ncat backup.json | opentasks import -\n```\n\n### Verify\n```bash\n# Verify data integrity\nopentasks verify\n\n# Verify with detailed output\nopentasks verify --verbose\n\n# Verify a backup file without importing\nopentasks verify --file backup.json\n```\n\n### Repair\n```bash\n# Attempt automatic repair\nopentasks repair\n\n# Show what would be repaired (dry run)\nopentasks repair --dry-run\n\n# Repair specific issues\nopentasks repair --fix orphan-edges\nopentasks repair --fix dangling-refs\nopentasks repair --fix duplicate-ids\n```\n\n## Technical Design\n\n### Export Service\n```typescript\n// src/backup/export.ts\n\ninterface ExportOptions {\n format: 'json' | 'jsonl'\n types?: NodeType[]\n compress?: boolean\n includeDeleted?: boolean\n}\n\ninterface ExportService {\n /** Export to writable stream */\n export(output: Writable, options?: ExportOptions): Promise<ExportResult>\n \n /** Export to file */\n exportToFile(path: string, options?: ExportOptions): Promise<ExportResult>\n}\n\ninterface ExportResult {\n nodes: number\n edges: number\n bytes: number\n duration: number\n}\n```\n\n### Import Service\n```typescript\n// src/backup/import.ts\n\ntype ImportMode = 'merge' | 'replace' | 'update'\n\ninterface ImportOptions {\n mode: ImportMode\n dryRun?: boolean\n onConflict?: (existing: Node, imported: Node) => 'keep' | 'replace' | 'skip'\n}\n\ninterface ImportService {\n /** Import from readable stream */\n import(input: Readable, options?: ImportOptions): Promise<ImportResult>\n \n /** Import from file */\n importFromFile(path: string, options?: ImportOptions): Promise<ImportResult>\n}\n\ninterface ImportResult {\n created: number\n updated: number\n skipped: number\n errors: ImportError[]\n}\n```\n\n### Verification Service\n```typescript\n// src/backup/verify.ts\n\ninterface VerifyResult {\n valid: boolean\n issues: VerifyIssue[]\n stats: {\n nodes: number\n edges: number\n orphanEdges: number\n danglingRefs: number\n duplicateIds: number\n }\n}\n\ninterface VerifyIssue {\n type: 'orphan-edge' | 'dangling-ref' | 'duplicate-id' | 'invalid-schema' | 'cycle'\n severity: 'error' | 'warning'\n message: string\n details: Record<string, unknown>\n}\n\ninterface VerifyService {\n /** Verify current storage */\n verify(): Promise<VerifyResult>\n \n /** Verify a backup file */\n verifyFile(path: string): Promise<VerifyResult>\n}\n```\n\n### Repair Service\n```typescript\n// src/backup/repair.ts\n\ninterface RepairOptions {\n dryRun?: boolean\n fixes?: RepairFix[]\n}\n\ntype RepairFix = \n | 'orphan-edges' // Remove edges pointing to non-existent nodes\n | 'dangling-refs' // Clear references to deleted nodes\n | 'duplicate-ids' // Regenerate duplicate IDs\n | 'schema-migration' // Update old schema versions\n\ninterface RepairService {\n /** Repair current storage */\n repair(options?: RepairOptions): Promise<RepairResult>\n}\n\ninterface RepairResult {\n fixed: RepairAction[]\n failed: RepairError[]\n}\n```\n\n### Automatic Backups\n```typescript\n// Optional: automatic backup before dangerous operations\n\ninterface AutoBackupConfig {\n enabled: boolean\n beforeOperations: ('import' | 'repair' | 'compact')[]\n maxBackups: number // Keep last N auto-backups\n path: string // Default: .opentasks/backups/\n}\n\n// Creates: .opentasks/backups/auto-2025-01-29T10-30-00.json.gz\n```\n\n## Integrity Checks\n\n### On Export\n- Count all nodes and edges\n- Include checksum in metadata\n- Verify schema compliance\n\n### On Import\n- Validate schema for each entry\n- Check referential integrity\n- Detect duplicate IDs\n- Verify checksum if present\n\n### On Verify\n- Schema validation for all entries\n- Referential integrity (all edge targets exist)\n- No duplicate IDs\n- No orphan edges\n- No cycles in blocking relationships (optional)\n\n## Deliverables\n\n- [ ] Export service (JSON, JSONL formats)\n- [ ] Import service (merge, replace, update modes)\n- [ ] Verify service\n- [ ] Repair service\n- [ ] CLI commands (export, import, verify, repair)\n- [ ] Compression support (gzip)\n- [ ] Streaming support for large datasets\n- [ ] Dry-run mode for import/repair\n- [ ] Auto-backup before dangerous operations\n- [ ] Progress reporting for large operations\n\n## Success Criteria\n\n1. Can export entire graph and re-import to identical state\n2. Import handles conflicts gracefully\n3. Verify detects all common integrity issues\n4. Repair fixes issues without data loss\n5. Large graphs (10k+ nodes) export/import efficiently\n6. Compressed exports reduce storage significantly\n7. Dry-run shows exactly what would happen\n\n## Dependencies\n\n- [[s-cli]] CLI Implementation (for commands)\n- [[s-logging]] Logging System (for operation logging)\n","priority":1,"archived":0,"archived_at":null,"created_at":"2026-01-29 18:52:48","updated_at":"2026-01-29 18:52:48","parent_id":null,"parent_uuid":null,"relationships":[{"from":"s-2oag","from_type":"spec","to":"s-6w1s","to_type":"spec","type":"depends-on"},{"from":"s-2oag","from_type":"spec","to":"s-7toh","to_type":"spec","type":"depends-on"}],"tags":["backup","data-safety","production","recovery"]}
17
- {"id":"s-3mg3","uuid":"2adca8cc-e9dc-4a56-8176-658e1a386c3f","title":"User Documentation","file_path":"specs/s-3mg3_user_documentation.md","content":"# User Documentation\n\n**Priority:** High\n\n## Overview\n\nCreate comprehensive user-facing documentation. Currently the README is empty and while technical docs exist, there's no onboarding path for new users.\n\n## Goals\n\n1. Enable new users to get started in under 5 minutes\n2. Provide reference documentation for all commands\n3. Explain common workflows and use cases\n4. Document configuration options\n5. Provide troubleshooting guidance\n\n## Documentation Structure\n\n```\nREADME.md # Project overview, quick start\ndocs/\n├── getting-started.md # Installation, first steps\n├── cli-reference.md # All CLI commands\n├── configuration.md # Config file reference\n├── workflows.md # Common usage patterns\n├── providers.md # Provider setup (Beads, Claude Tasks)\n├── troubleshooting.md # Common issues and solutions\n├── api-reference.md # Programmatic API\n└── architecture.md # (existing) System internals\n```\n\n## README.md\n\n```markdown\n# OpenTasks\n\nUniversal task graph for AI agents and humans.\n\n## What is OpenTasks?\n\nOpenTasks is a graph-based task management system designed for:\n- **AI agents** coordinating work via specs and issues\n- **Developers** tracking tasks with dependencies\n- **Teams** managing work across multiple projects\n\n## Quick Start\n\n# Install\nnpm install -g opentasks\n\n# Initialize in your project\ncd my-project\nopentasks init\n\n# Start the daemon\nopentasks daemon start\n\n# Create your first spec\nopentasks create spec --title \"My First Feature\"\n\n# Create an implementing issue\nopentasks create issue --title \"Implement feature\" --implements s-xxxx\n\n# See what's ready to work on\nopentasks ready\n\n## Key Features\n\n- **Graph-based**: Specs, issues, and their relationships\n- **Provider integration**: Sync with Beads, Claude Tasks, and more\n- **Dependency tracking**: Know what's blocked and what's ready\n- **Multi-location**: Work across repos and worktrees\n- **Agent-friendly**: 3-tool MCP interface for AI agents\n\n## Documentation\n\n- [Getting Started](docs/getting-started.md)\n- [CLI Reference](docs/cli-reference.md)\n- [Configuration](docs/configuration.md)\n- [Workflows](docs/workflows.md)\n\n## License\n\nMIT\n```\n\n## Getting Started Guide\n\n### Content\n1. **Installation**\n - npm/yarn install\n - Verify installation (`opentasks --version`)\n\n2. **Initialize a Project**\n - Run `opentasks init`\n - Explain created files\n\n3. **First Workflow**\n - Create a spec\n - Create implementing issues\n - Add blocking relationships\n - Query ready items\n - Close issues\n\n4. **Agent Integration**\n - MCP server setup\n - Tool overview (link, query, annotate)\n\n## CLI Reference\n\nDocument every command with:\n- Synopsis\n- Description\n- Options (with defaults)\n- Examples\n- Exit codes\n- Related commands\n\nExample entry:\n```markdown\n## opentasks create\n\nCreate a new node (spec, issue, or feedback).\n\n### Synopsis\nopentasks create <type> --title <title> [options]\n\n### Arguments\n- `type` - Node type: `spec`, `issue`, or `feedback`\n\n### Options\n- `--title, -t <string>` - Node title (required)\n- `--content, -c <string>` - Node content/description\n- `--status, -s <string>` - Initial status (default: \"open\")\n- `--priority, -p <0-4>` - Priority level (default: 2)\n- `--implements <id>` - Link to spec this implements (issues only)\n- `--blocked-by <ids>` - Comma-separated blocker IDs\n- `--format <json|table>` - Output format (default: table)\n\n### Examples\n# Create a spec\nopentasks create spec --title \"User Authentication\"\n\n# Create an issue implementing a spec\nopentasks create issue --title \"Add login form\" --implements s-abc1\n\n# Create a blocked issue\nopentasks create issue --title \"Deploy to prod\" --blocked-by i-def2,i-ghi3\n\n### Exit Codes\n- 0: Success\n- 1: Invalid arguments\n- 2: Daemon not running\n```\n\n## Configuration Guide\n\nDocument all config options with:\n- Key path\n- Type\n- Default value\n- Description\n- Example\n- Environment variable\n\n## Workflows Guide\n\n### Spec-Driven Development\n1. Write spec describing feature\n2. Break into issues\n3. Link issues to spec\n4. Track completion\n\n### Multi-Agent Coordination\n1. Manager creates work items\n2. Agents query ready work\n3. Agents claim and complete\n4. Blockers cascade updates\n\n### External Provider Sync\n1. Enable Beads provider\n2. Reference beads:// URIs\n3. Automatic materialization\n\n## Troubleshooting Guide\n\n### Categories\n- **Installation issues**\n- **Daemon problems**\n- **Provider errors**\n- **Data issues**\n- **Performance**\n\n### Format\n```markdown\n## Daemon won't start\n\n### Symptoms\n- `opentasks daemon start` hangs or fails\n- \"Address already in use\" error\n\n### Causes\n1. Another daemon already running\n2. Stale socket file\n3. Permission issues\n\n### Solutions\n\n**Check for existing daemon:**\nopentasks daemon status\n\n**Remove stale socket:**\nrm .opentasks/daemon.sock\nopentasks daemon start\n\n**Check permissions:**\nls -la .opentasks/\n# Socket should be writable by current user\n```\n\n## Deliverables\n\n- [ ] README.md with quick start\n- [ ] docs/getting-started.md\n- [ ] docs/cli-reference.md (all commands)\n- [ ] docs/configuration.md (all options)\n- [ ] docs/workflows.md (common patterns)\n- [ ] docs/providers.md (Beads, Claude Tasks setup)\n- [ ] docs/troubleshooting.md (common issues)\n- [ ] docs/api-reference.md (programmatic usage)\n- [ ] Man pages for CLI (optional)\n- [ ] `--help` text for all commands (sync with docs)\n\n## Success Criteria\n\n1. New user can install and create first task in < 5 minutes\n2. All CLI commands are documented with examples\n3. All config options are documented\n4. Common issues have documented solutions\n5. Workflows show real-world usage patterns\n6. API docs enable programmatic integration\n7. Docs are searchable and navigable\n\n## Dependencies\n\n- [[s-cli]] CLI Implementation (documents CLI)\n- [[s-config]] Configuration System (documents config)\n","priority":2,"archived":0,"archived_at":null,"created_at":"2026-01-29 18:52:48","updated_at":"2026-01-29 18:52:48","parent_id":null,"parent_uuid":null,"relationships":[{"from":"s-3mg3","from_type":"spec","to":"s-1nsc","to_type":"spec","type":"depends-on"},{"from":"s-3mg3","from_type":"spec","to":"s-6w1s","to_type":"spec","type":"depends-on"}],"tags":["documentation","onboarding","production","user-facing"]}
18
- {"id":"s-70k2","uuid":"2c86187c-c5fd-40b7-a39f-6a08f0ef5bae","title":"E2E Agent Workflow Testing","file_path":"specs/s-70k2_e2e_agent_workflow_testing.md","content":"# E2E Agent Workflow Testing\n\n## Overview\n\nEnd-to-end tests that validate complete agent workflows using the full OpenTasks stack: providers for node creation, 3-tool interface for relationships/queries/feedback, and IPC for communication.\n\n## Goals\n\n1. Validate the core value proposition: spec-driven development with blocking dependencies\n2. Test multi-agent coordination scenarios\n3. Ensure feedback loops work correctly\n4. Provide coverage for provider CRUD operations in realistic workflows\n\n## Architecture\n\n### Test Infrastructure (Phase 5 - Complete)\n\nThe E2E infrastructure is already in place:\n- `tests/e2e/helpers/system-setup.ts` - Full system setup (IPC, storage, graph store)\n- `tests/e2e/helpers/test-agent.ts` - TestAgent wrapper\n- `vitest.e2e.config.ts` - E2E-specific configuration\n\n### Required Enhancements\n\n#### 1. Provider Integration in E2ESystemContext\n\n```typescript\ninterface E2ESystemContext {\n // ... existing fields (rootDir, socketPath, server, store, client)\n \n /** Provider registry for resolving URIs */\n providerRegistry: ProviderRegistry\n \n /** Native provider for creating specs/issues */\n nativeProvider: Provider\n}\n```\n\n#### 2. Extended TestAgent Interface\n\n```typescript\ninterface TestAgent {\n // === Existing 3-tool interface ===\n link(params: LinkParams): Promise<LinkResult>\n query(params: QueryParams): Promise<QueryResult>\n annotate(params: AnnotateParams): Promise<AnnotateResult>\n \n // === Convenience methods (existing) ===\n ready(options?: ReadyOptions): Promise<NodeSummary[]>\n blockers(nodeId: string): Promise<NodeSummary[]>\n blocks(fromId: string, toId: string): Promise<LinkResult>\n implements(issueId: string, specId: string): Promise<LinkResult>\n addFeedback(targetId: string, content: string, type?: FeedbackType): Promise<AnnotateResult>\n \n // === Provider operations (new) ===\n createSpec(title: string, content?: string, options?: CreateOptions): Promise<ProviderNode>\n createIssue(title: string, options?: CreateIssueOptions): Promise<ProviderNode>\n updateNode(id: string, updates: ProviderUpdateInput): Promise<ProviderNode>\n closeIssue(id: string): Promise<ProviderNode>\n getNode(id: string): Promise<ProviderNode | null>\n}\n\ninterface CreateOptions {\n priority?: number\n metadata?: Record<string, unknown>\n}\n\ninterface CreateIssueOptions extends CreateOptions {\n status?: string // default: 'open'\n}\n```\n\n## Test Suites\n\n### Suite 1: Spec-Driven Development (`spec-driven.e2e.test.ts`)\n\nTests the core workflow: create requirements → implement → complete.\n\n#### Test Cases\n\n1. **Complete spec→issue→close cycle**\n - Create spec with requirements\n - Create implementing issue\n - Link issue to spec with 'implements' edge\n - Verify issue appears in ready queue\n - Close issue\n - Verify issue no longer in ready queue\n\n2. **Multiple issues implementing one spec**\n - Create spec\n - Create 3 issues, all implementing the spec\n - Verify all 3 appear in ready queue\n - Close issues one by one\n - Verify ready queue updates correctly\n\n3. **Spec with priority inheritance**\n - Create high-priority spec (priority: 0)\n - Create implementing issue\n - Verify issue inherits or respects priority in queries\n\n4. **Issue without spec (standalone)**\n - Create issue without implements link\n - Verify it appears in ready queue\n - Close and verify removal\n\n### Suite 2: Multi-Agent Coordination (`multi-agent.e2e.test.ts`)\n\nTests blocking dependencies and coordination between agents.\n\n#### Test Cases\n\n1. **Sequential blocking**\n - Agent1 creates foundation issue\n - Agent1 creates dependent issue blocked by foundation\n - Agent2 queries ready → sees only foundation\n - Agent1 closes foundation\n - Agent2 queries ready → now sees dependent\n\n2. **Diamond dependency**\n ```\n A\n / \\\n B C\n \\ /\n D\n ```\n - Create issues A, B, C, D with blocking relationships\n - Verify only A is ready initially\n - Close A → B and C become ready\n - Close B → D still blocked (waiting for C)\n - Close C → D becomes ready\n\n3. **Concurrent issue creation**\n - 3 agents create issues simultaneously\n - Verify all issues have unique IDs\n - Verify all appear in ready queue\n\n4. **Cross-agent blocking**\n - Agent1 creates issue X\n - Agent2 creates issue Y blocked by X\n - Agent1 closes X\n - Agent2 sees Y become ready\n\n5. **Transitive blocking query**\n - Create chain: A blocks B blocks C\n - Query blockers for C with transitive=true\n - Verify both A and B returned\n\n### Suite 3: Feedback Loop (`feedback-loop.e2e.test.ts`)\n\nTests the annotate tool and feedback lifecycle.\n\n#### Test Cases\n\n1. **Add feedback to spec**\n - Create spec\n - Add comment feedback\n - Query feedback on spec\n - Verify feedback content and type\n\n2. **Feedback from implementing issue**\n - Create spec and implementing issue\n - Add feedback to spec with from_id=issue\n - Verify edge created between issue and spec\n\n3. **Resolve and dismiss feedback**\n - Create spec with 3 feedback items\n - Resolve one, dismiss another\n - Query with resolved=false → only unresolved\n - Query with include_dismissed=true → includes dismissed\n\n4. **Feedback types**\n - Add comment, suggestion, request to same spec\n - Query by type filter\n - Verify correct filtering\n\n5. **Anchored feedback**\n - Create spec with multi-line content\n - Add feedback anchored to specific line\n - Verify anchor preserved in query result\n\n## Test Utilities\n\n### Assertion Helpers\n\n```typescript\n// Wait for condition with timeout\nasync function waitForReady(agent: TestAgent, issueId: string, timeout?: number): Promise<void>\n\n// Assert issue is/isn't in ready queue\nasync function expectReady(agent: TestAgent, issueId: string): Promise<void>\nasync function expectNotReady(agent: TestAgent, issueId: string): Promise<void>\n\n// Assert blocking relationship\nasync function expectBlocks(agent: TestAgent, blockerId: string, blockedId: string): Promise<void>\n```\n\n### Fixture Helpers\n\n```typescript\n// Create a spec with standard test content\nasync function createTestSpec(agent: TestAgent, name?: string): Promise<ProviderNode>\n\n// Create an issue with standard test content\nasync function createTestIssue(agent: TestAgent, name?: string): Promise<ProviderNode>\n\n// Create a blocking chain of issues\nasync function createBlockingChain(agent: TestAgent, count: number): Promise<ProviderNode[]>\n```\n\n## Provider Coverage\n\n### Phase 6 Focus: NativeProvider\n- All workflow tests use NativeProvider for node CRUD\n- Tests provider.create, provider.update, provider.get\n\n### Phase 7 (Future): Cross-Provider\n- BeadsProvider integration (requires bd CLI)\n- Cross-provider blocking (native issue blocked by beads task)\n- Provider sync and materialization\n\n## Success Criteria\n\n1. All workflow tests pass with `RUN_FULL_AGENT_TESTS=1`\n2. Tests complete in < 30 seconds total\n3. No flaky tests (run 10x without failure)\n4. Coverage of all 3-tool operations in realistic scenarios\n\n## File Structure\n\n```\ntests/e2e/\n├── helpers/\n│ ├── system-setup.ts # Enhanced with providers\n│ ├── test-agent.ts # Enhanced with provider methods\n│ ├── assertions.ts # New: assertion helpers\n│ ├── fixtures.ts # New: fixture helpers\n│ └── index.ts\n├── infrastructure.e2e.test.ts # Existing (14 tests)\n└── workflows/\n ├── spec-driven.e2e.test.ts\n ├── multi-agent.e2e.test.ts\n └── feedback-loop.e2e.test.ts\n```\n\n## Implementation Order\n\n1. Enhance system-setup.ts with provider registry and native provider\n2. Enhance test-agent.ts with provider operations\n3. Create assertion and fixture helpers\n4. Implement spec-driven.e2e.test.ts\n5. Implement multi-agent.e2e.test.ts\n6. Implement feedback-loop.e2e.test.ts\n7. Update TESTING.md with Phase 6 completion","priority":1,"archived":0,"archived_at":null,"created_at":"2026-01-29 19:34:08","updated_at":"2026-01-29 19:34:08","parent_id":null,"parent_uuid":null,"relationships":[{"from":"s-70k2","from_type":"spec","to":"s-7u8f","to_type":"spec","type":"references"}],"tags":["e2e","phase-6","testing","workflows"]}
19
- {"id":"s-6uv7","uuid":"c0f4a4e9-e50d-4ca4-8d44-fe6f628048b6","title":"Phase 7: Provider Sync E2E Tests","file_path":"specs/s-6uv7_phase_7_provider_sync_e2e_tests.md","content":"# Phase 7: Provider Sync E2E Tests\n\n## Overview\n\nEnd-to-end tests that validate provider synchronization, cross-provider relationships, and the hydration/materialization lifecycle. Tests real BeadsProvider integration (skipped if `bd` CLI unavailable).\n\n## Goals\n\n1. Validate cross-provider blocking dependencies work correctly\n2. Test hydration and caching behavior with real external providers\n3. Verify background sync refreshes stale materialized nodes\n4. Ensure federated ready queries resolve external blockers correctly\n\n## Prerequisites\n\n- `bd` CLI installed and available in PATH\n- Tests skip gracefully if `bd` unavailable (like Phase 4 integration tests)\n\n## Test Suites\n\n### Suite 1: Hydration and Caching (`hydration.e2e.test.ts`)\n\nTests the HydratingFederatedGraph's on-demand loading and cache management.\n\n#### Test Cases\n\n1. **First access hydration**\n - Create external node via BeadsProvider\n - Access via HydratingFederatedGraph\n - Verify node fetched and cached to SQLite\n - Verify `cached_at` timestamp set\n\n2. **Cache reuse when fresh**\n - Hydrate external node\n - Access again within TTL\n - Verify no provider call made (cache hit)\n\n3. **Stale refresh**\n - Hydrate external node\n - Advance time past TTL (or set short TTL)\n - Access again\n - Verify provider called to refresh\n\n4. **Missing node handling**\n - Request non-existent external node\n - Verify null returned, no crash\n - Verify no cache entry created\n\n5. **Concurrent hydration**\n - Multiple clients request same external node simultaneously\n - Verify only one provider call made\n - All clients receive same data\n\n### Suite 2: Cross-Provider Edges (`cross-provider-edges.e2e.test.ts`)\n\nTests edge resolution across NativeProvider and BeadsProvider.\n\n#### Test Cases\n\n1. **Native blocks external**\n - Create native issue\n - Create Beads task\n - Create 'blocks' edge from native → external\n - Verify edge stored with correct `source` field\n - Query blockers for external node → returns native\n\n2. **External blocks native**\n - Create Beads task\n - Create native issue\n - Create 'blocks' edge from external → native\n - Verify edge traversable in both directions\n\n3. **Edge query from provider**\n - Create Beads task with blocks relationships (via bd CLI)\n - Hydrate the task\n - Verify edges fetched via `RelationshipQueryable`\n - Verify IDs converted to URIs correctly\n\n4. **Transitive cross-provider**\n - Create chain: Native A → Beads B → Native C\n - Query reachable from A with transitive=true\n - Verify both B and C returned\n\n5. **Diamond dependency across providers**\n ```\n Native A\n / \\\n Beads B Native C\n \\ /\n Beads D\n ```\n - Verify ready() behavior as nodes close\n\n### Suite 3: Federated Ready Query (`federated-ready.e2e.test.ts`)\n\nTests the ready query with mixed native and external blockers.\n\n#### Test Cases\n\n1. **Ready with no blockers**\n - Create native issue with no blockers\n - Query ready → issue present\n\n2. **Blocked by open external**\n - Create native issue\n - Create open Beads task that blocks it\n - Query ready → native issue NOT present\n\n3. **Unblocked when external closes**\n - Create native issue blocked by Beads task\n - Close the Beads task (status: 'done')\n - Query ready → native issue NOW present\n\n4. **Multiple external blockers**\n - Create native issue blocked by 2 Beads tasks\n - Close one → still blocked\n - Close both → becomes ready\n\n5. **External status field mapping**\n - Test various external statuses: 'done', 'completed', 'resolved', 'cancelled'\n - Verify all treated as \"closed\" for blocking purposes\n\n6. **Provider filter option**\n - Create issues in both providers\n - Query ready with provider filter\n - Verify only matching provider's issues returned\n\n### Suite 4: Materialization Strategies (`materialization.e2e.test.ts`)\n\nTests different materialization behaviors.\n\n#### Test Cases\n\n1. **On-demand strategy**\n - Configure on-demand materialization\n - Access external node via resolve → NOT materialized\n - Explicit materialize call → NOW cached\n\n2. **Lazy strategy**\n - Configure lazy materialization\n - First resolve access → triggers materialization\n - Subsequent access → uses cache\n\n3. **Eager strategy** (if applicable)\n - Configure eager materialization\n - Register provider\n - Verify known nodes materialized immediately\n\n4. **None strategy**\n - Configure none strategy\n - Always fetches fresh, never caches\n\n5. **Per-provider TTL override**\n - Configure different TTL for BeadsProvider\n - Verify BeadsProvider nodes use custom TTL\n - Verify other providers use default TTL\n\n### Suite 5: Background Sync (`background-sync.e2e.test.ts`)\n\nTests periodic refresh of stale materialized nodes.\n\n#### Test Cases\n\n1. **Start/stop sync**\n - Start background sync\n - Verify isRunning() returns true\n - Stop sync\n - Verify isRunning() returns false\n\n2. **Periodic refresh**\n - Materialize external node\n - Start background sync with short interval\n - Wait for refresh cycle\n - Verify `cached_at` updated\n\n3. **Stale detection**\n - Configure short `staleAfter` threshold\n - Materialize node\n - Wait past threshold\n - Verify node detected as stale\n\n4. **Refresh failure handling**\n - Materialize node\n - Make provider return error on refresh\n - Verify node marked stale, not deleted\n - Verify sync continues for other nodes\n\n5. **No overlapping syncs**\n - Start sync with short interval\n - Make refresh slow\n - Verify second sync waits for first to complete\n\n6. **Provider disconnection**\n - Start sync\n - Unregister/disable provider\n - Verify sync handles gracefully (skips, logs, continues)\n\n## Test Infrastructure\n\n### Helpers Needed\n\n```typescript\n// Check bd CLI availability\nasync function isBdAvailable(): Promise<boolean>\n\n// Create a Beads workspace for testing\nasync function createBeadsWorkspace(dir: string): Promise<void>\n\n// Create a Beads task via bd CLI\nasync function createBeadsTask(workspace: string, title: string, options?: {\n status?: string\n blocks?: string[]\n}): Promise<string> // Returns beads:// URI\n\n// Update Beads task status\nasync function updateBeadsStatus(workspace: string, id: string, status: string): Promise<void>\n\n// Get HydratingFederatedGraph with test configuration\nfunction createTestHydratingGraph(options: {\n store: GraphStore\n registry: ProviderRegistry\n cacheTTL?: number\n}): HydratingFederatedGraph\n```\n\n### System Setup Enhancement\n\nExtend `E2ESystemContext` for Phase 7:\n\n```typescript\ninterface E2ESystemContext {\n // ... existing fields\n \n /** Beads workspace directory (if bd available) */\n beadsWorkspace?: string\n \n /** BeadsProvider instance (if bd available) */\n beadsProvider?: BeadsProvider\n \n /** Hydrating federated graph */\n hydratingGraph: HydratingFederatedGraph\n \n /** Materialization manager */\n materializationManager: MaterializationManager\n}\n```\n\n## File Structure\n\n```\ntests/e2e/\n├── helpers/\n│ ├── beads-helpers.ts # NEW: Beads workspace/CLI helpers\n│ └── ...existing\n└── workflows/\n ├── provider-sync/\n │ ├── hydration.e2e.test.ts\n │ ├── cross-provider-edges.e2e.test.ts\n │ ├── federated-ready.e2e.test.ts\n │ ├── materialization.e2e.test.ts\n │ └── background-sync.e2e.test.ts\n └── ...existing\n```\n\n## Success Criteria\n\n1. All tests pass with `RUN_FULL_AGENT_TESTS=1` when `bd` CLI available\n2. Tests skip gracefully with descriptive message when `bd` unavailable\n3. No flaky tests (10x runs without failure)\n4. Test suite completes in < 60 seconds\n\n## Implementation Order\n\n1. Create beads-helpers.ts with CLI wrappers and workspace setup\n2. Enhance system-setup.ts with BeadsProvider and HydratingGraph\n3. Implement hydration.e2e.test.ts (foundation)\n4. Implement cross-provider-edges.e2e.test.ts\n5. Implement federated-ready.e2e.test.ts\n6. Implement materialization.e2e.test.ts\n7. Implement background-sync.e2e.test.ts\n8. Update TESTING.md with Phase 7 completion","priority":1,"archived":0,"archived_at":null,"created_at":"2026-01-29 20:20:06","updated_at":"2026-01-29 20:20:06","parent_id":null,"parent_uuid":null,"relationships":[{"from":"s-6uv7","from_type":"spec","to":"s-70k2","to_type":"spec","type":"references"}],"tags":["beads","e2e","phase-7","provider-sync","testing"]}
20
- {"id":"s-4qzv","uuid":"6ec7e651-60f3-4c00-8e36-aac87bf94085","title":"Trajectory-Based Tool Tracking via Entire Transcripts","file_path":"specs/s-4qzv_trajectory_based_tool_tracking_via_entire_transcri.md","content":"\n# Trajectory-Based Tool Tracking via Entire Transcripts\n\n> Extends: Entire Integration, SkillTracker\n>\n> Tags: entire, tracking, skill-tracker, claude-tasks, trajectory, agent-session-parser\n>\n> Dependencies: [`agent-session-parser`](https://www.npmjs.com/package/agent-session-parser) (npm)\n\n## Problem\n\nOpenTasks has two tracking gaps:\n\n### Gap 1: SkillTracker is blind to MCP tools\n\nThe current `SkillTracker` (`src/tracking/skill-tracker.ts`) records opentasks daemon IPC calls inline — it hooks into `tools.link`, `tools.query`, `tools.annotate`, `tools.task` handlers in `src/daemon/methods/tools.ts`. But:\n\n- The **sudocode MCP tools** Claude actually calls (`upsert_issue`, `show_spec`, `list_issues`, etc.) go directly to the sudocode MCP server. They never touch the opentasks daemon.\n- The SkillTracker only fires when `_sessionId` is explicitly passed in the IPC request params.\n- Result: the SkillTracker misses all MCP tool usage, which is the primary way agents interact with specs/issues.\n\n### Gap 2: Claude's ephemeral tools are untracked\n\nClaude Code's native tools — `TaskCreate`, `TaskUpdate`, `TaskList`, `EnterPlanMode`, `ExitPlanMode` — are ephemeral, in-session constructs. They:\n\n- Don't persist across conversations\n- Don't emit events to external systems\n- Don't go through any opentasks chokepoint\n- Contain valuable planning/coordination data (task subjects, statuses, dependencies, plan file paths)\n\n### Why Entire transcripts solve both\n\nEntire captures the **complete session transcript** as JSONL — every `tool_use` and `tool_result` block, regardless of which system handled it. This is the single source of truth for what tools an agent actually used during a session.\n\n## Solution: Transcript-Driven Tool Extraction\n\nSupplement the current inline SkillTracker with a **post-hoc transcript parser** that runs when an Entire session ends. Uses the [`agent-session-parser`](https://www.npmjs.com/package/agent-session-parser) package for transcript parsing — a TypeScript port of the Entire CLI's agent-specific parsers.\n\n### Why agent-session-parser\n\nThe Entire CLI stores transcripts in agent-specific formats:\n\n| Agent | Format | Inner structure |\n|---|---|---|\n| Claude Code | JSONL (one JSON per line) | Anthropic API message format with `tool_use` content blocks |\n| Gemini CLI | Single JSON object | `messages` array with `toolCalls` arrays |\n| Cursor | SQLite (planned) | — |\n| Aider | Markdown (planned) | — |\n\nThe filename is always `full.jsonl` but the content varies. The `metadata.json` alongside it has an `agent` field for dispatch. The Entire CLI's Go parsing logic is not exportable (Go-only, no `--json` flag on `entire explain`), so `agent-session-parser` ports the type definitions and parsing logic to TypeScript.\n\n**What the package provides (we don't need to build):**\n- `claude.parseFromString(content)` → `TranscriptLine[]`\n- `claude.ContentBlock` type with `type`, `name`, `input`, `tool_use_id`\n- `detectAgentTypeFromContent()` → agent dispatch\n- `claude.extractSpawnedAgentIds()` → subagent tracking\n- `claude.calculateTotalTokenUsage()` → token accounting\n- `claude.filterAfterUUID()` / `truncateAtUUID()` → checkpoint-scoped parsing\n- Streaming dedup (handles multiple JSONL rows per API message via `message.id`)\n- Chunking/reassembly for >50MB transcripts\n- Gemini CLI support out of the box\n\n**What we build on top (our value-add):**\n- Tool call categorization by system (claude-native vs mcp-sudocode vs opentasks-ipc)\n- Claude task state reconstruction from `TaskCreate`/`TaskUpdate` sequences\n- Plan mode transition tracking\n- SkillTracker backfill\n- Graph materialization (session metadata enrichment, optional external nodes)\n\n### Architecture\n\n```\nEntire session ends\n → EntireWatcher emits 'ended' event\n → TranscriptExtractor runs BEFORE EntireAutoLinker finalizes\n → Fetches transcript via git:\n git show entire/checkpoints/v1:<shard>/<id>/1/full.jsonl\n git show entire/checkpoints/v1:<shard>/<id>/1/metadata.json\n → Reads metadata.json to get agent type\n → Dispatches to agent-session-parser:\n claude.parseFromString() or gemini.parseTranscript()\n → Extracts tool_use blocks, categorizes by system\n → Feeds into:\n 1. SkillTracker records (backfill MCP + claude-native tool usage)\n 2. Claude task state reconstruction\n 3. Plan mode transition log\n → EntireAutoLinker then finalizes:\n - registry.remove(sessionId) captures complete summary\n - Attaches to session ExternalNode metadata\n```\n\n### Ordering constraint\n\nThe TranscriptExtractor **must** run before the EntireAutoLinker's `ended` handler, because the linker calls `skillTrackerRegistry.remove(sessionId)` which finalizes the summary. Backfilled records must be in the tracker before that call.\n\n```typescript\n// In lifecycle.ts or location-state.ts:\nentireWatcher.onSessionEvent(async (event) => {\n // Step 1: Backfill from transcript (BEFORE linker finalizes)\n if (event.type === 'ended' && transcriptExtractor) {\n await transcriptExtractor.extract(event);\n }\n\n // Step 2: Linker finalizes (calls registry.remove())\n await entireLinker.handleSessionEvent(event);\n});\n```\n\n### Component: TranscriptExtractor\n\n```typescript\nimport { claude, gemini, detectAgentTypeFromContent } from 'agent-session-parser';\nimport type { claude as claudeTypes } from 'agent-session-parser';\n\ninterface TranscriptExtractorConfig {\n store: GraphStore;\n flushManager: DaemonFlushManager;\n skillTrackerRegistry?: SkillTrackerRegistry;\n}\n\ninterface ExtractedToolCall {\n /** Tool name as it appears in the transcript */\n toolName: string;\n\n /** tool_use block ID */\n toolUseId: string;\n\n /** Normalized category */\n category: 'claude-native' | 'mcp-sudocode' | 'mcp-other' | 'unknown';\n\n /** Input parameters */\n input: Record<string, unknown>;\n\n /** Output/result content (from matching tool_result) */\n output?: string;\n\n /** Whether the call succeeded (from tool_result.is_error) */\n success: boolean;\n\n /** Position in transcript (line index) */\n lineIndex: number;\n}\n\ninterface TranscriptExtractionResult {\n sessionId: string;\n agentType: string;\n\n /** All extracted tool calls, chronological */\n toolCalls: ExtractedToolCall[];\n\n /** Claude native task state reconstructed from tool calls */\n claudeTasks?: ReconstructedClaudeTaskState;\n\n /** Plan mode transitions */\n planModeTransitions: PlanModeTransition[];\n\n /** Token usage (from agent-session-parser) */\n tokenUsage: TokenUsage;\n\n /** Spawned subagent IDs */\n subagentIds: Map<string, string>;\n}\n```\n\n### Tool Categorization\n\nCategorize by `tool_use` block `name` field:\n\n| Pattern | Category | What to extract |\n|---|---|---|\n| `TaskCreate` | claude-native | `input.subject`, `input.description`, `input.activeForm` |\n| `TaskUpdate` | claude-native | `input.taskId`, `input.status`, `input.owner`, `input.addBlockedBy` |\n| `TaskList` | claude-native | (query only) |\n| `TaskGet` | claude-native | `input.taskId` |\n| `EnterPlanMode` | claude-native | transition timestamp |\n| `ExitPlanMode` | claude-native | `input.plan` (plan content) |\n| `mcp__plugin_sudocode_sudocode__*` | mcp-sudocode | spec/issue CRUD, links, feedback |\n| `mcp__*` | mcp-other | tool name, success/failure |\n| Everything else | unknown | tool name only |\n\n### Transcript JSONL Format (Claude Code)\n\nEach line is a JSON object following the Anthropic API message format:\n\n```jsonl\n{\"type\":\"assistant\",\"uuid\":\"...\",\"message\":{\"id\":\"msg_...\",\"content\":[{\"type\":\"tool_use\",\"id\":\"toolu_01...\",\"name\":\"TaskCreate\",\"input\":{\"subject\":\"Fix auth bug\",\"description\":\"...\",\"activeForm\":\"Fixing auth bug\"}}],\"usage\":{...}}}\n{\"type\":\"user\",\"uuid\":\"...\",\"message\":{\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"toolu_01...\",\"content\":\"Task #1 created successfully: Fix auth bug\"}]}}\n```\n\n**Streaming detail**: A single API response may be split across multiple JSONL lines chained by `parentUuid`. The `agent-session-parser` handles deduplication via `message.id`.\n\n**Additional JSONL entry types** (filtered out during parsing):\n- `system` — compaction events, turn duration\n- `progress` — subagent streaming\n- `queue-operation` — task queue events\n- `file-history-snapshot` — file backup snapshots\n\n### Transcript Access\n\nTwo paths to get `full.jsonl`:\n\n1. **Git direct** (preferred, no CLI dependency):\n ```\n git show entire/checkpoints/v1:<id[:2]>/<id[2:]>/1/full.jsonl\n git show entire/checkpoints/v1:<id[:2]>/<id[2:]>/1/metadata.json\n ```\n\n2. **Entire CLI** (fallback):\n ```\n entire explain --raw-transcript --checkpoint <id>\n ```\n\nThe metadata.json contains the `agent` field for dispatch:\n```json\n{\"agent\": \"Claude Code\", \"checkpoint_id\": \"8a513f56ed70\", ...}\n```\n\n### Claude Task State Reconstruction\n\nFrom sequential `TaskCreate`/`TaskUpdate` calls, reconstruct the ephemeral task list state.\n\n**Parsing TaskCreate results**: The `tool_result` content is a plain string like `\"Task #1 created successfully: Fix auth bug\"`. Extract task ID via regex: `/Task #(\\d+) created/`.\n\n**Parsing TaskUpdate results**: The `tool_result` content is `\"Updated task #1 status\"` or similar.\n\n```typescript\ninterface ReconstructedClaudeTaskState {\n /** Tasks that existed during the session */\n tasks: ReconstructedTask[];\n\n /** Final task list snapshot at session end */\n finalSnapshot: ReconstructedTask[];\n}\n\ninterface ReconstructedTask {\n /** Task ID (from TaskCreate response or TaskUpdate params) */\n taskId: string;\n\n /** Subject (from TaskCreate input) */\n subject: string;\n\n /** Description (from TaskCreate input) */\n description?: string;\n\n /** Status transitions in order */\n statusHistory: Array<{ status: string; lineIndex: number }>;\n\n /** Final status */\n finalStatus: 'pending' | 'in_progress' | 'completed';\n\n /** Owner if assigned via TaskUpdate */\n owner?: string;\n\n /** Dependencies from TaskUpdate addBlocks/addBlockedBy */\n blocks?: string[];\n blockedBy?: string[];\n}\n```\n\n### Plan Mode Tracking\n\n```typescript\ninterface PlanModeTransition {\n type: 'enter' | 'exit';\n lineIndex: number;\n\n /** For exit: the plan content from input.plan */\n planContent?: string;\n\n /** For exit: whether user approved (inferred from subsequent tool calls) */\n approved?: boolean;\n}\n```\n\n## Integration Points\n\n### 1. Trigger: Entire session 'ended' event\n\nWire into the existing `entireWatcher.onSessionEvent`, running **before** the linker:\n\n```typescript\n// lifecycle.ts or location-state.ts\nentireWatcher.onSessionEvent(async (event) => {\n if (event.type === 'ended' && transcriptExtractor) {\n await transcriptExtractor.extract(event); // backfill first\n }\n await entireLinker.handleSessionEvent(event); // finalize second\n});\n```\n\n### 2. Transcript retrieval\n\nFor each checkpoint in `session.checkpoints[]`:\n```typescript\nconst metadata = JSON.parse(\n execSync(`git show entire/checkpoints/v1:${shard}/${id}/1/metadata.json`).toString()\n);\nconst transcript = execSync(\n `git show entire/checkpoints/v1:${shard}/${id}/1/full.jsonl`\n).toString();\n```\n\n### 3. Agent dispatch via agent-session-parser\n\n```typescript\nimport { claude, gemini, detectAgentTypeFromContent } from 'agent-session-parser';\n\nconst agentType = metadata.agent; // \"Claude Code\" or \"Gemini CLI\"\n// Or auto-detect: detectAgentTypeFromContent(transcript)\n\nif (agentType === 'Claude Code' || !agentType) {\n const lines = claude.parseFromString(transcript);\n return extractClaudeToolCalls(lines);\n} else if (agentType === 'Gemini CLI') {\n const parsed = gemini.parseTranscript(transcript);\n return extractGeminiToolCalls(parsed);\n}\n```\n\n### 4. SkillTracker backfill\n\nFeed extracted tool calls into the existing registry before it's finalized:\n\n```typescript\nconst tracker = skillTrackerRegistry.getOrCreate(sessionId);\n\nfor (const call of result.toolCalls) {\n tracker.record({\n skill: call.toolName,\n success: call.success,\n operation: categorizeOperation(call),\n targets: extractTargets(call),\n });\n}\n// EntireAutoLinker then calls registry.remove(sessionId) to finalize\n```\n\n### 5. Session metadata enrichment\n\nAttach extraction results to the session's ExternalNode:\n\n```typescript\nawait store.updateNode(sessionNodeId, {\n metadata: {\n toolUsage: result.toolCalls.length,\n toolCategories: countByCategory(result.toolCalls),\n claudeTasks: result.claudeTasks?.finalSnapshot,\n planTransitions: result.planModeTransitions,\n tokenUsage: result.tokenUsage,\n subagentIds: Object.fromEntries(result.subagentIds),\n },\n});\n```\n\n### 6. Optional: Claude task graph nodes\n\nMaterialize reconstructed Claude tasks as opentasks external nodes:\n\n```\nclaude://session-id/task-1 (ExternalNode, type: 'external', source: 'claude-tasks')\n --worked-on→ entire://session/...\n --implements→ i-xxxx (if correlatable)\n```\n\nThis is optional for v1 — session metadata enrichment (point 5) may be sufficient.\n\n## Migration: SkillTracker Inline vs Transcript\n\n### Option A: Keep both (recommended)\n- Inline tracker: real-time, available during session, but only sees daemon IPC\n- Transcript tracker: post-hoc, complete coverage, runs on session end\n- Merge on session end: transcript results supplement inline records before `registry.remove()`\n\n### Option B: Transcript-only\n- Remove inline tracking from `tools.ts` handlers\n- All tracking flows through Entire transcript parsing\n- Simpler code, but no real-time visibility during session\n- Hard dependency on Entire being installed\n\n**Recommendation: Option A.** Keep inline tracking for real-time use. Transcript parsing backfills the gaps (MCP tools, Claude native tools). The `registry.remove()` call captures the merged result.\n\n## File Manifest\n\n| File | Action | Description |\n|---|---|---|\n| `package.json` | Edit | Add `agent-session-parser` dependency |\n| `src/tracking/transcript-extractor.ts` | Create | Orchestrator: fetches transcript, dispatches to parser, categorizes tool calls |\n| `src/tracking/claude-tool-categorizer.ts` | Create | Categorizes Claude tool_use blocks by system, extracts relevant fields |\n| `src/tracking/claude-task-reconstructor.ts` | Create | Replays TaskCreate/TaskUpdate sequence to reconstruct task state |\n| `src/tracking/plan-mode-tracker.ts` | Create | Extracts EnterPlanMode/ExitPlanMode transitions |\n| `src/tracking/__tests__/transcript-extractor.test.ts` | Create | Integration tests with sample JSONL fixtures |\n| `src/tracking/__tests__/claude-tool-categorizer.test.ts` | Create | Categorization tests for all tool families |\n| `src/tracking/__tests__/claude-task-reconstructor.test.ts` | Create | Task state reconstruction tests |\n| `src/tracking/__tests__/plan-mode-tracker.test.ts` | Create | Plan mode transition tests |\n| `src/daemon/lifecycle.ts` | Edit | Wire transcript extractor into session ended event (before linker) |\n| `src/daemon/location-state.ts` | Edit | Create transcript extractor in location init |\n| `src/tracking/index.ts` | Edit | Export new types and functions |\n\n## Resolved Questions\n\n1. **Transcript format**: Confirmed. Claude Code uses JSONL with Anthropic API message format. `tool_use` blocks have `type`, `id`, `name`, `input`. Gemini uses single JSON with `messages` array. The `agent-session-parser` package handles both.\n\n2. **Agent-specific formats**: Confirmed. `full.jsonl` is NOT uniform — it's agent-specific content in a uniform filename. `metadata.json` has the `agent` field for dispatch. `agent-session-parser` provides `detectAgentTypeFromContent()` as fallback.\n\n3. **Checkpoint vs session transcript**: Parse per-checkpoint. Each checkpoint's `full.jsonl` contains the cumulative transcript up to that commit. Use `metadata.json.checkpoint_transcript_start` to scope to checkpoint-specific content if needed.\n\n## Open Questions\n\n1. **Correlation with opentasks issues**: If a Claude `TaskCreate` subject matches an opentasks issue title, should we auto-link them? What confidence threshold?\n2. **Graph materialization**: Should reconstructed Claude tasks become external nodes in the graph, or just live as session metadata? Session metadata is simpler for v1.\n3. **Gemini tool categorization**: Gemini uses different tool names (`write_file`, `edit_file`). Do we need a Gemini-specific categorizer, or is Claude-only sufficient for v1?\n","priority":1,"archived":0,"archived_at":null,"created_at":"2026-02-19 01:02:40","updated_at":"2026-02-19 20:43:47","parent_id":null,"parent_uuid":null,"relationships":[],"tags":["agent-session-parser","claude-tasks","entire","skill-tracker","tracking","trajectory"]}
21
- {"id":"s-2i2s","uuid":"675c839e-b18f-466a-8580-540690295176","title":"Federation & Sync Strengthening","file_path":"specs/s-2i2s_federation_sync_strengthening.md","content":"Strengthen the cross-location federation and sync capabilities of OpenTasks across three areas:\n\n1. **Global Provider Watch** — Project-level daemons get real-time notifications when nodes change in the global `~/.opentasks/` graph. The global provider implements the `Watchable` trait via IPC subscription protocol.\n\n2. **Cross-Location Blocker Resolution** — `ready()` in a project graph correctly considers blockers from the global graph by wiring the `NodeResolver` through to the `QueryEngine` and updating `expandedReady()` to cascade cross-location blockers.\n\n3. **Git Graph Sync** — Automated commit/push/pull of `graph.jsonl` via git for cross-machine replication, with configurable auto-commit (default manual) and a custom merge driver for conflict resolution.\n\nSee plan: `/Users/alexngai/.claude/plans/sharded-snacking-hinton.md`","priority":1,"archived":0,"archived_at":null,"created_at":"2026-02-25 20:54:45","updated_at":"2026-02-25 20:54:45","parent_id":null,"parent_uuid":null,"relationships":[],"tags":["architecture","federation","sync"]}
22
- {"id":"s-9w1q","uuid":"e98fa139-5c30-4f0e-8d45-3849fa66d406","title":"Phase 1: Global Provider Watch","file_path":"specs/s-9w1q_phase_1_global_provider_watch.md","content":"Project-level daemons get real-time notifications when nodes change in the global `~/.opentasks/` graph.\n\n## Requirements\n\n1. Extend `IPCClient` to handle server-push notifications (messages with `id: null`)\n2. Add `watch.subscribe`/`watch.unsubscribe` IPC methods to the daemon\n3. Add `broadcastNotification()` to `IPCServer` to push change events to subscribed clients\n4. Global provider implements `Watchable` trait — converts IPC notifications to `ProviderChangeEvent`\n5. Register global provider in project-level daemons (guarded against self-registration on global daemon)\n\n## Key Files\n- `src/daemon/ipc.ts` — IPCClient notification handler, IPCServer broadcast\n- `src/daemon/methods/watch.ts` — New file for subscription methods\n- `src/providers/global.ts` — Watchable trait implementation\n- `src/daemon/lifecycle.ts` — Registration and wiring\n- `src/config/schema.ts` — `providers.global.enabled` config","priority":1,"archived":0,"archived_at":null,"created_at":"2026-02-25 20:54:53","updated_at":"2026-02-25 20:54:53","parent_id":"s-2i2s","parent_uuid":"675c839e-b18f-466a-8580-540690295176","relationships":[],"tags":["federation","ipc","watch"]}
23
- {"id":"s-9dem","uuid":"2648e07b-43f3-434f-9f35-836014b403b0","title":"Phase 2: Cross-Location Blocker Resolution","file_path":"specs/s-9dem_phase_2_cross_location_blocker_resolution.md","content":"`ready()` in a project graph correctly considers blockers from the global graph (and vice versa).\n\n## Requirements\n\n1. Wire `NodeResolver` through to `QueryEngine` via a late-binding `setNodeResolver()` on `GraphStore`\n2. In daemon lifecycle, create a resolver that delegates to `providerStore.resolveNode()` and set it on the store\n3. Update `expandedReady()` to post-filter locally-ready tasks against cross-location blockers\n4. With Phase 1 watch in place, materialized blocker nodes auto-refresh so cached status stays current\n\n## Key Files\n- `src/graph/store.ts` — Add `setNodeResolver()`\n- `src/graph/query.ts` — Already supports `NodeResolver`, just needs wiring\n- `src/daemon/lifecycle.ts` — Wire resolver after provider registration\n- `src/daemon/location-state.ts` — Same for multi-location mode\n- `src/graph/expansion.ts` — Post-filter in `expandedReady()`","priority":1,"archived":0,"archived_at":null,"created_at":"2026-02-25 20:54:58","updated_at":"2026-02-25 20:54:58","parent_id":"s-2i2s","parent_uuid":"675c839e-b18f-466a-8580-540690295176","relationships":[],"tags":["blockers","federation","query"]}
24
- {"id":"s-d4xu","uuid":"891ab6be-3d35-46f7-9fe5-66276da3207a","title":"Phase 3: Git Graph Sync","file_path":"specs/s-d4xu_phase_3_git_graph_sync.md","content":"Automated commit/push/pull of `graph.jsonl` via git for cross-machine replication.\n\n## Requirements\n\n1. New `GitGraphSyncer` module with commit/push/pull/sync operations\n2. Hook into daemon flush lifecycle — optionally auto-commit after flush\n3. Add `reload()` to `GraphStore` for loading external changes after pull\n4. Wire file watcher to trigger reload on external `graph.jsonl` changes\n5. Config schema extension for `sync.git` settings\n6. Default is manual sync (`autoCommit: false`), configurable to auto\n\n## Key Files\n- `src/graph/git-graph-syncer.ts` — New module\n- `src/core/merge-driver.ts` — Reused as-is (already complete)\n- `src/graph/store.ts` — Add `reload()`\n- `src/daemon/location-state.ts` — Init syncer, hook into flush\n- `src/daemon/lifecycle.ts` — Wire file watcher reload\n- `src/config/schema.ts` — `sync.git` config","priority":2,"archived":0,"archived_at":null,"created_at":"2026-02-25 20:55:02","updated_at":"2026-02-25 20:55:02","parent_id":"s-2i2s","parent_uuid":"675c839e-b18f-466a-8580-540690295176","relationships":[],"tags":["git","replication","sync"]}