Customer Health Report — AI Workflow Plan | Diaphora
Customer Health Report
Query BigQuery for a tenant's server usage, daily trend, tool breakdown, user activity, and error patterns, then synthesize an executive customer-health report.
Best for
- Customer success
- Account teams
- Ops
Runs with
- BigQuery
- Adoption risk
- Error patterns
At a glance
04 Output
01 Capabilities
03 Teams
Core outputs
- Health overview
- Risk flags
- Adoption gaps
- Champion asks
- Capability requirements
What it solves
Health calls run on gut feel because the data sits in warehouse tables nobody queries by hand.
Every health call grounded in real numbers. Not a feeling.
Adoption risk and single-user dependency, surfaced before churn — not after.
Concrete asks a CSM can actually bring to their champion.
Workflow
- Run scoped BigQuery reads for per-server, daily, tool, user, and error data.
- Assemble the telemetry into a single typed tenant dataset.
- Synthesize adoption risk, single-user dependency, and next steps.
Implementation
Review the underlying FML blueprint — the sessions, tools, and typed schemas that define this workflow — and see exactly how it is instructed for repeatable execution.
FML Blueprint
customer-analytics.fml
system("You are a CS and DevOps analyst generating a customer health report.")
parameter("tenant_id", type=string, title="Tenant ID")
parameter("customer_name", type=string, title="Customer Name")
require mcp BigQuery
components {
schema("ServerStats") {
mcp_name: string
status: string
total_tool_calls: int
total_errors: int
error_rate: float
active_users: int
distinct_tools_called: int
active_days: int
first_call: string
last_call: string
days_since_last_call: int
connected_but_never_called: bool
}
schema("DailyRollup") {
event_date: string
total_calls: int
errors: int
error_rate: float
active_tenants: int
}
schema("TopServers") {
mcp_server: string
total_calls: int
errors: int
error_rate: float
active_days: int
}
schema("ToolStats") {
mcp_server: string
tool_name: string
total_calls: int
errors: int
error_rate: float
}
schema("UserActivity") {
user_id: string
total_exec_calls: int
last_active_date: string
stage: string
recency: string
}
schema("ErrorPattern") {
mcp_server: string
tool_name: string
error_message: string
occurrences: int
last_seen: string
}
}
session("server_breakdown") {
use mcp BigQuery
+ Run this BigQuery SQL to get per-server stats for {{ .params.customer_name }} (tenant {{ .params.tenant_id }}):
```sql
SELECT
mcp_name,
status,
total_tool_calls,
total_errors,
SAFE_DIVIDE(total_errors, NULLIF(total_tool_calls, 0)) AS error_rate,
active_users,
distinct_tools_called,
active_days,
CAST(first_tool_call AS STRING) AS first_call,
CAST(last_tool_call AS STRING) AS last_call,
days_since_last_call,
connected_but_never_called
FROM `barndoor-production.gtm_analytics.mcp_block`
WHERE tenant_id = '{{ .params.tenant_id }}'
ORDER BY total_tool_calls DESC;
- Map results into the schema.
schema $ServerStats[] }
session("daily_rollup", after="server_breakdown") { use mcp BigQuery
- Run this BigQuery SQL to get the 30-day daily call trend for {{ .params.customer_name }}:
SELECT
CAST(event_date AS STRING) AS event_date,
SUM(call_count) AS total_calls,
SUM(error_count) AS errors,
SAFE_DIVIDE(SUM(error_count), NULLIF(SUM(call_count), 0)) AS error_rate,
COUNT(DISTINCT tenant_id) AS active_tenants
FROM `barndoor-production.gtm_analytics.fact_tool_call_daily`
WHERE tenant_id = '{{ .params.tenant_id }}'
AND event_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
GROUP BY event_date
ORDER BY event_date ASC;
- Map results.
schema $DailyRollup[] }
session("top_servers", after="daily_rollup") { use mcp BigQuery
- Run this BigQuery SQL to get the top servers by volume for {{ .params.customer_name }} over the last 30 days:
SELECT
mcp AS mcp_server,
SUM(call_count) AS total_calls,
SUM(error_count) AS errors,
SAFE_DIVIDE(SUM(error_count), NULLIF(SUM(call_count), 0)) AS error_rate,
COUNT(DISTINCT event_date) AS active_days
FROM `barndoor-production.gtm_analytics.fact_tool_call_daily`
WHERE tenant_id = '{{ .params.tenant_id }}'
AND event_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
GROUP BY mcp
ORDER BY total_calls DESC
LIMIT 10;
- Map results.
schema $TopServers[] }
session("tool_breakdown", after="top_servers") { use mcp BigQuery
- Run this BigQuery SQL to get tool-level usage for {{ .params.customer_name }}:
SELECT
mcp AS mcp_server,
tool_name,
SUM(call_count) AS total_calls,
SUM(error_count) AS errors,
SAFE_DIVIDE(SUM(error_count), NULLIF(SUM(call_count), 0)) AS error_rate
FROM `barndoor-production.gtm_analytics.fact_tool_call_daily`
WHERE tenant_id = '{{ .params.tenant_id }}'
AND event_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
GROUP BY mcp, tool_name
ORDER BY total_calls DESC;
- Map results.
schema $ToolStats[] }
session("user_activity", after="tool_breakdown") { use mcp BigQuery
- Run this BigQuery SQL to get user-level activity for {{ .params.customer_name }}:
SELECT
user_id,
total_exec_calls,
CAST(last_active_date AS STRING) AS last_active_date,
stage,
recency
FROM `barndoor-production.gtm_analytics.user_block`
WHERE tenant_id = '{{ .params.tenant_id }}'
AND total_exec_calls > 0
ORDER BY total_exec_calls DESC
LIMIT 50;
- Map results.
schema $UserActivity[] }
session("error_patterns", after="user_activity") { use mcp BigQuery
- Run this BigQuery SQL to get error patterns for {{ .params.customer_name }}:
SELECT
mcp AS mcp_server,
tool_name,
error_message,
COUNT(*) AS occurrences,
MAX(CAST(timestamp AS STRING)) AS last_seen
FROM `barndoor-production.gtm_analytics.tool_call_errors`
WHERE tenant_id = '{{ .params.tenant_id }}'
AND event_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
GROUP BY mcp, tool_name, error_message
ORDER BY occurrences DESC;
- Map results.
schema $ErrorPattern[] }
session("executive_summary", after="error_patterns") { context "Servers: {{ .context.server_breakdown | json }}\nDaily Rollup: {{ .context.daily_rollup | json }}\nTop Servers: {{ .context.top_servers | json }}\nTools: {{ .context.tool_breakdown | json }}\nUsers: {{ .context.user_activity | json }}\nErrors: {{ .context.error_patterns | json }}"
- You are a Customer Success lead preparing an executive health report for {{ .params.customer_name }}. Based on the data above, synthesize a report covering: adoption risk, single-user dependency, dormant server inventory, policy gaps, and concrete next steps for the CS and account teams.
schema { overview: string risk_flags: string[] adoption_gaps: string[] action_items: string[] recommended_asks_for_champion: string[] }