THIS PROJECT USES SVELTE 5 WITH RUNES. YOU MUST ALWAYS:
-
Use
$state()for reactive variables - NOTlet foo = 'bar'❌ WRONG: let count = 0 ✅ RIGHT: let count = $state(0)
-
Use
$props()for component props - NOTexport let❌ WRONG: export let title = '' ✅ RIGHT: let { title = '' } = $props() -
Use
watchfrom runed for watching prop changes - NOT$effect()❌ WRONG: $effect(() => { if (target_field) doSomething() }) ✅ RIGHT: watch(() => target_field, (value) => { if (value) doSomething() })- Import:
import { watch } from "runed" - Use
watchwhen reacting to specific prop/state changes - Use
$effect()only for setup/cleanup side effects (e.g., event listeners)
- Import:
-
Use
$derived()for computed values - NOT$:assignments❌ WRONG: $: doubled = count * 2 ✅ RIGHT: let doubled = $derived(count * 2)
-
Use
onclick={handler}NOTon:click={handler}❌ WRONG: <button on:click={handler}>Click</button> ✅ RIGHT: <button onclick={handler}>Click</button>
-
BEFORE writing ANY Svelte component:
- Use
mcp__svelte__svelte-autofixertool to validate your code - Pass
desired_svelte_version: 5andasync: false(unless using await in markup) - Fix ALL issues the autofixer reports before proceeding
- Use
No exceptions. Svelte 4 syntax will break this codebase.
tinykit is an open-source, self-hosted AI development platform—think Lovable, but running on your own server alongside the apps it builds. It provides database, editor, and hosting all at /tinykit, enabling you to ship production CRUD apps in an afternoon.
Core Value Proposition: Let the AI handle the boring 80% (routes, auth, CRUD operations, basic UI), then you take over for the last mile—the details that actually matter.
- Frontend Framework: SvelteKit 2.x with TypeScript
- Database & Storage: Pocketbase 0.23.8
- Styling: Tailwind CSS 3.4.x
- Icons: Lucide (via lucide-svelte)
- Editor: CodeMirror 6 with Emmet support
- AI Integration: Vercel AI SDK (@ai-sdk/openai, @ai-sdk/anthropic, @ai-sdk/google)
- Version Control: Snapshots stored in Pocketbase (code-only)
- Self-hosted, single-server deployment
- No external services required (except LLM API)
- Two Pocketbase collections:
_tk_projects- All project data_tk_settings- App configuration (LLM keys, etc.)
- Pocketbase proxied through SvelteKit at
/_pb/(same port) - Live preview with in-browser Svelte compilation
- Server-side build system for production HTML
- id (auto)
- name (text)
- domain (text, unique, required)
- frontend_code (text, max 10MB)
- backend_code (text, max 10MB)
- custom_instructions (text, max 1MB)
- design (json) - CSS variables array
- content (json) - Content fields array
- snapshots (json) - Time travel history
- agent_chat (json) - Conversation history
- data (json) - App data tables
- settings (json) - Project settings (vibe_zone_enabled, etc.)
- published_html (file) - Built production HTML
- created/updated (auto)
- id (text, primary key) - Setting key (e.g., "llm")
- value (json) - Setting value
Each project is associated with a domain. Users can point multiple domains to a single tinykit server:
calculator.myserver.com/ → Serves calculator production app
calculator.myserver.com/tinykit/studio → Edit calculator app
calculator.myserver.com/tinykit/dashboard → See ALL apps
blog.myserver.com/ → Serves blog production app
blog.myserver.com/tinykit/studio → Edit blog app
Route Resolution:
/- Serve production app for current domain (frompublished_htmlfile)/tinykit/studio- Edit the project for current domain/tinykit/studio?id=X- Edit specific project by ID/tinykit/dashboard- List all projects/tinykit/new?domain=X- Create new project for domain/tinykit/settings- LLM configuration/setup- First-time setup wizard
┌───────────────────────────────────────────────────────────┐
│ tinykit · My Project [Vibe] [Deploy] │
├────────────────────────────┬──────────────────────────────┤
│ [Agent] [Code] [Content] │ Preview │
│ [Design] [Data] [History] │ │
├────────────────────────────┤ │
│ │ │
│ Left Pane Content │ Live Preview │
│ (tabs switchable) │ │
│ │ │
└────────────────────────────┴──────────────────────────────┘
- Left Pane: 6 tabs
- Agent (Cmd+1): AI chat interface for building apps
- Code (Cmd+2): CodeMirror editor for manual code editing
- Content (Cmd+3): CMS-like content fields
- Design (Cmd+4): CSS variables for theming (colors, fonts, spacing)
- Data (Cmd+5): Project data tables
- History (Cmd+6): Snapshots for time travel / undo
- Right Pane: Live preview iframe with hot reload
- Split View: Resizable layout with PaneForge
Fun mini-games/visuals to enjoy while waiting for AI responses:
- Starfield animation
- Tetris, Snake, 2048, Wordle
- Lo-fi music player (Chillhop, LofiGirl)
- Generative art
- Can be toggled per-project via settings
tinykit/
├── src/
│ ├── routes/
│ │ ├── login/ # Login page
│ │ │ └── +page.svelte
│ │ ├── setup/ # First-time setup wizard
│ │ │ └── +page.svelte
│ │ ├── tinykit/ # Main admin interface
│ │ │ ├── +layout.svelte # Auth guard
│ │ │ ├── +page.svelte # Redirect to dashboard
│ │ │ ├── dashboard/ # Projects list
│ │ │ ├── studio/ # Project editor (main UI)
│ │ │ │ ├── +page.svelte
│ │ │ │ ├── project.svelte.ts # ProjectStore class
│ │ │ │ ├── panels/ # Tab panels
│ │ │ │ │ ├── agent/AgentPanel.svelte
│ │ │ │ │ ├── code/CodePanel.svelte
│ │ │ │ │ ├── content/ContentPanel.svelte
│ │ │ │ │ ├── design/DesignPanel.svelte
│ │ │ │ │ ├── data/DataPanel.svelte
│ │ │ │ │ └── history/HistoryPanel.svelte
│ │ │ │ └── components/ # UI components
│ │ │ │ ├── Header.svelte
│ │ │ │ ├── VibeZone.svelte
│ │ │ │ ├── CodeEditor.svelte
│ │ │ │ └── vibes/ # VibeZone games
│ │ │ ├── new/ # New project page
│ │ │ ├── settings/ # LLM settings
│ │ │ ├── [id]/ # Legacy redirect
│ │ │ ├── lib/ # Local utilities (api.svelte.ts, storage.ts)
│ │ │ ├── types.ts # Shared TypeScript types
│ │ │ └── context.ts # Svelte context helpers
│ │ ├── api/
│ │ │ ├── projects/[id]/
│ │ │ │ ├── agent/+server.ts # LLM streaming endpoint
│ │ │ │ ├── build/+server.ts # Svelte compilation
│ │ │ │ ├── export/+server.ts # Project export
│ │ │ │ └── templates/+server.ts
│ │ │ ├── templates/ # Starter templates
│ │ │ ├── settings/ # LLM settings CRUD
│ │ │ ├── setup/ # Setup endpoint
│ │ │ └── proxy/ # External URL proxy
│ │ ├── _tk/ # Internal data endpoints
│ │ │ ├── data/ # Project data CRUD
│ │ │ └── realtime/ # SSE for realtime updates
│ │ ├── +layout.svelte # Root layout
│ │ ├── +server.ts # Root route (serves production apps)
│ │ └── [...path]/+server.ts # Catch-all for production app assets
│ ├── lib/
│ │ ├── pocketbase.svelte.ts # PB client singleton + auth
│ │ ├── services/
│ │ │ └── project.svelte.ts # Project CRUD via SDK
│ │ ├── stores/
│ │ │ ├── project.svelte.ts # Reactive project store
│ │ │ └── vibe_zone.svelte.ts
│ │ ├── components/ # Shared UI components
│ │ │ ├── ui/ # shadcn-svelte components
│ │ │ └── Preview.svelte # Live preview iframe
│ │ ├── compiler/ # In-browser Svelte compiler
│ │ ├── server/ # Server-side utilities
│ │ │ ├── pb.ts # Server PB client
│ │ │ └── data-security.ts
│ │ ├── ai/ # AI agent implementation
│ │ │ ├── sdk-agent.ts # Main agent with tools
│ │ │ ├── index.ts
│ │ │ └── types.ts
│ │ ├── templates/ # Starter templates
│ │ ├── themes.ts # App themes
│ │ ├── builder_themes.ts # Builder UI themes
│ │ └── utils.ts # Utility functions
│ ├── hooks.server.ts # Pocketbase proxy + domain resolution
│ ├── app.html # HTML template
│ └── app.css # Global styles with Tailwind
├── scripts/
│ └── download-pocketbase.js # Downloads PB binary for platform
├── pocketbase/
│ ├── pocketbase # Binary (downloaded)
│ ├── pb_data/ # Database & files
│ └── pb_migrations/ # Collection migrations
├── static/ # Static assets
├── .env.example # Environment template
├── package.json
├── svelte.config.js
├── vite.config.ts
├── tailwind.config.js
└── claude.md # This file
Reactive store class that manages project state with real-time Pocketbase subscriptions:
import { getProjectStore } from "./project.svelte";
const store = getProjectStore();
// Reactive state
store.project; // Full project object
store.code; // frontend_code
store.messages; // agent_chat array
store.content; // content fields
store.design; // design fields
store.data_files; // data table names
store.is_processing; // true during AI generation
// Methods
await store.init();
await store.refresh();
await store.loadSnapshots();SDK-based CRUD operations:
import { project_service } from "$lib/services/project.svelte";
const projects = await project_service.list();
const project = await project_service.get(id);
await project_service.create({ name, domain });
await project_service.update(id, { frontend_code: "..." });
await project_service.delete(id);Uses Vercel AI SDK with tool calling:
Available Tools:
write_code- Write/update frontend codecreate_content_field- Add CMS content fieldsupdate_content_field- Update content field valuescreate_design_field- Add CSS variable design fieldsupdate_design_field- Update design field valuescreate_data_table- Create new data tableadd_data_record- Add record to data tableupdate_data_record- Update data recorddelete_data_record- Delete data record
Agent (LLM Integration):
POST /api/projects/[id]/agent- Stream AI response- Server-side for LLM API key security
- Returns SSE stream with text and tool calls
Build System:
POST /api/projects/[id]/build- Compile Svelte to standalone HTML- Server-side compilation with Svelte 5
- Uploads result to
published_htmlfile field
Settings:
GET/POST /api/settings- Get/save LLM configurationPOST /api/settings/validate-llm- Validate LLM API keyGET /api/settings/llm-status- Check if LLM is configured
Templates:
GET /api/templates- List available starter templatesGET /api/templates/[id]- Get template details
Setup:
POST /api/setup- First-time Pocketbase admin creation
Most operations use the PB SDK directly:
import { pb } from "$lib/pocketbase.svelte";
// Projects
const projects = await pb.collection("_tk_projects").getFullList();
const project = await pb.collection("_tk_projects").getOne(id);
await pb.collection("_tk_projects").update(id, { frontend_code: "..." });
// Real-time subscriptions
pb.collection("_tk_projects").subscribe(id, (e) => {
if (e.action === "update") {
// Handle update
}
});# Clone the repository
git clone https://github.com/tinykit-studio/tinykit.git
cd tinykit
# Install dependencies
npm install
# Copy environment variables
cp .env.example .env
# Start dev server (auto-downloads Pocketbase, starts both services)
npm run dev
# Visit http://localhost:5173/setup to complete first-time setupnpm run dev- Start dev server (Pocketbase + Vite)npm run dev:vite- Start only Vite (if PB already running)npm run build- Build for productionnpm run preview- Preview production buildnpm run check- Type checknpm run pocketbase:serve- Start only Pocketbase
- Frontend: http://localhost:5173
- Admin UI: http://localhost:5173/tinykit
- Setup: http://localhost:5173/setup
- Settings: http://localhost:5173/tinykit/settings
- Pocketbase Admin: http://localhost:5173/_pb/_
- Pocketbase API: http://localhost:5173/\_pb/api/
# LLM Configuration (set via /tinykit/settings UI, stored in _tk_settings)
# Not needed in .env - configured through the app
# Pocketbase Configuration
POCKETBASE_URL=http://127.0.0.1:8091
# Server Configuration (optional)
PORT=5173
HOST=0.0.0.0- Pocketbase's built-in
userscollection - Admin UI (
/tinykit/*) requires login - JWT tokens with automatic refresh
- Collection rules enforce
@request.auth.id != ''
src/lib/pocketbase.svelte.ts- Auth storesrc/routes/login/+page.svelte- Login formsrc/routes/tinykit/+layout.svelte- Auth guard
- LLM API Keys: Stored encrypted in Pocketbase, never exposed to client
- File Access: Data operations scoped to project
- Code Execution: AI-generated code runs in sandboxed iframe
- Auth Required: All admin routes require authentication
- Check if port 8091 is available:
lsof -i :8091 - Verify file permissions:
chmod +x ./pocketbase/pocketbase - Check logs in
pocketbase/pb_data/logs/
- Clear cache:
rm -rf .svelte-kit node_modules/.vite - Restart dev server
- Hard refresh: Cmd+Shift+R (Mac) / Ctrl+Shift+R (Windows)
- Visit
/tinykit/settingsto verify LLM configuration - Check browser console for API errors
- Verify API key is valid and has credits
- Check browser console for compilation errors
- Ensure code is valid Svelte 5 syntax
- Try manual refresh of preview pane
Last Updated: 2025-12-14 Version: 0.1.0