Skip to content

city.json

The code city: one flat, sorted, JSON-shaped tree. No classes, no cycles, no Maps — it must survive JSON.stringify unchanged and arrive intact in a browser. Written by city; the same shape with an extra replay block is written by replay and by history --city.

Field names are those of CityModel in packages/city/src/city.ts.

Top level

Field Type Meaning
kind string always codegraph.city/1
generatedBy string always @codegraph/city
view ViewDescriptor {name, filters} — the view the city was built under
corpus {name, roots, repository?} display name, the model roots verbatim, and the union’s repository facts when every model that carries one agrees
conventions object what the renderer may assume; see below
bindings ResolvedBinding[] the legend in machine form, one entry per bound channel
districts District[] sorted by id
buildings Building[] sorted by id
arrows Arrow[] type-level dependencies, sorted by (from, to)
districtArrows Arrow[] module-level dependencies between districts, from the analyzer’s fold at level: "module" under the same view
roles {framework, values} present only with --framework: which framework spoke and the distinct roles it assigned, sorted
diagnostics CityDiagnostics what the transform left out
layout ResolvedLayout present only after --layout
bounds Bounds present only after --layout: the whole ground plane
replay CityReplay present only in a replay city

conventions

Field Value Meaning
arrowAttachment "roof" arrows attach at the roof of each building, at both ends
heightAxis "y" height grows along this axis
groundPlane "xz" the plane the districts tile
units "city" abstract city units — not metres, not pixels; only ratios mean anything

bindings[]ResolvedBinding

Field Type Meaning
channel "height" | "footprint"
metric string the resolved metric name (loc, sum:cyclomatic, …)
unit string what one unit of the value is, for the legend
describe string the metric source’s own one-line description
scale "linear" | "sqrt" | "log"
range {min, max} the dimension given to the smallest and largest measured value
domain {min, max} observed across the buildings that had a value; absent when none did
unmeasured integer buildings the model could not measure on this channel

See City metrics.

districts[]District

Field Type Meaning
id EntityId the module’s rendered id
name string | undefined
kind string the entity kind, verbatim from the model
isStub boolean
identity {lang, module, symbol, disambiguator?} symbol is empty exactly when the element IS the module
parent EntityId the nearest ancestor module that is itself a district, when the model declares module containment; never derived from the id or the name
buildings EntityId[] sorted; every building whose type folds into this module
footprintDemand number total base area its buildings occupy, in city units²
bounds {x, y, width, depth} after --layout

buildings[]Building

Field Type Meaning
id EntityId
name string | undefined
kind string the entity kind, verbatim: class, interface, enum
isStub boolean
district EntityId
identity {lang, module, symbol, disambiguator?}
source {file, span?} the anchor, for source links; absent when the model anchors nothing (stubs)
role string the architectural role a framework profile assigns, with --framework; absent means the framework says nothing about it, never “plain”
height number along the height axis
footprint {width, depth} base rectangle
metrics Record<string, number | null> raw measurements by metric name — the bound channels plus anything --carry asked for; null means the model does not say
attributes {name, type?, value?}[] sorted by name; empty for stubs and memberless types, never absent
operations {signature, parameters?}[] sorted by signature; a parameter is {name, type?}
owner {name, share} dominant author of the element’s file, replay cities only and only when a history was joined
position {x, y} after --layout: minimum corner of the footprint, absolute in city coordinates

arrows[] and districtArrows[]Arrow

Field Type Meaning
from, to EntityId
count integer base edges aggregated into this arrow
kinds EdgeKind[] sorted
provenances Provenance[] sorted
inferred boolean true when at least one base edge is not declared — precomputed so the renderer cannot get the rule wrong
crossDistrict boolean true when the endpoints stand in different districts; trivially true on districtArrows
feedback boolean true when this dependency is in the minimum feedback set of its strongly connected component at its own fold level

Buildings reference their district and districts list their buildings: both directions are stored in the artifact even though one is derivable, because a renderer walks both ways per frame. This is not the interchange model, where inverse indexes are never serialized.

diagnosticsCityDiagnostics

Field Type Meaning
unplacedBuildings EntityId[] types whose module the model does not give; excluded, sorted
droppedArrows integer arrows dropped because an endpoint was not placed
selfArrows integer type-level self-dependencies, excluded
droppedDistrictArrows integer district arrows dropped because an endpoint module is not a district here
selfDistrictArrows integer module-level self-dependencies, excluded — internal cohesion, not an arrow
unmeasured Record<string, number> per metric name, how many buildings the model could not measure
fold {unfoldableEntities, droppedEdges, foldedEdges} passed through from the fold that produced the buildings

layoutResolvedLayout

