Repository navigation
Releases
v0.10.0 — Understand the codebase, not just check it
New: codebase-comprehension features
Conformance checking tells you what's wrong. It doesn't help someone dropped
into an unfamiliar repo actually understand what's there. This release adds
that, fully language-agnostic — no framework- or ecosystem-specific parsing.
## Start hereinarchsteer docs/report— ranks core components
by how much internal code depends on them, and separately lists likely
entry points (real exported APIs, nothing internal depends on them).## Component map— a real file-to-file Mermaid dependency graph,
capped to the 25 most-connected components. The existing layer diagram
only ever drew layer-to-layer arrows; this shows the actual edges, e.g.
two different controllers sharing the same dependency.archsteer graph <path>— one component's direct dependencies and
dependents. Noarchsteer init/declared intent required — same posture
asarchsteer xray, built for "I just cloned this and need to orient."- MCP:
current_architecture()now surfaces core components + entry
points; newcomponent_neighborstool for an agent mid-task.
Validated against Spring PetClinic (Java) and Dreamhouse LWC (Apex/LWC) —
no change to conformance scoring, purely additive read-only surfaces.
Full Changelog: v0.9.1...v0.10.0
v0.9.1 — SQL-prose false positives, nested-source-root Python imports
Fixes
- SQL-literal detection no longer misfires on ordinary prose. Strings like
"Select a model","Explicitly select terminal rendering", or"Could not update detection rule"were being read as raw SQL. The heuristic now requires anUPDATEto have a realSETclause and aSELECTto have a realFROMclause (with the entity extracted from that clause, not guessed from the first token) — bounded to the actual containing string/line, not scanned hundreds of lines ahead. Verified on the PetClinic benchmark: a garbledptypedata-store entity is now correctlyPetType; on Dreamhouse LWC, a spurious single-letteraentity is gone and conformance ticks up from 95.3% to 95.9%. - Python absolute imports below a nested source root now resolve.
tools/python/mypkg/api.pyimportingmypkg.store(wheretools/pythonis the realsys.pathroot, common in monorepos) previously stayed unresolved/external. Resolution is conservative: only a unique unambiguous path-suffix match resolves — if two packages could plausibly satisfy the same dotted import, it correctly stays external rather than guessing. - Intel macOS installs stay on a working
cryptographywheel. Pinnedcryptography<49sopip install archsteerdoesn't fall back to a Rust source build on Intel Macs, where a compatible prebuilt wheel exists on the 48.x line. - README: clarified the local first-run flow and where to send feedback.
Validation
40 tests (up from 34), all passing. Spring PetClinic and trailheadapps/dreamhouse-lwc benchmarks re-verified — no regressions, and the SQL-prose fix visibly cleans up both.
Full diff: v0.9.0...v0.9.1
v0.9.0 — Fixes a phantom-worktree bug, adds Next.js App Router support
The headline bug fix
Dogfooding archsteer on its own repo surfaced a real, embarrassing bug: .claude/ was never in the ignore list. A Claude Code subagent's git worktree under .claude/worktrees/<id>/ is a full duplicate checkout of the repo — scanning it double-counted every component, and in one sample run, 100% of the reported "raw SQL" violations turned out to be phantom (0% were real). This affects every user running archsteer inside a Claude Code project, not just this repo. .cursor/, .hg/, and .svn/ are now excluded too.
Next.js App Router support (new)
- New
nextjs-app-routerstarter pack — layers inferred from Next.js's own reserved filenames (page.tsx→page,layout.tsx→layout,route.ts→api, regardless of directory) before falling back to directory names. Rules: data access (Supabase/Prisma/raw SQL) and third-party calls confined tolib/or a route handler; no hardcoded secrets. initnow tells a real Next.js App Router app apart from an Express repo migrating to Next —next+ anapp/dir + noexpressgets the new pack; anything withexpressstill gets the migration-flavoredexpress-to-nextpack, even oncenextshows up as a dependency.- Supabase query detection —
.from("table").select(/insert/update/upsert/delete)(...), including calls chained across lines, now registers as data access (same as the existing Prisma/SQLAlchemy/raw-SQL detectors).
Two false-positive fixes with broad real-world impact
fetch('/api/x')is no longer flagged as an external call. A component calling its own Next.js route handler was previously indistinguishable fromfetch('https://stripe.com/...')— same-origin relative-path fetches are now excluded, and absolute URLs get a real hostname as the destination label instead of a genericHTTP_CLIENT_CALL.@/lib/x-style imports now resolve to real internal edges. This is the default alias in everycreate-next-appproject — withouttsconfig.json/jsconfig.jsonpathsresolution, every one of these imports was textually indistinguishable from a third-party package, leaving the layer diagram edge-less on most real Next.js/TS repos. (Along the way, fixed a bug in the JSONC comment-stripper itself: it read the/inside the string"@/*"as a block-comment start and corrupted the JSON — fixed with a string-literal-aware tokenizer.)
Validation
Re-ran end to end on archsteer's own web/ app: unassigned components dropped from 52% to 14%, the Mermaid diagram went from zero edges to a real page→lib, page→ui, ui→lib, layout→ui, api→lib picture, and the conformance score is now a genuinely exercised 100% (real Supabase calls and real external calls are present and correctly placed) rather than a vacuous one computed against rules that didn't apply to the repo at all. Spring PetClinic (100%) and trailheadapps/dreamhouse-lwc (95.3%) benchmarks unchanged — no regressions.
Full diff: v0.8.0...v0.9.0
v0.8.0 — Incremental parse cache + pre-push quality-score hook
Faster on real repos
Profiling on nestjs/nest (~1700 TS files) showed archsteer check taking 2.9–7s per run — too slow for something meant to run on every git push. The bottleneck was re-parsing every file on every invocation regardless of what actually changed.
build_model now caches each file's extracted component keyed by a content hash in .archsteer/parse_cache.json (gitignored, machine-local). Unchanged files reuse their cached result; only changed files get re-parsed and re-scanned. Cross-file edge resolution still runs over the full component set every time, since a file's imports can resolve differently when other files change. Measured on nestjs/nest: 2.9s cold → ~1.0s warm, whether nothing changed or a single file did. The remaining ~1s is fixed CLI/interpreter startup overhead this change doesn't touch.
Quality score before every push
archsteer check now prints a one-line readout — conformance %, delta since the last snapshot, and net-new violation count — every time it runs, not just on failure.
New archsteer install-hooks wires check into a local git pre-push hook: same non-blocking-on-existing-debt ratchet already used in CI (blocks only NET-NEW error violations), just earlier feedback than waiting for CI. Won't clobber a hook it didn't write without --force; --uninstall removes it cleanly. Already on husky/pre-commit/lefthook? The README now shows wiring archsteer check into those instead.
Also fixes a dead README reference to a hooks/pre-commit file that didn't actually exist in the repo.
Full diff: v0.7.0...v0.8.0
v0.7.0 — Security baseline: hardcoded secrets, external-call layering
New rule types
forbidden_security_finding— flags hardcoded credentials, API keys, and tokens via a language-agnostic regex scan over raw source text: variable-name-shaped assignments (password = "...",api_key: "...") plus high-confidence literal patterns for AWS access keys, GitHub/Slack tokens, and PEM private-key blocks. Runs once per file duringarchsteer map, independent of per-language parsing — covers every extension archsteer already visits, with env-lookup and placeholder-value exclusions to keep false positives down.required_layer_for_external_call— confines outbound HTTP/SDK calls (and Salesforce Apex callouts) to a declared layer, mirroring the existingrequired_layer_for_data_accesscheck but over external calls instead of data access.
Security baseline in every starter pack
java-spring, salesforce, python-service, and express-to-next all now ship two additional rules out of the box, each backed by a new ADR:
no-hardcoded-secrets(error)external-calls-only-in-service(warn) — callouts confined to the service layer in Salesforce, service layer elsewhere
Validation
Spring PetClinic stays 100% conformant with the new rules active (no false positives). trailheadapps/dreamhouse-lwc's existing violations are unchanged — zero new noise introduced by the security rules. The repo's own dogfooded architecture.yaml now adopts no-hardcoded-secrets too.
Full diff: v0.6.0...v0.7.0
v0.6.0 — ADR drafts for widespread rule violations
New
archsteer adr only ever looked backwards — it diffed the current snapshot against the previous one, so a repo's existing, systemic violations (SOQL scattered across a dozen controllers, say) never surfaced as anything an architect could act on. check/govern just listed them one by one.
Added a second, complementary source: a rule violated across 3+ components in the current snapshot is drafted as its own ADR — a standing architectural question ("ratify this as accepted debt, or the rule is wrong for this codebase") regardless of whether time has passed since the last map. Wired into adr, xray, report, and push alongside the existing diff-based drafts.
- A single violation isn't a pattern —
check/governalready surface those individually; this only fires on genuine repetition. - Idempotent: the draft's slug is derived from the rule id, not the violation count, so re-running as counts drift never duplicates a draft already on disk.
- Distinguishes rules that already have a backing ADR (
rule.adrinarchitecture.yaml) from ones that don't, and tailors the context accordingly.
Validation
Same benchmark pair used for 0.5.0: trailheadapps/dreamhouse-lwc (86.4% conformant) now drafts a real ADR reviewing soql-only-in-selectors against its 6 violating files. Spring PetClinic (100% conformant) and archsteer's own dogfooded repo both stay silent, as they should — no violations, nothing to review.
Full diff: v0.5.0...v0.6.0
v0.5.0 — Java + Salesforce Apex support
New languages
The engine parsed JS/TS and Python only — Java and Salesforce repos x-rayed to zero components. Both are now first-class:
- Java (
.java) — layers inferred from Spring annotations first (@RestController/@Controller→ controller,@Service→ service,@Repository→ repository,@Entity→ model), then Spring Data repository interfaces (extends JpaRepository/CrudRepository/...), then class-name-suffix fallback (*Controller,*Service,*Repository/*Dao). Imports resolve to internal dependency edges; JDBC/JPA calls register as data access. - Salesforce Apex (
.cls,.trigger) — since Apex has no imports, dependency edges come from resolving type references (new X(),extends,implements, static calls) against the org's own class names. SOQL registers as a read, DML as a write/delete. Layers come from Salesforce naming convention (*TriggerHandler→ handler,*Controller→ controller,*Service→ service,*Selector→ repository,*Domain→ model,*Batch/*Queueable/*Schedulable→ job, triggers get their own layer).
Starter packs + auto-detection
archsteer init now inspects the repo for build manifests (pom.xml/build.gradle → java-spring, sfdx-project.json/force-app → salesforce, pyproject.toml/setup.py/requirements.txt → python-service, else express-to-next) and seeds a matching baseline architecture.yaml + ADRs — real rules on first run, not a blank slate. Override with --pack if the guess is wrong.
java-spring: persistence only in repositories; controllers must not touch repositories directlysalesforce: SOQL only in selectors; no DML in triggers or controllerspython-service: persistence only in repositories; API layer must not touch repositories directly
Validation
Benchmarked against real repos: Spring PetClinic scores 100% conformant on the java-spring pack (reference app — any violation there means a broken heuristic). trailheadapps/dreamhouse-lwc genuinely violates the salesforce pack (~29 SOQL-in-controller findings) — a positive control confirming the rules fire correctly on real code.
Full diff: v0.4.2...v0.5.0
v0.4.2
Fixes
archsteer steercrashed on real repos that already had a.cursor/rules/directory (Cursor's own convention) — the CLI tried to write a file where a directory existed. Steering now targets.cursor/rules/archsteer.mdcdirectly and injects proper frontmatter (alwaysApply: true) into empty or frontmatter-less.mdcfiles.- MCP registry
server.jsonused a deprecated schema (2025-07-09 snake_case) — the live registry validates against 2025-12-11 camelCase. Fixed field names and trimmed the description under the registry's 100-char limit.
0.4.1 (rolled into this release — no separate tag was pushed)
- Python dependency resolution was broken: relative imports (
from .x,from ..pkg.mod) and same-package absolute imports (from mypkg import mod) were never resolved to internal edges — only JS/TS relative imports were. Every Python repo'smodel.jsonshowed zero internal dependencies. Fixed. - Manifest dependency extraction now reads
project.dependencies(runtime only) viatomllibinstead of a regex that swept up dev-tooling strings and license identifiers. mcppromoted from an optional extra to a base dependency —uvx/registry runners can't express extras, soarchsteer mcpwas failing on a plain install for exactly the agentic audience the MCP listing targets.- archsteer now dogfoods itself: ships its own
architecture.yaml(engine must not import cli/steer/docs/mcp; stays network-free) and passesarchsteer checkclean. - Listed on the official MCP registry (
io.github.einvoice-dev1/archsteer).
Full diff: v0.4.0...v0.4.2
v0.4.0
ArchSteer CLI 0.4.0
- New:
archsteer mcp— a local MCP server so agents (Claude Code, Cursor, etc.) query the live model + declared intent mid-edit. Runs over stdio, spawned by your own editor — no cloud, no auth, no account. Free with the CLI.current_architecture— component/layer counts, conformance/drift, target.get_target_pattern— the invariants for a file, before you write to it.check_file— whether a file conforms, without waiting for CI.
- Optional dependency:
pip install "archsteer[mcp]".
Install: pipx install --upgrade archsteer && pipx inject archsteer mcp
Docs: see the README's "Using with AI agents (MCP)" section.
v0.3.0
ArchSteer CLI 0.3.0
archsteer pushnow reports your repo URL (auto-detected from the git remote) so the situation room deep-links to each repo's committed living docs.report.htmlnow has a footer linking back to the situation room.
Install: pipx install --upgrade archsteer