Service twin · API + UI
Datadog
Test observability and on-call agents that manage monitors, dashboards, events, metrics, logs, SLOs, downtimes, incidents, synthetics tests, and notebooks.
$ uv tool install --with "blobfish-sdk @ https://blobfish.ai/sdk/blobfish_sdk-0.6.2-py3-none-any.whl" "blobfish-cli @ https://blobfish.ai/sdk/blobfish_cli-0.1.13-py3-none-any.whl"
$ blobfish login
$ blobfish twin-runs create --twins datadog --ttl 60 --waitWhat’s inside
A deterministic, seeded, resettable replica: every operation below executes real state transitions against the twin’s own SQLite state — reads are hash-invariant, writes produce inspectable diffs, and reset restores the seed baseline.
Seeded entities
| Entity | Table | Fields | About |
|---|---|---|---|
| dashboard | dashboards | 19 | A dashboard (v1 Dashboard object): title, layout_type and widgets are required, as in the vendor schema. |
| dashboard_list | dashboard_lists | 8 | A manual dashboard list (v1 DashboardList object). |
| downtime | downtimes | 14 | A downtime (v2 JSON:API resource, modeled flat: id, type + attributes). Cancel is a guarded status transition to `canceled`, as the vendor keeps canceled downtimes listable. |
| event | events | 21 | An event (v1 Event object; v2 event reads add message/timestamp flat). v1 and v2 event operations share this table. |
| incident | incidents | 31 | An incident (v2 JSON:API resource, modeled flat: id, type + attributes; create/update bodies are the request's attributes object). |
| incident_impact | incident_impacts | 10 | An incident impact (v2 JSON:API resource, modeled flat; incident_id is taken from the URL). |
| incident_todo | incident_todos | 9 | An incident todo (v2 JSON:API resource, modeled flat; incident_id references the incident). |
| incident_type | incident_types | 11 | An incident type (v2 JSON:API resource, modeled flat: id, type + attributes). |
| log | logs | 12 | A log line: the v2 intake item (ddsource, ddtags, hostname, message, service) plus the searchable log attributes (host, status, tags, timestamp), modeled flat. |
| logs_archive | logs_archives | 12 | A logs archive (v2 JSON:API resource, modeled flat: id, type + attributes). |
| logs_metric | logs_metrics | 5 | A log-based metric (v2 JSON:API resource, modeled flat: id, type + attributes). |
| logs_pipeline | logs_pipelines | 9 | A logs processing pipeline (v1 LogsPipeline object). |
| metric | metrics | 11 | A submitted metric series (v2 MetricSeries / v1 Series): one row per submitted series; the query endpoints search these rows and the v1/v2 metrics listings (`GET /api/v1/metrics`, `GET /api/v2/metrics`) are served from them. Per-metric-name metadata and tag-configuration writes are not modeled. |
| monitor | monitors | 18 | A monitor (v1 Monitor object): type + query define the check; options/tags/priority as in the vendor schema. type is enum-checked on write; priority is declared 1..5 (seeds stay in range) but not enforced on write. The server-computed per-group `state` object is not modeled (the twin evaluates no monitor queries), so reads carry no `state` key. |
| monitor_config_policy | monitor_config_policies | 4 | Monitor configuration policy (v2 JSON:API resource, modeled flat: id, type + attributes). |
| monitor_notification_rule | monitor_notification_rules | 9 | Monitor notification rule (v2 JSON:API resource, modeled flat: id, type + attributes). |
| notebook | notebooks | 11 | A notebook (v1 JSON:API resource, modeled flat: id, type + attributes; create/update bodies are the request's attributes object). |
| service_check | service_checks | 7 | A submitted service check run (v1 ServiceCheck object), one row per submitted check. |
| shared_dashboard | shared_dashboards | 18 | A public (shared) dashboard link (v1 SharedDashboard object), keyed by its share token. |
| slo | slos | 17 | A service level objective (v1 ServiceLevelObjective object). |
| slo_correction | slo_corrections | 15 | An SLO status correction (v1 JSON:API resource, modeled flat: id, type + attributes; slo_id references the SLO). |
| synthetics_global_variable | synthetics_global_variables | 10 | A synthetics global variable (v1 SyntheticsGlobalVariable object). |
| synthetics_location | synthetics_locations | 2 | A synthetics managed location (v1 SyntheticsLocation object). |
| synthetics_private_location | synthetics_private_locations | 6 | A synthetics private location (v1 SyntheticsPrivateLocation object). |
| synthetics_test | synthetics_tests | 13 | A synthetics test (v1 SyntheticsTestDetails, API and browser variants merged), keyed by public_id. Bulk delete, trigger runs and the pause toggle are not modeled. |
| synthetics_test_result | synthetics_test_results | 8 | A synthetics API test result (v1 result objects), keyed by result_id; public_id is taken from the URL. |
Guarded lifecycles
These state machines are enforced, not decorative: an action whose from state doesn’t match is rejected the way the production service rejects it.
downtime.status
cancel: scheduled|active → canceled
Three surfaces, one state
Mount Datadog in a twin environment and the same seeded state serves vendor-shaped REST operations, an MCP endpoint for tool calling, and a generated bf-twin CLI — with copy-on-write sessions per rollout and a one-call reset to the seed baseline. Prefer raw HTTP? The same create works with curl:
$ curl -sS -X POST https://blobfish.ai/api/v1/twin/environments \
-H "X-API-Key: $BLOBFISH_API_KEY" -H "Content-Type: application/json" \
-d '{"services":["datadog"],"ttl_minutes":60}'Known limitations
Spec-grounded surface with synthetic seeded values; operations outside the spec are not mounted.