Query REST API
Read-only HTTP API over a READY scan of your workspace. Default: LATEST READY for the canonical workspace. Override with ?scanId= (pin one scan) or ?workspaceId= (LATEST for another workspace).
Base URL: https://helix-flow.igentify.in
Programmatic access: @igentify/helix-flowgraph (queryGraph, queryFeatures, …).
Prefer GET through CloudFront (POST on some routes may hit the SPA fallback).
What you are querying
Helix materializes each scan as a technical graph:
- Nodes — code entities (routes, services, React components, HTTP client calls, product features, …)
- Edges — relationships (
CALLS,HANDLED_BY,CALLS_REMOTE,USES, …) - Features — product capabilities resolved from
features/*.yamlplus synthetic FE↔BE bridge features
The API never runs your code. It answers questions like:
- Which backend endpoint handles this UI call?
- What code sits in the neighbourhood of a feature?
- If I change node X, which features are affected?
- What did the AI pass note about risks or behaviour on this endpoint?
Pipeline background: How Helix works. Vocabulary: Glossary.
Quick start
export BASE=https://helix-flow.igentify.in
export TOKEN="<cognito-id-token>"
export AUTH="X-Helix-Authorization: Bearer $TOKEN"
# 1. Discover features (cheap — good first call)
curl -sS "$BASE/query/features" -H "$AUTH"
# 2. Pick a feature id from the list, e.g. feature:enrollments:…
curl -sS "$BASE/query/feature?featureId=feature:…" -H "$AUTH"
# 3. Or narrow to one repository
curl -sS "$BASE/query/repo-graph?repoKey=ng-access-service" -H "$AUTH"TypeScript (@helix/shared):
import { helixQueryJson, loadTechnicalGraphFromQueryResponse } from "@helix/shared";
const config = {
baseUrl: process.env.HELIX_QUERY_BASE_URL!,
getIdToken: async () => process.env.HELIX_ID_TOKEN,
};
const { features, scanId } = await helixQueryJson<{ features: Feature[]; scanId: string }>(
config,
"/query/features",
);
const graph = await loadTechnicalGraphFromQueryResponse(
await helixQueryJson(config, "/query/technical-graph"),
);Every graph response includes scanId — treat it as the snapshot version. If you cache graph data, key by scanId.
Scan selection (0.2.1+)
All /query/* routes accept optional query parameters:
| Parameter | Effect |
|---|---|
| (none) | LATEST READY for the canonical workspace (igentify / HELIX_WORKSPACE_ID) |
scanId | Load graph + AI artifacts from that READY scan in S3 |
workspaceId | LATEST READY for the given workspace (ephemeral pre-feature scans, etc.) |
# Default — canonical latest
curl -sS "$BASE/query/features" -H "X-Helix-Api-Key: $KEY"
# Historical / branch scan (after scan start + READY)
curl -sS "$BASE/query/repo-graph?repoKey=ng-access-service&scanId=01KX0JWPM83J" -H "X-Helix-Api-Key: $KEY"
# Latest in an alternate workspace
curl -sS "$BASE/query/features?workspaceId=pre-feature-enrollments" -H "X-Helix-Api-Key: $KEY"await queryFeatures({ scanId: "01KX…" });
await queryRepos("ng-access-service", { workspaceId: "pre-feature-enrollments" });Workflow for pre-feature branch comparison: POST /scan/start with repos[].commit → wait for READY → query with returned scanId. See NPM client — querying a previous scan.
Choosing an endpoint
Use the smallest response that answers your question.
| Goal | Endpoint | Why |
|---|---|---|
| List product features | GET /query/features | Small JSON; no graph load |
| Human labels for features | GET /query/feature-display-titles | Map featureId → display string |
| One feature’s code neighbourhood | GET /query/feature?featureId= | 1-hop subgraph around the feature |
| Everything in one repo | GET /query/repo-graph?repoKey= | Filtered nodes/edges |
| Full workspace graph | GET /query/technical-graph | All repos; largest payload |
| Compare two features | POST /query/compare-features | Shared vs unique implementation nodes |
| Blast radius of a code change | POST /query/impact | Features with USES → your node |
| Walk the graph locally | POST /query/node | One node + neighbour ids |
| Find where to implement something | POST /query/implementation-anchor | Heuristic anchor lookup |
| AI notes on a backend route | GET /query/endpoint-qa?endpointId= | Per-endpoint Q&A bundle |
| AI risks on a backend route | GET /query/endpoint-potential-issues?endpointId= | Risk list |
| Same for frontend client call | GET /query/endpoint-qa-fe?clientCallId= | FE-side Q&A |
| AI feature summary | GET /query/feature-insights?featureId= | Narrative + structured insights |
Agent rule of thumb: start with /query/features or /query/repo-graph, drill into /query/feature or /query/node, call AI artifact endpoints only when you need prose or risk analysis—not as a substitute for graph structure.
Graph data model
Node id format
Technical nodes are repo-scoped:
repo:<repoKey>|<kind>:<path-or-symbol>Examples:
repo:ng-access-service|ApiEndpoint:GET /users/{id}repo:ng-work-space-ui|ApiClientCall:src/api/users.ts#getUser
Feature nodes use the feature: prefix (legacy scans may still contain flow:).
Common node labels
| Label | Meaning |
|---|---|
Feature | Product capability (from YAML or FE↔BE bridge) |
ApiEndpoint | Backend HTTP route / handler entry |
ApiClientCall | Frontend typed HTTP call site |
ReactPage / ReactComponent / Hook | UI structure |
Controller / Service / Method | Backend stack |
Repository / Entity / DataModel | Persistence layer |
Full enum: shared/src/graph.ts → GraphNodeLabel.
Common edge types
| Type | Meaning |
|---|---|
CALLS | Intra-repo call |
CALLS_REMOTE | FE ApiClientCall → BE ApiEndpoint (cross-repo) |
HANDLED_BY | Route stack → handler |
USES | Feature → implementation node |
CALLS_API | UI → client call |
IMPORTS | Module dependency |
Walk sequences by following outgoing edges from an ApiEndpoint or ApiClientCall. Cross-repo behaviour requires CALLS_REMOTE.
Node fields
{
"id": "repo:ng-access-service|Method:src/users/users.service.ts#findById",
"label": "Method",
"name": "findById",
"repository": "ng-access-service",
"filePath": "src/users/users.service.ts",
"summary": "optional AI one-liner",
"data": { "httpMethod": "GET", "path": "/users/:id" }
}Use filePath + repository to map graph nodes back to source files for edit suggestions.
Endpoint reference
GET /query/features
Returns: { features: FeatureSummary[], scanId }
{
"features": [
{ "id": "feature:bridge:…", "name": "User enrollment", "flowKey": "enrollments" }
],
"scanId": "01KWHRCVJFBBD2AK6W97QFGDYA"
}Use when: building feature pickers, scoping an agent task to one product area, checking whether a feature exists in the latest scan.
GET /query/feature-display-titles
Returns: { "<featureId>": "<human label>", … }
Use when: rendering user-facing names; keys are the same ids as /query/features.
GET /query/feature?featureId=<id>
Returns: NormalizedGraphResponse — feature metadata + 1-hop subgraph.
{
"queryType": "feature_graph",
"feature": { "id": "feature:…", "name": "…", "flowKey": "…" },
"summary": { "implementationAnchors": ["repo:…|Service:…"] },
"nodes": [ … ],
"edges": [ … ],
"implementationAnchors": [ … ],
"sharedNodes": [],
"missingSegments": []
}Use when: explaining how a feature is wired in code, finding entry routes/endpoints, preparing a change plan scoped to one feature.
Agent tips:
implementationAnchors— start here for “where is this implemented?”missingSegments— gaps the resolver could not close (stale YAML, missing repo in scan)- Follow
USESedges from the feature node outward to reach concreteMethod/ApiEndpointnodes
GET /query/repo-graph?repoKey=<key>
Returns: { queryType: "repo_graph", repoKey, nodes, edges, scanId }
Use when: the task is repo-scoped (e.g. “review ng-access-service”), or the full workspace graph is unnecessarily large.
GET /query/technical-graph
Returns: Full workspace graph for the latest scan.
Use loadTechnicalGraphFromQueryResponse() from @helix/shared — it handles the response shape and returns { nodes, edges, repos? }.
Use when: cross-repo analysis, global search by label, building custom traversals.
Avoid when: a repo or feature endpoint suffices — smaller responses are faster and easier to reason about.
Optional: ?inline=1 forces inline JSON when supported (mainly for debugging).
POST /query/compare-features
Body: { "featureA": "<id>", "featureB": "<id>" }
Returns: { queryType: "feature_compare", featureA, featureB, nodes, edges, sharedNodeIds, uniqueToA, uniqueToB }
Use when: deduplicating work, finding shared services between features, spotting unintended coupling.
Agent tips:
sharedNodeIds— candidates for careful regression testing when changing either featureuniqueToA/uniqueToB— safe-ish isolation boundaries for refactors
POST /query/impact
Body: { "nodeId": "<graph node id>" }
Returns:
{
"nodeId": "repo:…|Method:…",
"impactedFeatures": ["feature:…"],
"impactedRoutes": [],
"impactedEndpoints": [],
"impactedSharedNodes": []
}Use when: before editing a method/service — list features that USE this node.
Agent tips:
- Non-empty
impactedFeatures→ warn the user and suggest running tests / reviewing those feature subgraphs - Combine with
/query/featureon each impacted id for a concrete change checklist
POST /query/node
Body: { "nodeId": "<id>" }
Returns: { node, neighbours: string[] } or 404 { error: "node_not_found" }
Use when: incremental graph exploration without downloading the full graph.
Agent tips:
- BFS/DFS from an
ApiEndpointorMethodusing repeated/query/nodecalls - Prefer this over loading
/query/technical-graphwhen depth is bounded (≤ 3 hops)
POST /query/implementation-anchor
Body: { "featureQuery": "<search string>", "flowKey?": "<optional>" }
Returns:
{
"resolved": true,
"existingAnchors": ["repo:…|Service:…"],
"recommendedInsertions": [],
"supportingGraphNodeIds": ["repo:…|Service:…"]
}When unresolved, recommendedInsertions may contain placeholder suggestions (deterministic stub — verify against real repo layout).
Use when: “where should this logic live?” — pair graph anchors with your own file search.
AI artifact endpoints
All are lazy S3 reads — 404 if the helix-agent pass has not produced that artifact yet.
| Endpoint | Query param | Content |
|---|---|---|
GET /query/feature-insights | featureId | Narrative insights, structured bullets |
GET /query/endpoint-qa | endpointId | Backend endpoint Q&A |
GET /query/endpoint-potential-issues | endpointId | Backend risk notes |
GET /query/endpoint-qa-fe | clientCallId | Frontend client-call Q&A |
GET /query/endpoint-potential-issues-fe | clientCallId | Frontend risk notes |
Use when: enriching human-facing explanations or flagging review items — not as sole evidence (always cross-check graph nodes and source files).
Agent tips on 404:
- Artifact missing → say “no AI pass yet” and fall back to graph structure
- Suggest re-running scan + helix-agent for that repo if insights are required
Agent playbooks
“Explain how feature X works”
GET /query/features— resolve exactfeatureIdif the user gave a fuzzy nameGET /query/feature-display-titles— optional friendly nameGET /query/feature?featureId=— structural answer from nodes/edgesGET /query/feature-insights?featureId=— optional narrative layer- Trace
ApiEndpoint/CALLS_REMOTE/CALLSchains; citefilePathon each node
“What breaks if I change this method?”
- Identify
nodeId(from repo-graph or feature subgraph) POST /query/impactwith{ nodeId }- For each
impactedFeatures[],GET /query/feature?featureId= - Recommend: tests covering those features, review of shared
Service/Methodnodes
“Find the backend for this UI action”
GET /query/repo-graph?repoKey=<frontend-repo>- Locate
ApiClientCallnodes (or search by path/name in nodes) - Follow
CALLS_REMOTEedges toApiEndpointin backend repos - Optional:
GET /query/endpoint-qa-fe?clientCallId=andGET /query/endpoint-qa?endpointId=
“Suggest a fix / improvement”
Combine evidence layers:
| Signal | Source |
|---|---|
| Structure | /query/feature, /query/repo-graph, /query/node |
| Blast radius | /query/impact |
| Documented risks | /query/endpoint-potential-issues* |
| Behaviour Q&A | /query/endpoint-qa* |
| Product context | /query/feature-insights |
Recommendations should reference concrete node ids and file paths. If missingSegments is non-empty or no CALLS_REMOTE exists where expected, say the graph gap explicitly (missing repo in scan, bridge not resolved, stale feature YAML) rather than inventing wiring.
Errors and limits
| Status | Meaning | Agent action |
|---|---|---|
401 | Missing/invalid token | Refresh Cognito ID token |
404 | Unknown node or missing AI artifact | Verify id from /query/features or repo-graph; for AI, note artifact not generated |
502 | Lambda failure | Retry; check scan is READY |
| HTML body | Wrong method or path hit SPA | Use GET with query params on documented routes |
CloudFront may cache GET responses briefly — if a new scan just finished, prefer checking scanId in the response.
Local development
HELIX_GRAPH_PATH="$(pwd)/scans/latest/reports/technical-graph.json" npm run dev:api
curl -sS http://localhost:8787/query/featuresNo auth when COGNITO_USER_POOL_ID is unset. See Local development.
Implementation reference
| Concern | Location |
|---|---|
| Route handlers | backend/src/routes.ts |
| Request schemas | shared/src/queries.ts |
| Graph types | shared/src/graph.ts |
| HTTP client | shared/src/helixQueryClient.ts |
| Graph loader helper | shared/src/technicalGraphDelivery.ts |
For AWS service discovery (SSM params, helix-aws): Other AWS Apps Integration.