How Massu Detects Your Repo
massu init runs a pure-filesystem detection engine that identifies languages, frameworks, source layouts, monorepo structure, and verification commands without any network calls, child processes, or database writes. The result is written to massu.config.yaml with schema_version: 2.
Detection runs in packages/core/src/detect/ and is exposed through runDetection(projectRoot). This page documents every signal the engine reads, every field it produces, and how to override the built-in rules.
Detection Signals
Five independent detectors compose into a single DetectionResult. They run in dependency order: packages first, then frameworks, then source/monorepo in parallel, then domains and VR commands.
| Signal | What It Reads | What It Produces |
|---|---|---|
PackageDetector | package.json, pyproject.toml, requirements.txt, Pipfile, Cargo.toml, Package.swift, go.mod, pom.xml, build.gradle, Gemfile | manifests[] — language, runtime, dependencies, devDependencies, scripts per manifest |
FrameworkDetector | Dependency lists from PackageDetector | frameworks map — per-language { framework, router, orm, test_framework, ui } |
SourceDirDetector | Filesystem globs for */.<ext> (TS, PY, RS, SWIFT, GO, JAVA, RB) | sourceDirs map — per-language { source_dirs, test_dirs, colocated } |
MonorepoDetector | turbo.json, nx.json, lerna.json, pnpm-workspace.yaml, package.json#workspaces, Cargo.toml#workspace, WORKSPACE, WORKSPACE.bazel | monorepo — { type, packages[], nested[] } |
DomainInferrer | Output of MonorepoDetector + SourceDirDetector | domains[] — suggested DomainConfig entries |
VRCommandMap | Language + test framework from FrameworkDetector | verificationCommands — per-language { test, type, build, syntax, lint } |
Supported Languages and Frameworks
The detector classifies manifests into one of eight languages: typescript, javascript, python, rust, swift, go, java, ruby. For each language, framework detection recognizes the dependencies in the table below.
Web Frameworks
| Language | Frameworks |
|---|---|
| Python | fastapi, flask, django, aiohttp, sanic, starlette |
| TypeScript / JavaScript | next, nestjs, fastify, express, hono, sveltekit, nuxt, angular, react, vue |
| Rust | actix-web, axum, rocket, warp |
| Swift | vapor, swift-nio |
| Go | gin, echo, fiber, chi |
| Java | spring-boot |
| Ruby | rails, sinatra |
Test Frameworks
| Language | Test Framework Signals |
|---|---|
| Python | pytest, pytest-asyncio, unittest |
| TypeScript / JavaScript | vitest, jest, mocha, playwright |
| Rust | cargo (built-in) |
| Swift | xctest |
| Go | testify (go test is the default) |
| Java | junit, junit-jupiter |
| Ruby | rspec |
ORMs and Routers
| Language | ORMs | Routers |
|---|---|---|
| Python | sqlalchemy, peewee, tortoise-orm, django-orm | fastapi, flask, django |
| TypeScript | prisma, drizzle, typeorm, mongoose, sequelize | trpc, graphql, express-router, fastify-router, hono-router |
| Rust | diesel, sqlx, sea-orm | actix-web, axum, rocket |
| Go | gorm | gin, echo, fiber, chi |
| Ruby | activerecord | rails, sinatra |
Source Directory Detection
SourceDirDetector globs each project for known file extensions (.ts/.tsx, .py, .rs, .swift, .go, .java, .rb), clusters hits by top-level path segment, and classifies each file as source vs test using patterns like test.go$, .test.tsx?$, test.py, and Tests/.
Security Rules
followSymbolicLinks: falseon every glob call- Any file whose
realpathescapesprojectRootis filtered out post-glob - Secret-like paths are excluded:
/.env,/.env.,/.pem,/.key,/.aws/,/.ssh/,/credentials.json,/.p12,*/.pfx - The detector never reads file contents, only filenames
Ignored Directories
node_modules, .venv, dist, build, .build, target, .next, .nuxt, coverage, .git, .massu, .turbo, .cache, .pytest_cache, .mypy_cache, DerivedData, Pods.
Monorepo Detection
Monorepo detection uses a fixed priority: turbo > nx > lerna > pnpm > yarn > bazel > generic > single. When an outer workspace (turbo, nx, lerna) coexists with an inner package manager (pnpm, yarn), the inner scheme is reported under nested[].
| Type | Trigger |
|---|---|
turbo | turbo.json at root |
nx | nx.json at root |
lerna | lerna.json at root |
pnpm | pnpm-workspace.yaml |
yarn | package.json#workspaces array |
bazel | WORKSPACE or WORKSPACE.bazel |
generic | Any apps/, packages/, services/, libs/, modules/* layout |
single | Flat repo with one manifest |
VR Command Generation
Once language and test framework are known, VRCommandMap.getVRCommands(language, framework, dir) emits the five standard verification commands. When dir is . or empty, commands are emitted without a cd <dir> && prefix.
| Language + Framework | VR-TEST | VR-TYPE | VR-BUILD |
|---|---|---|---|
| Python + pytest | python3 -m pytest -q | python3 -m mypy . | — |
| Python + unittest | python3 -m unittest | — | — |
| TypeScript (any test framework) | npm test | npx tsc --noEmit | npm run build |
| Rust | cargo test | cargo check | cargo build |
| Swift | swift test | swift build | xcodebuild build |
| Go | go test ./... | go vet ./... | go build ./... |
| Java + Maven | mvn test | mvn compile | mvn package |
| Ruby + RSpec | bundle exec rspec | — | — |
See vr-types for the full VR-* catalog and custom type registration.
Overriding Detection
Users override detection in two places in massu.config.yaml:
detection.rules.<language>.<framework>— add custom framework signalsverification.<language>— override VR commands per language
detection Config Override
Add signals that the built-in rule table does not know about. Each entry lists the dependency strings that trigger the framework, with an optional priority. User-supplied priority defaults to 100, which beats every built-in (max built-in priority is 10).
detection:
rules:
python:
my-custom-framework:
signals: ["fastapi-extensions", "my-internal-deps"]
priority: 50
typescript:
my-trpc-fork:
signals: ["@myorg/trpc"]
priority: 150
# To replace built-ins entirely instead of appending:
disable_builtin: falseverification Config Override
Override the five VR commands on a per-language basis. Keys not set fall through to the built-in table.
verification:
python:
test: cd app && python3 -m pytest -q --cov
type: cd app && python3 -m mypy --strict .
lint: cd app && python3 -m ruff check .
typescript:
test: npm run test:unit
type: cd packages/core && npx tsc --noEmit
build: npm run build:proddetection.rules.disable_builtin
Setting detection.disable_builtin: true removes the built-in rule table entirely. Only user-supplied rules run. Use this when you need total control — for example, in a repo where built-in signals produce false positives.
Detection Warnings
When runDetection encounters a malformed manifest (invalid JSON, broken TOML), it appends a DetectionWarning to result.warnings and continues. Warnings surface in massu init as stderr output but do not abort. Each warning includes:
path— relative manifest pathreason— parse error summary
Fix the manifest or add it to your project's .gitignore to suppress.
Drift Detection (Planned)
Phase 5 of the autodetect plan ships a SHA-256 fingerprint over a stable-sorted JSON summary of DetectionResult. See ci-drift-check for the planned CI wiring. The computeFingerprint and detectDrift functions are implemented in packages/core/src/detect/drift.ts as of 1.0.0; the drift-check CI command surface is not in the MVP cut.