CodeRadius LogoCodeRadius Docs

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.

coderadius.yaml
package.json

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.

SectionEngineWhat it does
packagesTaint (AST)Controls which packages to analyze, ignore, or map to services
decoratorsASTTeaches CodeRadius to recognize custom framework decorators
databasesGraphDeclares database identity, technology, and table ownership
hintsAI (LLM)Provides natural language instructions for proprietary SDKs
messageBrokersStructuralDeclares physical broker instances (cluster, host, vhost, env) so DSN env-vars do not break weld identity
message_channelsGraphAliases (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 URL

SDK entry kind values

KindWhat it tells the AIGenerated graph node
http-clientMethod calls on this SDK are outbound HTTP API callsAPIEndpoint (OUTBOUND)
broker-clientPublish/emit/send calls are message channel writesMessageChannel (WRITES)
db-clientRead/write calls are data container I/ODataContainer

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

KindWhat it creates
message-consumerA MessageChannel node with a LISTENS_TO edge
http-routeAn APIEndpoint node with an EXPOSES edge
scheduled-jobA 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:

  1. URN scope resolution — determines the identity of DataTable nodes in the graph
  2. Datastore declaration — creates Datastore infrastructure 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:orders

This 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 infrastructure

Field reference

FieldRequiredDefaultDescription
idStable logical ID. Becomes a URN segment. Must be unique within the repo.
technologyTechnology identifier: mysql, postgres, mongodb, redis, s3, etc.
sharedfalseIf 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

PatternMatches
ordersOnly orders (exact)
wp_*wp_posts, wp_options, etc.
*_logsaudit_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

  1. The AST parser scans the file for imports matching any patterns keyword
  2. If matched, the description text is injected into the LLM prompt
  3. 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

SignalUse
SDK maps to a specific servicepackages.services (deterministic, no LLM)
Custom decorator patterndecorators (deterministic, no LLM)
Proprietary wrapper with complex semanticshints (AI-assisted)
Package should be analyzed but no context neededpackages.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-1

Field reference

FieldRequiredNotes
idyesStable identifier referenced from message_channels.mirrors[].physical[].broker.
provideryesOne of: rabbitmq, kafka, pubsub, sqs, sns, azure-service-bus, nats, pulsar, redis-streams, mqtt, mosquitto, zeromq, symfony-messenger.
hostnoDNS hostname or IP.
portnoTCP port.
vhostnoRabbitMQ vhost (or Pulsar namespace). Root / is omitted from the URN; named vhosts are slugified.
regionnoAWS / GCP / Azure region tag. Surfaced on the graph for environment filtering.
envnoFree-form environment label (dev, staging, prod).
clusternoLogical cluster name when multiple physical hosts back the same cluster.
fingerprintnoOverride 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: pubsub

mirrors

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, table

The 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:

  1. coderadius.yaml
  2. coderadius.yml

The first file found is used.


Further Reading

  • CLI Referencecr analyze code --force and other commands that interact with this configuration

On this page