Seamcheck
Your AI wrote 400 lines. Which of them are actually wired to anything?
Seamcheck reads a Django + JavaScript project and tells you what connects to what — which
fetch() lands on which view, which template element the JS is reaching for, which CSS
rule nothing has referenced since 2023. Then it tells you what it couldn't work out,
which turns out to be the part that matters.
No SaaS. No upload. One command, one HTML file, and an exit code for CI.
The four answers
Every dead-code tool ever written has told you something was unused and been wrong, and you stopped trusting it. Seamcheck has a fourth answer:
connected |
something reaches this — here's the file and line |
unresolved |
something reaches for this and it isn't there |
unused |
both ends are observable and nothing uses it |
uncertain |
no evidence either way. Not a claim it's dead. |
That last row is the whole product. A page reached by an <a href> looks exactly like a
dead one if you only parse fetch() calls. Seamcheck says so instead of guessing. On a
700-URL project that's the difference between a report you act on and 668 lies.
It also reports its own coverage — how much of each file it actually reasoned about. No other tool I've found will tell you where it wasn't looking.
What it found in the project it was built on
Not hypotheticals. Real bugs, in a real 36,000-symbol codebase, found while writing this:
- Five CSS custom properties in a loaded stylesheet that resolve to nothing —
--text-primary,--border-colorand friends. Those declarations render nothing today. - An endpoint reported missing that turned out to be
<str:division_id>matching a deliberate'all'sentinel — so I fixed the matcher instead of "fixing" the code. - 65 API routes whose path appears in no source file at all.
- 46 DOM elements written by more than one module — the reason a display bug survives being "fixed" in one of them.
Install
pip install seamcheck
Then two things in settings.py:
INSTALLED_APPS = [..., "seamcheck"]
SEAMCHECK_CONFIG = {
"urlconf_module": "myproject.urls",
"templates_root": "myapp/templates",
"js_source_root": "myapp/static/js",
"css_source_root": "myapp/static/css",
"first_party_prefixes": ["myapp", "myproject"],
}
Every project-specific path lives in that dict. Nothing is hardcoded anywhere in the extractors — which is how this was lifted out of the project it grew in without touching a line of it.
You need Node on PATH. The JS and CSS parsers run on it. You do not need npm or
node_modules — acorn and postcss ship inlined in the wheel. If Node is missing,
Seamcheck says so and gives you the Python half rather than dying.
Use
seamcheck help # every command, one line each
seamcheck scan # scan, summary, snapshot for later diffs
seamcheck check # exit 1 on new findings. This is the CI one.
seamcheck map # the UI, one self-contained HTML file
seamcheck serve # ...opened from your phone
seamcheck explain <id> # one symbol, with the code around it
It finds your project by walking up to the nearest manage.py and reading the settings
module out of it, so it works from anywhere inside the tree. Everything is also available
as python manage.py seamcheck ... if you prefer — same code, one implementation.
The UI
One file, no network, opens on a phone. A left rail of views; a canvas that draws every symbol a page touches at once — 1,366 of them on the biggest page here — with the broken ones filled in red so they find you rather than the other way round.
Click any node and it lights the line through it: page → module → fetch() → URL →
view, each hop with the real source, and a button to show the whole enclosing function.
Or isolate that one chain and drop everything else.
There's a Files view too — your actual folder tree, with a bar per file showing how many of its declarations Seamcheck reasoned about. Because "no findings" and "never looked" are not the same sentence.
seamcheck serve # open it from your phone
seamcheck serve --tunnel # ...from anywhere
Nothing is uploaded. --serve is a socket on your machine that dies with the command.
Per-commit
seamcheck backfill 20 # scan the last 20 commits
Now the map has a commit picker. Pick one and see what that commit changed — added, removed, status flipped — including things it deleted, which no longer exist to be drawn and get named instead.
CI
seamcheck check --since $BASE_SHA
1 = new findings. 2 = no baseline, so the gate didn't run. 0 = clean. That
distinction matters: a gate that never ran is not a gate that passed.
Agents
Seamcheck ships an MCP server, so your assistant can check its own work before it hands it to you. It speaks over stdin/stdout — no port, no daemon, no network.
Claude Code
claude mcp add seamcheck -- seamcheck-mcp
Cursor, Windsurf, Claude Desktop — in the MCP config:
{
"mcpServers": {
"seamcheck": {
"command": "seamcheck-mcp",
"cwd": "/path/to/your/django/project"
}
}
}
cwd matters: Seamcheck reads a real project, so it needs to start in one. It finds the
settings module the same way the CLI does — the nearest manage.py — so the project root
is the right answer.
Four tools: seamcheck_check (scan, report findings new since the last snapshot),
seamcheck_report (the digest), seamcheck_explain (one symbol with its evidence), and
seamcheck_triage (record a disposition).
There is also an AGENTS.md with the one rule that matters:
never delete something because it came back uncertain. That is the scan saying it
has no evidence, not that the code is dead.
What it can't do
Written down because a tool that hides its blind spots is worse than no tool:
- Django + vanilla JS. No React, Vue, or TypeScript yet.
- Celery, Redis, WebSockets and Stripe aren't traced. Anything reached only through those is invisible, and the UI says so rather than showing a confident zero.
- A URL built at runtime stays
uncertain. The prefix is recorded, never a guess. - It has been run against one real project. Mine. That's one more than most tools at this stage and far fewer than you'd want.
Contributing
Issues and PRs welcome. One house rule, and it's the reason the tool is worth anything:
never make a claim the scan can't evidence. If you can't prove it, it's uncertain,
and the note says which evidence source was missing.
License
MIT.
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 seamcheck-0.3.0.tar.gz.
File metadata
- Download URL: seamcheck-0.3.0.tar.gz
- Upload date:
- Size: 224.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
57741d0adf1921a126fb3fc5fe6f4436b9c23fa255d8c70bd1a738a96b9a3991
|
|
| MD5 |
e477a21d28e8a769bc226d0dd2de2485
|
|
| BLAKE2b-256 |
d0431fbbd377c2bbd7cf381cf6211acbc6adc50cb96aecb3ec79b2e4b4a0f71d
|
Provenance
The following attestation bundles were made for seamcheck-0.3.0.tar.gz:
Publisher:
release.yml on dardameiz/seamcheck
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
seamcheck-0.3.0.tar.gz -
Subject digest:
57741d0adf1921a126fb3fc5fe6f4436b9c23fa255d8c70bd1a738a96b9a3991 - Sigstore transparency entry: 2655548295
- Sigstore integration time:
-
Permalink:
dardameiz/seamcheck@9d4eb8bd371311c62859397bea74ec2873a8de12 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/dardameiz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9d4eb8bd371311c62859397bea74ec2873a8de12 -
Trigger Event:
push
-
Statement type:
File details
Details for the file seamcheck-0.3.0-py3-none-any.whl.
File metadata
- Download URL: seamcheck-0.3.0-py3-none-any.whl
- Upload date:
- Size: 196.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eb2b7d17fd017132d99310647446b9c205e0e15eb87cf091de23cae6839ee845
|
|
| MD5 |
de84ad2785c76b54e590a98546af261f
|
|
| BLAKE2b-256 |
10abead25363742e4ce3ae2e65f715d1461b7982b5db944d0cd952f2ac6d3e31
|
Provenance
The following attestation bundles were made for seamcheck-0.3.0-py3-none-any.whl:
Publisher:
release.yml on dardameiz/seamcheck
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
seamcheck-0.3.0-py3-none-any.whl -
Subject digest:
eb2b7d17fd017132d99310647446b9c205e0e15eb87cf091de23cae6839ee845 - Sigstore transparency entry: 2655548306
- Sigstore integration time:
-
Permalink:
dardameiz/seamcheck@9d4eb8bd371311c62859397bea74ec2873a8de12 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/dardameiz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9d4eb8bd371311c62859397bea74ec2873a8de12 -
Trigger Event:
push
-
Statement type: