Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pup skills list

| Skill | Description |
|-------|-------------|
| **dd-onboarding** | Agent install, APM, logs, integrations — AI-driven setup via live skill API |
| **dd-pup** | Primary CLI - all pup commands, auth, site config |
| **dd-monitors** | Create, manage, mute monitors and alerts |
| **dd-logs** | Search logs, pipelines, archives |
Expand Down
38 changes: 38 additions & 0 deletions skills/dd-onboarding/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: dd-onboarding
description: Datadog Agentic Onboarding. Guides installation and setup of the Datadog Agent, APM, logs, integrations, and cloud environments via an AI-driven workflow.
metadata:
version: "1.0.0"
author: datadog-labs
repository: https://github.com/DataDog/dd-source
tags: datadog,onboarding,setup,install,apm,agent,kubernetes,docker,lambda,ecs
alwaysApply: "false"
---

# Datadog Agentic Onboarding

For any Datadog setup, installation, configuration, or troubleshooting task, fetch the onboarding
orchestrator first and follow its instructions:

```bash
curl -s -X GET "https://api.${DD_SITE:-datadoghq.com}/api/v2/onboarding/skills/orchestrator" \
-H "DD-API-KEY: ${DD_API_KEY}" \
-H "DD-APPLICATION-KEY: ${DD_APP_KEY}" \
| jq -r '.data.attributes.content'
```

The orchestrator will guide credential validation, environment discovery, skill selection, and
step-by-step setup. Follow it exactly — do not skip steps or proceed without the orchestrator
content loaded.

## Prerequisites

`DD_API_KEY`, `DD_APP_KEY`, and `DD_SITE` must be set before fetching the orchestrator. If any are
missing, ask the user to provide them. Default `DD_SITE` to `datadoghq.com` if unset.

## When this skill applies

- Installing the Datadog Agent on any platform (Kubernetes, Linux, Docker, ECS, Lambda, Azure, GCP)
- Setting up APM, logs, RUM, or cloud integrations
- Troubleshooting an existing Datadog Agent or APM installation
- Any question that starts with "how do I monitor…", "set up Datadog on…", or "install the agent on…"
99 changes: 99 additions & 0 deletions src/commands/skills.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use anyhow::{bail, Result};

use crate::client;
use crate::config::Config;
use crate::formatter;
use crate::skills;
use std::path::Path;

/// Resolve the platform list from CLI input, validating each entry.
///
Expand Down Expand Up @@ -300,6 +304,101 @@ pub fn path(platform: Option<String>, project: bool) -> Result<()> {
Ok(())
}

pub async fn catalog_list(cfg: &Config, tags: Vec<String>) -> Result<()> {
let query = tags
.iter()
.map(|t| format!("tags={t}"))
.collect::<Vec<_>>()
.join("&");
let path = if query.is_empty() {
"/api/v2/skills".to_string()
} else {
format!("/api/v2/skills?{query}")
};
let data = client::raw_get(cfg, &path, &[]).await?;
formatter::output(cfg, &data)
}

pub async fn catalog_get(cfg: &Config, name: String) -> Result<()> {
let path = format!("/api/v2/skills/{name}");
let data = client::raw_get(cfg, &path, &[]).await?;
formatter::output(cfg, &data)
}

pub async fn catalog_publish(
cfg: &Config,
file: String,
name: String,
description: Option<String>,
tags: Vec<String>,
) -> Result<()> {
let content = std::fs::read_to_string(Path::new(&file))
.map_err(|e| anyhow::anyhow!("failed to read {file}: {e}"))?;
let desc = description.unwrap_or_default();
let body = serde_json::json!({
"data": {
"type": "registry_skill",
"attributes": {
"name": name,
"description": desc,
"content": content,
"tags": tags,
}
}
});
let data = client::raw_post(cfg, "/api/v2/skills", body).await?;
formatter::output(cfg, &data)
}

pub async fn catalog_update(
cfg: &Config,
file: String,
name: String,
description: Option<String>,
tags: Vec<String>,
) -> Result<()> {
let content = std::fs::read_to_string(Path::new(&file))
.map_err(|e| anyhow::anyhow!("failed to read {file}: {e}"))?;
let mut attrs = serde_json::json!({
"content": content,
"tags": tags,
});
if let Some(desc) = description {
attrs["description"] = serde_json::json!(desc);
}
let body = serde_json::json!({
"data": {
"type": "registry_skill",
"attributes": attrs,
}
});
let path = format!("/api/v2/skills/{}", name.replace('/', "%2F"));
let data = client::raw_put(cfg, &path, body).await?;
formatter::output(cfg, &data)
}

