One definition · four surfaces

One route() is four surfaces.

June is the opinionated, agent-ready React framework. A single route() serves a page to people and .md, .json, and /mcp to agents — from one definition. Nothing drifts, because nothing is duplicated.

$ npm create june@latest my-app
Why June →
59ms dev cold start0 client JS by default1 auth gate, both audiences
route() · /
June

The opinionated, agent-ready React framework.

01
One definition, four surfaces

HTML to people; .md, .json, and /mcp to agents — derived, never maintained by hand.

02
No glue layer

Auth, data, and agents are one model. run(input, ctx) is the only gate.

03
Data magic

Writes auto-invalidate the cache; reads auto-batch into one query.

npm create june@latest →

01 — One definition

Write it once. Serve humans and agents alike.

Every route() projects four surfaces, and every defineAction() is a UI action and an MCP tool. The projections are derived — never maintained by hand.

text/html

Human view

Server-streamed RSC, zero client JS by default.

text/markdown

Agent reads

The same route(), as clean markdown — append .md to any page.

application/json

Machine API

The same route() as structured data.

/mcp

Agent acts

Every defineAction() is a callable tool, one auth gate.

02 — No glue layer

Auth, data, and agents are one model.

There is no "expose to agents" step and no second permission system. A defineAction() is a server action and an MCP tool behind a single authorization gate — run(input, ctx) is the only gate.

  • one gaterun(input, ctx) — the same ctx whether the caller is your React UI or an agent at /mcp.
  • no adapteryou wire no adapter matrix. The route graph derives the API catalog, sitemap, and llms.txt.
  • authBetter Auth is the blessed default (a first-class integration is coming soon) — or bring your own. Either way the gate is the same.
app/actions.tsts
import { db } from "@junejs/db";  // ambient + scoped — never on ctx

export const createUser = defineAction({
  id: "createUser",
  description: "Create a user",  // → an MCP tool
  input: { name: "string" },
  run: (input, ctx) => {
    // ctx is the principal (user/session) — UI or agent.
    return db.users.insert(input);
  },
});

03 — Agents as scoped users

Watch an agent use your app.

No SDK, no tool re-declaration. Your routes and actions are the surface — an agent connects as a scoped principal and works the same authorization the UI does.

  • /mcpevery action, as a callable tool
  • /llms.txtthe site map an agent reads first
  • *.mdyour authored bytes, verbatim
scoped as user_42
agent session · /mcpscoped as user_42
01
tools/list
search_siteget_pagecreateUser
02
tools/call search_site {"q": "cold start"} auth ✓
3 hits · top: "59ms: anatomy of a dev cold start"
done · 2 tool calls · 71ms · one auth gate

04 — Data

Declare it once. The layer does the rest.

Declare db / kv / blob in your config; reach them ambiently with import { db } — scoped per request, plain SQL, no ORM ceremony. It maps to D1, Turso, or local SQLite per target — or bring your own.

  • ambient dbimport { db }, scoped per request — ctx is identity-only (user/session), never the database.
  • plain SQLthe SQL you read is the SQL that runs — no DSL for a human or an agent to misread.
  • writesauto-invalidate the cache — no revalidatePath, no tags to remember.
  • reads8.8× fewer queries on D1 vs concurrent per-component reads, auto-batched.
app/page.tsxtsx
async function Page() {
  // N reads in N components → 1 batched query
  const user = await db.users.find(id);
  const posts = await db.posts.byAuthor(id);
  return <Profile user={user} posts={posts} />;
}

// a write anywhere auto-invalidates the reads
await db.posts.insert({ ... });  // cache: stale ✓

05 — Start

Ship in an afternoon.

Four commands from empty directory to an app deployed at the edge — already speaking to humans and agents.

01
$ npm create june@latest
Scaffold an app — no adapter matrix to configure.
02
$ june dev
Boot in 59ms. Save → HMR pushes a flight in 73ms.
03
$ june build
Freeze the dev graph into a deployable bundle.
04
$ june deploy
Ship to Workers, Vercel, or Deno — same graph.

06 — Measured, not marketing

Every number traces to a named run.

59ms
dev cold start
73ms
HMR flight
0
client JS default
8.8×
fewer D1 queries
See all benchmarks →

Your app is the agent's API.

One React framework for both audiences. 0.0.x preview — APIs will change, and we'll tell you when.

Stableroutes · projections · actions · MCPChangingdata layer · authExperimentalnative runtime · live RSC
Stability & roadmap →
$ npm create june@latest my-app