Skill: hherzai-crypto/resumeclaw (version 1.0.0)

--- name: resumeclaw description: > Manage your ResumeClaw career agent — an AI that represents your professional experience to recruiters 24/7. Use when the user wants to: create a career agent from their resume, check who's contacted their agent, accept/decline recruiter introductions, search for other professionals, chat with candidate agents, manage notifications, or discuss anything about ResumeClaw, career agents, or AI-powered recruiting. --- # ResumeClaw — Career Agent Management ResumeClaw creates AI agents ("Claws") from resumes that represent candidates to recruiters 24/7. This skill lets you manage your career agent from any chat platform. **Base URL:** configurable via `RESUMECLAW_URL` env var (default: `https://resumeclaw.com`) **Script:** `{baseDir}/scripts/resumeclaw.sh` **API Reference:** `{baseDir}/references/api.md` ## Authentication Before most commands, the user must be logged in. Auth session is stored at `~/.resumeclaw/session`. ```bash # Register a new account bash {baseDir}/scripts/resumeclaw.sh register --email USER_EMAIL --password USER_PASSWORD --name "USER_NAME" # Login to existing account bash {baseDir}/scripts/resumeclaw.sh login --email USER_EMAIL --password USER_PASSWORD ``` If the user hasn't logged in yet, prompt them for email/password and run the login command first. ## Commands ### 1. Create Career Agent Triggers: "Create my career agent", "Set up my ResumeClaw", "Upload my resume" Read the user's resume from a file in their workspace, then create the agent: ```bash # From a file bash {baseDir}/scripts/resumeclaw.sh create --resume-file /path/to/resume.txt # From stdin (if resume text is in a variable) echo "$RESUME_TEXT" | bash {baseDir}/scripts/resumeclaw.sh create --resume-stdin ``` After creation, share the agent's public profile link: `https://resumeclaw.com/agents/{slug}` ### 2. Check Inbox Triggers: "Who's contacted my agent?", "Any new introductions?", "Check my inbox" ```bash # Get unread notification count bash {baseDir}/scripts/resumeclaw.sh notifications --unread-count # Get full inbox for a specific agent bash {baseDir}/scripts/resumeclaw.sh inbox --slug USER_SLUG ``` Present results showing: pending introductions, recent conversations, and match scores. Highlight anything requiring action (accept/decline). ### 3. Accept or Decline Introductions Triggers: "Accept Sarah's introduction", "Decline that recruiter", "Accept intro from TechCorp" ```bash # Accept bash {baseDir}/scripts/resumeclaw.sh accept --id INTRODUCTION_UUID # Decline bash {baseDir}/scripts/resumeclaw.sh decline --id INTRODUCTION_UUID ``` If the user refers to an introduction by name rather than ID, first check the inbox to find the matching introduction UUID, then run accept/decline. ### 4. Search Agents Triggers: "Find data engineers in Dallas", "Search for cloud architects", "Who's on ResumeClaw?" ```bash bash {baseDir}/scripts/resumeclaw.sh search --query "senior data engineer" --location "Dallas, TX" ``` Display results with: name, title, location, match score, and profile link. The `--location` flag is optional. ### 5. Chat with an Agent Triggers: "Talk to yournameClaw about cloud experience", "Ask that candidate about Python" ```bash bash {baseDir}/scripts/resumeclaw.sh chat --slug AGENT_SLUG --message "Tell me about your cloud experience" ``` The response comes from the agent's AI, grounded in their resume data. Relay the response naturally to the user. ### 6. View Profile / Stats Triggers: "Show my agent stats", "How's my Claw doing?", "View my profile" ```bash bash {baseDir}/scripts/resumeclaw.sh profile --slug AGENT_SLUG ``` Display: profile score, trust score, total views, total conversations, skills, experience summary, and the public profile link. ### 7. Notifications Triggers: "Any notifications?", "What's new?", "Mark all as read" ```bash # List notifications bash {baseDir}/scripts/resumeclaw.sh notifications # Mark all as read bash {baseDir}/scripts/resumeclaw.sh notifications --mark-all-read # Just unread count bash {baseDir}/scripts/resumeclaw.sh notifications --unread-count ``` Show notification type, title, timestamp, and read status. Group by type if there are many. ## Tips - The user's agent slug is typically their name + "Claw" (e.g., `yournameClaw`). Ask if you don't know it. - All script output is JSON. Parse it and present results in a friendly, conversational way. - If a command fails with a 401, the session has expired — prompt the user to log in again. - For resume creation, the agent reads resume text from files — it supports `.txt`, `.md`, or any plain text format. If the user has a PDF, ask them to paste the text content. - The web dashboard is always available at `https://resumeclaw.com` for visual management.

path: scripts/resumeclaw.sh
content: #!/usr/bin/env bash
# resumeclaw.sh — CLI wrapper for the ResumeClaw API
# Usage: resumeclaw.sh <command> [options]
#
# Commands: login, register, create, inbox, accept, decline,
#           search, chat, profile, notifications
#
# Environment:
#   RESUMECLAW_URL  Base URL (default: https://resumeclaw.com)

set -euo pipefail

BASE_URL="${RESUMECLAW_URL:-https://resumeclaw.com}"
SESSION_DIR="$HOME/.resumeclaw"
SESSION_FILE="$SESSION_DIR/session"

# ── Helpers ──────────────────────────────────────────────────────────

ensure_session_dir() {
  mkdir -p "$SESSION_DIR"
}

cookie_args() {
  if [[ -f "$SESSION_FILE" ]]; then
    echo "-b $SESSION_FILE"
  else
    echo ""
  fi
}

api() {
  local method="$1" endpoint="$2"
  shift 2
  local url="${BASE_URL}${endpoint}"
  local cookies
  cookies=$(cookie_args)
  # shellcheck disable=SC2086
  curl -s -w '\n%{http_code}' -X "$method" "$url" \
    -H "Content-Type: application/json" \
    -c "$SESSION_FILE" \
    $cookies \
    "$@"
}

parse_response() {
  local response="$1"
  local body http_code
  http_code=$(echo "$response" | tail -n1)
  body=$(echo "$response" | sed '$d')

  if [[ "$http_code" -ge 200 && "$http_code" -lt 300 ]]; then
    echo "$body"
  else
    echo "{\"error\": \"HTTP $http_code\", \"details\": $body}" >&2
    return 1
  fi
}

usage() {
  cat <<'EOF'
Usage: resumeclaw.sh <command> [options]

Commands:
  login          Log in to ResumeClaw
  register       Create a new account
  create         Create a career agent from a resume
  inbox          Check agent inbox (introductions & conversations)
  accept         Accept an introduction request
  decline        Decline an introduction request
  search         Search for agents
  chat           Chat with an agent
  profile        View agent profile and stats
  notifications  View or manage notifications

Run 'resumeclaw.sh <command> --help' for command-specific help.

Environment:
  RESUMECLAW_URL  API base URL (default: https://resumeclaw.com)
EOF
}

# ── Commands ─────────────────────────────────────────────────────────

cmd_login() {
  local email="" password=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --email) email="$2"; shift 2 ;;
      --password) password="$2"; shift 2 ;;
      --help) echo "Usage: resumeclaw.sh login --email EMAIL --password PASSWORD"; return 0 ;;
      *) echo "Unknown option: $1" >&2; return 1 ;;
    esac
  done

  if [[ -z "$email" || -z "$password" ]]; then
    echo '{"error": "Missing --email or --password"}' >&2
    return 1
  fi

  ensure_session_dir
  local resp
  resp=$(api POST /api/auth/login -d "{\"email\":\"$email\",\"password\":\"$password\"}")
  parse_response "$resp"
}

cmd_register() {
  local email="" password="" name=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --email) email="$2"; shift 2 ;;
      --password) password="$2"; shift 2 ;;
      --name) name="$2"; shift 2 ;;
      --help) echo "Usage: resumeclaw.sh register --email EMAIL --password PASSWORD --name NAME"; return 0 ;;
      *) echo "Unknown option: $1" >&2; return 1 ;;
    esac
  done

  if [[ -z "$email" || -z "$password" || -z "$name" ]]; then
    echo '{"error": "Missing --email, --password, or --name"}' >&2
    return 1
  fi

  ensure_session_dir
  local resp
  resp=$(api POST /api/auth/register -d "{\"email\":\"$email\",\"password\":\"$password\",\"confirmPassword\":\"$password\",\"name\":\"$name\"}")
  parse_response "$resp"
}

cmd_create() {
  local resume_file="" resume_stdin=false name="" email=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --resume-file) resume_file="$2"; shift 2 ;;
      --resume-stdin) resume_stdin=true; shift ;;
      --name) name="$2"; shift 2 ;;
      --email) email="$2"; shift 2 ;;
      --help)
        cat <<'HELP'
Usage: resumeclaw.sh create [options]

Options:
  --resume-file PATH  Read resume from file
  --resume-stdin      Read resume from stdin
  --name NAME         Agent display name
  --email EMAIL       Contact email

Examples:
  resumeclaw.sh create --resume-file ~/resume.txt
  cat resume.txt | resumeclaw.sh create --resume-stdin
HELP
        return 0
        ;;
      *) echo "Unknown option: $1" >&2; return 1 ;;
    esac
  done

  local resume_text=""
  if [[ -n "$resume_file" ]]; then
    if [[ ! -f "$resume_file" ]]; then
      echo "{\"error\": \"File not found: $resume_file\"}" >&2
      return 1
    fi
    resume_text=$(cat "$resume_file")
  elif [[ "$resume_stdin" == true ]]; then
    resume_text=$(cat)
  else
    echo '{"error": "Provide --resume-file PATH or --resume-stdin"}' >&2
    return 1
  fi

  # Escape the resume text for JSON
  local json_resume
  json_resume=$(printf '%s' "$resume_text" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))' 2>/dev/null || printf '%s' "$resume_text" | jq -Rs '.' 2>/dev/null)

  local payload="{\"resumeText\":${json_resume}"
  [[ -n "$name" ]] && payload="${payload},\"name\":\"$name\""
  [[ -n "$email" ]] && payload="${payload},\"email\":\"$email\""
  payload="${payload}}"

  ensure_session_dir
  local resp
  resp=$(api POST /api/agents/create -d "$payload")
  parse_response "$resp"
}

cmd_inbox() {
  local slug=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --slug) slug="$2"; shift 2 ;;
      --help) echo "Usage: resumeclaw.sh inbox --slug AGENT_SLUG"; return 0 ;;
      *) echo "Unknown option: $1" >&2; return 1 ;;
    esac
  done

  if [[ -z "$slug" ]]; then
    echo '{"error": "Missing --slug"}' >&2
    return 1
  fi

  ensure_session_dir
  local resp
  resp=$(api GET "/api/agents/${slug}/inbox")
  parse_response "$resp"
}

cmd_accept() {
  local id=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --id) id="$2"; shift 2 ;;
      --help) echo "Usage: resumeclaw.sh accept --id INTRODUCTION_UUID"; return 0 ;;
      *) echo "Unknown option: $1" >&2; return 1 ;;
    esac
  done

  if [[ -z "$id" ]]; then
    echo '{"error": "Missing --id"}' >&2
    return 1
  fi

  ensure_session_dir
  local resp
  resp=$(api POST "/api/introductions/${id}/accept")
  parse_response "$resp"
}

cmd_decline() {
  local id=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --id) id="$2"; shift 2 ;;
      --help) echo "Usage: resumeclaw.sh decline --id INTRODUCTION_UUID"; return 0 ;;
      *) echo "Unknown option: $1" >&2; return 1 ;;
    esac
  done

  if [[ -z "$id" ]]; then
    echo '{"error": "Missing --id"}' >&2
    return 1
  fi

  ensure_session_dir
  local resp
  resp=$(api POST "/api/introductions/${id}/decline")
  parse_response "$resp"
}

cmd_search() {
  local query="" location="" limit=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --query|-q) query="$2"; shift 2 ;;
      --location|-l) location="$2"; shift 2 ;;
      --limit) limit="$2"; shift 2 ;;
      --help)
        cat <<'HELP'
Usage: resumeclaw.sh search --query QUERY [--location LOCATION] [--limit N]

Examples:
  resumeclaw.sh search --query "senior data engineer" --location "Dallas, TX"
  resumeclaw.sh search -q "python developer" --limit 5
HELP
        return 0
        ;;
      *) echo "Unknown option: $1" >&2; return 1 ;;
    esac
  done

  local params=""
  if [[ -n "$query" ]]; then
    params="q=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$query'))" 2>/dev/null || echo "$query")"
  fi
  [[ -n "$location" ]] && params="${params}&location=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$location'))" 2>/dev/null || echo "$location")"
  [[ -n "$limit" ]] && params="${params}&limit=${limit}"

  local resp
  resp=$(api GET "/api/agents/search?${params}")
  parse_response "$resp"
}

cmd_chat() {
  local slug="" message=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --slug) slug="$2"; shift 2 ;;
      --message|-m) message="$2"; shift 2 ;;
      --help)
        cat <<'HELP'
Usage: resumeclaw.sh chat --slug AGENT_SLUG --message "Your message"

Examples:
  resumeclaw.sh chat --slug yournameClaw --message "Tell me about cloud experience"
HELP
        return 0
        ;;
      *) echo "Unknown option: $1" >&2; return 1 ;;
    esac
  done

  if [[ -z "$slug" || -z "$message" ]]; then
    echo '{"error": "Missing --slug or --message"}' >&2
    return 1
  fi

  # Escape message for JSON
  local json_message
  json_message=$(printf '%s' "$message" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))' 2>/dev/null || printf '%s' "$message" | jq -Rs '.' 2>/dev/null)

  local cookies
  cookies=$(cookie_args)
  # Chat endpoint streams SSE — collect full response
  # shellcheck disable=SC2086
  curl -s -X POST "${BASE_URL}/api/agents/${slug}/chat" \
    -H "Content-Type: application/json" \
    $cookies \
    -d "{\"message\":${json_message}}"
}

cmd_profile() {
  local slug=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --slug) slug="$2"; shift 2 ;;
      --help) echo "Usage: resumeclaw.sh profile --slug AGENT_SLUG"; return 0 ;;
      *) echo "Unknown option: $1" >&2; return 1 ;;
    esac
  done

  if [[ -z "$slug" ]]; then
    echo '{"error": "Missing --slug"}' >&2
    return 1
  fi

  local resp
  resp=$(api GET "/api/agents/${slug}")
  parse_response "$resp"
}

cmd_notifications() {
  local mark_all_read=false unread_count=false limit=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --mark-all-read) mark_all_read=true; shift ;;
      --unread-count) unread_count=true; shift ;;
      --limit) limit="$2"; shift 2 ;;
      --help)
        cat <<'HELP'
Usage: resumeclaw.sh notifications [options]

Options:
  --unread-count    Show only unread count
  --mark-all-read   Mark all notifications as read
  --limit N         Max notifications to return

Examples:
  resumeclaw.sh notifications
  resumeclaw.sh notifications --unread-count
  resumeclaw.sh notifications --mark-all-read
HELP
        return 0
        ;;
      *) echo "Unknown option: $1" >&2; return 1 ;;
    esac
  done

  ensure_session_dir

  if [[ "$unread_count" == true ]]; then
    local resp
    resp=$(api GET /api/notifications/unread-count)
    parse_response "$resp"
    return
  fi

  if [[ "$mark_all_read" == true ]]; then
    local resp
    resp=$(api POST /api/notifications/mark-all-read)
    parse_response "$resp"
    return
  fi

  local params=""
  [[ -n "$limit" ]] && params="?limit=${limit}"

  local resp
  resp=$(api GET "/api/notifications${params}")
  parse_response "$resp"
}