Field Value on the default run Meaning
algorithm "shelf-rows"
order "area-desc,id-asc"
buildingGap 2 street kept open between two buildings of one district
districtPadding 3 sidewalk between a district’s border and its outermost buildings
districtGap 6 avenue kept open between two districts

replayCityReplay

Present in a replay city only.

Field Type Meaning
clock "commits" | "revisions" what a tick IS: every commit of a mined history, or the sampled revisions of a temporal store
ticks {hash, time, author, fix?}[] chronological; time is unix seconds
series Record<string, [tick, height, heat?][]> building id → sparse keyframes. A keyframe holds until the next one; before the first the building does not exist (height 0), and height 0 later means the element is deleted
coChange {a, b, support, confidence}[] logical-coupling arcs between buildings, mined from history — an INFERENCE, never a dependency. Absent when no history was joined

Excerpt

codegraph city fixtures/java/expected/model.jsonl --layout, trimmed to one district, one building and one arrow of each kind:

{
  "kind": "codegraph.city/1",
  "generatedBy": "@codegraph/city",
  "view": { "name": "all", "filters": [] },
  "corpus": { "name": "src", "roots": ["fixtures/java/src"] },
  "conventions": { "arrowAttachment": "roof", "heightAxis": "y", "groundPlane": "xz", "units": "city" },
  "bindings": [
    { "channel": "height", "metric": "loc", "unit": "source lines",
      "describe": "Lines the type's own source anchor spans (end - start + 1).",
      "scale": "linear", "range": { "min": 1, "max": 40 }, "domain": { "min": 4, "max": 51 },
      "unmeasured": 18 },
    { "channel": "footprint", "metric": "members", "unit": "entities",
      "describe": "Base entities that folded into the building, the type included.",
      "scale": "sqrt", "range": { "min": 2, "max": 20 }, "domain": { "min": 1, "max": 22 },
      "unmeasured": 0 }
  ],
  "districts": [
    { "id": "java:com.megacorp.ledger", "name": "com.megacorp.ledger", "kind": "package",
      "isStub": true,
      "identity": { "lang": "java", "module": "com.megacorp.ledger", "symbol": "" },
      "buildings": ["java:com.megacorp.ledger/LedgerClient"],
      "footprintDemand": 4,
      "bounds": { "x": 46, "y": 84.673, "width": 8, "depth": 8 } }
  ],
  "buildings": [
    { "id": "java:com.acme.order.adapter/LedgerAdapter", "name": "LedgerAdapter", "kind": "class",
      "isStub": false, "district": "java:com.acme.order.adapter",
      "identity": { "lang": "java", "module": "com.acme.order.adapter", "symbol": "LedgerAdapter" },
      "source": { "file": "com/acme/order/adapter/LedgerAdapter.java", "span": [6, 15] },
      "height": 5.979, "footprint": { "width": 8.029, "depth": 8.029 },
      "metrics": { "loc": 10, "members": 5 },
      "attributes": [{ "name": "trail", "type": "AuditTrail" }],
      "operations": [
        { "signature": "<init>()", "parameters": [] },
        { "signature": "post(java.lang.Object)",
          "parameters": [{ "name": "document", "type": "Object" }] }
      ],
      "position": { "x": 24.013, "y": 28 } }
  ],
  "arrows": [
    { "from": "java:com.acme.order.adapter/LedgerAdapter",
      "to": "java:com.megacorp.ledger/LedgerClient",
      "count": 1, "kinds": ["inheritance"], "provenances": ["declared"],
      "inferred": false, "crossDistrict": true, "feedback": false }
  ],
  "districtArrows": [
    { "from": "java:com.acme.order", "to": "java:com.acme.order.legacy",
      "count": 2, "kinds": ["invocation", "reference"], "provenances": ["declared"],
      "inferred": false, "crossDistrict": true, "feedback": false }
  ],
  "diagnostics": {
    "unplacedBuildings": ["java:com.acme.order.adapter/AuditTrail", "java:com.acme.order/Invoice"],
    "droppedArrows": 2, "selfArrows": 12,
    "droppedDistrictArrows": 0, "selfDistrictArrows": 3,
    "unmeasured": { "loc": 18, "members": 0 },
    "fold": { "unfoldableEntities": 10, "droppedEdges": 11, "foldedEdges": 177 }
  },
  "layout": { "algorithm": "shelf-rows", "order": "area-desc,id-asc",
              "buildingGap": 2, "districtPadding": 3, "districtGap": 6 },
  "bounds": { "x": 0, "y": 0, "width": 85.55, "depth": 96.673 }
}

Why the city is a model rather than a picture: The city is a model.

Last updated on