# BankOps.ai — Claude Code Agent Instructions

You are building a professional presentation using the BankOps.ai platform. This document tells you everything you need to create, populate, inspect, and export a presentation via the API.

**Important**: Replace `{BASE_URL}` with the actual URL from the user's prompt (e.g. `https://staging.bankops.ai`). Replace `{TOKEN}` with the bearer token provided by the user.

## Authentication

Use `Authorization: Bearer {TOKEN}` on **every** API request.

```bash
AUTH="Authorization: Bearer {TOKEN}"
```

## 1. Create a Presentation

```bash
curl -X POST {BASE_URL}/api/presentations \
  -H "$AUTH" \
  -H "Content-Type: application/json" \
  -d '{"title": "My Presentation"}'
```

Returns: `{ "presentation": { "id": "...", ... } }`

Save the `id` as your `PRESENTATION_ID` for all subsequent requests.

## 2. Read / Update the Presentation

**Read** the current deck JSON:

```
GET {BASE_URL}/api/presentations/{PRESENTATION_ID}
Authorization: Bearer {TOKEN}
```

**Update** — full content replace:

```
PATCH {BASE_URL}/api/presentations/{PRESENTATION_ID}
Authorization: Bearer {TOKEN}
Content-Type: application/json

{ "content": <full deck JSON object> }
```

**Update** — partial edit via JSON Patch (preferred for edits):

```
PATCH {BASE_URL}/api/presentations/{PRESENTATION_ID}
Authorization: Bearer {TOKEN}
Content-Type: application/json

{ "patch": [<array of RFC 6902 operations>] }
```

JSON Patch details:
- `"patch"` and `"content"` are mutually exclusive — use one or the other.
- Operations: `add`, `remove`, `replace`, `move`, `copy`, `test`.
- Paths use JSON Pointer syntax (RFC 6901): `/slides/0/title`, `/slides/1/body/children/0/content/text`.
- Array indices are zero-based. Use `/-` to append to the end of an array.
- All operations are atomic — if any fails, nothing is applied.
- Use `"content"` for initial deck generation. Use `"patch"` for incremental edits.

Examples:
```json
{ "patch": [{ "op": "replace", "path": "/slides/0/title", "value": "New Title" }] }
{ "patch": [{ "op": "add", "path": "/slides/-", "value": { "type": "grid", "title": "New Slide", "body": { "children": [] } } }] }
{ "patch": [{ "op": "remove", "path": "/slides/2" }] }
```

**Response** (both modes):
- `presentation`: the saved record (includes `presentation.content` — the full deck JSON)
- `annotatedContent`: a deep copy of content with capacity annotations on every text/table/bulletList zone. Key fields:
  - Text: `_charsPerLine`, `_maxLines`, `_maxChars`
  - Bullet lists: `_charsPerLine`, `_maxLines`, `_maxChars`, `_maxCharsPerItem`
  - Tables: `data._cellMaxChars[]` (per column), `data._headersMaxChars[]`, `data._maxRows`
  - Slides: `_titleMaxChars`, `_titleCharsPerLine`, `_titleMaxLines`, `_sectionLabelMaxChars`, `_footerMaxChars`
  - Zone nodes: `_headerMaxChars`, `_subheaderMaxChars`

**Save research notes** alongside the presentation:

```
PATCH {BASE_URL}/api/presentations/{PRESENTATION_ID}
Content-Type: application/json
Authorization: Bearer {TOKEN}

{ "researchDoc": "<markdown string with your research notes>" }
```

You can include `"researchDoc"` alongside `"content"` or `"patch"` in the same request.

## 3. Slide Image (Visual Inspection)

```
GET {BASE_URL}/api/presentations/{PRESENTATION_ID}/slides/{slideNumber}/image?borders=true
Authorization: Bearer {TOKEN}
```

- `slideNumber` is 1-based (first slide = 1).
- `borders=true` draws thin dashed blue borders around every zone (not in final PPTX).
- Returns: `image/png` binary (960×720 pixels).
- **Always** use `?borders=true` when inspecting — zone borders make overflow visible.
- Save to a file and view it: `curl -H "$AUTH" "{BASE_URL}/api/presentations/{PRESENTATION_ID}/slides/1/image?borders=true" -o slide1.png`

## 4. Process Images

After building the deck, trigger server-side resolution of all image/SVG/HTML/ECharts placeholders:

**Start the job:**
```
POST {BASE_URL}/api/presentations/{PRESENTATION_ID}/process-images
Authorization: Bearer {TOKEN}
```

Returns: `{ "jobId": "...", "total": N, "status": "pending" }`

If `total` is 0, there are no unresolved placeholders — skip polling.

**Poll until done:**
```
GET {BASE_URL}/api/presentations/{PRESENTATION_ID}/process-images/{jobId}
Authorization: Bearer {TOKEN}
```

Returns: `{ "jobId", "status", "total", "completed", "currentLabel", "errors" }`

