Skip to content
Open
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
13 changes: 6 additions & 7 deletions skill/reference/axiom.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
# Axiom API Capabilities

Summary of all operations available via Axiom API with a personal access token (PAT).
Summary of all operations available via Axiom API.

**Base URL:** `https://api.axiom.co` (for all endpoints except ingestion)
**Ingest URL:** Use edge deployment domain (e.g., `https://us-east-1.aws.edge.axiom.co`)
**Base URL:** `https://api.axiom.co` (for management endpoints)
**Query & Ingest URL:** Use edge deployment domain (e.g., `https://us-east-1.aws.edge.axiom.co`)

**Authentication:**
- PAT: `Authorization: Bearer $PAT` + `x-axiom-org-id: $ORG_ID`
- API Token: `Authorization: Bearer $API_TOKEN`
- `Authorization: Bearer $API_TOKEN` — use an advanced API token with minimal privileges

---

## Querying

| Operation | Endpoint | Description |
|-----------|----------|-------------|
| Run APL query | `POST /v1/datasets/_apl?format=tabular` | Execute APL query with tabular output |
| Run APL query (legacy) | `POST /v1/datasets/_apl?format=legacy` | Execute APL query with legacy output |
| Run APL query (edge) | `POST /v1/query/_apl?format=tabular` | Execute APL query with tabular output |
| Run APL query (legacy) | `POST /v1/query/_apl?format=legacy` | Execute APL query with legacy output |
| Run query (legacy) | `POST /v1/datasets/{dataset_name}/query` | Legacy query endpoint with filter/aggregation model |

**Query parameters:** `apl`, `startTime`, `endTime`, `cursor`, `includeCursor`, `queryOptions`, `variables`
Expand Down
20 changes: 17 additions & 3 deletions skill/scripts/axiom-api
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
# Axiom API helper - uses unified config
# Usage: axiom-api <deployment> <method> <endpoint> [body]
# Examples:
# axiom-api dev POST "/v1/datasets/_apl?format=tabular" '{"apl": "..."}'
# axiom-api dev GET "/v1/datasets"
# axiom-api dev GET "/v1/datasets/my-dataset"

set -euo pipefail

Expand All @@ -20,8 +20,22 @@ fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
eval "$("$SCRIPT_DIR/config" axiom "$DEPLOYMENT")"

# edge URL for ingest endpoints
REQUEST_URL="$AXIOM_URL"

