| name | building-edgespark-apps |
| description | Build and modify EdgeSpark apps. Use when a project has edgespark.toml, the user mentions EdgeSpark, or work involves the edgespark CLI, server SDK types, storage/auth/database workflows, deployment, or @edgespark/web. |
EdgeSpark App Development
Use this skill for EdgeSpark-specific implementation and workflow decisions.
This skill is not EdgeSpark documentation. For exact contracts, read source, generated types, CLI help, and docs/Mintlify MCP. Use this skill for workflow, guardrails, and bug-prevention.
The reliable public surface in this repo is:
- the
edgespark CLI
- scaffolded project structure from
edgespark init
- generated
src/__generated__/edgespark.d.ts
- generated
src/__generated__/server-types.d.ts
- the
@edgespark/web browser SDK
Learn from older examples, but do not inherit old patterns blindly. In particular, do not treat @edgespark/client and renderAuthUI() as the default path for new code.
Read Order
Read only what is needed for the task:
edgespark.toml
- repo or project agent instruction file (
AGENTS.md, CLAUDE.md, or GEMINI.md)
src/__generated__/edgespark.d.ts
src/__generated__/server-types.d.ts
src/defs/index.ts, src/defs/db_schema.ts, src/defs/db_relations.ts, src/defs/runtime.ts, src/defs/storage_schema.ts
node_modules/@edgespark/web/dist/index.d.ts when installed
Then load the specific reference you need:
Hard Rules
- Run
edgespark <command> --help before assuming flags or exact behavior.
- Run
edgespark commands on behalf of the user. Only hand off steps that explicitly require a human browser action.
- Never run multiple
edgespark commands in parallel.
- Treat scaffolded
src/__generated__/edgespark.d.ts and src/__generated__/server-types.d.ts as placeholders until edgespark pull types populates them.
- Do not edit files under
src/__generated__/.
- Use
@edgespark/web for new browser code.
- Use
es.api.fetch() for app API calls, not bare fetch() to same-origin app routes.
- Use
authUI.mount() for managed auth UI unless custom forms are explicitly requested.
- For custom browser auth flows, use
client.auth from @edgespark/web, not manual /api/_es/auth/* calls.
- Import
auth from edgespark/http, not edgespark.
- Auth is a managed service at
/api/_es/auth/. OAuth callback URLs use /api/_es/auth/callback/<provider>, not /api/auth/.
- Treat
/api/_es/auth/*, storage provider details, and deployment internals as platform implementation details unless the user is explicitly debugging them.
- Do not import runtime SDK values from
edgespark inside src/defs/**.
- Use
db.batch() instead of db.transaction().
- Use migration workflow for schema changes. Do not use DDL through
edgespark db sql.
- Store S3 URIs in the database and return presigned URLs to clients.
- For client-originated uploads, generate presigned PUT URLs instead of streaming files through the Worker.
- Update
src/defs/runtime.ts before using vars.get() or secret.get().
- Use
edgespark ... --help for exact command syntax instead of duplicating help text in this skill.
- If exact behavior is unclear, prefer source code, generated types, or docs MCP over guessing.
Default Workflow
For the operational workflow by area, read dev-workflow.md.
Existing project
- Read generated type files first.
- Read the relevant defs files before changing schema, storage, or runtime keys.
- Read the web SDK types before touching auth or browser API code.
Fresh scaffold
- Inspect
edgespark.toml to confirm server-only vs full-stack layout.
- If generated files are placeholders, run
edgespark pull types before making SDK assumptions.
- Follow the scaffolded root,
server/, and web/ agent instruction files for package boundaries.
When Stuck
- Read the generated type files again before assuming an API shape.
- Run the relevant
edgespark ... --help command before guessing flags.
- Use docs/Mintlify MCP for product documentation details.
Quick Start
Server:
import { db, storage, vars, secret, ctx } from "edgespark";
import { auth } from "edgespark/http";
import { posts, buckets } from "@defs";
import { Hono } from "hono";
import { eq } from "drizzle-orm";
const app = new Hono()
.get("/api/posts", async (c) => {
return c.json(await db.select().from(posts));
})
.post("/api/posts", async (c) => {
const data = await c.req.json();
const [post] = await db.insert(posts)
.values({ ...data, user_id: auth.user!.id })
.returning();
return c.json(post, 201);
});
export default app;
Web:
import { createEdgeSpark } from "@edgespark/web";
import "@edgespark/web/styles.css";
const es = createEdgeSpark();
es.authUI.mount(document.getElementById("auth")!, {
redirectTo: "/dashboard",
});
const res = await es.api.fetch("/api/posts");
const posts = await res.json();