CSMI is an experimental, language-neutral interchange specification for portable semantic models of code.
Read the navigable CSMI documentation or go directly to the v0.1 specification and JSON Schema.
Standard profiles now cover several language ecosystems plus analyzer-neutral
identity-separating value transfers.
The C and C++ profile supplies exact artifact,
resolver, alias, and declaration identity for the initial std::basic_string
case. Their value-transfer and
C/C++ suites include positive, near-miss,
indeterminate, and fail-closed cases grounded in the native Bifrost contract.
The goal is simple: one tool should be able to describe the semantics of a library, framework, dependency, generated API, or otherwise unavailable implementation, and an unrelated analysis tool should be able to consume that knowledge without sharing the producer's internal representation.
Status: early proposal. CSMI is not yet a stable standard. The initial work is intended to establish a small interoperable core, implement it in Bifrost, and validate it with at least one independent consumer.
Static analysis works best when an analyzer can inspect every relevant implementation. Real software rarely provides that luxury.
Applications routinely depend on code that is:
- distributed as binaries rather than source;
- expensive or impractical to analyze repeatedly;
- implemented in another language;
- generated dynamically;
- supplied by frameworks, runtimes, or native libraries;
- hidden behind dependency boundaries; or
- better modeled by domain knowledge than by source analysis alone.
Most language ecosystems have a way to describe the shape of external code. Python has type stubs, TypeScript has declaration files, JVM and .NET tooling have metadata, and code-intelligence systems index symbols, definitions, references, and signatures.
Those mechanisms generally do not provide enough portable behavioral information for deeper program analysis.
An analyzer may need to know facts such as:
parameter[0] -> return
parameter[1] -> receiver.field[x]
receiver.field[y] -> exceptional_return
It may also need to know that a call allocates, mutates its receiver, invokes a callback, escapes an argument, sanitizes a value, or has no additional effects beyond those explicitly modeled.
Static-analysis systems therefore maintain library models, procedure summaries, framework models, and other semantic knowledge. These are useful, but they are usually tied to a specific analyzer.
CSMI proposes a common interchange boundary for that semantic knowledge.
A producer derives semantic information from source, binaries, metadata, expert-authored models, or some combination of those inputs:
flowchart LR
A[Source / binary / metadata] --> B[Semantic producer]
B --> C[CSMI pack]
C --> D[Analyzer A]
C --> E[Analyzer B]
C --> F[IDE / code intelligence tool]
The producer and consumers do not need to share a compiler, intermediate representation, query language, or analysis engine.
A semantic model becomes a portable artifact.
Suppose a dependency exposes:
class Strings {
static String normalize(String input) {
// implementation unavailable to the application analyzer
}
}A CSMI procedure summary could state that the first parameter flows to the normal return value:
# Illustrative syntax; not yet normative.
procedure_summaries:
- symbol: Strings.normalize
transfers:
- from:
parameter: 0
to:
return: normal
completeness:
transfers: completeAn analyzer examining:
String input = request.getParameter("name");
String normalized = Strings.normalize(input);
save(normalized);can preserve the flow through Strings.normalize without inspecting its implementation.
The important property is not that Bifrost can read the model. The important property is that another analysis engine can assign the same meaning to it.
The first version of CSMI should be deliberately small. The initial semantic core is expected to cover the following areas.
A model must identify the software artifact to which it applies, including enough information to determine compatibility safely.
CSMI should reuse existing standards where they already solve this problem. In particular, Package URL (PURL / ECMA-427) is a strong candidate for cross-ecosystem package identity.
Artifact digests and version constraints may additionally be required where package coordinates alone are insufficient.
Models must refer unambiguously to externally visible program entities such as types, methods, functions, fields, and parameters.
CSMI should reuse or adapt proven language-neutral symbol-addressing concepts rather than inventing another incompatible symbol grammar without need.
CSMI may carry the declaration facts required to interpret semantic summaries, including:
- types;
- members;
- callables and signatures;
- inheritance and implementation relationships; and
- selected symbol relationships.
CSMI is not intended to replace a language's complete type system.
The principal behavioral abstraction is a procedure summary.
A procedure can expose semantic input locations such as:
receiver
parameter[n]
heap location
captured value
and output locations such as:
receiver
normal return
exceptional return
heap location
A summary can then express relationships between those locations without prescribing how a consumer implements its dataflow engine.
Some behavior is not naturally represented as a value transfer. Procedure models may therefore describe effects such as:
allocation
mutation
escape
call
CSMI 0.1 deliberately does not make those words generic core facts. Allocation, mutation, escape, and invocation each need a versioned profile that defines its targets, modality, observation boundary, merging, and completeness. Mutation is the strongest candidate for a first standard effect profile because it can reuse core boundary locations without standardizing an analyzer heap model.
More specialized domains should likewise be expressed as versioned profiles or extensions rather than forcing every CSMI consumer to implement every possible analysis vocabulary.
The csmi.value-transfer 0.1.0 profile
adds copy, aggregate-copy, move, conversion, boxing, and unboxing semantics to
selected core transfers without changing the CSMI 0.1 core. It keeps value
dependence separate from storage identity, preserves source invalidation and
value-preservation uncertainty, and requires exact implicit-operation identity.
The independent C and C++ profile family uses
csmi.c-cpp-resolution for the shared structured resolution boundary and
csmi.cpp for the canonical std::basic_string fixtures.
A normative language profile defines deterministic Python import and
declaration identity, distribution-to-import mappings, runtime/stub
correspondence, and compatibility boundaries. See the
csmi.python 0.1 profile and its
conformance cases.
Missing information is not the same thing as absence of behavior.
A portable semantic model must be able to distinguish at least these cases:
These are all transfers.
These are the transfers currently known by the producer.
No semantic model is available.
Completeness is therefore part of the semantic contract, not merely metadata. Without it, consumers can accidentally turn partial models into false guarantees and unsound analysis results.
Consumers need enough provenance to decide whether a semantic model should be trusted and whether it applies to the artifact being analyzed.
Relevant metadata may include:
- producer identity and version;
- generation method;
- target package and version constraints;
- source artifact digest;
- creation metadata;
- confidence or certainty; and
- model completeness.
CSMI distinguishes the semantic producer that established a fact from the pack assembler that selected and packaged existing resources. Facts and completeness claims retain producer provenance; the pack manifest records assembly, licensing, and byte integrity without becoming a second source of semantic truth.
CSMI is not intended to standardize an analyzer's internal intermediate representation.
It is not intended to encode arbitrary ASTs, control-flow graphs, SSA graphs, or complete whole-program representations.
It is not intended to standardize analysis findings or diagnostics.
It is not intended to define application-specific security policy such as which values should be considered sensitive.
It is not intended to require every consumer to support every semantic domain.
The core should remain small enough that independent producers and consumers can realistically implement it.
CSMI builds on substantial prior work. The proposal is not that procedure summaries or library models are new; the gap is the lack of a broadly adopted, analyzer-neutral interchange format for distributing them across tools.
SARIF standardizes the output of static-analysis tools: findings, locations, rules, diagnostics, and related result metadata.
CSMI addresses the other side of analysis:
semantic knowledge
|
v
source code ------> analyzer ------> findings
| |
CSMI SARIF
SARIF communicates what an analyzer found. CSMI is intended to communicate semantic knowledge that an analyzer may use while performing its analysis.
The two formats are complementary.
SCIP is a language-agnostic protocol for indexing source code and supporting operations such as definitions, references, and implementations. LSIF and systems such as Kythe address closely related code-intelligence problems.
That work overlaps strongly with the symbol and declaration-identification problem CSMI must solve. CSMI should reuse proven concepts from this ecosystem where practical.
Its additional concern is analyzer-independent behavioral semantics: value transfer, effects, exceptional behavior, escapes, completeness, and related procedure properties.
Python .pyi files, TypeScript .d.ts files, interface metadata, and similar mechanisms are extremely useful representations of API surfaces.
Their primary concern is declarations and type information rather than portable behavioral summaries. CSMI is intended to complement these mechanisms, not replace them.
CodeQL model packs are particularly close prior art. They allow library and framework behavior to be modeled separately from source and distributed as packs. Their data extensions can add semantic knowledge for dependencies to CodeQL analyses.
This demonstrates that distributable dependency semantics solve a real problem.
CSMI differs in its intended abstraction boundary: the semantic representation should not depend on CodeQL predicates, a CodeQL query pack, or any other single analysis engine. A model produced for one consumer should be meaningfully consumable by another.
A future CodeQL adapter is therefore an important interoperability test for CSMI.
Code Property Graph ecosystems provide language-neutral representations of program structure and semantics and are useful interchange representations for analyzed programs.
CSMI has a narrower target. Rather than representing an entire program, it aims to represent portable semantic knowledge about externally referenced program entities, particularly dependencies and APIs.
Static-analysis frameworks have long supported hand-authored or synthesized summaries for unavailable library code. This is important prior art and reinforces the usefulness of the abstraction.
CSMI's goal is not to replace those internal models. It is to identify the subset of their meaning that can be exchanged between independent implementations.
A core CSMI concept should not depend on the internal representation of one analyzer.
If a semantic concept cannot be implemented meaningfully by a second independent consumer, it is a strong candidate for an extension rather than the core specification.
The model should describe concepts such as parameters, returns, receivers, heap locations, transfers, and effects without requiring Java, Python, Rust, JavaScript, or another specific source language.
Language-specific semantics may be represented through extensions.
Unknown, partial, and complete information must remain distinguishable.
Consumers must not be forced to interpret omitted fields as semantic guarantees.
Analysis domains evolve faster than a core interchange specification should.
CSMI should support standardized profiles and namespaced extensions such as:
csmi.security.taint
csmi.effects.io
csmi.effects.network
csmi.ownership
csmi.concurrency
csmi.typestate
These are illustrative future names, not assigned profiles.
and implementation-specific extensions such as:
ai.brokk.bifrost.*
Standard profiles reserve the csmi. namespace. Vendor extensions use a
publisher-controlled reverse-DNS namespace. Every exact-versioned use must say
whether it is optional or required and identify the semantic units it affects,
so an unsupported consumer can fail closed without discarding unrelated facts.
Where another specification already solves an identity or metadata problem well, CSMI should integrate it rather than create a competing representation.
Potential examples include PURL for package identity and SPDX identifiers for licensing metadata.
Equivalent semantic models should have a deterministic or canonical representation where practical, enabling reproducible generation, content addressing, caching, signing, comparison, and deduplication.
A CSMI pack is a content-addressed collection of semantic documents and supporting resources. Semantic documents remain self-describing and own artifact applicability, vocabulary uses, facts, completeness, and producer provenance. The root manifest owns resource descriptors, assembly identity, licensing, and integrity.
A pack logically contains its root manifest, one or more semantic-document resources, and any described supporting resources such as vocabulary schemas, license texts, notices, or auxiliary data. CSMI does not prescribe how those logical resources are laid out by a transport.
Each resource is described by a safe logical path, media type, byte size, and SHA-256 digest. The pack digest is the SHA-256 of its RFC 8785-canonical root manifest, which commits transitively to every described resource. Detached signatures or attestations can name that digest later without changing the pack's identity.
The semantic data model is separate from its transport and registry mechanism. A directory, archive, OCI artifact, or future registry may carry the same logical pack; transport and registry protocols are outside CSMI 0.1.
Bifrost is expected to be the first CSMI producer and consumer.
The intended architecture is:
Bifrost internal model -> CSMI pack
CSMI pack -> Bifrost analysis
That alone is not sufficient evidence of interoperability. The critical milestone is an independent consumer that does not depend on Bifrost internals:
flowchart TD
B[Bifrost] -->|generates| P[CSMI pack]
P --> C1[Bifrost consumer]
P --> C2[Independent consumer]
If two unrelated consumers assign the same relevant meaning to a model, the interchange boundary has been demonstrated independently of Bifrost.
The public CSMI demo repository is where we will demonstrate this boundary with controlled producer/consumer cases. It will show independent analyzers consuming the same CSMI pack and compare results with and without imported semantics. Demo code and results are interoperability evidence, not normative specification material.
The normative schema, fixtures, and validation tooling live beside the prose:
spec/
0.1/
specification.md
schema.json
examples/
*.json
profiles/
rust/
0.1/
profile.md
schema.json
fixtures/
value-transfer/
0.1/
profile.md
schema.json
fixtures/
cpp/
0.1/
profile.md
schema.json
fixtures/
fixtures/
valid/
invalid/
semantic-invalid/
conformance/
*.md
scripts/
lint-json.py
validate-profiles.py
validate-rust-profile.py
validate-value-transfer.py
validate-cpp-profile.py
validate-schema.py
The normative specification should live in the repository. A documentation website may render the same material for easier navigation, but should not become a separate source of truth.
The CSMI 0.1 specification defines the normative semantic boundary, while schema.json defines the first machine-readable serialization.
Versioned language profiles remain outside the language-neutral core. The normative Rust interoperability profile defines Rust source-item identity, Cargo/crate/sysroot applicability, compilation configuration, implementation and reexport facts, generation evidence, and the explicit source-to-native mapping boundary. Its payload schema is profiles/rust/0.1/schema.json, and its semantic cases are conformance/rust-profile.md.
Define the smallest useful portable model for:
- artifact identity;
- symbol identity;
- declarations;
- procedure inputs and outputs;
- transfer semantics;
- effect-profile mechanics;
- completeness;
- provenance;
- extension mechanics; and
- schema validation.
Implement CSMI export and import in Bifrost.
Build a deliberately small analysis that consumes a Bifrost-generated CSMI pack without using Bifrost libraries or internal data structures.
The demo should visibly produce a stronger or more complete result with the semantic pack than without it.
Explore meaningful mappings to established ecosystems, particularly CodeQL model packs and SCIP-compatible symbol/declaration data. These adapters should help identify which concepts belong in the portable core and which should remain ecosystem-specific.
Language-specific SDKs, validators, CLIs, and generated bindings may be created separately once the specification stabilizes enough to justify them. The specification repository itself should remain implementation-neutral.
Design feedback and interoperability use cases are welcome, but external pull requests are not accepted at this stage.
During the initial specification phase, changes to the repository will be authored or incorporated by BrokkAi maintainers. This keeps authorship, licensing, and specification stewardship simple while the model is still changing rapidly.
Please see CONTRIBUTING.md for the current policy.
Run the dependency-free strict JSON lint before committing changes to examples, fixtures, or schemas:
python3 scripts/lint-json.pyIt rejects malformed JSON, duplicate object keys, invalid UTF-8, non-finite numbers, and invalid Unicode surrogate values.
To meta-validate the Draft 2020-12 schema and check all structural fixture expectations without installing a CSMI SDK:
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements-validation.txt
.venv/bin/python scripts/validate-schema.py
.venv/bin/python scripts/validate-profiles.py
.venv/bin/python scripts/validate-rust-profile.py
.venv/bin/python scripts/validate-value-transfer.py
.venv/bin/python scripts/validate-cpp-profile.pyThe canonical schema identity is
https://csmi.brokk.ai/schema/0.1/schema.json; validation uses the repository
copy and does not require network retrieval. GitHub runs both validation layers
after pushes to main, then publishes that validated repository copy to the
same path on the GitHub Pages site. The Pages custom-domain setting and DNS
record map csmi.brokk.ai to that site; they are deployment configuration, not
an alternate source of schema truth.
Versioned standard profiles have their own normative definitions and payload
schemas. The Java/JVM interoperability profile
keeps Java source
identities distinct from JVM binary linkage identities and defines an explicit,
evidence-bearing mapping between them. Run
python3 scripts/validate-profiles.py to validate its schemas and conformance
instances. The value-transfer and C/C++ profiles add dedicated validators for
their cross-record and canonical-identity invariants.
The contents of this repository are licensed under the Apache License 2.0.