# CLI Exports Implementation Plan

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** Add three export commands (`eval export`, `eval report`, `agents card`) and an `eval-analysis` skill to `@indemn/cli`, producing markdown dumps and branded PDFs identical to the Copilot Dashboard.

**Architecture:** Port React-PDF templates from `indemn-platform-v2/ui/src/components/report/` to run headlessly in Node.js. The CLI fetches data from existing APIs (Copilot Server + Evaluations Service) via the SDK, then renders locally. A new `src/report/` module contains the ported templates, brand assets, and a `generate.ts` driver that produces PDF buffers.

**Tech Stack:** TypeScript ESM, `@react-pdf/renderer` (headless Node.js PDF generation), `react` (JSX runtime — no DOM), Barlow font family, existing `IndemnClient` SDK.

**Design doc:** `operating-system/projects/jarvis-cli-mcp/artifacts/2026-03-13-cli-exports-design.md`

**Source templates:** `/Users/home/Repositories/indemn-platform-v2/ui/src/components/report/` (1,779 lines across 10 files)

**Target repo:** `/Users/home/Repositories/indemn-cli/` (main branch)

---

### Task 1: Add dependencies and configure JSX

**Files:**
- Modify: `/Users/home/Repositories/indemn-cli/package.json`
- Modify: `/Users/home/Repositories/indemn-cli/tsconfig.json`

**Step 1: Install react-pdf and react**

Run:
```bash
cd /Users/home/Repositories/indemn-cli && npm install @react-pdf/renderer react && npm install -D @types/react
```

Note: `react-dom` is NOT needed — react-pdf renders to buffers directly.

**Step 2: Add JSX config to tsconfig.json**

In `tsconfig.json`, add `"jsx": "react-jsx"` to `compilerOptions`:

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "outDir": "dist",
    "rootDir": "src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "jsx": "react-jsx"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "test"]
}
```

**Step 3: Add postbuild script for asset copying**

In `package.json`, add a `postbuild` script:

```json
"scripts": {
  "build": "tsc",
  "postbuild": "cp -r src/report/assets dist/report/assets",
  "dev": "tsx --watch src/cli/index.ts",
  "test": "vitest run",
  "test:watch": "vitest"
}
```

**Step 4: Verify build still works**

Run: `npm run build`
Expected: Clean compilation (no errors)

**Step 5: Commit**

```bash
git add package.json package-lock.json tsconfig.json
git commit -m "feat: add react-pdf dependencies and JSX config for PDF exports"
```

---

### Task 2: Bundle brand assets (fonts + logo)

**Files:**
- Create: `src/report/assets/fonts/Barlow-Regular.ttf`
- Create: `src/report/assets/fonts/Barlow-Medium.ttf`
- Create: `src/report/assets/fonts/Barlow-SemiBold.ttf`
- Create: `src/report/assets/fonts/Barlow-Bold.ttf`
- Create: `src/report/assets/Indemn_PrimaryLogo_Iris.png`

**Step 1: Copy font files from dashboard**

```bash
cd /Users/home/Repositories/indemn-cli
mkdir -p src/report/assets/fonts
cp /Users/home/Repositories/indemn-platform-v2/ui/public/fonts/Barlow-Regular.ttf src/report/assets/fonts/
cp /Users/home/Repositories/indemn-platform-v2/ui/public/fonts/Barlow-Medium.ttf src/report/assets/fonts/
cp /Users/home/Repositories/indemn-platform-v2/ui/public/fonts/Barlow-SemiBold.ttf src/report/assets/fonts/
cp /Users/home/Repositories/indemn-platform-v2/ui/public/fonts/Barlow-Bold.ttf src/report/assets/fonts/
```

**Step 2: Copy logo**

```bash
cp /Users/home/Repositories/indemn-platform-v2/ui/public/Indemn_PrimaryLogo_Iris.png src/report/assets/
```

**Step 3: Verify build copies assets**

```bash
npm run build
ls dist/report/assets/fonts/
ls dist/report/assets/Indemn_PrimaryLogo_Iris.png
```

Expected: All 4 font files and logo present in `dist/report/assets/`

**Step 4: Commit**

```bash
git add src/report/assets/
git commit -m "feat: bundle Barlow fonts and Indemn logo for PDF reports"
```

---

### Task 3: Port styles and scoring utilities

**Files:**
- Create: `src/report/styles.ts`
- Create: `src/report/scoring.ts`

**Step 1: Create styles.ts**

Port from `/Users/home/Repositories/indemn-platform-v2/ui/src/components/report/styles.ts`. Key changes:
- Replace `import.meta.env` / `window.location.origin` asset URL logic with local file path resolution using ESM `import.meta.url`
- Font registration uses absolute file paths to bundled `.ttf` files

```typescript
// src/report/styles.ts
import { Font, StyleSheet } from '@react-pdf/renderer';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';

