{"slug": "archkeel-coding-agents-declare-architecture-changes-before-they-submit", "title": "Archkeel – coding agents declare architecture changes before they submit", "summary": "Archkeel, a tool from rapiddweller, checks architecture boundaries and declared changes in AI-assisted code by comparing an accepted commit with a candidate and verifying the candidate matches an expectation published before its first submission. The tool catches two failure modes that finding-only diffs miss: architecture changed without being declared, and a scanner seeing less of the program so results look clean only because the graph became blinder. In Fixture A, a refactor introduced no new forbidden import, cycle, or private crossing, but resolved calls fell from 2 of 2 to 0 of 1 and unresolved calls rose from 0 to 1, producing an Archkeel verdict of FAIL with no new finding fingerprints.", "body_md": "**The agent declares before it submits. The check is deterministic.**\n\nArchkeel checks architecture boundaries and declared changes in AI-assisted code. It compares an accepted commit with a candidate, checks their scans against the configured contract, and verifies that the candidate matches an expectation published before its first submission.\n\nIt catches two failure modes that finding-only diffs miss:\n\n- the architecture changed without being declared;\n- the scanner saw less of the program, so the result looks clean only because the graph became blinder.\n\n[Try the demo](#try-the-demo) · [Onboard your project](#onboard-your-project) · [How it works](#how-it-works) ·\n[Reference](https://github.com/rapiddweller/archkeel/blob/main/docs/reference.md) · [Roadmap](https://github.com/rapiddweller/archkeel/blob/main/docs/roadmap.md)\n\nImplemented and planned work is tracked in the [roadmap](https://github.com/rapiddweller/archkeel/blob/main/docs/roadmap.md).\n\nAn agent can keep tests green and introduce no new architecture finding while making the code harder to analyze. If the gate compares finding identities only, that change passes.\n\nFixture A is the smallest example:\n\n``` php\n def run(key: str) -> int:\n-    return first() + second()\n+    handlers = {\"first\": first, \"second\": second}\n+    return handlers[key]()\n```\n\nThe refactor introduces no new forbidden import, cycle, or private crossing. But static call resolution gets worse:\n\n| Observation | Accepted | Candidate | \n|---|---|---|\n| Resolved calls | 2 of 2 | 0 of 1 | \n| Unresolved calls | 0 | 1 | \n| New finding fingerprints | 0 | 0 | \n| Archkeel verdict | baseline | **FAIL** | \n\n``` php\nexpectation_fulfilled: FAIL\nregression check failed in calls_unresolved: 0->1\nregression check failed in unresolved_ratio: 0/2->1/1\n```\n\nArchkeel compares raw measurements as well as finding counts and fingerprints. The ratio check uses integer cross-multiplication, never rounded percentages:\n\n```\nU_candidate × T_accepted <= U_accepted × T_candidate   (when both T > 0)\n```\n\n- **Precommitment with evidence.** The agent publishes the intended change\nbefore it submits the candidate. Git ancestry and host records prove the\norder; author timestamps do not.\n- **Coverage-aware regression checks.** A disappearing edge is not mistaken\nfor an improvement just because a finding disappeared with it.\n- **Explicit uncertainty.** An incomplete scan, broken lock, empty scope, or\nruntime mismatch returns exit`2` with a diagnostic. Unknown never becomes\ngreen.\n\nArchkeel complements tests, linters, and human review. It does not replace any of them. Its job is narrower: keep architecture changes declared, observable, and mechanically checkable.\n\nThe HTML report is designed for a reviewer making a merge decision:\n\n- **Decision first.**`PASS` ,`REJECT` , or`UNVERIFIABLE` and one sentence explaining it are\nvisible before details, in the HTML report and in the terminal.\n- **No blended score.** Scan completeness, contract compliance, expectation matching, Git order\nand publication order remain separate verdicts.\n- **Unknown stays visible.** Missing or invalid evidence includes the affected subject,\nunknown claim, and remedy.\n- **Evidence stays inspectable.** Exact counts, fingerprints, source locations, digests,\nand runtime provenance remain available beside the verdict.\n\nThe demo builds three small Git repositories and runs the real checks. Fixture A is rejected because the call graph got blinder, Fixture B because its expectation was published too late, and Fixture C passes.\n\n```\ngit clone https://github.com/rapiddweller/archkeel.git\ncd archkeel\nmake demo\n```\n\n`make demo-screenshots OUTPUT=<directory>` also captures each HTML report as PNG and each\nterminal view as SVG.\n\nRequirements: Python 3.11+ and a Git repository with at least one commit.\n\n```\nuvx archkeel skill install claude    # or codex\nuvx archkeel init\nuvx archkeel validate\n```\n\n`init` observes the only top-level package and writes `archkeel.toml`,\n`architecture-contract.json` and `docs/architecture/architecture.md`. It proposes one\ncomponent per subpackage and forbids every component pair that is not imported today. Each rule\nstarts with a `TODO:` rationale, so `validate` lists every decision that remains, each with a\nJSON Pointer. Give the prompt in [docs/onboarding.md](https://github.com/rapiddweller/archkeel/blob/main/docs/onboarding.md)\nto your coding agent, or work through the list yourself. The rule catalog is in\n[docs/rules.md](https://github.com/rapiddweller/archkeel/blob/main/docs/rules.md).\n\nTo install it permanently instead, run `pip install archkeel`. Every command explains itself\nwith `archkeel <command> --help`.\n\nObserve the current repository:\n\n```\narchkeel report\n```\n\nThe command writes the canonical `architecture.json` and a self-contained\n`architecture.report.html` beside it. A terminal shows the decision and verdicts; pipes and\n`--json` receive the JSON result.\n\nCheck a candidate against its published expectation:\n\n```\narchkeel check \\\n  --root /repo \\\n  --baseline \"$B\" \\\n  --expectation-commit \"$E\" \\\n  --head \"$H\" \\\n  --expected expectation.json \\\n  --expected-digest \"$DIGEST\" \\\n  --accepted-branch main \\\n  --branch candidate\n```\n\nRun the Python version required by the repository being scanned. A mismatch is\nreported as `runtime_mismatch` with exit `2`, not as broken source code.\n\n``` php\nflowchart TB\n    B[\"Locked accepted state\"] --> O[\"Observe accepted + candidate\"]\n    E[\"Expectation published first\"] --> H[\"Candidate submitted\"]\n    H --> O\n    O --> C{\"Deterministic check\"}\n    C --> P[\"0 · pass\"]\n    C --> R[\"1 · reject\"]\n    C --> U[\"2 · unverifiable\"]\n\n    classDef locked fill:#141414,stroke:#C5F82A,color:#E8E8E2\n    classDef declared fill:#141414,stroke:#5EEAD4,color:#E8E8E2\n    classDef candidate fill:#141414,stroke:#8A8A84,color:#E8E8E2\n    classDef gate fill:#C5F82A,stroke:#C5F82A,color:#0D1F05\n    classDef result fill:#141414,stroke:#2A2A28,color:#E8E8E2\n\n    class B locked\n    class E declared\n    class H,O candidate\n    class C gate\n    class P,R,U result\n```\n\nA check answers three independent questions. It never compresses them into a single score.\n\n| Verdict | Question | Typical failure | \n|---|---|---|\n| `observation_complete` | Did the scan see everything it claims to see? | Incomplete scan, empty scope, rule without subjects | \n| `declared_rules` | Does the code obey the architecture contract? | Forbidden import between components | \n| `expectation_fulfilled` | Did the candidate match the declaration without regressions? | Coverage regression, undeclared change, late expectation | \n\n| Exit | Meaning | \n|---|---|\n| `0` | Complete report or successful check | \n| `1` | Rejected because at least one verdict is `FAIL` | \n| `2` | Unverifiable input, always with at least one diagnostic | \n\nEvery exit `2` diagnostic contains:\n\n```\nkind · subject · unknown_claim · remedy\n```\n\nA broken lock is therefore not interpreted as an empty accepted state.\n\n```\ngitGraph\n    commit id: \"M · accepted\"\n    commit id: \"B · lock only\"\n    branch candidate\n    commit id: \"E · expectation only\"\n    commit id: \"H · implementation\"\n```\n\n| Commit | Contract | \n|---|---|\n| **M** | Accepted state. Archkeel re-observes it. | \n| **B** | Lock-only child of M and tip of the accepted branch. It binds the config, checker, and observation digests. | \n| **E** | Child of B that changes only the expectation file. It must be published before the first submission of H. | \n| **H** | Descendant of E. It must not modify the lock, config, architecture contract, or expectation. | \n\n1. Start from the lock commit **B** .\n2. Write the intended architecture change and commit it alone as **E** .\n3. Publish **E** before submitting implementation work.\n4. Implement the change in one or more commits ending at **H** .\n5. Run `archkeel check` . Fix the code or revise the proposal in a new protocol\ncycle; do not rewrite protected inputs inside H.\n\nFixture B writes its expectation after implementation by deriving it from the observed delta. Its architecture findings are otherwise clean. Archkeel still rejects it:\n\n```\nhost_order: FAIL\nexpectation_fulfilled: FAIL\nexpectation was not published before the first candidate submission\n```\n\nPrecommitment proves \"published before submission.\" It does not prove that no private edit existed before publication.\n\nIn GitLab CI, Archkeel reads merge-request diff versions through `glab` to\nestablish publication order.\n\nFor local testing, replay captured host records:\n\n```\nuv run archkeel check ... --host-records records.json\n```\n\nA local replay validates the record shape and behavior. It does not prove host authenticity.\n\nRun the complete project gate:\n\n```\nmake check\n```\n\nThis runs Ruff, strict mypy, pytest, and Archkeel's self-check.\n\nRun the full release check, build both distributions, and install each one in isolation:\n\n```\nmake release-check\n```\n\nReproduce the protocol fixtures:\n\n```\nmake fixtures\n```\n\n[architecture-contract.json](https://github.com/rapiddweller/archkeel/blob/main/architecture-contract.json)\nholds Archkeel to the rules it sells, and every rule was proven by a deliberate violation:\n\n- **Closed world.** Seven components; every ordered pair is either one of the ten observed\nimports or forbidden with a rationale. The[architecture guide](https://github.com/rapiddweller/archkeel/blob/main/docs/architecture/archkeel.md) explains each allowed edge in the single marked component graph.\n- **Deterministic core.**`ir` and`check` never import adapters or presentation; the CLI is\nthe composition root. The analyzer may import only`archkeel.ir.model` and`archkeel.ir.codec` .\n- **No dynamic shortcuts.**`getattr` ,`hasattr` ,`cast` ,`eval` ,`exec` , dynamic imports and`type: ignore` are forbidden everywhere.\n- **Confined dependencies.**`packaging` only in the analyzer runtime gate,`rich` only in the\nterminal view,`rich_argparse` only in the CLI.\n- **Complete and acyclic.** Every module belongs to exactly one component, and components form\nno cycle.\n\n`make check` reobserves the repository and compares it with\n[fixtures/D-self](https://github.com/rapiddweller/archkeel/blob/main/fixtures/D-self/result.json);\nCI also runs `archkeel validate` and uploads the self-observation.\n\nArchkeel is deliberately strict about what it can prove:\n\n- **Competing implementations:** review is still required when no declared rule\nor observed regression exposes them.\n- **Private crossings:** only import records are checked.`import pkg; pkg._member` is not detected.\n- **Precommitment:** publication order is proven; private editing order is not.\n- **Analyzer runtime:** Archkeel's Python must be at least the target\nrepository's Python.\n- **Acceptance:**`accept` is a placeholder and returns exit`2` .\n- **Onboarding:**`init` detects one top-level package; other layouts need`--source` and`--namespace` . It cannot know why a boundary exists, so every rationale stays a decision.\n\nCompleted work and the ordered UI, CI and release plan live in\n[docs/roadmap.md](https://github.com/rapiddweller/archkeel/blob/main/docs/roadmap.md).\nItems remain planned until their listed evidence exists.\n\nMIT © 2026 Rapiddweller Asia Co., Ltd.\n\nMaintained by [Alexander Kell](https://github.com/ake2l).", "url": "https://wpnews.pro/news/archkeel-coding-agents-declare-architecture-changes-before-they-submit", "canonical_source": "https://github.com/rapiddweller/archkeel", "published_at": "2026-09-15 04:11:32+00:00", "updated_at": "2026-09-15 04:33:42.952112+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools"], "entities": ["Archkeel", "rapiddweller", "Git", "Python 3.11", "Fixture A", "Fixture B", "Fixture C"], "alternates": {"html": "https://wpnews.pro/news/archkeel-coding-agents-declare-architecture-changes-before-they-submit", "markdown": "https://wpnews.pro/news/archkeel-coding-agents-declare-architecture-changes-before-they-submit.md", "text": "https://wpnews.pro/news/archkeel-coding-agents-declare-architecture-changes-before-they-submit.txt", "jsonld": "https://wpnews.pro/news/archkeel-coding-agents-declare-architecture-changes-before-they-submit.jsonld"}}