# Sens

> A project index for Claude Code — query your codebase instead of reading it all. Fewer tokens, cleaner context, and dead-code detection. MCP server + CLI + web dashboard.

- **Type:** MCP server
- **Install:** `agentstack add mcp-iitzsenn-sens`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [iiTzSenn](https://agentstack.voostack.com/s/iitzsenn)
- **Installs:** 0
- **Category:** [Data & Analytics](https://agentstack.voostack.com/c/data-and-analytics)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [iiTzSenn](https://github.com/iiTzSenn)
- **Source:** https://github.com/iiTzSenn/Sens

## Install

```sh
agentstack add mcp-iitzsenn-sens
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

Let the model query your codebase instead of reading it all.
  Fewer tokens, cleaner context, and a heads-up when code already exists or is dead.

  WORKS WITH

  
  &nbsp;&nbsp;&nbsp;&nbsp;
  
  &nbsp;&nbsp;&nbsp;&nbsp;
  
  &nbsp;&nbsp;&nbsp;&nbsp;
  

  Claude&nbsp;Code&nbsp;&nbsp;·&nbsp;&nbsp;Codex&nbsp;&nbsp;·&nbsp;&nbsp;GitHub&nbsp;Copilot&nbsp;&nbsp;·&nbsp;&nbsp;Cursor

---

## Why Sens?

If you use Claude Code on a **subscription**, your pain isn't a per-token bill — it's the **usage limit** and the **context window filling up**. Every time the agent opens 20 files just to orient itself, it burns your quota and bloats the context (which then compacts and quietly loses memory).

Sens keeps a compact **index** of your project and serves it to Claude — through a **hook** that answers the model's searches before they run, a **skill** it loads on demand, or an **MCP** server — so the model asks focused questions instead of reading everything:

> *"where is `login`?"* · *"who uses it?"* · *"does something like this already exist?"* · *"what's dead code here?"*

One engine, two payoffs:

- 🪙 **Fewer tokens / cleaner context** → your subscription lasts longer and long sessions stay sharp.
- 🧹 **Cleaner code** → reuse what already exists instead of duplicating, and surface dead code.

> [!NOTE]
> Sens is **not** a "write-less" rules engine (that's what [ponytail](https://github.com/DietrichGebert/ponytail) does well). Sens is the missing piece underneath: the **project knowledge** that makes "reuse what exists" actually work. They're complementary.

## Contents

- [Quick start](#quick-start) · [What Claude gets](#what-claude-gets-mcp-tools) · [Slash commands](#slash-commands) · [CLI](#cli) · [Dashboard](#dashboard)
- [Does it actually help?](#does-it-actually-help) · [How it works](#how-it-works) · [Configuration](#configuration) · [Dead code](#dead-code--read-this) · [Roadmap](#roadmap) · [License](#license)

## Quick start

Install Sens and set it up in your project:

```bash
npm i -g sens-mcp
cd your-project
sens init
```

`sens init` builds the index, installs a **skill** so Claude knows when to query Sens, wires a **hook** that answers Claude's searches *before they run* (when the model is about to grep for a symbol, Sens returns it and every use directly; a file read gets the outline injected first), and puts your **working rules** in front of the model at the start of every session. Nothing else to start: just work normally and ask Claude naturally (*"any dead code? check with sens"*).

Using another agent? `sens init --agent codex` (or `copilot`, `cursor`, `all`) writes the same guide + rules into that agent's instructions file (`AGENTS.md`, `.github/copilot-instructions.md`, `.cursorrules`) so it drives the `sens` CLI too.

Prefer MCP? (or a host that only speaks MCP)

Add Sens as an MCP server instead. In your project's `.mcp.json` (or Claude Code's MCP config):

```json
{
  "mcpServers": {
    "sens": {
      "command": "npx",
      "args": ["-y", "sens-mcp", "mcp"]
    }
  }
}
```

Or register it once for **every** project:

```bash
claude mcp add sens -s user -- npx -y sens-mcp mcp
```

Claude Code launches Sens on demand — no per-project install, no manual server to run.

## What Claude gets

The same set of operations, whether Claude runs them as `sens` commands (driven by the skill/hook) or as MCP tools:

| Operation | What it does | Replaces |
| --- | --- | --- |
| `project_map` | A one-screen map of the repo with each file's exports | Reading many files to orient |
| `find_symbol` | Where a symbol is defined (file:line + signature) | `grep` |
| `who_uses` | Every place a symbol is used | `grep` + reads |
| `file_outline` | A file's signatures, without its bodies | Reading the whole file |
| `already_exists` | Whether something matching keywords already exists | Duplicating by accident |
| `explain_symbol` | A symbol's callers and callees (call-graph neighborhood) | Reading files to trace a function |
| `symbol_path` | The shortest chain of calls connecting two symbols | Manually following the call chain |
| `dead_code` | Unused symbols / exports (candidates) | — |
| `file_dependencies` | What a file imports and what imports it (import graph) | Grepping for imports across the project |

## Working rules

Sens's MCP server also hands Claude a short set of **working rules** it follows when writing or changing code — reuse what exists instead of duplicating, keep code minimal but maintainable, and leave nothing orphaned — each tied to the tool that lets it *verify* the rule (`already_exists`/`find_symbol` before writing, `dead_code` before finishing, `who_uses` before a rename). The rules are **composable modules** (search-first, minimal, no-orphans, optimization, plus opt-in error-handling and testing). `sens init` wires a `SessionStart` hook that injects the active modules at the start of every session, so they apply automatically. Enable/disable modules or add your own in `sens.config.json`, from the **dashboard's "Working rules" panel**, or see their state with `sens rules --list`. Run `sens rules` to print the active set, or `sens rules --write` to drop a `SENS_RULES.md` you can reference from your `CLAUDE.md` / `AGENTS.md`.

## Slash commands

Sens also registers prompts, so it shows up in Claude Code's `/` menu:

| Command | Does |
| --- | --- |
| `/sens map` | Compact project map |
| `/sens dead-code` | List dead-code candidates |
| `/sens find ` | Locate a symbol |
| `/sens exists ` | Check for existing code before writing |
| `/sens rules` | Load the working rules and follow them |
| `/sens dashboard` | Open the web dashboard (graph) |

## CLI

You can also drive Sens yourself:

```bash
npx sens-mcp init           # set up here (--agent codex|copilot|cursor|all for other agents)
npx sens-mcp index          # build/update the index (cached by file mtime)
npx sens-mcp map [subdir]   # compact project map
npx sens-mcp find     # where a symbol is defined
npx sens-mcp who      # where a symbol is used (--full for every call site)
npx sens-mcp explain  # a symbol's callers and callees (call graph)
npx sens-mcp path     # shortest chain of calls between two symbols
npx sens-mcp outline  # a file's signatures, no bodies
npx sens-mcp exists  # does something like this already exist?
npx sens-mcp dead-code      # unused symbols (candidates)
npx sens-mcp deps     # what a file imports and what imports it
npx sens-mcp report         # self-contained HTML report → .sens/report.html
npx sens-mcp dashboard      # interactive web dashboard
npx sens-mcp rules          # print active rules (--list for module states, --write to save)
npx sens-mcp skill          # print the Claude Code skill (--write to install it)
npx sens-mcp usage          # which Sens tools the model has actually called
```

> Installed globally (`npm i -g sens-mcp`) the command is just `sens `.

Every command shares one modern look — a braille spinner while indexing, a consistent `sens › ` header, and color that *means* something (green ok, red error, yellow warning, gray for paths/counts/timings). Errors stay a single clear line; add `--verbose` for the full stack trace. This styling is **terminal-only**: what the model reads over the MCP server or the hook stays plain text, so nothing here bloats its context.

## Dashboard

`sens dashboard` starts a local web UI (default `http://localhost:4319`):

- an **interactive graph** of your project — files as nodes, imports as edges (drag, click a node to see its symbols);
- live **stats** and a clickable **dead-code** list;
- a symbol **search**;
- a **Working rules** panel to toggle rule modules on/off and add your own;
- a one-click **Connect to Claude Code** (writes `.mcp.json`) and a **Rebuild index** button.

```bash
npx sens-mcp dashboard --root . --port 4319   # --no-open to skip opening the browser
npx sens-mcp dashboard --host                 # also expose on your LAN (prints a Network URL + QR)
npx sens-mcp dashboard --tunnel               # also get a public URL via cloudflared/ngrok if installed
```

> `--host` / `--tunnel` are opt-in and guarded by an access token in the printed link, because the dashboard can **write** your project's config. By default it binds to `localhost` only.

  
  
  

Nodes are files; blue = has exports, gray = internal, red = has dead code. Light &amp; dark themes, multiple graph layouts (network, chord, arc, treemap…).

## Does it actually help?

A reproducible benchmark suite ([`bench/run.ts`](bench/run.ts)) measures this on Sens's own repo and fixtures — run it yourself with `npm run bench`. No estimates, no anecdotes: every number below comes straight from that script.

| Metric | Result | How it's measured |
| --- | --- | --- |
| Size to **orient** in a project | **~97% fewer characters** | `project_map` output vs. concatenating every file in `src/` |
| **Re-index** when nothing changed | **~100\u2013125\u00d7 faster** *(varies by run/hardware)* | median cold build (`force: true`) vs. median cached read, 5 runs each |
| **Duplication** | caught *before* writing | `already_exists("subtract two numbers")` surfaces the existing `subtract` |
| **Dead code** false positives | **0 out of 8** labeled symbols | against fixtures with known used / dead / object-shorthand-referenced symbols |

> Re-run `npm run bench` on your own machine or project to reproduce (or challenge) these numbers. Re-index speed varies with CPU and disk, so treat it as a range, not a fixed multiplier.

## How it works

Pluggable per-language parsers behind one language-agnostic index. Sens walks your source (respecting `.gitignore`), extracts top-level symbols with compact signatures, resolves references, and caches the result in `.sens/index.json` — only rebuilt when file mtimes change; a schema version invalidates stale caches across upgrades.

**Languages:**

- **JavaScript / TypeScript** (`.ts .tsx .js .jsx .mts .cts`) via [ts-morph](https://ts-morph.com) — cross-file references are resolved *semantically* (it follows your imports).
- **Python, Go, Rust, Java, C#, C, C++, PHP, Ruby, Kotlin** via [tree-sitter](https://tree-sitter.github.io/) — functions, classes/structs, methods, constants, and an import graph per file.

Everything lands in one language-agnostic index, so a mixed repo (e.g. a TS frontend + a Python or Go backend) is indexed as a single project. For the tree-sitter languages, cross-file references are resolved *by name* — the best a syntax-only parser can do without whole-program type inference — so `who_uses` / `dead-code` are slightly more approximate than for JS/TS: they over-count rather than miss, which keeps dead-code candidates conservative. Adding a language is a small self-contained parser (`src/indexer/languages/`); more are on the roadmap.

## Configuration

Optional `sens.config.json` at your project root:

```json
{
  "ignore": ["**/generated/**"],
  "entryPoints": ["src/public-api.ts"]
}
```

- **`ignore`** — extra globs to skip (on top of `.gitignore`, `node_modules`, `dist`).
- **`entryPoints`** — files whose exports are your public API, so they're never flagged as dead. `**/index.*` files are treated as entry points by default.

## Dead code — read this

Dead-code results are **candidates**, not certainties. Sens can't see:

- dynamic usage (string-based access, reflection);
- framework "magic" (e.g. Vue/Nuxt auto-imported components — SFC support is on the roadmap);
- a public API meant for external consumers (use `entryPoints`).

Test files count as usage sources but are never themselves reported as dead. **Verify before deleting.**

## Roadmap

- [ ] Enforcement hook (warn/block when an edit introduces dead code or a duplicate)
- [ ] Semantic `already_exists` (embeddings) + near-duplicate detection
- [ ] More languages via tree-sitter; Vue/Svelte SFCs
- [ ] Dashboard: symbol-level graph, live file watching
- [x] A reproducible benchmark suite (`npm run bench`)

## Contributing

Issues and PRs welcome. To develop locally:

```bash
npm install
npm run build      # bundle to dist/
npm test           # vitest
npm run typecheck
```

`npm link` makes `sens` a global command pointing at your local build.

## License

[MIT](LICENSE) — do what you want, just keep the copyright notice. See the note below on why.

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [iiTzSenn](https://github.com/iiTzSenn)
- **Source:** [iiTzSenn/Sens](https://github.com/iiTzSenn/Sens)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-iitzsenn-sens
- Seller: https://agentstack.voostack.com/s/iitzsenn
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