const __dirname = dirname(fileURLToPath(import.meta.url));
const assetsDir = join(__dirname, 'assets');

// Register Barlow font family from bundled files
Font.register({
  family: 'Barlow',
  fonts: [
    { src: join(assetsDir, 'fonts', 'Barlow-Regular.ttf'), fontWeight: 400 },
    { src: join(assetsDir, 'fonts', 'Barlow-Medium.ttf'), fontWeight: 500 },
    { src: join(assetsDir, 'fonts', 'Barlow-SemiBold.ttf'), fontWeight: 600 },
    { src: join(assetsDir, 'fonts', 'Barlow-Bold.ttf'), fontWeight: 700 },
  ],
});

export const logoPath = join(assetsDir, 'Indemn_PrimaryLogo_Iris.png');

// Copy the entire `colors` object and `styles` StyleSheet from the dashboard file verbatim.
// Source: /Users/home/Repositories/indemn-platform-v2/ui/src/components/report/styles.ts lines 31-147
```

**Step 2: Create scoring.ts**

Port from `/Users/home/Repositories/indemn-platform-v2/ui/src/lib/scoring.ts`. Copy these functions verbatim — they are pure arithmetic with no browser dependencies:

- `SCORE_THRESHOLDS` constant
- `ScoreMetrics` interface
- `ScoreColor` type
- `getScoreColor()` (lines 192-197)
- `getScoreColorClasses()` (lines 202-212) — keep hex values, remove Tailwind classes
- `getScoreHexColor()` (lines 217-219)
- `getRunScoreMetrics()` (lines 69-107)
- `getRunCriteriaScore()` (lines 112-115)
- `getRunRubricScore()` (lines 120-123)
- `getResultsScoreMetrics()` (lines 139-157)
- `getAggregatePassRate()` (lines 166-183)

Remove all imports from `@/api/hooks/useEvaluations` and `@/components/evaluation/types`. Define the minimal types inline (the function signatures only need `EvaluationRun` and `EvaluationResult` shapes — use the existing types from `src/sdk/types.ts` or define compatible interfaces).

**Step 3: Verify build**

Run: `npm run build`
Expected: Clean compilation

**Step 4: Commit**

```bash
git add src/report/styles.ts src/report/scoring.ts
git commit -m "feat: port brand styles and scoring utilities for PDF reports"
```

---

### Task 4: Port agent card templates

**Files:**
- Create: `src/report/agent-card/cover.tsx`
- Create: `src/report/agent-card/document.tsx`
- Create: `src/report/agent-card/types.ts`

**Step 1: Create types.ts**

Define the `AgentCardData`, `AgentCardTool`, `AgentCardKnowledgeBase`, `AgentCardLLMConfig`, `AgentCardEvalRun` interfaces.

Copy from `/Users/home/Repositories/indemn-platform-v2/ui/src/components/report/AgentCardDocument.tsx` lines 9-72. For `LifecycleStage` and `V1Owner`, define inline:

```typescript
export type LifecycleStage = 'prototype' | 'beta' | 'published';

