Townie
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
This is a full-stack application built on the Val Town platform that serves as an AI-powered development assistant for Val Town projects.
Townie helps developers work with Val Town by providing an intelligent assistant interface with chat-based interactions and AI agent capabilities.
This project uses the Val Town CLI for development workflow:
- Push changes:
vt push
- Push local changes to Val Town- ⚠️ CRITICAL: NEVER push or watch to main branch without explicit user permission
- Watch for changes:
vt watch
- Auto-sync changes with Val Town (includes WebSocket server for companion browser extension)- ⚠️ CRITICAL: NEVER push or watch to main branch without explicit user permission
- Manage branches:
vt branch
- List all branchesvt branch -D <name>
- Delete a branchvt checkout <branch>
- Switch to existing branch
- Pull updates:
vt pull
- Pull latest changes from Val Town - Check status:
vt status
- Show working tree status - Browse:
vt browse
- Open Val's main page in browser
- Testing: Run tests with
await runTests()
in backend/database/queries_test.tsx - Linting: The project uses Deno's built-in linter configured in deno.json
- Database: Uses SQLite with schema migrations in backend/database/schema.tsx
backend/main.tsx
- Main application entry pointbackend/routes/
- API route handlersbackend/database/
- Database schema and queries (SQLite)- Authentication via OAuth with Val Town
frontend/
- React components and pages- Uses React 18.2.0 (pinned version)
- Custom hooks for API integration
- Local storage for user preferences
*.http.tsx
- HTTP endpoint handlers*_test.tsx
- Test files*Route.tsx
- Route components- Database schema versioning (increment table names vs altering)
The application includes an AI agent system with various tools:
text-editor
- File editing capabilitiesfetch
- HTTP request handlingthink
- Internal reasoningtraces
- Execution tracingchange-val-type
- Val type modifications
- Runtime: Deno
- Backend: Hono framework
- Frontend: React 18.2.0 (pinned)
- Database: SQLite
- Authentication: OAuth (Val Town)
- Styling: CSS modules and inline styles
- State Management: React hooks and context
- Testing: Custom test runner in queries_test.tsx
- Uses SQLite with custom schema management
- Schema versioning pattern: increment table names (_2, _3) instead of altering schemas
- Query functions organized in backend/database/queries.tsx
- Test suite in backend/database/queries_test.tsx
- React components organized by feature
- Custom hooks for API integration
- Local storage for user preferences
- Custom hooks for API integration
- Ask clarifying questions when requirements are ambiguous
- Provide complete, functional solutions rather than skeleton implementations
- Test your logic against edge cases before presenting the final solution
- Build incrementally and test as you go. Clean up after yourself and don't leave technical debt
- Only code if you're 100% certain - continue asking questions until aligned on what to build
- Generate code in TypeScript or TSX
- Add appropriate TypeScript types and interfaces for all data structures
- Prefer official SDKs or libraries rather than writing API calls directly
- Never bake secrets into code - always use environment variables with
Deno.env.get('keyname')
- Include comments explaining complex logic (avoid commenting obvious operations)
- Follow modern ES6+ conventions and functional programming practices
- Read files from base directory
/
directly, not/repo/
- Keep README.md up to date whenever making code changes (unless user asks not to)
- Use str_replace in smaller chunks wherever possible
- Directories are created implicitly when creating files within them
- Pin React to 18.2.0: Use
?deps=react@18.2.0,react-dom@18.2.0
and include/** @jsxImportSource https://esm.sh/react@18.2.0 */
- Use Val Town utilities: Import from
https://esm.town/v/std/utils/index.ts
forreadFile
,serveFile
, etc. - SQLite schema changes: Change table names (e.g.,
_2
,_3
) instead of altering schemas - Error handling: Include Hono error unwrapping:
app.onError((err) => Promise.reject(err))
- Static files: Use
serveFile()
utility, NEVER use Hono'sserveStatic
middleware - Imports: Use
https://esm.sh
for npm packages to ensure browser/server compatibility
// Blob Storage
import { blob } from "https://esm.town/v/std/blob";
// SQLite
import { sqlite } from "https://esm.town/v/stevekrouse/sqlite";
// OpenAI
import { OpenAI } from "https://esm.town/v/std/openai";
// Email
import { email } from "https://esm.town/v/std/email";
- Redirects: Use
c.redirect()
in Hono, ornew Response(null, { status: 302, headers: { Location: "/url" }})
- No binary files: Val Town only supports text files
- No Deno KV: Use SQLite or blob storage instead
- No browser APIs: Don't use
alert()
,prompt()
, orconfirm()
- Error debugging: Add
<script src="https://esm.town/v/std/catch"></script>
to HTML - CORS: Val Town automatically handles CORS - don't import cors middleware
- Use
fetch
tool to debug HTTP vals by making requests and examining responses - Use
requests
tool to debug all kinds of vals - shows logs, headers, status, runtime, errors - Default to smaller changes where possible to minimize code impact