opentasks 0.1.3 → 0.2.0

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 (273) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +174 -49
  3. package/dist/cli.d.ts +20 -0
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +451 -15
  6. package/dist/cli.js.map +1 -1
  7. package/dist/client/client.d.ts +54 -0
  8. package/dist/client/client.d.ts.map +1 -1
  9. package/dist/client/client.js +148 -4
  10. package/dist/client/client.js.map +1 -1
  11. package/dist/client/index.d.ts +1 -1
  12. package/dist/client/index.d.ts.map +1 -1
  13. package/dist/client/index.js +1 -1
  14. package/dist/client/index.js.map +1 -1
  15. package/dist/core/discover.d.ts.map +1 -1
  16. package/dist/core/discover.js +7 -2
  17. package/dist/core/discover.js.map +1 -1
  18. package/dist/core/hash.d.ts.map +1 -1
  19. package/dist/core/hash.js +7 -0
  20. package/dist/core/hash.js.map +1 -1
  21. package/dist/core/id.d.ts +1 -1
  22. package/dist/core/id.d.ts.map +1 -1
  23. package/dist/core/id.js +2 -0
  24. package/dist/core/id.js.map +1 -1
  25. package/dist/core/worktree.js +4 -4
  26. package/dist/core/worktree.js.map +1 -1
  27. package/dist/daemon/events.d.ts +82 -0
  28. package/dist/daemon/events.d.ts.map +1 -0
  29. package/dist/daemon/events.js +71 -0
  30. package/dist/daemon/events.js.map +1 -0
  31. package/dist/daemon/flush.d.ts.map +1 -1
  32. package/dist/daemon/flush.js +12 -2
  33. package/dist/daemon/flush.js.map +1 -1
  34. package/dist/daemon/health-counters.d.ts +38 -0
  35. package/dist/daemon/health-counters.d.ts.map +1 -0
  36. package/dist/daemon/health-counters.js +42 -0
  37. package/dist/daemon/health-counters.js.map +1 -0
  38. package/dist/daemon/idempotency.d.ts +50 -0
  39. package/dist/daemon/idempotency.d.ts.map +1 -0
  40. package/dist/daemon/idempotency.js +104 -0
  41. package/dist/daemon/idempotency.js.map +1 -0
  42. package/dist/daemon/ipc.d.ts +32 -2
  43. package/dist/daemon/ipc.d.ts.map +1 -1
  44. package/dist/daemon/ipc.js +54 -3
  45. package/dist/daemon/ipc.js.map +1 -1
  46. package/dist/daemon/lifecycle.d.ts.map +1 -1
  47. package/dist/daemon/lifecycle.js +145 -9
  48. package/dist/daemon/lifecycle.js.map +1 -1
  49. package/dist/daemon/location-state.d.ts +60 -1
  50. package/dist/daemon/location-state.d.ts.map +1 -1
  51. package/dist/daemon/location-state.js +136 -31
  52. package/dist/daemon/location-state.js.map +1 -1
  53. package/dist/daemon/methods/context-files.d.ts.map +1 -1
  54. package/dist/daemon/methods/context-files.js +4 -3
  55. package/dist/daemon/methods/context-files.js.map +1 -1
  56. package/dist/daemon/methods/events.d.ts +22 -0
  57. package/dist/daemon/methods/events.d.ts.map +1 -0
  58. package/dist/daemon/methods/events.js +30 -0
  59. package/dist/daemon/methods/events.js.map +1 -0
  60. package/dist/daemon/methods/graph.d.ts +7 -0
  61. package/dist/daemon/methods/graph.d.ts.map +1 -1
  62. package/dist/daemon/methods/graph.js +24 -14
  63. package/dist/daemon/methods/graph.js.map +1 -1
  64. package/dist/daemon/methods/lifecycle.d.ts +16 -0
  65. package/dist/daemon/methods/lifecycle.d.ts.map +1 -1
  66. package/dist/daemon/methods/lifecycle.js +3 -1
  67. package/dist/daemon/methods/lifecycle.js.map +1 -1
  68. package/dist/daemon/methods/location.js.map +1 -1
  69. package/dist/daemon/methods/sync.d.ts +48 -2
  70. package/dist/daemon/methods/sync.d.ts.map +1 -1
  71. package/dist/daemon/methods/sync.js +106 -3
  72. package/dist/daemon/methods/sync.js.map +1 -1
  73. package/dist/daemon/methods/tools.d.ts.map +1 -1
  74. package/dist/daemon/methods/tools.js +42 -8
  75. package/dist/daemon/methods/tools.js.map +1 -1
  76. package/dist/daemon/methods/watch.d.ts +24 -0
  77. package/dist/daemon/methods/watch.d.ts.map +1 -1
  78. package/dist/daemon/methods/watch.js +178 -88
  79. package/dist/daemon/methods/watch.js.map +1 -1
  80. package/dist/graph/EdgeTypeRegistry.d.ts.map +1 -1
  81. package/dist/graph/EdgeTypeRegistry.js +32 -0
  82. package/dist/graph/EdgeTypeRegistry.js.map +1 -1
  83. package/dist/graph/FederatedGraph.d.ts.map +1 -1
  84. package/dist/graph/GraphologyAdapter.d.ts.map +1 -1
  85. package/dist/graph/GraphologyAdapter.js.map +1 -1
  86. package/dist/graph/HydratingFederatedGraph.d.ts.map +1 -1
  87. package/dist/graph/HydratingFederatedGraph.js +1 -1
  88. package/dist/graph/HydratingFederatedGraph.js.map +1 -1
  89. package/dist/graph/attempts.d.ts +50 -0
  90. package/dist/graph/attempts.d.ts.map +1 -0
  91. package/dist/graph/attempts.js +51 -0
  92. package/dist/graph/attempts.js.map +1 -0
  93. package/dist/graph/coordination.d.ts +4 -2
  94. package/dist/graph/coordination.d.ts.map +1 -1
  95. package/dist/graph/coordination.js +77 -85
  96. package/dist/graph/coordination.js.map +1 -1
  97. package/dist/graph/expansion.d.ts.map +1 -1
  98. package/dist/graph/expansion.js +1 -1
  99. package/dist/graph/expansion.js.map +1 -1
  100. package/dist/graph/git-graph-syncer.d.ts +24 -0
  101. package/dist/graph/git-graph-syncer.d.ts.map +1 -1
  102. package/dist/graph/git-graph-syncer.js +95 -28
  103. package/dist/graph/git-graph-syncer.js.map +1 -1
  104. package/dist/graph/provider-store.d.ts +12 -1
  105. package/dist/graph/provider-store.d.ts.map +1 -1
  106. package/dist/graph/provider-store.js +35 -8
  107. package/dist/graph/provider-store.js.map +1 -1
  108. package/dist/graph/query.d.ts.map +1 -1
  109. package/dist/graph/query.js +18 -2
  110. package/dist/graph/query.js.map +1 -1
  111. package/dist/graph/store.d.ts +18 -2
  112. package/dist/graph/store.d.ts.map +1 -1
  113. package/dist/graph/store.js +43 -0
  114. package/dist/graph/store.js.map +1 -1
  115. package/dist/graph/sync.js +1 -1
  116. package/dist/graph/sync.js.map +1 -1
  117. package/dist/graph/types.d.ts +9 -1
  118. package/dist/graph/types.d.ts.map +1 -1
  119. package/dist/graph/types.js.map +1 -1
  120. package/dist/graph/validation.d.ts.map +1 -1
  121. package/dist/graph/validation.js +20 -2
  122. package/dist/graph/validation.js.map +1 -1
  123. package/dist/index.d.ts +2 -0
  124. package/dist/index.d.ts.map +1 -1
  125. package/dist/index.js +4 -0
  126. package/dist/index.js.map +1 -1
  127. package/dist/materialization/archiver.d.ts.map +1 -1
  128. package/dist/materialization/archiver.js.map +1 -1
  129. package/dist/materialization/snapshot.d.ts.map +1 -1
  130. package/dist/materialization/snapshot.js +1 -1
  131. package/dist/materialization/snapshot.js.map +1 -1
  132. package/dist/materialization/types.d.ts +7 -5
  133. package/dist/materialization/types.d.ts.map +1 -1
  134. package/dist/materialization/types.js.map +1 -1
  135. package/dist/mcp/server.d.ts +2 -1
  136. package/dist/mcp/server.d.ts.map +1 -1
  137. package/dist/mcp/server.js +308 -11
  138. package/dist/mcp/server.js.map +1 -1
  139. package/dist/providers/beads.d.ts.map +1 -1
  140. package/dist/providers/beads.js +2 -0
  141. package/dist/providers/beads.js.map +1 -1
  142. package/dist/providers/claude-tasks.d.ts.map +1 -1
  143. package/dist/providers/claude-tasks.js.map +1 -1
  144. package/dist/providers/global.js +1 -1
  145. package/dist/providers/global.js.map +1 -1
  146. package/dist/providers/location.d.ts.map +1 -1
  147. package/dist/providers/location.js.map +1 -1
  148. package/dist/providers/map-client-factory.d.ts.map +1 -1
  149. package/dist/providers/map-client-factory.js +1 -1
  150. package/dist/providers/map-client-factory.js.map +1 -1
  151. package/dist/providers/map-connector.js +1 -1
  152. package/dist/providers/map-connector.js.map +1 -1
  153. package/dist/providers/map-event-bridge.d.ts.map +1 -1
  154. package/dist/providers/map-event-bridge.js +1 -0
  155. package/dist/providers/map-event-bridge.js.map +1 -1
  156. package/dist/providers/map.d.ts.map +1 -1
  157. package/dist/providers/map.js +5 -2
  158. package/dist/providers/map.js.map +1 -1
  159. package/dist/providers/native.d.ts.map +1 -1
  160. package/dist/providers/native.js +21 -8
  161. package/dist/providers/native.js.map +1 -1
  162. package/dist/providers/registry.js +1 -1
  163. package/dist/providers/registry.js.map +1 -1
  164. package/dist/providers/sudocode.d.ts.map +1 -1
  165. package/dist/providers/sudocode.js +5 -11
  166. package/dist/providers/sudocode.js.map +1 -1
  167. package/dist/providers/traits/Reconcilable.d.ts.map +1 -1
  168. package/dist/providers/traits/TaskManageable.d.ts +15 -1
  169. package/dist/providers/traits/TaskManageable.d.ts.map +1 -1
  170. package/dist/providers/traits/TaskManageable.js +26 -0
  171. package/dist/providers/traits/TaskManageable.js.map +1 -1
  172. package/dist/providers/traits/Watchable.d.ts +6 -0
  173. package/dist/providers/traits/Watchable.d.ts.map +1 -1
  174. package/dist/providers/traits/Watchable.js.map +1 -1
  175. package/dist/providers/types.d.ts +1 -1
  176. package/dist/providers/types.d.ts.map +1 -1
  177. package/dist/schema/edges.d.ts +5 -1
  178. package/dist/schema/edges.d.ts.map +1 -1
  179. package/dist/schema/index.d.ts +2 -2
  180. package/dist/schema/index.d.ts.map +1 -1
  181. package/dist/schema/index.js +1 -1
  182. package/dist/schema/index.js.map +1 -1
  183. package/dist/schema/nodes.d.ts +55 -2
  184. package/dist/schema/nodes.d.ts.map +1 -1
  185. package/dist/schema/storage.d.ts +2 -0
  186. package/dist/schema/storage.d.ts.map +1 -1
  187. package/dist/schema/validation.d.ts +6 -2
  188. package/dist/schema/validation.d.ts.map +1 -1
  189. package/dist/schema/validation.js +18 -1
  190. package/dist/schema/validation.js.map +1 -1
  191. package/dist/sessionlog/agent/registry.js.map +1 -1
  192. package/dist/sessionlog/agent/session-types.d.ts.map +1 -1
  193. package/dist/sessionlog/agent/types.d.ts.map +1 -1
  194. package/dist/sessionlog/commands/clean.js +1 -1
  195. package/dist/sessionlog/commands/clean.js.map +1 -1
  196. package/dist/sessionlog/commands/disable.d.ts.map +1 -1
  197. package/dist/sessionlog/commands/disable.js.map +1 -1
  198. package/dist/sessionlog/commands/doctor.js +1 -1
  199. package/dist/sessionlog/commands/doctor.js.map +1 -1
  200. package/dist/sessionlog/commands/enable.js +1 -1
  201. package/dist/sessionlog/commands/enable.js.map +1 -1
  202. package/dist/sessionlog/commands/resume.js +1 -1
  203. package/dist/sessionlog/commands/resume.js.map +1 -1
  204. package/dist/sessionlog/commands/rewind.d.ts.map +1 -1
  205. package/dist/sessionlog/commands/rewind.js +1 -1
  206. package/dist/sessionlog/commands/rewind.js.map +1 -1
  207. package/dist/sessionlog/commands/status.d.ts.map +1 -1
  208. package/dist/sessionlog/commands/status.js.map +1 -1
  209. package/dist/sessionlog/hooks/lifecycle.d.ts.map +1 -1
  210. package/dist/sessionlog/hooks/lifecycle.js +3 -3
  211. package/dist/sessionlog/hooks/lifecycle.js.map +1 -1
  212. package/dist/sessionlog/security/redaction.js +1 -1
  213. package/dist/sessionlog/security/redaction.js.map +1 -1
  214. package/dist/sessionlog/store/checkpoint-store.d.ts.map +1 -1
  215. package/dist/sessionlog/store/checkpoint-store.js +2 -2
  216. package/dist/sessionlog/store/checkpoint-store.js.map +1 -1
  217. package/dist/sessionlog/store/native-store.d.ts.map +1 -1
  218. package/dist/sessionlog/store/native-store.js.map +1 -1
  219. package/dist/sessionlog/store/session-store.d.ts.map +1 -1
  220. package/dist/sessionlog/store/session-store.js +1 -1
  221. package/dist/sessionlog/store/session-store.js.map +1 -1
  222. package/dist/sessionlog/strategy/attribution.js +2 -2
  223. package/dist/sessionlog/strategy/attribution.js.map +1 -1
  224. package/dist/sessionlog/strategy/common.d.ts +1 -1
  225. package/dist/sessionlog/strategy/common.d.ts.map +1 -1
  226. package/dist/sessionlog/strategy/common.js +3 -3
  227. package/dist/sessionlog/strategy/common.js.map +1 -1
  228. package/dist/sessionlog/strategy/content-overlap.d.ts.map +1 -1
  229. package/dist/sessionlog/strategy/content-overlap.js +1 -1
  230. package/dist/sessionlog/strategy/content-overlap.js.map +1 -1
  231. package/dist/sessionlog/strategy/manual-commit.d.ts.map +1 -1
  232. package/dist/sessionlog/strategy/manual-commit.js +6 -16
  233. package/dist/sessionlog/strategy/manual-commit.js.map +1 -1
  234. package/dist/sessionlog/utils/preview-rewind.d.ts.map +1 -1
  235. package/dist/sessionlog/utils/preview-rewind.js +1 -1
  236. package/dist/sessionlog/utils/preview-rewind.js.map +1 -1
  237. package/dist/sessionlog/utils/trailers.d.ts.map +1 -1
  238. package/dist/sessionlog/utils/trailers.js +0 -1
  239. package/dist/sessionlog/utils/trailers.js.map +1 -1
  240. package/dist/storage/interface.d.ts +64 -0
  241. package/dist/storage/interface.d.ts.map +1 -1
  242. package/dist/storage/interface.js.map +1 -1
  243. package/dist/storage/jsonl.js +2 -2
  244. package/dist/storage/jsonl.js.map +1 -1
  245. package/dist/storage/sqlite-schema.d.ts +8 -2
  246. package/dist/storage/sqlite-schema.d.ts.map +1 -1
  247. package/dist/storage/sqlite-schema.js +10 -1
  248. package/dist/storage/sqlite-schema.js.map +1 -1
  249. package/dist/storage/sqlite.d.ts +16 -1
  250. package/dist/storage/sqlite.d.ts.map +1 -1
  251. package/dist/storage/sqlite.js +134 -2
  252. package/dist/storage/sqlite.js.map +1 -1
  253. package/dist/tools/link.js +1 -1
  254. package/dist/tools/link.js.map +1 -1
  255. package/dist/tools/query.d.ts.map +1 -1
  256. package/dist/tools/query.js +8 -29
  257. package/dist/tools/query.js.map +1 -1
  258. package/dist/tools/task.d.ts.map +1 -1
  259. package/dist/tools/task.js +115 -5
  260. package/dist/tools/task.js.map +1 -1
  261. package/dist/tools/types.d.ts +84 -3
  262. package/dist/tools/types.d.ts.map +1 -1
  263. package/dist/tools/types.js.map +1 -1
  264. package/dist/version.d.ts +14 -0
  265. package/dist/version.d.ts.map +1 -0
  266. package/dist/version.js +44 -0
  267. package/dist/version.js.map +1 -0
  268. package/package.json +32 -7
  269. package/skills/opentasks/SKILL.md +226 -0
  270. package/skills/opentasks/dependency-management.md +119 -0
  271. package/skills/opentasks/feedback-and-review.md +100 -0
  272. package/skills/opentasks/linking-external-data.md +103 -0
  273. package/skills/opentasks/spec-to-implementation.md +171 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alex Ngai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,42 +1,120 @@