export interface V1Owner {
  firstname?: string;
  lastname?: string;
  email?: string;
}
```

**Step 2: Create cover.tsx**

Port from `/Users/home/Repositories/indemn-platform-v2/ui/src/components/report/AgentCardCover.tsx` (234 lines). Key changes:
- Replace `import { assetBaseUrl } from './styles'` → `import { logoPath } from '../styles.js'`
- Replace `const getLogoUrl = () => \`\${assetBaseUrl}/Indemn_PrimaryLogo_Iris.png\`` → use `logoPath` directly
- Replace `import { getScoreHexColor } from '@/lib/scoring'` → `import { getScoreHexColor } from '../scoring.js'`
- Replace `import type { LifecycleStage, V1Owner } from '@/types'` → `import type { LifecycleStage, V1Owner } from './types.js'`

**Step 3: Create document.tsx**

Port from `/Users/home/Repositories/indemn-platform-v2/ui/src/components/report/AgentCardDocument.tsx` (639 lines). This is the largest file — contains 7 page components (SystemPromptPage, ToolsPage, KnowledgeBasesPage, LLMConfigPage, EvaluationHistoryPage, MetadataPage) plus the main `AgentCardDocument`.

Key changes:
- Same import path fixes as cover.tsx
- Replace `import type { ComponentScores, ComponentScoreDetail } from '@/api/hooks/useEvaluations'` → define inline or import from `./types.js`

**Step 4: Verify build**

Run: `npm run build`
Expected: Clean compilation

**Step 5: Commit**

```bash
git add src/report/agent-card/
git commit -m "feat: port agent card PDF templates from dashboard"
```

---

### Task 5: Port eval report templates

**Files:**
- Create: `src/report/eval-report/types.ts`
- Create: `src/report/eval-report/cover.tsx` (V1 cover, 71 lines)
- Create: `src/report/eval-report/v2-cover.tsx` (V2 cover, 104 lines)
- Create: `src/report/eval-report/item-page.tsx` (V2 per-item, 212 lines)
- Create: `src/report/eval-report/matrix-page.tsx` (V1 matrix, 125 lines)
- Create: `src/report/eval-report/example-page.tsx` (V1 per-question, 122 lines)
- Create: `src/report/eval-report/document.tsx` (root document, 115 lines)

**Step 1: Create types.ts**

Define `MatrixData`, `MatrixRow`, `EvaluatorInfo`, `WeightConfig` interfaces needed for V1 reports. Also re-export `EvaluationResult` from SDK types for V2 reports.

Source: `/Users/home/Repositories/indemn-platform-v2/ui/src/components/evaluation/types.ts` — extract only the types referenced by the report components.

**Step 2: Port V2 components (covers + item page)**

These are the primary target — V2 is the current eval system:
- `v2-cover.tsx` from `EvalReportV2Cover.tsx` (104 lines)
- `item-page.tsx` from `EvalReportItemPage.tsx` (212 lines)

Key import changes:
- `@/lib/scoring` → `../scoring.js`
- `@/components/evaluation/types` → `./types.js`
- `./styles` → `../styles.js`

**Step 3: Port V1 components (cover, matrix, example)**

- `cover.tsx` from `EvalReportCover.tsx` (71 lines)
- `matrix-page.tsx` from `EvalReportMatrixPage.tsx` (125 lines)
- `example-page.tsx` from `EvalReportExamplePage.tsx` (122 lines)

Same import path changes.

**Step 4: Port document.tsx**

From `EvalReportDocument.tsx` (115 lines). This is the root component that selects V1 or V2 format.

Import `calculateWeightedScores` from `../scoring.js` (will be ported in Task 3 from `evaluation/utils.ts`).

Note: `calculateWeightedScores` lives in `/Users/home/Repositories/indemn-platform-v2/ui/src/components/evaluation/utils.ts`. Port it to `src/report/scoring.ts` alongside the other scoring functions.

**Step 5: Verify build**

Run: `npm run build`
Expected: Clean compilation

**Step 6: Commit**

```bash
git add src/report/eval-report/
git commit -m "feat: port eval report PDF templates (V1 matrix + V2 per-item)"
```

---

### Task 6: Create generate.ts — PDF rendering driver

**Files:**
- Create: `src/report/generate.ts`

**Step 1: Write the rendering driver**

This module provides two async functions that take data, render React-PDF components to a buffer, and write to disk:

