Skip to main content

Archkeel

The agent declares before it submits. The check is deterministic.

Archkeel architecture gate and keel

Python 3.11+ CI License: MIT PyPI version

Archkeel 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.

It catches two failure modes that finding-only diffs miss:

  • the architecture changed without being declared;
  • the scanner saw less of the program, so the result looks clean only because the graph became blinder.

Archkeel rejects Fixture A in the terminal because calls_unresolved rose from 0 to 1

Try the demo · Onboard your project · How it works · Reference · Roadmap

Implemented and planned work is tracked in the roadmap.

Why Archkeel

An 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.

Fixture A is the smallest example:

 def run(key: str) -> int:
-    return first() + second()
+    handlers = {"first": first, "second": second}
+    return handlers[key]()

The refactor introduces no new forbidden import, cycle, or private crossing. But static call resolution gets worse:

Observation Accepted Candidate
Resolved calls 2 of 2 0 of 1
Unresolved calls 0 1
New finding fingerprints 0 0
Archkeel verdict baseline FAIL
expectation_fulfilled: FAIL
regression check failed in calls_unresolved: 0->1
regression check failed in unresolved_ratio: 0/2->1/1

Archkeel compares raw measurements as well as finding counts and fingerprints. The ratio check uses integer cross-multiplication, never rounded percentages:

U_candidate × T_accepted <= U_accepted × T_candidate   (when both T > 0)

What the gate adds

  • Precommitment with evidence. The agent publishes the intended change before it submits the candidate. Git ancestry and host records prove the order; author timestamps do not.
  • Coverage-aware regression checks. A disappearing edge is not mistaken for an improvement just because a finding disappeared with it.
  • Explicit uncertainty. An incomplete scan, broken lock, empty scope, or runtime mismatch returns exit 2 with a diagnostic. Unknown never becomes green.

Archkeel 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.

Review surface

Archkeel check report rejecting Fixture A with five independent verdicts and the failed regression checks

The HTML report is designed for a reviewer making a merge decision:

  • Decision first. PASS, REJECT, or UNVERIFIABLE and one sentence explaining it are visible before details, in the HTML report and in the terminal.
  • No blended score. Scan completeness, contract compliance, expectation matching, Git order and publication order remain separate verdicts.
  • Unknown stays visible. Missing or invalid evidence includes the affected subject, unknown claim, and remedy.
  • Evidence stays inspectable. Exact counts, fingerprints, source locations, digests, and runtime provenance remain available beside the verdict.

Try the demo

The 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.

git clone https://github.com/rapiddweller/archkeel.git
cd archkeel
make demo

make demo-screenshots OUTPUT=<directory> also captures each HTML report as PNG and each terminal view as SVG.

Onboard your project

Requirements: Python 3.11+ and a Git repository with at least one commit.

uvx archkeel skill install claude    # or codex
uvx archkeel init
uvx archkeel validate

init observes the only top-level package and writes archkeel.toml, architecture-contract.json and docs/architecture/architecture.md. It proposes one component per subpackage and forbids every component pair that is not imported today. Each rule starts with a TODO: rationale, so validate lists every decision that remains, each with a JSON Pointer. Give the prompt in docs/onboarding.md to your coding agent, or work through the list yourself. The rule catalog is in docs/rules.md.

To install it permanently instead, run pip install archkeel. Every command explains itself with archkeel <command> --help.

Quickstart

Observe the current repository:

archkeel report

The command writes the canonical architecture.json and a self-contained architecture.report.html beside it. A terminal shows the decision and verdicts; pipes and --json receive the JSON result.

Check a candidate against its published expectation:

archkeel check \
  --root /repo \
  --baseline "$B" \
  --expectation-commit "$E" \
  --head "$H" \
  --expected expectation.json \
  --expected-digest "$DIGEST" \
  --accepted-branch main \
  --branch candidate

Run the Python version required by the repository being scanned. A mismatch is reported as runtime_mismatch with exit 2, not as broken source code.

How it works

flowchart TB
    B["Locked accepted state"] --> O["Observe accepted + candidate"]
    E["Expectation published first"] --> H["Candidate submitted"]
    H --> O
    O --> C{"Deterministic check"}
    C --> P["0 · pass"]
    C --> R["1 · reject"]
    C --> U["2 · unverifiable"]

    classDef locked fill:#141414,stroke:#C5F82A,color:#E8E8E2
    classDef declared fill:#141414,stroke:#5EEAD4,color:#E8E8E2
    classDef candidate fill:#141414,stroke:#8A8A84,color:#E8E8E2
    classDef gate fill:#C5F82A,stroke:#C5F82A,color:#0D1F05
    classDef result fill:#141414,stroke:#2A2A28,color:#E8E8E2

    class B locked
    class E declared
    class H,O candidate
    class C gate
    class P,R,U result

A check answers three independent questions. It never compresses them into a single score.

Verdict Question Typical failure
observation_complete Did the scan see everything it claims to see? Incomplete scan, empty scope, rule without subjects
declared_rules Does the code obey the architecture contract? Forbidden import between components
expectation_fulfilled Did the candidate match the declaration without regressions? Coverage regression, undeclared change, late expectation

