Bring your coding agent to its senses.
Agents drift, CI is too late, and existing static checks are too slow to run every turn. sensez is a small suite of CLIs that return structured signals — duplication, dead code, cycles, boundary violations, and design smells — in under a millisecond, so the agent can catch itself before the slop compounds.
uv add --dev sensezCoding agents drift because their feedback loop is leaky.
Three things compound on every agent-authored repo. sensez exists because fixing any one of them in isolation doesn't work.
Instructions fade mid-task.
You tell it to respect boundaries, follow SOLID, and think like a staff engineer. A few turns and two context summaries later, it confidently rewrites the same CSV parser a colleague shipped two weeks ago.
Soft signals arrive where nobody acts.
CI is excellent at saying “absolutely not.” It is much worse at saying “this duplication is small, but suspicious.” You cannot block every PR over a few repeated lines, and non-blocking warnings have a natural habitat: ignored forever.
Existing checks can't run every turn.
pylint's symilar took nearly four minutes on its own repository, and that's just duplicate detection. Nothing that takes minutes belongs inside an agent's edit loop.
A small suite of CLIs fast enough to run on every agent turn. Each one returns a short, structured signal — duplication, dead code, cycles, boundary violations, design smells — so the agent can react before the slop compounds, and before CI ever sees it.
A few small Rust CLIs.
Each tool is a single binary you can call from an agent loop, a git hook, or your terminal. The "senses" naming is just a mental model for what each one looks at.
Sniffs out duplication, dead code, import cycles, and design smells your linter and type checker don't own — in a compact format an agent can parse.
Audits the boundaries you declared in sensez.toml. If domain code starts importing the web layer, bonez says so before it ossifies.
Local-only metrics: scans, gate blocks, triage decisions, resolved findings. No telemetry, no source upload — everything stays under .sensez/local-metrics/.
Doc and comment search for first-pass orientation — a lead finder, not a complete code search. Downloads an embedding model on first use, then stays local.
What noze actually looks for.
A small, opinionated set of code smells — the ones agents trip on most often. Each one is tuned to be cheap enough to run on every turn.
Tuple Packing
Agents love returning tuple[int, str, int]. To a human reader, positional tuples hide what each slot means — noze flags them so you can swap in a NamedTuple or dataclass.
Loose Typing
An agent will slap dict[str, Any] on a return type and call it a day. The contract becomes invisible to callers and type checkers. noze nudges you toward a tighter signature.
Duplication
Agents rarely check whether a helper already exists, and confidently re-implement it. noze cross-checks structural duplicates so you don't pay maintenance twice.
Full smell catalogexpand
- Boolean BlindnessBare booleans at the call site — use an enum or keyword args.
- Data ClumpThe same group of values passed together everywhere — bundle them.
- Deep NestingMany levels deep — flatten with early returns.
- Divergent ChangeOne module edited for many reasons — split responsibilities.
- Feature EnvyA method that uses another object's data more than its own.
- God ModuleToo much of the codebase depends on it — a coupling hotspot.
- Heavy Nested FunctionA nested function that grew large — promote it.
- High Cognitive ComplexityHard to follow — branches and loops weighted by depth.
- High Cyclomatic ComplexityMany independent paths — hard to test fully.
- Implicit SchemaA dict accessed by many string keys — an unwritten schema.
- Inappropriate IntimacyTwo classes reach into each other's internals.
- Large ClassToo many methods and responsibilities — split it.
- Literal MembershipBranching on `x in ['a','b']` — use an Enum.
- Long FunctionToo many lines to grasp at once — extract pieces.
- Long Parameter ListToo many parameters — group related ones.
- Loose TypingPublic signature leans on `Any` or untyped — tighten it.
- Magic NumbersUnexplained numeric literals — name them as constants.
- Message ChainLong `a.b.c.d` chains — Law of Demeter.
- Mutated ParameterFunction mutates a caller's argument in place.
- Reassigned ParameterA parameter rebound mid-body — use a local.
- Refused BequestSubclass inherits methods it doesn't use.
- Shotgun Surgery HazardOne change ripples across many modules.
- Split VariableOne local reassigned to mean different things.
- Too Many ReturnsMany exit points — consolidate, or split the function.
- Tuple PackingPositional tuples whose fields aren't named.
Pick your package manager.
sensez ships as two language-native distributions: the Python package analyzes Python projects, and the JS/TS package analyzes JS/TS projects. Pick the one that matches your codebase.
Heads up: the PyPI and npm packages are still on their way to being published. No Cargo, Docker, or Homebrew distributions planned.
Use uv for one-off scans, or add it as a dev dependency.
uvx --from sensez sense noze .uv add --dev sensezpip install sensezOne structural pass. A fraction of the wait.
sensez scans the structural pillars together instead of paying for a chain of narrowly focused tools. Lower is faster; all values are measured wall-clock seconds from the generated benchmark runs.
pylint repository
zod repository
Python › sensez covers all structural pillars in 0.27s. Vulture focuses on dead code; repowise applies custom ranking that includes dead code.
Scale note › symilar checks line-based duplication and took 234.12s. Its bar is capped at 20s so the faster results remain readable.