@sudosandwich/limps 0.2.0 → 0.3.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 (216) hide show
  1. package/README.md +281 -33
  2. package/dist/cli/config-cmd.d.ts +68 -0
  3. package/dist/cli/config-cmd.d.ts.map +1 -0
  4. package/dist/cli/config-cmd.js +206 -0
  5. package/dist/cli/config-cmd.js.map +1 -0
  6. package/dist/cli/index.d.ts +11 -0
  7. package/dist/cli/index.d.ts.map +1 -0
  8. package/dist/cli/index.js +12 -0
  9. package/dist/cli/index.js.map +1 -0
  10. package/dist/cli/init-project.d.ts +12 -0
  11. package/dist/cli/init-project.d.ts.map +1 -0
  12. package/dist/cli/init-project.js +104 -0
  13. package/dist/cli/init-project.js.map +1 -0
  14. package/dist/cli/list-agents.d.ts +66 -0
  15. package/dist/cli/list-agents.d.ts.map +1 -0
  16. package/dist/cli/list-agents.js +147 -0
  17. package/dist/cli/list-agents.js.map +1 -0
  18. package/dist/cli/list-plans.d.ts +63 -0
  19. package/dist/cli/list-plans.d.ts.map +1 -0
  20. package/dist/cli/list-plans.js +218 -0
  21. package/dist/cli/list-plans.js.map +1 -0
  22. package/dist/cli/next-task.d.ts +83 -0
  23. package/dist/cli/next-task.d.ts.map +1 -0
  24. package/dist/cli/next-task.js +201 -0
  25. package/dist/cli/next-task.js.map +1 -0
  26. package/dist/cli/registry.d.ts +94 -0
  27. package/dist/cli/registry.d.ts.map +1 -0
  28. package/dist/cli/registry.js +150 -0
  29. package/dist/cli/registry.js.map +1 -0
  30. package/dist/cli/status.d.ts +35 -0
  31. package/dist/cli/status.d.ts.map +1 -0
  32. package/dist/cli/status.js +110 -0
  33. package/dist/cli/status.js.map +1 -0
  34. package/dist/cli.d.ts +3 -0
  35. package/dist/cli.d.ts.map +1 -0
  36. package/dist/cli.js +10 -0
  37. package/dist/cli.js.map +1 -0
  38. package/dist/commands/config/add.d.ts +9 -0
  39. package/dist/commands/config/add.d.ts.map +1 -0
  40. package/dist/commands/config/add.js +20 -0
  41. package/dist/commands/config/add.js.map +1 -0
  42. package/dist/commands/config/discover.d.ts +3 -0
  43. package/dist/commands/config/discover.d.ts.map +1 -0
  44. package/dist/commands/config/discover.js +9 -0
  45. package/dist/commands/config/discover.js.map +1 -0
  46. package/dist/commands/config/index.d.ts +3 -0
  47. package/dist/commands/config/index.d.ts.map +1 -0
  48. package/dist/commands/config/index.js +7 -0
  49. package/dist/commands/config/index.js.map +1 -0
  50. package/dist/commands/config/list.d.ts +3 -0
  51. package/dist/commands/config/list.d.ts.map +1 -0
  52. package/dist/commands/config/list.js +9 -0
  53. package/dist/commands/config/list.js.map +1 -0
  54. package/dist/commands/config/path.d.ts +3 -0
  55. package/dist/commands/config/path.d.ts.map +1 -0
  56. package/dist/commands/config/path.js +10 -0
  57. package/dist/commands/config/path.js.map +1 -0
  58. package/dist/commands/config/remove.d.ts +9 -0
  59. package/dist/commands/config/remove.d.ts.map +1 -0
  60. package/dist/commands/config/remove.js +17 -0
  61. package/dist/commands/config/remove.js.map +1 -0
  62. package/dist/commands/config/set.d.ts +9 -0
  63. package/dist/commands/config/set.d.ts.map +1 -0
  64. package/dist/commands/config/set.js +17 -0
  65. package/dist/commands/config/set.js.map +1 -0
  66. package/dist/commands/config/show.d.ts +3 -0
  67. package/dist/commands/config/show.d.ts.map +1 -0
  68. package/dist/commands/config/show.js +15 -0
  69. package/dist/commands/config/show.js.map +1 -0
  70. package/dist/commands/config/use.d.ts +9 -0
  71. package/dist/commands/config/use.d.ts.map +1 -0
  72. package/dist/commands/config/use.js +17 -0
  73. package/dist/commands/config/use.js.map +1 -0
  74. package/dist/commands/index.d.ts +3 -0
  75. package/dist/commands/index.d.ts.map +1 -0
  76. package/dist/commands/index.js +7 -0
  77. package/dist/commands/index.js.map +1 -0
  78. package/dist/commands/init.d.ts +13 -0
  79. package/dist/commands/init.d.ts.map +1 -0
  80. package/dist/commands/init.js +20 -0
  81. package/dist/commands/init.js.map +1 -0
  82. package/dist/commands/list-agents.d.ts +13 -0
  83. package/dist/commands/list-agents.d.ts.map +1 -0
  84. package/dist/commands/list-agents.js +31 -0
  85. package/dist/commands/list-agents.js.map +1 -0
  86. package/dist/commands/list-plans.d.ts +11 -0
  87. package/dist/commands/list-plans.d.ts.map +1 -0
  88. package/dist/commands/list-plans.js +21 -0
  89. package/dist/commands/list-plans.js.map +1 -0
  90. package/dist/commands/next-task.d.ts +13 -0
  91. package/dist/commands/next-task.d.ts.map +1 -0
  92. package/dist/commands/next-task.js +46 -0
  93. package/dist/commands/next-task.js.map +1 -0
  94. package/dist/commands/serve.d.ts +11 -0
  95. package/dist/commands/serve.d.ts.map +1 -0
  96. package/dist/commands/serve.js +31 -0
  97. package/dist/commands/serve.js.map +1 -0
  98. package/dist/commands/status.d.ts +13 -0
  99. package/dist/commands/status.d.ts.map +1 -0
  100. package/dist/commands/status.js +28 -0
  101. package/dist/commands/status.js.map +1 -0
  102. package/dist/components/AgentsList.d.ts +19 -0
  103. package/dist/components/AgentsList.d.ts.map +1 -0
  104. package/dist/components/AgentsList.js +29 -0
  105. package/dist/components/AgentsList.js.map +1 -0
  106. package/dist/components/Error.d.ts +6 -0
  107. package/dist/components/Error.d.ts.map +1 -0
  108. package/dist/components/Error.js +6 -0
  109. package/dist/components/Error.js.map +1 -0
  110. package/dist/components/NextTask.d.ts +12 -0
  111. package/dist/components/NextTask.d.ts.map +1 -0
  112. package/dist/components/NextTask.js +11 -0
  113. package/dist/components/NextTask.js.map +1 -0
  114. package/dist/components/PlanStatus.d.ts +11 -0
  115. package/dist/components/PlanStatus.d.ts.map +1 -0
  116. package/dist/components/PlanStatus.js +18 -0
  117. package/dist/components/PlanStatus.js.map +1 -0
  118. package/dist/components/PlansList.d.ts +12 -0
  119. package/dist/components/PlansList.d.ts.map +1 -0
  120. package/dist/components/PlansList.js +23 -0
  121. package/dist/components/PlansList.js.map +1 -0
  122. package/dist/components/Success.d.ts +6 -0
  123. package/dist/components/Success.d.ts.map +1 -0
  124. package/dist/components/Success.js +6 -0
  125. package/dist/components/Success.js.map +1 -0
  126. package/dist/index.d.ts +6 -0
  127. package/dist/index.d.ts.map +1 -1
  128. package/dist/index.js +9 -246
  129. package/dist/index.js.map +1 -1
  130. package/dist/server-main.d.ts +11 -0
  131. package/dist/server-main.d.ts.map +1 -0
  132. package/dist/server-main.js +81 -0
  133. package/dist/server-main.js.map +1 -0
  134. package/dist/server.js +1 -1
  135. package/dist/server.js.map +1 -1
  136. package/dist/theme/colors.d.ts +64 -0
  137. package/dist/theme/colors.d.ts.map +1 -0
  138. package/dist/theme/colors.js +85 -0
  139. package/dist/theme/colors.js.map +1 -0
  140. package/dist/theme/index.d.ts +6 -0
  141. package/dist/theme/index.d.ts.map +1 -0
  142. package/dist/theme/index.js +6 -0
  143. package/dist/theme/index.js.map +1 -0
  144. package/dist/tools/claim-task.d.ts +7 -10
  145. package/dist/tools/claim-task.d.ts.map +1 -1
  146. package/dist/tools/create-doc.d.ts +7 -10
  147. package/dist/tools/create-doc.d.ts.map +1 -1
  148. package/dist/tools/create-plan.d.ts +1 -7
  149. package/dist/tools/create-plan.d.ts.map +1 -1
  150. package/dist/tools/delete-doc.d.ts +1 -9
  151. package/dist/tools/delete-doc.d.ts.map +1 -1
  152. package/dist/tools/get-next-task.d.ts +19 -9
  153. package/dist/tools/get-next-task.d.ts.map +1 -1
  154. package/dist/tools/get-next-task.js +64 -1
  155. package/dist/tools/get-next-task.js.map +1 -1
  156. package/dist/tools/get-plan-status.d.ts +24 -0
  157. package/dist/tools/get-plan-status.d.ts.map +1 -0
  158. package/dist/tools/get-plan-status.js +48 -0
  159. package/dist/tools/get-plan-status.js.map +1 -0
  160. package/dist/tools/index.d.ts.map +1 -1
  161. package/dist/tools/index.js +66 -18
  162. package/dist/tools/index.js.map +1 -1
  163. package/dist/tools/list-agents.d.ts +24 -0
  164. package/dist/tools/list-agents.d.ts.map +1 -0
  165. package/dist/tools/list-agents.js +60 -0
  166. package/dist/tools/list-agents.js.map +1 -0
  167. package/dist/tools/list-docs.d.ts +1 -11
  168. package/dist/tools/list-docs.d.ts.map +1 -1
  169. package/dist/tools/list-plans.d.ts +23 -0
  170. package/dist/tools/list-plans.d.ts.map +1 -0
  171. package/dist/tools/list-plans.js +44 -0
  172. package/dist/tools/list-plans.js.map +1 -0
  173. package/dist/tools/open-document-in-cursor.d.ts +1 -9
  174. package/dist/tools/open-document-in-cursor.d.ts.map +1 -1
  175. package/dist/tools/process-doc.d.ts +43 -0
  176. package/dist/tools/process-doc.d.ts.map +1 -0
  177. package/dist/tools/{rlm-query.js → process-doc.js} +7 -8
  178. package/dist/tools/process-doc.js.map +1 -0
  179. package/dist/tools/process-docs.d.ts +54 -0
  180. package/dist/tools/process-docs.d.ts.map +1 -0
  181. package/dist/tools/{rlm-multi-query.js → process-docs.js} +10 -10
  182. package/dist/tools/process-docs.js.map +1 -0
  183. package/dist/tools/release-task.d.ts +5 -10
  184. package/dist/tools/release-task.d.ts.map +1 -1
  185. package/dist/tools/search-docs.d.ts +1 -7
  186. package/dist/tools/search-docs.d.ts.map +1 -1
  187. package/dist/tools/update-doc.d.ts +6 -90
  188. package/dist/tools/update-doc.d.ts.map +1 -1
  189. package/dist/tools/update-task-status.d.ts +7 -12
  190. package/dist/tools/update-task-status.d.ts.map +1 -1
  191. package/dist/utils/config-resolver.d.ts +19 -0
  192. package/dist/utils/config-resolver.d.ts.map +1 -0
  193. package/dist/utils/config-resolver.js +65 -0
  194. package/dist/utils/config-resolver.js.map +1 -0
  195. package/dist/utils/index.d.ts +1 -0
  196. package/dist/utils/index.d.ts.map +1 -1
  197. package/dist/utils/index.js +1 -0
  198. package/dist/utils/index.js.map +1 -1
  199. package/dist/utils/markdown.d.ts +15 -0
  200. package/dist/utils/markdown.d.ts.map +1 -0
  201. package/dist/utils/markdown.js +20 -0
  202. package/dist/utils/markdown.js.map +1 -0
  203. package/dist/utils/os-paths.d.ts +4 -4
  204. package/dist/utils/os-paths.js +5 -5
  205. package/dist/utils/os-paths.js.map +1 -1
  206. package/package.json +22 -11
  207. package/dist/tools/read-doc.d.ts +0 -44
  208. package/dist/tools/read-doc.d.ts.map +0 -1
  209. package/dist/tools/read-doc.js +0 -174
  210. package/dist/tools/read-doc.js.map +0 -1
  211. package/dist/tools/rlm-multi-query.d.ts +0 -110
  212. package/dist/tools/rlm-multi-query.d.ts.map +0 -1
  213. package/dist/tools/rlm-multi-query.js.map +0 -1
  214. package/dist/tools/rlm-query.d.ts +0 -56
  215. package/dist/tools/rlm-query.d.ts.map +0 -1
  216. package/dist/tools/rlm-query.js.map +0 -1
