AI coding agents regularly ship thirty PRs each week. Do their landings add up to anything recognizable? archwhere places every change — every PR, every task, every agent — on a declared architecture map. The map records which component each change touches, whether that component is a security zone, and what currently needs attention. Beyond that, the map becomes the place where developers converse with their agents.

Traditional architecture tools such as Structurizr or IcePanel depend on a human architect to keep the model current. Without that stewardship, the model rots. CODEOWNERS and labelers map files to owners, but those mappings carry little semantic meaning. archwhere inverts the dynamic: agents maintain the map as a condition of merging. A SKILL.md file tells them how, and archwhere check fails CI when the map goes stale. The result is that developers read components, not diffs.

npx archwhere init drafts the model from the repo

Getting started requires one command: npx archwhere init. That drafts the model from the repository itself — its directory structure, package.json workspaces, and import edges. The tool assigns guessed kinds: auth maps to security, ui to product, scripts to ops. Along with the map, init prints a PR-comment workflow and two agent listeners. From minute one, archwhere check passes; developers rename and refine the model rather than starting from a blank file. The tool also prints a prompt that can be pasted to a coding agent so the agent polishes the model by surveying the repo. The cold-start problem that stalls every architecture-as-code tool is handled automatically.

Daily driver commands

Once the model exists, a handful of commands serve as the daily driver:

  • npx archwhere — shows what the working tree is touching
  • npx archwhere --base origin/main — shows what the branch touches
  • npx archwhere check — CI guard: model valid, no file unmapped, no stale glob
  • npx archwhere check --fix — adopts unmapped files into the nearest component
  • npx archwhere heat — which components churned most in the last 30 days?
  • npx archwhere doc --out ARCHITECTURE.md — exports the model to markdown
  • npx archwhere mission — launches the UI at http://localhost:4610

When an agent's PR adds files the model does not own, the PR comment does more than complain. It suggests the exact patch: adopt the files into the nearest component, or create a new one. Running archwhere check --fix applies the adoption. The map stays alive with no human bookkeeping required. Adding the action - uses: tapaskar/archwhere@v1 (one of the files init writes) ensures every PR gets a comment: a component/kind/files table, security flags, and the system map with touched components highlighted, rendered natively by GitHub.

The mission control UI

npx archwhere mission serves a local UI where the map is the conversation surface. An attention rail runs security → blocked → needs-attention → ready-to-merge. (The Merge button uses the user's token; agents never merge.) Clicking any component opens a thread. Threads are GitHub issues labelled component: (auto-created). The agent answers; the reply appears on the map. Four lenses are available: Structure, Changes, Heat, and Runtime. Heat colours components by git churn over the last 30 days — where agents are actually spending effort. Runtime colours them by live health from any endpoint pointed to via RUNTIME_URL, returning a payload such as {"components": {"": {"status": "ok|warn|bad", "lines": ["…"]}}}.

Agent communication through GitHub

The bus is GitHub — archwhere never talks to an agent directly. The table below summarizes the setup for different agent types:

Your agentSetup
Claudeagent-reply.yml (written by init) answers @claude via the Claude GitHub App
Any agent with an APIagent-webhook.yml POSTs each thread event (component, issue, body, HMAC) to AGENT_WEBHOOK_URL; it replies with its own GitHub token
Anything already watching GitHubnothing to do — have it watch issues labelled component:*

The mention the UI appends is configured in arch/mission.config.json via {"agentMention": "@your-bot"}. The env var AGENT_MENTION overrides it; setting it to "" disables mentions.

One file, declared judgment

The model lives in a single JSON file — not an auto-extracted import hairball. An example:

{
  "system": "Meridian",
  "components": {
    "auth": {
      "name": "Auth & sessions",
      "kind": "security",
      "provider": "Auth0 + RBAC",
      "paths": ["core/auth/**"],
      "watch": [{ "pattern": "session|token|rbac", "note": "security review" }],
      "deps": []
    }
  },
  "lanes": [["web-app"], ["auth"]],
  "flows": { "signup": {
    "name": "...",
    "actor": "...",
    "steps": [{"from": "web-app", "to": "auth", "label": "SSO"}]
  }}

Kinds include core, security, feature, infra, product, ops, and docs. Flows are C4-style dynamic views — the process layer above the components. The full example lives in examples/meridian/architecture.json.

Competing tools compared

maps PRsvisualagents maintain ittalk to agents on it
CODEOWNERS / labeler✓———
Structurizr / IcePanel—✓——
dependency graphs✓hairballn/a—
archwhere✓✓✓✓

From stranger to agent-replies-on-the-map takes under twenty minutes. The full funnel, stage by stage, is documented in docs/ONBOARDING.md. The repository is MIT © Tapas Kar. It is built with and for AI coding agents — the repo's own model lives in arch/architecture.json, of course.