coderadius.yaml
Configure CodeRadius per-repository. Teach the AI about proprietary SDKs, map database identities, and tune taint propagation — without writing any code.
coderadius.yaml
Every repository CodeRadius analyzes can optionally contain a coderadius.yaml file at its root. This file is your Architecture-as-Code escape hatch: a lightweight configuration layer that teaches CodeRadius about proprietary patterns, internal SDKs, and database topology that static analysis alone cannot infer.
The file is optional. Without it, CodeRadius applies all its built-in heuristics and defaults. You only need coderadius.yaml when the defaults don't match your infrastructure.
File Format
packages:
analyze: [...]
ignore: [...]
services: [...]
decorators: [...]
databases: [...]
hints: [...]
messageBrokers: [...]
message_channels:
aliases: [...]
mirrors: [...]Six sections. Zero ambiguity. All top-level keys are optional — add only what you need.
| Section | Engine | What it does |
|---|---|---|
packages | Taint (AST) | Controls which packages to analyze, ignore, or map to services |
decorators | AST | Teaches CodeRadius to recognize custom framework decorators |
databases | Graph | Declares database identity, technology, and table ownership |
hints | AI (LLM) | Provides natural language instructions for proprietary SDKs |
messageBrokers | Structural | Declares physical broker instances (cluster, host, vhost, env) so DSN env-vars do not break weld identity |
message_channels | Graph | Aliases (DI → physical name) and mirrors (cross-broker Shovel/Federation declarations) |
packages
Controls the taint propagation engine — which packages trigger analysis, which to ignore, and which map to specific services.
packages.analyze
Force CodeRadius to analyze files that import these packages. Use this for internal I/O libraries that the built-in heuristics don't recognize.
Entries can be plain strings (taint only) or typed SDK objects (taint + LLM hint generation):
packages:
analyze:
# Plain string — marks as taint sink, no extra context
- "@acme/internal-http-client"
# Typed SDK entry — marks as taint sink + auto-generates LLM hints
- name: "@acme/notification-client"
kind: http-client
label: "Notification API" # optional: graph node name
baseUrl: "https://api.notify.io" # optional: helps LLM emit correct URLSDK entry kind values
| Kind | What it tells the AI | Generated graph node |
|---|---|---|
http-client | Method calls on this SDK are outbound HTTP API calls | APIEndpoint (OUTBOUND) |
broker-client | Publish/emit/send calls are message channel writes | MessageChannel (WRITES) |
db-client | Read/write calls are data container I/O | DataContainer |
When you add a typed entry, CodeRadius automatically generates LLM instructions from the kind, label, and baseUrl fields — you don't need a separate hints entry for the same SDK.
packages.ignore
Exclude these packages from taint propagation. Use this for observability, logging, and monitoring libraries that create false positives.
packages:
ignore:
- "@datadog/browser-logs"
- "@sentry/node"
- "pino"
- "winston"decorators
Teaches CodeRadius to recognize custom framework decorators via deterministic AST matching. No LLM involved — pure tree-sitter pattern matching.
decorators:
- name: MessageConsumer
kind: message-consumer # message-consumer | http-route | scheduled-job
args: [routingKey, queue] # argument keys that contain the resource name
- name: CronHandler
kind: scheduled-job
args: [cronExpression]Supported kinds
| Kind | What it creates |
|---|---|
message-consumer | A MessageChannel node with a LISTENS_TO edge |
http-route | An APIEndpoint node with an EXPOSES edge |
scheduled-job | A SystemProcess node with a SPAWNS edge |
How it works
When CodeRadius encounters this decorator in your code:
@MessageConsumer({ routingKey: 'order.created', queue: 'order-events' })
handleOrderCreated(data: OrderEvent) { ... }It creates a MessageChannel node named order.created and links the function to it — without calling the LLM.
Multi-repo isolation: When processing multiple repositories, decorator registrations are automatically cleared between repos. A decorator registered for repo A will not leak into repo B.
databases
Declares database identity, technology, and table ownership. Unifies two responsibilities:
- URN scope resolution — determines the identity of
DataTablenodes in the graph - Datastore declaration — creates
Datastoreinfrastructure nodes with technology metadata
The Problem It Solves
When CodeRadius finds SELECT * FROM orders, it creates a DataTable node. Without configuration, the node is scoped to the repository:
cr:datatable:your-org/payments-api:ordersThis is safe — but CodeRadius can't tell that two services are accessing the same physical database.
databases lets you declare the physical database context explicitly, enabling cross-service data lineage.
Configuration
databases:
- id: main-mysql
technology: mysql
tables:
- "orders"
- "users"
- "wp_*" # prefix glob
- "*_logs" # suffix glob
- id: analytics-pg
technology: postgres
shared: true # cross-repo convergence
tables:
- "metrics_*"
- id: redis-cache
technology: redis
# no tables → catches all Cache infrastructureField reference
| Field | Required | Default | Description |
|---|---|---|---|
id | ✅ | — | Stable logical ID. Becomes a URN segment. Must be unique within the repo. |
technology | ✅ | — | Technology identifier: mysql, postgres, mongodb, redis, s3, etc. |
shared | false | If true, the Datastore node uses the shared namespace for cross-repo convergence. | |
tables | [] | Table name patterns for routing. Supports exact match, prefix (wp_*), suffix (*_logs), and wildcard (*). |
Table pattern matching
| Pattern | Matches |
|---|---|
orders | Only orders (exact) |
wp_* | wp_posts, wp_options, etc. |
*_logs | audit_logs, event_logs, etc. |
* | Everything (escape hatch) |
Tables not matched by any pattern fall back to the repository name as scope.
hints
Provides natural language instructions to the AI analyzer for proprietary SDKs and patterns that can't be resolved via AST alone.
hints:
- patterns: [MessageEmitterService, emitEvent]
description: >
Wrapper proprietario per RabbitMQ. I metodi emit*()
pubblicano messaggi. Tratta come WRITES verso un MessageChannel.
- patterns: [EventBusClient, publishEvent, subscribe]
description: >
GCP Pub/Sub wrapper. publishEvent() first arg is the topic name.
subscribe() first arg is the subscription name.
- patterns: [urql, useQuery, useMutation]
description: >
GraphQL client. If directed to '/graphql', target is the
internal API service.How it works
- The AST parser scans the file for imports matching any
patternskeyword - If matched, the
descriptiontext is injected into the LLM prompt - The LLM uses this context to correctly classify infrastructure interactions
This is NOT prompt injection. The hints are inserted in a dedicated section of the system prompt and cannot execute code or override safety guardrails. Think of it as a "tech lead whispering context to the AI".
When to use hints vs. other sections
| Signal | Use |
|---|---|
| SDK maps to a specific service | packages.services (deterministic, no LLM) |
| Custom decorator pattern | decorators (deterministic, no LLM) |
| Proprietary wrapper with complex semantics | hints (AI-assisted) |
| Package should be analyzed but no context needed | packages.analyze |
Complete Example
TypeScript / Node.js
# coderadius.yaml — TypeScript monorepo
packages:
analyze:
- "@acme/internal-http"
- "@acme/cache-wrapper"
ignore:
- "@datadog/browser-logs"
- "@sentry/node"
- "pino"
services:
- package: "@acme/notification-client"
target: notification-service
- package: "@acme/search-client"
target: search-service
protocol: grpc
decorators:
- name: MessageConsumer
kind: message-consumer
args: [routingKey, queue]
- name: CronJob
kind: scheduled-job
args: [cronExpression]
databases:
- id: main-mysql
technology: mysql
tables:
- "quotes_*"
- "res_*"
- shopping_carts
- id: shared-redis
technology: redis
shared: true
hints:
- patterns: [MessageEmitterService, emitEvent]
description: >
Internal RabbitMQ wrapper. emit*() methods publish messages.
Treat as WRITES to a MessageChannel.
- patterns: [urql, useQuery, useMutation]
description: >
GraphQL client. Calls to '/graphql' target the internal API.PHP / Symfony
# coderadius.yaml — PHP monolith
packages:
analyze:
- "App\\Infrastructure\\Messaging\\DomainEventBus"
- "App\\Infrastructure\\Http\\InternalApiGateway"
ignore:
- "App\\Infrastructure\\Logging\\Logger"
- "Sentry\\SDK"
services:
- package: "App\\Infrastructure\\Http\\InternalApiGateway"
target: internal-gateway
decorators:
- name: DomainEventListener
kind: message-consumer
args: [event, queue]
databases:
- id: legacy-mysql
technology: mysql
tables:
- "*"
- id: shared-redis
technology: redis
shared: true
hints:
- patterns: [EntityManager, persist, flush, remove]
description: >
Doctrine ORM. persist()/flush() is a WRITE, find()/findBy() is
a READ. EntityManager::remove() is a DELETE. The table name is
the entity class in snake_case (e.g. InvoiceEntity → invoice).messageBrokers
Declares physical message-broker instances and anchors them to a stable URN. CodeRadius normally infers a broker from DSN strings inside config files (messenger.yaml, rabbitmq-definitions.json, …), but DSNs frequently contain unresolved env-vars (%env(RABBITMQ_URL)%). Without a declaration the broker is registered with declaredVia: 'inferred' and confidence: 0.3, which leaves room for ambiguity in multi-env / multi-region setups. Declaring it makes the broker authoritative.
messageBrokers:
- id: rmq-prod-eu
provider: rabbitmq
host: rabbitmq.eu-west-1.internal
port: 5672
vhost: /prod
env: prod
region: eu-west-1
cluster: rmq-cluster-1
- id: rmq-prod-us
provider: rabbitmq
host: rabbitmq.us-east-1.internal
port: 5672
vhost: /prod
env: prod
region: us-east-1Field reference
| Field | Required | Notes |
|---|---|---|
id | yes | Stable identifier referenced from message_channels.mirrors[].physical[].broker. |
provider | yes | One of: rabbitmq, kafka, pubsub, sqs, sns, azure-service-bus, nats, pulsar, redis-streams, mqtt, mosquitto, zeromq, symfony-messenger. |
host | no | DNS hostname or IP. |
port | no | TCP port. |
vhost | no | RabbitMQ vhost (or Pulsar namespace). Root / is omitted from the URN; named vhosts are slugified. |
region | no | AWS / GCP / Azure region tag. Surfaced on the graph for environment filtering. |
env | no | Free-form environment label (dev, staging, prod). |
cluster | no | Logical cluster name when multiple physical hosts back the same cluster. |
fingerprint | no | Override the computed sha256_trunc8(provider:host:port:vhost) identity. Use only when two functionally separate brokers share host+port+vhost. |
Strict broker isolation
Two MessageChannel nodes with the same name but different brokerUrn are never welded heuristically — even by the suffix or cross-kind welders. The only way two channels on different brokers converge into a single logical event is an explicit message_channels.mirrors[] entry (next section).
message_channels
aliases
DI / runtime alias → physical channel name. Use when the static analyzer sees a logical key (e.g. messaging.topics.sample_user) but the actual broker resource has a different name (e.g. Platform-SampleUser).
message_channels:
aliases:
- from: messaging.topics.sample_user
name: Platform-SampleUser
channelKind: topic
technology: pubsubmirrors
Cross-broker mirror declarations (RabbitMQ Shovel/Federation, Kafka MirrorMaker, SNS replication). Each entry materializes a MessageChannel{scope:'logical'} node and a MANIFESTS_AS edge to every declared physical channel.
message_channels:
mirrors:
- logical: OrderCreated
kind: topic
physical:
- { broker: rmq-prod-eu, channel: acme.orders, kind: topic }
- { broker: rmq-prod-us, channel: acme.orders, kind: topic }The two physical channels stay as distinct nodes with different URNs (strict isolation). The logical channel sits above them so blast-radius queries can answer "who consumes OrderCreated regardless of region?" with a single MATCH.
Mirroring is opt-in by design. Without an explicit declaration, the welder treats same-name channels on different brokers as unrelated topologies (e.g. an orders test queue on a shared cluster should never be confused with prod).
Governance: Shared Database Detection
Once databases is configured consistently across multiple repositories, CodeRadius generates Governance Alerts for shared database anti-patterns.
You can query for shared database collisions in Memgraph Lab:
MATCH (dt1:DataTable), (dt2:DataTable)
WHERE dt1.name = dt2.name
AND dt1.id <> dt2.id
AND dt1.scope IS NOT NULL
AND dt1.scope = dt2.scope
AND dt1.sourceRepo <> dt2.sourceRepo
RETURN dt1.name AS table,
dt1.scope AS sharedScope,
dt1.sourceRepo AS repo1,
dt2.sourceRepo AS repo2
ORDER BY sharedScope, tableThe Governance Dashboard in cr ui surfaces these findings automatically as "Possible Shared Database" alerts.
File Lookup Order
CodeRadius looks for the configuration file in the repository root:
coderadius.yamlcoderadius.yml
The first file found is used.
Further Reading
- CLI Reference —
cr analyze code --forceand other commands that interact with this configuration