Y2 Elite workspaces are rolling out for teams
Y2Y2Docs

Use Y2 from the Command Line

Install the native Y2 harness, save an API key, and call Y2 from a terminal

Use Y2 Information Dominance for interactive agent work and one-off prompts. Use curl for reproducible API checks, pagination, exports, and JSON selection.

Install the native harness

The installer supports macOS and Linux on x86-64 and arm64. It downloads the matching release, verifies its SHA-256 checksum, and installs y2 under ~/.y2/bin by default.

The initial macOS CLI archives are SHA-256 verified native binaries, but they are not Developer ID signed or Apple notarized. The signed and notarized Apple release is intentionally deferred.

Terminal
export PATH="$HOME/.y2/bin:$PATH" && curl -fsSL https://y2.dev/harness/install.sh | sh

This one command makes y2 available in the current terminal and adds the same PATH entry to your detected shell profile for future terminals. Pass --no-modify-path to leave shell profiles unchanged. Verify the binary:

Terminal
export PATH="$HOME/.y2/bin:$PATH"
y2 --version

Pin an exact release when you need a reproducible install:

Terminal
export PATH="$HOME/.y2/bin:$PATH" && curl -fsSL https://y2.dev/harness/install.sh | sh -s -- v0.0.7

Upgrade an installed harness on the stable channel:

Terminal
y2 upgrade

Save a Y2 API key

Create a key with the agent:y2 scope. New API keys require a Pro or Elite workspace plan. y2 auth opens Y2 API Keys in your browser, prints the URL as a fallback, and securely prompts for the key:

Terminal
y2 auth

The harness stores the key in its supported local credential backend. Run y2 setup when you already have a key and want to enter it without opening the browser. For ephemeral shells and CI, set the key in the environment instead:

Terminal
export Y2_API_KEY="y2_..."

Keep the key out of shell history, logs, prompts, tool arguments, and browser bundles.

Run Agent Y2

Start an interactive session from the project you want the harness to use as its workspace:

Terminal
cd your-project
y2

Run one noninteractive prompt with y2 ask:

Terminal
y2 ask "Summarize the changes in this repository"

The CLI sends its local tool schemas through Agent Y2's isolated harness mode. It discovers applicable AGENTS.md files from the workspace root down to each target file, makes skills and subagents available to the model, and keeps file and command execution on your machine behind the configured permission policy. Y2's API returns tool calls; it does not execute the CLI's local tools on the server.

Agent Y2 is the default route. Inspect the active configuration and local preflight without printing the key:

Terminal
y2 status --json
y2 doctor

To use another OpenAI-compatible endpoint directly, provide its base URL, key, and model:

Terminal
export OPENAI_BASE_URL="https://your-provider.example/v1"
export OPENAI_API_KEY="your-provider-api-key"
export Y2_MODEL="your-model-id"
y2

OPENAI_BASE_URL may include /chat/completions; otherwise y2 appends it. See the Agent Y2 API guide for the default endpoint and streaming contract.

Use curl directly

You need curl and, for JSON processing, jq:

curl --version
jq --version
export Y2_API_KEY="y2_..."

New API keys require Pro or Elite. The key must carry the scope required by each operation.

Shell history, debug tracing, process listings, and CI output can expose secrets. Keep the key in the environment, quote variable expansions, and do not use set -x in credentialed scripts.

Create a reusable GET helper

y2.sh
#!/usr/bin/env bash
set -euo pipefail

: "${Y2_API_KEY:?Set Y2_API_KEY before running this script}"

y2_get() {
  local path="$1"
  curl --fail-with-body --silent --show-error \
    "https://api.y2.dev${path}" \
    --header "Authorization: Bearer $Y2_API_KEY" \
    --header "Accept: application/json"
}

y2_get "/api/v1/news/feeds" | jq '.meta'

The helper accepts origin-relative API paths such as /api/v1/news and /api/v2/incidents. That also makes it safe to pass a pagination link returned by Y2.

Discover News topics

List all current topic IDs and names:

y2_get "/api/v1/news/feeds" |
  jq -r '.data[] | [.id, .name, .groupLabel] | @tsv'

Then request a bounded page:

y2_get "/api/v1/news?topics=markets,macro&limit=10" |
  jq -r '.data[] | [
    .publishedAt,
    (.sentiment.label // "unknown"),
    .title,
    (.links.canonical // "")
  ] | @tsv'

Current News rows use title, summary, and nested sentiment fields. Use the feed directory instead of assuming an older crypto-only topic list.

Inspect profile and subscription IDs

GET /profiles returns paired resources. Print both IDs before scripting updates:

y2_get "/api/v1/profiles" |
  jq -r '.data[] | [
    .profile.id,
    .subscription.id,
    .profile.name,
    .subscription.delivery.method
  ] | @tsv'

Use prf_... for profile configuration and report filtering. Use sub_... when changing delivery.

Create a profile idempotently

profile_id=$(
  curl --fail-with-body --silent --show-error \
    "https://api.y2.dev/api/v1/profiles" \
    --request POST \
    --header "Authorization: Bearer $Y2_API_KEY" \
    --header "Content-Type: application/json" \
    --header "Idempotency-Key: supplier-risk-2026-07-21" \
    --data '{
      "name": "Critical Supplier Risk",
      "topic": "Monitor disruption affecting strategic semiconductor suppliers.",
      "frequency": "daily",
      "scheduleTimeOfDay": "08:00"
    }' |
    jq -r '.data.id'
)

printf '%s\n' "$profile_id"

The response ID is the profile's canonical prf_... ID. Reuse the same idempotency key only with the same request body.

Paginate every report for a profile

Y2 returns an opaque continuation link. Follow it unchanged:

export-report-index.sh
#!/usr/bin/env bash
set -euo pipefail

: "${Y2_API_KEY:?Set Y2_API_KEY}"
: "${PROFILE_ID:?Set PROFILE_ID to a prf_ ID}"

next="/api/v1/reports?profileId=$PROFILE_ID&limit=20"

while [ -n "$next" ]; do
  page=$(
    curl --fail-with-body --silent --show-error \
      "https://api.y2.dev${next}" \
      --header "Authorization: Bearer $Y2_API_KEY" \
      --header "Accept: application/json"
  )

  jq -r '.data[] | [.id, .publishedAt, (.summary // "")] | @tsv' <<<"$page"
  next=$(jq -r '.links.next // empty' <<<"$page")
done

Do not decode or edit the cursor. It is bound to the original filters and ordering.

Export one report as Markdown

: "${REPORT_ID:?Set REPORT_ID to an rpt_ ID}"

curl --fail-with-body --silent --show-error \
  "https://api.y2.dev/api/v1/reports/$REPORT_ID" \
  --header "Authorization: Bearer $Y2_API_KEY" \
  --header "Accept: text/markdown" \
  --output "$REPORT_ID.md"

The file contains the report body directly. It is not a JSON envelope.

Process NDJSON one row at a time

News and several list endpoints can return newline-delimited JSON:

curl --fail-with-body --silent --show-error --get \
  "https://api.y2.dev/api/v1/news" \
  --header "Authorization: Bearer $Y2_API_KEY" \
  --header "Accept: application/x-ndjson" \
  --data-urlencode "topics=cybersecurity" \
  --data-urlencode "limit=50" |
while IFS= read -r row; do
  jq -r '[.publishedAt, .title] | @tsv' <<<"$row"
done

For multi-page ingestion, also capture X-Y2-Next-Cursor from the response headers and send it as the next request's cursor value.

Capture status, headers, and errors

Use temporary files when a script needs to branch on HTTP status while retaining Problem Details:

body_file=$(mktemp)
headers_file=$(mktemp)
trap 'rm -f "$body_file" "$headers_file"' EXIT

status=$(
  curl --silent --show-error \
    --output "$body_file" \
    --dump-header "$headers_file" \
    --write-out '%{http_code}' \
    "https://api.y2.dev/api/v1/reports/not-a-report-id" \
    --header "Authorization: Bearer $Y2_API_KEY" \
    --header "Accept: application/json"
)

if [ "$status" -ge 400 ]; then
  jq '{status, code, detail, requestId}' "$body_file" >&2
  grep -i '^Retry-After:' "$headers_file" >&2 || true
  exit 1
fi

Log requestId, not credentials. Retry safe reads or idempotent writes only, and follow Retry-After on 429.

Call Intel v2

Intel paths use /api/v2 directly:

y2_get "/api/v2/incidents?limit=20" |
  jq -r '.data[] | [.id, .severity, .title] | @tsv'

Do not place /api/v1 before an Intel v2 path.

Know when curl is not enough

curl can inspect the initial 402 and PAYMENT-REQUIRED header, but it does not create an EIP-3009 signature by itself. Use an x402 v2-capable wallet client, then retry with the generated PAYMENT-SIGNATURE.