Files
hanzo.ai/app/page.tsx
zeekay 0910c3cc68 agents: a start page for AI agents, and the site describes itself to them
/agents is where an agent lands: get a key (device flow or HTTP sign-up),
the free tier as /v1/billing/plans states it, a first call, the MCP server
for Claude Code, Codex, Cursor and Zed, Kai and its harness, a campaign
draft, and how an owner pays and bounds spend. The Agents SDK page moves
to /agents/sdk.

The prompt an agent pastes is lib/agents.ts, drawn on /agents and written
into llms.txt, which now keeps every hand-written section. robots.txt names
the AI crawlers; JSON-LD carries the positioning, 2014, the founders as
/about names them, and drops a SearchAction /search never answered;
/.well-known/api-catalog points at the OpenAPI document. /about gains a
track-record band, each line beside its source.

Claude-Session: https://claude.ai/code/session_017vrVus6PPBgP5YRzKV1iqW
2026-10-26 11:45:15 -07:00

75 lines
3.3 KiB
TypeScript

import type { Metadata } from 'next'
import Home from '@/components/home/Home'
import { ogImages, getOgImageUrl, getTwitterImages } from '@/lib/constants/og'
import { BOOT } from '@hanzo/app/lib/session'
import { RETURNED } from '@/lib/auth/returned'
import { Apex } from './_apex'
// The apex. It lives outside the (marketing) route group, so the root layout is
// all that wraps it and it carries its own header and footer.
// The title mirrors the h1's promise, so the tab, search result and first line
// of the page all set the same expectation.
const TITLE = 'Hanzo AI — Better, Faster, Cheaper. Pick Three.'
const DESCRIPTION =
"The AI operating system for business: chat, Dev, Studio and one API on every model. Building business software since 2014 for hundreds of venture-funded startups. Techstars 2017. Start free."
const IMAGE_URL = getOgImageUrl('/')
/**
* The app's addresses before they were paths, which links and bookmarks still
* carry: a conversation, `/?chat=<id>`, is `/chat/<id>` now (@hanzo/app
* lib/host `talk`), and Dev's `/?at=<place>` is `/dev?at=<place>`, which /dev
* replaces with the place's path (app/dev/_door.tsx `moved`). The document moves
* once, before anything is drawn or asked for; the id is carried as one
* encoded segment, so it can only name a conversation.
*/
const MOVED = `try{if(location.hostname==='hanzo.reviews'||location.hostname==='www.hanzo.reviews'){location.replace('/reviews')}var q=new URLSearchParams(location.search),c=q.get('chat'),a=q.get('at');if(c)location.replace('/chat/'+encodeURIComponent(c));else if(a!==null){a=a.replace(/^\\/+/,'');location.replace(a?'/dev?at='+encodeURIComponent(a):'/dev')}}catch(_){}`
export const metadata: Metadata = {
title: TITLE,
description: DESCRIPTION,
alternates: { canonical: 'https://hanzo.ai' },
openGraph: {
title: TITLE,
description: DESCRIPTION,
url: 'https://hanzo.ai',
siteName: 'Hanzo',
type: 'website',
images: ogImages(TITLE, IMAGE_URL),
},
twitter: {
card: 'summary_large_image',
title: TITLE,
description: DESCRIPTION,
images: getTwitterImages(IMAGE_URL),
},
}
/**
* The apex: the landing for a stranger, the web app for a signed-in reader.
*
* `/` is this site's search result and its share card, and every crawler that
* reads them arrives as a stranger — so the export answers with the whole
* landing and the metadata that describes it, byte for byte.
*
* A SIGNED-IN READER IS ANSWERED WITH THE APP (app/_web.tsx), in Chat; Dev is
* the same app at `/dev`. It is the same address, not a trip somewhere else, so
* a sign-in lands here, a reload stays here, and hanzo.ai typed by a member
* opens their work. An old address, `/?chat=` or `/?at=`, moves to its path (`MOVED`). `Apex` decides in
* the browser, because a static export has no server to decide with; `BOOT`
* is the landing's first child and runs before the rest of it is parsed, so the
* pitch never paints at a member while the app loads. An OAuth popup returning
* here hands its answer to its opener and closes before any of it
* (lib/auth/returned `RETURNED`).
*/
export default function Page() {
return (
<Apex>
<script dangerouslySetInnerHTML={{ __html: RETURNED }} />
<script dangerouslySetInnerHTML={{ __html: MOVED }} />
<script dangerouslySetInnerHTML={{ __html: BOOT }} />
<Home />
</Apex>
)
}