lindy-observability
A guide to monitoring Lindy AI agent task completion, credit consumption, and step failures via webhooks and metrics.
Install
mkdir -p .claude/skills/lindy-observability && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/9294" && unzip -o skill.zip -d .claude/skills/lindy-observability && rm skill.zipInstalls to .claude/skills/lindy-observability
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Monitor Lindy AI agent health, task success rates, and credit consumption.Key capabilities
- →Monitor task completion rates
- →Configure alerts for failed tasks
- →Collect metrics via webhook callbacks
- →Visualize performance in dashboards
How it works
Observability is implemented by using Lindy's built-in task history or by configuring agents to send execution data to an external metrics endpoint via HTTP Request actions.
Inputs & outputs
When to use lindy-observability
- →Monitor agent task completion
- →Build dashboards for agent performance
- →Track credit consumption over time
- →Configure alerts for failed tasks
About this skill
Lindy Observability
Overview
Monitor workflow health from Lindy's documented task surfaces. Start with Tasks for manual inspection, then use an Agent Task Change trigger followed by Get Task Details for workflow-based monitoring and send only bounded operational fields to an external collector; task inputs, outputs, customer content, and secrets do not belong in metrics or logs.
Prerequisites
- Lindy workspace with active custom agents
- Access to each monitored agent's Tasks view
- For external monitoring: an HTTPS receiver and a metrics stack
- A distinct, nonempty callback secret stored as
LINDY_CALLBACK_SECRETby the receiver and as a protected value in the Lindy HTTP Request action
Authentication and Data Boundary
Authenticate Lindy's outbound HTTP Request with a dedicated bearer value generated for the metrics receiver. Store it only in Lindy's protected action configuration and the receiver's secret manager, require at least 32 characters, compare it in constant time, and rotate it independently. Never reuse an inbound Lindy webhook secret or a metrics-scrape credential. Export only the three schema fields defined below.
Instructions
Step 1: Establish the Built-In View
- Open the custom agent and select Tasks.
- Review task status and open representative runs.
- Inspect chronological steps, timestamps, conditions, and the error location.
- Record a workspace-specific baseline by agent and workflow class. Do not copy task inputs or outputs into the baseline.
The documented sources for operational signals are:
| Signal | Source | Handling |
|---|---|---|
| Task outcome and frequency | Tasks / Agent Task Change | Aggregate by configured agent key |
| Duration and failing block | Get Task Details | Retain duration; keep block content in Lindy |
| Workspace spend | Lindy billing view | Keep billing data at its documented source |
Step 2: Build the Monitoring Workflow
Create a separate monitoring agent using documented Lindy utilities:
- Add Agent Task Change as the trigger.
- Select the agent and actionable events: Task succeeded, Task failed, and Task was canceled. Add created/working only when lifecycle telemetry is needed.
- Add Get Task Details after the trigger. Leave Agent and Sub Task on Auto so Lindy associates the triggering task; set Max Number of Blocks high enough to cover the measured workflow.
- Map the result into the small telemetry schema in Step 3.
- Route human-readable failure alerts inside Lindy. Include an agent key, status, task link, and failing block name; omit block inputs and outputs.
Step 3: Collect Bounded Metrics
Use Lindy's HTTP Request action to POST the sanitized result. This TypeScript receiver rejects unknown agents, statuses, fields, oversized bodies, invalid durations, and empty secrets:
import { timingSafeEqual } from 'node:crypto';
import express from 'express';
import { Counter, Histogram, Registry } from 'prom-client';
const app = express();
app.use(express.json({ limit: '4kb', strict: true }));
const callbackSecret = process.env.LINDY_CALLBACK_SECRET;
if (!callbackSecret || callbackSecret.trim().length < 32) {
throw new Error('LINDY_CALLBACK_SECRET must contain at least 32 characters');
}
const agentKeys = new Set(
(process.env.LINDY_MONITORED_AGENTS ?? '')
.split(',')
.map((value) => value.trim())
.filter(Boolean),
);
if (agentKeys.size === 0) throw new Error('LINDY_MONITORED_AGENTS is empty');
type TaskStatus = 'succeeded' | 'failed' | 'canceled';
type MetricInput = { agent: string; status: TaskStatus; durationSeconds: number };
const statuses = new Set<TaskStatus>(['succeeded', 'failed', 'canceled']);
function authorized(header: string | undefined): boolean {
if (!header?.startsWith('Bearer ')) return false;
const actual = Buffer.from(header.slice('Bearer '.length));
const expected = Buffer.from(callbackSecret);
return actual.length === expected.length && timingSafeEqual(actual, expected);
}
function parseMetricInput(value: unknown): MetricInput | null {
if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
const input = value as Record<string, unknown>;
const allowed = new Set(['agent', 'status', 'durationSeconds']);
if (Object.keys(input).some((key) => !allowed.has(key))) return null;
if (typeof input.agent !== 'string' || !agentKeys.has(input.agent)) return null;
if (typeof input.status !== 'string' || !statuses.has(input.status as TaskStatus)) return null;
if (
typeof input.durationSeconds !== 'number' ||
!Number.isFinite(input.durationSeconds) ||
input.durationSeconds < 0 ||
input.durationSeconds > 86_400
) return null;
return input as MetricInput;
}
const registry = new Registry();
const taskCounter = new Counter<'agent' | 'status'>({
name: 'lindy_tasks_total',
help: 'Total Lindy agent tasks',
labelNames: ['agent', 'status'],
registers: [registry],
});
const taskDuration = new Histogram<'agent'>({
name: 'lindy_task_duration_seconds',
help: 'Lindy task execution duration',
labelNames: ['agent'],
buckets: [1, 2, 5, 10, 30, 60, 120],
registers: [registry],
});
app.post('/lindy/metrics', (req, res) => {
if (!authorized(req.headers.authorization)) return res.sendStatus(401);
const input = parseMetricInput(req.body);
if (!input) return res.status(400).json({ error: 'invalid_metrics_schema' });
taskCounter.inc({ agent: input.agent, status: input.status });
taskDuration.observe({ agent: input.agent }, input.durationSeconds);
// Do not log req.body or task details.
return res.json({ recorded: true });
});
app.get('/metrics', async (_req, res) => {
res.set('Content-Type', registry.contentType);
res.send(await registry.metrics());
});
Configure the HTTP Request action with an allowlisted HTTPS URL, POST, JSON content
type, and Authorization: Bearer <protected callback secret>. Map only:
{
"agent": "support-bot",
"status": "succeeded",
"durationSeconds": 12.4
}
The agent value is a stable configured key, never a task/customer identifier. Do not reuse a secret generated for an inbound Webhook Received trigger as the outbound callback secret.
Step 4: Query and Alert
Use correct counter/histogram aggregation:
| Panel | PromQL |
|---|---|
| Success ratio | sum(rate(lindy_tasks_total{status="succeeded"}[1h])) / clamp_min(sum(rate(lindy_tasks_total[1h])), 1e-9) |
| Failure rate | sum by (agent) (rate(lindy_tasks_total{status="failed"}[15m])) |
| Duration p95 | histogram_quantile(0.95, sum by (le, agent) (rate(lindy_task_duration_seconds_bucket[15m]))) |
| Trigger frequency | sum by (agent) (rate(lindy_tasks_total[15m])) |
Set windows and thresholds from the measured workspace baseline and service objectives. Alert text may link to the task but must not reproduce task content.
Step 5: Add Quality Regression Checks
Lindy currently documents evals as offline evaluation of selected historical tasks. Use them to compare quality after changes; do not describe them as live monitoring. Keep operational alerts on Tasks/Agent Task Change and quality regression on evals.
Error Handling
| Issue | Response |
|---|---|
| Agent Task Change is silent | Confirm the monitoring agent is active, selected agent is correct, and event is enabled |
| Collector returns 401 | Rotate and update the dedicated callback secret on both sides |
| Collector returns 400 | Reject the event; inspect only field names/types, not payload content |
| Cardinality spike | Restore the configured agent allowlist and remove dynamic labels |
| Dashboard has no samples | Verify HTTP status in the Lindy task and scrape the registry endpoint |
Output
Return an observability plan containing:
- monitored agents and selected Agent Task Change events;
- the exact low-cardinality telemetry schema and agent allowlist;
- secret ownership and rotation notes for
LINDY_CALLBACK_SECRET; - baseline-derived dashboard queries and alert thresholds;
- a privacy review confirming that no task input, output, customer identifier, or credential leaves Lindy; and
- a verification receipt with a successful sample, a rejected bad secret, a rejected unknown field/agent, and a Prometheus scrape.
Examples
For a support workflow, select success/failure/canceled events, retrieve task details,
and map only {agent: "support-bot", status: "failed", durationSeconds: 12.4}. The
receiver increments one bounded counter/histogram series. The alert links an operator
to the Lindy task for authorized investigation; it does not copy the customer message
or block output into Slack, logs, or Prometheus.
Resources
Next Steps
Hand the verified alert contract and task-link policy to lindy-incident-runbook so
responders can investigate inside Lindy without expanding telemetry data exposure.
When not to use it
- →When monitoring requirements are limited to basic dashboard checks
- →When the agent environment is too small to justify external metrics
Prerequisites
Limitations
- →External monitoring requires a separate metrics stack
- →Eval runs consume credits
How it compares
It provides a tiered maturity model for observability, ranging from built-in dashboard checks to automated remediation agents.
Compared to similar skills
lindy-observability side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| lindy-observability (this skill) | 0 | 2mo | Caution | Advanced |
| distributed-tracing | 5 | 4mo | No flags | Intermediate |
| service-mesh-observability | 5 | 4mo | No flags | Advanced |
| observability-engineer | 12 | 5mo | No flags | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by jeremylongshore
View all by jeremylongshore →You might also like
distributed-tracing
wshobson
Implement distributed tracing with Jaeger and Tempo to track requests across microservices and identify performance bottlenecks. Use when debugging microservices, analyzing request flows, or implementing observability for distributed systems.
service-mesh-observability
wshobson
Implement comprehensive observability for service meshes including distributed tracing, metrics, and visualization. Use when setting up mesh monitoring, debugging latency issues, or implementing SLOs for service communication.
observability-engineer
sickn33
Build production-ready monitoring, logging, and tracing systems. Implements comprehensive observability strategies, SLI/SLO management, and incident response workflows. Use PROACTIVELY for monitoring infrastructure, performance optimization, or production reliability.
prometheus-configuration
wshobson
Set up Prometheus for comprehensive metric collection, storage, and monitoring of infrastructure and applications. Use when implementing metrics collection, setting up monitoring infrastructure, or configuring alerting systems.
langfuse
davila7
Expert in Langfuse - the open-source LLM observability platform. Covers tracing, prompt management, evaluation, datasets, and integration with LangChain, LlamaIndex, and OpenAI. Essential for debugging, monitoring, and improving LLM applications in production. Use when: langfuse, llm observability, llm tracing, prompt management, llm evaluation.
slo-implementation
wshobson
Define and implement Service Level Indicators (SLIs) and Service Level Objectives (SLOs) with error budgets and alerting. Use when establishing reliability targets, implementing SRE practices, or measuring service performance.