Install
$ agentstack add skill-ironbee-ai-ironbee-devtools-skills-backend-testing ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Backend Testing Skill
End-to-end backend verification with the IronBee Backend DevTools CLI. Drive requests, watch logs, and assert on database state — all in one session.
See the full CLI reference at [ironbee-backend-devtools-cli](../ironbee-backend-devtools-cli/SKILL.md). Domain-level docs: [request](../ironbee-backend-devtools-cli/references/request.md), [log](../ironbee-backend-devtools-cli/references/log.md), [db](../ironbee-backend-devtools-cli/references/db.md), [o11y](../ironbee-backend-devtools-cli/references/o11y.md).
When to Use
This skill activates when:
- User wants to test backend APIs over HTTP/1.1, HTTP/2, gRPC, GraphQL, or WebSocket
- User needs to assert on log lines that a request produced (file, Docker, or Kubernetes logs)
- User needs to verify that a request changed exactly the right database rows
- User wants to replay a captured
curlcommand or HAR entry - User needs to seed test fixtures and roll them back automatically
- User wants to correlate a request chain with a single W3C trace id
Core principle: correlate by trace id
Pin a trace id once on the session and every request automatically carries it. Then read your server logs filtered by that trace id — that's the cleanest agent-driven verification loop.
SESSION="--session-id e2e"
TRACE=$(ironbee-backend-devtools-cli $SESSION --json o11y new-trace-id | jq -r .traceId)
ironbee-backend-devtools-cli $SESSION request http --url "https://api.example.com/orders" --method POST --body '{"kind":"json","value":{"sku":"ABC"}}'
ironbee-backend-devtools-cli $SESSION --json log read --source app --pattern "$TRACE" --parse-json --select '["timestamp","level","msg","span_id"]'
Capabilities
HTTP / GraphQL / gRPC / WebSocket requests
# HTTP with JSON body
ironbee-backend-devtools-cli --json request http \
--url "https://api.example.com/orders" \
--method POST \
--body '{"kind":"json","value":{"sku":"ABC","qty":2}}'
# GraphQL
ironbee-backend-devtools-cli --json request graphql \
--url "https://api.example.com/graphql" \
--query 'mutation($s:String!){createOrder(sku:$s){id}}' \
--variables '{"s":"ABC"}'
# gRPC unary via .proto file
ironbee-backend-devtools-cli --json request grpc \
--target "api.example.com:443" \
--service "orders.v1.OrderService" \
--method "GetOrder" \
--proto-source '{"kind":"protoFile","path":"./protos/orders.proto"}' \
--request '{"orderId":"abc-123"}'
# WebSocket — multi-step (open / send / receive / close)
CONN=$(ironbee-backend-devtools-cli --json request websocket-open --url "wss://api.example.com/stream" | jq -r .connectionId)
ironbee-backend-devtools-cli request websocket-send --connection-id "$CONN" --data '{"kind":"json","value":{"subscribe":"orders"}}'
ironbee-backend-devtools-cli --json request websocket-receive --connection-id "$CONN" --max-count 50 --timeout-ms 5000
ironbee-backend-devtools-cli request websocket-close --connection-id "$CONN"
Session state: cookies, default headers, default gRPC metadata
# Pin auth on every call to api.example.com for this session
ironbee-backend-devtools-cli request set-default-headers \
--host "api.example.com" \
--headers '{"Authorization":"Bearer $TOKEN"}'
# Pin gRPC metadata for a specific target
ironbee-backend-devtools-cli request set-default-metadata \
--target "api.example.com:443" \
--metadata '{"x-tenant-id":"acme"}'
# Inspect / clear when needed
ironbee-backend-devtools-cli request list-default-headers
ironbee-backend-devtools-cli request list-cookies
ironbee-backend-devtools-cli request clear-cookies --domain "api.example.com"
Replay captured calls (curl or HAR)
ironbee-backend-devtools-cli --json request replay \
--source '{"kind":"curl","value":"curl -X POST https://api.example.com/orders -d ..."}' \
--overrides '{"headers":{"Authorization":"Bearer NEW"}}' \
--new-trace-id
Log capture: register → read or follow
# Point-in-time read with JSON filters
ironbee-backend-devtools-cli log register-source --name app --type file --path /var/log/app.log
ironbee-backend-devtools-cli --json log read --source app --tail 200 \
--level ERROR --parse-json --json-filter '{"span.kind":"server"}'
# Multi-line stack coalescing
ironbee-backend-devtools-cli --json log read --source app --pattern "TypeError" --coalesce true \
--context-before 2 --context-after 10
# Live follow during a request (drain after)
FOLLOW=$(ironbee-backend-devtools-cli --json log follow --source app --max-buffer-lines 1000 | jq -r .followId)
ironbee-backend-devtools-cli request http --url "https://api.example.com/orders" --method POST --body '{"kind":"json","value":{}}'
ironbee-backend-devtools-cli --json log get-followed --follow-id "$FOLLOW" --drain --pattern "trace_id="
ironbee-backend-devtools-cli log stop-follow --follow-id "$FOLLOW"
# Read across multiple sources (file + docker), interleaved by timestamp
ironbee-backend-devtools-cli log register-source --name api --type docker --container my-api
ironbee-backend-devtools-cli log register-source --name worker --type kubernetes --pod worker-0 --namespace prod
ironbee-backend-devtools-cli --json log read-multi --sources '["app","api","worker"]' --tail 500 --pattern "$TRACE"
Database verification: snapshot → request → snapshot → diff
# Prefer connection-string-env so the credential never enters the agent's context
ironbee-backend-devtools-cli db connect --name main --type postgres --connection-string-env DATABASE_URL
BEFORE=$(ironbee-backend-devtools-cli --json db snapshot \
--connection main --table orders --where "customer_id = $1" --params '["cust-1"]' | jq -r .snapshotId)
ironbee-backend-devtools-cli request http --url "https://api.example.com/orders" --method POST --body '{"kind":"json","value":{"customer_id":"cust-1"}}'
AFTER=$(ironbee-backend-devtools-cli --json db snapshot \
--connection main --table orders --where "customer_id = $1" --params '["cust-1"]' | jq -r .snapshotId)
ironbee-backend-devtools-cli --json db diff --from "$BEFORE" --to "$AFTER"
Database watch-changes (async writes)
WATCH=$(ironbee-backend-devtools-cli --json db watch-changes \
--connection main --table outbox --poll-interval-ms 500 | jq -r .watchId)
ironbee-backend-devtools-cli request http --url "https://api.example.com/orders" --method POST --body '{"kind":"json","value":{}}'
# Pull the latest diffs (each event = one poll cycle's added/removed/changed)
ironbee-backend-devtools-cli --json db get-changes --watch-id "$WATCH" --drain
Writable transactions: fixtures with auto-rollback
ironbee-backend-devtools-cli db connect --name main --type postgres --connection-string-env TEST_DATABASE_URL --allow-writes
ironbee-backend-devtools-cli db transaction-begin --connection main --writable
ironbee-backend-devtools-cli db seed --connection main --table users \
--rows '[{"id":"u1","email":"a@example.com"},{"id":"u2","email":"b@example.com"}]'
# ... run requests, take snapshots, assert ...
ironbee-backend-devtools-cli db transaction-rollback --connection main
Readonly probes: list-tables / describe-table / query
ironbee-backend-devtools-cli --json db list-tables --connection main
ironbee-backend-devtools-cli --json db describe-table --connection main --table orders
ironbee-backend-devtools-cli --json db query --connection main \
--sql "SELECT id, status FROM orders WHERE customer_id = \$1" --params '["cust-1"]'
Canonical flows
A. Log-correlated request → assertion
SESSION="--session-id flow-a"
# Pin trace id, register log source, start follower
TRACE=$(ironbee-backend-devtools-cli $SESSION --json o11y new-trace-id | jq -r .traceId)
ironbee-backend-devtools-cli $SESSION log register-source --name app --type file --path /var/log/app.log
FOLLOW=$(ironbee-backend-devtools-cli $SESSION --json log follow --source app --max-buffer-lines 2000 | jq -r .followId)
# Trigger the operation
ironbee-backend-devtools-cli $SESSION request http \
--url "https://api.example.com/orders" --method POST \
--body '{"kind":"json","value":{"sku":"ABC"}}'
# Drain just the lines tagged with our trace id
ironbee-backend-devtools-cli $SESSION --json log get-followed \
--follow-id "$FOLLOW" --drain --pattern "$TRACE" \
--parse-json --select '["timestamp","level","msg","error"]'
ironbee-backend-devtools-cli $SESSION log stop-follow --follow-id "$FOLLOW"
B. Database-correlated request → diff
SESSION="--session-id flow-b"
ironbee-backend-devtools-cli $SESSION db connect --name main --type postgres --connection-string-env DATABASE_URL
BEFORE=$(ironbee-backend-devtools-cli $SESSION --json db snapshot --connection main --table orders | jq -r .snapshotId)
ironbee-backend-devtools-cli $SESSION request http \
--url "https://api.example.com/orders" --method POST \
--body '{"kind":"json","value":{"sku":"ABC"}}'
AFTER=$(ironbee-backend-devtools-cli $SESSION --json db snapshot --connection main --table orders | jq -r .snapshotId)
ironbee-backend-devtools-cli $SESSION --json db diff --from "$BEFORE" --to "$AFTER"
C. Sandboxed fixture write inside a transaction
SESSION="--session-id flow-c"
ironbee-backend-devtools-cli $SESSION db connect --name test --type postgres \
--connection-string-env TEST_DATABASE_URL --allow-writes
ironbee-backend-devtools-cli $SESSION db transaction-begin --connection test --writable
ironbee-backend-devtools-cli $SESSION db seed --connection test --table customers \
--rows '[{"id":"cust-1","email":"a@example.com"}]'
# ... run requests / verifications that depend on the seeded row ...
# Always rollback unless you explicitly want to keep the rows
ironbee-backend-devtools-cli $SESSION db transaction-rollback --connection test
Best Practices
- Pin a trace id at the start of a flow —
o11y new-trace-idonce, then correlate logs / spans / db audit rows by it. - Treat 4xx / 5xx and non-OK gRPC as data, not errors. Only transport-level failures (DNS, TLS, timeout, abort) populate the
errorfield. - Prefer
--connection-string-envover inline credentials — the value stays inprocess.envand never enters the agent's context. - Default to readonly db access. Open with
--allow-writesonly when you need fixtures, and always wrap writes in a transaction you roll back. - Use the cookie jar for login flows. It's on by default — set credentials once and every subsequent request inherits the session.
- Pin host-scoped default headers (
request set-default-headers) for auth tokens instead of passing--headerson every call. - Set up log followers BEFORE the request so the buffer captures lines emitted during the call.
log get-followedanddb get-changesdrain by default; passing--drainis a no-op but harmless. To peek without clearing, call via MCP /run executewithdrain: false. - Snapshot just the affected rows with a tight
--whereclause — full-table snapshots are slow and noisy in the diff. - Compose flows in a scenario when you'll reuse them — see [scenario reference](../ironbee-backend-devtools-cli/references/scenario.md). Scenarios are platform-agnostic and work on the backend CLI too.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: ironbee-ai
- Source: ironbee-ai/ironbee-devtools-skills
- License: MIT
- Homepage: https://ironbee.ai/products/ironbee-devtools
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.