Region: If more than one
squaredup-*server is connected, ask the user which one they mean before running any tools, then use that same server for every SquaredUp tool call in the task.
Querying the SquaredUp entity graph
The graph_query tool accepts Gremlin against the tenant's entity graph. Tenant scoping is automatic - never include tenant filters in the query.
Schema essentials
- Vertex label is always
obj(single label across the whole graph). Use.has('type', ...)to filter by entity kind, not.hasLabel(...). typeproperty carries the canonical entity type. Common values:host,container,kpi,space(workspaces are graph nodes too with typespace).sourceTypeproperty is multi-valued (e.g.['INFRASTRUCTURE_HOST_ENTITY', 'HOST']or'Microsoft.Windows.Computer'). Gremlin'shasmatches any value in the array, so.has('sourceType', 'AWS::EC2::Instance')works whether the value is single- or multi-valued.- Edge labels:
is(membership/identity),tags(tagging),monitors(monitor → target). - Source props present on most vertices:
sourceId,sourceName,sourceInstance,sourceAccount,sourceType.
Patterns
Find all hosts:
g.V().has('type', 'host').limit(50)
Find entities of a specific source type:
g.V().has('sourceType', 'AWS::EC2::Instance').limit(20)
What is connected to a known entity:
g.V().hasId('node-4tfDTNWMNFf9Hdygh53vwWB4pLY5iK6WYB-4cp3PAvZbuEoJr0V3iX7').both().dedup().limit(50)
Find entities in a workspace:
For the common case, prefer scope_resolve with workspaceIds - it's purpose-built and faster. Reach for Gremlin only when you need a non-membership traversal off the workspace node:
g.V().hasId('space-4cp3PAvZbuEoJr0V3iX7').both().dedup().limit(100)
Use .hasId(...) for vertex IDs, not .has('id', ...) - id is the Gremlin built-in identifier, not a regular property.
Always limit
Tenants can have hundreds of thousands of nodes. Always finish with .limit(N). Start with 10-50 while exploring; only widen if the user explicitly asks for "all".
Bindings
For values that come from user input (names, IDs, types), use parameter bindings rather than string-concatenating into the query:
{
query: "g.V().has('type', t).limit(n)",
bindings: { t: "host", n: 25 }
}
Choosing graph_query vs other tools
- Need rows of metric/log/event data →
data_stream_query(graph queries can't return stream data). - Need to know which entities match a saved scope →
scope_resolve(cheaper, purpose-built). - Need an ad-hoc traversal or property filter →
graph_query. - Need "what's connected to my alert" →
graph_querywith.both()from the known node.
Common mistakes
- Filtering on label -
.hasLabel('host')silently returns nothing because every vertex shares the labelobj. Use.has('type', 'host')instead. - Forgetting
.limit(N)- runs against the whole tenant graph; on a real tenant that can mean tens of thousands of rows back through the LLM context. sourceTypecase mismatch - values are case-sensitive (AWS::EC2::Instanceis notaws::ec2::instance). When in doubt, fetch one example vertex first and read the exact value.- Adding a tenant filter - tenant scoping is automatic. An explicit tenant clause is wrong, not redundant: it will narrow against an internal field you don't control and return nothing.
- String-concatenating user input into the query - use
bindings(see above).