1
1
  # OpenTasks
2
2
 
3
- Cross-system graph for tasks and specs. Link Claude Tasks to Beads issues to Jira tickets. Query blockers and ready work across all of them.
3
+ [![CI](https://github.com/alexngai/opentasks/actions/workflows/ci.yml/badge.svg)](https://github.com/alexngai/opentasks/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/opentasks.svg)](https://www.npmjs.com/package/opentasks)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
6
+ [![Node >= 18](https://img.shields.io/node/v/opentasks.svg)](https://nodejs.org)
7
+
8
+ **One dependency graph across every task system you already use.** OpenTasks is a
9
+ local-first graph layer that links Claude Tasks, Beads, and native tasks — with
10
+ Jira, Linear, and other trackers on the roadmap ([docs/STATUS.md](docs/STATUS.md)) —
11
+ so you can ask *what's blocked* and *what's ready* across all of them at once.
4
12
 
5
13
  ```
6
14
  npm install opentasks
7
15
  ```
8
16
 
17
+ ## Why OpenTasks
18
+
19
+ - **It's the relationship layer, not another tracker.** Keep using Beads, Jira, or
20
+ Claude Tasks. OpenTasks adds typed edges (`blocks`, `depends-on`, `implements`,
21
+ `verifies`, …) *between* items that live in different systems — the layer none of
22
+ them have.
23
+ - **Cross-system `ready` / `blocked` in one query.** Surface unblocked work, or the
24
+ chain holding something up, spanning every connected provider at once.
25
+ - **Local-first, no server to run.** A tiny Unix-socket daemon auto-starts on first
26
+ use. `graph.jsonl` is the git-tracked source of truth; SQLite is a rebuildable
27
+ cache. Nothing to host, nothing to sign up for.
28
+ - **Agent-native.** Ships an MCP server (22 tools across 5 scopes) and is built for
29
+ multi-agent work: collision-resistant IDs, task leases/claims, idempotent writes,
30
+ change events, and a git merge driver so concurrent worktrees don't clobber the graph.
31
+ - **Federated and offline-tolerant.** Providers own their content; remote items
32
+ resolve on demand and disappear cleanly when a backend is unreachable — no stale data.
33
+
34
+ ### How it compares
35
+
36
+ | | Task trackers (Beads / Jira / Linear / Claude Tasks) | Orchestration engines | **OpenTasks** |
37
+ |--|:--:|:--:|:--:|
38
+ | Stores task content | yes | sometimes | no — delegates to providers |
39
+ | Typed edges *across* systems | no | no | **yes** |
40
+ | `ready` / `blocked` across systems | no | no | **yes** |
41
+ | Local-first, no server | varies | no | **yes** |
42
+ | Built for agents (MCP, leases, idempotency) | no | varies | **yes** |
43
+
44
+ OpenTasks doesn't replace your tracker — it connects them. See
45
+ [What This Is Not](#what-this-is-not).
46
+
9
47
  ## Quick Start
10
48
 
49
+ OpenTasks runs as a small daemon that the CLI, the MCP server, and the client all
50
+ talk to over a Unix socket. **You don't manage it** — the first command that needs
51
+ it starts one automatically (opt out with `--no-autostart`). If it ever misbehaves,
52
+ see [docs/TROUBLESHOOTING.md](./docs/TROUBLESHOOTING.md).
53
+
54
+ ### CLI
55
+
56
+ ```bash
57
+ npm install -g opentasks # or run any command below via `npx opentasks …`
58
+
59
+ opentasks init # create .opentasks/ in your repo
60
+ opentasks create --type task --title "Wire up auth" --status open
61
+ opentasks create --type task --title "Add OAuth provider" --status open
62
+
63
+ opentasks ready # unblocked tasks, ready to work on
64
+ opentasks list # open tasks (closed hidden)
65
+ opentasks tree t-xxxx # a task and its blocker tree
66
+ ```
67
+
68
+ `ready` / `list` / `blocked` / `tree` are compact, token-light views. Linking
69
+ edges, claiming tasks with a lease, and arbitrary graph queries are each one more
70
+ subcommand — run `opentasks help`.
71
+
72
+ ### MCP (Claude Code / agents)
73
+
74
+ Register the server once; the daemon auto-starts on first use:
75
+
76
+ ```bash
77
+ claude mcp add opentasks -- npx opentasks mcp --scope all
78
+ ```
79
+
80
+ …or in `.mcp.json`:
81
+
82
+ ```json
83
+ {
84
+ "mcpServers": {
85
+ "opentasks": { "command": "npx", "args": ["opentasks", "mcp", "--scope", "all"] }
86
+ }
87
+ }
88
+ ```
89
+
90
+ Scopes are `tasks` (default), `graph`, `annotate`, `context`, `attempts`; `--scope all`
91
+ enables everything. The agent gets `create_task`, `claim_task`, `query`, `events_since`,
92
+ and the rest.
93
+
94
+ ### Programmatic (embedders)
95
+
11
96
  ```typescript
12
- import { link, query, annotate } from 'opentasks'
97
+ import { createClient } from 'opentasks'
13
98
 
14
- // Connect a Beads issue to a Jira ticket
15
- await link({
16
- fromId: 't-x7k9',
17
- toId: 'jira://PROJ-123',
18
- type: 'blocks',
19
- })
99
+ const client = createClient({ autoConnect: true })
20
100
 
21
101
  // What's ready to work on?
22
- const ready = await query({ ready: {} })
102
+ const ready = await client.query({ ready: {} })
23
103
 
24
- // What blocks this task?
25
- const blockers = await query({
26
- blockers: { nodeId: 't-x7k9', transitive: true },
27
- })
104
+ // Connect a task to an external reference
105
+ await client.link({ fromId: 't-x7k9', toId: 'beads://./bd-xyz', type: 'blocks' })
28
106
 
29
- // Leave feedback on a context
30
- await annotate({
31
- targetId: 'c-a2b3',
32
- create: {
33
- content: 'Needs error handling for token refresh',
34
- type: 'suggestion',
35
- anchor: { text: 'OAuth2 with PKCE' },
36
- },
37
- })
107
+ // What blocks this task (full chain)?
108
+ const blockers = await client.query({ blockers: { nodeId: 't-x7k9', transitive: true } })
109
+
110
+ await client.disconnect()
38
111
  ```
39
112
 
113
+ > The top-level `link`/`query`/`annotate` exports are the lower-level forms that
114
+ > take a `GraphStore` as their first argument — see [Programmatic API](#programmatic-api)
115
+ > for daemon-free usage. The `client.*` methods above take params only and route
116
+ > through the daemon.
117
+
40
118
  ## The Problem
41
119
 
42
120
  Claude Tasks, Beads, Jira, Linear, Taskmaster each manage their own content. None of them can express cross-system relationships. You cannot say "this Claude subtask implements that Beads issue" or "this Beads issue is blocked by that Jira ticket."
@@ -78,6 +156,10 @@ You keep using each system's native tools. OpenTasks owns the graph.
78
156
 
79
157
  ## Three Tools
80
158
 
159
+ *Examples below use the bare tool form for brevity. Through a daemon, call them
160
+ as `client.link(...)` / `client.query(...)` / `client.annotate(...)` (params only);
161
+ the top-level `link`/`query`/`annotate` functions take a `GraphStore` first arg.*
162
+
81
163
  ### link()
82
164
 
83
165
  Create or remove edges between any nodes.
@@ -88,7 +170,7 @@ await link({ fromId: 't-setup', toId: 't-impl', type: 'blocks' })
88
170
  await link({ fromId: 't-setup', toId: 't-impl', type: 'blocks', remove: true })
89
171
  ```
90
172
 
91
- Edge types: `blocks` (cycle-checked), `implements`, `references`, `related`, `parent-of`, `depends-on`, `discovered-from`, `duplicates`, `supersedes`. Add custom types as strings.
173
+ Edge types: `blocks` (cycle-checked), `implements`, `references`, `related`, `parent-of`, `child-of`, `depends-on`, `discovered-from`, `duplicates`, `supersedes`, `verifies`, `reproduces`. Add custom types as strings.
92
174
 
93
175
  ### query()
94
176
 
@@ -125,14 +207,17 @@ Types: `comment`, `suggestion`, `request`. Each can be resolved, dismissed, or r
125
207
 
126
208
  ## Nodes
127
209
 
128
- Four types, all stored in `.opentasks/graph.jsonl`:
210
+ Five types, all stored in `.opentasks/graph.jsonl`:
129
211
 
130
212
  | Type | Prefix | Purpose |
131
213
  |------|--------|---------|
132
- | Spec | s- | Requirements, context, user intent |
133
- | Task | i- | Actionable work with status (open / in_progress / blocked / closed) |
214
+ | Context | c- | Requirements, specs, user intent (inline or file-backed) |
215
+ | Task | t- | Actionable work with status (open / in_progress / blocked / closed) |
134
216
  | Feedback | f- | Anchored comments on nodes, with threading |
135
- | ExternalNode | e- | References to Jira, Beads, Linear, GitHub |
217
+ | ExternalNode | e- | References to Beads — and (planned) Jira, Linear, GitHub |
218
+ | Attempt | a- | Records of work attempts, with `verifies` / `reproduces` edges |
219
+
220
+ Edges carry an `x-` prefix.
136
221
 
137
222
  A typical feature graph looks like this:
138
223
 
@@ -140,7 +225,7 @@ A typical feature graph looks like this:
140
225
  graph LR
141
226
  S["c-a2b3<br/>Auth Spec"]
142
227
  I1["t-x7k9<br/>Implement OAuth"]
143
- I2["i-m4n5<br/>Add rate limiting"]
228
+ I2["t-m4n5<br/>Add rate limiting"]
144
229
  F["f-p8q9<br/>suggestion"]
145
230
  EXT["e-jira<br/>PROJ-123"]
146
231
 
@@ -208,41 +293,50 @@ File-backed contexts never duplicate file content into the graph store. They rec
208
293
  Expose the full tool interface via [Model Context Protocol](https://modelcontextprotocol.io):
209
294
 
210
295
  ```bash
211
- opentasks mcp --scope tasks,graph,annotate,context
296
+ opentasks mcp --scope tasks,graph,annotate,context,attempts
297
+ ```
298
+
299
+ Register with Claude Code (the MCP server auto-starts the daemon on first use):
300
+
301
+ ```bash
302
+ claude mcp add opentasks -- npx opentasks mcp --scope all
212
303
  ```
213
304
 
214
- 15 tools across 4 scopes: `tasks` (CRUD + lifecycle), `graph` (edges, queries, context summary), `annotate` (feedback), `context` (context CRUD with file/snippet/inline sources).
305
+ 22 tools across 5 scopes: `tasks` (CRUD + lifecycle + atomic claiming: `claim_task`, `claim_next`, `release_task`, `renew_claim`), `graph` (edges, queries, context summary, `events_since` change polling), `annotate` (feedback), `context` (context CRUD with file/snippet/inline sources), `attempts` (`record_attempt`, `list_attempts` with `verifies` edges).
215
306
 
216
307
  ## Programmatic API
217
308
 
218
- For direct graph manipulation without the daemon:
309
+ For direct graph manipulation without the daemon. `createStoreForLocation` wires
310
+ the SQLite cache and JSONL persister for a `.opentasks/` directory and initializes
311
+ the store:
219
312
 
220
313
  ```typescript
221
- import { createGraphStore, createJSONLPersister } from 'opentasks'
314
+ import { createStoreForLocation } from 'opentasks'
222
315
 
223
- const persister = createJSONLPersister({ path: '.opentasks/graph.jsonl' })
224
- const store = createGraphStore({ storage: persister })
316
+ const store = await createStoreForLocation('.opentasks')
225
317
 
226
- const spec = await store.create({
318
+ const spec = await store.createNode({
227
319
  type: 'context',
228
320
  title: 'OAuth2 authentication',
229
321
  content: 'Users authenticate via OAuth2 with PKCE...',
230
322
  })
231
323
 
232
- const issue = await store.create({
324
+ const task = await store.createNode({
233
325
  type: 'task',
234
326
  title: 'Implement OAuth2 flow',
235
327
  status: 'open',
236
328
  })
237
329
 
238
330
  await store.createEdge({
239
- from_id: issue.id,
331
+ from_id: task.id,
240
332
  to_id: spec.id,
241
333
  type: 'implements',
242
334
  })
243
335
 
244
- const ready = await store.ready()
245
- const blockers = await store.blockers(issue.id)
336
+ const ready = await store.query.ready()
337
+ const blockers = await store.query.blockers(task.id)
338
+
339
+ await store.close() // flush pending changes to graph.jsonl
246
340
  ```
247
341
 
248
342
  ## Client Library
@@ -262,7 +356,7 @@ await client.disconnect()
262
356
 
263
357
  ```
264
358
  .opentasks/
265
- ├── graph.jsonl # Append-only source of truth (git-tracked)
359
+ ├── graph.jsonl # Git-tracked source of truth (rewritten on flush)
266
360
  ├── tombstones.jsonl # Soft deletes with configurable TTL
267
361
  ├── cache.db # SQLite for fast queries (gitignored, rebuilt from JSONL)
268
362
  ├── config.json # Location config, providers, retention
@@ -286,15 +380,25 @@ graph TB
286
380
  style MD fill:#f0f0f0,stroke:#999,stroke-dasharray: 5 5
287
381
  ```
288
382
 
289
- JSONL is the source of truth (git-tracked, append-only). SQLite is the query cache (gitignored, rebuilt on startup). Markdown is optional human-readable expansion.
383
+ JSONL is the source of truth (git-tracked). The daemon writes it as a full-file snapshot on a debounced flush (not literally append-only). SQLite is the query cache (gitignored, rebuilt on startup). Markdown is optional human-readable expansion.
384
+
385
+ ## Configuration
386
+
387
+ Everything lives in `.opentasks/config.json` (created by `opentasks init`); every
388
+ field is optional. Precedence is **defaults < `config.json` < `OPENTASKS_*` env
389
+ vars**. See the full reference — storage, daemon, providers, sync, reconciliation,
390
+ logging, and env-var overrides — in [docs/CONFIGURATION.md](./docs/CONFIGURATION.md).
391
+
392
+ Daemon acting up (socket not found, hangs, stale lock, `NODE_MODULE_VERSION`)?
393
+ See [docs/TROUBLESHOOTING.md](./docs/TROUBLESHOOTING.md).
290
394
 
291
395
  ## Providers
292
396
 
293
- OpenTasks owns the graph. Providers own node content. Three patterns:
397
+ OpenTasks owns the graph. Providers own node content. Four patterns:
294
398
 
295
399
  | Pattern | Use | Example |
296
400
  |---------|-----|---------|
297
- | Provider | Resolve URIs on demand | Jira, Linear, GitHub |
401
+ | Provider | Resolve URIs on demand | Jira, Linear, GitHub *(planned)* |
298
402
  | Adapter | Delegate all CRUD to backend | Beads (`bd` CLI) |
299
403
  | SyncTarget | Two-way sync | Sudocode |
300
404
  | IPC Bridge | Federate across daemons | Global store (`~/.opentasks`) |
@@ -350,19 +454,25 @@ opentasks://../other-repo/c-c4d5 # Relative path
350
454
 
351
455
  ### Global Store
352
456
 
353
- Use opentasks without initializing in a project. The global store at `~/.opentasks/` acts as a fallback when no project-level `.opentasks/` is found.
457
+ A shared store at `~/.opentasks/` you can use from any directory handy for a
458
+ personal todo list that isn't tied to one repo. Commands are project-local by
459
+ default; pass `--global` (or set `OPENTASKS_GLOBAL=1`) to target the global store
460
+ instead.
354
461
 
355
462
  ```bash
356
463
  # One-time setup
357
464
  opentasks init --global
358
465
 
359
- # Now use from any directory (no per-project init needed)
466
+ # Use from anywhere with --global (no per-project init needed)
360
467
  cd /any/directory
361
- opentasks create --type task --title "Read paper on transformers"
362
- opentasks query '{"ready": {}}'
468
+ opentasks create --type task --title "Read paper on transformers" --status open --global
469
+ opentasks ready --global
363
470
  ```
364
471
 
365
- The client discovers daemons in order: project `.opentasks/` > git worktree > global `~/.opentasks/`. Project stores always take precedence.
472
+ `--global` routes both the auto-started daemon and the client at `~/.opentasks/`,
473
+ so a task created from one directory is visible from any other. Without it, a
474
+ command operates on the project store it discovers: project `.opentasks/` > git
475
+ worktree > (fallback) global `~/.opentasks/`.
366
476
 
367
477
  ### Federation
368
478
 
@@ -429,7 +539,7 @@ graph TB
429
539
  style W3 fill:#fff3cd,stroke:#ffc107
430
540
  ```
431
541
 
432
- One daemon serves all worktrees. Workers redirect reads and writes to the manager. Hash-based IDs prevent collisions across concurrent agents. Append-only JSONL plus a custom merge driver handle branch merges.
542
+ One daemon serves all worktrees. Workers redirect reads and writes to the manager. Hash-based IDs prevent collisions across concurrent agents. A custom git merge driver handles branch merges of `graph.jsonl`.
433
543
 
434
544
  ```gitattributes
435
545
  .opentasks/graph.jsonl merge=opentasks
@@ -447,6 +557,8 @@ Hash-based, collision-resistant. Generated from UUID v4 through SHA256 and base3
447
557
 
448
558
  ## Git Sync
449
559
 
560
+ > For the full consistency model — durability tiers, flush↔pull serialization, graceful shutdown, and the multi-machine last-writer-wins caveat — see [docs/SYNC.md](docs/SYNC.md).
561
+
450
562
  OpenTasks can auto-commit and auto-push `graph.jsonl` to a git remote. When enabled in `.opentasks/config.json`:
451
563
 
452
564
  ```json
@@ -535,6 +647,19 @@ OpenTasks is not a replacement for Claude Tasks, Beads, Jira, or any existing to
535
647
 
536
648
  It adds the relationship layer these tools lack.
537
649
 
650
+ ## Documentation
651
+
652
+ | Doc | What's in it |
653
+ |-----|--------------|
654
+ | [CONFIGURATION.md](./docs/CONFIGURATION.md) | Full `config.json` reference + env overrides |
655
+ | [TROUBLESHOOTING.md](./docs/TROUBLESHOOTING.md) | Daemon issues, socket resolution, recovery |
656
+ | [ARCHITECTURE.md](./docs/ARCHITECTURE.md) | System design and layering |
657
+ | [PROVIDERS.md](./docs/PROVIDERS.md) | Provider patterns, MAP, reconciliation |
658
+ | [SYNC.md](./docs/SYNC.md) | Git sync model and consistency |
659
+ | [PERSISTENCE.md](./docs/PERSISTENCE.md) | Storage, JSONL/SQLite, archiving |
660
+ | [SCHEMA.md](./docs/SCHEMA.md) | Node and edge schema |
661
+ | [STATUS.md](./docs/STATUS.md) | As-built implementation status |
662
+
538
663
  ## Development
539
664
 
540
665
  ```bash
package/dist/cli.d.ts CHANGED
@@ -5,14 +5,34 @@
5
5
  * Command-line interface for OpenTasks.
6
6
  * Phase 2 additions: init, connect, disconnect, connections
7
7
  */
8
+ /**
9
+ * Resolve the directory the daemon actually uses for its lock + socket.
10
+ *
11
+ * In a git repo the daemon runs in multi-location mode with its home at
12
+ * `<git-common-dir>/opentasks` (shared across worktrees); otherwise it's the
13
+ * location's own `.opentasks`. This must match `cmdDaemonStart`'s single-vs-multi
14
+ * decision, or the CLI's `checkExistingDaemon` probes look in the wrong place and
15
+ * never detect a running git-repo daemon (auto-start "times out", `daemon status`
16
+ * reports not_running, `daemon stop` no-ops — even though the daemon is up).
17
+ */
18
+ export declare function daemonHomeFor(opentasksDir: string): string;
8
19
  /**
9
20
  * Extract a flag value from args. Returns undefined if not present.
10
21
  */
11
22
  export declare function getFlag(args: string[], flag: string): string | undefined;
12
23
  export declare function hasFlag(args: string[], flag: string): boolean;
24
+ export declare function cmdReady(args: string[]): Promise<void>;
25
+ export declare function cmdList(args: string[]): Promise<void>;
26
+ export declare function cmdBlocked(args: string[]): Promise<void>;
27
+ export declare function cmdCleanup(args: string[]): Promise<void>;
28
+ export declare function cmdTree(args: string[]): Promise<void>;
13
29
  export declare function cmdLink(args: string[]): Promise<void>;
14
30
  export declare function cmdQuery(args: string[]): Promise<void>;
15
31
  export declare function cmdAnnotate(args: string[]): Promise<void>;
32
+ export declare function cmdClaim(args: string[]): Promise<void>;
33
+ export declare function cmdClaimNext(args: string[]): Promise<void>;
34
+ export declare function cmdRelease(args: string[]): Promise<void>;
35
+ export declare function cmdRenew(args: string[]): Promise<void>;
16
36
  export declare function cmdCreate(args: string[]): Promise<void>;
17
37
  export declare function cmdGet(args: string[]): Promise<void>;
18
38
  export declare function cmdUpdate(args: string[]): Promise<void>;
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAsoBH;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGxE;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7D;AAgBD,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB3D;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAe5D;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB/D;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC7D;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAa1D;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC7D;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBrE;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAe7D;AAMD,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgF9D;AAMD,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC7D"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAsiBH;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAG1D;AAiND;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGxE;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7D;AAmED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB5D;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB3D;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB9D;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuC9D;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC3D;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB3D;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAe5D;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB/D;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB5D;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBhE;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB9D;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB5D;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAoC7D;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAa1D;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC7D;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBrE;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAe7D;AAMD,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgF9D;AAMD,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC7D"}