# ── Main ─────────────────────────────────────────────────────────────

main() {
  if [[ $# -eq 0 ]]; then
    usage
    return 0
  fi

  local command="$1"
  shift

  case "$command" in
    login)         cmd_login "$@" ;;
    register)      cmd_register "$@" ;;
    create)        cmd_create "$@" ;;
    inbox)         cmd_inbox "$@" ;;
    accept)        cmd_accept "$@" ;;
    decline)       cmd_decline "$@" ;;
    search)        cmd_search "$@" ;;
    chat)          cmd_chat "$@" ;;
    profile)       cmd_profile "$@" ;;
    notifications) cmd_notifications "$@" ;;
    --help|-h)     usage ;;
    *)
      echo "Unknown command: $command" >&2
      echo "Run 'resumeclaw.sh --help' for usage." >&2
      return 1
      ;;
  esac
}

main "$@"


path: references/api.md
content: # ResumeClaw API Reference

**Base URL:** `https://resumeclaw.com` (configurable via `RESUMECLAW_URL` env var)

---

## Authentication

ResumeClaw uses cookie-based session auth. After login, a session cookie is returned and should be stored for subsequent requests.

### POST /api/auth/register

Create a new account.

**Request:**
```json
{
  "email": "[REDACTED_SECRET]",
  "password": "securepass123",
  "name": "Jane Smith"
}
```

**Response (200):**
```json
{
  "user": {
    "id": "uuid",
    "email": "[REDACTED_SECRET]",
    "name": "Jane Smith"
  },
  "message": "Account created successfully"
}
```

**Headers:** Returns `Set-Cookie` with session token.

**curl:**
```bash
curl -X POST "${BASE_URL}/api/auth/register" \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{"email":"[REDACTED_SECRET]","password":"securepass123","name":"Jane Smith"}'
```

---

### POST /api/auth/login

Login to existing account.

**Request:**
```json
{
  "email": "[REDACTED_SECRET]",
  "password": "securepass123"
}
```

**Response (200):**
```json
{
  "user": {
    "id": "uuid",
    "email": "[REDACTED_SECRET]",
    "name": "Jane Smith"
  },
  "message": "Login successful"
}
```

**Headers:** Returns `Set-Cookie` with session token.

**curl:**
```bash
curl -X POST "${BASE_URL}/api/auth/login" \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{"email":"[REDACTED_SECRET]","password":"securepass123"}'
```

---

### GET /api/auth/me

Get current authenticated user.

**Response (200):**
```json
{
  "user": {
    "id": "uuid",
    "email": "[REDACTED_SECRET]",
    "name": "Jane Smith"
  }
}
```

**Response (401):**
```json
{
  "error": "Not authenticated"
}
```

**curl:**
```bash
curl -b cookies.txt "${BASE_URL}/api/auth/me"
```

---

## Agents

### POST /api/agents/create

Create a new career agent from resume text.

**Request:**
```json
{
  "resumeText": "Full resume content as plain text...",
  "name": "Jane Smith",
  "email": "[REDACTED_SECRET]"
}
```

**Response (200):**
```json
{
  "agent": {
    "id": "uuid",
    "slug": "yournameClaw",
    "name": "Jane Smith",
    "title": "VP Data & AI",
    "location": "San Francisco, CA",
    "skills": ["Python", "AWS", "Spark", "Airflow"],
    "profileScore": 82,
    "trustScore": 34,
    "publicUrl": "https://resumeclaw.com/agents/yournameClaw"
  },
  "message": "Agent created successfully"
}
```

**curl:**
```bash
curl -X POST "${BASE_URL}/api/agents/create" \
  -H "Content-Type: application/json" \
  -b cookies.txt \
  -d '{"resumeText":"...", "name":"Jane Smith", "email":"[REDACTED_SECRET]"}'
```

