Skip to content

AI Agents & AnomalyGuard

AnomalyGuard exposes a stable REST API and anomalyguard CLI so AI agents can discover filters, pull anomalies and aggregates, read comments context, and reuse LLM summaries — without opening the web UI.

This tutorial focuses on CLI-first agent integration (same endpoints as the API; one command ≈ one HTTP call).

Why agents use the CLI

Benefit Detail
Structured data Filters, anomalies, aggregates, series, comments — JSON payloads agents can reason over
Saved business views Reuse pinned / shared Filters instead of inventing ad-hoc queries
Optional prose Filter summarization endpoints for ready-made briefings
--json Machine-readable wrapper for reliable tool parsing
API keys Unattended auth — no interactive login in the agent runtime

Typical agent jobs: morning leadership brief, regional escalation triage, “explain this spike”, ticket drafting, or feeding another LLM with grounded anomaly context.

Prerequisites

  1. CLI matching your AnomalyGuard version — download from the UI or /api/cli/download/… (see How to use the CLI).
  2. API key with access to the data views the agent may read — create under API Keys (prefer User role + least-privilege data views).
  3. At least one saved filter (and ideally one with aggregation / summarization enabled) that the key can access.
export ANOMALYGUARD_BASE_URL="https://anomalyguard.contoso.com"
export ANOMALYGUARD_API_KEY="<agent-api-key>"

anomalyguard ping --json
anomalyguard access whoami --json

Never put the API key in the agent system prompt. Inject it only as an environment variable (or a secret store) available to the tool runner.

How an agent should call the CLI

Give the agent a shell / tool that can run anomalyguard … --json. Prefer:

  1. Always pass --json.
  2. Check statusCode (expect 200).
  3. Parse body as JSON (it is a string containing the API payload).
  4. Prefer saved filter IDs over free-form queries when a business view already exists.
  5. Cap context: use Top N on filters, or take only the first N rows from results before stuffing the LLM context window.

CLI JSON envelope:

{
  "statusCode": 200,
  "reasonPhrase": "OK",
  "body": "<raw response body as string>"
}

Example parse with jq:

anomalyguard filters list-little --json | jq '.body | fromjson'
ping / whoami
    → list filters (or pinned)
        → pick filter by name / comment
            → get summarization (if any)
            → OR anomalies / aggregates by-filter
                → optional: series-data / similar for one anomaly
                    → answer user / open ticket / notify
Step Command
Health anomalyguard ping --json
Identity & access anomalyguard access whoami --json
Data views anomalyguard access me-dataviews --json
Discover filters anomalyguard filters list-little --json or filters pinned --json
Filter definition anomalyguard filters get {id} --json
Anomalies anomalyguard anomalies by-filter {id} --json
Aggregates anomalyguard anomalies aggregates-by-filter {id} --json
Stored summary anomalyguard filters summarization {id} --json
Refresh summary anomalyguard filters refresh-summarization {id} --json
Series chart data anomalyguard anomalies series-data {anomalyId} --json
Similar anomalies anomalyguard anomalies similar {anomalyId} --json

End-to-end sample: morning brief agent

Goal. User asks: “What should leadership care about in sales this morning?”
The agent uses a pinned enterprise filter, prefers the stored AI summary, and falls back to top aggregates.

1. Bootstrap (ops / one-time)

export ANOMALYGUARD_BASE_URL="https://anomalyguard.contoso.com"
export ANOMALYGUARD_API_KEY="<agent-api-key>"

# Confirm CLI ↔ server
anomalyguard --version
anomalyguard ping --json

Create or reuse a filter (UI or CLI) such as Enterprise sales — last 7 days, enable aggregation + summarization, pin it. Note its id (example: 12).

2. Script the agent can run as a tool

#!/usr/bin/env bash
# tools/ag_morning_brief.sh — agent tool: morning brief for one filter
set -euo pipefail

FILTER_ID="${1:?Usage: $0 <filterId>}"

echo "== identity =="
anomalyguard access whoami --json | jq '{statusCode, body: (.body | fromjson)}'

echo "== filter =="
anomalyguard filters get "$FILTER_ID" --json | jq '.body | fromjson | {id, name, comment, timeRange, isAggregated, isSummarized}'