if [[ "$ENDPOINT" == /v1/ingest/* ]]; then
DATASET="${ENDPOINT#/v1/ingest/}"
DATASET="${DATASET%%[?/]*}"
if [[ -n "$DATASET" ]]; then
RESOLVED=$("$SCRIPT_DIR/resolve-url" "$DEPLOYMENT" "$DATASET" 2>/dev/null || true)
if [[ -n "$RESOLVED" && "$RESOLVED" != "$AXIOM_URL" ]]; then
REQUEST_URL="$RESOLVED"
fi
fi
fi

if [[ -n "$BODY" ]]; then
"$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" -d "$BODY" "${AXIOM_URL}${ENDPOINT}"
"$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" -d "$BODY" "${REQUEST_URL}${ENDPOINT}"
else
"$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" "${AXIOM_URL}${ENDPOINT}"
"$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" "${REQUEST_URL}${ENDPOINT}"
fi
2 changes: 1 addition & 1 deletion skill/scripts/axiom-link
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ fi
# Derive web UI URL from configured API URL
# Replace "api." with "app." in the domain
# Examples:
# https://api.axiom.co → https://app.axiom.co
# https://api.staging.axiom.co → https://app.staging.axiom.co
# https://api.dev.axiom.co → https://app.dev.axiom.co
# https://cloud.axiom.co → https://app.axiom.co
# https://api.axiom.co → https://app.axiom.co
if [[ "$URL" == *"cloud.axiom.co"* ]]; then
BASE_URL="https://app.axiom.co"
elif [[ "$URL" == https://api.* ]]; then
Expand Down
55 changes: 44 additions & 11 deletions skill/scripts/axiom-query
Original file line number Diff line number Diff line change
Expand Up @@ -141,28 +141,61 @@ PAYLOAD=$(jq -cn \
# shellcheck disable=SC1090
eval "$("$SCRIPT_DIR/config" axiom "$DEPLOYMENT")"

CACHE_DIR="${TMPDIR:-/tmp}/axiom-edge-cache"
REGIONS_CACHE="$CACHE_DIR/regions__${DEPLOYMENT}"
if [[ ! -f "$REGIONS_CACHE" ]]; then
if [[ "$AXIOM_URL" == *"cloud.axiom.co"* ]]; then
APP_URL="https://app.axiom.co"
else
APP_URL="${AXIOM_URL/api./app.}"
fi
REGIONS_JSON=$("$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X GET "${APP_URL}/api/internal/regions/axiom" 2>/dev/null) || true
if [[ -n "$REGIONS_JSON" ]]; then
mkdir -p "$CACHE_DIR"
echo "$REGIONS_JSON" > "$REGIONS_CACHE"
fi
fi

LAST_EDGE_CACHE="$CACHE_DIR/last-edge__${DEPLOYMENT}"
if [[ -f "$LAST_EDGE_CACHE" ]]; then
FIRST_EDGE=$(cat "$LAST_EDGE_CACHE")
elif [[ -f "$REGIONS_CACHE" ]]; then
FIRST_EDGE=$(jq -r '.axiom[] | select(.environmentDefault == true) | .domain // empty' "$REGIONS_CACHE" 2>/dev/null)
fi
EDGE_URLS="${FIRST_EDGE:-}"
if [[ -f "$REGIONS_CACHE" ]]; then
OTHER_URLS=$(jq -r '.axiom[].domain // empty' "$REGIONS_CACHE" 2>/dev/null | grep -v "^${FIRST_EDGE:-}$" || true)
EDGE_URLS="$EDGE_URLS
$OTHER_URLS"
fi

RESP_HEADERS=$(mktemp)
RESP_BODY=$(mktemp)
cleanup() {
rm -f "$RESP_HEADERS" "$RESP_BODY"
}
trap cleanup EXIT

# Execute query and pipe to formatter
HTTP_CODE=$(curl -sS -o "$RESP_BODY" -D "$RESP_HEADERS" -w "%{http_code}" \
-X POST "$AXIOM_URL/v1/datasets/_apl?format=tabular" \
-H "Authorization: Bearer $AXIOM_TOKEN" \
-H "X-Axiom-Org-Id: $AXIOM_ORG_ID" \
-H "Content-Type: application/json" \
-d "$PAYLOAD")
QUERY_OK=false
for QUERY_URL in $EDGE_URLS; do
HTTP_CODE=$(curl -sS -o "$RESP_BODY" -D "$RESP_HEADERS" -w "%{http_code}" \
-X POST "${QUERY_URL}/v1/query/_apl?format=tabular" \
-H "Authorization: Bearer $AXIOM_TOKEN" \
-H "X-Axiom-Org-Id: $AXIOM_ORG_ID" \
-H "Content-Type: application/json" \
-d "$PAYLOAD")
if [[ "$HTTP_CODE" -ge 200 && "$HTTP_CODE" -lt 300 ]]; then
echo "$QUERY_URL" > "$LAST_EDGE_CACHE"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Problem: Agents can run multiple queries concurrently. This would be a race condition, this would clobber that file. We need a different solution. Is there a backend endpoint that returns the canonical edge URL for each dataset in an org? We already run the discover-axiom script, it would be ideal for that script to not only output the dataset names but which region they are in. Then the model can use the right region in the queries. We'll need to add the region flag / argument to most axiom scripts. We'll need an eval for this.

QUERY_OK=true
break
fi
done

if [[ "$HTTP_CODE" -lt 200 || "$HTTP_CODE" -ge 300 ]]; then
if [[ "$QUERY_OK" != true ]]; then
msg=$(jq -r '.message // empty' "$RESP_BODY" 2>/dev/null)
trace=$(grep -i '^x-axiom-trace-id:' "$RESP_HEADERS" | tail -1 | awk '{print $2}' | tr -d '\r')
echo "error: ${msg:-http $HTTP_CODE}" >&2
if [[ -n "$trace" ]]; then
echo "trace_id: $trace" >&2
fi
[[ -n "${trace:-}" ]] && echo "trace_id: $trace" >&2
exit 1
fi

Expand Down
99 changes: 99 additions & 0 deletions skill/scripts/resolve-url
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/usr/bin/env bash
# resolve-url: Resolve the regional edge URL for a dataset
#
# Usage: resolve-url <deployment> <dataset>
#
# Two-step resolution:
# 1. GET /v1/datasets → find dataset's region (e.g. cloud.us-east-1.aws)
# 2. GET /api/internal/regions/axiom → map region to edge domain
#
# Both steps are cached to avoid repeated API calls.

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

DEPLOYMENT="${1:-}"
DATASET="${2:-}"

if [[ -z "$DEPLOYMENT" || -z "$DATASET" ]]; then
echo "Usage: resolve-url <deployment> <dataset>" >&2
exit 1
fi

CACHE_DIR="${TMPDIR:-/tmp}/axiom-edge-cache"

# Check dataset edge URL cache (valid for 1 hour)
DATASET_CACHE="$CACHE_DIR/edge__${DEPLOYMENT}__${DATASET}"
if [[ -f "$DATASET_CACHE" ]]; then
if [[ "$(uname)" == "Darwin" ]]; then
AGE=$(( $(date +%s) - $(stat -f %m "$DATASET_CACHE") ))
else
AGE=$(( $(date +%s) - $(stat -c %Y "$DATASET_CACHE") ))
fi
if [[ $AGE -lt 3600 ]]; then
cat "$DATASET_CACHE"
exit 0
fi
fi

eval "$("$SCRIPT_DIR/config" axiom "$DEPLOYMENT")"

# Step 1: get dataset region
REGION=$("$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X GET "${AXIOM_URL}/v1/datasets" \
| jq -r --arg name "$DATASET" '.[] | select(.name == $name) | .edgeDeployment // .region // empty' 2>/dev/null)

if [[ -z "$REGION" || "$REGION" == "null" ]]; then
mkdir -p "$CACHE_DIR"
echo "$AXIOM_URL" > "$DATASET_CACHE"
echo "$AXIOM_URL"
exit 0
fi

# Step 2: look up edge domain from regions API (cached 24h per deployment)
REGIONS_CACHE="$CACHE_DIR/regions__${DEPLOYMENT}"
REGIONS_JSON=""
if [[ -f "$REGIONS_CACHE" ]]; then
if [[ "$(uname)" == "Darwin" ]]; then
AGE=$(( $(date +%s) - $(stat -f %m "$REGIONS_CACHE") ))
else
AGE=$(( $(date +%s) - $(stat -c %Y "$REGIONS_CACHE") ))
fi
if [[ $AGE -lt 86400 ]]; then
REGIONS_JSON=$(cat "$REGIONS_CACHE")
fi
fi

if [[ -z "$REGIONS_JSON" ]]; then
if [[ "$AXIOM_URL" == *"cloud.axiom.co"* ]]; then
APP_URL="https://app.axiom.co"
else
APP_URL="${AXIOM_URL/api./app.}"
fi
REGIONS_JSON=$("$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X GET "${APP_URL}/api/internal/regions/axiom" 2>/dev/null) || true
if [[ -n "$REGIONS_JSON" ]]; then
mkdir -p "$CACHE_DIR"
echo "$REGIONS_JSON" > "$REGIONS_CACHE"
fi
fi

EDGE_DOMAIN=""
if [[ -n "$REGIONS_JSON" ]]; then
EDGE_DOMAIN=$(echo "$REGIONS_JSON" | jq -r --arg region "$REGION" '.axiom[] | select(.id == $region) | .domain // empty' 2>/dev/null)
fi

if [[ -z "$EDGE_DOMAIN" ]]; then
mkdir -p "$CACHE_DIR"
echo "$AXIOM_URL" > "$DATASET_CACHE"
echo "$AXIOM_URL"
exit 0
fi

# Cache the resolved edge URL
mkdir -p "$CACHE_DIR"
if [[ "$EDGE_DOMAIN" != https://* ]]; then
EDGE_DOMAIN="https://${EDGE_DOMAIN}"
fi
echo "$EDGE_DOMAIN" > "$DATASET_CACHE"

echo "$EDGE_DOMAIN"
Loading