Skip to content
Back to skills

Juicebox Upgrade Migration

ASecurity

'Plan Juicebox SDK upgrades.

  • 2,719 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 21, 2026
ai-agentstypescriptbashtestingapidocumentation

Works with

  • claude code
  • cursor
  • cli
  • api

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned September 21, 2026

npx -y skills add jeremylongshore/claude-code-plugins-plus --skill juicebox-upgrade-migration --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Juicebox Upgrade Migration?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Juicebox Upgrade Migration
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jeremylongshore-juicebox-upgrade-migration-0dba666a/badge)](https://www.skillsdirectory.com/skills/jeremylongshore-juicebox-upgrade-migration-0dba666a)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: juicebox-upgrade-migration
description: 'Plan Juicebox SDK upgrades.

  Trigger: "upgrade juicebox", "juicebox migration".

  '
allowed-tools: Read, Write, Edit, Bash(npm:*)
version: 1.16.0
license: MIT
author: Jeremy Longshore <jeremy@intentsolutions.io>
tags:
- saas
- recruiting
- juicebox
compatibility: Designed for Claude Code
---
# Juicebox Upgrade & Migration

## Overview

Juicebox is an AI-powered people search and analysis platform used for recruiting and market research. The API provides endpoints for dataset management, people searches, and AI-generated analyses. Tracking API versions is essential because Juicebox evolves its search query syntax, dataset schema, and analysis output format — upgrading without testing can break saved search filters, corrupt dataset imports, and change the structure of AI-generated candidate profiles that downstream systems consume.

## Version Detection

```typescript
const JUICEBOX_BASE = "https://api.juicebox.work/v1";

async function detectJuiceboxVersion(apiKey: string): Promise<void> {
  const res = await fetch(`${JUICEBOX_BASE}/datasets`, {
    headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
  });
  const version = res.headers.get("x-juicebox-api-version") ?? "v1";
  console.log(`Juicebox API version: ${version}`);

  // Check for deprecated search parameters
  const searchRes = await fetch(`${JUICEBOX_BASE}/search`, {
    method: "POST",
    headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
    body: JSON.stringify({ query: "test", limit: 1 }),
  });
  const deprecation = searchRes.headers.get("x-deprecated-params");
  if (deprecation) console.warn(`Deprecated search params: ${deprecation}`);
}
```

## Migration Checklist

- [ ] Review Juicebox changelog for API breaking changes
- [ ] Audit codebase for hardcoded dataset field names
- [ ] Verify search query syntax — filter operators may have changed
- [ ] Check analysis output format for new or renamed fields
- [ ] Update dataset import schema if column mapping changed
- [ ] Test people search result structure (profile fields, enrichment data)
- [ ] Validate pagination — cursor-based vs. offset may have changed
- [ ] Update SDK version in `package.json` and verify type compatibility
- [ ] Check webhook payloads for analysis completion events
- [ ] Run integration tests with sample dataset to verify search quality

## Schema Migration

```typescript
// Juicebox search results evolved: flat profile → enriched profile with sources
interface OldSearchResult {
  id: string;
  name: string;
  title: string;
  company: string;
  email?: string;
  linkedin_url?: string;
}

interface NewSearchResult {
  id: string;
  profile: {
    full_name: string;
    current_title: string;
    current_company: { name: string; domain: string };
    emails: Array<{ address: string; type: "work" | "personal"; verified: boolean }>;
    social: { linkedin?: string; twitter?: string };
  };
  match_score: number;
  enrichment_sources: string[];
}

function migrateSearchResult(old: OldSearchResult): NewSearchResult {
  return {
    id: old.id,
    profile: {
      full_name: old.name,
      current_title: old.title,
      current_company: { name: old.company, domain: "" },
      emails: old.email ? [{ address: old.email, type: "work", verified: false }] : [],
      social: { linkedin: old.linkedin_url },
    },
    match_score: 0,
    enrichment_sources: [],
  };
}
```

## Rollback Strategy

```typescript
class JuiceboxClient {
  private currentVersion: "v1" | "v2";

  constructor(private apiKey: string, version: "v1" | "v2" = "v2") {
    this.currentVersion = version;
  }

  async search(query: string, filters?: Record<string, any>): Promise<any> {
    try {
      const res = await fetch(`https://api.juicebox.work/${this.currentVersion}/search`, {
        method: "POST",
        headers: { Authorization: `Bearer ${this.apiKey}`, "Content-Type": "application/json" },
        body: JSON.stringify({ query, filters }),
      });
      if (!res.ok) throw new Error(`Juicebox search ${res.status}`);
      return await res.json();
    } catch (err) {
      if (this.currentVersion === "v2") {
        console.warn("Falling back to Juicebox API v1");
        this.currentVersion = "v1";
        return this.search(query, filters);
      }
      throw err;
    }
  }
}
```

## Error Handling

| Migration Issue | Symptom | Fix |
|----------------|---------|-----|
| Search filter syntax changed | `400 Bad Request` with `invalid filter operator` | Update filter syntax to new query DSL format |
| Dataset schema mismatch | Import succeeds but columns mapped incorrectly | Re-map dataset columns using `/datasets/schema` endpoint |
| Profile field restructured | Code crashes accessing `result.name` (now `result.profile.full_name`) | Update all property access paths to new nested structure |
| Analysis format changed | AI analysis output missing expected sections | Update parser for new structured analysis response |
| Rate limit reduced | `429 Too Many Requests` on previously working batch sizes | Reduce batch size and implement request queuing |

## Prerequisites

- An approved change record, version inventory, synthetic sandbox dataset, source/destination allowlists, suppression controls, compatibility test plan, and tested rollback release.

## Instructions

1. Back up configuration metadata without copying records, then run the migration against synthetic fixtures in staging.
2. Validate schema, authorization, redaction, suppression, retention, and `contacts_exported=0`; reject unapproved sources or destinations.
3. Promote through a bounded canary only after owner approval; halt on drift and restore the prior version/configuration immediately.
4. Retain only a redacted migration receipt and delete staged fixtures and temporary access at completion.

## Output

Produce a migration receipt with versions, environment, fixture classification, compatibility results, suppression/no-export checks, canary outcome, approver, retention/deletion proof, and rollback reference. Exclude records, contacts, and secrets.

## Examples

`from=v2; to=v3; env=staging; fixture=synthetic; compatibility=pass; suppression=pass; contacts_exported=0; rollback=v2` supports a controlled promotion.

## Resources

- Juicebox Changelog
- Juicebox API Documentation

## Next Steps

For CI pipeline integration, see `juicebox-ci-integration`.

Files in this skill

  • SKILL.md6.3 KB
  • references/implementation-guide.md3.7 KB
  • references/implementation.md1.6 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.