io.github.paulbreuler/limps
MCP planning server for AI agents — plan management, full-text search, and task lifecycle
Open source Open in the app JSON README (API)
About
MCP planning server for AI agents — plan management, full-text search, and task lifecycle
Details
- Kind
- MCP servers
- Topic
- No topic detected
- Publisher
- paulbreuler
- Origin
- official
- Category
- ferramentas
- Transport
- local
- Version
- 3.4.0
- Stars
- 10
- Forks
- 1
- Open pull requests
- 2
- Last push
- 2026-03-02T17:59:14Z
- Repository state
- ativo
- Language
- TypeScript
- License
- MIT
- Added
- 2026-08-29 04:00:59
- Updated
- 2026-08-29 04:00:59
- Origin id
io.github.paulbreuler/limps
README
# limps
**L**ocal **I**ntelligent **M**CP **P**lanning **S**erver — A document and planning layer for AI assistants. No subscriptions, no cloud. Point limps at **any folder** (local, synced, or in git). One shared source of truth across Claude, Cursor, Codex, and any MCP-compatible tool.
[](https://www.npmjs.com/package/@sudosandwich/limps)
[](https://opensource.org/licenses/MIT)


[](https://lobehub.com/mcp/paulbreuler-limps)

## Table of Contents
- [Quick Start](#quick-start)
- [Features](#features)
- [How I Use limps](#how-i-use-limps)
- [Health & Automation](#health--automation)
- [How You Can Use It](#how-you-can-use-it)
- [Why limps?](#why-limps)
- [Installation](#installation)
- [Upgrading from v2](#upgrading-from-v2)
- [Project Setup](#project-setup)
- [Client Setup](#client-setup)
- [Transport](#transport)
- [Daemon Management](#daemon-management)
- [CLI Commands](#cli-commands)
- [Configuration](#configuration)
- [Environment Variables](#environment-variables)
- [Troubleshooting](#troubleshooting)
- [MCP Tools](#mcp-tools)
- [Skills & Commands](#skills--commands)
- [Extensions](#extensions)
- [Obsidian Compatibility](#obsidian-compatibility)
- [Development](#development)
- [Used in Production](#used-in-production)
- [Creating a feature plan](#creating-a-feature-plan)
- [Deep Dive](#deep-dive)
- [What is MCP?](#what-is-mcp)
- [License](#license)
## Quick Start
```bash
# Install globally
npm install -g @sudosandwich/limps
# Initialize in your project
cd ~/Documents/my-planning-docs
limps init
# Start the HTTP daemon
limps server start
# → Daemon starts on http://127.0.0.1:4269/mcp
# → PID file written to OS-standard location
# → Ready for MCP client connections
# Generate MCP client config
limps config print --client claude-code
# Copy the output to your MCP client config file
```
That's it. Your AI assistant now has access to your documents via HTTP transport. The folder can be anywhere—local, synced, or in a repo; limps does not require a git repository or a `plans/` directory.
**Tip:** `limps server status` always includes system-wide daemon discovery. If a project config is found (or passed via `--config`), it also reconciles the configured project target against that global list.
## Features
- **Document CRUD + full-text search** across any folder of Markdown files
- **Plan + agent workflows** with status tracking and task scoring
- **Next-task suggestions** with score breakdowns and bias tuning
- **Sandboxed document processing** via `process_doc(s)` helpers
- **Multi-client support** for Cursor, Claude, Codex, and more
- **Extensions** for domain-specific tooling (e.g., limps-headless)
- **Knowledge graph** — Entity extraction, hybrid retrieval, conflict detection, and graph-based suggestions
- **Health automation** — Staleness detection, code drift checks, status inference, and auto-fix proposals
- **Advanced task scoring** — Dependency-aware prioritization with per-plan/agent weight overrides
- **MCP Registry** — Published to the official MCP Registry (`registry.modelcontextprotocol.io`)
### What to know before you start
- **Local only** — Your data stays on disk (SQLite index + your files). No cloud, no subscription.
- **Restart after changes** — If you change the indexed folder or config, restart the MCP server (or rely on the file watcher) so the index and tools reflect the current state.
- **Daemon management** — The HTTP server runs as a background process. Use `limps server start`, `limps server stop`, and `limps server status` to manage the daemon lifecycle. PID files are stored in OS-standard directories for system-wide awareness.
- **Sandboxed user code** — `process_doc` and `process_docs` run your JavaScript in a QuickJS sandbox with time and memory limits; no network or Node APIs.
- **One optional network call** — `limps version --check` fetches from the npm registry to compare versions. All other commands (serve, init, list, search, create/update/delete docs, process_doc, etc.) do **not** contact the internet. Omit `version --check` if you want zero external calls.
## How I Use limps
I use `limps` as a local planning layer across multiple AI tools, focused on **create → read → update → closure** for plans and tasks. The MCP server points at whatever directory I want (not necessarily a git repo), so any client reads and updates the same source of truth.
Typical flow:
1. Point limps at a docs directory (any folder, local or synced).
2. Use CLI + MCP tools to create plans/docs, read the current status, update tasks, and close work when done.
3. Add the limps MCP entry to each client config so Cursor/Claude/Codex all see the same plans.
Commands and tools I use most often:
- **Create**: `limps init`, `create_plan`, `create_doc`
- **Read**: `list_plans`, `list_agents`, `list_docs`, `search_docs`, `get_plan_status`
- **Update**: `update_doc`, `update_task_status`, `manage_tags`
- **Close**: `update_task_status` (e.g., `PASS`), `delete_doc` if needed
- **Analyze**: `graph health`, `graph search`, `graph check`, `health check`
Full lists are below in "CLI Commands" and "MCP Tools."
## How You Can Use It
`limps` is designed to be generic and portable. Point it at **any folder** with Markdown files and use it from any MCP-compatible client. **No git repo required.** **Not limited to planning**—planning (plans, agents, task status) is one use case; the same layer gives you document CRUD, full-text search, and programmable processing on any indexed folder.
Common setups:
- **Single project**: One docs folder for a product.
- **Multi-project**: Each project gets its own `.limps/config.json`; pass `--config` to target a specific one.
- **Shared team folder**: Put plans in a shared location and review changes like code.
- **Local-first**: Keep everything on disk, no hosted service required.
Key ideas:
- **Any folder** — You choose the path; if there’s no `plans/` subdir, the whole directory is indexed. Use generic tools (`list_docs`, `search_docs`, `create_doc`, `update_doc`, `delete_doc`, `process_doc`, `process_docs`) or plan-specific ones (`create_plan`, `list_plans`, `list_agents`, `get_plan_status`, `update_task_status`, `get_next_task`).
- **One source of truth** — MCP tools give structured access; multiple clients share the same docs.
## Why limps?
**The problem:** Each AI assistant maintains its own context. Planning documents, task status, and decisions get fragmented across Claude, Cursor, ChatGPT, and Copilot conversations.
**The solution:** limps provides a standardized MCP interface that any tool can access. Your docs live in one place—a folder you choose. Use git (or any sync) if you want version control; limps is not tied to a repository.
## Installation
```bash
npm install -g @sudosandwich/limps
```
## Upgrading from v2
v3 introduces major changes:
### HTTP Transport (Breaking Change)
v3 uses **HTTP transport exclusively**. stdio transport has been removed.
**Migration steps:**
1. **Start the HTTP daemon** for each project:
```bash
limps server start --config /path/to/.limps/config.json
```
2. **Update MCP client configs** — Replace stdio configs with HTTP transport:
```json
{
"mcpServers": {
"limps-planning-myproject": {
"transport": {
"type": "http",
"url": "http://127.0.0.1:4269/mcp"
}
}
}
}
```
Use `limps config print` to generate the correct snippet.
### Per-Project Configs (Breaking Change)
v3 removes the centralized project registry. If you previously used `limps config add`, `config use`, or the `--project` flag:
1. **Run `limps init`** in each project directory to create `.limps/config.json`.
2. **Update MCP client configs** — Replace `--project <name>` with HTTP transport config (see above).
3. **Remove environment variable** — `LIMPS_PROJECT` no longer exists. Use `MCP_PLANNING_CONFIG` to override config path.
**Removed commands:** `config list`, `config use`, `config add`, `config remove`, `config set`, `config discover`, `config migrate`, `config sync-mcp`, `serve`.
**Replaced by:** `limps init` + `limps server start` + `limps config print`.
## Project Setup
### Initialize a New Project
```bash
cd ~/Documents/my-planning-docs
limps init
```
This creates `.limps/config.json` in the current directory and prints MCP client setup instructions.
You can also specify a path:
```bash
limps init ~/Documents/my-planning-docs
```
If the directory contains a `plans/` subdirectory, limps uses it. Otherwise, it indexes the entire directory.
### Multiple Projects
Each project has its own `.limps/config.json`. Use `--config` to target a specific project:
```bash
limps plan list --config ~/docs/project-b/.limps/config.json
```
## Client Setup
After running `limps init`, you need to add a limps entry to your MCP client's config file. Use `limps config print` to generate the correct snippet for your client, then paste it into the appropriate config file:
```bash
limps config print --client cursor
limps config print --client claude-code
limps config print --client claude
```
The output tells you exactly what JSON (or TOML) to add and where the config file lives.
### Per-Client Examples
All clients connect to the HTTP daemon. Start the daemon first with `limps server start`, then configure your client.
<details>
<summary><b>Cursor</b></summary>
Add to `.cursor/mcp.json` in your project:
```json
{
"mcpServers": {
"limps-planning-myproject": {
"transport": {
"type": "http",
"url": "http://127.0.0.1:4269/mcp"
}
}
}
}
```
</details>
<details>
<summary><b>Claude Code</b></summary>
Add to `.mcp.json` in your project root:
```json
{
"mcpServers": {
"limps-planning-myproject": {
"transport": {
"type": "http",
"url": "http://127.0.0.1:4269/mcp"
}
}
}
}
```
</details>
<details>
<summary><b>Claude Desktop</b></summary>
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"limps-planning-myproject": {
"transport": {
"type": "http",
"url": "http://127.0.0.1:4269/mcp"
}
}
}
}
```
</details>
<details>
<summary><b>OpenAI Codex</b></summary>
Add to `~/.codex/config.toml`:
```toml
[mcp_servers.limps-planning-myproject.transport]
type = "http"
url = "http://127.0.0.1:4269/mcp"
```
</details>
<details>
<summary><b>ChatGPT</b></summary>
ChatGPT requires a remote MCP server over HTTPS. Deploy limps behind an MCP-compatible HTTPS reverse proxy (nginx, Caddy, etc.) with authentication.
In ChatGPT → Settings → Connectors → Add custom connector:
- **Server URL**: `https://your-domain.example/mcp`
- **Authentication**: Configure as needed for your proxy
Print setup instructions:
```bash
limps config print --client chatgpt
```
</details>
## Transport
limps v3 uses **HTTP transport exclusively** via a persistent daemon. This allows multiple MCP clients to share a single server instance, avoiding file descriptor bloat from multiple stdio processes.
### Start the HTTP daemon
```bash
# Start the daemon
limps server start
# Check status (shows uptime, sessions, PID)
limps server status
# Stop the daemon
limps server stop
```
The daemon runs at `http://127.0.0.1:4269/mcp` by default. Use `limps config print` to generate the correct MCP client configuration:
```bash
limps config print --client claude-code
```
See [Daemon Management](#daemon-management) for detailed lifecycle documentation.
### MCP Client Configuration
All clients use HTTP transport. Example config:
```json
{
"mcpServers": {
"limps-planning-myproject": {
"transport": {
"type": "http",
"url": "http://127.0.0.1:4269/mcp"
}
}
}
}
```
### Server Config Options
Customize the HTTP server by adding a `"server"` section to your `config.json`:
| Option | Default | Description |
| ------------------ | ---------------------- | ---------------------------------------- |
| `port` | `4269` | HTTP listen port |
| `host` | `127.0.0.1` | Bind address |
| `maxSessions` | `100` | Maximum concurrent MCP sessions |
| `sessionTimeoutMs` | `1800000` | Session idle timeout in ms (30 min) |
| `corsOrigin` | `""` (none) | CORS origin (`""`, `"*"`, or a URL) |
| `maxBodySize` | `10485760` | Max request body in bytes (10 MB) |
| `rateLimit` | `100 req/min` | Rate limit per client IP |
Example custom server config:
```json
{
"server": {
"port": 8080,
"host": "0.0.0.0"
}
}
```
**Note:** PID files are stored in OS-standard application directories:
- **macOS**: `~/Library/Application Support/limps/pids/`
- **Linux**: `$XDG_DATA_HOME/limps/pids/` or `~/.local/share/limps/pids/`
- **Windows**: `%APPDATA%/limps/pids/`
This enables `limps server status` to perform system-wide daemon discovery from any directory. When a limps config is found for the current directory (or passed via `--config`), the CLI also reports and reconciles that project's configured target.
- **Remote clients**: Use an MCP-compatible HTTPS proxy for remote clients (e.g., ChatGPT).
## Daemon Management
limps v3 uses a persistent HTTP daemon with system-wide awareness. PID files are stored in OS-standard directories, allowing you to manage and discover daemons from any directory on your system.
### PID File Locations
PID files are stored in platform-specific application data directories:
**macOS:**
```
~/Library/Application Support/limps/pids/
```
**Linux:**
```
$XDG_DATA_HOME/limps/pids/
# or if XDG_DATA_HOME is not set:
~/.local/share/limps/pids/
```
**Windows:**
```
%APPDATA%/limps/pids/
```
Each PID file is named by port number (`limps-{port}.pid`) to enable system-wide discovery. Example PID file structure:
```json
{
"pid": 12345,
"port": 4269,
"host": "127.0.0.1",
"startedAt": "2026-02-08T12:00:00.000Z",
"configPath": "/path/to/project/.limps/config.json",
"logPath": "/Users/you/Library/Application Support/limps/logs/limps-4269.log"
}
```
This port-based naming allows `limps server status` to find all running daemons across different projects without needing a config file.
Daemon logs are written to OS-standard application log directories:
**macOS:**
```
~/Library/Application Support/limps/logs/
```
**Linux:**
```
$XDG_DATA_HOME/limps/logs/
# or if XDG_DATA_HOME is not set:
~/.local/share/limps/logs/
```
**Windows:**
```
%APPDATA%/limps/logs/
```
Daemon logs are intentionally operational-only: limps redacts uncaught exception/rejection payloads and does not persist raw AI prompt/response content.
Daemon log files are append-only and are not auto-rotated; if you run long-lived daemons, rotate or truncate these files with your system tooling.
### Starting the Daemon
**Background mode (default):**
```bash
limps server start
# → Daemon starts on http://127.0.0.1:4269/mcp
# → PID file written to OS-standard location
# → Logs written to OS-standard log file (append mode)
# → Process detaches and runs in background
```
**Foreground mode (debugging):**
```bash
limps server start --foreground
# → Runs in foreground (blocks terminal)
# → Logs appear in stderr
# → Useful for debugging startup issues
# → Still creates PID file for discovery
```
**Custom port/host (via config):**
Configure `server.port` and `server.host` in your `.limps/config.json`:
```json
{
"server": {
"port": 8080,
"host": "0.0.0.0"
}
}
```
Then start normally:
```bash
limps server start
# → Starts using server.port/server.host from config
# → PID file: limps-8080.pid
```
The `start` command performs health verification by polling the `/health` endpoint for up to 5 seconds, issuing repeated HTTP requests. Each individual health-check request has its own shorter timeout (for example, ~1000ms). If any request fails during this window, you'll see one of these error codes:
- **TIMEOUT** — A single health-check HTTP request exceeded its per-request timeout (e.g., ~1000ms). The daemon may be slow to start or system resources may be constrained. Try `limps server start --foreground` to see logs.
- **NETWORK_ERROR** — Cannot connect to daemon. Port may be blocked or already in use by another process.
- **NON_200_STATUS** — Health endpoint returned a non-200 status code. Check daemon logs with foreground mode.
- **INVALID_RESPONSE** — Health endpoint responded, but the response was invalid or could not be parsed as expected (for example, malformed or missing required fields).
### Checking Daemon Status
**With project config (reconciled with global discovery):**
```bash
# From within a project directory with .limps/config.json
limps server status
# Project target:
# limps server is running
# PID: 12345 | 127.0.0.1:4269
# Uptime: 2h 15m
# Sessions: 3
# Log: /Users/you/Library/Application Support/limps/logs/limps-4269.log
# Project target is present in system-wide daemon discovery.
# System-wide daemons:
# 127.0.0.1:4269 (PID 12345) [project target]
# Uptime: 2h 15m | Sessions: 3
# Log: /Users/you/Library/Application Support/limps/logs/limps-4269.log
# Or specify config explicitly
limps server status --config /path/to/.limps/config.json
```
**Without project config (global discovery only):**
```bash
# From a directory without a limps config
cd /tmp
limps server status
# Found 2 running daemons:
# 127.0.0.1:4269 (PID 12345)
# Uptime: 2h 15m | Sessions: 3
# Log: /Users/you/Library/Application Support/limps/logs/limps-4269.log
# 127.0.0.1:8080 (PID 67890)
# Uptime: 45m 30s | Sessions: 1
# Log: /Users/you/Library/Application Support/limps/logs/limps-8080.log
```
When `limps server status` cannot resolve a config file in the current directory (and no `--config` is provided), it reports global daemon discovery only. When a config is found, it reports both the configured project target and the global daemon list.
### Stopping the Daemon
```bash
# From the project directory (where your .limps config lives):
limps server stop
# → Gracefully shuts down daemon
# → Closes all MCP sessions
# → Stops file watchers
# → Removes PID file
# → Process exits
# Or from any directory, by specifying the config explicitly:
limps server stop --config /path/to/.limps/config.json
```
The `stop` command is project-specific and resolves the config to determine which daemon to stop. The daemon performs a graceful shutdown by:
1. Closing all active MCP sessions
2. Shutting down file watchers
3. Removing the PID file
4. Exiting the process
### Port Conflicts
If you try to start a daemon on a port that's already in use, limps will detect the conflict and provide resolution guidance:
```bash
limps server start
# Error: Port 4269 is already in use.
# Process using port: node (PID 12345)
# Command: /usr/local/bin/node /usr/local/bin/limps server start
#
# To stop the process: kill 12345
# Or use a different port: limps server start --port <port>
```
On systems with `lsof` available (macOS, Linux), limps can identify which process is using the port and show its command line. If `lsof` is not available, you'll see a simpler error message suggesting a different port.
### Foreground Mode
Use foreground mode for debugging, Docker deployments, or CI/CD pipelines:
```bash
limps server start --foreground
```
**Use cases:**
- **Debugging** — See server logs in real-time to diagnose startup issues
- **Docker** — Keep container alive with the daemon as the main process
- **CI/CD** — Run tests against a limps daemon without background processes
**Behavior differences from background mode:**
- Logs to stderr instead of being silent
- Blocks the terminal (press Ctrl+C to stop)
- Still creates a PID file for discovery by other processes
- Responds to SIGINT (Ctrl+C) and SIGTERM for graceful shutdown
### Health Endpoint
The HTTP daemon exposes a `/health` endpoint for monitoring and health checks:
```bash
curl http://127.0.0.1:4269/health
```
**Example response:**
```json
{
"status": "ok",
"sessions": 3,
"uptime": 8145,
"pid": 12345,
"sessionTimeoutMs": 1800000
}
```
**HTTP status codes:**
- **200** — Daemon is healthy and accepting connections
- **429** — Rate limit exceeded (rate limiter may return this before the request reaches `/health`)
### Session Management & Reconnection
Sessions automatically expire after 30 minutes of inactivity (configurable via `sessionTimeoutMs`). When a session expires, MCP clients receive a specific error response indicating they should reconnect.
**Session Expiration Response:**
When a session expires or is closed, subsequent requests with that session ID return:
```json
{
"error": "Session expired",
"code": "SESSION_EXPIRED",
"message": "Session expired due to timeout. Please reconnect without session ID.",
"expiredAt": "2026-02-11T10:30:00.000Z"
}
```
**Headers:**
- `X-Session-Expired: true`
- `X-Session-Expired-Reason: timeout` (or `closed`, `deleted`)
**MCP Client Reconnection Flow:**
When receiving `SESSION_EXPIRED`, clients should:
1. **Clear the stored session ID** — Remove the cached `mcp-session-id`
2. **Create a new session** — Send POST to `/mcp` **without** the session ID header
3. **Store the new session ID** — Save the new `mcp-session-id` from response headers
4. **Retry the original request** — Resubmit with the new session ID
**Configuration:**
Adjust session timeout in `.limps/config.json`:
```json
{
"server": {
"sessionTimeoutMs": 3600000 // 1 hour (default: 1800000 = 30 min)
}
}
```
Set to `0` to disable timeout (sessions persist until server restart).
**Expired Session Tracking:**
The server tracks expired sessions for 24 hours to help clients distinguish between "session expired" vs "session never existed":
- `SESSION_EXPIRED` — Session previously existed but timed out (client should reconnect)
- `SESSION_NOT_FOUND` — Session ID was never valid (possible server restart or invalid ID)
Use this endpoint for:
- Monitoring daemon health in scripts or dashboards
- Verifying daemon is running before connecting MCP clients
- Automated health checks in orchestration tools (Kubernetes, Docker Compose)
### Multiple Daemons
You can run multiple limps daemons on different ports for different projects by configuring different ports in each project's config:
```bash
# Project A with default port (4269)
cd ~/projects/project-a
# .limps/config.json has server.port: 4269 (or uses default)
limps server start
# → Running on http://127.0.0.1:4269/mcp
# Project B with custom port (8080)
cd ~/projects/project-b
# .limps/config.json has server.port: 8080
limps server start
# → Running on http://127.0.0.1:8080/mcp
```
Each daemon has its own PID file:
- `limps-4269.pid` — Project A
- `limps-8080.pid` — Project B
Discover all running daemons (run from a directory without a limps config):
```bash
cd /tmp
limps server status
# Found 2 running daemons:
# 127.0.0.1:4269 (PID 12345)
# Uptime: 2h 15m | Sessions: 3
# 127.0.0.1:8080 (PID 67890)
# Uptime: 45m 30s | Sessions: 1
```
Each MCP client can connect to different daemons by configuring different URLs in their config files.
## CLI Commands
### Recommended Grouped Commands
```bash
limps plan list # List all plans with status
limps plan agents <plan> # List agents in a plan
limps plan status <plan> # Show plan progress summary
limps plan next <plan> # Get highest-priority available task
limps plan score --plan <plan> --agent <n> # Score a single task
limps plan scores --plan <plan> # Score all available tasks in a plan
limps docs list [path] # List files/directories
limps docs search <query> # Search indexed docs
limps docs process [path] --code "<js>" # Process docs with JavaScript
limps server start # Start HTTP daemon
limps server status # Show daemon status
limps server stop # Stop HTTP daemon
```
### Project Management
```bash
limps init [path] # Initialize new project
limps config show # Display current config
limps config print # Print MCP client config snippets
limps completion zsh # Generate Zsh tab-completion script
```
### Health & Automation
```bash
limps health check # Aggregate all health signals
limps health staleness [plan] # Find stale plans/agents
limps health inference [plan] # Suggest status updates
limps proposals [plan] # List auto-fix proposals
limps proposals apply <id> # Apply a proposal
limps proposals apply-safe # Apply all safe proposals
```
### Knowledge Graph
```bash
limps graph reindex # Build/rebuild graph
limps graph health # Graph stats and conflicts
limps graph search <query> # Search entities
limps graph trace <entity> # Trace relationships
limps graph entity <id> # Entity details
limps graph overlap # Find overlapping features
limps graph check [type] # Run conflict detection
limps graph suggest <type> # Graph-based suggestions
limps graph watch # Watch and update incrementally
```
### Scoring & Repair
```bash
limps plan scores --plan <plan> # Score all agents in a plan
limps plan score --plan <plan> --agent <n> # Score a single task
limps plan repair [--fix] # Check/fix agent frontmatter
```
## Configuration
Config lives at `.limps/config.json` in your project directory, created by `limps init`.
### Config Options
```json
{
"plansPath": "./plans",
"docsPaths": ["."],
"fileExtensions": [".md"],
"dataPath": ".limps/data",
"extensions": ["@sudosandwich/limps-headless"],
"tools": {
"allowlist": ["list_docs", "search_docs"]
},
"scoring": {
"weights": { "dependency": 40, "priority": 30, "workload": 30 },
"biases": {}
}
}
```
| Option | Description |
| ---------------- | ---------------------------------------------------------- |
| `plansPath` | Directory for structured plans (`NNNN-name/` with agents) |
| `docsPaths` | Additional directories to index |
| `fileExtensions` | File types to index (default: `.md`) |
| `dataPath` | SQLite database location |
| `tools` | Tool allowlist/denylist filtering |
| `extensions` | Extension packages to load |
| `scoring` | Task prioritization weights and biases |
| `server` | HTTP daemon settings (port, host, CORS, sessions, timeout) |
| `graph` | Knowledge graph settings (e.g., entity extraction options) |
| `retrieval` | Search recipe configuration for hybrid retrieval |
## Environment Variables
| Variable | Description | Example |
| ---------------------- | ---------------------------------------------------------- | ------------------------------------------------- |
| `MCP_PLANNING_CONFIG` | Path to config file (overrides default discovery) | `MCP_PLANNING_CONFIG=./my-config.json limps server bridge`|
| `LIMPS_ALLOWED_TOOLS` | Comma-separated allowlist; only these tools are registered | `LIMPS_ALLOWED_TOOLS="list_docs,search_docs"` |
| `LIMPS_DISABLED_TOOLS` | Comma-separated denylist; tools to hide | `LIMPS_DISABLED_TOOLS="process_doc,process_docs"` |
**Precedence:** `config.tools` overrides env vars. If allowlist is set, denylist is ignored.
## Troubleshooting
### Daemon Won't Start
**"Port already in use" error:**
If you see this error, another process is using the port:
```bash
limps server start
# Error: Port 4269 is already in use.
# Process using port: node (PID 12345)
```
**Resolution:**
1. **Kill the existing process**: `kill 12345`
2. **Or use a different port**: `limps server start --port 8080`
3. **Check if it's another limps daemon**: `limps server status` (if so, use `limps server stop` first)
**"Daemon may have failed to start" error:**
If the daemon starts but doesn't respond to health checks:
```bash
limps server start
# Error: Daemon may have failed to start. Check logs or try: limps server start --foreground
```
**Resolution:**
1. **Check daemon log path**: `limps server status` (or run foreground mode: `limps server start --foreground`)
2. **Check for permission issues**: Ensure you have write access to the PID directory
3. **Verify port is accessible**: Try `curl http://127.0.0.1:4269/health`
4. **Enable debug logging**: `DEBUG=1 limps server start --foreground`
**Permission issues with PID directory:**
If you can't create PID files:
```bash
# macOS
ls -la ~/Library/Application\ Support/limps/pids/
# Linux
ls -la ~/.local/share/limps/pids/
# Windows
dir %APPDATA%\limps\pids
```
Ensure the directory exists and you have write permissions. If not, create it manually:
```bash
# macOS
mkdir -p ~/Library/Application\ Support/limps/pids
# Linux
mkdir -p ~/.local/share/limps/pids
# Windows
mkdir %APPDATA%\limps\pids
```
### Health Check Failures
**TIMEOUT error:**
The daemon did not respond within the configured timeout. Each health-check request has its own timeout (for example, 1000ms during the final `limps server start` check and 3000ms for `limps server status`), and during startup limps will poll for up to about 5 seconds before reporting "Daemon may have failed to start".
**Common causes:**
- System resource constraints (high CPU/memory usage)
- Slow filesystem (especially for index initialization)
- Large document corpus requiring time to index
**Resolution:**
1. Check system resources: `top` or Activity Monitor
2. Wait a bit longer and retry: `limps server status`
3. Run in foreground to see progress: `limps server start --foreground`
**NETWORK_ERROR:**
Cannot establish connection to the daemon.
**Common causes:**
- Port is blocked by firewall
- Daemon crashed after starting
- Incorrect host/port configuration
**Resolution:**
1. Verify daemon is running: `limps server status`
2. Check firewall settings for port 4269
3. Try `curl http://127.0.0.1:4269/health` manually
4. Check daemon logs: see `Log:` path in `limps server status` output
### Stale PID Files
limps automatically cleans up stale PID files when:
- Running `limps server status` (discovers and removes stale files)
- Running `limps server start` (removes stale file for the target port)
- The daemon shuts down gracefully with `limps server stop`
If you need to manually clean up PID files:
```bash
# macOS
rm ~/Library/Application\ Support/limps/pids/limps-*.pid
# Linux
rm ~/.local/share/limps/pids/limps-*.pid
# Windows
del %APPDATA%\limps\pids\limps-*.pid
```
**When to manually clean up:**
- After a system crash or forced shutdown
- If `limps server start` reports a daemon is running but it's not
- Before uninstalling limps
### Multiple Daemons Conflict
If you accidentally try to start a second daemon on the same port:
```bash
limps server start
# Error: limps daemon already running (PID 12345 on 127.0.0.1:4269). Run 'limps server stop' first.
```
This is expected behavior — limps prevents multiple daemons on the same port using PID-based locking.
**Resolution:**
1. **Check all running daemons**: `limps server status`
2. **Stop the existing daemon**: `limps server stop`
3. **Or start on a different port**: `limps server start --port 8080`
### Debugging Connection Issues
If MCP clients can't connect to the daemon, verify connectivity step by step:
**1. Check daemon status:**
```bash
limps server status
# Should show daemon running with healthy status
```
**2. Verify health endpoint:**
```bash
curl http://127.0.0.1:4269/health
# Should return JSON with status "ok"
```
**3. Verify MCP endpoint:**
```bash
curl -X POST http://127.0.0.1:4269/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{}}}'
# Should return MCP initialize response
```
**4. Enable debug logging:**
```bash
DEBUG=1 limps server start --foreground
# Watch for connection attempts and errors
```
**5. Check MCP client config:**
Ensure the URL in your client config matches the daemon:
```json
{
"mcpServers": {
"limps-planning-myproject": {
"transport": {
"type": "http",
"url": "http://127.0.0.1:4269/mcp"
}
}
}
}
```
### Config Resolution Issues
**Problem: limps is using the wrong config file**
If `limps config path` shows a different config than expected, use the diagnostic command to understand why:
```bash
limps config show-resolution
```
This shows all three priority levels for config resolution:
1. **CLI `--config` argument** (highest priority)
2. **`MCP_PLANNING_CONFIG` environment variable** (second priority)
3. **Local `.limps/config.json`** (searches up from cwd)
**Common causes:**
- **Environment variable set**: Check if `MCP_PLANNING_CONFIG` is set in your shell or IDE. This takes priority over local config files.
```bash
# Check if set
echo $MCP_PLANNING_CONFIG
# Unset if needed
unset MCP_PLANNING_CONFIG
```
- **Wrong working directory**: Config search starts from your current working directory. Make sure you're in the right directory when running limps commands.
```bash
# Check current directory
pwd
# Navigate to your project
cd /path/to/your/project
```
- **Missing `.limps/config.json`**: The config file must be in a `.limps` subdirectory, not at the project root.
```bash
# Correct location
/path/to/project/.limps/config.json
# Wrong - won't be found
/path/to/project/config.json
```
**Quick fixes:**
```bash
# Override with explicit path
limps plan list --config /path/to/project/.limps/config.json
# Or set environment variable
export MCP_PLANNING_CONFIG=/path/to/project/.limps/config.json
# Or initialize a new config in current directory
limps init
```
## MCP Tools
limps exposes MCP tools for AI assistants:
| Category | Tools |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| **Documents** | `process_doc`, `process_docs`, `create_doc`, `update_doc`, `delete_doc`, `list_docs`, `search_docs`, `manage_tags`, `open_document_in_cursor` |
| **Plans** | `create_plan`, `list_plans`, `list_agents`, `get_plan_status` |
| **Tasks** | `get_next_task`, `update_task_status`, `configure_scoring` |
| **Health** | `check_staleness`, `check_drift`, `infer_status`, `get_proposals`, `apply_proposal` |
| **Knowledge Graph** | `graph` (unified: health, search, trace, entity, overlap, reindex, check, suggest) |
### Knowledge Graph
The knowledge graph builds a structured, queryable representation of your planning documents. It extracts 6 entity types (**plan**, **agent**, **feature**, **file**, **tag**, **concept**) and their relationships (ownership, dependency, modification, tagging, conceptual links). Use it to find conflicts, trace dependencies, and get graph-based suggestions.
```bash
# Build the graph from plan files
limps graph reindex
# Check graph health and conflicts
limps graph health --json
# Search entities
limps graph search "auth" --json
# Trace relationships
limps graph trace plan:0042 --direction down
# Detect conflicts (file contention, circular deps, stale WIP)
limps graph check --json
# Get graph-based suggestions
limps graph suggest dependency-order
```
See [Knowledge Graph Architecture](docs/knowledge-graph.md) and [CLI Reference](docs/cli-reference.md) for details.
### Health & Automation
limps includes automated health checks that detect issues and suggest fixes:
- **Staleness** — Flags plans/agents not updated within configurable thresholds
- **Code drift** — Detects when agent frontmatter references files that no longer exist
- **Status inference** — Suggests status changes based on dependency completion and body content
- **Proposals** — Aggregates all suggestions into reviewable, apply-able fixes
```bash
limps health check --json # Run all checks
limps proposals apply-safe # Auto-apply safe fixes
```
## Skills & Commands
This repo ships Claude Code slash commands in [`.claude/commands/`](/.claude/commands/) and a [Vercel Skills](https://github.com/vercel-labs/skills) skill in `skills/limps-planning`.
**Claude Code commands** (available automatically when limps is your working directory):
| Command | Description |
| ---------------------- | ------------------------------------- |
| `/create-feature-plan` | Create a full TDD plan with agents |
| `/run-agent` | Pick up and execute the next agent |
| `/close-feature-agent` | Mark an agent PASS and clean up |
| `/update-feature-plan` | Revise an existing plan |
| `/audit-plan` | Audit a plan for completeness |
| `/list-feature-plans` | List all plans with status |
| `/plan-list-agents` | List agents in a plan |
| `/plan-check-status` | Check plan progress |
| `/pr-create` | Create a PR from the current branch |
| `/pr-check-and-fix` | Fix CI failures and update PR |
| `/pr-comments` | Review and respond to PR comments |
| `/review-branch` | General code review of current branch |
| `/review-mcp` | Review code for MCP/LLM safety |
| `/attack-cli-mcp` | Stress-test CLI + MCP for robustness |
**Vercel Skills** (for other AI IDEs):
Install the limps planning skill to get AI-powered guidance for plan creation, agent workflows, and task management:
```bash
# Install only the limps planning skill (recommended for consumers)
npx skills add https://github.com/sudosandwich/limps/tree/main/.claude/skills/limps-plan-operations
# Or install all available skills
npx skills add sudosandwich/limps
```
**Available Skills:**
| Skill | Description |
|-------|-------------|
| `limps-plan-operations` | Plan identification, artifact loading, distillation rules, and lifecycle guidance using limps MCP tools |
| `mcp-code-review` | Security-focused code review for MCP servers and LLM safety |
| `branch-code-review` | General code review for design, maintainability, and correctness |
| `git-commit-best-practices` | Conventional commits and repository best practices |
See [`skills.yaml`](./skills.yaml) for the complete manifest of the `.claude/skills` packages installed via `npx skills add` above; the separate `skills/limps-planning/` package in this repo is a legacy distribution and new consumers should prefer the `.claude/skills` method.
## Extensions
Extensions add MCP tools and resources. Install from npm:
```bash
npm install -g @sudosandwich/limps-headless
```
Add to config:
```json
{
"extensions": ["@sudosandwich/limps-headless"],
"limps-headless": {
"cacheDir": "~/Library/Application Support/limps-headless"
}
}
```
**Available extensions:**
- `@sudosandwich/limps-headless` — Headless UI contract extraction, semantic analysis, and drift detection (Radix UI and Base UI migration).
## Obsidian Integration
The `@sudosandwich/limps-obsidian-plugin` package provides deep Obsidian integration:
- **Persistent MCP session** to the limps daemon with auto-reconnect, keepalive, and CLI fallback
- **Document management** — create, update, delete plan documents from within Obsidian
- **Task management** — get next task, update task status (GAP/WIP/PASS/BLOCKED)
- **Search & proposals** — full-text search, proposal review, and auto-apply for safe fix types
- **Health Hub** — sidebar view with daemon, graph, link, and MCP status
- **Directed graph view** — interactive 2D/3D force graph with clickable nodes
- **Scheduled health checks** — periodic staleness, drift, and conflict detection
- **Vault automation** — auto-reindex when plan files change, event-driven refresh
- **Editor diagnostics** — inline link validation
- **Graph sync** to Obsidian surfaces (`.md`, `.canvas`, `.base`)
Full YAML frontmatter support, tag management (frontmatter and inline `#tag`), and automatic exclusion of `.obsidian/`, `.git/`, `node_modules/`.
See [`packages/limps-obsidian-plugin/README.md`](packages/limps-obsidian-plugin/README.md) for setup instructions, commands, and settings reference.

## Development
```bash
git clone https://github.com/paulbreuler/limps.git
cd limps
npm install
npm run build
npm test
```
This is a monorepo with:
- `packages/limps` — Core MCP server
- `packages/limps-headless` — Headless UI extension (Radix/Base UI contract extraction and audit)
## Used in Production
limps manages planning for [runi](https://github.com/paulbreuler/runi), using a separate folder (in this case a git repo) for plans.
---
## Creating a feature plan
The fastest way is the `/create-feature-plan` slash command (Claude Code) — it handles numbering, doc creation, and agent distillation automatically via MCP tools. See [`.claude/commands/create-feature-plan.md`](/.claude/commands/create-feature-plan.md) for the full spec.
You can also run the same steps manually with MCP tools:
1. `list_plans` → determine next plan number
2. `create_plan` → scaffold the plan directory
3. `create_doc` → add plan, interfaces, README, and agent files
4. `update_task_status` → track progress
Plans follow this layout:
```
NNNN-descriptive-name/
├── README.md
├── NNNN-descriptive-name-plan.md
├── interfaces.md
└── agents/
├── 000_agent_infrastructure.agent.md
├── 001_agent_feature-a.agent.md
└── ...
```
Numbered prefixes keep plans and agents lexicographically ordered. `get_next_task` uses the agent number (plus dependency and workload scores) to suggest what to work on next.
## Deep Dive
<details>
<summary><b>Plan Structure</b></summary>
```
plans/
├── 0001-feature-name/
│ ├── 0001-feature-name-plan.md # Main plan with specs
│ ├── interfaces.md # Interface contracts
│ ├── README.md # Status index
│ └── agents/ # Task files
│ ├── 000-setup.md
│ ├── 001-implement.md
│ └── 002-test.md
└── 0002-another-feature/
└── ...
```
Agent files use frontmatter to track status:
```yaml
---
status: GAP | WIP | PASS | BLOCKED
persona: coder | reviewer | pm | customer
depends_on: ["000-setup"]
files:
- src/components/Feature.tsx
---
```
</details>
<details>
<summary><b>Task Scoring Algorithm</b></summary>
`get_next_task` returns tasks scored by:
| Component | Max Points | Description |
| ---------- | ---------- | ----------------------------------------------- |
| Dependency | 40 | All dependencies satisfied = 40, else 0 |
| Priority | 30 | Based on agent number (lower = higher priority) |
| Workload | 30 | Based on file count (fewer = higher score) |
**Biases** adjust final scores:
```json
{
"scoring": {
"biases": {
"plans": { "0030-urgent-feature": 20 },
"personas": { "coder": 5, "reviewer": -10 },
"statuses": { "GAP": 5, "WIP": -5 }
}
}
}
```
</details>
<details>
<summary><b>RLM (Recursive Language Model) Support</b></summary>
`process_doc` and `process_docs` execute JavaScript in a secure QuickJS sandbox. User-provided code is statically validated and cannot use `require`, `import`, `eval`, `fetch`, `XMLHttpRequest`, `WebSocket`, `process`, timers, or other host/network APIs—so it cannot make external calls or access the host.
```typescript
await process_doc({
path: "plans/0001-feature/plan.md",
code: `
const features = extractFeatures(doc.content);
return features.filter(f => f.status === 'GAP');
`,
});
```
**Available extractors:**
- `extractSections()` — Markdown headings
- `extractFrontmatter()` — YAML frontmatter
- `extractFeatures()` — Plan features with status
- `extractAgents()` — Agent metadata
- `extractCodeBlocks()` — Fenced code blocks
**LLM sub-queries** (opt-in):
```typescript
await process_doc({
path: "plans/0001/plan.md",
code: "extractFeatures(doc.content)",
sub_query: "Summarize each feature",
allow_llm: true,
llm_policy: "force", // or 'auto' (skips small results)
});
```
</details>
<details>
<summary><b>MCP Resources</b></summary>
Progressive disclosure via resources:
| Resource | Description |
| ----------------- | ---------------------------- |
| `plans://index` | List of all plans (minimal) |
| `plans://summary` | Plan summaries with key info |
| `plans://full` | Full plan documents |
| `decisions://log` | Decision log entries |
</details>
<details>
<summary><b>Example: Custom Cursor Commands</b></summary>
Create `.cursor/commands/run-agent.md`:
```markdown
# Run Agent
Start work on the next available task.
## Instructions
1. Use `get_next_task` to find the highest-priority task
2. Use `process_doc` to read the agent file
3. Use `update_task_status` to mark it WIP
4. Follow the agent's instructions
```
This integrates with limps MCP tools for seamless task management.
</details>
---
## What is MCP?
**Model Context Protocol** is a standardized protocol for AI applications to connect to external systems. Originally from Anthropic (Nov 2024), now part of the Linux Foundation's Agentic AI Foundation.
- [MCP Specification](https://modelcontextprotocol.io/)
- [MCP Documentation](https://modelcontextprotocol.io/docs)
## License
MIT