---
title: "Docs · landmine"
url: https://landmine.tech/docs/
updated: 2026-10-23
---

> Install landmine, scan your lockfile for open GitHub issues filed against your exact dependency versions, and give your coding agent a known-bugs list, a pre-edit hook and an MCP server.
> Source: https://landmine.tech/docs/ · Repository: https://github.com/devanshranjan10/landmines

Docs · v0.2

# Everything landmine does, *in one page*.

Scan once, tell the agent first, keep the hook as a backstop. Node ≥ 22.12. The npm package is `landmines`, with an s; it installs the `landmine` and `landmines` commands.

## Quickstart

In your project's root:

```
npx landmines scan             # find the open issues filed against your exact versions
npx landmines install --rules  # known-bugs section in AGENTS.md + CLAUDE.md, plus the pre-edit hook
```

`scan` needs a GitHub token, because GitHub search and GraphQL require auth. It uses `GITHUB_TOKEN`, then `GH_TOKEN`, then `gh auth token`. A token with no scopes is enough for public repositories.

**Start with the rules section.** On landmine-bench it took Claude Sonnet 5.5 from 86% to 99%; the hook alone didn't significantly beat no help. `--rules` writes both. Claude Code doesn't read AGENTS.md, which is why CLAUDE.md gets its own copy.

Re-run `scan` after you change dependencies. The hook only reads the index.

## Install options

```
npx landmines <command>                         # no install
npm i -D landmines                              # dev dependency (recommended for teams)
npm i -g landmines                              # global: `landmine` and `landmines` on PATH
brew install devanshranjan10/tap/landmines      # Homebrew (also: devanshranjan10/tap/landmine)
```

`install` writes the hook command that matches how you installed, so it keeps working for everyone:

| Installed as | Command it writes |
| --- | --- |
| dev dependency | `npx --no-install landmines hook` |
| `npx` / `pnpm dlx` / `bunx` | the pinned `npx -y landmines@<version> hook` |
| global | `landmine hook` |
| source checkout | absolute paths, with a warning |

**Claude Code plugin.** The hook, the MCP server and a `/landmines:scan` command, without touching your settings files:

```
claude plugin marketplace add devanshranjan10/landmines
claude plugin install landmines@landmines
```

**MCP server only.** Any MCP client can run `npx -y landmines mcp` (stdio) after a scan, or connect to the hosted server at `https://landmine.tech/mcp` with nothing to install.

The same package is on GitHub Packages as `@devanshranjan10/landmines`; that needs a token with `read:packages`, so npm is the simpler route. `landmine` (no s) on npm is an unrelated package.

## Teams and CI

```
npm i -D landmines
npx landmines scan && npx landmines install --rules
git add .landmine/index.json .landmine/cards AGENTS.md CLAUDE.md
```

-   **Commit the index.** `.landmine/index.json` (and `.landmine/cards/`) lets teammates and CI share one index. `.landmine/.gitignore` keeps the raw cache and the per-machine install registry out of git.
-   **Pre-commit or CI backstop**, for agents with no pre-edit hook: `npx landmines check --staged --exit-code` checks only the lines a commit adds and exits 1 on a blocking match.
-   **Refresh the index** on a schedule with `npx landmines scan`. If a package can't be fetched, its previous issues are kept, marked stale, and the scan exits 2.

## Commands

Run each as `npx landmines <command>`, or `landmine <command>` after a global install.

| Command | What it does |
| --- | --- |
| `scan` | Reads lockfiles, queries npm, PyPI and GitHub, and writes `.landmine/index.json`. Raw responses are cached for 24 h. Flags: `--refresh`, `--offline` (re-analyse the cache, no network), `--max-issues 100`, `--prod`, `--json`, `-q`. |
| `install` | Adds the hook or plugin for Claude Code plus every agent whose config is in the project. Leaves your other hooks alone; running it again is harmless. `--harness auto|all|<names>`, `--mode block|warn`, `--heads-up`, `--mcp [agents]`, `--rules [files]`. |
| `rules` | Prints, or writes between `<!-- landmine:start/end -->` markers, a short known-bugs section any agent reads, ranked by the APIs your code uses. `--write <files>`, `--skill` (full list as an Agent Skill), `--max 15`, `--rank usage|confidence`. |
| `cards` | Optional. A model reads each indexed issue once and writes a trigger card. At most 50 new model calls per run unless `--all`. `--provider anthropic|claude-cli|openai`, `--model`, `--from`, `--export`. |
| `check <files>` | Treats whole files as just written and reports matches, marked `[blocks: …]` or `[heads-up only]`. `--exit-code [--strict]`, `--json`. |
| `check --staged` | Checks only the lines staged for commit. |
| `lookup <packages…>` | The open issues filed against exact versions, without a lockfile or scan: `lookup next@16.4.0 pandas==2.3.1`. A bare name means the latest. `--pypi`, `--json`. |
| `mcp` | Runs the MCP server over stdio. |
| `list [package]` | Shows indexed issues; by default only the ones the hook can act on. `--all`, `--json`. |
| `share` | One postable line about this project's scan, plus a README badge. Counts and package names only. |
| `uninstall` | Removes landmine's hook entries, plugin files, rules sections and skill. |
| `hook` | The hook entry point: harness payload on stdin, response on stdout. You don't call it yourself. |

