Examples
Watch Enola catch a regression, interpret Rails routes, trace change impact across repositories, replay architecture history, suggest reviewers and check compliance constraints. Eight examples include unedited recordings from Discourse, Mastodon, Chatwoot and Enola itself. Hand-built terminal output is labelled as illustrative.
Tests passing and a green build don't mean the architecture is still sound. With enola install --hooks, a Stop hook grades every session against the baseline it pinned at the start, and hands the verdict back—only when something actually regressed.
→ edit src/domain/orders.ts + import { listOrders } from '../store' → edit src/api/orders.ts ✓ tsc: no errors ✓ tests: 14 passed ✓ PR merged → domain ↔ store cycle shipped — nothing caught it
→ enola.set_baseline() pinned at SessionStart → edit src/domain/orders.ts + import { listOrders } from '../store' → edit src/api/orders.ts → enola.diff_snapshot() Stop hook · 1 regression ✗ FAIL — cycle: src/domain ↔ src/store → edit src/domain/orders.ts - import { listOrders } from '../store' ✓ enola.diff_snapshot() — 0 regressions, calls it done
Measured mechanism · 9 Claude Code headless trials with the gate set to --fail-on=cycles. Enola fails nothing unless a policy names it. Small sample: evidence that the mechanism works, not an effect size. Full methodology.
app/jobs into app/controllers; the agent reroutes the change and finishes with no regression.Claude Code changes EnqueueDigestEmails and checks it against the baseline. Enola reports layers: domain -> controller; the agent routes through SiteSetting instead and lands on zero regressions and no new module-level coupling. bin/rspec and bin/lint both fail on this machine because of a Ruby version mismatch, so the specs are unrun.
Start with a read-only pass. enola --explain shows where coupling is concentrated; those numbers are leads, not findings. The agent investigates one edge, changes the code and checks the result against a pinned baseline. Then the same verdict is reproduced from a clean shell, without trusting the agent’s session.
--explain puts pkg/command near the top for coupling, with 86 outgoing dependencies. The agent investigates those edges, finds one that reaches past internal/providers into a specific provider implementation, and moves that knowledge behind the provider boundary.Recorded on a throwaway clone at 0ab4d24, with no baseline pinned—the agent pins its own. pkg/command imported internal/providers/rubydex directly and named that provider in two string literals. The agent moved that knowledge into internal/providers behind BuiltInInfo and FetchBuiltIn.
Enola reports PASS, dependencies -1, imports -1 and no new module-level coupling. A scope check finds both touched packages with no spillover, and compare_receipts confirms that the two snapshots used equivalent inputs. Cyclomatic complexity rises by 1 in each touched function (9→10 and 3→4). Behaviour is checked against the real binary on every path, including the error path for an unknown provider. One pre-existing internal/providers test failure reproduces on a clean tree and is left alone.
Finally, the same working tree is graded outside the agent session. baseline clear discards the agent’s baseline, git stash -u rebuilds it from git, and enola check returns the same verdict.
Nothing forbade the import. Enola’s declared layer order allows this downward dependency, so go build, go vet and the layer gate remain silent. The import is visible in source; the graph reveals why it matters: the command layer reaches past the provider boundary into one specific implementation.
Ruby has no compiler, import graph or sound find-usages. The recording starts with a falsifiable check: whether Enola expands Rails only: and except: routes correctly. It then shows what those framework-aware facts reveal about Mastodon’s layer boundaries.
Recorded at 348a6689 with Enola 0.4.4. resources :invites, only: [:index, :create, :destroy] yields three routes; resources :filters, except: [:show] yields six without filters#show. Enola recognises rails-mvc at 86% and reports seven controller-layer concerns outside the controller layer. After the layer order is declared in eight lines, the same seven findings return at confidence 1.00.
A new engineer — or a fresh agent session — needs orientation, not a file dump. A top-level snapshot returns the module map and entry points in one pass.
→ enola.explore(target="src/billing") ✓ src/billing — 9 modules, 41 symbols entry BillingService.charge() depends on money · invoices · payments-api exposes 4 routes · 2 queue handlers patterns idempotency keys · retry w/ backoff
Illustrative output showing the shape of an answer, not a measured result.
A common onboarding question. Without a map the agent crawls middleware, servers, and routes one file at a time. With enola. it reads the answer from a single scoped snapshot.
→ list_files src/ → read src/middleware/auth.ts → read src/server/index.ts → grep -r "requireAuth" . → read src/routes/api/users.ts → read src/routes/api/billing.ts → continue following references file by file
→ enola.explore(target="middleware/auth") ✓ Auth applied at src/middleware/auth.ts mounted by src/server/index.ts:42 wraps 47 routes across 6 modules bypassed by 3 public endpoints → one scoped lookup — served from the map
Illustrative comparison of the two exploration paths, not a measured retrieval-cost result.
Before editing a shared symbol, an agent needs its structural blast radius. Grepping for call sites is noisy and misses transitive paths. impact_analysis returns the dependent graph directly, grouped by depth.
→ enola.impact_analysis(target="formatCurrency") ✓ formatCurrency defined in src/lib/money.ts:18 direct dependents 12 symbols · 5 modules transitive reach 38 call sites crosses into billing · invoices · reports ⚠ used in 2 public API responses — review before edit
Illustrative output showing the shape of an answer, not a measured result.
pkg/history.Read
pkg/history.Read, run before the agent touches the symbol.The agent calls Enola ten times. Of the 59 direct dependents, 49 are controllers that raise no layer question and ten cross a layer. Three matches are unrelated. Ruby’s implicit autoloading also means specs that exercise the code indirectly do not appear as edges.
File-by-file exploration does not automatically connect callers and endpoints across repository boundaries. Enola. links repositories into one graph: generate the first snapshot, then add each additional repository with append: true. A reverse traversal can then follow the connection across all of them.
→ enola.traverse(node="POST /charge", direction="reverse") ✓ POST /charge in payments-api/src/routes/charge.ts called by checkout-web src/api/pay.ts:64 mobile-bff src/payments.ts:121 billing-worker jobs/retry.ts:48 3 repos · 4 call sites · 1 deprecated path
Illustrative output showing the shape of an answer, not a measured result.
enola coverage reports three detected calls, two resolved and one unresolved, then names the unmatched call site.The target may live in a repository that was not snapshotted, belong to a third-party endpoint or expose a gap in Enola’s extraction. Enola reports the unresolved call instead of guessing which.
Generated stubs make the path from a gRPC client call to its implementation difficult to follow, especially across languages. Enola. binds each proto RPC to its handler and resolves Go, Python and TypeScript client calls to the same route.
→ enola.explore(target="InventoryService/UpdateInventory") ✓ InventoryService/UpdateInventory in inventory-svc/internal/server/inventory.go:88 bound via handled_by edge · proto inventory/v1/inventory.proto called by reporting-worker jobs/sync_inventory.py:41 (grpc-python stub) admin-console src/api/inventory.ts:19 (connect-es) 2 repos · Go ← Python, TypeScript · 0 unresolved
Illustrative output showing the shape of an answer, not a measured result.
Every other example asks what a change is about to do. This one asks what an earlier change did. Enola. records a graph per commit, so a structural violation can be traced to the revision that introduced it. The result is the same architecture delta the gate would have printed at the time.
enola blame notify finds four events across six revisions; enola show HEAD~2 replays the introducing commit as an architecture diff.The history includes the commit that introduced the finding, the one that resolved it and the dependency and symbol edges behind each. The replay reports one new storage -> delivery layer violation at confidence 1.00.
CODEOWNERS records declared ownership. Commit history shows who has worked in a module. Neither alone tells you whether the author owns the modules that depend on what they changed. Enola combines history with the import graph to suggest reviewers for that ownership gap.
Recorded at cf6ee136, built from main after v0.4.8. Contributor names are pseudonyms: an untracked .mailmap renames authors before Enola reads %aN; no commit or contribution count is changed. Without --reviewers, the check passes without reading an author name. With the flag, the verdict stays unchanged and a routing section reports 55% ownership of app/models/channel, 0% for the author and six dependent modules the author does own.
The reviewer signal follows the major/minor ownership concept studied by Bird, Nagappan, Murphy, Gall and Devanbu in Don’t Touch My Code! (ESEC/FSE 2011). Their 5% threshold and reported correlation are evidence, not a rule declared by your repository—which is why reviewer routing cannot affect Enola’s verdict.
This example defines a compliance boundary in the repository. A policy page lists the files in scope, and each constraint describes a prohibited change and cites the requirement behind it. When a change violates a strict constraint, the check fails and reports the relevant rule, reason and source line.
./run.sh with Enola installed to reproduce it.The example applies seven constraints to a small Go module: six strict and one advisory. A policy page lists the files in the cardholder-data environment. The script then makes three changes: analytics gains an indirect path to card data, a new file is added without being linked from a policy page, and code that handles personal data logs a subject identifier. go build and go vet pass, but Enola reports three strict violations. The ledger also lists two existing exemptions, including the owner, reason and date for each one.
This example checks reachability and policy coverage: which code can reach other code, and which files a policy page includes. It does not check runtime or data properties such as encryption at rest, retention periods, lawful basis or access logging. Enola checks code against a scope that someone has declared; it does not detect sensitive data.
Try it on your repository
Install Enola, generate the graph and give your coding agent the same architecture context.