`status` is one of: `"pending"`, `"processing"`, `"completed"`, `"failed"`. Poll every 10 seconds.

## 5. Export PPTX

```bash
curl -H "Authorization: Bearer {TOKEN}" \
  "{BASE_URL}/api/presentations/{PRESENTATION_ID}/export" \
  -o presentation.pptx
```

This downloads the final `.pptx` file.

## 6. Skills & References

**Skills** are task-specific build instructions (e.g. how to build a company profile, competitive analysis, etc.).

Discover all skills:
```
GET {BASE_URL}/api/skills
Authorization: Bearer {TOKEN}
```
Returns: `{ "skills": [{ "slug", "name", "description", "isCustom" }] }`

Fetch a specific skill:
```
GET {BASE_URL}/api/skills/{slug}
Authorization: Bearer {TOKEN}
```
Returns: `{ "skill": { "slug", "name", "content" } }`

**References** are example presentations curated by the organization.

List references:
```
GET {BASE_URL}/api/references
Authorization: Bearer {TOKEN}
```
Returns: `{ "references": [{ "id", "name", "description", "presentation": { "id", "title" } }] }`

Fetch a reference:
```
GET {BASE_URL}/api/references/{id}
Authorization: Bearer {TOKEN}
```
Returns: `{ "reference": { "id", "name", "description", "presentation": { "id", "title", "content" } } }`

## 7. Schema Reference

**Before building any slides**, read the full deck JSON schema:

```
{BASE_URL}/developers/schema.md
```

This is critical — it documents every property, content type, chart type, and layout rule.

## 8. Example Decks

Study these for proper JSON structure and idiomatic patterns:

- Cybersecurity example: `{BASE_URL}/developers/example-deck-cybersecurity.json`
- Biotech example: `{BASE_URL}/developers/example-deck-biotech.json`

If the organization has References (see section 6), prefer those — they're curated for the org's style.

---

## Workflow

Follow these steps in order for every presentation.

### Step 1: Create the presentation
`POST {BASE_URL}/api/presentations` with `{ "title": "..." }`. Save the returned `id`.

### Step 2: Read the schema
Fetch `{BASE_URL}/developers/schema.md` and study it thoroughly. This tells you how to structure every slide, zone, table, chart, and image.

### Step 3: Discover skills
`GET {BASE_URL}/api/skills`. If a skill matches the user's request (e.g. "company profile" → look for a profile skill), fetch its full content and follow it precisely — it has the definitive layout, slide count, and content rules.

### Step 4: Discover references
`GET {BASE_URL}/api/references`. Study any relevant reference presentations for layout patterns and styling.

### Step 5: Research
Use your own tools (web search, file reading, etc.) to gather current data for the presentation. Your training data may be outdated — verify all factual claims. For any data you cannot verify, use [brackets] as placeholders: `[$XX B]`, `[CEO Name]`.

### Step 6: Plan the skeleton
Design slide layouts with zone types, sizes, headers, but use placeholder/empty text for content. Think about:
- How many slides are needed to fairly represent the research
- Zone sizes proportional to content importance
- At least one visual element per content slide (chart, image, table, logo grid)

PATCH the skeleton to save it.

### Step 7: Read capacity annotations
From the PATCH response's `annotatedContent`, read the capacity metadata:
- `_maxChars`, `_charsPerLine`, `_maxLines` for text zones
- `_cellMaxChars[]`, `_maxRows` for tables
- `_titleMaxChars`, `_headerMaxChars` for titles/headers

### Step 8: Populate content
Write text that fits within the annotated budgets. PATCH again.

### Step 9: Visual inspection
For **each slide**:
1. Fetch the slide image: `GET .../slides/{num}/image?borders=true`
2. Check for: overflow (text/tables clipped), empty zones, poor spacing, visual balance
3. Fix any issues and PATCH again
4. Re-inspect if major issues remain

### Step 10: Process images
`POST .../process-images` to resolve all image/SVG/HTML/ECharts placeholders. Poll until complete.

### Step 11: Export
`GET .../export` and save as `.pptx`.

---

## Key Layout & Content Rules

### Grid System
- 12-column grid. Each zone has a `span` (1–12). Children spans within a parent must sum to ≤ 12.
- `direction`: `"row"` (side by side) or `"col"` (stacked).
- Nesting: 2–3 levels max.

### Slide Structure
```json
{
  "type": "grid",
  "title": "Slide Title",
  "sectionLabel": "Section Name",
  "footer": "Source: ...",
  "margin": 0.4,
  "body": {
    "direction": "row",
    "gap": 0.15,
    "children": [
      { "span": 6, "header": "Left Column", "content": { "type": "text", "text": "..." } },
      { "span": 6, "header": "Right Column", "content": { "type": "chart", ... } }
    ]
  }
}
```

