Val Town Platform Reference

Preserved vendor-platform reference for uAgents. Follow AGENTS.md and ../AGENTS.md when a local convention differs.

Core Guidelines

  • Ask clarifying questions when requirements are ambiguous.
  • Provide complete, functional solutions rather than skeleton implementations.
  • Test logic against edge cases before presenting it.
  • Follow Val Town platform requirements.
  • Refactor into subcomponents when a section becomes too complex.

Code Standards

  • Generate TypeScript or TSX.
  • Add types and interfaces for data structures.
  • Prefer official SDKs or libraries over direct API calls.
  • Ask for API or library documentation when it is needed to resolve uncertainty.
  • Never put secrets in code; use environment variables.
  • Comment complex logic, not obvious operations.
  • Prefer modern ES6+ and functional patterns where suitable.

Trigger Types

HTTP Trigger

Create web APIs and endpoints. HTTP-trigger files contain http in their name.

export default async function (req: Request) { return new Response("Hello World"); }

Cron Trigger

Run scheduled work. Cron-trigger files contain cron in their name.

export default async function () { // Scheduled task code }

Email Trigger

Process incoming emails. Email-trigger files contain email in their name.

export default async function (email: Email) { // Process email }

Val Town Standard Libraries

Blob Storage

import { blob } from "https://esm.town/v/std/blob"; await blob.setJSON("myKey", { hello: "world" }); const value = await blob.getJSON("myKey"); const keys = await blob.list("app_"); await blob.delete("myKey");

SQLite

import { sqlite } from "https://esm.town/v/stevekrouse/sqlite"; const tableName = "todo_app_users_2"; await sqlite.execute(`CREATE TABLE IF NOT EXISTS ${tableName} ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL )`); const result = await sqlite.execute(`SELECT * FROM ${tableName} WHERE id = ?`, [1]);

Change the table name when a schema changes to create a fresh table. Run creation before querying.

OpenAI

import { OpenAI } from "https://esm.town/v/std/openai"; const openai = new OpenAI(); const completion = await openai.chat.completions.create({ messages: [{ role: "user", content: "Say hello in a creative way" }], model: "gpt-4o-mini", max_tokens: 30, });

Email

import { email } from "https://esm.town/v/std/email"; await email({ subject: "Hi", text: "Hi", html: "<h1>Hi</h1>", });

Utility Imports

Pin utility imports to a version:

import { parseProject, readFile, serveFile } from "https://esm.town/v/std/utils@85-main/index.ts";

serveFile

app.get("/frontend/*", (c) => serveFile(c.req.path, import.meta.url)); app.get("/shared/*", (c) => serveFile(c.req.path, import.meta.url));

readFile

const fileContent = await readFile("/frontend/index.html", import.meta.url);

listFiles

const files = await listFiles(import.meta.url);

parseProject

const projectVal = parseProject(import.meta.url); console.log(projectVal.username); console.log(projectVal.name); console.log(projectVal.version); console.log(projectVal.branch); console.log(projectVal.links.self.project);

parseProject and the other standard-library utilities run only on the server. Pass needed data to the client through HTML or an API request.

Platform Specifics

  • Redirect with new Response(null, { status: 302, headers: { Location: "/place/to/redirect" }}) rather than Response.redirect.
  • Avoid external or base64 images. Prefer emoji, Unicode, icon libraries, or platform-supported image generation.
  • Use <img src="https://maxm-imggenurl.web.val.run/the-description-of-your-image" /> for inline AI images.
  • Do not use Deno KV for storage.
  • Do not use browser alert(), prompt(), or confirm().
  • Use Open-Meteo for weather unless the task says otherwise.
  • Add a view-source link from import.meta.url.replace("ems.sh", "val.town") with target="_top".
  • Add <script src="https://esm.town/v/std/catch"></script> to capture client errors.
  • Use try/catch only with a clear local resolution; let contextual errors bubble.
  • Read environment variables with Deno.env.get("KEY"); prefer APIs that avoid keys when possible.
  • Use https://esm.sh for npm and Deno dependencies that must work on server and browser.
  • Prefer static client-side sites unless backend storage is explicitly required.

React and Styling

When React is needed, pin matching versions and put this first in the file:

/** @jsxImportSource https://esm.sh/react@18.2.0 */

Pin React and its dependencies consistently. The generic platform default is Tailwind through <script src="https://cdn.twind.style" crossorigin></script>; uAgents instead follows the local beer.css conventions in ../AGENTS.md.

├── backend/
│   ├── database/
│   │   ├── migrations.ts
│   │   ├── queries.ts
│   │   └── README.md
│   ├── routes/
│   │   ├── [route].ts
│   │   └── static.ts
│   └── index.ts
├── frontend/
│   ├── components/
│   │   ├── App.tsx
│   │   └── [Component].tsx
│   ├── favicon.svg
│   ├── index.html
│   ├── index.tsx
│   ├── README.md
│   └── style.css
├── README.md
└── shared/
    └── utils.ts

Backend (Hono) Patterns

  • Use Hono for APIs.
  • Keep the entry point at backend/index.ts.
  • Serve static assets with serveFile.
  • Create RESTful CRUD routes.
  • Re-throw Hono errors to retain original error detail:
app.onError((err, c) => { throw err; });

For an HTML entry point that needs initial server data, read the file, fetch the data, inject a serialized script before </head>, and return c.html(html).

Database Patterns

  • Run migrations on startup or comment them out when performance requires it.
  • Change table names instead of altering existing SQLite tables.
  • Export clear, typed query functions.

Common Gotchas

  1. Val Town runs Deno serverlessly, not Node.js.
  2. Code in shared/ must work in browser and server contexts; do not use Deno there.
  3. Use https://esm.sh imports that work in both contexts.
  4. SQLite has limited ALTER TABLE support; create a new table and copy data for schema changes.
  5. Pin React to 18.2.0 consistently; mismatched versions cause rendering issues.
  6. Val Town supports text files only. Use readFile helpers to read project files across branches and forks.
  7. A fetch handler is the HTTP entry point: export default app.fetch.

Key Files

  • AGENTS.md — uAgents-local conventions and module map
  • ../AGENTS.md — Val Town repository conventions
  • README.md — uAgents architecture and operating contracts