```typescript
// src/report/generate.ts
import React from 'react';
import { renderToBuffer } from '@react-pdf/renderer';
import * as fs from 'fs';
import * as path from 'path';
import { AgentCardDocument } from './agent-card/document.js';
import { EvalReportDocument } from './eval-report/document.js';
import type { AgentCardData } from './agent-card/types.js';
import type { EvalReportData } from './eval-report/document.js';

function generateFilename(prefix: string, name: string, date: string, ext: string): string {
  const cleanName = name.replace(/[^a-zA-Z0-9\s]/g, '').replace(/\s+/g, '_');
  const cleanDate = date.replace(/[^a-zA-Z0-9]/g, '_');
  return `${prefix}_${cleanName}_${cleanDate}.${ext}`;
}

export async function generateAgentCardPDF(data: AgentCardData, outputPath?: string): Promise<string> {
  const filename = outputPath || generateFilename('Indemn_Agent_Card', data.name, data.generatedDate, 'pdf');
  const buffer = await renderToBuffer(
    React.createElement(AgentCardDocument, { data })
  );
  const resolvedPath = path.resolve(filename);
  fs.writeFileSync(resolvedPath, buffer);
  return resolvedPath;
}

export async function generateEvalReportPDF(data: EvalReportData, outputPath?: string): Promise<string> {
  const customerName = data.customerName;
  const filename = outputPath || generateFilename('Indemn_Evaluation', customerName, data.reportDate, 'pdf');
  const buffer = await renderToBuffer(
    React.createElement(EvalReportDocument, { data })
  );
  const resolvedPath = path.resolve(filename);
  fs.writeFileSync(resolvedPath, buffer);
  return resolvedPath;
}
```

**Step 2: Verify build**

Run: `npm run build`
Expected: Clean compilation

**Step 3: Smoke test**

Write a quick script to verify PDF generation works:

```bash
cd /Users/home/Repositories/indemn-cli
node -e "
import('./dist/report/generate.js').then(async ({ generateAgentCardPDF }) => {
  const path = await generateAgentCardPDF({
    id: 'test', name: 'Test Agent', channels: ['WEB'],
    tools: [], knowledge_bases: [], generatedDate: 'Mar 13, 2026',
  });
  console.log('Generated:', path);
  const fs = await import('fs');
  console.log('Size:', fs.statSync(path).size, 'bytes');
  fs.unlinkSync(path);
});
"
```

Expected: Generates a PDF file > 0 bytes, no errors.

**Step 4: Commit**

```bash
git add src/report/generate.ts
git commit -m "feat: PDF rendering driver — generates agent card and eval report PDFs"
```

---

### Task 7: Implement `indemn eval export` (markdown dump)

**Files:**
- Modify: `src/cli/eval.ts`

**Step 1: Add the export subcommand**

Add after the existing `eval list` command in `src/cli/eval.ts`:

```typescript
eval_
  .command('export')
  .argument('<run-id>', 'Evaluation run ID')
  .description('Export evaluation results as markdown')
  .option('--output <path>', 'Output file path')
  .action(async (runId: string, options) => {
    try {
      const client = new IndemnClient();
      const evalSdk = new EvalSDK(client);
      const rubricsSdk = new RubricsSDK(client);
      const testSetsSdk = new TestSetsSDK(client);
      const spinner = ora('Fetching evaluation data...').start();

      // Fetch all data in parallel
      const [run, results] = await Promise.all([
        evalSdk.getRunStatus(runId),
        evalSdk.getRunResults(runId),
      ]);

      // Fetch rubric, test set, bot context based on run data
      const [rubric, testSet, botContext] = await Promise.all([
        run.rubric_id ? rubricsSdk.getRubric(run.rubric_id) : null,
        run.test_set_id ? testSetsSdk.getTestSet(run.test_set_id) : null,
        evalSdk.getBotContext(run.agent_id),
      ]);

      spinner.text = 'Generating markdown...';

      const markdown = formatEvalMarkdown(run, results, rubric, testSet, botContext);
      const agentName = botContext?.bot_name || run.agent_id;
      const date = new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
      const defaultFilename = `Indemn_Evaluation_${agentName.replace(/[^a-zA-Z0-9\s]/g, '').replace(/\s+/g, '_')}_${date.replace(/[^a-zA-Z0-9]/g, '_')}.md`;

      const outputPath = path.resolve(options.output || defaultFilename);
      fs.writeFileSync(outputPath, markdown);

      spinner.stop();
      printSuccess(`Exported to ${outputPath}`);
    } catch (err: any) {
      printError(err.message || String(err));
      process.exit(1);
    }
  });
```

