[{"data":1,"prerenderedAt":1830},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fexternal":135,"\u002Fdocs\u002Fexternal-surround":1825},[4],{"title":5,"path":6,"stem":7,"children":8,"page":134},"Docs","\u002Fdocs","docs",[9,13,17,21,25,29,33,37,41,45,49,53,57,61,70,74,78,82,86,90,94,98,102,106,110,114,118,122,126,130],{"title":10,"path":11,"stem":12},"AI harnesses: LLM tools, MCP servers and agents","\u002Fdocs\u002Fai-tools","docs\u002Fai-tools",{"title":14,"path":15,"stem":16},"Architecture","\u002Fdocs\u002Farchitecture","docs\u002Farchitecture",{"title":18,"path":19,"stem":20},"Web \u002F native bridges","\u002Fdocs\u002Fbridges","docs\u002Fbridges",{"title":22,"path":23,"stem":24},"Broadcast channels and tests","\u002Fdocs\u002Fchannels-and-tests","docs\u002Fchannels-and-tests",{"title":26,"path":27,"stem":28},"CLI reference","\u002Fdocs\u002Fcli","docs\u002Fcli",{"title":30,"path":31,"stem":32},"Completeness: how far an answer reaches","\u002Fdocs\u002Fcompleteness","docs\u002Fcompleteness",{"title":34,"path":35,"stem":36},"Configuration","\u002Fdocs\u002Fconfiguration","docs\u002Fconfiguration",{"title":38,"path":39,"stem":40},"External systems","\u002Fdocs\u002Fexternal","docs\u002Fexternal",{"title":42,"path":43,"stem":44},"Generated, copied and vendored files","\u002Fdocs\u002Fgenerated","docs\u002Fgenerated",{"title":46,"path":47,"stem":48},"Installing and updating cg","\u002Fdocs\u002Finstall","docs\u002Finstall",{"title":50,"path":51,"stem":52},"Java","\u002Fdocs\u002Fjava","docs\u002Fjava",{"title":54,"path":55,"stem":56},"Kotlin","\u002Fdocs\u002Fkotlin","docs\u002Fkotlin",{"title":58,"path":59,"stem":60},"Known limitations","\u002Fdocs\u002Flimitations","docs\u002Flimitations",{"title":62,"path":63,"stem":64,"children":65},"MCP server","\u002Fdocs\u002Fmcp","docs\u002Fmcp",[66],{"title":67,"path":68,"stem":69},"code-graph MCP: sample outputs (real calls via the MCP Python SDK stdio client)","\u002Fdocs\u002Fmcp\u002Fsample_outputs","docs\u002Fmcp\u002Fsample_outputs",{"title":71,"path":72,"stem":73},"Rust, C and C++","\u002Fdocs\u002Fnative","docs\u002Fnative",{"title":75,"path":76,"stem":77},"Port gaps: cg parity","\u002Fdocs\u002Fparity","docs\u002Fparity",{"title":79,"path":80,"stem":81},"PHP","\u002Fdocs\u002Fphp","docs\u002Fphp",{"title":83,"path":84,"stem":85},"Planned changes","\u002Fdocs\u002Fplans","docs\u002Fplans",{"title":87,"path":88,"stem":89},"Platform-specific code","\u002Fdocs\u002Fplatforms","docs\u002Fplatforms",{"title":91,"path":92,"stem":93},"Protocol links","\u002Fdocs\u002Fprotocols","docs\u002Fprotocols",{"title":95,"path":96,"stem":97},"Python","\u002Fdocs\u002Fpython","docs\u002Fpython",{"title":99,"path":100,"stem":101},"Quick start","\u002Fdocs\u002Fquickstart","docs\u002Fquickstart",{"title":103,"path":104,"stem":105},"Graph schema","\u002Fdocs\u002Fschema","docs\u002Fschema",{"title":107,"path":108,"stem":109},"Attack surface","\u002Fdocs\u002Fsurface","docs\u002Fsurface",{"title":111,"path":112,"stem":113},"Swift","\u002Fdocs\u002Fswift","docs\u002Fswift",{"title":115,"path":116,"stem":117},"TypeScript \u002F JavaScript frameworks","\u002Fdocs\u002Fts-frameworks","docs\u002Fts-frameworks",{"title":119,"path":120,"stem":121},"How we validate","\u002Fdocs\u002Fvalidation","docs\u002Fvalidation",{"title":123,"path":124,"stem":125},"Validation log","\u002Fdocs\u002Fvalidation-log","docs\u002Fvalidation-log",{"title":127,"path":128,"stem":129},"Value facts and resolutions","\u002Fdocs\u002Fvalue-facts","docs\u002Fvalue-facts",{"title":131,"path":132,"stem":133},"Visual view","\u002Fdocs\u002Fviz","docs\u002Fviz",false,{"id":136,"title":38,"body":137,"description":143,"extension":1820,"meta":1821,"navigation":1822,"path":39,"seo":1823,"stem":40,"__hash__":1824},"docs\u002Fdocs\u002Fexternal.md",{"type":138,"value":139,"toc":1815},"minimark",[140,144,155,181,1046,1051,1107,1153,1184,1277,1354,1435,1476,1482,1613,1624,1694,1717,1764,1769,1799,1811],[141,142,143],"p",{},"A Postgres server, Redis, SMTP, LDAP, SFTP or S3 bucket is one node. The address usually lives\nin configuration, not in the call.",[145,146,151],"pre",{"className":147,"code":149,"language":150},[148],"language-text","code -CONNECTS_TO-> external:\u003Cprotocol>:\u003Ctarget>\nexternal -CONFIGURED_BY-> env:\u003CKEY> | config:\u003Ckey>\nexternal -CREDENTIAL_FROM-> env:\u003CKEY>          # where the secret is, never its value\n","text",[152,153,149],"code",{"__ignoreMap":154},"",[141,156,157,160,161,164,165,168,169,172,173,176,177,180],{},[152,158,159],{},"target"," is ",[152,162,163],{},"host:port"," when a literal, a DSN, ",[152,166,167],{},".env.example"," or a compose service names it;\n",[152,170,171],{},"config:\u003Cmodule>.\u003Csetting>"," for a settings dict aimed at the local machine; otherwise\n",[152,174,175],{},"env:\u003CKEY>",". After ",[152,178,179],{},"cg link",", two repos that name the same address share the node.",[182,183,184,197],"table",{},[185,186,187],"thead",{},[188,189,190,194],"tr",{},[191,192,193],"th",{},"source",[191,195,196],{},"what becomes a node",[198,199,200,212,252,279,289,329,365,386,518,542,694,780,860,937,1000],"tbody",{},[188,201,202,209],{},[203,204,205,206],"td",{},"Laravel ",[152,207,208],{},"config\u002Fdatabase.php",[203,210,211],{},"the default connection, connections models use, custom connections. Unused framework templates are skipped",[188,213,214,220],{},[203,215,216,219],{},[152,217,218],{},"READS_ENV"," prefixes",[203,221,222,225,226,225,229,225,232,235,236,225,239,225,242,225,245,225,248,251],{},[152,223,224],{},"DB_*",", ",[152,227,228],{},"DATABASE_URL",[152,230,231],{},"REDIS_*",[152,233,234],{},"MAIL_*"," (only when the mailer is smtp), ",[152,237,238],{},"MONGO*",[152,240,241],{},"AMQP_*",[152,243,244],{},"LDAP_*",[152,246,247],{},"S3_*",[152,249,250],{},"KAFKA_*",", …",[188,253,254,264],{},[203,255,256,257,260,261],{},"Python ",[152,258,259],{},"*settings*"," \u002F ",[152,262,263],{},"*config*",[203,265,266,267,260,270,225,273,225,275,278],{},"Django ",[152,268,269],{},"DATABASES",[152,271,272],{},"CACHES",[152,274,228],{},[152,276,277],{},"CELERY_BROKER_URL",". sqlite and local-memory caches are not network systems",[188,280,281,286],{},[203,282,283,285],{},[152,284,167],{}," and compose",[203,287,288],{},"non-secret values; compose services with a known image (postgres, redis, kafka broker images, …). A broker no client mentions is still listed, with no CONNECTS_TO",[188,290,291,294],{},[203,292,293],{},"client constructors",[203,295,296,297,225,300,225,303,225,306,225,309,312,313,225,316,225,319,225,322,225,325,328],{},"Python (",[152,298,299],{},"psycopg",[152,301,302],{},"redis",[152,304,305],{},"pymongo",[152,307,308],{},"pika",[152,310,311],{},"boto3",", …) and Node (",[152,314,315],{},"pg",[152,317,318],{},"ioredis",[152,320,321],{},"mongoose",[152,323,324],{},"amqplib",[152,326,327],{},"knex",", …). A localhost default is not a system",[188,330,331,334],{},[203,332,333],{},"ORM datasources",[203,335,336,337,340,341,344,345,348,349,352,353,356,357,360,361,364],{},"Prisma ",[152,338,339],{},"datasource",", TypeORM ",[152,342,343],{},"DataSource",", Drizzle ",[152,346,347],{},"dbCredentials",", Laravel tables on ",[152,350,351],{},"$connection",", PHP ",[152,354,355],{},"new PDO",", Spring ",[152,358,359],{},"spring.datasource.url",". sqlite \u002F H2 \u002F HSQLDB \u002F Derby are skipped. The one SQL system in a repo is attached to ORM tables that name none (",[152,362,363],{},"via: sole \u003Cprotocol> system",")",[188,366,367,370],{},[203,368,369],{},"Redis \u002F Elasticsearch",[203,371,372,373,260,376,379,380,260,383],{},"literal key prefixes and ",[152,374,375],{},"KEY_PREFIX",[152,377,378],{},"ELASTICSEARCH_INDEX_PREFIX"," on ",[152,381,382],{},"attrs.key_prefixes",[152,384,385],{},"attrs.indices",[188,387,388,391],{},[203,389,390],{},"HTTP and SDKs",[203,392,393,396,397,225,400,225,403,225,406,225,409,412,413,416,417,225,420,225,423,225,426,225,429,225,432,225,435,225,438,441,442,225,445,225,448,451,452,455,456,459,460,412,463,225,466,225,469,225,472,225,475,225,478,459,481,225,484,225,487,225,490,493,494,497,498,501,502,260,505,508,509,511,512,515,516],{},[152,394,395],{},"external:http(s):\u003Chost>:\u003Cport>"," for a real other-origin host; ",[152,398,399],{},"external:s3:\u003Cbucket>",[152,401,402],{},"gcs",[152,404,405],{},"azure-blob",[152,407,408],{},"aws:\u003Cservice>",[152,410,411],{},"saas:\u003Cprovider>"," (",[152,414,415],{},"stripe",", the mail \u002F SMS APIs ",[152,418,419],{},"sendgrid",[152,421,422],{},"mailgun",[152,424,425],{},"postmark",[152,427,428],{},"resend",[152,430,431],{},"twilio",[152,433,434],{},"vonage",[152,436,437],{},"messagebird",[152,439,440],{},"plivo",", and the push services ",[152,443,444],{},"apns",[152,446,447],{},"webpush",[152,449,450],{},"expo-push","; SES is ",[152,453,454],{},"aws:ses",", KMS is ",[152,457,458],{},"aws:kms[:key]","), ",[152,461,462],{},"gcp:\u003Cservice>[:resource]",[152,464,465],{},"fcm",[152,467,468],{},"firestore[:collection]",[152,470,471],{},"firebase-rtdb",[152,473,474],{},"firebase-auth",[152,476,477],{},"secretmanager[:secret]",[152,479,480],{},"kms",[152,482,483],{},"azure:keyvault[:vault-host]",[152,485,486],{},"k8s:\u003Capi-group>",[152,488,489],{},"docker:\u003Csocket-or-host:port>",[152,491,492],{},"llm:\u003Cprovider>",". Loopback and ",[152,495,496],{},"${host}"," stay unattached. Test-only callers are left out. A PHP ",[152,499,500],{},"Http"," \u002F Guzzle call whose host is a literal is one of these nodes; a base read from ",[152,503,504],{},"config()",[152,506,507],{},"env()"," stays a client endpoint (sample value from ",[152,510,167],{}," only, never ",[152,513,514],{},".env",") and is matched by ",[152,517,179],{},[188,519,520,523],{},[203,521,522],{},"Laravel disks \u002F django-storages",[203,524,525,260,528,260,530,533,534,537,538,541],{},[152,526,527],{},"s3",[152,529,402],{},[152,531,532],{},"azure"," disks. ",[152,535,536],{},"Storage::disk"," and ",[152,539,540],{},"default_storage.save"," connect to that disk",[188,543,544,547],{},[203,545,546],{},"Mail and SMS APIs",[203,548,549,550,225,553,225,556,225,559,225,562,225,565,225,568,225,571,574,575,225,578,225,581,225,583,225,585,225,587,225,590,225,592,594,595,225,597,225,600,225,603,225,605,225,607,225,609,611,612,615,616,225,618,225,620,225,622,625,626,260,629,260,632,635,636,639,640,642,643,646,647,649,650,260,653,260,656,659,660,663,664,667,668,225,671,673,674,676,677,680,681,684,685,260,688,260,691],{},"PHP ",[152,551,552],{},"sendgrid\u002Fsendgrid",[152,554,555],{},"mailgun\u002Fmailgun-php",[152,557,558],{},"wildbit\u002Fpostmark-php",[152,560,561],{},"resend\u002Fresend-php",[152,563,564],{},"twilio\u002Fsdk",[152,566,567],{},"vonage\u002Fclient",[152,569,570],{},"messagebird\u002Fphp-rest-api",[152,572,573],{},"plivo\u002Fplivo-php","; TS ",[152,576,577],{},"@sendgrid\u002Fmail",[152,579,580],{},"mailgun.js",[152,582,425],{},[152,584,428],{},[152,586,431],{},[152,588,589],{},"@vonage\u002Fserver-sdk",[152,591,437],{},[152,593,440],{},"; Python ",[152,596,419],{},[152,598,599],{},"twilio.rest",[152,601,602],{},"postmarker",[152,604,428],{},[152,606,434],{},[152,608,437],{},[152,610,440],{},". Laravel ",[152,613,614],{},"config\u002Fmail.php"," mailers (",[152,617,422],{},[152,619,425],{},[152,621,428],{},[152,623,624],{},"ses","; ",[152,627,628],{},"smtp",[152,630,631],{},"sendmail",[152,633,634],{},"log"," are skipped, SMTP is its own system) read their keys from ",[152,637,638],{},"config\u002Fservices.php","; the default mailer (",[152,641,167],{}," ",[152,644,645],{},"MAIL_MAILER",", else the ",[152,648,507],{}," fallback) is used by ",[152,651,652],{},"Mail::send",[152,654,655],{},"Mail::to()->send()",[152,657,658],{},"Mail::raw",", and ",[152,661,662],{},"Mail::mailer('x')"," names one. A notification ",[152,665,666],{},"via()"," returning ",[152,669,670],{},"mail",[152,672,434],{}," or ",[152,675,431],{}," connects to that provider. Django ",[152,678,679],{},"EMAIL_BACKEND = \"anymail.backends.\u003Cesp>.EmailBackend\""," with the ",[152,682,683],{},"ANYMAIL"," dict is one node used by ",[152,686,687],{},"send_mail",[152,689,690],{},"send_mass_mail",[152,692,693],{},"EmailMessage.send",[188,695,696,699],{},[203,697,698],{},"Push",[203,700,701,702,705,706,225,709,712,713,352,716,642,719,722,723,726,727,729,730,733,734,260,737,642,740,712,743,260,746,352,749,225,752,729,755,758,759,642,762,225,765,225,768,729,771,625,774,160,777],{},"FCM through ",[152,703,704],{},"firebase-admin"," messaging (TS ",[152,707,708],{},"getMessaging().send",[152,710,711],{},"admin.messaging()",", Python ",[152,714,715],{},"messaging.send",[152,717,718],{},"kreait\u002Ffirebase-php",[152,720,721],{},"createMessaging()->send",", Laravel ",[152,724,725],{},"laravel-notification-channels\u002Ffcm"," via ",[152,728,666],{},") is ",[152,731,732],{},"external:gcp:fcm","; APNs (",[152,735,736],{},"@parse\u002Fnode-apn",[152,738,739],{},"apn",[152,741,742],{},"new apn.Provider",[152,744,745],{},"apns2",[152,747,748],{},"aioapns",[152,750,751],{},"edamov\u002Fpushok",[152,753,754],{},"laravel-notification-channels\u002Fapn",[152,756,757],{},"external:saas:apns","; Web Push (",[152,760,761],{},"web-push",[152,763,764],{},"sendNotification",[152,766,767],{},"pywebpush",[152,769,770],{},"minishlink\u002Fweb-push",[152,772,773],{},"external:saas:webpush",[152,775,776],{},"expo-server-sdk",[152,778,779],{},"external:saas:expo-push",[188,781,782,785],{},[203,783,784],{},"Firebase (server SDKs)",[203,786,787,788,225,791,225,794,797,798,225,801,729,804,807,808,811,812,815,816,225,819,797,822,729,825,828,829,832,833,260,836,260,839,260,842,845,846,160,849,852,853,225,856,859],{},"Firestore (",[152,789,790],{},"getFirestore().collection('orders')",[152,792,793],{},"admin.firestore()",[152,795,796],{},"firestore.client()",", kreait ",[152,799,800],{},"createFirestore()",[152,802,803],{},"@google-cloud\u002Ffirestore",[152,805,806],{},"external:gcp:firestore:\u003Ccollection>"," for a literal or env collection, ",[152,809,810],{},"external:gcp:firestore"," for transactions and other calls; Realtime Database is ",[152,813,814],{},"external:gcp:firebase-rtdb","; Auth admin (",[152,817,818],{},"getAuth().verifyIdToken",[152,820,821],{},"auth.verify_id_token",[152,823,824],{},"createAuth()",[152,826,827],{},"external:gcp:firebase-auth","; Storage buckets reuse ",[152,830,831],{},"external:gcs:\u003Cbucket>",". ",[152,834,835],{},"cert(...)",[152,837,838],{},"credentials.Certificate(...)",[152,840,841],{},"withServiceAccount(...)",[152,843,844],{},"GOOGLE_APPLICATION_CREDENTIALS"," give the credential; ",[152,847,848],{},"applicationDefault()",[152,850,851],{},"ambient",". Browser and mobile Firebase client SDKs (",[152,854,855],{},"firebase\u002Ffirestore",[152,857,858],{},"firebase\u002Fauth",") are not systems",[188,861,862,865],{},[203,863,864],{},"Kubernetes",[203,866,867,412,870,642,873,260,876,260,879,225,882,885,886,412,889,260,892,225,895,898,899,902,903,412,906,225,909,225,912,915,916,919,920,923,924,926,927,930,931,642,934],{},[152,868,869],{},"@kubernetes\u002Fclient-node",[152,871,872],{},"KubeConfig",[152,874,875],{},"loadFromDefault",[152,877,878],{},"loadFromCluster",[152,880,881],{},"loadFromFile",[152,883,884],{},"makeApiClient(CoreV1Api)","), Python ",[152,887,888],{},"kubernetes",[152,890,891],{},"config.load_incluster_config",[152,893,894],{},"load_kube_config",[152,896,897],{},"client.CoreV1Api().list_namespaced_pod","), PHP ",[152,900,901],{},"renoki-co\u002Fphp-k8s",": ",[152,904,905],{},"external:k8s:\u003Capi-group>",[152,907,908],{},"core-v1",[152,910,911],{},"apps-v1",[152,913,914],{},"batch-v1",", ...), ",[152,917,918],{},"op"," is the API method and ",[152,921,922],{},"namespace"," on the edge is a literal one. In-cluster and default kubeconfig are ",[152,925,851],{},"; a kubeconfig path from an env key is ",[152,928,929],{},"CREDENTIAL_FROM",", one written in the code is ",[152,932,933],{},"credential_source",[152,935,936],{},"file",[188,938,939,942],{},[203,940,941],{},"Docker Engine API",[203,943,944,412,947,225,950,225,953,885,956,412,959,225,962,225,965,898,968,902,971,974,975,978,979,981,982,985,986,989,990,260,993,260,996,999],{},[152,945,946],{},"dockerode",[152,948,949],{},"new Docker()",[152,951,952],{},"{ socketPath }",[152,954,955],{},"{ host, port }",[152,957,958],{},"docker",[152,960,961],{},"from_env()",[152,963,964],{},"DockerClient(base_url=...)",[152,966,967],{},"containers.run",[152,969,970],{},"docker-php",[152,972,973],{},"external:docker:\u003Ctarget>"," where the target is the socket path (",[152,976,977],{},"\u002Fvar\u002Frun\u002Fdocker.sock"," by default), ",[152,980,163],{},", or ",[152,983,984],{},"env:DOCKER_HOST"," when the address is read from it. Plain TCP without TLS is ",[152,987,988],{},"tls=false","; a TLS client reads ",[152,991,992],{},"ca",[152,994,995],{},"cert",[152,997,998],{},"key"," as its credential",[188,1001,1002,1005],{},[203,1003,1004],{},"Key management",[203,1006,1007,1008,1011,1012,225,1015,1018,1019,729,1022,1025,1026,1029,1030,1033,1034,225,1037,225,1040,729,1043],{},"AWS KMS (",[152,1009,1010],{},"KMSClient"," + ",[152,1013,1014],{},"EncryptCommand({ KeyId })",[152,1016,1017],{},"boto3.client('kms')",", aws-sdk-php ",[152,1020,1021],{},"KmsClient",[152,1023,1024],{},"external:aws:kms[:key]"," (an alias, key id or env key; an ARN is cut to the key id); GCP Secret Manager is ",[152,1027,1028],{},"external:gcp:secretmanager[:secret]"," and GCP KMS ",[152,1031,1032],{},"external:gcp:kms","; Azure Key Vault (",[152,1035,1036],{},"SecretClient(vaultUrl)",[152,1038,1039],{},"KeyClient",[152,1041,1042],{},"CertificateClient",[152,1044,1045],{},"external:azure:keyvault[:vault-host]",[1047,1048,1050],"h3",{"id":1049},"tables-on-several-connections","Tables on several connections",[141,1052,1053,1054,225,1057,1060,1061,1063,1064,1066,1067,1070,1071,1074,1075,412,1078,225,1081,1084,1085,1088,1089,1092,1093,1096,1097,1100,1101,1106],{},"A table name used on more than one database connection (",[152,1055,1056],{},"Book::on('warehouse')",[152,1058,1059],{},"DB::connection('reporting')->table('books')",", a model with ",[152,1062,351],{},") stays one ",[152,1065,182],{}," node. Its ",[152,1068,1069],{},"attrs.connections"," lists every connection seen with the number of table \u002F column edges (",[152,1072,1073],{},"{\"mysql\": 22, \"warehouse\": 3}","), and the table gets one ",[152,1076,1077],{},"CONNECTS_TO",[152,1079,1080],{},"op: table",[152,1082,1083],{},"via: connection \u003Cname>",") to the system of each connection that maps to one; ",[152,1086,1087],{},"attrs.system"," stays the model's or the default connection's system. A dynamic connection (",[152,1090,1091],{},"legacy_{store.id}",") or ",[152,1094,1095],{},"?"," has no system. ",[152,1098,1099],{},"cg reaches table:books --connection warehouse"," filters the code by connection (",[1102,1103,1105],"a",{"href":1104},"\u002Fdocs\u002Fcli#database-connections","CLI",").",[141,1108,1109,1110,1113,1114,1117,1118,1120,1121,1124,1125,1127,1128,1131,1132,1135,1136,1139,1140,1143,260,1146,832,1149,1152],{},"Confidence is ",[152,1111,1112],{},"exact"," for a literal host, ",[152,1115,1116],{},"resolved"," through ",[152,1119,167],{}," or compose,\n",[152,1122,1123],{},"heuristic"," otherwise. ",[152,1126,224],{}," without a driver takes the one SQL client in package.json \u002F\nrequirements \u002F pyproject, or the compose service. A Node env wrapper (",[152,1129,1130],{},"env.X",",\n",[152,1133,1134],{},"EnvSchema.safeParse(process.env)",", Joi ",[152,1137,1138],{},"validate(process.env)",") is READS_ENV with ",[152,1141,1142],{},"via",[152,1144,1145],{},"env wrapper",[152,1147,1148],{},"env schema",[152,1150,1151],{},"process.env.X ="," is a write, not a read.",[141,1154,1155,1156,1159,1160,1163,1164,1167,1168,1171,1172,1175,1176,1179,1180,1183],{},"DSNs cover postgres(ql), mysql \u002F mariadb, mssql, oracle, mongodb(+srv), redis \u002F rediss, amqp(s),\nsmtp(s), ldap(s), sftp \u002F ssh, ftp(s), elasticsearch, nats, kafka (",[152,1157,1158],{},"bootstrap_servers","),\nmqtt(s), imap, clickhouse, cassandra, http(s) and ",[152,1161,1162],{},"jdbc:",". Default ports come from the scheme (\n",[152,1165,1166],{},"amqps"," 5671, ",[152,1169,1170],{},"smtps"," 465, ",[152,1173,1174],{},"ldaps"," 636). TLS is true for TLS schemes, ",[152,1177,1178],{},"sslmode=require"," \u002F\n",[152,1181,1182],{},"ssl=true"," and ports 465 \u002F 636 \u002F 993; false for plaintext schemes; unknown otherwise.",[141,1185,1186,1187,260,1189,225,1192,225,1195,225,1198,1131,1200,225,1203,225,1206,260,1208,225,1211,260,1214,225,1217,1131,1220,1223,1224,1227,1228,225,1231,1131,1234,1237,1238,642,1240,225,1243,1245,1246,459,1249,225,1252,225,1254,225,1256,1131,1259,225,1262,225,1264,225,1267,225,1270,225,1273,1276],{},"Python constructors include ",[152,1188,299],{},[152,1190,1191],{},"asyncpg",[152,1193,1194],{},"pymysql",[152,1196,1197],{},"redis.from_url",[152,1199,305],{},[152,1201,1202],{},"smtplib",[152,1204,1205],{},"ldap3",[152,1207,308],{},[152,1209,1210],{},"kombu",[152,1212,1213],{},"aiokafka",[152,1215,1216],{},"confluent_kafka",[152,1218,1219],{},"elasticsearch",[152,1221,1222],{},"boto3.client(\"s3\")",", and a client built bare then ",[152,1225,1226],{},"connect()"," 'd (",[152,1229,1230],{},"paramiko",[152,1232,1233],{},"ftplib",[152,1235,1236],{},"SMTP.connect"," in another method). Node constructors include ",[152,1239,315],{},[152,1241,1242],{},"Pool",[152,1244,318],{}," (including\na project subclass and ",[152,1247,1248],{},"super()",[152,1250,1251],{},"mysql2",[152,1253,321],{},[152,1255,324],{},[152,1257,1258],{},"new Kafka({brokers})",[152,1260,1261],{},"Sequelize",[152,1263,327],{},[152,1265,1266],{},"ldapjs",[152,1268,1269],{},"S3Client",[152,1271,1272],{},"ssh2",[152,1274,1275],{},"basic-ftp",". sqlite dialects are not\nsystems.",[141,1278,1279,1280,225,1283,225,1286,225,1289,225,1292,412,1295,1298,1299,1302,1303,1306,1307,459,1310,1313,1314,260,1316,1319,1320,537,1322,1325,1326,1306,1329,459,1332,1335,1336,1339,1340,225,1342,1345,1346,225,1348,673,1351,1106],{},"Node attrs: ",[152,1281,1282],{},"protocol",[152,1284,1285],{},"host",[152,1287,1288],{},"port",[152,1290,1291],{},"tls",[152,1293,1294],{},"tls_verify",[152,1296,1297],{},"false"," when a call turns certificate verification off; ",[152,1300,1301],{},"cg external"," prints ",[152,1304,1305],{},"tls verify off",", see ",[1102,1308,1309],{"href":108},"surface",[152,1311,1312],{},"url_from_input"," on the ",[152,1315,1077],{},[152,1317,1318],{},"HTTP_CALLS"," edges of a call whose URL is built from request input (",[152,1321,1301],{},[152,1323,1324],{},"cg api-calls"," print ",[152,1327,1328],{},"url from input (query.url, url)",[1102,1330,1309],{"href":1331},"\u002Fdocs\u002Fsurface#outbound-urls-from-request-input-ssrf",[152,1333,1334],{},"resource"," (database, bucket),\n",[152,1337,1338],{},"address_source"," (literal, env-example, compose, config, env), ",[152,1341,933],{},[152,1343,1344],{},"auth"," (\n",[152,1347,851],{},[152,1349,1350],{},"explicit",[152,1352,1353],{},"unknown",[141,1355,1356,1357,1360,1361,1363,1364,1366,1367,412,1369,225,1372,225,1375,1378,1379,1381,1382,260,1385,260,1388,260,1391,1179,1394,1397,1398,412,1401,642,1403,1405,1406,642,1408,225,1411,1414,1415,1418,1419,642,1421,1423,1424,1426,1427,1430,1431,1434],{},"Mail and SMS providers (",[152,1358,1359],{},"external:saas:\u003Cprovider>",") follow the SDK shapes above: ",[152,1362,1077],{}," carries ",[152,1365,1142],{}," (the\nlibrary) and ",[152,1368,918],{},[152,1370,1371],{},"send",[152,1373,1374],{},"messages.create",[152,1376,1377],{},"notification",", ...), and a Mailgun domain is ",[152,1380,1334],{}," on the edge and\nnode (an attribute, not a second node). Credentials: an ",[152,1383,1384],{},"env",[152,1386,1387],{},"getenv",[152,1389,1390],{},"process.env",[152,1392,1393],{},"config('services.x.key')",[152,1395,1396],{},"settings.X"," key is ",[152,1399,1400],{},"CREDENTIAL_FROM env:\u003CKEY>",[152,1402,933],{},[152,1404,1384],{},"); a key written in the code is\n",[152,1407,933],{},[152,1409,1410],{},"literal",[152,1412,1413],{},"credential_literal"," true on the node and ",[152,1416,1417],{},"literal_credential"," on the edge (it feeds the\nsecret checks); no key found is ",[152,1420,1344],{},[152,1422,1353],{},". SES with no key is ",[152,1425,851],{},". Endpoint overrides stay attributes.\n",[152,1428,1429],{},"cg external --protocol saas"," lists them and ",[152,1432,1433],{},"cg impact external:saas:twilio"," reaches the routes and jobs that send.",[141,1436,1437,1438,1440,1441,642,1443,1445,1446,1449,1450,1452,1453,1455,1456,1131,1458,1460,1461,642,1463,1465,1466,1468,1469,1471,1472,1475],{},"Push, Firebase, Kubernetes, Docker and key-management systems (#42 part 3b) use the same shapes. A service-account,\nkubeconfig or APNs key path read from an env key is ",[152,1439,1400],{},"; a path written in the code is\n",[152,1442,933],{},[152,1444,936],{}," with ",[152,1447,1448],{},"credential_file"," on the node and the edge (no ",[152,1451,929],{},", because a path is not an\nenv key); a key written in the code is ",[152,1454,1410],{}," as above. Default credentials (",[152,1457,848],{},[152,1459,844],{}," unset, in-cluster config, the local Docker socket) are ",[152,1462,1344],{},[152,1464,851],{},"; no key found for\na push or SaaS client is ",[152,1467,1353],{},". Plain Docker TCP is ",[152,1470,1291],{}," false, which ",[152,1473,1474],{},"cg external --tls-off"," lists.",[145,1477,1480],{"className":1478,"code":1479,"language":150},[148],"$ cg external --protocol k8s --db out\u002Fgraph.db\nexternal:k8s:batch-v1  [exact]\n    address sdk; credentials ambient\n    \u003C- function:src\u002Fjobs.ts#runExport @ src\u002Fjobs.ts:9  (@kubernetes\u002Fclient-node)\n$ cg external --protocol docker --tls-off --db out\u002Fgraph.db\nexternal:docker:10.20.0.5:2375  [exact]\n    address literal; auth unknown; plaintext; resource 10.20.0.5:2375\n    \u003C- function:src\u002Frunner.ts#build @ src\u002Frunner.ts:18  (dockerode)\n$ cg impact external:gcp:fcm --db out\u002Fgraph.db\nentry points: 1\n  http_route       POST \u002Forders\u002F{id}\u002Fship  conf=exact\n",[152,1481,1479],{"__ignoreMap":154},[141,1483,1484,642,1488,260,1491,412,1494,1497,1498,537,1501,1504,1505,225,1507,260,1510,225,1512,225,1514,225,1517,1520,1521,459,1524,642,1527,1179,1529,260,1532,260,1535,642,1538,659,1541,412,1544,225,1547,1131,1550,1553,1554,1557,1558,1560,1561,1564,1565,160,1568,642,1571,1573,1574,1577,1578,1580,1581,225,1584,225,1587,1131,1590,225,1593,1595,1596,1599,1600,1603,1604,537,1606,1608,1609,1612],{},[1485,1486,1487],"strong",{},"Third-party HTTP from TypeScript.",[152,1489,1490],{},"http",[152,1492,1493],{},"https",[152,1495,1496],{},"node:"," prefix or not) ",[152,1499,1500],{},"request",[152,1502,1503],{},"get"," (an options object with\n",[152,1506,1282],{},[152,1508,1509],{},"hostname",[152,1511,1285],{},[152,1513,1288],{},[152,1515,1516],{},"path",[152,1518,1519],{},"method","; a URL string; ",[152,1522,1523],{},"new URL(path, base)",[152,1525,1526],{},"undici",[152,1528,1500],{},[152,1530,1531],{},"fetch",[152,1533,1534],{},"new Client(origin)",[152,1536,1537],{},"new Pool(origin)",[152,1539,1540],{},".request({ path, method })",[152,1542,1543],{},"got",[152,1545,1546],{},"got(url)",[152,1548,1549],{},"got.post",[152,1551,1552],{},"got.extend({ prefixUrl })"," instances) are client endpoints, so third-party hosts reach this list as\n",[152,1555,1556],{},"external:https:\u003Chost>:443"," like ",[152,1559,1531],{}," and axios. The method defaults to ",[152,1562,1563],{},"GET"," and the scheme comes from the module. A\nhost read from ",[152,1566,1567],{},"process.env.X",[152,1569,1570],{},"origin_kind",[152,1572,1384],{},"; a const map indexed by a parameter (",[152,1575,1576],{},"HOSTS[env]",") gives one\nendpoint per value, ",[152,1579,1123],{},". A file that imports one of those modules (or ",[152,1582,1583],{},"node-fetch",[152,1585,1586],{},"superagent",[152,1588,1589],{},"needle",[152,1591,1592],{},"phin",[152,1594,1500],{},") and calls it, with no endpoint made there, is the ",[152,1597,1598],{},"ts_unrecognised_http_client"," blind spot\n(",[1102,1601,1602],{"href":31},"completeness","); ",[152,1605,1301],{},[152,1607,1324],{}," end with a ",[152,1610,1611],{},"coverage note:"," naming it.",[141,1614,1615,1616,1619,1620,1623],{},"The graph never stores a secret. A DSN password becomes ",[152,1617,1618],{},"***"," before anything else sees it.\n",[152,1621,1622],{},"cg external --source literal"," lists hard-coded addresses or credentials.",[145,1625,1629],{"className":1626,"code":1627,"language":1628,"meta":154,"style":154},"language-bash shiki shiki-themes cg-light cg-light cg-dark","cg external --db graph.db\ncg external --protocol redis --tls-off --db graph.db\ncg external 'external:postgres:*' --json --db graph.db\n","bash",[152,1630,1631,1650,1670],{"__ignoreMap":154},[1632,1633,1636,1640,1644,1647],"span",{"class":1634,"line":1635},"line",1,[1632,1637,1639],{"class":1638},"sZJo5","cg",[1632,1641,1643],{"class":1642},"sha9Y"," external",[1632,1645,1646],{"class":1642}," --db",[1632,1648,1649],{"class":1642}," graph.db\n",[1632,1651,1653,1655,1657,1660,1663,1666,1668],{"class":1634,"line":1652},2,[1632,1654,1639],{"class":1638},[1632,1656,1643],{"class":1642},[1632,1658,1659],{"class":1642}," --protocol",[1632,1661,1662],{"class":1642}," redis",[1632,1664,1665],{"class":1642}," --tls-off",[1632,1667,1646],{"class":1642},[1632,1669,1649],{"class":1642},[1632,1671,1673,1675,1677,1681,1684,1687,1690,1692],{"class":1634,"line":1672},3,[1632,1674,1639],{"class":1638},[1632,1676,1643],{"class":1642},[1632,1678,1680],{"class":1679},"sZ_TN"," '",[1632,1682,1683],{"class":1642},"external:postgres:*",[1632,1685,1686],{"class":1679},"'",[1632,1688,1689],{"class":1642}," --json",[1632,1691,1646],{"class":1642},[1632,1693,1649],{"class":1642},[141,1695,1696,1697,832,1700,537,1703,1706,1707,225,1710,537,1713,1716],{},"Each system lists its tables, the functions that use it, CONFIGURED_BY \u002F CREDENTIAL_FROM, and\nTLS. MCP: ",[152,1698,1699],{},"external_systems(pattern?, protocol?, source?, tls_off?)",[152,1701,1702],{},"reaches",[152,1704,1705],{},"impact"," on\n",[152,1708,1709],{},"external:…",[152,1711,1712],{},"table:…",[152,1714,1715],{},"column:orders.total"," walk CONNECTS_TO, USES_CONNECTION,\nREADS_TABLE \u002F WRITES_TABLE and column edges.",[141,1718,1719,1721,1722,1131,1724,1727,1728,260,1731,1734,1735,1738,1739,1741,1742,1745,1746,1749,1750,1753,1754,1756,1757,1759,1760,1763],{},[152,1720,1705],{}," on a database reaches model users through the tables stored in it (ORM ",[152,1723,1077],{},[152,1725,1726],{},"op = table","). A table's impact also covers code that reads or writes only some of its columns\n(",[152,1729,1730],{},"READS_COLUMN",[152,1732,1733],{},"WRITES_COLUMN"," on the columns it ",[152,1736,1737],{},"CONTAINS","). ",[152,1740,179],{}," still skips\n",[152,1743,1744],{},"origin_kind: other"," when matching routes; the ",[152,1747,1748],{},"external:http(s)"," nodes are not routes. An SDK\nendpoint URL is ",[152,1751,1752],{},"attrs.endpoint"," on the resource node and is not also an ",[152,1755,1748],{},"\nnode. Explicit keys are ",[152,1758,929],{},"; a default credential chain is ",[152,1761,1762],{},"auth=ambient",".\nCallers that are already test nodes are left out.",[1765,1766,1768],"h2",{"id":1767},"not-covered-yet","Not covered yet",[1770,1771,1772,1776,1790,1796],"ul",{},[1773,1774,1775],"li",{},"Node clients built from a caller-supplied options object, or from a template string.",[1773,1777,1778,1779,1782,1783,1785,1786,1789],{},"Spring ",[152,1780,1781],{},"application.yml"," beyond ",[152,1784,359],{},", Rails ",[152,1787,1788],{},"database.yml",", Helm and\nTerraform values, compose files outside the root.",[1773,1791,1792,1793,1795],{},"SDK libraries for Rust, Kotlin, Swift and Dart, and SMTP (#44). Broker pairing is ",[1102,1794,91],{"href":92},".",[1773,1797,1798],{},"A Prisma schema in a sibling workspace package is not found from the app.",[141,1800,1801,1802,1806,1807,1795],{},"Corpus notes: ",[1102,1803,1805],{"href":1804},"\u002Fdocs\u002Fvalidation-log#external-systems-40","external systems","; mail, SMS, push and infrastructure SDKs on six real apps: ",[1102,1808,1810],{"href":1809},"\u002Fdocs\u002Fvalidation-log#mail--sms--push--infra-sdks-42-parts-3a-and-3b","validation log",[1812,1813,1814],"style",{},"html pre.shiki code .sZJo5, html code.shiki .sZJo5{--shiki-light:#65A30D;--shiki-default:#65A30D;--shiki-dark:#84CC16}html pre.shiki code .sha9Y, html code.shiki .sha9Y{--shiki-light:#9F8CFF;--shiki-default:#9F8CFF;--shiki-dark:#C4B5FD}html pre.shiki code .sZ_TN, html code.shiki .sZ_TN{--shiki-light:#71717A;--shiki-default:#71717A;--shiki-dark:#A1A1AA}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":154,"searchDepth":1816,"depth":1652,"links":1817},4,[1818,1819],{"id":1049,"depth":1672,"text":1050},{"id":1767,"depth":1652,"text":1768},"md",{},true,{"title":38,"description":143},"M8VbWtuFyMvq0G2_xmOivzldSTXSlPeypWC6gzHDbPM",[1826,1828],{"title":34,"path":35,"stem":36,"description":1827,"children":-1},"code-graph indexes a project with zero configuration. A .cg.yaml (or .cg.yml) at the indexed root is optional. The CLI, the MCP index tool and the visual view read it on every index. Command-line flags take precedence.",{"title":42,"path":43,"stem":44,"description":1829,"children":-1},"cg keeps generated files out of the graph by default and lists them in cg coverage. A copy\npoints back at the file you edit.",1792170236884]