Exit codes

Exit Meaning
0 Complete report or successful check
1 Rejected because at least one verdict is FAIL
2 Unverifiable input, always with at least one diagnostic

Every exit 2 diagnostic contains:

kind · subject · unknown_claim · remedy

A broken lock is therefore not interpreted as an empty accepted state.

The M → B → E → H protocol

gitGraph
    commit id: "M · accepted"
    commit id: "B · lock only"
    branch candidate
    commit id: "E · expectation only"
    commit id: "H · implementation"
Commit Contract
M Accepted state. Archkeel re-observes it.
B Lock-only child of M and tip of the accepted branch. It binds the config, checker, and observation digests.
E Child of B that changes only the expectation file. It must be published before the first submission of H.
H Descendant of E. It must not modify the lock, config, architecture contract, or expectation.

Agent workflow

  1. Start from the lock commit B.
  2. Write the intended architecture change and commit it alone as E.
  3. Publish E before submitting implementation work.
  4. Implement the change in one or more commits ending at H.
  5. Run archkeel check. Fix the code or revise the proposal in a new protocol cycle; do not rewrite protected inputs inside H.

Fixture B writes its expectation after implementation by deriving it from the observed delta. Its architecture findings are otherwise clean. Archkeel still rejects it:

host_order: FAIL
expectation_fulfilled: FAIL
expectation was not published before the first candidate submission

Precommitment proves "published before submission." It does not prove that no private edit existed before publication.

Host evidence

In GitLab CI, Archkeel reads merge-request diff versions through glab to establish publication order.

For local testing, replay captured host records:

uv run archkeel check ... --host-records records.json

A local replay validates the record shape and behavior. It does not prove host authenticity.

Development

Run the complete project gate:

make check

This runs Ruff, strict mypy, pytest, and Archkeel's self-check.

Run the full release check, build both distributions, and install each one in isolation:

make release-check

Reproduce the protocol fixtures:

make fixtures

Archkeel checks itself

architecture-contract.json holds Archkeel to the rules it sells, and every rule was proven by a deliberate violation:

  • Closed world. Seven components; every ordered pair is either one of the ten observed imports or forbidden with a rationale. The architecture guide explains each allowed edge in the single marked component graph.
  • Deterministic core. ir and check never import adapters or presentation; the CLI is the composition root. The analyzer may import only archkeel.ir.model and archkeel.ir.codec.
  • No dynamic shortcuts. getattr, hasattr, cast, eval, exec, dynamic imports and type: ignore are forbidden everywhere.
  • Confined dependencies. packaging only in the analyzer runtime gate, rich only in the terminal view, rich_argparse only in the CLI.
  • Complete and acyclic. Every module belongs to exactly one component, and components form no cycle.

make check reobserves the repository and compares it with fixtures/D-self; CI also runs archkeel validate and uploads the self-observation.

Current boundaries

Archkeel is deliberately strict about what it can prove:

  • Competing implementations: review is still required when no declared rule or observed regression exposes them.
  • Private crossings: only import records are checked. import pkg; pkg._member is not detected.
  • Precommitment: publication order is proven; private editing order is not.
  • Analyzer runtime: Archkeel's Python must be at least the target repository's Python.
  • Acceptance: accept is a placeholder and returns exit 2.
  • 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.

Roadmap

Completed work and the ordered UI, CI and release plan live in docs/roadmap.md. Items remain planned until their listed evidence exists.

License

MIT © 2026 Rapiddweller Asia Co., Ltd.

Maintained by Alexander Kell.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

archkeel-0.2.0.tar.gz (1.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

archkeel-0.2.0-py3-none-any.whl (118.3 kB view details)

Uploaded Python 3

File details

Details for the file archkeel-0.2.0.tar.gz.

File metadata

  • Download URL: archkeel-0.2.0.tar.gz
  • Upload date:
  • Size: 1.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for archkeel-0.2.0.tar.gz
Algorithm Hash digest
SHA256 83d2bbde7d42f399070edad8346b5b574f3c27ded22b35cf0bf4c8ce0c52c934
MD5 c2e9af487ca33fa65ec3deecad88cbc6
BLAKE2b-256 6b0c00d2a74320084a67d51ca4db03769395b84138b644d41e386db659773e0d

See more details on using hashes here.

Provenance

The following attestation bundles were made for archkeel-0.2.0.tar.gz:

Publisher: release.yml on rapiddweller/archkeel

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file archkeel-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: archkeel-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 118.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for archkeel-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 43108b8f903421f46841cdb75514585cd96b79c0a03fd378c43493ededd7093e
MD5 4dad4c9e2ba6bbf59fc7f3c15538c48b
BLAKE2b-256 238597800a2e89611d019ed67304d2a512ff05d74e64cdd00c54f4ae7696bd38

See more details on using hashes here.

Provenance

The following attestation bundles were made for archkeel-0.2.0-py3-none-any.whl:

Publisher: release.yml on rapiddweller/archkeel

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.3.0

2 files

This release

0.2.0 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page