**Step 2: Write the `formatEvalMarkdown` function**

This is a pure function that takes the fetched data and returns a markdown string. Follow the format specified in the design doc (Section "Markdown Export Format"):

- Header with run ID, date, agent, model, pass rates, component scores
- Per test case: conversation turns, criteria scores table, rubric scores table
- Each test case separated by `---`

Add `import * as path from 'path'` at the top of `eval.ts` (already has `import * as fs`).

**Step 3: Test against real data**

```bash
npm run build
indemn eval export 2dff7636-296d-4da1-9b5a-145ee610c4b1
cat Indemn_Evaluation_*.md | head -40
```

Expected: Markdown file with run summary and per-item results.

**Step 4: Commit**

```bash
git add src/cli/eval.ts
git commit -m "feat: indemn eval export — markdown dump of evaluation results"
```

---

### Task 8: Implement `indemn eval report` (branded PDF)

**Files:**
- Modify: `src/cli/eval.ts`

**Step 1: Add the report subcommand**

```typescript
eval_
  .command('report')
  .argument('<run-id>', 'Evaluation run ID')
  .description('Generate branded evaluation report PDF')
  .option('--output <path>', 'Output file path')
  .action(async (runId: string, options) => {
    try {
      const client = new IndemnClient();
      const evalSdk = new EvalSDK(client);
      const spinner = ora('Fetching evaluation data...').start();

      const [run, results] = await Promise.all([
        evalSdk.getRunStatus(runId),
        evalSdk.getRunResults(runId),
      ]);

      const botContext = await evalSdk.getBotContext(run.agent_id);

      spinner.text = 'Generating PDF...';

      // Detect V1 vs V2 and build report data
      const isV2 = results.length > 0 && results[0].criteria_scores != null;
      const customerName = botContext?.organization_name || botContext?.bot_name || run.agent_id;
      const reportDate = new Date().toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' });

      let reportData: EvalReportData;
      if (isV2) {
        reportData = { customerName, reportDate, v2Results: results };
      } else {
        // V1: transform results into MatrixData
        // (implement transformToMatrixData in src/report/eval-report/transform.ts)
        reportData = { customerName, reportDate, matrixData: transformToMatrixData(results), weights: defaultWeights };
      }

      const outputPath = await generateEvalReportPDF(reportData, options.output);

      spinner.stop();
      printSuccess(`Report saved to ${outputPath}`);
    } catch (err: any) {
      printError(err.message || String(err));
      process.exit(1);
    }
  });
```

Import `generateEvalReportPDF` from `../report/generate.js` and the `EvalReportData` type.

**Step 2: If V1 support is needed, create transform.ts**

Create `src/report/eval-report/transform.ts` that converts raw V1 API results (with `scores` dict) into `MatrixData` format. If V1 is deferred, throw a clear error: "V1 report format not yet supported. Use eval export for markdown output."

**Step 3: Test against real V2 run**

```bash
npm run build
indemn eval report 2dff7636-296d-4da1-9b5a-145ee610c4b1
ls -la Indemn_Evaluation_*.pdf
```

Expected: PDF file generated, opens correctly, matches dashboard layout.

**Step 4: Commit**

```bash
git add src/cli/eval.ts src/report/
git commit -m "feat: indemn eval report — branded PDF evaluation report"
```

---

### Task 9: Implement `indemn agents card` (agent card PDF)

**Files:**
- Modify: `src/cli/agents.ts`

**Step 1: Add the card subcommand**

Add to the agents command group in `src/cli/agents.ts`:

```typescript
agents
  .command('card')
  .argument('<agent-id>', 'Agent ID')
  .description('Generate branded agent card PDF')
  .option('--output <path>', 'Output file path')
  .action(async (agentId: string, options) => {
    try {
      const client = new IndemnClient();
      const agentsSdk = new AgentsSDK(client);
      const evalSdk = new EvalSDK(client);
      const spinner = ora('Fetching agent data...').start();

      // Fetch agent details, config, and functions in parallel
      const [agent, config, functions] = await Promise.all([
        agentsSdk.getAgent(agentId),
        client.get(`/organization/:org_id/ai-studio/bots/${agentId}/configurations`),
        client.get(`/organization/:org_id/ai-studio/bots/${agentId}/functions`),
      ]);

      // Fetch recent eval runs
      let evalRuns: any[] = [];
      try {
        evalRuns = await evalSdk.listRuns(agentId);
      } catch { /* evals may not be available */ }

      spinner.text = 'Generating PDF...';

      // Map to AgentCardData
      const cardData = mapToAgentCardData(agent, config, functions, evalRuns);
      const outputPath = await generateAgentCardPDF(cardData, options.output);

      spinner.stop();
      printSuccess(`Agent card saved to ${outputPath}`);
    } catch (err: any) {
      printError(err.message || String(err));
      process.exit(1);
    }
  });
```

**Step 2: Write `mapToAgentCardData` helper**

Map Copilot Server V1 responses to `AgentCardData` interface. Reference the mapping table in the design doc:

- `tools`: map function `name` → `tool_name`, function display `name`
- `knowledge_bases`: from v2 bots response (includes `document_count`)
- `evaluationSummary`: sum criteria/rubric passed/total across completed runs
- `componentScores`: from latest completed run's `component_scores`
- `evaluationRuns`: map runs to `AgentCardEvalRun[]` with computed percentage scores
- `system_prompt`: from config's `ai_config.system_prompt`
- `llm_config`: from config's `ai_config` (provider, model, parameters)

**Step 3: Test against real agent**

```bash
npm run build
indemn agents card 69a40cea71552df0c6b680cb
ls -la Indemn_Agent_Card_*.pdf
```

Expected: Multi-page PDF with cover, system prompt, tools, KBs, LLM config, eval history (if any), metadata.

**Step 4: Commit**

```bash
git add src/cli/agents.ts
git commit -m "feat: indemn agents card — branded agent card PDF"
```

---

### Task 10: Add MCP tools for exports

**Files:**
- Modify: `src/mcp/tools.ts`

**Step 1: Add three export tools**

Add to the `registerTools` function in `src/mcp/tools.ts`:

1. `export_eval_markdown` — calls eval export logic, returns `{ file_path, file_name, file_type: 'markdown' }`
2. `export_eval_report` — calls eval report logic, returns `{ file_path, file_name, file_type: 'pdf' }`
3. `export_agent_card` — calls agent card logic, returns `{ file_path, file_name, file_type: 'pdf' }`

Each tool's input schema needs:
- `run_id` (string, required) for eval tools
- `agent_id` (string, required) for agent card
- `output_path` (string, optional) for all three

Extract the rendering logic from the CLI commands into shared functions (in `src/report/generate.ts` or a new `src/report/export.ts`) so both CLI and MCP can call them without duplication.

**Step 2: Verify tools register**

```bash
npm run build
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node dist/mcp/server.js 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); tools=[t['name'] for t in d['result']['tools']]; print(f'{len(tools)} tools'); [print(f'  {t}') for t in tools if 'export' in t or 'card' in t]"
```

Expected: 58 tools total, including `export_eval_markdown`, `export_eval_report`, `export_agent_card`.

**Step 3: Commit**

```bash
git add src/mcp/tools.ts src/report/
git commit -m "feat: MCP tools for eval export, eval report, and agent card"
```

---

### Task 11: Adapt eval-analysis skill for CLI

**Files:**
- Create: `skills/eval-analysis/SKILL.md`
- Create: `skills/eval-analysis/references/data-shapes.md`

**Step 1: Create SKILL.md**

Adapt from `/Users/home/Repositories/operating-system/.claude/worktrees/jarvis-cli-mcp/.claude/skills/eval-analysis/SKILL.md`. Key changes:

- Frontmatter: `allowed-tools: Bash(indemn *)`
- Replace all `curl` commands with `indemn` CLI equivalents:
  - `curl .../runs/{run_id}` → `indemn eval status <run-id> --json`
  - `curl .../runs/{run_id}/results` → `indemn eval results <run-id> --json`
  - `curl .../rubrics/{rubric_id}` → `indemn rubric get <rubric-id> --json`
  - `curl .../test-sets/{test_set_id}` → `indemn testset get <testset-id> --json`
  - `curl .../bots/{agent_id}/context` → `indemn eval bot-context <agent-id> --json`
  - `curl -X PUT .../test-sets/{id}` → `indemn testset update <id> --file updated.json`
  - `curl -X PUT .../rubrics/{id}` → `indemn rubric update <id> --file updated.json`
- Replace `python3 -m json.tool` with `--json` flag
- Remove OS-specific references (subagents, markdown-pdf skill, project artifacts)
- Update export section to reference `indemn eval export` and `indemn eval report`
- Keep the 7-step workflow, failure categories, and divergence analysis exactly as-is

**Step 2: Copy data-shapes.md**

```bash
cp /Users/home/Repositories/operating-system/.claude/worktrees/jarvis-cli-mcp/.claude/skills/eval-analysis/references/data-shapes.md skills/eval-analysis/references/data-shapes.md
```

Ship as-is — the API response shapes are identical.

**Step 3: Commit**

```bash
git add skills/eval-analysis/
git commit -m "feat: eval-analysis skill adapted for CLI (replaces curl with indemn commands)"
```

---

### Task 12: End-to-end testing and publish

**Files:**
- Modify: `package.json` (version bump)

**Step 1: Test all three commands against real dev data**

```bash
npm run build

# Eval export (markdown)
indemn eval export 2dff7636-296d-4da1-9b5a-145ee610c4b1
cat Indemn_Evaluation_*.md | head -50

# Eval report (PDF)
indemn eval report 2dff7636-296d-4da1-9b5a-145ee610c4b1
ls -la Indemn_Evaluation_*.pdf

# Agent card (PDF)
indemn agents card 69a40cea71552df0c6b680cb
ls -la Indemn_Agent_Card_*.pdf

# MCP tools
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node dist/mcp/server.js 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d['result']['tools']), 'tools')"
```

Expected:
- Markdown file with full eval data
- PDF eval report that matches dashboard output
- PDF agent card with all pages
- 58 MCP tools registered

**Step 2: Open the PDFs and visually verify**

```bash
open Indemn_Evaluation_*.pdf
open Indemn_Agent_Card_*.pdf
```

Verify: branded cover page, correct data, proper font rendering, all pages present.

**Step 3: Bump version**

In `package.json`, change `"version": "1.0.0"` to `"version": "1.1.0"`.

**Step 4: Clean up test files**

```bash
rm -f Indemn_Evaluation_*.md Indemn_Evaluation_*.pdf Indemn_Agent_Card_*.pdf
```

**Step 5: Commit and push**

```bash
git add -A
git commit -m "feat: CLI exports — eval markdown, eval report PDF, agent card PDF, eval-analysis skill"
git push
```

**Step 6: Publish to npm**

```bash
npm publish --access public
```

Note: You'll need npm auth. If using the granular token, set it first:
```bash
npm config set //registry.npmjs.org/:_authToken <token>
```

Expected: `@indemn/cli@1.1.0` published.

**Step 7: Verify install**

```bash
npm install -g @indemn/cli@1.1.0
indemn eval export --help
indemn eval report --help
indemn agents card --help
```

---

## Task Dependency Graph

```
Task 1 (deps + JSX config)
  └→ Task 2 (assets)
       └→ Task 3 (styles + scoring)
            ├→ Task 4 (agent card templates)
            └→ Task 5 (eval report templates)
                 └→ Task 6 (generate.ts driver)
                      ├→ Task 7 (eval export CLI)
                      ├→ Task 8 (eval report CLI)
                      ├→ Task 9 (agents card CLI)
                      └→ Task 10 (MCP tools)
Task 11 (eval-analysis skill) — independent, can run in parallel with Tasks 4-10
Task 12 (E2E test + publish) — after all others
```
