dd-pup — Claude Code skill: Datadog work through the pup CLI
A skill that hands your agent ready pup commands for Datadog: logs, metrics, monitors, incidents. Useful when triage happens in the chat window.
npx skills add datadog-labs/agent-skills --skill dd-pup -a claude-codeWhat dd-pup does
The skill documents pup, a Rust CLI for the Datadog API. It ships a quick-reference table plus sections for monitors, logs, metrics, traces, incidents, dashboards, SLOs, on-call and audit logs. Your agent copies a working command instead of guessing at flags.
Auth runs through OAuth2 in the browser or through API keys. Tokens last about an hour, so a 401 or 403 mid-conversation means running pup auth refresh first and falling back to pup auth login only if that fails. Headless machines have no browser: set DD_API_KEY, DD_APP_KEY and DD_SITE instead.
One rule stands out: never fire a command that still holds a placeholder such as <env> or <monitor-id>. Check the conversation, run a discovery command, confirm with the user, then execute. Dashboard create, clone and update get their own workflow — a read-only snapshot, a separate payload stripped of response-only fields, then a comparison of source and destination. The skill calls the pup binary, so nothing works until pup is on the machine.
What it helps with
- pull error logs for a service from the last hour
- diff a live monitor against a local JSON file
- schedule monitor downtime from a payload file
- find slow traces for one service
- trace deleted actions in audit logs
Example prompts for the agent
- Search error logs for the checkout service from the last hour
- Show slow traces for api-gateway over the past hour
- Diff monitor 12345 against monitor.json
How to install dd-pup
1Skills CLI (Vercel)
npx skills add datadog-labs/agent-skills --skill dd-pup -a claude-code2Manually: put the files in place
~/.claude/skills/dd-pup/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/dd-pup/
1Skills CLI (Vercel)
npx skills add datadog-labs/agent-skills --skill dd-pup -a codex2Manually: put the files in place
.agents/skills/dd-pup/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add datadog-labs/agent-skills --skill dd-pup -a cursor2Manually: put the files in place
.cursor/skills/dd-pup/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install datadog-labs/agent-skills dd-pup2Manually: put the files in place
.github/skills/dd-pup/SKILL.md1Skills CLI (Vercel)
npx skills add datadog-labs/agent-skills --skill dd-pup -a gemini-cli2Platform CLI
gemini skills install https://github.com/datadog-labs/agent-skills --path dd-pupManually: put the files in place
.devin/skills/dd-pup/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add datadog-labs/agent-skills --skill dd-pup -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about dd-pup
How do I install dd-pup in Claude Code?
Run npx skills add datadog-labs/agent-skills --skill dd-pup -a claude-code. The skill lands in ~/.claude/skills/dd-pup/SKILL.md.
What does dd-pup do?
It gives the agent a reference for the pup CLI: log search, metric queries, monitors, incidents, dashboards and audit logs.
What do I need before using it?
pup installed and authenticated. On a desktop, pup auth login is enough; headless setups need DD_API_KEY, DD_APP_KEY and DD_SITE.
Source text
SKILL.md · MIT
---
name: dd-pup
description: Datadog CLI (Rust). OAuth2 auth with token refresh.
metadata:
version: "1.0.2"
author: datadog-labs
repository: https://github.com/datadog-labs/agent-skills
tags: datadog,cli,dd-pup,pup
alwaysApply: "false"
---
# pup (Datadog CLI)
Pup CLI for Datadog API operations. Supports OAuth2 and API key auth.
## Quick Reference
| Task | Command |
|------|---------|
| Search error logs | `pup logs search --query "status:error" --from 1h` |
| List monitors | `pup monitors list` |
| Diff a monitor definition | `pup monitors diff <monitor-id> monitor.json` |
| Schedule monitor downtime | `pup downtime create --file downtime.json` |
| Open a dashboard at a live time window | `pup dashboards url <dashboard-id> --from now-1h --to now --live true` |
| Find recent slow traces for a service (last 1h) | `pup traces search --query "service:<service-name> @duration:>500ms" --from 1h` |
| List incidents | `pup incidents list --limit 50` |
| Import incident payload | `pup incidents import --file incident.json` |
| Query metrics | `pup metrics query --query "avg:system.cpu.user{*}"` |
| List hosts | `pup infrastructure hosts list --count 50` |
| Check SLOs | `pup slos list` |
| On-call teams | `pup on-call teams list` |
| Triage open critical security signals (last 1h) | `pup security signals list --query "status:open severity:critical" --from 1h --limit 100` |
| Search audit logs | `pup audit-logs search --query "@action:deleted" --from 24h` |
| Audit activity by user | `pup audit-logs search --query "@usr.email:[email protected]" --from 7d` |
| Investigate API key | `pup audit-logs search --query "@metadata.api_key.id:KEY_ID" --from 90d` |
| Check auth | `pup auth status` |
| Token expiry (time left) | `pup auth status` |
| Refresh token | `pup auth refresh` |
## Prerequisites
Install pup using the [setup instructions](https://github.com/datadog-labs/agent-skills/tree/main?tab=readme-ov-file#setup-pup).
## Required Input Resolution
For commands that need specific scope values (`<env>`, `<service-name>`, `<team-id>`, resource IDs), use this order:
1. Check context first (conversation history, prior command output, saved variables).
2. If missing, run a discovery command first (list/search) to get valid values.
3. If still missing or ambiguous, ask the user to confirm the exact value.
4. Then run the target command.
5. Never run commands with unresolved placeholders like `<env>` or `<monitor-id>`.
## Auth
```bash
pup auth login # OAuth2 browser flow (recommended)
pup auth status # Check token validity
pup auth refresh # Refresh expired token (no browser)
pup auth logout # Clear credentials
```
**Tokens expire (~1 hour)**. If a command fails with 401/403 mid-conversation:
```bash
pup auth refresh # Try refresh first
pup auth login # If refresh fails, full re-auth
```
If Chrome opens the wrong profile/window, use the one-time OAuth URL printed by `pup auth login`
(`If the browser doesn't open, visit: ...`) and open that link manually in the correct account session.
### Headless/CI (no browser)
```bash
# Use env vars or:
export DD_API_KEY=your-api-key
export DD_APP_KEY=your-app-key
export DD_SITE=datadoghq.com # or datadoghq.eu, etc.
```
## Command Reference
### Monitors
```bash
pup monitors list --limit 10
pup monitors list --tags "env:<env>"
pup monitors get <monitor-id>
pup monitors search --query "<monitor-name>"
pup monitors create --file monitor.json
pup monitors update <monitor-id> --file monitor.json
pup monitors diff <monitor-id> monitor.json
pup monitors delete <monitor-id>
# No pup monitors mute/unmute commands; use downtime payloads instead.
pup downtime create --file downtime.json
```
### Logs
```bash
pup logs search --query "status:error" --from 1h
pup logs search --query "service:<service-name>" --from 1h --limit 100
pup logs search --query "@http.status_code:5*" --from 24h
pup logs search --query "env:<env> level:error" --from 1h
pup logs aggregate --query "service:<service-name>" --compute count --from 1h
```
### Metrics
```bash
pup metrics query --query "avg:system.cpu.user{*}" --from 1h --to now
pup metrics query --query "sum:trace.express.request.hits{service:<service-name>}" --from 1h --to now
pup metrics list --filter "system.*"
```
### APM / Traces
```bash
# Confirm env tag with the user first (do not assume production/prod/prd).
pup apm services list --env <env> --from 1h --to now
pup traces search --query "service:<service-name>" --from 1h
pup traces search --query "service:<service-name> @duration:>500ms" --from 1h
pup traces search --query "service:<service-name> status:error" --from 1h
```
### Incidents
```bash
pup incidents list --limit 50
pup incidents get <incident-id>
pup incidents import --file incident.json
```
### Dashboards
```bash
pup dashboards list
pup dashboards get <dashboard-id> --read-only
pup dashboards url <dashboard-id> --from now-1h --to now --live true
pup dashboards create --file dashboard.json
pup dashboards update <dashboard-id> --file dashboard.json
pup dashboards delete <dashboard-id>
```
#### Safe dashboard create, clone, and update workflow
The goal is a recoverable source and a verified destination. A successful API response alone does not prove that widget content or placement was preserved.
1. Fetch the source or update target with `--read-only` and save the exact response as an immutable snapshot. Never overwrite this file with transformed JSON.
```bash
pup dashboards get <dashboard-id> --read-only -o json > dashboard-source.json
```
2. Build a separate mutation payload. Remove response-only fields before create/update: `author_handle`, `author_name`, `created_at`, `id`, `modified_at`, and `url`.
```bash
jq 'del(.author_handle, .author_name, .created_at, .id, .modified_at, .url)' \
dashboard-source.json > dashboard-payload.json
```
3. For a backup or clone, leave the source dashboard unchanged and change only explicitly requested fields, usually `title` or `description`. Preserve `layout_type`, `reflow_type`, widget order, and every recursive widget `layout` object (`x`, `y`, `width`, `height`, and `is_column_break`). Repacking or compacting coordinates creates a derived layout, not an exact clone.
4. Create or update from `dashboard-payload.json`, then fetch the destination into a new file.
```bash
pup dashboards create --file dashboard-payload.json
pup dashboards get <destination-id> --read-only -o json > dashboard-destination.json
```
5. Normalize away the response-only fields and compare the complete definitions. The only differences should be the fields intentionally changed.
6. Also compare layout projections separately so a placement regression cannot hide in a large widget diff:
```bash
jq '{layout_type, reflow_type, layouts: [.. | objects | .layout? // empty]}' dashboard-source.json
jq '{layout_type, reflow_type, layouts: [.. | objects | .layout? // empty]}' dashboard-destination.json
```
Pup 1.6.3 does not expose dashboard version history. If an exact historical version is required and no immutable snapshot exists, inspect version history in the Datadog UI before changing the dashboard.
### SLOs
```bash
pup slos list
pup slos get <slo-id>
pup slos status <slo-id> --from 30d --to now
pup slos create --file slo.json
```
### Synthetics
```bash
pup synthetics tests list
pup synthetics tests get <test-id>
pup synthetics tests search --text "login"
pup synthetics locations list
```
### On-Call
```bash
pup on-call teams list
# Pick a real team id from `pup on-call teams list` output.
pup on-call teams get <team-id>
pup on-call teams memberships list <team-id>
```
### Hosts / Infrastructure
```bash
pup infrastructure hosts list --count 50
pup infrastructure hosts list --filter "env:<env>"
pup infrastructure hosts get <host-name>
```
### Events
```bash
pup events list --from 24h
pup events list --tags "source:deploy"
pup events search --query "deploy" --from 24h --limit 50
pup events get <event-id>
```
### Downtimes
```bash
pup downtime list
pup downtime create --file downtime.json
pup downtime cancel <downtime-id>
```
### Users / Teams
```bash
pup users list
pup users get <user-id>
```
### Security
```bash
pup security signals list --query "*" --from 1h --limit 100
pup security signals list --query "status:open severity:critical" --from 1h --limit 100
# Broader lookback for historical triage
pup security signals list --query "severity:critical" --from 24h --limit 100
```
### Audit Logs
```bash
# List recent events
pup audit-logs list --from 1h --limit 100
# Search with query (Lucene syntax, same as Log Explorer)
pup audit-logs search --query "@action:deleted" --from 24h
pup audit-logs search --query "@usr.email:[email protected]" --from 7d
pup audit-logs search --query "@evt.name:Authentication @action:login" --from 7d
pup audit-logs search --query "@metadata.api_key.id:KEY_ID" --from 90d --limit 200
# JSON output for piping to jq
pup audit-logs search --query "@action:deleted" --from 24h -o json | jq '.data[].attributes'
# audit-logs is the long form (both work)
pup audit-logs search --query "@evt.name:Monitor @action:modified" --from 7d
```
### Service Catalog
```bash
pup service-catalog list
pup service-catalog get <service-name>
```
### Notebooks
```bash
pup notebooks list
pup notebooks get <notebook-id>
```
### Workflows
```bash
pup workflows get <workflow-id>
pup workflows run <workflow-id> --payload '{"key":"value"}'
pup workflows instances list <workflow-id>
```
### Observability Pipelines
```bash
pup obs-pipelines list --limit 50
pup obs-pipelines get <pipeline-id>
pup obs-pipelines create --file pipeline.json
pup obs-pipelines update <pipeline-id> --file pipeline.json
pup obs-pipelines delete <pipeline-id>
pup obs-pipelines validate --file pipeline.json
```
### LLM Observability
```bash
pup llm-obs projects list
pup llm-obs projects create --file project.json
pup llm-obs experiments list
pup llm-obs experiments list --filter-project-id <project-id>
pup llm-obs experiments list --filter-dataset-id <dataset-id>
pup llm-obs experiments create --file experiment.json
pup llm-obs experiments update <experiment-id> --file experiment.json
pup llm-obs experiments delete --file delete-request.json
pup llm-obs datasets list --project-id <project-id>
pup llm-obs datasets create --project-id <project-id> --file dataset.json
pup llm-obs spans search --ml-app <ml-app-name> --from 1h --limit 20
```
### Reference Tables
```bash
pup reference-tables list --limit 50
pup reference-tables get <table-id>
pup reference-tables create --file table.json
pup reference-tables batch-query --file query.json
```
### Cost Cloud Configs
```bash
# AWS CUR configs
pup cost aws-config list
pup cost aws-config get <account-id>
pup cost aws-config create --file config.json
pup cost aws-config delete <account-id>
# Azure UC configs
pup cost azure-config list
pup cost azure-config get <account-id>
pup cost azure-config create --file config.json
pup cost azure-config delete <account-id>
# GCP usage cost configs
pup cost gcp-config list
pup cost gcp-config get <account-id>
pup cost gcp-config create --file config.json
pup cost gcp-config delete <account-id>
```
## Subcommand Discovery
```bash
pup --version # Confirm installed version before documenting workarounds
pup --help # List all commands
pup <command> --help # Command-specific help
pup dashboards get <dashboard-id> --jq '{title, layout_type}' # Filter output before formatting
```
If local help differs from this skill, compare `pup --version` with the latest stable release before inventing a workaround.
## Error Handling
| Error | Cause | Fix |
|-------|-------|-----|
| 401 Unauthorized | Token expired | `pup auth refresh` |
| 403 Forbidden | Missing scope | Check app key permissions |
| 404 Not Found | Wrong ID/resource | Verify resource exists |
| Rate limited | Too many requests | Add delays between calls |
## Install
See [Setup Pup](https://github.com/datadog-labs/agent-skills/tree/main?tab=readme-ov-file#setup-pup) for installation instructions.
### Verify Installation
```bash
which pup
pup --version
```
## Sites
| Site | `DD_SITE` value |
|------|-----------------|
| US1 (default) | `datadoghq.com` |
| US3 | `us3.datadoghq.com` |
| US5 | `us5.datadoghq.com` |
| EU1 | `datadoghq.eu` |
| AP1 | `ap1.datadoghq.com` |
| AP2 | `ap2.datadoghq.com` |
| US1-FED | `ddog-gov.com` |
© datadog-labs · MIT · datadog-labs/agent-skills