Skip to main content

data-querying

General guidance on querying data sources, using existing scripts vs ad-hoc queries, filtering patterns, and generating charts for the analytics app.

소스 정보

저장소
BuilderIO/agent-native
최근 소스 활동
2026년 10월 19일 18:55
감지된 SKILL.md 언어
영어
스타
7,449
포크
681

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
2 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
data-querying
description
General guidance on querying data sources, using existing scripts vs ad-hoc queries, filtering patterns, and generating charts for the analytics app.
# Data Querying The analytics app connects to multiple data sources. This skill covers general patterns for querying data effectively. ## Approach 0. **Use retrieved references first** — data questions may start with a small set of relevant data-dictionary entries and saved dashboard panels in `<resource scope="analytics-catalog">`. Treat them as definitions and query examples, never live results. If they do not fit, call `find-data` before querying; use data-source status when provider availability matters. 1. **Route named account health deliberately** — for a customer/org health, QBR, renewal, contract-utilization, risk, or adoption request, read `account-health` before writing SQL. It adds identity-lock and metric-definition checks that an ordinary lookup does not need. 2. **Read the relevant provider skill first** — check `.agents/skills/<provider>/SKILL.md` for table names, column mappings, auth, and gotchas. For BigQuery, read `.agents/skills/bigquery/SKILL.md` and use `search-bigquery-schema` before guessing table or column names. 3. **Clarify if ambiguous** — if the metric definition, date range, or grain is unclear and a wrong guess would change the numbers, use the `ask-question` clarifying tool (multiple-choice) before querying. Ask at most once per turn; skip it when the dictionary or the user already answered. 4. **Use existing actions or connected provider MCP tools** — call the provider action/tool with structured arguments, then filter or aggregate the returned records in your answer 5. **Write ad-hoc scripts** — if no existing script covers the question, create one in `actions/` 6. **Present data in chat** — don't just say "check the dashboard" — actually query, get the data, and present it. Only present numbers you actually retrieved; never report a value you did not query. For a question naming a dbt metric, use `tool-search` to load `query-dbt-semantic-metric` and pass its exact dbt name. Use dbt as the metric- definition and grain source; Sigma and Amplitude are examples or cross-checks. If no dbt connection is available, use the source-selection path below. If the metric is not defined or its deployment is not ready, report that state and use a verified warehouse path only when it answers the same definition. Use the metric's returned dimensions and `queryableGranularities` for a breakdown. Pass exact dimension names in `groupBy`; grouped MetricFlow queries require an inclusive `timeRange` no longer than 366 days. Use `metric_time` and an explicit grain for a time series. The action validates dimensions and grains against dbt metadata, and returns the executed `querySpec`; preserve it when interpreting rows or continuing with the returned `queryId` and `nextPage`. MetricFlow names grouped time columns `metric_time__<GRAIN>` in the returned rows; preserve that key when presenting the result. When activity could mean Builder product events or Agent-Native app opens, keep the populations separate and ask which one the user intends if the source is ambiguous. ## Metric semantics and source status - Keep event families separate unless the dbt metric or exact saved query defines their union. A UI click and a submitted message are different events even if a dashboard labels both as activity. - Verify population filters and exclusions from model/metric SQL or tests. Similar aggregate totals do not prove that a model excludes staff, internal users, or any other group. - A bounded date or partition scan supports conclusions only for the scanned range. State that range and any bytes or query limit; an empty result in those partitions does not establish absence elsewhere. - For a source inventory, call `data-source-status` and distinguish configured credentials from a healthy workspace connection. A provider appearing in the tool catalog is not evidence that this workspace has connected it. For events recorded by the analytics template itself via its `/track` endpoint, use `pnpm action query-agent-native-analytics --sql "SELECT ... FROM analytics_events ..."`. This includes pageviews, site/app traffic, template usage, app usage, and event counts collected by this analytics app. Pageviews and traffic can also live in GA4, BigQuery/warehouse tables, Mixpanel, PostHog, Amplitude, or another configured provider, so choose the source from the user's wording, connected-source status, existing dashboards, data dictionary, and user/org resources. Ask one concise clarification only when multiple configured sources are plausible and the choice would change the numbers; otherwise name the source you used. Do not use `db-query` for data-source analysis; `db-query` is only for internal app tables and will confuse analytics questions. The shipped `agent-native-templates-first-party` SQL dashboard is the template engagement dashboard for the first-party collector source. For first-party counts, active-user, and retention questions, prefer the compact tenant-scoped daily event and user-day rollups. Use `analytics_events` only for a bounded recent drill-down with an explicit date/time range. For the Builder.io production organization after the BigQuery cutover, these logical tables are served by partitioned BigQuery data and views; the source still does not require an end user's separate warehouse connection. The Builder.io BigQuery path translates a restricted PostgreSQL-compatible SQL subset. Extract an event property with `properties::jsonb ->> 'key'`; bare JSON operators are not translated. Avoid `LATERAL`, `unnest`, `generate_series`, `FILTER (WHERE ...)`, `DISTINCT ON`, and `ILIKE`, which the BigQuery path rejects. Use `||` explicitly for string concatenation. Rewrite `FILTER (WHERE ...)` as a conditional aggregate such as `SUM(CASE WHEN ... THEN value ELSE 0 END)`, `ILIKE` as `LOWER(left) LIKE LOWER(right)`, and `DISTINCT ON` as `ROW_NUMBER()` in a CTE with an outer `WHERE` filter. After an unsupported-syntax error, make one corrected attempt and do not repeat unchanged SQL. Follow the first-party query's typed recovery instruction: schema errors call for `find-data` or `search-bigquery-schema`; permission failures stop; billed-byte failures need a narrower scan; only timeout, rate-limit, and temporary backend failures permit one unchanged retry. Use the separate BigQuery action for GoogleSQL-only SQL. First-party reads exclude test identities (QA/E2E accounts): ingest never stores their events or replays, and the read scope filters `user_id` (events, replays) and `user_key` (user-days). Pass `includeTestIdentities: true` to `query-agent-native-analytics` only to debug those accounts. Daily event rollups and BigQuery-source panels that query the raw warehouse table directly are clean from ingest onward but are not filtered at read time. The one exception is the legacy `@app_events` table, which keeps a test identity's `$exception` rows marked `JSON_VALUE(data, '$.test_identity') = 'true'`; exclude those from any metric over it. When the user rules out BigQuery, skip the health check below, which queries BigQuery on a BigQuery-backed scope. Call `get-first-party-analytics-backend` to see which tables Postgres serves, then pass `backend: "postgres"` to `query-agent-native-analytics`. If it fails with `first_party_backend_not_postgres`, this scope reads those tables only from BigQuery: say so and let the user decide. Otherwise, before a large or historical first-party query, call `get-first-party-analytics-health`. Keep Neon as the default while its status is `healthy` or `monitor`; a `recommend_bigquery` result means the app has observed 1M+ events, repeated slow queries, or a timeout/30-second query. Treat that status as a compatibility name for an external-backend recommendation, not as a requirement to use BigQuery. The health result lists the supported options: - BigQuery for warehouse SQL and complete historical analysis. - Amplitude for product analytics, funnels, and retention. A `recommend_bigquery` result is advice, not a stop: answer the bounded question first. Use the setup link only for a historical or high-volume request with no suitable backend configured, via its returned link or `data-source-status --key <provider>`, to guide the user through the existing Data Sources walkthrough. Connecting a query backend alone does not move the collector or copy existing Neon events. For the Builder.io production organization, the hidden `migrate-first-party-analytics-to-bigquery` action is the explicit state machine: prepare dual-write, backfill through bounded, newest-first UTC time shards with per-shard leases, then cut over with confirmation. The worker excludes `http.response` by default and uses BigQuery `insertId` values for retry-safe writes. After cutover, `/track` writes and event queries use BigQuery; public-key metadata, derived exception issues, and session-replay data remain in SQL. After cutover, an org admin can point charts at a scheduled warehouse events model with `configure-first-party-events-model`; run `check` first, which dry-runs as the app and saves nothing. With a model set, a first-party query reads `analytics_events` from the model only when its WHERE filters `event_name` to named events (`= 'x'` or `IN (...)`, ANDed, no OR or NOT), because the model has no `http.response` rows; its result carries `eventsSource` and `sourceGeneration` (the model build it read). Unfiltered queries, `SELECT *`, and queries that name `public_key_id` or `context`, read `http.response`, or read `properties` other than through `JSON_VALUE`, `JSON_EXTRACT_SCALAR`, `JSON_VALUE_ARRAY`, or `JSON_EXTRACT_STRING_ARRAY` stay on the raw table, as do alerts and onboarding journeys; `eventsSource.modelSkipped` says why. A model result trails the newest events by up to one rebuild, so for the last few minutes give the model's age from `get-analytics-source-generation` (a metadata read, no query) rather than calling the count complete. Example pageviews query for a local calendar day: ```sql SELECT COUNT(*) AS pageviews FROM analytics_events WHERE event_name = 'pageview' AND timestamp >= '<start-utc>' AND timestamp < '<end-utc>' ``` Convert the user's requested local date/timezone to UTC before querying. For example, May 1, 2026 in America/New_York is `2026-05-01T04:00:00Z` through `2026-05-02T04:00:00Z`. ### LLM observability events Agent runs are `analytics_events` rows with `event_name = '$ai_generation'`. Useful `properties`: - Identity: `$ai_trace_id`/`run_id`, `$ai_session_id`/`thread_id`, `$ai_model`/`model`, `$ai_provider`/`provider`. - Usage: `$ai_input_tokens`/`input_tokens`, `$ai_output_tokens`/`output_tokens`, `cache_read_tokens`, `cache_write_tokens`. - Cost: `$ai_total_cost_usd`/`cost_usd`, `cost_cents_x100`. - Time: `duration_ms` is the full run in milliseconds; `$ai_latency` is model time in seconds (run minus tool time). - Tools: `tool_calls`, `successful_tools`, `failed_tools`, `tools`, `tools_truncated`. The bounded `tools` array holds names, relative start times, durations, statuses, and coarse error classes, never args or results; failed runs and interrupted tools stay queryable. - Delegation: `delegated`, `delegation_protocol`, `caller_app`, `delegation_task_id`, `a2a_task_id`, `parent_run_id`, `parent_turn_id`. Agent Teams child runs use `delegation_protocol = 'agent-team'`, keep their own `run_id`, and link to the launching run through `parent_run_id`. - Errors: `status`, `$ai_error` (terminal code, cause, retryable, and a fixed code-derived message), `$ai_error_type`. Run failure messages are omitted from telemetry. ## Inline Charts In Chat For an in-chat answer, **emit a live `/chart` embed** — never `generate-chart`. The embed mounts a live `SqlChart` that re-queries when its source changes, and it doesn't choke on rigid JSON params the way the PNG action does. Reach for `generate-chart` only when you're building a dashboard artifact that needs a persisted report image. If `generate-chart` returns an error in any chat-answering flow, the recovery is to switch to the live embed, not to retry with reformatted params. **How it renders.** The core chat markdown renderer turns any fenced block tagged `embed` into a sandboxed, same-origin iframe. Emit: ````markdown ```embed src: /chart?panel=<base64url-encoded panel JSON> title: Daily pageviews height: 320 ``` ```` Fence keys: `src` (required, same-origin path), `title`, and either `height` (px) or `aspect` (`16/9`, `4/3`, `1/1`, `21/9`, `3/2`, `2/1`; default `16/9`). A cross-origin `src` renders an "Embed blocked" notice instead of a chart. **This fence is the only supported syntax.** Never write a bare line like `` `/chart type=bar title="..." labels=[...] data=[...] color=#...` `` in chat text — that pattern comes from confusing `generate-chart`'s tool parameters (`title`, `labels`, `data`, `type`) with markdown; those are arguments to a tool call, not something to type into a chat message. The chat renderer has a best-effort compatibility fallback that tries to recover a chart from that exact shorthand shape, but it is not the contract: it rejects mismatched lengths, negative values, and malformed input (falling back to plain text), and it does not re-query live data the way the embed does. If you catch yourself typing `label` or `data` followed by `=` in a chat reply, stop and build the ` ```embed ` fence above instead. **Panel JSON.** The `/chart` route decodes `panel` into a `SqlPanel` (`app/pages/adhoc/sql-dashboard/types.ts`): - `sql` — required, non-empty. - `source` — required, one of `bigquery`, `ga4`, `amplitude`, `first-party`, `demo`, `prometheus`. `program` is deliberately **not** embeddable. - `chartType` — required, one of `line`, `area`, `bar`, `metric`, `table`, `pie`. Dashboard-layout types (`section`, `heatmap`, `callout`, `extension`) are rejected. - `id` (defaults `"embed"`), `title` (rendered above the chart), `width` (dashboard-only, ignored here), `config` (passed through unvalidated — `xKey`/`yKeys`, `colors`, `yFormatter`, `rightYKeys`/`rightYFormatter` for a dual-axis line/area/bar chart, `columns`, `stacked`, `legend`, …). An unknown `source`/`chartType` or blank `sql` renders an error card, not a chart. **Encoding.** JSON-stringify the panel, base64-encode it, then make it URL-safe: `+` → `-`, `/` → `_`, strip `=` padding. No further URL-encoding is needed. Keep the SQL short — it rides in a query string; if it's long, save it as a dashboard panel and link to the dashboard instead. Full details (per-field validation, `config` keys, a verified round-trip example, and how this differs from `generate-chart`) are in `references/inline-chart-embeds.md` — read it with `docs-search --slug "skill-data-querying--references-inline-chart-embeds"`. ## Script Patterns ### Reusing Existing Actions ```bash # Jira tickets pnpm action jira-search --jql="summary ~ SSO" --fields=key,summary,status # HubSpot deals pnpm action hubspot-deals --query="The Knot" --limit=10 --properties=dealname,amount,dealstage # HubSpot + Gong account/deal deep dive pnpm action account-deep-dive --query="The Knot" --days=180 --gongLimit=10 --transcriptLimit=5 # HubSpot contacts or companies pnpm action hubspot-records --objectType=companies --query=builder.io --properties=name,domain,lifecyclestage # Gong call evidence (quotes, counts); ask run-gong-native-insight first for "what did they say" pnpm action gong-calls --company="The Knot" --days=180 --includeTranscripts=true --transcriptLimit=5 ``` The first-class actions above are convenience shortcuts for the common cases, not the limit of what you can do. Many providers (GitHub, Amplitude, PostHog, Mixpanel, Apollo, Common Room, Twitter/X, Notion, Pylon, GA4, plus any endpoint/filter a shortcut can't express) have **no bespoke action** — reach them through the shared provider API escape-hatch pattern: `provider-api-catalog` / `provider-api-docs` to learn the endpoint, then `provider-api-request` (or `providerFetch` inside `run-code`) against the provider's real HTTP API. Ask the provider to do the work first: use its own search or semantic tool, or a server-side filter on a bounded window (for Gong, `run-gong-native-insight`). Only for exhaustive coverage, exact counts, or an absence claim ("how many", "any/none across all …") stage the raw API response with `stageAs`/`saveToFile` and reduce it with `query-staged-dataset` or `run-code`, rather than stretching a capped shortcut action or paging by hand to filter locally. ### Writing Ad-Hoc Scripts When no existing script covers the question: 1. Create a new script in `actions/` that imports the relevant server lib 2. Run it via `pnpm action <name>` 3. For one-off queries, you can delete the script after 4. For reusable queries, keep the script ```ts // scripts/my-query.ts import { runQuery } from "../server/lib/bigquery.js"; import { output } from "./helpers.js"; export default async function main(args: string[]) { const results = await runQuery("SELECT ..."); output(results); } ``` ## Cross-Referencing Sources For answers that span multiple sources, follow the `cross-source-analysis` skill: plan which source owns each fact, fetch per source, stitch identities on BOTH a stable id AND email (ids can be reassigned), de-duplicate, and cite per-source provenance. For complete answers, combine data from multiple sources: - **BigQuery** for analytics events, signups, pageviews - **First-party Analytics** (`query-agent-native-analytics`) for events collected through `/track` - **HubSpot** for CRM data — `hubspot-records` for contacts/companies/tickets/general lookup; `hubspot-deals` and `hubspot-metrics` for pipeline and revenue analysis - **Gong** for sales-call evidence — ask `run-gong-native-insight` first for what was said, risks, objections, or next steps; use `gong-calls` with `includeTranscripts=true` for quotes, counts, or when native operations are not connected - **Jira** for engineering metrics — tickets, sprints - **GitHub** for code metrics — PRs, reviews - **Agent-Native Analytics Monitoring -> Errors** for first-party captured client/server issues; use `list-error-issues` and `get-error-issue` for grouped details - **Sentry** for external error rates and trends when connected - **Grafana** for infrastructure metrics
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기