living-architecture
living-architecture is a Claude Code plugin (la) and a CLI that keep coding agents from eroding the
architecture of a Python or TypeScript codebase. You draw the modules and the imports allowed between them as a
LikeC4 model, and la-arch-check fails whenever the real imports and the model disagree.
Every PR an agent writes can be reasonable on its own while the codebase still drifts into spaghetti, one small
shortcut at a time. Telling the agent the rules in CLAUDE.md doesn't hold: it will quote a principle back to
you and then add the import that breaks it. So la turns the architecture into a check, like a test. A declared
arrow is the only thing that licenses an import, and no arrow means the import is banned.
- An architecture that is enforced, not just drawn. Elements of the model map to packages or directories,
and their arrows decide which may import which. Existing violations are marked
#legacyand counted against a baseline. Each element can carry arc42 principles with status tags, and agents treat the model and the principles like tests: changing them needs your approval. - A four-stage PR flow.
/la:printerviews you into a Codex-reviewed OpenSpec plan, writes the failing tests, implements until they pass, then loops CI, Codex, CodeRabbit and Sonar reviews until every gate is clean. Each stage resumes from the branch name alone, and the plan is archived with the code. - Refactoring without import churn. Python and TypeScript moves and renames rewrite every import automatically, and the type checker proves nothing was left dangling.
What it looks like
A model in architecture/model.c4 with three packages, where api may use core and core may use store:
python = system 'python' {
api = node 'api' { metadata { package 'shop.api' } }
core = node 'core' { metadata { package 'shop.core' } }
store = node 'store' { metadata { package 'shop.store' } }
api -> core
core -> store
}
An agent adds a shortcut from api straight to store, and the check fails in its review loop and in CI:
$ la-arch-check
model-truth: measured runtime edge python.api -> python.store is missing from the model (import shop.api -> shop.store)
arch_check: 1 finding(s)
The match is exact in both directions. An arrow that no import uses fails too, so the model can't go stale:
$ la-arch-check
model-truth: modeled relation python.api -> python.store has no measured runtime edge
arch_check: 1 finding(s)
The model is also rendered as a mermaid diagram into the arc42 docs that agents read before every change, and the
check fails when a diagram is out of date. Try the whole loop in five minutes with the
quickstart example,
or see the model this repo checks itself against in
architecture/system.arc42.md.
Install
# the plugin
/plugin marketplace add MotleyAI/living-architecture
/plugin install la@living-architecture
# the commands (la-*, dr-*), pinned to the same version as the plugin, from your repo's ecosystem
uv tool install living-architecture==0.4.0 # Python repos (Python >= 3.11)
npm install -g living-architecture@0.4.0 # TypeScript/JavaScript repos (Node >= 22)
The commands come as a PyPI package and an npm package of the same name, with identical behaviour. Each serves its own ecosystem natively, needs nothing from the other in a single-language repo, and calls the other for the other language's files in a mixed repo (details). Skills check that the installed commands match the plugin before they run.
living-architecture.yaml records the repo's format version. After an upgrade that changes the format, most
commands refuse to run on the repo until you run la-arch-migrate once, and la-doctor says so.
Quick start
Just the architecture check
You don't need the plugin or the PR flow to enforce the architecture. Tell the checker where your code lives in
architecture/index.yaml:
python:
root_package: mypkg # the package the model's python root maps to
source_root: src # optional
legacy_arrows: {baseline: 0}
Then declare in living-architecture.yaml, at the repo root, that the repo has an architecture model:
architecture: true
Stamp the repo format, write a first model from the imports the code has today, and check it:
la-arch-migrate # adds format: to living-architecture.yaml
la-arch-scaffold # writes architecture/model.c4, views.c4 and system.arc42.md from the measured imports
la-arch-check
The scaffold allows every import that exists, so the first check passes once any OpenSpec specs you have are
mapped to elements. Then mark the arrows you don't want as #legacy, set legacy_arrows.baseline to their count
and run la-arch-diagrams. That is the one time to raise the baseline. To retire a legacy arrow later, remove it
together with the imports behind it and lower the baseline to the new count, all in one change: the check fails
on an arrow or an import left alone, and on any difference between the count and the baseline. TypeScript and
mixed repos are set up the same way; see
Configuration.
Pin the check in CI to a release, in your ecosystem's form:
# Python
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
- run: uvx --no-build --from living-architecture==0.4.0 la-arch-check
# TypeScript
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
- run: npx -y -p living-architecture@0.4.0 la-arch-check
When you move the pin to a release with a newer repo format, first run that release's la-arch-migrate and commit
the result: the check refuses a repo in an older format.
The whole flow
In the repo you want to onboard, run:
/la:init
It detects your tracker, test, lint and type-check commands, Codex, Sonar and any existing OpenSpec or
architecture setup, then proposes a living-architecture.yaml and asks only about what it cannot detect. It then
offers to set up OpenSpec, record the type-check baseline and build the architecture model with /la:arch-init.
After that, start each change with /la:pr on a branch named after its issue.
Skills
| Skill | Purpose |
|---|---|
la:init |
Onboard a repo: detect its tools, write living-architecture.yaml, offer the next setup steps |
la:pr |
Run a change through plan → failing tests → implementation → review |
la:arch-init |
Build the first architecture model from the measured code, then its principles |
la:arch-cleanup |
Retire a batch of #legacy arrows, or carve a new boundary, with verified moves |
la:deterministic-refactor |
Rename or move Python or TypeScript code, proven complete by the type checker |
These skills call helper skills that you can also run on their own; see Skills.
How it differs from other import checkers
Import-boundary checkers already exist: import-linter for Python,
and dependency-cruiser,
eslint-plugin-boundaries and
Nx module boundaries for TypeScript. They check
imports against rules you write in a config file. la differs in what the rules are and what else is held to
them:
- The rules are a diagram. The LikeC4 model is the check, and the same model is drawn into the docs agents read, so the picture and the check can't disagree.
- The model must match the code exactly: an import with no arrow fails, and so does an arrow with no import.
- One model covers Python and TypeScript, in the same repo.
- Grandfathered arrows are counted against a baseline in
architecture/index.yaml, so a new one also changes the baseline, an edit that shows in review. After setup the plugin's skills only ever lower it. - Each element carries principles with status tags (the test that enforces it, the issue that will, or
[review]), whichla-arch-checkverifies and every stage of the PR flow reads before it acts.
If all you need is layer rules for one language and you don't want a diagram, those tools are lighter.
Prerequisites
Always: git, bash, gh (authenticated) and jq.
Per repo language (la-doctor checks them):
| Language | Needs |
|---|---|
| Python | Python >= 3.11; the PyPI package; basedpyright in the project env for the type-check gate |
| TypeScript | node (>= 22) and npx; the npm package; tsc in node_modules for the type-check gate |
The rest is optional. /la:init detects what you have, asks before turning on anything it can't find, and
records the choice in living-architecture.yaml:
| Gate | Needs |
|---|---|
tracker: linear |
the Linear MCP server |
tracker: github |
nothing beyond gh |
openspec: true |
npx (the OpenSpec CLI) |
architecture: true |
npx (the LikeC4 CLI) |
reviewers.codex: true |
the Codex MCP server (mcp__codex__codex) |
| Sonar on your PRs | the SonarQube MCP server |
Background
The ideas behind the plugin, and how it came out of the SLayer codebase, which uses it:
- Why I no longer read code (much): the four-stage PR flow
- How I enforce architecture on coding agents: modularity and principle-based development
- Living architecture, enforced: the LikeC4 import law and the arc42 principles
Documentation
- Living architecture, explained: the problems it solves, one by one
- Quickstart example: the architecture check on a toy repo
- Skills: main and helper skills
- Configuration:
living-architecture.yamland the language sections ofarchitecture/index.yaml - Commands: the
la-*anddr-*commands, and CI - Deterministic refactoring
- Development: working from a checkout, layout, releasing
- Contributing and release notes
Metadata
Release files for living-architecture 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| living_architecture-0.4.0.tar.gz | 121.0 kB | With provenance | Details for living_architecture-0.4.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| living_architecture-0.4.0-py3-none-any.whl | Python 3 | none | any | Details for living_architecture-0.4.0-py3-none-any.whl |
Total release size: 277.5 kB
Release files / living_architecture-0.4.0.tar.gz
| Download URL | living_architecture-0.4.0.tar.gz |
|---|---|
| Size | 121.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2ec5461e386bf4a9597cd16f9702088b385448ebcc191a3cfb4fb7d0dd36539d
|
|
BLAKE2b-256 checksum How to use checksums |
19c40fce5f275a28724330a4af1dc556b1783abee50c94af1dc09a4112bb5d77
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logRelease files / living_architecture-0.4.0-py3-none-any.whl
| Download URL | living_architecture-0.4.0-py3-none-any.whl |
|---|---|
| Size | 156.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
09a29d18ab82818edd05110b8eae5caaa28717e0191d53724869b9be3b3325d9
|
|
BLAKE2b-256 checksum How to use checksums |
bb37776a968a4da4ffdb31f8467cadf8d839a199cc2ee04d94a2eaeb469ec0c9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logSecurity for living-architecture 0.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for living_architecture-0.4.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.