Models¶
Core domain models for the Imbi ecosystem.
Overview¶
The models module provides Pydantic models for all core domain entities (projects, organizations, teams) and the blueprint system for dynamic schema extension.
Model Categories¶
Domain Models¶
- Organization: Top-level organizational units
- Team: Groups within organizations
- Environment: Deployment environments (production, staging, etc.)
- ProjectType: Project categorization and templates
- Project: Services and applications
- TagFormat: A named (
label) regular-expression (pattern) policy for release/deploy tags. BothOrganizationandProjectTypecarry atag_formats: list[TagFormat]field (see Release/Deploy Tag Formats).
Software-Composition Models¶
- Component: Third-party package identity (purl with version
stripped, e.g.
pkg:npm/express) - ComponentRelease: A specific version of a
Component(Component-[:HAS_RELEASE]->ComponentRelease); attached to a projectReleasevia[:USES_COMPONENT_RELEASE] - ComponentIdentifier: Globally unique
(kind, value)pair (purl / cpe / bom-ref / swid) linked to aComponentvia[:IDENTIFIED_BY]
Collaboration Models¶
- Document: A free-form, taggable markdown document attached to
exactly one owning vertex via
[:ATTACHED_TO]— aProject, aProjectType, or aUser(theUservertex is defined byimbi-api, so only the project and project-type edges are typed on the model). - DocumentTemplate: Reusable starter content for a
Document.typedeclares which attachment contexts may use the template:project,user,project_type, orglobal(every context);project_type_slugsoptionally narrows project types further. - CommentThread: A thread of comments anchored to a
Documentvia[:ON_DOCUMENT].kindispage(whole-document) orinline(text-anchored); inline anchors are flattened into theanchor_quote/anchor_prefix/anchor_suffix/anchor_startscalar properties. - Comment: A single comment within a
CommentThread(Comment-[:IN_THREAD]->CommentThread); carriesmentionsandacknowledged_byemail lists.
Blueprint Models¶
- Blueprint: Dynamic schema definitions
- BlueprintAssignment: Blueprint-to-entity relationships
Analytics Models¶
These are not graph nodes — they are typed rows inserted into ClickHouse
via clickhouse.insert. They are provider-agnostic so
any version-control plugin (GitHub, GitLab, …) can reuse them.
- CommitRecord: A VCS commit, written to the commits table
(ReplacingMergeTree keyed by (project_id, sha))
- TagRecord: A VCS tag, written to the tags table
(ReplacingMergeTree keyed by (project_id, name))
Basic Usage¶
from imbi.common import graph, models
# Create an organization
org = models.Organization(
name="My Company",
slug="my-company",
description="Our organization"
)
await db.create(org)
# Create a team linked to an organization
team = models.Team(
name="Platform Team",
slug="platform-team",
description="Infrastructure and platform",
organization=org
)
await db.create(team)
Release/Deploy Tag Formats¶
The tags accepted when cutting a release or promoting a deployment are
governed by a list of TagFormat policies. A tag is accepted when it
matches any configured format (full-string regex match).
Resolution is hierarchical, project-type overriding organization:
- If the project's type(s) configure
tag_formats, those apply. - Otherwise the organization's
tag_formatsapply. - If neither configures any, no restriction is imposed (any tag is
accepted). Seed
models.SEMVER_TAG_FORMATto require semver.
from imbi.common import models, versioning
org = models.Organization(
name="My Company",
slug="my-company",
tag_formats=[models.SEMVER_TAG_FORMAT],
)
patterns = [fmt.pattern for fmt in org.tag_formats]
versioning.matches_tag_formats("v1.2.3", patterns) # True
versioning.matches_tag_formats("nightly", patterns) # False
matches_tag_formats ¶
Return True when tag satisfies the configured tag formats.
patterns is the resolved list of regular-expression patterns for
the project (see imbi.common.models.TagFormat). Each pattern is
matched against the whole tag with :func:re.fullmatch, so a
pattern need not anchor itself with ^/$.
An empty patterns sequence means "no configured policy" and
matches any tag -- callers that need a stricter default should seed a
format (e.g. :data:SEMVER_TAG_PATTERN) rather than relying on this.
Invalid patterns are rejected at write time
(TagFormat validates them), so a bad pattern here is treated as a
non-match rather than raising.
Source code in libraries/common/src/imbi/common/versioning.py
API Reference¶
Base Classes¶
GraphModel ¶
Bases: BaseModel
Minimal base for any model stored as a graph vertex.
Provides identity (id), timestamps, and
extra='ignore' so AGE metadata is silently dropped.
Subclass Node when you also need name/slug.
Node ¶
Bases: GraphModel
Graph node with business identity fields.
The icon attribute can either be a URL or a CSS
class name.
Domain Models¶
ProjectType ¶
TagFormat ¶
Bases: BaseModel
A named release/deploy tag-format policy.
label is the human-facing name shown in the UI (e.g. Semver
or CalVer); pattern is a regular expression a tag must match.
A tag is accepted when it matches any configured TagFormat --
see imbi.common.versioning.matches_tag_formats.
Patterns are matched with :func:re.fullmatch and validated as
compilable at assignment time so an invalid expression is rejected at
the API boundary rather than at deploy/release time.
MCPServer ¶
Bases: Node
An external MCP server reachable over streamable HTTP.
The *_encrypted fields store the ciphertext (Fernet via
:mod:imbi.common.auth.encryption, keyed off
IMBI_CONFIG_ENCRYPTION_KEY). Plaintext secrets must never be
assigned to these fields; encryption and decryption happen in the
repository/consumer layer, never on the model.
Software-Composition Models¶
Component ¶
Bases: GraphModel
A piece of third-party software that may appear as a
dependency of a project Release.
Identity is the package URL with version stripped — e.g.
pkg:npm/express for any version of express. Versions are
captured as ComponentRelease nodes linked via
HAS_RELEASE.
ComponentRelease ¶
Bases: GraphModel
A specific version of a Component.
Per-component uniqueness of version is enforced at the
application layer via MERGE on
(Component)-[:HAS_RELEASE]->(ComponentRelease {version: ...});
no graph-wide UNIQUE index is possible because two components
may legitimately ship the same version string.
ComponentIdentifier ¶
Bases: GraphModel
A unique identifier for a software Component.
Versioned identifier kinds (purl with @version, CPE with
a version segment) are normalized to their version-agnostic form
before persistence so a single ComponentIdentifier resolves
one Component regardless of release. (kind, value) is
globally unique.
Collaboration Models¶
CommentThread ¶
Bases: GraphModel
A thread of comments anchored to a project Document.
kind is 'page' for a whole-document discussion or
'inline' for a comment tied to a span of the document's
text. The inline anchor is FLATTENED into the four
anchor_* scalar properties (rather than a nested model) so
the stored agtype stays a plain map. Page-level threads leave
the anchor fields at their defaults.
Comment ¶
Bases: GraphModel
A single comment within a CommentThread.
mentions and acknowledged_by hold email addresses and
round-trip through AGE as agtype arrays. body is markdown
text and is embedded so semantic search can surface comments
alongside other corpus content.
Blueprint Models¶
Blueprint ¶
Bases: Node
generate_and_validate_slug ¶
Generate slug from name if not provided and validate it.
Source code in libraries/common/src/imbi/common/models.py
validate_kind_fields ¶
Validate kind-specific required fields.
Source code in libraries/common/src/imbi/common/models.py
BlueprintAssignment ¶
Bases: BaseModel
BlueprintEdge ¶
Bases: NamedTuple
Analytics Models¶
CommitRecord ¶
Bases: BaseModel
A VCS commit recorded in the ClickHouse commits table.
Generic across version-control providers — a GitHub, GitLab, or
Bitbucket plugin maps its API response onto these fields and inserts
via :func:imbi.common.clickhouse.insert. The table is a
ReplacingMergeTree keyed by (project_id, sha), so re-syncing an
overlapping commit range collapses duplicates on merge.
TagRecord ¶
Bases: BaseModel
A VCS tag recorded in the ClickHouse tags table.
Mirrors :class:CommitRecord's role for tags. The table is a
ReplacingMergeTree keyed by (project_id, name); annotated-tag
metadata (message, tagger_*, tagged_at) is populated when
the provider exposes it and left at its default otherwise.
sha is always the commit the tag resolves to. Providers that
expose annotated tags as their own objects (git, hence GitHub) must
peel the tag before recording it: consumers join this column against
commits.sha and match it against deployment committishes, so a tag
object hash silently matches nothing. A tag that cannot be peeled to a
commit must be skipped rather than recorded against the unresolved
hash -- no row is better than one nothing can join to.