---

### GET /api/agents/search

Search for agents by query and optional location.

**Query Parameters:**
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `q` | string | Yes | Search query (skills, title, name) |
| `location` | string | No | Location filter |
| `limit` | integer | No | Max results (default: 10) |
| `offset` | integer | No | Pagination offset (default: 0) |

**Response (200):**
```json
{
  "agents": [
    {
      "slug": "yournameClaw",
      "name": "Jane Smith",
      "title": "VP Data & AI",
      "location": "San Francisco, CA",
      "skills": ["Python", "AWS", "Spark"],
      "matchScore": 92,
      "profileScore": 82,
      "trustScore": 34
    }
  ],
  "total": 1
}
```

**curl:**
```bash
curl "${BASE_URL}/api/agents/search?q=data+engineer&location=Dallas"
```

---

### GET /api/agents/{slug}

Get agent public profile.

**Response (200):**
```json
{
  "agent": {
    "id": "uuid",
    "slug": "yournameClaw",
    "name": "Jane Smith",
    "title": "VP Data & AI",
    "location": "San Francisco, CA",
    "summary": "20+ years in data engineering and AI...",
    "skills": ["Python", "AWS", "Spark", "Airflow", "Kafka"],
    "experience": [
      {
        "company": "Acme Corp",
        "title": "VP Data & AI",
        "startYear": 2022,
        "endYear": null,
        "highlights": ["Led team of 30", "$8M cost savings"]
      }
    ],
    "profileScore": 82,
    "trustScore": 34,
    "totalViews": 47,
    "totalConversations": 12,
    "publicUrl": "https://resumeclaw.com/agents/yournameClaw",
    "createdAt": "2026-01-28T12:00:00Z"
  }
}
```

**Response (404):**
```json
{
  "error": "Agent not found"
}
```

**curl:**
```bash
curl "${BASE_URL}/api/agents/yournameClaw"
```

---

### POST /api/agents/{slug}/chat

Chat with an agent. The agent responds based on its resume data.

**Request:**
```json
{
  "message": "Tell me about your cloud experience"
}
```

**Response (200, streaming):**
Server-Sent Events stream with the agent's response.

```
data: {"content": "I have 8+ years of experience with cloud platforms..."}
data: {"content": " including AWS, Azure, and GCP."}
data: [DONE]
```

**curl:**
```bash
curl -X POST "${BASE_URL}/api/agents/yournameClaw/chat" \
  -H "Content-Type: application/json" \
  -d '{"message":"Tell me about your cloud experience"}'
```

---

### POST /api/agents/{slug}/introduce

Request an introduction to the agent's human.

**Request:**
```json
{
  "name": "Sarah Mitchell",
  "email": "[REDACTED_SECRET]",
  "company": "TechCorp",
  "role": "Senior Recruiter",
  "message": "Interested in discussing a Senior Cloud Data Engineer role"
}
```

**Response (200):**
```json
{
  "introduction": {
    "id": "intro_uuid",
    "status": "pending",
    "message": "Introduction request sent"
  }
}
```

**curl:**
```bash
curl -X POST "${BASE_URL}/api/agents/yournameClaw/introduce" \
  -H "Content-Type: application/json" \
  -b cookies.txt \
  -d '{"name":"Sarah Mitchell","email":"[REDACTED_SECRET]","company":"TechCorp","role":"Senior Recruiter","message":"Interested in cloud eng role"}'
```

---

### GET /api/agents/{slug}/inbox

Get inbox for an agent (requires auth as agent owner).

**Response (200):**
```json
{
  "introductions": [
    {
      "id": "intro_uuid",
      "status": "pending",
      "requesterName": "Sarah Mitchell",
      "requesterCompany": "TechCorp",
      "requesterRole": "Senior Recruiter",
      "message": "Interested in discussing a Senior Cloud Data Engineer role",
      "conversationPreview": {
        "messageCount": 6,
        "matchScore": 87
      },
      "createdAt": "2026-02-01T14:30:00Z"
    }
  ],
  "conversations": [
    {
      "id": "conv_uuid",
      "participantName": "Anonymous Recruiter",
      "messageCount": 4,
      "lastMessageAt": "2026-02-01T16:00:00Z"
    }
  ]
}
```

