Workspaces let you declare which services are allowed to depend on which others, then continuously check the live system graph against those rules. This is your team's architecture lint: the intended architecture, expressed as code, verified on every update.
On a hosted workspace, rules and repo tags live in the workspace's Settings tab, under Architecture rules and Repo tags. Use the same matchers described below. The Conformance tab checks them each time it loads, so an edit shows there straight away, with no re-index.
Declaring rules (self-hosted)
On a self-hosted workspace, conformance rules live in a conformance: block in the workspace config
(no separate file). Each rule has a source matcher, a target
matcher, and an allow flag:
repos:
- path: web
alias: frontend
tags: [ui, edge]
- path: services/db
alias: db
tags: [data]
conformance:
rules:
# Deny rules (allow defaults to false): the dependency is a violation.
- source: frontend
target: db
description: The UI must call the API, never the database directly.
- source: "*"
target: legacy-payments
# Tag-based: nothing in the "ui" tier may depend on the "data" tier...
- source: "tag:ui"
target: "tag:data"
# ...except migrations, which are explicitly allowed (an exception).
- source: migrations
target: db
allow: trueA matcher resolves against service nodes in the system graph:
| Matcher form | Matches |
|---|---|
* | every service |
tag:<name> | every service whose repo declares that tag (see tags: on each repo) |
| anything else | a glob over the node id, repo alias, and display name (frontend, api::*, *-worker) |
A rule with allow: false (the default) is a deny rule: a
structural dependency from a matching source to a matching target is a
violation. A rule with allow: true is an exception that whitelists
an otherwise-denied edge. Only structural edges (HTTP, gRPC, event,
package, db) are evaluated; behavioral co-change is never treated as a
dependency.
Dependency cycles
Independently of any rules, conformance detects circular
dependencies among services over structural edges (A → B → … → A). A
cycle means the services cannot be built, deployed, or reasoned about
independently. Cycle detection runs even with zero rules declared, so
every workspace gets it for free.
Using it
Hosted
The workspace's Conformance tab shows the matrix, the violations and the cycles, and links to the rules in Settings. With no rules declared it says nothing was checked rather than reporting zero violations.
CLI (self-hosted)
repowise workspace check prints violations and cycles and exits
non-zero when any are found, so it gates CI:
repowise workspace check # human-readable report; exit 1 on findings
repowise workspace check --json # raw report JSON (still exits 1 on findings)It recomputes from the persisted system graph, so editing rules and re-running picks them up without a full re-index.
REST (self-hosted)
GET /api/workspace/conformance returns the report from the most recent
update, filterable by repo.
MCP
get_conformance exposes violations
and cycles to an agent. It has been opt-in since 0.33.0 rather than
part of the default tool surface, so enable it explicitly if your agent
needs it. The get_risk PR-mode directive gains
conformance_violations and dependency_cycles blocks for the findings
the diff's repo participates in regardless of whether get_conformance
itself is enabled.
Conformance view
The web UI's Conformance page renders a dependency-structure matrix (DSM): services on both axes, each filled cell a dependency tinted by transport, with rule violations ringed red and cycle cells amber. Governance panels list the violations and cycles. Violations also badge the offending edges on the System Map (toggle Conformance), reusing the same additive overlay as the breaking-change guard.
On a self-hosted workspace, because repowise workspace check exits non-zero on any finding, wiring
it into CI turns your declared architecture into a gate: a pull request
that introduces a forbidden dependency or a new cycle fails the build.