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

FieldTypeMeaning
kindstringalways codegraph.city/1
generatedBystringalways @codegraph/city
viewViewDescriptor{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
conventionsobjectwhat the renderer may assume; see below
bindingsResolvedBinding[]the legend in machine form, one entry per bound channel
districtsDistrict[]sorted by id
buildingsBuilding[]sorted by id
arrowsArrow[]type-level dependencies, sorted by (from, to)
districtArrowsArrow[]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
diagnosticsCityDiagnosticswhat the transform left out
layoutResolvedLayoutpresent only after --layout
boundsBoundspresent only after --layout: the whole ground plane
replayCityReplaypresent only in a replay city

conventions

FieldValueMeaning
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

FieldTypeMeaning
channel"height" | "footprint"
metricstringthe resolved metric name (loc, sum:cyclomatic, …)
unitstringwhat one unit of the value is, for the legend
describestringthe 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
unmeasuredintegerbuildings the model could not measure on this channel

See City metrics.

districts[] — District

FieldTypeMeaning
idEntityIdthe module’s rendered id
namestring | undefined
kindstringthe entity kind, verbatim from the model
isStubboolean
identity{lang, module, symbol, disambiguator?}symbol is empty exactly when the element IS the module
parentEntityIdthe nearest ancestor module that is itself a district, when the model declares module containment; never derived from the id or the name
buildingsEntityId[]sorted; every building whose type folds into this module
footprintDemandnumbertotal base area its buildings occupy, in city units²
bounds{x, y, width, depth}after --layout

buildings[] — Building

FieldTypeMeaning
idEntityId
namestring | undefined
kindstringthe entity kind, verbatim: class, interface, enum…
isStubboolean
districtEntityId
identity{lang, module, symbol, disambiguator?}
source{file, span?}the anchor, for source links; absent when the model anchors nothing (stubs)
rolestringthe architectural role a framework profile assigns, with --framework; absent means the framework says nothing about it, never “plain”
heightnumberalong the height axis
footprint{width, depth}base rectangle
metricsRecord<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

FieldTypeMeaning
from, toEntityId
countintegerbase edges aggregated into this arrow
kindsEdgeKind[]sorted
provenancesProvenance[]sorted
inferredbooleantrue when at least one base edge is not declared — precomputed so the renderer cannot get the rule wrong
crossDistrictbooleantrue when the endpoints stand in different districts; trivially true on districtArrows
feedbackbooleantrue 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.

diagnostics — CityDiagnostics

FieldTypeMeaning
unplacedBuildingsEntityId[]types whose module the model does not give; excluded, sorted
droppedArrowsintegerarrows dropped because an endpoint was not placed
selfArrowsintegertype-level self-dependencies, excluded
droppedDistrictArrowsintegerdistrict arrows dropped because an endpoint module is not a district here
selfDistrictArrowsintegermodule-level self-dependencies, excluded — internal cohesion, not an arrow
unmeasuredRecord<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

layout — ResolvedLayout

FieldValue on the default runMeaning
algorithm"shelf-rows"
order"area-desc,id-asc"
buildingGap2street kept open between two buildings of one district
districtPadding3sidewalk between a district’s border and its outermost buildings
districtGap6avenue kept open between two districts

replay — CityReplay

Present in a replay city only.

FieldTypeMeaning
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
seriesRecord<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