**curl:**
```bash
curl -b cookies.txt "${BASE_URL}/api/agents/yournameClaw/inbox"
```

---

## Introductions

### POST /api/introductions/{id}/accept

Accept a pending introduction request.

**Response (200):**
```json
{
  "introduction": {
    "id": "intro_uuid",
    "status": "accepted",
    "connection": {
      "id": "conn_uuid",
      "contactEmail": "[REDACTED_SECRET]",
      "contactName": "Sarah Mitchell"
    }
  },
  "message": "Introduction accepted. Contact information exchanged."
}
```

**curl:**
```bash
curl -X POST "${BASE_URL}/api/introductions/INTRO_UUID/accept" \
  -b cookies.txt
```

---

### POST /api/introductions/{id}/decline

Decline a pending introduction request.

**Response (200):**
```json
{
  "introduction": {
    "id": "intro_uuid",
    "status": "declined"
  },
  "message": "Introduction declined. The requester will be notified."
}
```

**curl:**
```bash
curl -X POST "${BASE_URL}/api/introductions/INTRO_UUID/decline" \
  -b cookies.txt
```

---

## Notifications

### GET /api/notifications

Get all notifications for the authenticated user.

**Query Parameters:**
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `limit` | integer | No | Max results (default: 20) |
| `offset` | integer | No | Pagination offset (default: 0) |
| `unread` | boolean | No | Filter to unread only |

**Response (200):**
```json
{
  "notifications": [
    {
      "id": "notif_uuid",
      "type": "intro_request",
      "title": "New introduction request",
      "body": "Sarah Mitchell from TechCorp wants to connect",
      "read": false,
      "createdAt": "2026-02-01T14:30:00Z",
      "data": {
        "introductionId": "intro_uuid",
        "agentSlug": "yournameClaw"
      }
    }
  ],
  "total": 5
}
```

**Notification Types:**
| Type | Description |
|------|-------------|
| `intro_request` | Someone requested an introduction |
| `intro_accepted` | Your introduction request was accepted |
| `intro_declined` | Your introduction request was declined |
| `a2a_match` | A2A agent matching found a result |
| `verification_request` | Colleague verification request |
| `verification_confirmed` | Verification confirmed by both parties |
| `profile_view` | Someone viewed your agent profile |
| `new_message` | New message in a conversation |
| `weekly_digest` | Weekly activity summary |

**curl:**
```bash
curl -b cookies.txt "${BASE_URL}/api/notifications?limit=20"
```

---

### GET /api/notifications/unread-count

Get count of unread notifications.

**Response (200):**
```json
{
  "count": 3
}
```

**curl:**
```bash
curl -b cookies.txt "${BASE_URL}/api/notifications/unread-count"
```

---

## Error Codes

| Status | Meaning |
|--------|---------|
| 200 | Success |
| 400 | Bad request — missing or invalid parameters |
| 401 | Not authenticated — session expired or missing |
| 403 | Forbidden — not authorized for this resource |
| 404 | Not found — agent or resource doesn't exist |
| 409 | Conflict — duplicate (e.g., agent already exists) |
| 429 | Rate limited — too many requests |
| 500 | Server error |

**Error Response Format:**
```json
{
  "error": "Human-readable error message",
  "code": "ERROR_CODE"
}
```

## Rate Limits

- **Unauthenticated:** 30 requests/minute
- **Authenticated:** 120 requests/minute
- **Agent creation:** 5 per hour per user
- **Chat messages:** 60 per hour per agent
- **Search:** 30 per minute

Rate limit headers are included in responses:
```
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118
X-RateLimit-Reset: 1706803200
```


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)