Repository navigation
Node IDs
Every node in the chart has a string id, and every edge, lock pin, annotation and CLI argument refers to nodes by that id. This page lists every id convention: entities and facts (yours to choose) and code ids (generated by the ingestor, one format per node kind and language). It also covers how scopes prefix code ids, why the ids are designed to be stable, and how the CLI resolves shorthand refs. Every example below was produced by starchart query on the demo or on the ingestor's test fixtures.
Code ids are built from names, not positions: scope + path + qualified name, never line numbers or hashes. Move a function down a file, reformat it or change its body, and its id stays put. Only its hash changes, which is exactly what the lockfile tracks. Rename or move a symbol and you get a new id. That's a real change, and STARCHART treats it as one (the old id vanishes from the graph, so dependents pinned to it go stale).
The same goes for facts: addon:pro.price.usd means the same thing forever, which is why it can live in YAML, annotations, lockfiles and PR comments.
| Kind | Format | Example |
|---|---|---|
| entity | any string you choose; convention <kind>:<name>
|
addon:pro, app:nebula
|
| fact | <entity>.<key>[.<key>…] |
addon:pro.price.usd |
| implicit status fact | <entity>.status |
addon:pro.status |
| design token entity |
tokens (fixed) |
tokens |
| design token | tokens.<dtcg path> |
tokens.color.brand.primary |
Pick entity ids with a colon. @starchart annotations read targets until the first word that has neither a : nor a . (see Annotations). Dotted ids without a colon work, so // @starchart anchors tokens.color.brand.primary anchors a token, but a bare entity id with neither character (the tokens entity itself, or a hypothetical brand) can't be an annotation target. Avoid . inside fact keys; it's the path separator.
Code ids always start with a kind prefix. Most of them include the scope name from code.scopes in Configuration:
| Kind | Format | Example |
|---|---|---|
| file | file:<scope>/<path in scope> |
file:ios/Sources/Core/Pricing.swift |
| test file |
test:<scope>/<path in scope> (replaces file:) |
test:ios/Tests/PaywallTests.swift |
| symbol |
symbol:<scope>/… (per language, below) |
symbol:ios/Pricing.proUSD |
| screen | screen:<scope>/<Name> |
screen:ios/Paywall |
| route | route:<scope>/<url path> |
route:web/pricing |
| root route | route:<scope>/ |
route:web/ |
| i18n key | i18n:<scope>/<key> |
i18n:ios/paywall.title |
| package |
pkg:<manager>/<name> (no scope) |
pkg:npm/stripe |
| env var |
env:<NAME> (no scope) |
env:STRIPE_SECRET_KEY |
| feature flag |
flag:<key> (no scope) |
flag:new-paywall |
| analytics event |
event:<name> (no scope) |
event:pro_checkout_started |
Packages, env vars, flags and events are global: two scopes reading STRIPE_SECRET_KEY point at the same env:STRIPE_SECRET_KEY node.
| Language | Format | Examples |
|---|---|---|
| TypeScript / JavaScript | symbol:<scope>/<path without extension>#<qualified name> |
symbol:web/lib/pricing#PRO_PRICE_USD, symbol:web/app/pricing/page#PricingPage, symbol:web/lib/starchart-facts#ADDON_PRO.name (object member), symbol:web/app/api/checkout/route#POST
|
| Swift |
symbol:<scope>/<Type path>.<member> (no file, no module) |
symbol:ios/Pricing.proUSD, symbol:ios/StarchartFacts.AddonPro.Price.usd (nested types) |
| Kotlin |
symbol:<scope>/<Type path>.<member> (no file, no package) |
symbol:android/Pricing.PRO_USD, symbol:android/Tier.isPaid
|
| Go | symbol:<scope>/<package dir>.<name> |
symbol:api/internal/pricing.ProUSD, symbol:api/internal/pricing.Plan.Total (method), symbol:api/main.main
|
Details that matter:
-
TS: the extension (
.ts,.tsx,.js,.jsx,.mjs,.cjs,.mts,.cts,.mdx) is stripped;indexis kept (lib/index#foo).export default <expr>becomes#default. Class and object members areOwner.member. -
Swift: ids come from the type path only, so an
extension PricinginPricing+EUR.swiftadds members to the samesymbol:ios/Pricingnode. When one id is declared in several files, STARCHART keeps one node, combines the hashes and lists the other files inmeta.alsoIn. Top-level functions aresymbol:<scope>/<name>. -
Kotlin: members use the enclosing type path. A top-level extension function
fun Tier.label()becomesTier.label. -
Go: the namespace is the file's directory relative to the scope. A file at the scope root uses its
packagename (main), falling back tomain. Methods are<ns>.<Receiver>.<Method>. -
Test files get no symbol nodes. They're a single
test:node withtestsedges.
| Source | Rule | Example |
|---|---|---|
| SwiftUI | top-level struct X: View, name minus a trailing View or Screen
|
PaywallView → screen:ios/Paywall
|
| Jetpack Compose |
@Composable fun XScreen(...), name minus Screen
|
PaywallScreen → screen:android/Paywall
|
| TS/React | no automatic detection; use @starchart screen <Name>
|
screen:web/Checkout |
| Annotation with a full id | @starchart screen screen:web/Checkout |
used as-is |
Routes are detected only in scopes that have a next.config.* file or a next dependency in package.json.
| Router | File | Route id |
|---|---|---|
| App | app/page.tsx |
route:web/ |
| App | app/pricing/page.tsx |
route:web/pricing |
| App | app/(marketing)/about/page.tsx |
route:web/about (route groups dropped) |
| App | app/blog/[slug]/page.tsx |
route:web/blog/[slug] |
| App | app/api/checkout/route.ts |
route:web/api/checkout (API handler) |
| Pages | pages/index.tsx |
route:web/ |
| Pages | pages/about.tsx |
route:web/about |
src/app and src/pages work too. Segments starting with _ are private and produce no route. @slot parallel-route segments are dropped from the URL. The route's label and meta.url carry the leading slash (/pricing).
| Package manager | Manifest(s) | Id | Example |
|---|---|---|---|
| npm |
package.json (plus bare imports of undeclared packages) |
pkg:npm/<name> |
pkg:npm/@sentry/nextjs |
| SwiftPM |
Package.resolved, Package.swift, project.pbxproj
|
pkg:swift/<identity, lowercased> |
pkg:swift/purchases-ios |
| Gradle |
build.gradle(.kts), libs.versions.toml
|
pkg:gradle/<group>:<artifact> |
pkg:gradle/com.revenuecat.purchases:purchases |
| Go | go.mod |
pkg:go/<module path> |
pkg:go/github.com/stripe/stripe-go/v76 |
i18n:<scope>/<key>, where the key comes from .xcstrings, *.lproj/*.strings, Android res/values*/strings.xml, or JSON files under a locales, locale, i18n, messages, lang or translations directory. The node's value maps locale → string:
i18n i18n:ios/paywall.title = {"en":"Unlock Nebula Pro","ja":"Nebula Pro を解放"}
i18n i18n:web/pricing.cta = {"en":"Get Nebula Pro for $4.99/month"}
code.scopes maps a scope name to a directory. The name becomes the id prefix, so pick short, stable names (ios, web, api). Rules from code/files.ts:
- Default is
{ app: "." }. - Paths in ids are relative to the scope directory:
apps/ios/Sources/Core/Pricing.swiftin scopeios: apps/iosisfile:ios/Sources/Core/Pricing.swift. - Nested scopes win: each file belongs to exactly one scope, the most specific one.
- Files outside every scope are not ingested.
- Renaming a scope renames every code id under it. Relock afterwards.
Commands that take a node ref (impact, why, node) resolve it with resolveRef in api.ts:
- An exact node id.
- A file path, relative to your current directory. It resolves to the file (or test) node plus every symbol it contains.
- A unique id suffix (
Pricing.proUSD, or anything after a/) or an exact label. Multiple matches return up to 25 ids.
starchart impact apps/ios/Sources/Paywall/PaywallView.swiftChange: file:ios/Sources/Paywall/PaywallView.swift
Change: symbol:ios/PaywallView
Change: symbol:ios/PaywallView.body
…
Use starchart query --prefix <p>, --kind <k> or --text <t> to find ids.
★ STARCHART
☠ a Space Pirate Zero joint
STARCHART Every dependency. Code to cosmos.
Guides
Concepts
- Three-Layer Model
- Facts and Entities
- Artifacts and Bindings
- Edge Types
- Node IDs
- Impact Analysis
- Lockfile and Drift
- Rollout Ordering
Authoring
Code layer
Commands & API
Adapters & engine
- Adapters Overview
- Adapter: fs
- Adapter: url
- Adapter: Stripe
- Adapter: App Store Connect
- Writing an Adapter
- Audit and Break Detection
- Apply, Revert and Journals
- Future Universe Preview
- Viewer and Serve
- Reality X-Ray
Rules & analysis
Integrations
Project