### Content Types
- **text**: `{ type: "text", text: "...", fontSize: 1100, bold: true, align: "l" }`
- **bulletList**: `{ type: "bulletList", items: ["Item 1", "Item 2"] }`
- **table**: `{ type: "table", data: { headers: [...], rows: [...], colWidths: [3,3,3,3] } }` — `colWidths` must sum to 12. MUST use `data` wrapper.
- **chart**: `{ type: "chart", chartType: "bar", data: { series: [...] }, valuePrefix: "$", valueSuffix: "M", valueThousands: true }`
- **image**: `{ type: "image", source: "search", searchTerm: "NVIDIA logo", objectFit: "contain" }` or `{ type: "image", source: "ai", prompt: "..." }`
- **aiHtml**: `{ type: "aiHtml", htmlData: "<div>...</div>" }` — complete HTML with inline CSS, sized to `100vw × 100vh`.
- **aiSvg**: `{ type: "aiSvg", prompt: "..." }` or `{ type: "aiSvg", svgData: "<svg>...</svg>" }`
- **aiEcharts**: Only for chart types that `chart` cannot handle (radar, heatmap, treemap, funnel, sankey). Never use for simple bar/line/pie.

### fontSize
In **hundredths of a point**: 1000 = 10pt, 1300 = 13pt, 2400 = 24pt. Minimum: 800 (8pt).

### Spacing
All spacing values in **inches**: `gap`, `padding`, `margin`. Shadow values in **points**.

| Property | Description | Examples |
|---|---|---|
| gap | Space between children (default 0.15") | Tight: 0.08, Spacious: 0.25, None: 0 |
| padding | Internal whitespace (default 0) | Card: 0.12, Dense: 0.08 |
| margin | Outer bounds inset | Edge inset: 0.1 |
| background | Fill color (hex) | "#ffffff", "#f0f4ff" |
| border | Outline | "#cccccc" or { color: "#185ABD", width: 2, style: "solid" } |
| shadow | Drop shadow | { color: "#000000", alpha: 0.12, blur: 6, dist: 3, dir: 90 } |

### Tables
- MUST use `data` wrapper: `{ type: "table", data: { headers: [...], rows: [...] } }`
- Headers must be plain strings (no image objects).
- `colWidths` array must sum to 12.
- Best with 3–6 columns, 3–8 rows.
- Check `_cellMaxChars` and `_maxRows` from annotated response.
- Company names: use logo images instead of text: `{ type: "image", source: "search", searchTerm: "CompanyName logo" }`.
- Tables that overflow are **clipped invisible** in PPTX. Always visually inspect.

### Charts
- Always set `valueThousands: true`.
- For money: `valuePrefix: "$"`, `valueSuffix: "M"` or `"B"`.
- Don't set `title` on the chart — use the parent zone's `header`.
- Pie charts: use legend mode OR slice labels, not both.
- Use `pptxExportMode: "nativeExcel"` to make charts editable in PowerPoint.

### Images
- Default `objectFit: "contain"`. Use `"cover"` only for decorative/background images.
- Logos: `source: "search"`, `searchTerm: "CompanyName logo"`.
- AI-generated: `source: "ai"` with descriptive `prompt`.
- Don't resolve images yourself — leave as placeholders, then use Process Images endpoint.

### Sources & Citations
Add `_sources` on every zone displaying sourced data:
```json
"_sources": [
  { "url": "https://...", "label": "Revenue data", "date": "2026-01-15" }
]
```
Use slide `footer` or zone `subfooter` for visible citations.

### Visual Inspection Checklist
After every PATCH, inspect each changed slide:
1. No text overflow (clipped/cut off text)
2. No table overflow (rows disappearing)
3. No empty/sparse zones — fill at least 80% of text zones
4. Good visual balance — charts, images, or tables on every content slide
5. Headers and content properly sized
6. Sources cited on data zones

### Style
- Let the design system theme handle fonts and colors — don't set explicit overrides unless the user requests them.
- Style presets: `"corporate"` (finance), `"minimal"` (tech), `"warm"` (creative).
- Every content slide needs at least one visual element (chart, image, table, logo grid).
- Use `sectionLabel` on every content slide.
- Never truncate with "..." — write a genuinely shorter version.
- Never create empty slides.

### Layout Patterns
- **2-column**: `direction: "row"`, two children with `span: 6` each.
- **Sidebar**: `direction: "row"`, `span: 8` main + `span: 4` sidebar.
- **Title slide**: 3-column body — span 1 spacer, span 7 title column, span 4 AI image.
- **Section divider**: `direction: "row"` — span 2 section info, span 1 AI image.
- Use headers to label zones. Use subheaders for sub-sections.
- Prefer structured zones (header + children with sub-headers) over flat content.

### Execution Tips
- Before every edit, GET the latest presentation first.
- If the presentation already has slides, those are **template slides** — keep them and append using `"patch"` with `add` at `/slides/-`.
- Use `"patch"` (RFC 6902) for all edits. Use `"content"` only for full generation of a new empty presentation.
- Slide numbers: users mean 1-based. Slide 1 = array index 0.
