Build an evidence-backed model of your software architecture from declared and observed signals — with the evidence behind every architectural claim.
Quick Start · Runtime Demo · Evaluation · Documentation · Research Landscape
Hand-maintained architecture documentation tends to drift from the system it describes. AIP builds its knowledge graph automatically from artifacts that already exist and are already kept up to date as part of normal development — OpenAPI/AsyncAPI specs, a minimal manifest for the one thing they can't express (who calls what), and, optionally, real OpenTelemetry traffic — so every fact in the graph traces back to real evidence, never to a stale diagram someone forgot to update.
Traditional architecture documentation describes what a system is supposed to look like. AIP keeps declared architecture and runtime observations together, and preserves the evidence behind each fact:
| Evidence state | Status |
|---|---|
DECLARED + OBSERVED |
CONFIRMED — the documented relationship is also seen at runtime |
OBSERVED only |
OBSERVED_ONLY — a real dependency exists but was never declared |
DECLARED only |
NOT_OBSERVED_IN_WINDOW — declared, but not seen in this environment/time window |
That's the core idea: not just what the architecture says, but what the system actually does, and why AIP believes each relationship exists. See Declared vs Observed below for the full semantics.
Requires Docker and Docker Compose (Python 3.13 only if you want to run it outside a container):
git clone https://github.com/michaelegner/architecture-intelligence-platform.git
cd architecture-intelligence-platform
cp .env.example .env
docker compose up.env.example's NEO4J_PASSWORD is a fixed local-only default (change-me-local) — fine for
trying this out, never for anything reachable outside your machine.
Then open http://localhost:8000. config.yaml already points at this repo's examples/ fixture
services, so POST /api/import works immediately against them. See
docs/development.md for running locally without Docker, the test suite, and
linting.
After importing the bundled example, open the Service Explorer to inspect the architecture graph.
For the full declared-vs-observed experience — CONFIRMED, OBSERVED_ONLY, and
NOT_OBSERVED_IN_WINDOW relations, not just declared ones — run the
runtime demo below; it adds synthetic OpenTelemetry traffic on top of the same
fixture.
AIP shows declared and observed architecture side by side. In the bundled runtime demo:
OrderService -> ProductServiceisCONFIRMED— declared and observed.OrderService -> LegacyPricingServiceisOBSERVED_ONLY— a real dependency the manifest never declared.unused-qisNOT_OBSERVED_IN_WINDOW— declared, but not observed in this environment/time window.
See the runtime demo for the full walkthrough, or
examples/runtime-demo/README.md directly.
Ingestion
- ✓ OpenAPI ingestion
- ✓ AsyncAPI queue topology
- ✓ Architecture manifest support (the one place declared REST callers come from)
- ✓ Evidence / provenance on every fact, independently for declared and observed evidence
Graph & analysis
- ✓ Neo4j architecture knowledge graph
- ✓ Deterministic dependency analyses (queue senders/consumers, orphan queues)
- ✓ Architecture blast radius (mixed sync + async traversal)
- ✓ Semantic Cypher validation (a hard allowlist gate, not an LLM guardrail)
- ✓ Natural-language architecture queries — deterministic where possible, validated read-only Cypher otherwise
Runtime telemetry (OpenTelemetry)
- ✓ Runtime discovery of undeclared operations, services and queues
- ✓ Cross-batch HTTP correlation (a CLIENT and SERVER span arriving in separate OTLP requests still correlate to one observed dependency)
- ✓ Partial-instrumentation tolerance (a stable one-sided observation still counts, an unreliable one never gets guessed)
- ✓ Declared vs. observed architecture, and architecture drift detection
- ✓ Telemetry coverage qualification for negative findings
See docs/opentelemetry.md for what the CLIENT_SERVER/CLIENT_ONLY/
SERVER_ONLY/UNRESOLVED correlation modes above actually mean.
Every relation in the graph carries evidence, and its evidence can be DECLARED (from a spec/
manifest), OBSERVED (from real telemetry), or both. That's what turns into a status:
| Status | Meaning |
|---|---|
CONFIRMED |
Declared and observed |
OBSERVED_ONLY |
Observed, but never declared anywhere — an undocumented real dependency |
NOT_OBSERVED_IN_WINDOW |
Declared, but not seen in this window — never "obsolete"/"unused"/"dead", just not observed yet or here |
Removing a stale declaration never deletes a relation that still has observed evidence — it degrades
CONFIRMED to OBSERVED_ONLY instead. See docs/graph-model.md for the
exact invariant this guarantees and why it matters.
The bundled examples/ fixture is a small, fully synthetic four-service landscape:
unused-q (a sender with no consumer) and unknown-producer-q (a consumer with no known sender) are
included specifically to exercise the orphan-queue analyses. POST /api/import loads all of it in
one call.
A modular Python monolith (a single FastAPI process); Neo4j is the only external persistent
dependency. Ingestion is a strictly staged pipeline — scan -> parse -> source-validate -> map to canonical model -> canonical-validate -> reconcile/diff -> transactional graph write — where a
service's import either fully succeeds or is entirely discarded, never left partial. Source adapters
never write to Neo4j directly; they all map into one shared Canonical Model first. Full details,
including the graph/evidence model and every API route: docs/architecture.md.
Five fixed, parameterized Cypher analyses over declared architecture (queue senders/consumers,
orphan queues, mixed-architecture blast radius) plus five over declared-vs-observed runtime data
(what was actually observed, what's confirmed, what's observed-only, what's declared-only, and
per-service telemetry coverage). None of these involve the LLM — see
docs/analyses.md for the full list and what each one answers.
Two independent evaluation suites prove AIP's output against hand-authored, independently frozen ground truth — never generated from AIP's own output — with deterministic PASS/FAIL:
uv run python -m evaluation run # ten scenarios over declared/observed relation facts (v0.2)
uv run python -m evaluation answers # eight scenarios over the v0.4 ArchitectureAnswer envelope (I1.4)answers compares the complete ArchitectureAnswer — claims, evidence references, snapshot and
observation-context identity, limitations — against literal frozen expectations and emits a
machine-readable JSON result to evaluation/architecture_answers/results/i1-evaluation-result.json.
No LLM provider key is required — neither suite touches the natural-language query layer. See
evaluation/README.md for the full scenario lists, ground-truth formats,
and failure-report examples.
POST /v1/traces is AIP's OTLP/HTTP ingestion boundary. It resolves incoming spans against whatever
is already declared in the graph and persists observed facts and evidence alongside the declared
ones — never inventing a fact it can't trace back to real telemetry.
AIP is an additional telemetry consumer, not the primary observability backend. It must never be the only thing an OTel Collector forwards to, and its own availability must never affect an application's normal observability:
Failure isolation, buffering, and retry behavior belong in the Collector/deployment configuration —
/v1/traces does no buffering or retry of its own, by design. Full attribute allowlist, correlation
modes, and coverage-qualification model: docs/opentelemetry.md.
docker compose -f docker-compose.demo.yml up --buildBrings up architecture-intelligence + neo4j (as above) plus an otel-collector service and a
traffic-generator that emits realistic synthetic OTLP traces for the examples/ fixture topology
every few seconds (see examples/runtime-demo/traffic_generator.py's docstring for why this repo
generates spans directly rather than running real HTTP services). The Collector forwards every batch
to AIP's /v1/traces and, in parallel, to a debug exporter — standing in for "an additional
tracing backend" in the topology above.
Once it's running, POST /api/import to declare the fixture topology, then watch
GET /api/runtime/relations?environment=demo fill in with OBSERVED/CONFIRMED relations as the
generator's traffic lands — a live demonstration of the DECLARED + OBSERVED -> CONFIRMED and, on a
later reimport with a declaration removed, -> OBSERVED_ONLY transition described above. The
generator also emits an undeclared OrderService -> LegacyPricingService call (surfacing as
OBSERVED_ONLY on its own, with no reimport needed) and periodically splits one CLIENT/SERVER pair
across two OTLP requests to demonstrate cross-batch correlation. The same states are also visible in
the web UI at http://localhost:8000/ — the Service Explorer shows declared vs. observed side by
side, and http://localhost:8000/query answers questions like "Which dependencies are observed but
undocumented?" without needing an LLM configured. See
examples/runtime-demo/README.md for the full step-by-step
walkthrough — every state (CONFIRMED, OBSERVED_ONLY, NOT_OBSERVED_IN_WINDOW) and the
reconciliation scenario, each with exact curl commands and expected results.
The Service Explorer shows the same declared-vs-observed states illustrated in What you'll see, while the walkthrough above explains how each state is produced.
POST /api/query answers a plain-language question either by routing it to an existing
deterministic analysis (above) or, if it doesn't recognize the question, by generating Cypher that
must pass a strict read-only allowlist validator before it ever touches Neo4j. The LLM never holds
write credentials and its Cypher is always shown back alongside the answer for traceability. Fully
optional — the platform works completely without any LLM provider configured. See
docs/semantic-validation.md.
docs/architecture.md— pipeline, API surfacedocs/canonical-model.md— entities and deterministic idsdocs/graph-model.md— relations, fact/evidence invariants, observedPROVIDESdocs/evidence.md— provenance, theEvidencenode, correlation modesdocs/ingestion.md— the three declared source adaptersdocs/analyses.md— A1-A5 and O1-O5docs/semantic-validation.md— the NL query pipelinedocs/opentelemetry.md— runtime observation, attribute allowlist, coverageevaluation/README.md— the deterministic evaluation suite: scenarios, ground-truth format, running it, and reading a failure reportreal_world_validation/README.mdanddocs/real-world-validation/README.md— the v0.3 real-world validation contract: finding vocabulary,expected.yamlshape, dossier structuredocs/configuration.md— every setting and its defaultdocs/security-model.md— trust boundariesdocs/development.md— local dev, tests, lintingdocs/adapter-development.md— extending AIP with a new sourcedocs/adr/— Architecture Decision Records: why Neo4j, why a Canonical Model, why the LLM is read-only and never a source of truth, and moredocs/specifications/— the original design specifications, as a traceable history of how the platform got herelandscape.md— research landscape: formal foundations, adjacent platforms, agent context, architectural intent, governance, and verificationROADMAP.md/CHANGELOG.md— where this is headed, and what's shipped so far
See CONTRIBUTING.md for development setup, test/lint/format commands, and the
adapter contribution guide. Questions and ideas go in Discussions; bugs and
feature requests use the issue templates. Security vulnerabilities should never be reported as
public issues — see SECURITY.md. This project follows the
Contributor Covenant.
The original PoC (Canonical Model, OpenAPI/AsyncAPI/manifest ingestion, Neo4j graph, five
deterministic analyses, LLM query layer), the H1-H4 hardening/OpenTelemetry iterations, the full 11H
runtime-correctness roadmap (evidence reconciliation, cross-batch correlation, partial
instrumentation, observed provider relations, coverage qualification, the Collector-based demo), H5
(open-source readiness), v0.2 (the deterministic evaluation suite), and
v0.3.0
(real-world validation against Quarkus Super Heroes and Apache Airflow, plus cross-system model
hardening — zero production semantic changes were justified by either system's independent
evidence) are all shipped. See
docs/real-world-validation/cross-system/report.md
for the full cross-system report and
docs/release-validation/v0.3.0-post-release-verification.md
for the published-artifact verification.
See ROADMAP.md for the full release track — v0.4 (Architecture Intelligence Tools)
is next — and what's planned beyond it.
Licensed under the Apache License, Version 2.0. See LICENSE. Third-party dependency licenses: THIRD_PARTY_LICENSES.md.