## Agents

One normaliser reads every agent's payload shape (tool names, argument keys, patch formats) and answers in that agent's own deny format. live means run end to end against the real agent; "from docs" means built from the agent's documentation (and source, where open) with each payload shape covered by a test.

| Agent | What `install` writes | Verified |
| --- | --- | --- |
| Claude Code | `PreToolUse` hook, `.claude/settings.json` | live 2.1.304: blocked once, agent changed approach |
| Codex CLI | `PreToolUse` on `apply_patch`, `.codex/hooks.json` | live 0.159.0; trust the hook with `/hooks` |
| OpenCode | plugin, `.opencode/plugins/landmine.ts` | loaded live in 1.18.33; a blocked edit not yet run live |
| Cursor | `preToolUse`, `.cursor/hooks.json` | from docs |
| Gemini CLI | `BeforeTool`, `.gemini/settings.json` | from docs |
| GitHub Copilot | `.github/hooks/landmine.json` | from docs |
| Windsurf / Devin | `pre_write_code`, `.devin/hooks.json` | from docs |
| Antigravity | `.agents/hooks.json` | from docs |
| Factory Droid | `.factory/hooks.json` | from docs |
| Augment (Auggie) | `.augment/settings.json` | from docs |
| Kiro | `.kiro/hooks/landmine.json` | from docs |
| Qwen Code | `.qwen/settings.json` | from docs |
| Crush | `crush.json` | from docs |
| Goose | `.agents/plugins/landmine/` | from docs |
| OpenHands | `.openhands/hooks.json` | from docs |
| Trae | `.trae/hooks.json` | from docs |
| Kilo Code | plugin, `.kilo/plugin/landmine.ts` | tested against a stub host |
| Cline | plugin, `.cline/plugins/landmine.ts` | tested against a stub host |
| Amp | plugin, `.amp/plugins/landmine.ts` | tested against a stub host |
| Pi | extension, `.pi/extensions/landmine.ts` | tested against a stub host |
| Freebuff, Aider, Zed, Roo, Continue, Warp… | no pre-edit hook: `rules --write AGENTS.md`, `rules --skill`, `install --mcp`, `check --staged` | rules, skill and MCP config tested |

`install --mcp <agents>` registers the MCP server in the project config of 16 agents: Claude Code, Cursor, Gemini CLI, Qwen, Copilot, Droid, Kiro, Trae, Antigravity, Freebuff, Roo, Warp, Pi, OpenCode, Kilo and Crush. Codex, Windsurf and Cline keep MCP servers in user-level config; for Codex run `codex mcp add landmine -- npx -y landmines mcp`.

## Hook behaviour

-   **Blocks once, then steps aside.** The default `--mode block` denies an edit once per issue per agent session, and only for corroborated matches: the edit uses an issue's symbol *and* the file also uses something else the issue names (an option, a sibling API, the database driver). The retry goes through.
-   **Weaker matches are dropped by default**: on held-out real code about 93% of them didn't apply. `--heads-up` passes them as non-blocking context; `--mode warn` never blocks.
-   **Fast and offline.** About 0.11 s per call including Node startup, with a 149 KB index. It never touches the network.
-   **Never says "allow"**, so your own permission prompts still apply.
-   **Fails open.** Any error, a missing index or an unknown payload means no output, and the edit goes through.

## MCP server

The hook stays quiet unless a match is strong. The MCP server is for when the agent is already looking: a confusing error, behaviour it can't explain, or a dependency it is about to add. Four read-only tools:

-   `landmine_check`: a file in the project, or a snippet, against the scanned index.
-   `landmine_search`: error text or an API name.
-   `landmine_list`: the indexed issues.
-   `landmine_lookup`: any exact version, scanned or not (`next@16.4.0`, `pandas==2.3.1`), for adding or upgrading a dependency. It uses the same GitHub token as `scan`.

```
npx landmines install --mcp claude,cursor    # comma-separated; plain --mcp means Claude Code
```

In a live Claude Code session, asked whether inconsistent `RootModel` equality was a known bug in the pinned pydantic, Claude called `landmine_search` and answered with pydantic#10544, reported against 2.9.2.

Registry name: `tech.landmine/landmine` in the [official MCP Registry](https://registry.modelcontextprotocol.io/v0.1/servers?search=tech.landmine).

## Hosted MCP server

Nothing to install: `https://landmine.tech/mcp` speaks Streamable HTTP and needs no sign-in. It has no project to read, so its tools take exact versions:

-   `landmine_lookup`: the open issues filed against each version, with the evidence and the workaround from the thread. Pass `query` (an error message) to keep only the matching ones.
-   `landmine_check`: a code snippet plus the versions it runs on; returns the issues the code touches.

```
# Claude Code
claude mcp add --transport http landmine https://landmine.tech/mcp

# Codex
codex mcp add landmine --url https://landmine.tech/mcp

# Cursor: .cursor/mcp.json (or ~/.cursor/mcp.json)
{ "mcpServers": { "landmine": { "url": "https://landmine.tech/mcp" } } }

# OpenCode: opencode.json
{ "mcp": { "landmine": { "type": "remote", "url": "https://landmine.tech/mcp" } } }
```

Any other client that supports Streamable HTTP takes the same URL.

Lookups are cached for a day and limited to 60 requests a minute per IP. For a whole project, the CLI is better: `scan` covers every dependency in your lockfile, and `install --rules` puts the result where the agent always reads it.

## Trigger cards

Optional. A model reads each issue thread once and writes a card: the APIs, the extra conditions that make the bug fire, tokens that show the workaround is already applied, and the workaround. Each card is self-checked against the issue's own repro. The hook, rules and MCP server use cards when present; the hook never calls a model.

```
npx landmines cards --provider claude-cli      # uses an existing Claude Code login
npx landmines cards --provider openai          # any OpenAI-compatible endpoint (OPENAI_BASE_URL)
npx landmines cards --provider anthropic       # needs @anthropic-ai/sdk installed
```

Cards are cached per issue, version and model. Each run prints its plan first and caps new model calls at 50 unless you pass `--all`.

## Lockfiles and languages

-   **npm**: `package-lock.json` v1–v3, `npm-shrinkwrap.json`
-   **pnpm**: `pnpm-lock.yaml` 5.4, 6 and 9
-   **yarn**: classic and berry
-   **bun**: `bun.lock` (text; binary `bun.lockb` is not supported)
-   **Python**: `uv.lock`, `poetry.lock`, `Pipfile.lock`, pinned `requirements*.txt`

Only direct dependencies are checked. Source files: JS/TS (`.js .jsx .ts .tsx .mjs .cjs .mts .cts`) and Python (`.py .pyi`), read with a tolerant lexer so half-written code works. In `.vue`, `.svelte` and `.astro` files, template expressions can be missed.

## Exit codes

| Code | Meaning |
| --- | --- |
| `0` | Success. |
| `1` | `check --exit-code` found a match that would block an edit. With `--strict`, a heads-up match counts too. |
| `2` | An error or a partial result: bad input, a scan that couldn't fetch every package, or cards that failed. |

The hook always exits 0 (it fails open), except in the `exit2` format, where a block is exit code 2 with the reason on stderr.

## Security

-   **Untrusted text reaches your agent.** Issue titles, quotes and card summaries come from strangers on GitHub. landmine puts all of it inside one delimited untrusted block, neutralises forged delimiters, strips HTML, caps length, flags quotes that pipe a download into a shell or link unfamiliar hosts, and tells the agent never to follow instructions inside them. Don't let an agent run a quoted workaround without reading it.
-   **Network.** `scan`, `lookup` and the MCP server's `landmine_lookup` send dependency names and versions to registry.npmjs.org, pypi.org and api.github.com. `cards` sends each indexed issue's public thread to the model provider you choose. Nothing else leaves your machine.
-   **The hosted server.** landmine.tech/mcp receives the package versions you look up and any snippet you pass to its `landmine_check`. It caches each package version's result for a day and stores no snippets.
-   **Credentials.** The GitHub token is sent only to api.github.com and never written to the index, cache or logs.
-   **Files.** Only `.landmine/`, the agent config files `install` names, and the marker-delimited rules sections. `install` refuses to rewrite a settings file it can't parse without losing comments.

Report vulnerabilities privately through the repository's [security advisory form](https://github.com/devanshranjan10/landmines/security/advisories/new).

## Uninstall

```
npx landmines uninstall
```

Removes landmine's hook entries, plugin files, rules sections and skill, deletes config files and directories it leaves empty, and skips config it never touched. Delete `.landmine/` to remove the index.
