Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Reminders
* examples use npm not pnpm
* before merging, check the CI pipeline, lint, build, etc... then npm login and npm publish mindcache if relevant.

55 changes: 55 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
</div>
<div class="nav-links">
<a href="#cloud">Cloud</a>
<a href="#local-first">Local-First</a>
<a href="#features">Features</a>
<a href="#examples">Examples</a>
<a href="#docs">Docs</a>
Expand Down Expand Up @@ -126,6 +127,60 @@ <h3>Built-in AI APIs</h3>
</div>
</section>

<!-- Local-First Section -->
<section id="local-first" class="local-first-section">
<div class="container">
<div class="section-header">
<h2>Local-First with <span class="gradient-text">GitStore</span></h2>
<p>100% client-side apps with GitHub as your database</p>
</div>
<div class="cloud-features">
<div class="cloud-feature">
<div class="cloud-icon">💻</div>
<h3>No Server Required</h3>
<p>Run AI entirely in the browser. API keys stay in localStorage, never touch a server.</p>
</div>
<div class="cloud-feature">
<div class="cloud-icon">📂</div>
<h3>GitHub as Database</h3>
<p>Sync MindCache to any GitHub repo. Version history, branching, and collaboration built-in.</p>
</div>
<div class="cloud-feature">
<div class="cloud-icon">📱</div>
<h3>Cross-Platform</h3>
<p>Web, Mac, Android — all apps sync through GitHub. Works offline, syncs when online.</p>
</div>
<div class="cloud-feature">
<div class="cloud-icon">⚛️</div>
<h3>React Components</h3>
<p>Drop-in &lt;MindCacheChat&gt; component. Full AI chat in ~15 lines of code.</p>
</div>
</div>
<div class="example-code" style="margin-top: 2rem; max-width: 700px; margin-left: auto; margin-right: auto;">
<pre><code>// Local-first AI chat in 15 lines
import { MindCacheProvider, MindCacheChat } from 'mindcache';

function App() {
return (
&lt;MindCacheProvider
ai={{ provider: 'openai', model: 'gpt-4o', keyStorage: 'localStorage' }}
&gt;
&lt;MindCacheChat welcomeMessage="Hello! I run in your browser." /&gt;
&lt;/MindCacheProvider&gt;
);
}</code></pre>
</div>
<div class="cloud-cta" style="margin-top: 2rem;">
<a href="https://www.npmjs.com/package/@mindcache/gitstore" target="_blank" class="btn-secondary" style="margin-right: 1rem;">
<span>📦 @mindcache/gitstore</span>
</a>
<a href="https://github.com/dh7/mindcache/tree/main/examples/local_first_chat" target="_blank" class="btn-secondary">
<span>💡 Example App</span>
</a>
</div>
</div>
</section>

<!-- Features Section -->
<section id="features" class="features">
<div class="container">
Expand Down
14 changes: 14 additions & 0 deletions docs/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,20 @@ section {
text-align: center;
}

