Discover and Query
How agents find the right data in your semantic model, then run governed analytics, Matrix windows or SQL.
Before it queries, an agent finds out what's available. Semaphor is semantic first: the agent starts from your business-friendly semantic model and falls back to raw database tables only when it has to. Every data question starts with semaphor_get_analysis_context, which recommends the path.
The Analysis Context
Call semaphor_get_analysis_context first. Interactive sessions pass a projectId; token sessions use the token's project. It returns:
| Field | What it tells the agent |
|---|---|
recommendedPath | semantic, physical, restricted (the token's domain access excludes every domain) or unavailable |
recommendedNextTool | The tool to call next |
semanticDomains | The domains this caller can see |
fallbackConnections | Connections for physical discovery, when there are no domains and the caller has SQL access |
Semantic Path
When semantic domains exist, the agent works down from domain to field:
semaphor_list_semantic_domains: the domains this caller can seesemaphor_list_datasets: the datasets in a domainsemaphor_get_dataset_schema: measures, dimensions and date fields, plus a preview of related datasets with example field refssemaphor_get_domain_relationships: how datasets join (optional, useful for multi-dataset questions)
Then it queries with semaphor_analyze or semaphor_matrix.
Starting from a dashboard? Call semaphor_get_dashboard_analysis_context before broad discovery. It returns the dashboard's cards, filters, authored measures, dimensions and date fields, and query inputs the agent can reuse with semaphor_analyze.
Physical Path
When there are no semantic domains, callers with SQL access browse physical tables:
semaphor_list_connections: connections and their discovery capabilitiessemaphor_list_databasesandsemaphor_list_schemas: the levels each connection calls forsemaphor_list_tables: tables, or exact coordinates fromnameCandidatessemaphor_get_dataset_schemawith connection coordinates (connectionId,tableName, anddatabaseNameandschemaNameas needed)
Then it queries with semaphor_query_sql_advanced. Viewers and tokens minted with "sql": false don't see the physical tools and stay on the semantic path.
| Semantic path | Physical path | |
|---|---|---|
| Joins | From the semantic model, automatically | Written by hand in SQL |
| Field labels | Business-friendly names and descriptions | Raw column names |
| Who can use it | Every caller | Callers with SQL access |
| Best for | Business questions and governed analytics | SQL analysis and tables no domain represents |
Choose a Query Tool
Governed analyticssemaphor_analyze
The default. Measure by dimension, top-N, time series, filters, period comparisons and driver analysis, with joins and aggregates from the semantic model.
Matrix windowssemaphor_matrix
Pivot-style row and column hierarchies with totals, subtotals, scoped sorting, and Top or Bottom N with Others.
Advanced SQLsemaphor_query_sql_advanced
For questions the semantic tools can't express. Needs SQL access, and runs under the same security policies.
Recovery planningsemaphor_plan_analytics_recovery
When a question still has unanswered parts, plans the next governed tool calls from the schema evidence. It plans; it does not run queries.
semaphor_analyze | semaphor_matrix | semaphor_query_sql_advanced | |
|---|---|---|---|
| Query format | Semantic fields and analytics intent | Matrix definition and window | SQL |
| Joins | Automatic and governed | Automatic and governed | Written by hand |
| Aggregates | From the semantic model, with overrides | From the Matrix definition | Whatever the SQL says |
| Who can use it | Every caller | Every caller | Callers with SQL access |
Governed Analytics
semaphor_analyze resolves safe joins through semantic relationships, refuses known fan-out shapes instead of returning inflated numbers, and applies the caller's security policies. It returns records, columns, the generated SQL, relationship diagnostics, and a typed executionResult that says whether the question was answered.
{
"domainId": "dom_abc",
"datasetName": "fact_purchase_line",
"measures": [{ "datasetName": "fact_purchase_line", "name": "net_purchase_value" }],
"primaryMeasure": { "datasetName": "fact_purchase_line", "name": "net_purchase_value" },
"dimensions": [{ "datasetName": "dim_supplier", "name": "supplier_name" }],
"limit": 10
}If net_purchase_value is modeled with aggregate: "SUM", Semaphor generates a summed top-N query: the semantic model owns that default. To count rows when the model has no count measure, use the "__count" measure.
For a comparison, add { "kind": "previous_period" }, { "kind": "previous_year" } or { "kind": "target", "targetValue": 100 }. It uses the query's own date field and time window. See Metric Comparisons.
Time Windows
Pass a timeWindow with a dateField to bound the query:
{
"domainId": "dom_abc",
"datasetName": "orders",
"measures": [{ "datasetName": "orders", "name": "revenue" }],
"dateField": { "datasetName": "orders", "name": "order_date" },
"timeGrain": "week",
"timeWindow": { "kind": "calendar", "unit": "quarter", "period": "this" }
}Rolling windows such as { "unit": "month", "value": 6 } count back from the latest date in the data by default (anchor: "latest_available"). Use anchor: "now" to count back from today. See Tools Reference for every window shape.
Aggregate Overrides
The same measure can be asked about with a different rollup: total margin and average margin are both valid questions. Add aggregate to the measure for one call:
{
"domainId": "dom_abc",
"datasetName": "fact_sales_line",
"measures": [{ "datasetName": "fact_sales_line", "name": "gross_margin_value", "aggregate": "AVG" }],
"primaryMeasure": { "datasetName": "fact_sales_line", "name": "gross_margin_value", "aggregate": "AVG" },
"dimensions": [{ "datasetName": "dim_material", "name": "material_family" }],
"limit": 10
}The response marks the override in fieldsUsed with a measure_aggregate_override warning, so you can audit it. Omit aggregate to use the semantic model.
Matrix Windows
semaphor_matrix runs a governed Matrix: multi-level row and column hierarchies, totals and subtotals, scoped sorting, and Top or Bottom N with Others. You ask for a bounded window, and page cursors load more. A window is never a complete export. See Tools Reference.
Advanced SQL
semaphor_query_sql_advanced runs SQL against a connection, under the same security policies. Use it for custom CTEs, window functions, relationships the semantic model doesn't define, fields no domain exposes, raw-row inspection, or SQL debugging. It's available to organization users with an Author role or higher, and to end-user tokens unless SQL is turned off.
Every call states why semaphor_analyze can't answer, needs a connectionId from semaphor_list_connections, and can post-process rows with optional pythonCode.
{
"connectionId": "conn_abc123",
"analyzeFallbackReason": "unsupported_sql_construct",
"analyzeFallbackExplanation": "Month-over-month delta needs a LAG window function over a CTE.",
"sql": "WITH monthly AS (SELECT date_trunc('month', order_date) AS month, SUM(total_amount) AS revenue FROM orders GROUP BY 1) SELECT month, revenue, revenue - LAG(revenue) OVER (ORDER BY month) AS delta FROM monthly ORDER BY month LIMIT 100"
}Response Format
semaphor_analyze and semaphor_query_sql_advanced accept responseFormat: "json" (the default) returns records, metadata, diagnostics and generated SQL, also as structured content; "markdown" returns a readable summary. semaphor_matrix always returns JSON.
Tips
- List before you query. Call
semaphor_list_datasetsbeforesemaphor_get_dataset_schema, so the agent never guesses dataset names. - Use source-bearing refs. Include
datasetNameon each field ref when selecting fields from joined datasets. - Let the model choose aggregates. Omit
aggregateunless the question asks for a different rollup. - Check
executionResult. Itsstatusandcoveragesay whether the question was answered, not the surrounding text. - Use SQL as the escape hatch. It's fully governed, but it shouldn't be the first choice for ordinary analytics.
For more on modeling, see Semantic Domains.