Lindy ObservabilitySAFE
Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com.
Overview
Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com.
4f83675ca38aOBSERVED · 2026-10-09What it tells the agent
The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.
--- name: lindy-observability description: 'Monitor Lindy AI agent health, task success rates, and credit consumption. Use when setting up monitoring, building dashboards, configuring alerts, or tracking agent performance over time. Trigger with phrases like "lindy monitoring", "lindy observability", "lindy metrics", "lindy logging", "lindy dashboard". ' allowed-tools: Read, Write, Edit version: 1.20.0 license: MIT author: Jeremy Longshore <[email protected]> tags: - saas - lindy - monitoring - observability - dashboard compatibility: Compatible with AI coding agents that can read Markdown and review monitoring configurations --- # 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_SECRET` by 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 1. Open the custom agent and select **Tasks**. 2. Review task status and open representative runs. 3. Inspect chronological steps, timestamps, conditions, and the error location. 4. 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: 1. Add **Agent Task Change** as the trigger. 2. Select the agent and actionable events: **Task succeeded**, **Task failed**, and **Task was canceled**. Add created/working only when lifecycle telemetry is needed. 3. 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. 4. Map the result into the small telemetry schema in Step 3. 5. 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: ```typescript 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.sen
Trust audit
SAFEgrade B · trust 89/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | PASS |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- none-observed
- Network
- none-observed
- Shell
- none-observed
- Dependencies
- pinned
- Secrets in source
- none-found
Findings (0)
No findings outside the package's declared scope.
Gates applied: no_behavioural_pass.
4f83675ca38afull audit observations/trust-audit/skill/jeremylongshore__lindy-observability.json · Report an issue / request a re-scanAudit history
Every audit this skill has had.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-09 | 4f83675ca38a | SAFE | B | 89 | first audit |
Questions
What does the Lindy Observability skill do?
Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com.
Is Lindy Observability safe to install?
The audit found nothing in the source that contradicts what it says it does, and graded it B (89/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean skill reads B.
What can Lindy Observability access on my machine?
The audit observed no filesystem, network or shell use at all in its source.
How current is this page?
The grade is for one exact copy of the source (4f83675ca38a), read on 2026-10-09. The repository is watched, and a new audit runs when it changes — this is the first audit.