Codebase cartographer MCP server — part of the khimaira workspace. Generates and maintains structural documentation: feature CLAUDE.md files, barrel exports, dependency graphs, symbol manifests.
Project description
Scarlet
To find what is hidden, hold a séance. To bind the names you find, give them to Scarlet.
Scarlet now ships inside khimaira as a workspace member at
packages/scarlet/. Its tools are re-registered on khimaira's MCP server under source-prefixed names (mcp__khimaira__scarlet_analyze_project, etc.). The standalonescarlet servepath below still works for backward compatibility.
Scarlet is a codebase cartographer — an MCP server that walks any project, extracts structural metadata via tree-sitter, and generates the documentation scaffolding AI assistants need to actually understand a feature-organized codebase: per-feature CLAUDE.md files, barrel exports (index.js/index.ts), Mermaid dependency graphs, and symbol manifests.
Built for Claude Code, but works with any MCP-compatible client.
The dark cousin of Séance: Séance retrieves knowledge from the dead code via vector search; Scarlet inscribes the names of every entity into a permanent record. Both now live inside the khimaira workspace.
Why "Scarlet"
Named for the Scarlet Woman of Revelation 17 — the figure who sits on a beast "full of names of blasphemy" with a name written on her forehead and a cup full of mysteries in her hand. She is defined by the inscribed names she bears. A catalog walking around in human form.
That maps directly onto what the tool does:
- Catalogs named entities (components, hooks, slices, types, interfaces) from a codebase
- Inscribes them into permanent records — per-feature
CLAUDE.mdfiles, barrel exports, symbol manifests - Surfaces what was hidden — gotchas, invariants, TODOs, deep imports that bypass barrels
Other scarlet threads in scripture reinforce the metaphor:
- Isaiah 1:18 — "though your sins be as scarlet…". Scarlet was the dye that couldn't be washed out; the stain that remained visible. Documentation fixes structure in the same way — makes the shape of a feature indelible so refactors can't silently erase it.
- Rahab's scarlet cord (Joshua 2:18) — a visible marker placed on the house that should be preserved when everything around it is destroyed. Every generated
CLAUDE.mdis a scarlet cord: a feature tied to an inscription so it survives refactors that would otherwise erase its shape.
There's also Hawthorne's Scarlet Letter — a public mark that fixes identity, making a person's defining characteristic impossible to ignore. Scarlet does the same to features: once their symbols are inscribed, their identity is legible to anyone (or anything) reading the record.
And it pairs with its sibling tool in the ritual:
To find what is hidden, hold a séance. To bind the names you find, give them to Scarlet.
Séance is the summoning. Scarlet is the scribe at the ritual — the one who takes down what comes through.
What it does
flowchart LR
A[Any Project] -->|claude mcp add| B[Scarlet MCP]
B --> C[Tools]
C --> D[analyze_project]
C --> E[scan_features]
C --> F[extract_feature_metadata]
C --> G[generate_barrel]
C --> H[build_claude_md]
C --> I[generate_dep_graph]
C --> J[lint_claude_md]
D & E & F & G & H & I & J --> L[Project gets:<br/>CLAUDE.md per feature<br/>Barrel exports<br/>Mermaid dep graph<br/>Lint reports]
The core principle
Deterministic parts run in Python. Judgment parts run in Claude.
| Generated by Scarlet (Python + tree-sitter) | Generated by Claude (synthesis) |
|---|---|
| Public API list | Vocabulary (domain terms) |
| Key files index | Conventions and invariants |
| Cross-feature consumers | Common task recipes |
| Dependency graph | Known issues and gotchas |
| Barrel exports | One-paragraph feature description |
| Symbol manifests | The why behind every "don't do X" |
The tools generate structure. Claude generates meaning. On every CLAUDE.md update, the auto-derivable sections refresh and the human/Claude-written sections are preserved using <!-- BEGIN MANUAL --> ... <!-- END MANUAL --> markers.
Indexing pipeline
flowchart TD
A[Project root] --> B[analyze_project]
B --> C{Detect framework, state mgmt,<br/>features root, package manager}
C --> D[scan_features]
D --> E[For each feature]
E --> F[Walk source files]
F --> G[Tree-sitter parse]
G --> H[Extract exports:<br/>components, hooks, slices,<br/>interfaces, types]
H --> I[Find consumers via import graph]
I --> J[Build skeleton from template]
J --> K{Existing CLAUDE.md?}
K -->|Yes| L[Preserve manual sections,<br/>refresh auto sections]
K -->|No| M[Write new skeleton with<br/>placeholder manual sections]
L --> N[Write CLAUDE.md]
M --> N
The CLAUDE.md template
Every generated CLAUDE.md follows the same shape — auto sections refresh on every update, manual sections persist:
- Description (manual) — one-paragraph summary
- Vocabulary (manual) — domain terms specific to this feature
- Public API (auto) — exported components, hooks, slices, types
- Key files (auto) — every source file with the symbols it defines
- Conventions and patterns (manual) — invariants, idioms, the why behind every rule
- Consumers (auto) — features that import from this one
- Common tasks (manual) — step-by-step recipes
- Known issues and gotchas (manual) — landmines, deprecated patterns
- See also (auto) — cross-references to study guides and rules
Installation
Prerequisites
- Python 3.12+
- uv package manager
Setup
git clone git@github.com:fsocietydisobey/scarlet.git
cd scarlet
uv sync
No API keys required — Scarlet is fully local and stateless.
CLI usage
# Scan a project — overview + feature table
uv run scarlet scan ~/work/jeevy_portal
# Generate or refresh one feature's CLAUDE.md
uv run scarlet describe ~/work/jeevy_portal drawings
uv run scarlet describe ~/work/jeevy_portal drawings --dry-run # preview only
# Refresh all feature CLAUDE.md files
uv run scarlet sync ~/work/jeevy_portal
# Generate a barrel export for a feature
uv run scarlet barrel ~/work/jeevy_portal drawings --ext js
# Generate a Mermaid dependency graph
uv run scarlet graph ~/work/jeevy_portal -o shared-docs/feature-deps.mmd
# Lint all CLAUDE.md files for staleness and missing sections
uv run scarlet lint ~/work/jeevy_portal
# Start the MCP server
uv run scarlet serve
MCP integration
Claude Code
Register globally so it's available in every project:
claude mcp add -s user scarlet -- uv --directory /path/to/scarlet run scarlet serve
Once registered, Claude gets these tools:
| Tool | What it does |
|---|---|
analyze_project |
Detect framework, state mgmt, package manager, feature count |
scan_features |
List all features with state (CLAUDE.md, barrel, counts) |
extract_feature_metadata |
Pull all exports from one feature |
generate_barrel |
Create a barrel export file for one feature |
build_claude_md |
Generate or refresh a feature's CLAUDE.md |
generate_dep_graph |
Output Mermaid or JSON dependency graph |
lint_claude_md |
Validate a feature's CLAUDE.md for staleness |
list_consumers |
Find all features that import from a given feature |
Other MCP clients
{
"mcpServers": {
"scarlet": {
"command": "uv",
"args": ["--directory", "/path/to/scarlet", "run", "scarlet", "serve"]
}
}
}
Configuration
Create a .scarlet.yml at the root of any project to declare conventions:
project_type: nextjs
state_management: redux-toolkit
test_framework: jest
features_root: frontend/src/features
study_guides_path: frontend/study-guides
barrel_export_strategy: re_export_default
This makes Scarlet reusable across projects with different shapes. Without .scarlet.yml, Scarlet uses sensible defaults and detects most things heuristically.
Architecture
graph TB
subgraph "src/scarlet/"
CLI[cli.py<br/>CLI entry point]
SRV[server.py<br/>MCP server]
CFG[config.py<br/>.scarlet.yml loader]
subgraph "analyzer/"
PR[project.py<br/>framework detection]
FT[features.py<br/>feature scanning]
MD[metadata.py<br/>tree-sitter export extraction]
IM[imports.py<br/>import graph walker]
end
subgraph "generator/"
BR[barrel.py<br/>index.js generator]
CM[claude_md.py<br/>CLAUDE.md generator]
DG[dep_graph.py<br/>Mermaid renderer]
TPL[template.py<br/>skeleton template]
end
subgraph "validator/"
LN[linter.py<br/>staleness checks]
end
end
CLI --> PR & FT & MD & BR & CM & DG & LN
SRV --> PR & FT & MD & BR & CM & DG & LN & IM
CM --> MD & IM & TPL
BR --> MD
DG --> IM
Composition with Séance and Serena
Scarlet is the writer. It produces structure for the read tools to consume:
flowchart BT
A[Source Code<br/>ground truth]
A --> B[Serena<br/>LSP - exact symbolic queries]
A --> C[Séance<br/>vector search - semantic queries]
B & C --> D[Scarlet<br/>analysis + writing]
D --> E[Generated Docs<br/>CLAUDE.md, barrels, dep graphs]
E --> F[Architecture MCP<br/>serves curated docs]
| Tool | Question it answers | Mode |
|---|---|---|
| Serena | "Where is symbol X defined? Who calls it?" | Read (LSP-precise) |
| Séance | "Find code related to concept X" | Read (semantic-fuzzy) |
| Scarlet | "Generate or refresh the structural docs" | Write |
| Architecture MCP | "What does the curated map say about X?" | Read (curated prose) |
The four together form a complete loop: Scarlet writes, the others read.
Tech stack
- tree-sitter — AST parsing for Python, TypeScript, JavaScript
- MCP Python SDK — Model Context Protocol server
- Click — CLI framework
- PyYAML — Config file parsing
- uv — Package management
No vector database, no API keys, no embeddings. Scarlet is fully local, deterministic, and stateless.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file khimaira_scarlet-0.2.0.tar.gz.
File metadata
- Download URL: khimaira_scarlet-0.2.0.tar.gz
- Upload date:
- Size: 32.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.12 {"installer":{"name":"uv","version":"0.11.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e8ed65ffd162b993e1c681affe5b074d4fe7ab58b119c9aae0afc050ee0a6b9
|
|
| MD5 |
d7f008c13795a05396e7846bcbff5ad6
|
|
| BLAKE2b-256 |
f2f42239149f79fd0a3f60f4ea8b2d4882181a545a70845d2426bd546e849014
|
File details
Details for the file khimaira_scarlet-0.2.0-py3-none-any.whl.
File metadata
- Download URL: khimaira_scarlet-0.2.0-py3-none-any.whl
- Upload date:
- Size: 38.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.12 {"installer":{"name":"uv","version":"0.11.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42ba64536ca4887cf58aa59cdf2ac618cc3c42bd5a1780aec2842db4c952c862
|
|
| MD5 |
98c7b9f9b114f1d202e620ac873bbcd3
|
|
| BLAKE2b-256 |
b3ba5702acdf123ab1d38cd33c1a2ab3b7db1ec392256d91b01ceefb99ff3d95
|