← Fastly Agent ToolkitCONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to Fastly Agent Toolkit
Snapshot Oct 9, 2026 · 18:03 UTC · version 0.1.0
Collection source: downloaded plugin package.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"description": "Fastly traffic numbers: cache hit ratio, bandwidth, request counts, status-code and error rates, edge vs origin traffic, real-time requests-per-second, origin latency, per-domain traffic, account usage and billing totals. Owns the `fastly stats` CLI commands and the Historical Stats, Real-Time and Origin/Domain Inspector HTTP APIs. Use for any question that needs a number about how a Fastly service is performing or how much it is being used.",
"included_files": [
{
"relative_path": "references/api.md",
"size_in_bytes": 13137
},
{
"relative_path": "references/debugging.md",
"size_in_bytes": 9494
},
{
"relative_path": "references/fields.md",
"size_in_bytes": 12449
}
],
"name": "fastly-stats",
"skill_md_contents": "---\nname: fastly-stats\ndescription: \"Fastly traffic numbers: cache hit ratio, bandwidth, request counts, status-code and error rates, edge vs origin traffic, real-time requests-per-second, origin latency, per-domain traffic, account usage and billing totals. Owns the `fastly stats` CLI commands and the Historical Stats, Real-Time and Origin/Domain Inspector HTTP APIs. Use for any question that needs a number about how a Fastly service is performing or how much it is being used.\"\n---\n\n# Fastly stats\n\nPrefer the `fastly` CLI. Drop to `curl` only for the seven things the CLI cannot do, listed under\nRaw API below.\n\nRequires the `fastly` CLI, `jq`, and network access to Fastly APIs; raw API examples also require `curl`.\nUse the user's locally configured authentication.\nIf authentication is missing, direct the user to a local CLI login or local `FASTLY_API_TOKEN` configuration, never to paste a key in chat.\nKeep tokens out of output and avoid shell tracing for authenticated commands.\n\n## Rules that decide whether the answer is right\n\n1. Bytes to GB is decimal SI: `bytes / 1e9`. TB is `/ 1e12`. Never `2^30`. Fastly bills in\n decimal units, so a GiB figure is wrong by 7.4% and still reads as a plausible number.\n2. For a calendar window, pass explicit UTC boundaries:\n `--from 2026-07-01T00:00:00Z --to 2026-08-01T00:00:00Z` returns every day bucket in July. A\n bucket is emitted only when the whole period falls inside the window, and a relative window\n opens and closes mid-bucket, so `--from \"N days ago\" --by day` returns N-1 buckets, never N,\n and `\"1 day ago\"` returns none at all. Relative strings are safe at `--by hour`, not at\n `--by day`.\n3. On the raw API, `from=yesterday` means 12:00:00 UTC, not midnight, and `from=today` means now.\n `N days ago` / `N hours ago` are exact offsets. Read back `meta.from` / `meta.to`.\n4. `hit_ratio`, `edge_hit_ratio` and `origin_offload` are gauges. Never sum or average them\n across buckets. Recompute from the summed counters: `hits / (hits + miss)`.\n5. `ts/h` on `rt.fastly.com` covers the last 120 seconds, not an hour, and returns only the seconds\n that carried traffic. Divide a rate by 120 there, or by the window you bounded when sampling\n with the CLI; never by the sample count or the `recorded` span. Print the window beside the rate.\n6. `fastly stats ... --json` emits NDJSON, one object per line, no array. Slurp with `jq -s`\n before aggregating. The raw HTTP API returns a normal array in `data`.\n7. Stats responses omit services with zero traffic in the window. Enumerate from\n `fastly service list --json` and default sums with `add // 0`.\n8. Do not read the newest bucket. Historical aggregation keeps growing for a few minutes after\n a period closes.\n9. On a Compute service the traffic lands in `compute_requests` and `requests` stays 0. Summing\n `requests` alone reports zero traffic for a service that is serving fine. Check both.\n10. Status codes split the same way. Use `all_status_*`, never bare `status_*` or\n `compute_resp_status_*`: `status_5xx` is 0 on Compute, `compute_resp_status_5xx` is absent on\n VCL, `all_status_5xx` is right on both. No `all_requests` exists, so denominators still need\n `requests + compute_requests`.\n\n## Pick the command\n\n| You need | Command |\n| ------------------------------------ | -------------------------------------------------------------------------- |\n| One service over a past window | `fastly stats historical -s ID --from T --to T --by day` |\n| One field only | `fastly stats historical -s ID --field bandwidth` |\n| All services, one row of totals | `fastly stats aggregate --from T --to T --by day` |\n| Account usage totals, by region | `fastly stats usage --from T --to T --json` |\n| Account usage split per service | `fastly stats usage --by-service --json` |\n| Valid region codes | `fastly stats regions` |\n| POP codes and shield names | `fastly pops` |\n| Is Inspector enabled on this service | `fastly products -s ID` |\n| Per-origin metrics, origin latency | `fastly stats origin-inspector -s ID --downsample hour --metric responses` |\n| Per-domain metrics | `fastly stats domain-inspector -s ID --downsample hour --group-by domain` |\n| Live per-second data | `fastly stats realtime -s ID --json` |\n\n`historical`, `aggregate` and `usage` take `--by minute|hour|day` and `--field`. The two\ninspectors take `--downsample` and `--metric` (repeatable) instead, plus `--group-by`,\n`--datacenter`, `--limit`, `--cursor`, and `--domain` or `--host`. Mixing the two vocabularies\nfails with a usage error. `historical` has no `--datacenter`; `realtime` takes no filters at all,\nand `regions` takes no flags whatsoever, not even `--json`. The documented `--metric` cap of 10 is\nnot enforced; 20 names in one call are accepted and echoed in `meta.metric`. Full flag matrix: the\n`fastly-cli` skill's stats reference.\n\nService-scoped subcommands take `-s` / `--service-id` or `--service-name`, falling back to\n`FASTLY_SERVICE_ID` then `fastly.toml`.\n\n## Worked answers\n\nCache hit ratio over a whole month, recomputed from counters rather than averaged:\n\n```bash\nfastly stats historical -s \"$SID\" --by day \\\n --from 2026-07-01T00:00:00Z --to 2026-08-01T00:00:00Z --json \\\n | jq -s '(map(.hits)|add // 0) as $h | (map(.miss)|add // 0) as $m\n | {hits:$h, miss:$m, hit_ratio: (if $h+$m > 0 then $h/($h+$m) else null end)}'\n```\n\n5xx count and share over a month, correct on both service types:\n\n```bash\nfastly stats historical -s \"$SID\" --by day \\\n --from 2026-07-01T00:00:00Z --to 2026-08-01T00:00:00Z --json \\\n | jq -s '{requests: (map((.requests // 0) + (.compute_requests // 0))|add // 0),\n status_5xx: (map(.all_status_5xx // 0)|add // 0)}\n | . + {pct: (if .requests > 0 then .status_5xx/.requests*100 else null end)}'\n```\n\nBandwidth in GB per service, ranked. Drive the loop from the service list, not from a stats\nresponse, so zero-traffic services are still counted:\n\n```bash\nfastly service list --json | jq -r '.[] | \"\\(.ServiceID)|\\(.Name)\"' | while IFS='|' read -r id name; do\n gb=$(fastly stats historical -s \"$id\" --by day \\\n --from 2026-07-01T00:00:00Z --to 2026-08-01T00:00:00Z --json \\\n | jq -s '([.[].bandwidth] | add // 0) / 1e9')\n printf '%.3f\\t%s\\n' \"$gb\" \"$name\"\ndone | sort -rn\n```\n\nAccount totals for a month. `fastly stats usage --json` returns one object keyed by region, so sum\nthe leaves. Dropping `compute_requests` here omits every Compute service from the total:\n\n```bash\nfastly stats usage --from 2026-07-01T00:00:00Z --to 2026-08-01T00:00:00Z --json \\\n | jq '{bandwidth_gb: (([.[].bandwidth]|add)/1e9),\n requests: ([.[] | .requests + .compute_requests]|add)}'\n```\n\n`billable_units=true` on `GET /stats/usage_by_month` rescales, it does not switch quantity:\n`bandwidth` / 1e9, `requests` and `compute_requests` / 10,000, so a `requests` of `1.4452` means\n14,452. For one month `/stats/usage`, the per-service `/stats` sum and `/stats/usage_by_month` all\nreport the same byte total, so a mismatch is an arithmetic bug, not a billing subtlety.\n\nLive request rate. `fastly stats realtime --json` streams one flat object per second,\n`{recorded, aggregated, datacenter}`, no `Data` wrapper and no `Timestamp`; those exist only on the\nraw `rt.fastly.com` payload. It prints nothing on a quiet service and never exits, so `head -n`\ndeadlocks. Bound it by wall clock and divide by that bound:\n\n```bash\nSECS=20\nOUT=$(mktemp)\nfastly stats realtime -s \"$SID\" --json > \"$OUT\" & P=$!\nsleep \"$SECS\"; kill \"$P\" 2>/dev/null; wait \"$P\" 2>/dev/null\njq -s --argjson w \"$SECS\" \\\n '{samples: length, window_s: $w,\n requests: (map((.aggregated.requests // 0) + (.aggregated.compute_requests // 0))|add // 0)}\n | . + {rps: (.requests / $w)}' \"$OUT\"\nrm -f \"$OUT\"\n```\n\nReport the window beside the rate. Do not derive it from `recorded` min/max: only seconds with\ntraffic are emitted, so on bursty traffic that span is a fraction of what you watched and the rate\ncomes out several times too high. Ratios and same-window comparisons survive a misjudged window;\nextrapolated rates do not.\n\nOne-shot alternative, returns immediately even with no data:\n`GET rt.fastly.com/v1/channel/{id}/ts/h`, the traffic-bearing seconds of the last 120.\n\n## Raw API\n\nSeven things the CLI cannot do. Everything else has a CLI command above.\n\n| Need | Request |\n| --------------------------------------- | -------------------------------------------------------------------------------- |\n| Per-POP history on classic stats | `GET api.fastly.com/stats/service/{id}?datacenter=SJC,LHR&by=day` |\n| Every service broken out in one call | `GET api.fastly.com/stats?from=T&to=T&by=day` |\n| One field across every service | `GET api.fastly.com/stats/field/{field}?from=T&to=T&by=day` |\n| Month-to-date billable usage | `GET api.fastly.com/stats/usage_by_month?year=2026&month=07&billable_units=true` |\n| POP `region` / `stats_region` fields | `GET api.fastly.com/datacenters` |\n| Live per-origin or per-domain data | `GET rt.fastly.com/v1/{origins,domains}/{id}/ts/0` |\n| 120 s per-POP snapshot in one call | `GET rt.fastly.com/v1/channel/{id}/ts/h` |\n\n`datacenter=` is absent from the CLI's SDK input type, not just its flags, so no flag combination\nreaches per-POP history. The two account-wide rows need `curl` because `stats historical` always\nresolves a service ID and errors without one; `fastly stats aggregate` is not a substitute, it sums\nevery service into one series instead of breaking them out.\n\nAuth is the header `Fastly-Key: <token>`.\nUse `fastly auth token` in a shell substitution to supply it directly from the CLI.\n\n```bash\ncurl -sS -H \"Fastly-Key: $(fastly auth token)\" \\\n \"https://api.fastly.com/stats/service/$SID?from=2026-07-01T00:00:00Z&to=2026-08-01T00:00:00Z&by=day&datacenter=SJC\"\n```\n\nNever run `fastly auth token` standalone in an agent session: captured stdout can bypass its terminal-output guard.\nDo not echo the token or pass `-v` on an authenticated curl call; both expose it in the transcript.\n\nEndpoint paths, parameters and response shapes: [references/api.md](references/api.md).\nField names and aggregation shape: [references/fields.md](references/fields.md).\nErrors, empty data and wrong-scope symptoms: [references/debugging.md](references/debugging.md).\n\n## Scope traps\n\n- `region=` takes `stats_region` values (`usa`, `europe`), not the `region` values from\n `/datacenters` (`US-East`, `North-America`). Get the live list from `fastly stats regions`.\n- `region=` is ignored on `/stats/usage` and `/stats/usage_by_service`: `meta` echoes it and all\n eleven regions come back, byte-identical to the unfiltered response. `fastly stats usage --region`\n filters client-side, so the CLI and the raw URL disagree. Filter usage responses yourself.\n- Sending `region` and `datacenter` together returns HTTP 200 with the POP filter dropped\n silently: `meta` echoes `region` and omits `datacenter` entirely, and the numbers are\n whole-region. Never send both, and assert `meta` carries the filter you sent.\n- POP codes are uppercase. A lowercase or unknown code fails loudly with `invalid datacenter`.\n- Origin and Domain Inspector are paid add-ons. When not enabled the endpoints return HTTP 200,\n `\"status\":\"success\"` and an empty `data` array, which reads exactly like a service with no\n traffic. Check `fastly products -s ID` before concluding there is nothing to see.\n- A shield POP's `datacenter` entry carries edge-to-shield traffic, not client traffic. Identify\n shields from the `SHIELD` column of `fastly pops` and label them separately.\n- When diagnosing rather than reporting, pull the per-POP breakdown. A healthy service-wide\n number routinely hides one POP erroring: `datacenter=` on classic stats, `--group-by datacenter`\n on the inspectors, the `datacenter` map in real-time.\n\n## Not this skill\n\nCreating or configuring services, backends, VCL or WAF: `fastly-cli` and `fastly`. Raw request\nlogs: stats are pre-aggregated counters, not log lines. NGWAF security events: `fastly-ngwaf`.\n"
}SHA-256 of public snapshot: dc34f9d16396e8b137120e4aa25c7a4c3ec26e1b37e61c8934c81e95e767fc50