echo "== summarization (may be empty) =="
anomalyguard filters summarization "$FILTER_ID" --json | jq '.body | fromjson' || true

echo "== top aggregates =="
anomalyguard anomalies aggregates-by-filter "$FILTER_ID" --json \
  | jq '.body | fromjson | .[0:10] | map({start: .StartDateId, types: .AnomalyTypes, chg: .nChange, chgPct: .nChangePerc, share: .nSharePerc, common: .CommonCategories, different: .DifferentCategories})'

echo "== top anomalies (fallback detail) =="
anomalyguard anomalies by-filter "$FILTER_ID" --json \
  | jq '.body | fromjson | .[0:5] | map({id, date: .DateId, type: .AnomalyType, changePercent: .ChangePecent, share: .CategoryPercentageShare, categories: .Categories})'

Field names in body follow the API models; adjust the jq paths if your deployment returns slightly different casing. When unsure, dump one full object: jq '.body | fromjson | .[0]'.

3. Example agent system instructions

Paste something like this into the agent (Cursor, LangGraph, custom runner, etc.):

You are an AnomalyGuard analyst agent. You do not invent anomalies.
You only use data returned by the `anomalyguard` CLI (or REST API).

Environment already has ANOMALYGUARD_BASE_URL and ANOMALYGUARD_API_KEY.

Tools:
- Run shell: anomalyguard <args> --json
- Prefer filters list-little / pinned to find the right filter by name or comment.
- For leadership questions, prefer filters summarization {id}.
  If missing or stale, use anomalies aggregates-by-filter {id}, then by-filter.
- For “why did X move?”, take one anomaly id and call series-data / similar.
- Always cite filter id and key metrics (change %, share %, categories, date).
- If a matched comment says an event is expected, mark it as explained — do not escalate.
- Never print the API key. Never call admin-only commands unless explicitly allowed.

4. Example user turn → agent actions

User: Brief me on filter “Enterprise sales — last 7 days”.

Agent runs:

anomalyguard filters list-little --json
# → finds id 12

anomalyguard filters summarization 12 --json
# → if present, use as primary narrative

anomalyguard anomalies aggregates-by-filter 12 --json
# → verify top groups match the summary; drill if needed

Agent answers with: overview from summarization, 3–5 top aggregates (common/different), next steps, and which findings are already explained by comments.

5. Optional: refresh summary then notify

If the agent must force a fresh LLM brief (and global LLM setup is configured):

anomalyguard filters refresh-summarization 12 --json \
  | jq -r '.body | fromjson | .summarization // .Summarization // .'

Post the text to Slack / Teams / email with your own notifier. AnomalyGuard stores the summary on the filter; it does not send chat messages by itself.

6. Optional: Python helper for tool output

import json, os, subprocess

def ag(*args: str) -> dict:
    env = os.environ.copy()
    proc = subprocess.run(
        ["anomalyguard", *args, "--json"],
        check=True,
        capture_output=True,
        text=True,
        env=env,
    )
    envelope = json.loads(proc.stdout)
    if envelope.get("statusCode") != 200:
        raise RuntimeError(envelope)
    body = envelope.get("body")
    return json.loads(body) if isinstance(body, str) else body

filters = ag("filters", "list-little")
summary = ag("filters", "summarization", "12")
aggregates = ag("anomalies", "aggregates-by-filter", "12")

Discovering filters without hard-coding IDs

# Compact catalog for the agent
anomalyguard filters list-little --json | jq '.body | fromjson'

# What appears on Home for this identity
anomalyguard filters pinned --json | jq '.body | fromjson | map({id, name, comment})'

Match on name / comment (Home header text) so users can say “the Slovakia filter” without knowing numeric IDs.

Security checklist

  • Scope the API key to only the data views the agent needs (API Keys).
  • Prefer User keys for read/investigate agents; use Admin keys only for admin automation.
  • Keep secrets in the runtime env / vault — not in prompts, git, or chat logs.
  • Rotate keys with regenerate / revoke when an agent is decommissioned.
  • Log filter IDs and anomaly IDs in agent traces; avoid logging full series payloads if they contain sensitive volumes.
  • Keep a reliable backup of the external backend PostgreSQL database (filters, anomalies, comments, settings, and agent-consumed history live there — API/CLI access does not replace DB backup).