pub async fn session_record(
cfg: &Config,
session_id: String,
skill_ids: Vec<String>,
summary: String,
status: String,
) -> Result<()> {
let body = serde_json::json!({
"data": {
"type": "onboarding_session",
"id": session_id,
"attributes": {
"skill_ids": skill_ids,
"summary": summary,
"status": status,
}
}
});
let data = client::raw_post(cfg, "/api/v2/onboarding/sessions", body).await?;
formatter::output(cfg, &data)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
124 changes: 124 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9686,6 +9686,91 @@ enum SkillsActions {
#[arg(long)]
project: bool,
},
/// Browse the remote Datadog skill catalog
///
/// COMMANDS:
/// list List skills from the remote catalog (optionally filtered by tag)
/// get Fetch a single skill's full content by name
///
/// EXAMPLES:
/// pup skills catalog list
/// pup skills catalog list --tags apm
/// pup skills catalog list --tags apm --tags observability
/// pup skills catalog get kubernetes-agent-install
Catalog {
#[command(subcommand)]
action: SkillsCatalogActions,
},
/// Record an onboarding session checkpoint or terminal event
///
/// EXAMPLES:
/// pup skills session --session-id <uuid> --skill-ids kubernetes-agent-install --summary "installed agent" --status completed
/// pup skills session --session-id <uuid> --skill-ids apm-setup --skill-ids missing-traces --summary "in progress" --status in_progress
Session {
/// Session UUID
#[arg(long)]
session_id: String,
/// Skill IDs used in this session (repeatable)
#[arg(long = "skill-ids", name = "skill-ids")]
skill_ids: Vec<String>,
/// Human-readable summary of what happened
#[arg(long)]
summary: String,
/// Session status: in_progress, completed, failed, abandoned
#[arg(long)]
status: String,
},
}

#[cfg(not(target_arch = "wasm32"))]
#[derive(Subcommand)]
enum SkillsCatalogActions {
/// List skills from the remote Datadog skill catalog
List {
/// Filter by tag (repeatable, e.g. --tags apm --tags observability)
#[arg(long)]
tags: Vec<String>,
},
/// Fetch a single skill's full content by name
Get {
/// Skill name (e.g. apm-k8s-ssi-agent-install)
name: String,
},
/// Publish a skill file to the remote catalog (creates a new skill)
///
/// EXAMPLES:
/// pup skills catalog publish SKILL.md --name apm-k8s-ssi-agent-install --tags apm
/// pup skills catalog publish SKILL.md --name dd-apm --description "APM router" --tags apm --tags onboarding
Publish {
/// Path to the skill markdown file to publish
file: String,
/// Name to register the skill under in the catalog
#[arg(long)]
name: String,
/// Human-readable description of the skill
#[arg(long)]
description: Option<String>,
/// Tags for filtering (repeatable)
#[arg(long)]
tags: Vec<String>,
},
/// Update an existing skill in the remote catalog
///
/// EXAMPLES:
/// pup skills catalog update SKILL.md --name apm-k8s-ssi-agent-install
Update {
/// Path to the updated skill markdown file
file: String,
/// Name of the skill to update
#[arg(long)]
name: String,
/// Updated human-readable description
#[arg(long)]
description: Option<String>,
/// Updated tags (replaces existing tags)
#[arg(long)]
tags: Vec<String>,
},
}

// ---- Product Analytics ----
Expand Down Expand Up @@ -15113,6 +15198,45 @@ async fn main_inner() -> anyhow::Result<()> {
SkillsActions::Path { platform, project } => {
commands::skills::path(platform.map(|p| p.as_canonical().to_string()), project)?
}
SkillsActions::Catalog { action } => {
cfg.validate_auth()?;
match action {
SkillsCatalogActions::List { tags } => {
commands::skills::catalog_list(&cfg, tags).await?;
}
SkillsCatalogActions::Get { name } => {
commands::skills::catalog_get(&cfg, name).await?;
}
SkillsCatalogActions::Publish {
file,
name,
description,
tags,
} => {
commands::skills::catalog_publish(&cfg, file, name, description, tags)
.await?;
}
SkillsCatalogActions::Update {
file,
name,
description,
tags,
} => {
commands::skills::catalog_update(&cfg, file, name, description, tags)
.await?;
}
}
}
SkillsActions::Session {
session_id,
skill_ids,
summary,
status,
} => {
cfg.validate_auth()?;
commands::skills::session_record(&cfg, session_id, skill_ids, summary, status)
.await?;
}
},
// --- Product Analytics ---
Commands::ProductAnalytics { action } => {
Expand Down
8 changes: 8 additions & 0 deletions src/skills.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ static DD_PUP_PI_FILES: &[(&str, &str)] = &[

pub static SKILLS: &[SkillEntry] = &[
// --- Skills (from agent-skills + claude-plugin) ---
SkillEntry {
name: "dd-onboarding",
description: "Datadog Agentic Onboarding. Guides installation and setup of the Datadog Agent, APM, logs, integrations, and cloud environments via an AI-driven workflow.",
entry_type: "skill",
content: include_str!("../skills/dd-onboarding/SKILL.md"),
platform: "",
files: &[],
},
SkillEntry {
name: "dd-pup",
description: "Datadog CLI (pup). OAuth2 auth with token refresh.",
Expand Down
Loading