CtrlK
BlogDocsLog inGet started
Tessl Logo

juicebox-upgrade-migration

Plan Juicebox SDK upgrades. Trigger: "upgrade juicebox", "juicebox migration".

56

Quality

48%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Advisory

Suggest reviewing before use

Optimize this skill with Tessl

npx tessl skill review --optimize ./plugins/saas-packs/juicebox-pack/skills/juicebox-upgrade-migration/SKILL.md
SKILL.md
Quality
Evals
Security

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

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

// 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

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 IssueSymptomFix
Search filter syntax changed400 Bad Request with invalid filter operatorUpdate filter syntax to new query DSL format
Dataset schema mismatchImport succeeds but columns mapped incorrectlyRe-map dataset columns using /datasets/schema endpoint
Profile field restructuredCode crashes accessing result.name (now result.profile.full_name)Update all property access paths to new nested structure
Analysis format changedAI analysis output missing expected sectionsUpdate parser for new structured analysis response
Rate limit reduced429 Too Many Requests on previously working batch sizesReduce batch size and implement request queuing

Resources

  • Juicebox Changelog
  • Juicebox API Documentation

Next Steps

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

Repository
jeremylongshore/claude-code-plugins-plus-skills
Last updated
Created

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.