package/README.md CHANGED
@@ -1,28 +1,214 @@
1
- # MCP Planning Server
1
+ # limps
2
2
 
3
- MCP server for managing planning documents, agent coordination, and task tracking.
3
+ **L**ocal **I**ntelligent **M**CP **P**lanning **S**erver - AI agent plan management and coordination.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@sudosandwich/limps)](https://www.npmjs.com/package/@sudosandwich/limps)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ ![Tests](https://img.shields.io/badge/Tests-692%20passing-brightgreen)
8
+ ![Coverage](https://img.shields.io/badge/Coverage-%3E70%25-brightgreen)
9
+
10
+ ![limps in action](.github/assets/limps-in-action.gif)
11
+
12
+ *Claude Desktop accessing the planning MCP, talking to Runi project docs*
13
+
14
+ ## The Problem limps Solves
15
+
16
+ **Context drift between LLM providers** — Each AI assistant (Claude, ChatGPT, Cursor, GitHub Copilot, etc.) maintains its own separate context. Without a shared source of truth, planning documents, task status, and decisions get fragmented across different conversations and sessions.
17
+
18
+ limps solves this by providing a **standardized MCP interface** that any MCP-compatible tool can access. Your planning documents, tasks, and decisions live in one place, accessible to:
19
+
20
+ - **Claude Desktop** — Full access to search, read, update, create documents, claim tasks, and more
21
+ - **Cursor** — Integrated planning and task management via MCP tools
22
+ - **GitHub Copilot** — When MCP support is enabled
23
+ - **Any MCP-compatible tool** — Standard protocol means universal access
24
+
25
+ ### Deployment Options
26
+
27
+ - **Local (Default)** — Run limps locally for secure, private access
28
+ - **Deployed** — You can deploy the MCP server for global access, but **research AUTH** to protect your endpoint and documents
29
+
30
+ ## Used In Production
31
+
32
+ limps is actively used to build [runi](https://github.com/paulbreuler/runi) - managing planning documents, agent coordination, and task tracking across the development lifecycle.
33
+
34
+ ### How runi Uses limps
35
+
36
+ The [runi](https://github.com/paulbreuler/runi) project uses a separate git repository ([runi-planning-docs](https://github.com/paulbreuler/runi-planning-docs)) for version-controlled planning documents. Custom Cursor commands in `.cursor/commands/` integrate with limps tools:
37
+
38
+
39
+
40
+ **Core Commands:**
41
+
42
+ | Command | Description | MCP Tools Used |
43
+ |---------|-------------|----------------|
44
+ | `/create-feature-plan` | Generate TDD plan with docs and agent files | `create_plan`, `create_doc`, `list_docs` |
45
+ | `/list-feature-plans` | List all plans with clickable file paths | `list_docs`, `process_doc` |
46
+ | `/run-agent` | Start work on next agent task | `process_doc`, `claim_task` |
47
+ | `/close-feature-agent` | Verify completion, sync status | `process_doc`, `update_doc`, `release_task` |
48
+ | `/update-feature-plan` | Regenerate agents from updated plan | `process_doc`, `create_doc`, `process_docs` |
49
+ | `/plan-list-agents` | Show all agents with status | `list_docs`, `process_docs` |
50
+
51
+ **Example: `/create-feature-plan` using MCP tools:**
52
+
53
+ ```typescript
54
+ // 1. Find next plan number
55
+ const plans = await list_docs({ path: 'plans/', pattern: '*' });
56
+ const nextNum = Math.max(...plans.map(p => parseInt(p.name))) + 1;
57
+
58
+ // 2. Create plan structure
59
+ await create_plan({ name: `${nextNum}-my-feature`, description: '...' });
60
+
61
+ // 3. Create planning documents
62
+ await create_doc({ path: `plans/${nextNum}-my-feature/plan.md`, content: '...' });
63
+ await create_doc({ path: `plans/${nextNum}-my-feature/interfaces.md`, content: '...' });
64
+ ```
65
+
66
+ **Example: `/run-agent` using process_doc:**
67
+
68
+ ```typescript
69
+ // Extract next GAP feature from plan
70
+ const nextGap = await process_doc({
71
+ path: `plans/${planName}/plan.md`,
72
+ code: `
73
+ const features = extractFeatures(doc.content);
74
+ const gaps = features.filter(f => f.status === 'GAP');
75
+ return gaps.sort((a, b) => a.priority - b.priority)[0];
76
+ `,
77
+ });
78
+ ```
79
+
80
+ **Project Structure:**
81
+
82
+ ```
83
+ runi/ # Main codebase
84
+ ├── .cursor/commands/ # Cursor slash commands
85
+ │ ├── create-feature-plan.md
86
+ │ ├── list-feature-plans.md
87
+ │ ├── run-agent.md
88
+ │ ├── close-feature-agent.md
89
+ │ └── update-feature-plan.md
90
+ └── .claude/commands/ # Claude Code commands
91
+ └── pr.md
92
+
93
+ runi-planning-docs/ # Separate git repo for plans
94
+ ├── plans/
95
+ │ ├── 0004-datagrid/ # Feature plan
96
+ │ │ ├── plan.md # Full specifications
97
+ │ │ ├── interfaces.md # Interface contracts
98
+ │ │ ├── README.md # Status index
99
+ │ │ ├── gotchas.md # Discovered issues
100
+ │ │ └── agents/ # Agent task files
101
+ │ └── ...
102
+ └── decisions/ # Decision log
103
+ ```
4
104
 
5
105
  ## Installation
6
106
 
7
107
  ### Global Install (Recommended)
8
108
 
9
109
  ```bash
10
- npm install -g mcp-planning-server
110
+ npm install -g @sudosandwich/limps
111
+ ```
112
+
113
+ ### Quick Setup
114
+
115
+ ```bash
116
+ limps init my-project --docs-path ~/Documents/my-project
117
+ ```
118
+
119
+ This creates a config and outputs the Cursor/Claude Desktop configuration snippets with full paths.
120
+
121
+ ## CLI Commands
122
+
123
+ limps provides a full CLI for managing projects and viewing plans without needing an MCP client.
124
+
125
+ ```bash
126
+ limps --help # Show all commands
127
+ limps <command> --help # Show command help
11
128
  ```
12
129
 
130
+ ### Project Management
131
+
132
+ | Command | Description |
133
+ |---------|-------------|
134
+ | `limps init <name>` | Initialize a new project |
135
+ | `limps serve` | Start the MCP server |
136
+
137
+ ### Plan Commands
138
+
139
+ | Command | Description |
140
+ |---------|-------------|
141
+ | `limps list-plans` | List all plans with status |
142
+ | `limps list-agents <plan>` | List agents in a plan |
143
+ | `limps next-task <plan>` | Get the highest-priority available task |
144
+ | `limps status <plan>` | Show plan status summary |
145
+
146
+ ### Configuration
147
+
148
+ | Command | Description |
149
+ |---------|-------------|
150
+ | `limps config list` | Show all registered projects |
151
+ | `limps config use <name>` | Switch to a different project |
152
+ | `limps config show` | Display resolved configuration |
153
+ | `limps config path` | Print the config file path |
154
+ | `limps config add <name> <path>` | Register an existing config |
155
+ | `limps config remove <name>` | Unregister a project |
156
+ | `limps config set <path>` | Set current from config path |
157
+ | `limps config discover` | Find configs in default locations |
158
+
159
+ ### Multi-Project Workflow
160
+
161
+ ```bash
162
+ # Register multiple projects
163
+ limps init project-a --docs-path ~/Documents/project-a
164
+ limps init project-b --docs-path ~/Documents/project-b
165
+
166
+ # Switch between projects
167
+ limps config use project-a
168
+ limps list-plans
169
+
170
+ limps config use project-b
171
+ limps list-plans
172
+
173
+ # Use environment variable
174
+ LIMPS_PROJECT=project-a limps list-plans
175
+ ```
176
+
177
+ ### Example: Git-based Document Versioning
178
+
179
+ Point limps at a git repository to version control your planning documents:
180
+
181
+ ```bash
182
+ # Create a dedicated docs repo
183
+ mkdir ~/Documents/GitHub/my-planning-docs
184
+ cd ~/Documents/GitHub/my-planning-docs
185
+ git init
186
+
187
+ # Initialize limps with your docs repo
188
+ limps init my-project --docs-path ~/Documents/GitHub/my-planning-docs
189
+ ```
190
+
191
+ This approach gives you:
192
+ - **Version history** for all plans and decisions
193
+ - **Branching** for experimental planning
194
+ - **Collaboration** via pull requests
195
+ - **Backup** through remote repositories
196
+
197
+ ### Manual Configuration
198
+
13
199
  The server automatically finds configuration at OS-specific locations:
14
200
 
15
201
  | OS | Config Location |
16
202
  |----|-----------------|
17
- | macOS | `~/Library/Application Support/mcp-planning-server/config.json` |
18
- | Linux | `~/.config/mcp-planning-server/config.json` |
19
- | Windows | `%APPDATA%\mcp-planning-server\config.json` |
203
+ | macOS | `~/Library/Application Support/limps/config.json` |
204
+ | Linux | `~/.config/limps/config.json` |
205
+ | Windows | `%APPDATA%\limps\config.json` |
20
206
 
21
207
  ### From Source
22
208
 
23
209
  ```bash
24
- git clone https://github.com/yourusername/mcp-planning-server.git
25
- cd mcp-planning-server
210
+ git clone https://github.com/paulbreuler/limps.git
211
+ cd limps
26
212
  npm install
27
213
  npm run build
28
214
  ```
@@ -36,8 +222,8 @@ Create a `config.json` at the OS-specific location or specify a path:
36
222
  "plansPath": "~/Documents/my-plans",
37
223
  "docsPaths": ["~/Documents/my-plans"],
38
224
  "fileExtensions": [".md"],
39
- "dataPath": "~/Library/Application Support/mcp-planning-server/data",
40
- "coordinationPath": "~/Library/Application Support/mcp-planning-server/coordination.json",
225
+ "dataPath": "~/Library/Application Support/limps/data",
226
+ "coordinationPath": "~/Library/Application Support/limps/coordination.json",
41
227
  "heartbeatTimeout": 300000,
42
228
  "debounceDelay": 200,
43
229
  "maxHandoffIterations": 3
@@ -45,7 +231,7 @@ Create a `config.json` at the OS-specific location or specify a path:
45
231
  ```
46
232
 
47
233
  **Config priority:**
48
- 1. CLI: `mcp-planning-server --config /path/to/config.json`
234
+ 1. CLI: `limps --config /path/to/config.json`
49
235
  2. Environment: `MCP_PLANNING_CONFIG=/path/to/config.json`
50
236
  3. OS-specific default location
51
237
 
@@ -61,8 +247,8 @@ Add to Cursor settings (`Cmd+Shift+P` → "Preferences: Open User Settings (JSON
61
247
  ```json
62
248
  {
63
249
  "mcp.servers": {
64
- "mcp-planning-server": {
65
- "command": "mcp-planning-server"
250
+ "limps": {
251
+ "command": "limps"
66
252
  }
67
253
  }
68
254
  }
@@ -72,47 +258,101 @@ With explicit config:
72
258
  ```json
73
259
  {
74
260
  "mcp.servers": {
75
- "mcp-planning-server": {
76
- "command": "mcp-planning-server",
261
+ "limps": {
262
+ "command": "limps",
77
263
  "args": ["--config", "/path/to/config.json"]
78
264
  }
79
265
  }
80
266
  }
81
267
  ```
82
268
 
83
- From source:
269
+ ## Claude Desktop Setup
270
+
271
+ Claude Desktop runs in a macOS sandbox and cannot access global npm binaries. Use `npx` instead.
272
+
273
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
274
+
84
275
  ```json
85
276
  {
86
- "mcp.servers": {
87
- "mcp-planning-server": {
88
- "command": "node",
89
- "args": ["/path/to/mcp-planning-server/dist/index.js"],
90
- "cwd": "/path/to/mcp-planning-server"
277
+ "mcpServers": {
278
+ "limps": {
279
+ "command": "npx",
280
+ "args": ["-y", "@sudosandwich/limps", "--config", "/path/to/config.json"]
91
281
  }
92
282
  }
93
283
  }
94
284
  ```
95
285
 
286
+ > **Note:** Run `limps init my-project` first to generate the config, then copy the full path into the config above.
287
+
96
288
  ## Features
97
289
 
98
- ### Document Management (14 Tools)
290
+ ### MCP Tools (16 Tools)
291
+
292
+ #### Document Operations
99
293
 
100
294
  | Tool | Description |
101
295
  |------|-------------|
102
- | `read_doc` | Read full document content |
296
+ | `process_doc` | Process a document with JavaScript code (read, filter, transform, extract) |
297
+ | `process_docs` | Process multiple documents with JavaScript for cross-document analysis |
103
298
  | `create_doc` | Create new documents |
104
299
  | `update_doc` | Update with optimistic concurrency |
105
300
  | `delete_doc` | Delete documents |
106
301
  | `list_docs` | List files and directories |
107
302
  | `search_docs` | Full-text search (SQLite FTS5) |
108
- | `rlm_query` | JavaScript filter/transform on documents |
109
- | `rlm_multi_query` | Cross-document analysis with globs |
110
- | `create_plan` | Create feature plans with structure |
111
- | `update_task_status` | Update task status (GAP → WIP → PASS) |
303
+ | `open_document_in_cursor` | Open files in Cursor editor |
304
+
305
+ #### Plan Management
306
+
307
+ | Tool | Description |
308
+ |------|-------------|
309
+ | `create_plan` | Create feature plans with directory structure and agent files |
310
+ | `list_plans` | List all plans with status, workType, and overview |
311
+ | `list_agents` | List agents for a plan with status, persona, and file counts |
312
+ | `get_plan_status` | Get plan progress with completion %, blocked/WIP agents |
313
+
314
+ #### Task Coordination
315
+
316
+ | Tool | Description |
317
+ |------|-------------|
318
+ | `get_next_task` | Get highest-priority task with detailed score breakdown |
112
319
  | `claim_task` | Claim tasks with file locks |
113
320
  | `release_task` | Release tasks and locks |
114
- | `get_next_task` | Get highest-priority available task |
115
- | `open_document_in_cursor` | Open files in Cursor editor |
321
+ | `update_task_status` | Update task status (GAP → WIP → PASS/BLOCKED) |
322
+
323
+ #### Task Scoring Algorithm
324
+
325
+ When using `get_next_task` with a `planId`, returns a detailed score breakdown:
326
+
327
+ | Score Component | Max Points | Description |
328
+ |----------------|------------|-------------|
329
+ | Dependency Score | 40 | All dependencies satisfied = 40, otherwise 0 |
330
+ | Priority Score | 30 | Based on agent number (lower = higher priority) |
331
+ | Workload Score | 30 | Based on file count (fewer files = higher score) |
332
+ | **Total** | **100** | Sum of all components |
333
+
334
+ Example response:
335
+ ```json
336
+ {
337
+ "taskId": "0001-feature#002",
338
+ "title": "Implement API endpoints",
339
+ "totalScore": 85,
340
+ "dependencyScore": 40,
341
+ "priorityScore": 24,
342
+ "workloadScore": 21,
343
+ "reasons": ["All 2 dependencies satisfied", "Agent #2 priority: 24/30", "3 files to modify: 21/30"],
344
+ "otherAvailableTasks": 3
345
+ }
346
+ ```
347
+
348
+ ### RLM (Recursive Language Model) Support
349
+
350
+ Implements the [RLM pattern from MIT CSAIL](https://arxiv.org/abs/2512.24601) for programmatic document examination and recursive processing:
351
+
352
+ - **Sandbox execution** - Secure JavaScript via QuickJS
353
+ - **Recursive sub-calls** - Depth-limited processing
354
+ - **Parallel execution** - Cross-document analysis
355
+ - **Document extractors** - Markdown, YAML, Gherkin parsing
116
356
 
117
357
  ### Resources (Progressive Disclosure)
118
358
 
@@ -147,10 +387,16 @@ GitHub Actions automatically builds, tests, and creates releases with changelogs
147
387
 
148
388
  ## Architecture
149
389
 
150
- - **SQLite + FTS5** — Full-text search with auto-updates
151
- - **File Watching** — Real-time indexing (Chokidar)
152
- - **Multi-Agent Coordination** — File-based with heartbeats
153
- - **RLM Sandbox** — Secure JavaScript execution (QuickJS)
390
+ ![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue)
391
+ ![React](https://img.shields.io/badge/React-19-61dafb)
392
+ ![Ink](https://img.shields.io/badge/Ink-6-green)
393
+ ![SQLite](https://img.shields.io/badge/SQLite-FTS5-003B57)
394
+ ![Zod](https://img.shields.io/badge/Zod-4-3068b7)
395
+
396
+ - Full-text search with auto-indexing
397
+ - Real-time file watching (Chokidar)
398
+ - Multi-agent coordination with heartbeats
399
+ - RLM sandbox (QuickJS)
154
400
 
155
401
  ### Principles
156
402
 
@@ -165,6 +411,7 @@ GitHub Actions automatically builds, tests, and creates releases with changelogs
165
411
  The server is designed for planning documents but the core is generic:
166
412
 
167
413
  **Configuration-only:**
414
+
168
415
  ```json
169
416
  {
170
417
  "plansPath": "./your-docs",
@@ -174,6 +421,7 @@ The server is designed for planning documents but the core is generic:
174
421
  ```
175
422
 
176
423
  **For different domains** (wikis, knowledge bases):
424
+
177
425
  - Replace/remove planning-specific tools
178
426
  - Customize document extractors in `src/rlm/extractors.ts`
179
427
  - Modify coordination patterns or remove if single-agent
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Config subcommand handlers for limps CLI.
3
+ * Provides commands to manage the project registry and view configuration.
4
+ */
5
+ /**
6
+ * List all registered projects.
7
+ *
8
+ * @returns Formatted list of projects
9
+ */
10
+ export declare function configList(): string;
11
+ /**
12
+ * Switch to a different project.
13
+ *
14
+ * @param name - Project name to switch to
15
+ * @returns Success message
16
+ * @throws Error if project not found
17
+ */
18
+ export declare function configUse(name: string): string;
19
+ /**
20
+ * Show the resolved configuration values.
21
+ *
22
+ * @param resolveConfigPathFn - Function to resolve config path (injected to avoid circular deps)
23
+ * @returns Formatted configuration
24
+ */
25
+ export declare function configShow(resolveConfigPathFn: () => string): string;
26
+ /**
27
+ * Print the resolved config file path.
28
+ *
29
+ * @param resolveConfigPathFn - Function to resolve config path (injected to avoid circular deps)
30
+ * @returns The config path
31
+ */
32
+ export declare function configPath(resolveConfigPathFn: () => string): string;
33
+ /**
34
+ * Add/register an existing config file to the registry.
35
+ *
36
+ * @param name - Project name to use
37
+ * @param configFilePath - Path to the config file
38
+ * @returns Success message
39
+ * @throws Error if config file doesn't exist
40
+ */
41
+ export declare function configAdd(name: string, configFilePath: string): string;
42
+ /**
43
+ * Remove a project from the registry.
44
+ * Does not delete any files.
45
+ *
46
+ * @param name - Project name to remove
47
+ * @returns Success message
48
+ * @throws Error if project not found
49
+ */
50
+ export declare function configRemove(name: string): string;
51
+ /**
52
+ * Set the current project from an existing config file path.
53
+ * Auto-derives the project name from the parent directory.
54
+ * Registers the project if not already registered.
55
+ *
56
+ * @param configFilePath - Path to the config file
57
+ * @returns Success message
58
+ * @throws Error if config file doesn't exist or is invalid
59
+ */
60
+ export declare function configSet(configFilePath: string): string;
61
+ /**
62
+ * Discover and register config files from default OS locations.
63
+ * Scans the OS-specific application support directories for config.json files.
64
+ *
65
+ * @returns Summary of discovered projects
66
+ */
67
+ export declare function configDiscover(): string;
68
+ //# sourceMappingURL=config-cmd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-cmd.d.ts","sourceRoot":"","sources":["../../src/cli/config-cmd.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAmBnC;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG9C;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,mBAAmB,EAAE,MAAM,MAAM,GAAG,MAAM,CAiCpE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,mBAAmB,EAAE,MAAM,MAAM,GAAG,MAAM,CAEpE;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAkBtE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAmCxD;AAID;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAmDvC"}
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Config subcommand handlers for limps CLI.
3
+ * Provides commands to manage the project registry and view configuration.
4
+ */
5
+ import { existsSync, readdirSync } from 'fs';
6
+ import { resolve, dirname, basename } from 'path';
7
+ import { registerProject, unregisterProject, setCurrentProject, listProjects, loadRegistry, } from './registry.js';
8
+ import { loadConfig } from '../config.js';
9
+ /**
10
+ * List all registered projects.
11
+ *
12
+ * @returns Formatted list of projects
13
+ */
14
+ export function configList() {
15
+ const projects = listProjects();
16
+ if (projects.length === 0) {
17
+ return 'No projects registered. Run `limps init <name>` to create one.';
18
+ }
19
+ const lines = [];
20
+ lines.push('CURRENT NAME PATH');
21
+ lines.push('------- ------------------- ----');
22
+ for (const project of projects) {
23
+ const current = project.current ? '*' : ' ';
24
+ const name = project.name.padEnd(19);
25
+ const exists = existsSync(project.configPath) ? '' : ' (missing)';
26
+ lines.push(` ${current} ${name} ${project.configPath}${exists}`);
27
+ }
28
+ return lines.join('\n');
29
+ }
30
+ /**
31
+ * Switch to a different project.
32
+ *
33
+ * @param name - Project name to switch to
34
+ * @returns Success message
35
+ * @throws Error if project not found
36
+ */
37
+ export function configUse(name) {
38
+ setCurrentProject(name);
39
+ return `Switched to project "${name}"`;
40
+ }
41
+ /**
42
+ * Show the resolved configuration values.
43
+ *
44
+ * @param resolveConfigPathFn - Function to resolve config path (injected to avoid circular deps)
45
+ * @returns Formatted configuration
46
+ */
47
+ export function configShow(resolveConfigPathFn) {
48
+ const configPath = resolveConfigPathFn();
49
+ if (!existsSync(configPath)) {
50
+ return `Config file not found: ${configPath}\n\nRun \`limps init <name>\` to create a project.`;
51
+ }
52
+ const config = loadConfig(configPath);
53
+ const lines = [];
54
+ lines.push(`Config file: ${configPath}`);
55
+ lines.push('');
56
+ lines.push('Configuration:');
57
+ lines.push(` plansPath: ${config.plansPath}`);
58
+ lines.push(` dataPath: ${config.dataPath}`);
59
+ lines.push(` coordinationPath: ${config.coordinationPath}`);
60
+ if (config.docsPaths && config.docsPaths.length > 0) {
61
+ lines.push(` docsPaths:`);
62
+ for (const p of config.docsPaths) {
63
+ lines.push(` - ${p}`);
64
+ }
65
+ }
66
+ if (config.fileExtensions) {
67
+ lines.push(` fileExtensions: ${config.fileExtensions.join(', ')}`);
68
+ }
69
+ lines.push(` heartbeatTimeout: ${config.heartbeatTimeout}ms`);
70
+ lines.push(` debounceDelay: ${config.debounceDelay}ms`);
71
+ lines.push(` maxHandoffIterations: ${config.maxHandoffIterations}`);
72
+ return lines.join('\n');
73
+ }
74
+ /**
75
+ * Print the resolved config file path.
76
+ *
77
+ * @param resolveConfigPathFn - Function to resolve config path (injected to avoid circular deps)
78
+ * @returns The config path
79
+ */
80
+ export function configPath(resolveConfigPathFn) {
81
+ return resolveConfigPathFn();
82
+ }
83
+ /**
84
+ * Add/register an existing config file to the registry.
85
+ *
86
+ * @param name - Project name to use
87
+ * @param configFilePath - Path to the config file
88
+ * @returns Success message
89
+ * @throws Error if config file doesn't exist
90
+ */
91
+ export function configAdd(name, configFilePath) {
92
+ const absolutePath = resolve(configFilePath);
93
+ if (!existsSync(absolutePath)) {
94
+ throw new Error(`Config file not found: ${absolutePath}`);
95
+ }
96
+ // Validate it's a valid config file
97
+ try {
98
+ loadConfig(absolutePath);
99
+ }
100
+ catch (error) {
101
+ throw new Error(`Invalid config file: ${error instanceof Error ? error.message : 'unknown error'}`);
102
+ }
103
+ registerProject(name, absolutePath);
104
+ return `Registered project "${name}" with config: ${absolutePath}`;
105
+ }
106
+ /**
107
+ * Remove a project from the registry.
108
+ * Does not delete any files.
109
+ *
110
+ * @param name - Project name to remove
111
+ * @returns Success message
112
+ * @throws Error if project not found
113
+ */
114
+ export function configRemove(name) {
115
+ unregisterProject(name);
116
+ return `Removed project "${name}" from registry (files not deleted)`;
117
+ }
118
+ /**
119
+ * Set the current project from an existing config file path.
120
+ * Auto-derives the project name from the parent directory.
121
+ * Registers the project if not already registered.
122
+ *
123
+ * @param configFilePath - Path to the config file
124
+ * @returns Success message
125
+ * @throws Error if config file doesn't exist or is invalid
126
+ */
127
+ export function configSet(configFilePath) {
128
+ const absolutePath = resolve(configFilePath);
129
+ if (!existsSync(absolutePath)) {
130
+ throw new Error(`Config file not found: ${absolutePath}`);
131
+ }
132
+ // Validate it's a valid config file
133
+ try {
134
+ loadConfig(absolutePath);
135
+ }
136
+ catch (error) {
137
+ throw new Error(`Invalid config file: ${error instanceof Error ? error.message : 'unknown error'}`);
138
+ }
139
+ // Derive project name from parent directory
140
+ const projectName = basename(dirname(absolutePath));
141
+ // Check if already registered with this path
142
+ const registry = loadRegistry();
143
+ const existingEntry = Object.entries(registry.projects).find(([, project]) => project.configPath === absolutePath);
144
+ if (existingEntry) {
145
+ // Already registered, just set as current
146
+ setCurrentProject(existingEntry[0]);
147
+ return `Switched to project "${existingEntry[0]}"`;
148
+ }
149
+ // Register and set as current
150
+ registerProject(projectName, absolutePath);
151
+ setCurrentProject(projectName);
152
+ return `Registered and switched to project "${projectName}"`;
153
+ }
154
+ import { getOSBasePath } from '../utils/os-paths.js';
155
+ /**
156
+ * Discover and register config files from default OS locations.
157
+ * Scans the OS-specific application support directories for config.json files.
158
+ *
159
+ * @returns Summary of discovered projects
160
+ */
161
+ export function configDiscover() {
162
+ // Get the parent directory of where limps stores its config
163
+ // This respects any mocking of getOSBasePath for testing
164
+ const limpsBasePath = getOSBasePath('limps');
165
+ const searchDir = dirname(limpsBasePath);
166
+ const registry = loadRegistry();
167
+ const registeredPaths = new Set(Object.values(registry.projects).map((p) => p.configPath));
168
+ const discovered = [];
169
+ if (!existsSync(searchDir)) {
170
+ return 'No new projects discovered.';
171
+ }
172
+ try {
173
+ const entries = readdirSync(searchDir, { withFileTypes: true });
174
+ for (const entry of entries) {
175
+ if (!entry.isDirectory())
176
+ continue;
177
+ const configPath = `${searchDir}/${entry.name}/config.json`;
178
+ // Skip if already registered or doesn't exist
179
+ if (registeredPaths.has(configPath) || !existsSync(configPath))
180
+ continue;
181
+ // Validate it's a valid limps config
182
+ try {
183
+ loadConfig(configPath);
184
+ registerProject(entry.name, configPath);
185
+ discovered.push({ name: entry.name, path: configPath });
186
+ }
187
+ catch {
188
+ // Not a valid limps config, skip
189
+ }
190
+ }
191
+ }
192
+ catch {
193
+ // Can't read directory, skip
194
+ }
195
+ if (discovered.length === 0) {
196
+ return 'No new projects discovered.';
197
+ }
198
+ const lines = [`Discovered ${discovered.length} project(s):`, ''];
199
+ for (const { name, path } of discovered) {
200
+ lines.push(` ${name}: ${path}`);
201
+ }
202
+ lines.push('');
203
+ lines.push('Run `limps config use <name>` to switch to a project.');
204
+ return lines.join('\n');
205
+ }
206
+ //# sourceMappingURL=config-cmd.js.map