@lineman-io/mcp
v2.6.0
Published
Lineman MCP server — AI-powered code intelligence for Claude Code
Maintainers
Readme
@lineman-io/mcp
Lineman — AI-powered code assistant that routes data-heavy work (large-file reads, error classification, build-output triage) to a secondary LLM so your primary Claude context window stays free for reasoning.
Lineman's assist tool dispatches to one of these task_type values (from the audit + tool registration in src/server.ts):
File-reading tasks
- read_file — Returns a summary of a file. Params: {path}. The default Lineman path for any file Claude wants to understand without burning context on the verbatim
content.
- read_file_full — Returns verbatim lines, no summarization. Params: {path, offset?, limit?}. Use when you already know the line range you need (cheap; no AI involved,
just file IO).
- read_file_context — LLM identifies the relevant sections of a file given a query and returns those sections formatted for readability. Params: {path, query}. The
middle ground between summary and verbatim.
Content-summarization tasks
- summarize_file — Like read_file but emphasizes a structured summary with explicit source anchors.
- summarize_content — Summarize an arbitrary string (e.g. pasted log/output). Params include {content}.
- summarize_directory — Summarize a directory listing (file tree, what each top-level path contains). Used by Bash routing for find / ls / tree.
- summarize_diff — Summarize a git diff or git log/git show output. Used by Bash routing for git log/diff/show/blame.
- summarize_test_results — Compress test-runner output (pytest, vitest, jest, mocha, npm test) into pass/fail/why summary.
Build / log triage
- triage_build_output — Compress and structurally analyze build-tool output (gradle, mvn, generic large stdout). Returns key errors, warnings, and where they came from.
The Bash echo for build tools points the model here.
- analyze_logs — Similar shape but tuned for runtime log streams.
- classify_error — Take a single error / stack trace and classify it (root cause, category, suggested next step).
Code-structure tasks
- extract_symbols — Pull file's exported symbols / API surface (functions, classes, types) without returning the bodies.
- validate_patch — Given a {file_path, old_string, new_string} candidate, verify old_string actually exists in the file and surface closest-match suggestions on a typo.
Used internally by edit_file to give better error messages.
- grep_filter — Grep over already-fetched content with a structured intent, used to filter long outputs down before the model sees them.
Web tasks
- analyze_web_page — Fetch + compress an HTTP response. Params: {url, query?}. The Bash echo for curl / wget points the model here.
The assist tool dispatches all of these via a single {task_type, params} shape — meaning Claude only needs to remember one tool name; the task_type enum is the
dispatcher.Install (primary — Claude Code plugin)
The plugin bundles the MCP server, lifecycle hooks, and skills as a single unit:
/plugin marketplace add lineman-io/lineman-mono
/plugin install lineman@lineman
/reload-plugins
/lineman:auth/lineman:auth runs the device-code flow inside the Claude Code session — opens a browser, waits for confirmation, writes the token to ~/.goodex/lineman.json. No shell drop required. The npx lineman-mcp auth CLI entry point still exists for headless / scripted setups.
Once authenticated, /lineman:doctor runs a diagnostic checklist (MCP reachable, token valid, tier recognised, hooks installed, last-call latency). Tracked separately as LIN-320 — the doctor + stats MCP tools were dropped in the 2026-04-25 context-mode revert and are pending reactivation.
Install (alternative — MCP only)
If you only want the assist tool and don't want Lineman's lifecycle hooks or auto-routing skill, register the MCP server directly:
claude mcp add lineman -- npx -y @lineman-io/mcpThis gives you a callable tool but no automatic routing — you must invoke Lineman explicitly from prompts. Most users should prefer the plugin install above.
Usage
Once the plugin is installed, the lineman skill auto-loads when your prompt matches a data-heavy trigger ("read the file", "classify error", "summarize build output", etc.) and routes the work through mcp__plugin_lineman_core__assist. Results come back tagged [[LM_SUMMARY]] / [[LM_VERBATIM]] / [[LM_CONTEXT]] / [[LM_RESULT]] and should be treated as authoritative.
User-invocable slash commands:
| Command | Purpose |
|---------|---------|
| /lineman:auth | Run the device-code flow to acquire and save an API token. Required once per machine before assist / edit_file will work. |
| /lineman:doctor | Diagnostic checklist — MCP reachable, token valid, tier recognized, hooks installed, channels capability, last-call latency. Pending reactivation, see LIN-320. |
| /lineman:stats | Session metrics — total assist calls, input tokens saved, output tokens consumed, average latency, savings ratio, and a by-task-type breakdown. Pending reactivation, see LIN-320. |
Statusline (TUI)
Lineman ships a persistent bottom-bar statusline for the Claude Code TUI:
[Lineman] saved 73% / 182.50k tokens across 12 calls
It reads cumulative session-savings state written by the PostToolUse compression hook (Bash / Grep / Glob compressions) and renders zero-model-cost evidence-of-work alongside the standard Claude Code prompt. The per-call [Lineman] saved X% on Bash(...) systemMessage cue is unaffected — the statusline is additive, not a replacement.
Token counts come from gpt-tokenizer (cl100k_base, the GPT-3.5/GPT-4 BPE — approximates Anthropic's tokenizer to within a few percent for typical English + source code), computed once in the hook and stored in the state file. The statusline does no tokenisation at render time. Tokens scale as you'd expect: 256 tokens / 1.25k tokens / 3.65M tokens / 1.24B tokens.
The full lifecycle is direct-JSON from the SessionStart hook: install, refresh, conflict-skip, auto-uninstall-on-disable. No model in the loop, no slash command needed in the common case.
TUI-only. Claude Code desktop and IDE extensions do not render statuslines (only the CLI TUI does). On those surfaces you'll continue to see the per-call savings lines as before.
Auto-install on first startup
On the first SessionStart after claude plugin install lineman@lineman, Lineman writes its statusline script to ~/.claude/lineman-statusline.mjs and patches ~/.claude/settings.json to point at it. The first cue shown is:
[Lineman] Installed savings statusline. Restart Claude Code to see it at the bottom of your terminal.
statusLine config in ~/.claude/settings.json is read once at Claude Code startup — the new statusline takes effect on the next session, not the current one. Quit and reopen Claude Code (or /exit then start a new session).
On every later startup the on-disk script bytes are silently refreshed so plug-in upgrades keep the statusline in sync without re-emitting the install cue.
Conflict — you already have a custom statusLine
The auto-installer refuses to clobber. If you have an existing statusLine configured, the first SessionStart cue is a copy-paste bash one-liner pointing at our setup script (which DOES replace the slot, stashing your prior config for clean restoration):
[Lineman] You already have a custom statusline configured. To migrate to Lineman's
(your previous configuration is stashed and can be restored later), run:
node ~/.claude/plugins/cache/lineman-io/mcp/<version>/statusline/setup.mjs
Then restart Claude Code.The exact path is filled in by the hook — copy-paste it as-is.
Graceful degradation — disabling Lineman
Set LINEMAN_ENABLED=false in your shell and restart Claude Code. The SessionStart hook detects the kill switch and:
- Removes
~/.claude/lineman-statusline.mjs - Restores the prior
statusLineconfiguration (if any was stashed during install) - Removes the install marker
…then emits [Lineman] Disabled — removed savings statusline. Restart Claude Code to apply. Re-enabling (unset the env var) reinstalls on the next startup. Symmetric.
During the brief window between flipping the env var and the next session start, the running statusline renders a muted [Lineman] disabled rather than stale numbers.
Removing the statusline manually
To remove without disabling Lineman entirely, run the same companion script:
node ~/.claude/plugins/cache/lineman-io/mcp/<version>/statusline/remove.mjsIt deletes ~/.claude/lineman-statusline.mjs, removes (or restores the stashed value of) the statusLine field in ~/.claude/settings.json, and removes the install marker. Idempotent — safe to re-run.
Note:
claude plugin uninstall lineman@linemandoes NOT run cleanup scripts (no plug-in uninstall hook in the manifest spec). Run the remove script BEFORE uninstalling the plug-in, otherwise the statusline files are orphaned and need manual cleanup (rm ~/.claude/lineman-statusline.mjsplus removing thestatusLineblock from~/.claude/settings.jsonby hand).
Configuration
User config lives at ~/.goodex/lineman.json:
{
"dataApiUrl": "https://api-data.lineman.io",
"dataStreamApiUrl": "https://api-data-stream.lineman.io",
"controlApiUrl": "https://api-app.lineman.io",
"apiToken": "<set by /lineman:auth>",
"userId": "<set after auth>",
"tier": "free"
}The three URLs map to the three customer-facing Cloud Run services in the Lineman API split (see ADR-0001):
dataApiUrl— sync inference (/lineman/execute,/shape,/metrics,/hook-config)dataStreamApiUrl— streamed inference (/lineman/execute/stream, SSE)controlApiUrl— auth (/auth/device/*,/auth/verify), usage, dashboard
The MCP picks between the data URLs per request based on whether the
task type is in STREAMING_TASK_TYPES (currently triage_build_output).
The legacy serverUrl field is still read for backwards compatibility
on machines that authed pre-split — new writes always populate the
explicit per-plane fields.
Environment variables take precedence over the on-disk config:
| Variable | Overrides | Purpose |
|----------|-----------|---------|
| LINEMAN_DATA_API_URL | dataApiUrl | Sync inference Cloud Run service |
| LINEMAN_DATA_STREAM_API_URL | dataStreamApiUrl | Streaming inference Cloud Run service |
| LINEMAN_CONTROL_API_URL | controlApiUrl | Auth + usage + dashboard Cloud Run service |
| LINEMAN_API_TOKEN | apiToken | Override the saved token (CI / staging) |
All three URL env vars are required to resolve. Missing any of them at
boot results in a fatal startup error naming the missing var. There is
no LINEMAN_API_URL fallback — the per-plane convention is locked
in ADR-0001 and silently collapsing to a single URL re-introduces the
fault lines the split exists to fix.
Auth at use time
Lineman MCP tools (assist, edit_file) always register, even before authentication. Tool calls return a structured not_authenticated error envelope ({ error: { reason: "not_authenticated", message, auth_url } }) until LINEMAN_API_TOKEN is set (or apiToken is written to ~/.goodex/lineman.json via npx lineman-mcp auth). This means a fresh claude --plugin-dir apps/lineman/mcp session always sees the tools listed — the model gets a clear, actionable error pointing at the auth flow rather than silently missing tools — and the moment the env var lands, subsequent tool calls succeed without restarting the MCP server.
Runtime state (metrics, sentinels, pending prompts) is written to $CLAUDE_PLUGIN_DATA/ by the plugin — not to ~/.goodex/. In dev / tests without Claude Code present, it falls back to $TMPDIR/lineman/.
Telemetry
Lineman MCP sends a small, anonymous stream of operational telemetry to Sentry so we can detect outages, fix bugs, and measure activation. We never send raw prompts, source code, file contents, or environment variable values.
What we do send:
- A stable per-machine UUID (
lineman_install_id) generated on first launch. Not tied to your identity until you authenticate. - After authentication, your Lineman user id (
user_idfrom the signed claim). - Tool-call telemetry: tool name, task type, latency, byte counts, savings estimates, error class.
- Activation events:
mcp.first_run,mcp.auth_link_clicked,mcp.auth_completed,mcp.upgraded. - Operating system, Node version, MCP version, runtime host (claude-code / aider / continue / unknown).
What we strip before send:
- All absolute file paths are rewritten —
/Users/<you>/...and/home/<you>/...are replaced with~. - Stack-frame variables named
prompt,content,code,summary,messages,body,input, or anything matchingKEY|TOKEN|SECRET|PASSWORD|API|AUTH|CREDENTIALare blanked. - HTTP request bodies are blanked wholesale.
Disabling telemetry
Two ways, in resolution order:
/lineman:telemetry offfrom inside Claude Code (recommended). Runs thetelemetryskill, persists your preference to~/.goodex/lineman.json::telemetryEnabled. Restart your Claude Code session for the next MCP boot to pick it up. To re-enable, run/lineman:telemetry on.LINEMAN_TELEMETRYenv var (overrides the per-install setting). Useful for shared / regulated environments where the choice should be enforced by config-management rather than per-user.export LINEMAN_TELEMETRY=offAccepted values:
0,off,false,no→ telemetry disabled.1,on,true,yes→ telemetry enabled (overrides the file setting too).- Anything else / unset → fall through to the file setting / default.
In both cases the MCP skips Sentry.init entirely when disabled — no SDK loaded, no events emitted, no install_id sent. There's no silent degraded mode.
Troubleshooting
Run /lineman:doctor. It probes the MCP server, the API token, the configured tier, hook installation, channels capability, and last-call latency, and prints fail entries with actionable details (e.g. "no API token in ~/.goodex/lineman.json"). If everything is green but results look wrong, check $CLAUDE_PLUGIN_DATA/lineman-metrics.jsonl for per-call records.
Requirements
- Node.js >= 20
- Claude Code CLI with plugin support
License
Proprietary — see lineman.io for terms.
