Skip to content

How Massu Detects Your Repo

Complete reference for the auto-detection engine: detection signals, outputs, and how to override detection rules in massu.config.yaml


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.

SignalWhat It ReadsWhat It Produces
PackageDetectorpackage.json, pyproject.toml, requirements.txt, Pipfile, Cargo.toml, Package.swift, go.mod, pom.xml, build.gradle, Gemfilemanifests[] — language, runtime, dependencies, devDependencies, scripts per manifest
FrameworkDetectorDependency lists from PackageDetectorframeworks map — per-language { framework, router, orm, test_framework, ui }
SourceDirDetectorFilesystem globs for */.<ext> (TS, PY, RS, SWIFT, GO, JAVA, RB)sourceDirs map — per-language { source_dirs, test_dirs, colocated }
MonorepoDetectorturbo.json, nx.json, lerna.json, pnpm-workspace.yaml, package.json#workspaces, Cargo.toml#workspace, WORKSPACE, WORKSPACE.bazelmonorepo{ type, packages[], nested[] }
DomainInferrerOutput of MonorepoDetector + SourceDirDetectordomains[] — suggested DomainConfig entries
VRCommandMapLanguage + test framework from FrameworkDetectorverificationCommands — 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

LanguageFrameworks
Pythonfastapi, flask, django, aiohttp, sanic, starlette
TypeScript / JavaScriptnext, nestjs, fastify, express, hono, sveltekit, nuxt, angular, react, vue
Rustactix-web, axum, rocket, warp
Swiftvapor, swift-nio
Gogin, echo, fiber, chi
Javaspring-boot
Rubyrails, sinatra

Test Frameworks

LanguageTest Framework Signals
Pythonpytest, pytest-asyncio, unittest
TypeScript / JavaScriptvitest, jest, mocha, playwright
Rustcargo (built-in)
Swiftxctest
Gotestify (go test is the default)
Javajunit, junit-jupiter
Rubyrspec

ORMs and Routers

LanguageORMsRouters
Pythonsqlalchemy, peewee, tortoise-orm, django-ormfastapi, flask, django
TypeScriptprisma, drizzle, typeorm, mongoose, sequelizetrpc, graphql, express-router, fastify-router, hono-router
Rustdiesel, sqlx, sea-ormactix-web, axum, rocket
Gogormgin, echo, fiber, chi
Rubyactiverecordrails, 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: false on every glob call
  • Any file whose realpath escapes projectRoot is 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[].

TypeTrigger
turboturbo.json at root
nxnx.json at root
lernalerna.json at root
pnpmpnpm-workspace.yaml
yarnpackage.json#workspaces array
bazelWORKSPACE or WORKSPACE.bazel
genericAny apps/, packages/, services/, libs/, modules/* layout
singleFlat 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 + FrameworkVR-TESTVR-TYPEVR-BUILD
Python + pytestpython3 -m pytest -qpython3 -m mypy .
Python + unittestpython3 -m unittest
TypeScript (any test framework)npm testnpx tsc --noEmitnpm run build
Rustcargo testcargo checkcargo build
Swiftswift testswift buildxcodebuild build
Gogo test ./...go vet ./...go build ./...
Java + Mavenmvn testmvn compilemvn package
Ruby + RSpecbundle 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:

  1. detection.rules.<language>.<framework> — add custom framework signals
  2. verification.<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).

yaml
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: false

verification Config Override

Override the five VR commands on a per-language basis. Keys not set fall through to the built-in table.

yaml
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:prod

detection.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 path
  • reason — 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.