Command
okulo coupling
Find files or components that change together — including hidden, import-free coupling.
architecturedependencies
When to use it
You suspect hidden coupling, god utilities, or leaky boundaries between layers.
Usage
okulo coupling [repo] [options]
Options
| Option | Default | Description |
|---|---|---|
--level | file | file or component |
--min-shared | 5 | Minimum shared change sets |
--min-degree | 30 | Minimum coupling strength (%) |
--max-changeset | 30 | Ignore oversized change sets |
--cross-only | off | Only pairs that cross components/layers |
--implicit-only | off | Only pairs without a code reference (excludes test pairs) |
--group-by | commit | Use ticket to merge commits with the same ticket id |
Examples
Surprising file pairs
okulo coupling --implicit-only --min-shared 5 Cross-layer architecture smells
okulo coupling --level component --cross-only Ticket-oriented history
okulo coupling --group-by ticket -w all --min-shared 3
Sample output
Illustrative terminal output (column layout matches the real CLI):
Change coupling file level · 842 change sets (12 large and 3 mechanical skipped)
a b degree shared P(b|a) / P(a|b) flags
──────────────────────── ─────────────────────── ────── ────── ─────────────── ─────────────────────────────
src/billing/invoice.py web/checkout/Cart.tsx 72% 18 64% / 58% cross:backend↔frontend implicit
src/billing/invoice.py server/orders/api.go 61% 14 55% / 48% cross:backend↔backend
web/checkout/Cart.tsx web/checkout/Cart.test.tsx 88% 22 90% / 85% test
3 pair(s) · 2 cross-boundary · 1 implicit · 1 test↔subject
How to read it
- degree / shared — how often the pair moves together. High degree + many shared commits = strong temporal coupling.
- P(b|a) — when A changes, how often B does too (directional hint).
- cross:… — crosses architecture layers; often a missing API boundary or shared kernel.
- implicit — no import/reference found: hidden coupling. test pairs are usually expected noise.
Tips
- Raise
--min-sharedon busy repos to cut noise. - Cross-layer pairs often want a clearer module boundary or an extracted shared library.