# OpenClone Memory Vault — Cursor Rules

This project integrates with OpenClone for personal memory augmentation.
The vault is stored as Obsidian-compatible `.md` files at `./vault/` (or the configured VAULT_PATH).

## Vault Structure

- `vault/Audio/YYYY-MM-DD.md` — transcribed system audio, meetings, mic input
- `vault/Screen/YYYY-MM-DD.md` — screen OCR captures, active window content
- `vault/Web/YYYY-MM-DD.md` — web browsing history, article content, reading time
- `vault/Journal/YYYY-MM-DD.md` — voice journal entries, free-form notes
- `vault/Health/YYYY-MM-DD.md` — health & fitness data
- `vault/Calendar/YYYY-MM-DD.md` — calendar events & meetings
- `vault/Notes/YYYY-MM-DD.md` — notes from apps (Obsidian, Notion, etc.)
- `vault/Braindump/YYYY-MM-DD.md` — manual text captures

## Memory File Format

```markdown
---
type: audio_system        # source type (see below)
source: mac-audio         # plugin identifier
date: YYYY-MM-DD
plugin: openclone-mac-audio
platform: macos
tags: [audio, meeting]
---

### HH:MM
<!-- event_id: uuid-here -->
- **App:** ApplicationName
- **Duration:** 60s
- **Text:** "transcribed content..."
```

## Source Types

| type | Description | Folder |
|------|-------------|--------|
| `audio_system` | System audio (apps, meetings) | Audio/ |
| `audio_mic` | Ambient microphone | Audio/ |
| `screen_ocr` | Screen capture + OCR | Screen/ |
| `web_browsing` | Browser history + content | Web/ |
| `journal` | Voice/text journal | Journal/ |
| `health` | Health & fitness | Health/ |
| `calendar` | Calendar events | Calendar/ |
| `notes` | App notes | Notes/ |
| `music` | Music/podcasts | Music/ |
| `gps` | Location | Location/ |
| `braindump` | Free-form text | Braindump/ |

## Backend API

The OpenClone backend runs at `http://localhost:8000` by default.
Auth header: `X-Api-Key: <API_KEY>`

### Key Endpoints

```typescript
// Ingest new memory
POST /api/v1/ingest
{
  source_type: string,
  platform: string,
  device_id: string,
  plugin_id: string,
  plugin_version: string,
  timestamp: number,
  events: Array<{ timestamp: number, data: object }>
}

// Search vault
GET /api/search?q=query&type=source_type&limit=20&offset=0

// List memories
GET /api/memories?date=YYYY-MM-DD&source=Audio&limit=50

// Ask AI (streaming SSE)
POST /api/ask/stream
{ question: string, conversation_id?: string }
// → SSE: {"token": "..."} | {"done": true} | {"status": "Searching..."}

// Stats
GET /api/stats?period=today|week|month|all

// Daily brief
POST /api/brief/generate
GET /api/brief/YYYY-MM-DD
```

## Environment Variables

```env
API_KEY=your-secret-key
AI_PROVIDER=openai|anthropic|openrouter|gemini
AI_MODEL=gpt-4o-mini
AI_API_KEY=your-byok-key
VAULT_PATH=/path/to/obsidian/vault
DEFAULT_LANGUAGE=en
```

## Code Patterns

When reading vault files in code:
```typescript
// Parse frontmatter + entries
const file = await fs.readFile(`vault/Audio/${date}.md`, 'utf-8');
const [, frontmatter, body] = file.split('---');
const meta = parseYaml(frontmatter);
const entries = body.split('### ').filter(Boolean);
```

When calling the API:
```typescript
const response = await fetch('http://localhost:8000/api/ask/stream', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': process.env.API_KEY,
  },
  body: JSON.stringify({ question: userInput }),
});
// Parse SSE stream: each line is JSON {"token":"..."} or {"done":true}
```
