Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Configure Juicebox CI/CD. Trigger: "juicebox ci", "juicebox pipeline".
.claude/skills/jeremylongshore-juicebox-ci-integration/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-11 | ✗→✓ | ▲ Improved | 37% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 18% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 35% | 0% |
| case-04 | ✗→✓ | ▲ Improved | -18% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 33% | 0% |
Set up CI/CD for Juicebox AI data analysis integrations: run unit tests with mocked dataset and analysis responses on every PR, validate live API connectivity for data queries on merge to main. Juicebox provides AI-powered data exploration and visualization, so CI pipelines verify dataset upload logic, analysis execution, and result parsing workflows.
yaml# .github/workflows/juicebox-ci.yml name: Juicebox CI on: pull_request: paths: ['src/juicebox/**', 'tests/**'] push: branches: [main] jobs: unit-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '20' } - run: npm ci - run: npm test -- --reporter=verbose integration-tests: if: github.ref == 'refs/heads/main' needs: unit-tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '20' } - run: npm ci - run: npm run test:integration env: JUICEBOX_API_KEY: ${{ secrets.JUICEBOX_API_KEY }}
typescript// tests/juicebox-service.test.ts import { describe, it, expect, vi } from 'vitest'; import { analyzeDataset, getAnalysisResults } from '../src/juicebox-service'; vi.mock('../src/juicebox-client', () => ({ JuiceboxClient: vi.fn().mockImplementation(() => ({ createAnalysis: vi.fn().mockResolvedValue({ analysisId: 'ana_abc123', status: 'processing', datasetId: 'ds_xyz', }), getAnalysis: vi.fn().mockResolvedValue({ analysisId: 'ana_abc123', status: 'completed', results: { summary: 'Revenue increased 15% QoQ', charts: [{ type: 'bar', title: 'Revenue by Quarter' }], insights: ['Q4 drove majority of growth', 'APAC region outperformed'], }, }), listDatasets: vi.fn().mockResolvedValue({ datasets: [{ id: 'ds_xyz', name: 'Sales Data', rowCount: 50000 }], }), })), })); describe('Juicebox Service', () => { it('creates an analysis from dataset', async () => { const result = await analyzeDataset('ds_xyz', 'What drove revenue growth?'); expect(result.analysisId).toBe('ana_abc123'); expect(result.status).toBe('processing'); }); it('retrieves completed analysis with insights', async () => { const results = await getAnalysisResults('ana_abc123'); expect(results.status).toBe('completed'); expect(results.results.insights).toHaveLength(2); }); });
typescript// tests/integration/juicebox.integration.test.ts import { describe, it, expect } from 'vitest'; const hasKey = !!process.env.JUICEBOX_API_KEY; describe.skipIf(!hasKey)('Juicebox Live API', () => { it('lists available datasets', async () => { const res = await fetch('https://api.juicebox.ai/v1/datasets', { headers: { Authorization: `Bearer ${process.env.JUICEBOX_API_KEY}` }, }); expect(res.status).toBe(200); const body = await res.json(); expect(body).toHaveProperty('datasets'); }); });
| CI Issue | Cause | Fix | |----------|-------|-----| | 401 Unauthorized | Invalid API key | Regenerate at juicebox.ai account settings | | Analysis stuck on processing | Large dataset or complex query | Increase polling timeout to 120s | | Dataset not found (404) | Dataset ID changed or deleted | Use listDatasets to get a valid ID dynamically | | Rate limit (429) | Too many concurrent analyses | Queue analyses and limit to 2 parallel runs | | Empty insights array | Insufficient data for AI analysis | Ensure test dataset has 100+ rows with varied data |
See juicebox-deploy-integration.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-11 | fail→pass | 19,150 | 16,897 | -12% | 1 | 1 | 0% | 2,355 | 3,228 | +37% | 0 | 0 | — |
case-01 | fail→pass | 11,755 | 11,991 | +2% | 1 | 1 | 0% | 2,261 | 2,667 | +18% | 0 | 0 | — |
case-02 | fail→pass | 21,250 | 15,629 | -26% | 1 | 1 | 0% | 3,247 | 4,396 | +35% | 0 | 0 | — |
case-03 | fail→fail | 27,612 | 28,585 | +4% | 1 | 1 | 0% | 3,953 | 5,830 | +47% | 0 | 0 | — |
case-04 | fail→pass | 17,518 | 8,891 | -49% | 1 | 1 | 0% | 2,171 | 1,781 | -18% | 0 | 0 | — |
case-05 | fail→pass | 14,055 | 9,885 | -30% | 1 | 1 | 0% | 1,577 | 2,092 | +33% | 0 | 0 | — |
case-06 | fail→pass | 15,696 | 7,536 | -52% | 1 | 1 | 0% | 1,743 | 1,435 | -18% | 0 | 0 | — |
case-07 | fail→pass | 20,721 | 7,907 | -62% | 1 | 1 | 0% | 2,781 | 1,701 | -39% | 0 | 0 | — |
case-08 | pass→pass | 16,279 | 10,984 | -33% | 1 | 1 | 0% | 2,779 | 3,182 | +15% | 0 | 0 | — |
case-09 | fail→pass | 15,284 | 3,810 | -75% | 1 | 1 | 0% | 2,774 | 1,805 | -35% | 0 | 0 | — |
case-10 | pass→pass | 17,513 | 15,173 | -13% | 1 | 1 | 0% | 2,181 | 2,928 | +34% | 0 | 0 | — |
case-12 | fail→pass | 13,125 | 7,989 | -39% | 1 | 1 | 0% | 1,242 | 1,598 | +29% | 0 | 0 | — |
case-13 | fail→pass | 13,404 | 6,918 | -48% | 1 | 1 | 0% | 1,489 | 1,427 | -4% | 0 | 0 | — |
case-14 | fail→pass | 15,830 | 7,457 | -53% | 1 | 1 | 0% | 1,875 | 1,473 | -21% | 0 | 0 | — |
case-15 | fail→pass | 20,467 | 9,056 | -56% | 1 | 1 | 0% | 2,879 | 1,808 | -37% | 0 | 0 | — |
case-16 | fail→pass | 10,436 | 7,404 | -29% | 1 | 1 | 0% | 1,560 | 1,559 | -0% | 0 | 0 | — |
case-17 | fail→fail | 11,029 | 7,387 | -33% | 1 | 1 | 0% | 1,902 | 2,457 | +29% | 0 | 0 | — |
case-18 | fail→pass | 11,773 | 8,454 | -28% | 1 | 1 | 0% | 1,716 | 1,569 | -9% | 0 | 0 | — |
case-19 | fail→pass | 16,604 | 13,613 | -18% | 1 | 1 | 0% | 1,926 | 3,225 | +67% | 0 | 0 | — |
case-20 | fail→pass | 20,841 | 5,770 | -72% | 1 | 1 | 0% | 2,916 | 2,181 | -25% | 0 | 0 | — |
case-21 | pass→pass | 12,752 | 6,902 | -46% | 1 | 1 | 0% | 1,265 | 1,458 | +15% | 0 | 0 | — |
case-22 | fail→fail | 18,803 | 32,580 | +73% | 1 | 1 | 0% | 3,475 | 4,383 | +26% | 0 | 0 | — |
case-23 | pass→pass | 28,878 | 37,789 | +31% | 1 | 1 | 0% | 4,694 | 6,437 | +37% | 0 | 0 | — |
case-24 | pass→pass | 18,724 | 13,663 | -27% | 1 | 1 | 0% | 2,755 | 3,832 | +39% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted. The headline lift of +67 percentage points is the difference between those two pass rates over the 24 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.