/* Local-First Section */
.local-first-section {
background: linear-gradient(135deg, #0c1220 0%, #1a2744 50%, #0d3b66 100%);
padding: var(--space-3xl) 0;
}

.local-first-section .section-header h2 {
color: white;
}

.local-first-section .section-header p {
color: rgba(255, 255, 255, 0.7);
}

.btn-cloud {
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
text-decoration: none;
Expand Down
5 changes: 5 additions & 0 deletions examples/local_first_chat/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
.next
.env
.env.local
package-lock.json
70 changes: 70 additions & 0 deletions examples/local_first_chat/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Local-First Chat

A minimal example of a **100% client-side** AI chat app using MindCache.

## Features

- **No server required** - AI calls go directly from browser to OpenAI
- **API key in localStorage** - Never sent to any server
- **Data in IndexedDB** - Persists locally, works offline
- **Real-time streaming** - See responses as they generate
- **MindCache integration** - AI can read/write to your local data

## Quick Start

```bash
# Install dependencies
npm install

# Run development server
npm run dev
```

Open [http://localhost:3000](http://localhost:3000) and enter your OpenAI API key when prompted.

## How It Works

```tsx
// layout.tsx - Configure the provider (just 3 lines of config!)
<MindCacheProvider
ai={{
provider: 'openai',
model: 'gpt-4o',
keyStorage: 'localStorage'
}}
>
{children}
</MindCacheProvider>

// page.tsx - Use the chat component
<MindCacheChat
welcomeMessage="Hello!"
placeholder="Ask anything..."
/>
```

That's it! ~15 lines of code for a full AI chat app.

## Architecture

```
Browser
├── MindCache (IndexedDB) ← Local data persistence
├── AI SDK (streamText) ← Streaming AI responses
└── OpenAI API ← Direct API calls (no proxy)
```

## Adding MindCache Data

The AI can read and write to MindCache. Set up some initial data:

```tsx
const { mindcache } = useMindCacheContext();

// Add data the AI can see and modify
mindcache.set_value('user_name', 'Alice', {
systemTags: ['SystemPrompt', 'LLMWrite']
});
```

Now ask the AI: "What's my name?" or "Change my name to Bob"
3 changes: 3 additions & 0 deletions examples/local_first_chat/env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# No server-side env needed!
# API key is stored in browser localStorage
# Just run: pnpm dev
6 changes: 6 additions & 0 deletions examples/local_first_chat/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
6 changes: 6 additions & 0 deletions examples/local_first_chat/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
transpilePackages: ['mindcache']
};

module.exports = nextConfig;
21 changes: 21 additions & 0 deletions examples/local_first_chat/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "local-first-chat",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"mindcache": "file:../../packages/mindcache",
"next": "^15.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^19",
"typescript": "^5"
}
}
18 changes: 18 additions & 0 deletions examples/local_first_chat/src/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}

html, body {
height: 100%;
overflow: hidden;
background: #000;
color: #fff;
}

/* Blinking cursor animation for streaming */
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
40 changes: 40 additions & 0 deletions examples/local_first_chat/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'use client';

import { MindCacheProvider } from 'mindcache';
import './globals.css';

/**
* Local-first MindCache app layout
*
* - API key stored in browser localStorage (never sent to server)
* - AI runs directly in browser → OpenAI
* - Data persisted in IndexedDB
* - No server required!
*/
export default function RootLayout({
children
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<MindCacheProvider
mindcache={{
indexedDB: {
dbName: 'local_first_chat',
storeName: 'mindcache'
}
}}
ai={{
provider: 'openai',
model: 'gpt-4o',
keyStorage: 'localStorage'
}}
>
{children}
</MindCacheProvider>
</body>
</html>
);
}
55 changes: 55 additions & 0 deletions examples/local_first_chat/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use client';

import { MindCacheChat, useMindCacheContext } from 'mindcache';

/**
* Simple local-first chat page
*
* That's it! The MindCacheChat component handles:
* - API key input (if not set)
* - Real-time streaming
* - MindCache tool integration
* - Mobile-friendly UI
*/
export default function Home() {
return (
<main style={{ height: '100dvh', display: 'flex', flexDirection: 'column' }}>
<Header />
<MindCacheChat
welcomeMessage="Hello! I'm running entirely in your browser. Your API key and data never leave your device."
placeholder="Ask me anything..."
style={{ flex: 1 }}
/>
</main>
);
}

function Header() {
const { mindcache, isLoaded } = useMindCacheContext();

return (
<header style={{
padding: '12px 16px',
borderBottom: '1px solid #333',
backgroundColor: '#000',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
}}>
<h1 style={{
margin: 0,
fontSize: '16px',
color: '#22c55e',
fontFamily: 'system-ui'
}}>
Local-First Chat
</h1>
<span style={{
fontSize: '12px',
color: '#666'
}}>
{isLoaded ? `${Object.keys(mindcache?.getAll() || {}).length} keys in MindCache` : 'Loading...'}
</span>
</header>
);
}
21 changes: 21 additions & 0 deletions examples/local_first_chat/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [{ "name": "next" }],
"paths": { "@/*": ["./src/*"] }
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
5 changes: 5 additions & 0 deletions examples/local_first_mindcache/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
.next
.env
.env.local
package-lock.json
Loading
Loading