Skip to content

Building Your First App

This guide walks you through building a complete AI-powered app from scratch — a writing assistant that streams AI responses and saves drafts to storage.

Terminal window
vibedepot init writing-buddy

Choose vanilla template and writing category.

Edit writing-buddy/manifest.json:

{
"id": "writing-buddy",
"name": "Writing Buddy",
"version": "0.1.0",
"description": "AI writing assistant with draft saving.",
"author": "your-name",
"entry": "index.html",
"category": "writing",
"keywords": ["writing", "ai", "drafts"],
"permissions": ["ai", "storage.kv"],
"models": {
"required": true,
"providers": ["anthropic", "openai", "gemini"],
"default": "anthropic"
}
}

The ai permission enables AI calls. storage.kv is auto-granted but should still be declared for clarity.

Replace writing-buddy/index.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Writing Buddy</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
padding: 24px;
max-width: 720px;
margin: 0 auto;
}
h1 { margin-bottom: 16px; }
textarea {
width: 100%; height: 120px; padding: 12px;
border: 1px solid #d1d5db; border-radius: 8px;
font-size: 14px; resize: vertical;
}
.actions { margin-top: 12px; display: flex; gap: 8px; }
button {
padding: 8px 16px; border: none; border-radius: 6px;
cursor: pointer; font-size: 14px;
}
.primary { background: #3b82f6; color: white; }
.secondary { background: #e5e7eb; }
#output {
margin-top: 20px; padding: 16px;
background: #f8fafc; border-radius: 8px;
white-space: pre-wrap; min-height: 100px;
}
#status { margin-top: 8px; color: #6b7280; font-size: 13px; }
</style>
</head>
<body>
<h1>Writing Buddy</h1>
<textarea id="prompt" placeholder="Describe what you'd like to write..."></textarea>
<div class="actions">
<button class="primary" id="generate">Generate</button>
<button class="secondary" id="save">Save Draft</button>
<button class="secondary" id="load">Load Draft</button>
</div>
<div id="output"></div>
<div id="status"></div>
<script>
const prompt = document.getElementById('prompt');
const output = document.getElementById('output');
const status = document.getElementById('status');
// Generate with streaming
document.getElementById('generate').addEventListener('click', async () => {
if (!prompt.value.trim()) return;
output.textContent = '';
status.textContent = 'Generating...';
try {
await window.vibeDepot.ai.streamAI(
{
messages: [
{ role: 'system', content: 'You are a helpful writing assistant.' },
{ role: 'user', content: prompt.value }
]
},
(chunk) => {
output.textContent += chunk;
}
);
status.textContent = 'Done.';
} catch (err) {
status.textContent = 'Error: ' + err.message;
}
});
// Save draft to KV storage
document.getElementById('save').addEventListener('click', async () => {
await window.vibeDepot.storage.set('draft', {
prompt: prompt.value,
output: output.textContent,
savedAt: new Date().toISOString()
});
status.textContent = 'Draft saved.';
});
// Load draft from KV storage
document.getElementById('load').addEventListener('click', async () => {
const draft = await window.vibeDepot.storage.get('draft');
if (draft) {
prompt.value = draft.prompt || '';
output.textContent = draft.output || '';
status.textContent = 'Draft loaded from ' + draft.savedAt;
} else {
status.textContent = 'No saved draft found.';
}
});
// Adapt to system theme
window.vibeDepot.shell.theme().then((theme) => {
if (theme === 'dark') {
document.body.style.background = '#1e293b';
document.body.style.color = '#f1f5f9';
}
});
</script>
</body>
</html>
Terminal window
cd writing-buddy
vibedepot preview

Or sideload manually from the Library page (requires Publisher Mode in Settings).

Changes to index.html auto-reload — no need to re-sideload.

Terminal window
vibedepot validate

Fix any issues before publishing. See validation checks for details.

Terminal window
vibedepot publish

This creates a ZIP bundle, computes a SHA256 checksum, and opens a GitHub PR. See Publishing to the Registry for the full process.

  • Scaffolding an app with the CLI
  • Declaring permissions and AI providers in the manifest
  • Using streamAI() for real-time AI responses
  • Saving and loading data with KV storage
  • Reading the system theme
  • Testing with sideloading
  • Validating and publishing