Archkeel
The agent declares before it submits. The check is deterministic.
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.
Quickstart · How it works · Reference · Roadmap
[!NOTE] Milestone 1:
reportandcheckwork.acceptis still a placeholder. The Python analyzer ships inside the Archkeel package.
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
2with 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
The HTML report is designed for a reviewer making a merge decision:
- Decision first.
PASS,REJECT, orUNVERIFIABLEis visible before details. - No blended score. Scan completeness, contract compliance, and expectation matching 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.
Quickstart
Requirements
- Python 3.11+
Install from a checkout until the first Archkeel release on PyPI
(0.1.0 was published as codekeel):
uv sync --locked
uv run archkeel --help
Add archkeel.toml to the repository you want to check:
[scan]
roots = ["src/example"] # directories, not globs
namespace = "example"
contract = "architecture-contract.json"
Observe the current repository:
archkeel report \
--root /repo \
--output architecture.json
The command also writes a self-contained interactive.html beside the canonical JSON.
It presents the three independent verdicts, exact measurements, diagnostics and provenance.
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
- Start from the lock commit B.
- Write the intended architecture change and commit it alone as E.
- Publish E before submitting implementation work.
- Implement the change in one or more commits ending at H.
- 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 its own boundaries. archkeel.toml and
architecture-contract.json define the contract;
fixtures/D-self/result.json contains the latest
self-scan.
flowchart TB
CLI["cli"] --> CHECK["check"]
CLI --> ACCEPT["accept"]
CHECK --> IR["ir"]
CHECK --> PRODUCER["analyzer"]
CHECK --> HOST["host"]
ACCEPT --> IR
IR --> RULE["imports nothing from archkeel"]
classDef module fill:#141414,stroke:#5EEAD4,color:#E8E8E2
classDef core fill:#141414,stroke:#C5F82A,color:#E8E8E2
classDef invariant fill:#C5F82A,stroke:#C5F82A,color:#0D1F05
class CLI,CHECK,ACCEPT,PRODUCER,HOST module
class IR core
class RULE invariant
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._memberis 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:
acceptis a placeholder and returns exit2.
Roadmap
Milestone 1 delivers report and check. Next:
- CI-only
accept - a review page
- agent commands:
proposeandnext
See docs/roadmap.md for sequencing and docs/reference.md for lock, host-record, schema, and regression-check details.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file archkeel-0.1.0.tar.gz.
File metadata
- Download URL: archkeel-0.1.0.tar.gz
- Upload date:
- Size: 999.9 kB
- 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a3c15dacfd3253d49b1a420c0c105ac99a867866e8d4250eba03e0becbf4d64d
|
|
| MD5 |
88644b9ad44f7e02e204a4daa90361f0
|
|
| BLAKE2b-256 |
f522e327ce538f5268a8bc96eba6b56292d92f93dc765ac09ca435ce2ac38230
|
Provenance
The following attestation bundles were made for archkeel-0.1.0.tar.gz:
Publisher:
release.yml on rapiddweller/archkeel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
archkeel-0.1.0.tar.gz -
Subject digest:
a3c15dacfd3253d49b1a420c0c105ac99a867866e8d4250eba03e0becbf4d64d - Sigstore transparency entry: 2828757171
- Sigstore integration time:
-
Permalink:
rapiddweller/archkeel@e0a1c93a0a8f16660d20103c08c553ed17edde5c -
Branch / Tag:
refs/tags/0.1.0 - Owner: https://github.com/rapiddweller
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e0a1c93a0a8f16660d20103c08c553ed17edde5c -
Trigger Event:
push
-
Statement type:
File details
Details for the file archkeel-0.1.0-py3-none-any.whl.
File metadata
- Download URL: archkeel-0.1.0-py3-none-any.whl
- Upload date:
- Size: 94.5 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5f6dd3effc323bc9eb49d79207e57cf580f7ca5df6ab8348c2ec7bfc26922415
|
|
| MD5 |
3b62deaef82ca9f685a65ca962125b0f
|
|
| BLAKE2b-256 |
7489de53245955dadadd169e16600bc7b298349c414433295c07853e46c88a8c
|
Provenance
The following attestation bundles were made for archkeel-0.1.0-py3-none-any.whl:
Publisher:
release.yml on rapiddweller/archkeel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
archkeel-0.1.0-py3-none-any.whl -
Subject digest:
5f6dd3effc323bc9eb49d79207e57cf580f7ca5df6ab8348c2ec7bfc26922415 - Sigstore transparency entry: 2828757121
- Sigstore integration time:
-
Permalink:
rapiddweller/archkeel@e0a1c93a0a8f16660d20103c08c553ed17edde5c -
Branch / Tag:
refs/tags/0.1.0 - Owner: https://github.com/rapiddweller
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e0a1c93a0a8f16660d20103c08c553ed17edde5c -
Trigger Event:
push
-
Statement type: