# Granola View & Edit — Design

**Date:** 2026-03-03
**Status:** Approved
**Author:** kbx-dev

## Goal

Add `kbx granola view` and `kbx granola edit` commands to read and modify Granola
meeting notes, consistent with existing `kbx note edit` / `kbx view` patterns.

## CLI Surface

```
# View
kbx granola view <calendar-uid>              # notes with YAML header
kbx granola view <calendar-uid> --summary    # AI summary instead
kbx granola view <calendar-uid> --all        # notes + summary
kbx granola view <calendar-uid> --plain      # raw markdown only (no header)

# Edit
kbx granola edit <calendar-uid> --body "new content"      # full replace
kbx granola edit <calendar-uid> --body-file updated.md     # replace from file
kbx granola edit <calendar-uid> --append "extra content"   # append to end

# Push (unchanged)
kbx granola push <calendar-uid> --notes "prep" --title "1:1"
```

## Command Semantics

| Command | Creates doc? | Default mode | Use case |
|---------|-------------|--------------|----------|
| `view`  | No (error)  | Read         | Inspect notes/summary |
| `edit`  | No (error)  | Replace      | Modify existing notes |
| `push`  | Yes (auto)  | Prepend      | Pre-meeting prep injection |

Three verbs, three jobs: `view` reads, `edit` modifies, `push` injects.

## View Output

YAML frontmatter header matching existing meeting file format:

```yaml
---
title: performance - weekly sync
date: '2026-03-03'
granola_id: 5a01890c-29d3-4575-a558-9370e5f9d68c
calendar_uid: 0taavu3t0isi9opchr8nischj2_20260303T143000Z
files:
  notes: true
  transcript: true
  ai_summary: true
---

## Meeting Prep — Performance Weekly Sync
...
```

`--plain` skips the YAML header, outputs just the markdown body.

`--summary` shows `extract_panel_markdown(doc)` instead of notes.

`--all` shows notes, then `---`, then AI summary.

## Edit Data Flow

1. `find_document(calendar_uid)` → get doc (error if not found)
2. For `--append`: read existing `notes_markdown`, concatenate
3. `update_document_notes(doc_id, markdown, prepend=False)` → Granola API
4. Write-through: `write_meeting()` to update local `.granola.notes.md`
5. Staleness detector reindexes on next search

## Write-through

After edit, immediately re-sync that meeting's local `.granola.notes.md` using
`write_meeting()`. No explicit reindex — the staleness detector handles it.

## Error Handling

- No doc found → `click.ClickException("No Granola document found for UID …")`
- No notes on doc → view prints "(no notes)", edit proceeds (fresh write)
- API failure → httpx error propagation

## Files Changed

- `src/kb/cli.py` — `granola view`, `granola edit` commands
- `src/kb/sync/granola.py` — write-through helper if needed
- `tests/test_sync_granola.py` — tests for both commands

## Not In Scope

- Interactive `$EDITOR` mode (follow-up)
- Editing AI summaries (read-only)
- Editing transcripts
