mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 07:20:43 +00:00
Every word the landing, the header menus, the phone sheet, the footer,
the help corner and the way in (sign-in, sign-up, the reset, the
invitation, the callback, onboarding, the 404) write goes through
@hanzo/i18n's t(): one sentence is one message, its figures, names and
links arguments; copy written as data is phrase('…') where written and
t(label) where drawn. Plans, the chart, the API states and the lines
lib/kai and lib/enso build for the landing do the same.
Right to left: <html lang dir> is set before the first paint (the
package's bootScript first in the head); a figure, clock, range or
price outside a sentence is isolated; sides are logical gui props, the
layout's [data-join] corners logical, a bar grows from the start;
arrows along the line mirror (Onward for "words ->" links). The repo
dates read in the reader's language.
Gates select by slot, never by an English label (rtl, help). New gate
translated.spec.ts: in Arabic the landing at 1440 and 390, every menu
open, the phone sheet, sign-in, sign-up and the app signed in hold no
authored English, nothing scrolls sideways, every range is isolated;
French the same for English's commonest words. What another package
draws with no words prop is listed by name (@hanzo/ui's Footer label,
@hanzo/build's composer row and suggestions).
@hanzo/i18n 0.5.3 (the catalogs: 1,443 keys, every offered locale
complete), @hanzo/app 0.2.1 (the app's words). The link gate imports
the terms versions from @hanzo/app, the one SDK main now resolves.
359 lines
16 KiB
TypeScript
359 lines
16 KiB
TypeScript
/**
|
||
* Hanzo OS, as the layers a company runs on (HIP-0903).
|
||
*
|
||
* The layers stack from the company down to the machines it runs on, and the
|
||
* Record runs beside all of them: every act on every layer lands in it. The header,
|
||
* the home page, /products, each /products/<id> page and the footer read this
|
||
* file and nothing else.
|
||
*
|
||
* Every path under `ops` is an operation api.hanzo.ai serves, as hanzoai/cloud's
|
||
* openapi.yaml states it, and each `does` is that operation's own summary.
|
||
*/
|
||
|
||
import type { GlyphName } from '@hanzogui/shell'
|
||
import { phrase } from '@hanzo/i18n'
|
||
|
||
export type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
|
||
|
||
/** One operation: what to call, and what it does. */
|
||
export interface Op {
|
||
method: Method
|
||
path: string
|
||
does: string
|
||
}
|
||
|
||
/** A page on this site, or a document on another host. */
|
||
export interface Link {
|
||
label: string
|
||
href: string
|
||
}
|
||
|
||
export interface Layer {
|
||
/** The address segment: /products/<id>. */
|
||
id: string
|
||
/** Its name, marked with `phrase` (@hanzo/i18n) so the header draws it in the reader's language. */
|
||
name: string
|
||
/** The mark it wears in the header's Product menu. */
|
||
glyph: GlyphName
|
||
/** What it is, in one sentence. */
|
||
line: string
|
||
/** What it does, in one paragraph. */
|
||
body: string
|
||
ops: Op[]
|
||
/** A request a reader can paste into a shell. */
|
||
sample: string
|
||
docs: Link[]
|
||
/** This site's pages about the parts of the layer. */
|
||
pages: Link[]
|
||
/** Measured results that stand behind the layer. */
|
||
proofs?: Link[]
|
||
/** The rail beside the stack, not a layer in it. */
|
||
rail?: true
|
||
}
|
||
|
||
export const POSITIONING = 'A human signs a company into existence. After genesis, agents can run it.'
|
||
|
||
const DOCS = 'https://docs.hanzo.ai/docs'
|
||
|
||
const curl = (lines: string[]) => lines.join(' \\\n ')
|
||
const KEY = '-H "Authorization: Bearer $HANZO_API_KEY"'
|
||
const JSON_BODY = '-H "Content-Type: application/json"'
|
||
|
||
export const LAYERS: Layer[] = [
|
||
{
|
||
id: 'company',
|
||
name: phrase('Company'),
|
||
glyph: 'users',
|
||
line: 'The legal body: formation, cap table, documents and filings, as operations.',
|
||
body:
|
||
'Choose a structure, add founders, clear KYC, pay the fee, sign, and record the founding allocation. Each step is one guarded transition of the formation machine, so an agent can drive it and cannot skip a step. The law needs a person three times — identity, signature and the fee — and after genesis the shares, rounds and documents are operations like any other.',
|
||
ops: [
|
||
{ method: 'POST', path: '/v1/company/tariff', does: 'Itemises what a formation costs before anyone commits to it.' },
|
||
{ method: 'POST', path: '/v1/company', does: 'Begins the org’s one formation and returns the stages reachable from it.' },
|
||
{ method: 'POST', path: '/v1/company/advance', does: 'Runs the one guarded transition of the formation machine.' },
|
||
{ method: 'POST', path: '/v1/company/genesis', does: 'Seeds the cap table with the founding allocation and anchors its root on-chain.' },
|
||
{ method: 'GET', path: '/v1/captable/summary', does: 'Computes the org’s cap table.' },
|
||
{ method: 'POST', path: '/v1/legal/documents', does: 'Renders a document from a template and seals it in the org’s store.' },
|
||
],
|
||
sample: curl([
|
||
'curl https://api.hanzo.ai/v1/company/tariff',
|
||
KEY,
|
||
JSON_BODY,
|
||
`-d '{"structure": "c-corp", "jurisdiction": "DE"}'`,
|
||
]),
|
||
docs: [
|
||
{ label: 'Company API', href: `${DOCS}/openapi/company` },
|
||
{ label: 'Cap table API', href: `${DOCS}/openapi/captable` },
|
||
{ label: 'hanzo company', href: `${DOCS}/cli/company` },
|
||
],
|
||
pages: [
|
||
{ label: 'Cap table', href: '/captable' },
|
||
{ label: 'Data room', href: '/dataroom' },
|
||
{ label: 'Sign', href: '/sign' },
|
||
{ label: 'Commerce', href: '/commerce' },
|
||
{ label: 'Billing', href: '/billing' },
|
||
{ label: 'Payments', href: '/payments' },
|
||
{ label: 'Treasury', href: '/treasury' },
|
||
{ label: 'Ledger', href: '/ledger' },
|
||
{ label: 'Risk', href: '/risk' },
|
||
],
|
||
},
|
||
{
|
||
id: 'agents',
|
||
name: phrase('Agents'),
|
||
glyph: 'bot',
|
||
line: 'Workers the company keeps: a model, instructions, tools and a budget.',
|
||
body:
|
||
'An agent is defined once in the org and run by name. Every run is recorded with its input, output, model and duration, and a session carries a cap it cannot exceed. Each subsystem’s operations are MCP tools, so an agent reaches the same surface a founder does.',
|
||
ops: [
|
||
{ method: 'POST', path: '/v1/agent', does: 'Defines an agent in the org: a model, instructions and a set of tools.' },
|
||
{ method: 'POST', path: '/v1/agent/{ref}/run', does: 'Runs one of the org’s agents and returns the recorded run.' },
|
||
{ method: 'GET', path: '/v1/agent/{ref}/spend', does: 'Answers what one agent has spent, in micro-USD.' },
|
||
{ method: 'POST', path: '/v1/agent/sessions', does: 'Opens a live agent session in the org.' },
|
||
{ method: 'POST', path: '/v1/agent/sessions/{id}/budget', does: 'Sets, raises, or removes a session’s cap.' },
|
||
{ method: 'POST', path: '/v1/mcp', does: 'Every subsystem’s operations as MCP tools.' },
|
||
],
|
||
sample: [
|
||
curl([
|
||
'curl https://api.hanzo.ai/v1/agent',
|
||
KEY,
|
||
JSON_BODY,
|
||
`-d '{"name": "helper", "model": "enso-flash", "instructions": "be terse", "cap_micro_usd": 5000000, "period": "month"}'`,
|
||
]),
|
||
'',
|
||
curl([
|
||
'curl https://api.hanzo.ai/v1/agent/helper/run',
|
||
KEY,
|
||
JSON_BODY,
|
||
`-d '{"input": "Summarise yesterday’s signups"}'`,
|
||
]),
|
||
].join('\n'),
|
||
docs: [
|
||
{ label: 'Agents API', href: `${DOCS}/openapi/agents` },
|
||
{ label: 'Agents, the concept', href: `${DOCS}/concepts/agents` },
|
||
],
|
||
pages: [
|
||
{ label: 'Agents SDK', href: '/agents' },
|
||
{ label: 'Bot', href: '/bot' },
|
||
{ label: 'MCP', href: '/mcp' },
|
||
{ label: 'Skills', href: '/skills' },
|
||
{ label: 'Computer', href: '/computer' },
|
||
{ label: 'Operative', href: '/operative' },
|
||
{ label: 'Auto', href: '/auto' },
|
||
{ label: 'Automations', href: '/automations' },
|
||
{ label: 'Flow', href: '/flow' },
|
||
{ label: 'Extension', href: '/extension' },
|
||
{ label: 'CLI', href: '/cli' },
|
||
],
|
||
},
|
||
{
|
||
id: 'models',
|
||
name: phrase('Models'),
|
||
glyph: 'spark',
|
||
line: 'Every model behind one endpoint and one key.',
|
||
body:
|
||
'Send a request to api.hanzo.ai and name a model. The same request reaches Enso, Zen or a model another lab serves, in the wire format your client already speaks — OpenAI chat completions and responses, or Anthropic messages.',
|
||
ops: [
|
||
{ method: 'GET', path: '/v1/models', does: 'Returns the models the routing table serves.' },
|
||
{ method: 'POST', path: '/v1/chat/completions', does: 'The OpenAI-compatible chat completions API.' },
|
||
{ method: 'POST', path: '/v1/responses', does: 'The OpenAI-compatible responses API.' },
|
||
{ method: 'POST', path: '/v1/messages', does: 'The Anthropic Messages API.' },
|
||
{ method: 'POST', path: '/v1/embeddings', does: 'OpenAI-compatible embeddings.' },
|
||
],
|
||
sample: curl([
|
||
'curl https://api.hanzo.ai/v1/chat/completions',
|
||
KEY,
|
||
JSON_BODY,
|
||
`-d '{"model": "zen5", "messages": [{"role": "user", "content": "Hello"}]}'`,
|
||
]),
|
||
docs: [
|
||
{ label: 'Models', href: `${DOCS}/models` },
|
||
{ label: 'Chat completions', href: `${DOCS}/openapi/ai/post-chat-completions` },
|
||
],
|
||
pages: [
|
||
{ label: 'Model catalog', href: '/models' },
|
||
{ label: 'Enso', href: '/enso' },
|
||
{ label: 'Zen', href: '/zen' },
|
||
{ label: 'One API', href: '/api' },
|
||
{ label: 'Engine', href: '/engine' },
|
||
{ label: 'Gateway', href: '/gateway' },
|
||
{ label: 'Guard', href: '/guard' },
|
||
{ label: 'Jin', href: '/jin' },
|
||
],
|
||
},
|
||
{
|
||
id: 'memory',
|
||
name: phrase('Memory'),
|
||
glyph: 'base',
|
||
line: 'What the company knows, and when it knew it.',
|
||
body:
|
||
'The graph records assertions — an entity, a relation, a value, who said it and when it was so — and never overwrites one. A read takes two instants: as_of for when the world was so, as_known for how much had been heard. So a past answer can be reproduced exactly, and a correction does not erase what was believed before it. Each org’s own data lives in its Base, a SQLite store of its own.',
|
||
ops: [
|
||
{ method: 'POST', path: '/v1/graph', does: 'Asserts what is true of an entity.' },
|
||
{ method: 'GET', path: '/v1/graph', does: 'Reads the assertions the org has recorded, bounded by as_of and as_known.' },
|
||
{ method: 'POST', path: '/v1/graph/resolve', does: 'What is in force about an entity as of an instant, and what disagreed.' },
|
||
{ method: 'POST', path: '/v1/graph/diff', does: 'What came into force, was superseded and was retracted between two instants.' },
|
||
{ method: 'POST', path: '/v1/graph/answer', does: 'Answers a question from the whole graph, citing the assertions it rests on.' },
|
||
{ method: 'GET', path: '/v1/base/bases', does: 'Lists every Base the caller can reach, one per org.' },
|
||
],
|
||
sample: [
|
||
curl([
|
||
'curl https://api.hanzo.ai/v1/graph',
|
||
KEY,
|
||
JSON_BODY,
|
||
`-d '{"assertions": [{"entity": "acme/svc/api", "relation": "owner", "value": "acme/team/core", "names": true, "at": "2026-01-05T00:00:00Z", "source": "wiki/api"}]}'`,
|
||
]),
|
||
'',
|
||
curl([
|
||
'curl https://api.hanzo.ai/v1/graph/resolve',
|
||
KEY,
|
||
JSON_BODY,
|
||
`-d '{"entity": "acme/svc/api", "relation": "owner", "as_of": "2026-03-01T00:00:00Z", "as_known": "2026-02-01T00:00:00Z"}'`,
|
||
]),
|
||
].join('\n'),
|
||
docs: [
|
||
{ label: 'Graph API', href: `${DOCS}/openapi/graph` },
|
||
{ label: 'Memory, the concept', href: `${DOCS}/concepts/memory` },
|
||
{ label: 'hanzo graph', href: `${DOCS}/cli/graph` },
|
||
],
|
||
pages: [
|
||
{ label: 'Base', href: '/base' },
|
||
{ label: 'Search', href: '/search' },
|
||
{ label: 'Datastore', href: '/datastore' },
|
||
{ label: 'Object storage', href: '/s3' },
|
||
],
|
||
proofs: [
|
||
{ label: 'CronQuestions: point-in-time questions answered through /v1/graph', href: '/benchmarks/cronquestions' },
|
||
{ label: 'LoCoMo: multi-hop ALL@20 from 18.8 to 37.5 on the held-out split', href: '/benchmarks/locomo' },
|
||
{ label: 'LongMemEval-S: 500 questions over 4,846 sessions, top-five evidence 90.6% against 85.8% for cosine', href: '/benchmarks/longmemeval' },
|
||
{ label: 'MemoryAgentBench: FactConsolidation substring EM from 33 to 67 on a 262k haystack', href: '/benchmarks/memoryagentbench' },
|
||
],
|
||
},
|
||
{
|
||
id: 'identity',
|
||
name: phrase('Identity'),
|
||
glyph: 'shield',
|
||
line: 'Who is acting — a person, a program or an agent — and what it may reach.',
|
||
body:
|
||
'One issuer for every principal. A person signs in, a program trades its client credentials for a token, and every request carries the org it acts for. Keys are scoped to what they may reach, and secrets are held per org, never in the code that uses them.',
|
||
ops: [
|
||
{ method: 'POST', path: '/v1/iam/oauth/token', does: 'Exchanges a sign-in code, a refresh token or client credentials for tokens.' },
|
||
{ method: 'GET', path: '/v1/iam/oauth/userinfo', does: 'Returns the profile claims for whoever the access token belongs to.' },
|
||
{ method: 'POST', path: '/v1/iam/keys', does: 'Issues an API key.' },
|
||
{ method: 'GET', path: '/v1/kms/secrets', does: 'Lists the secrets the org holds, without their values.' },
|
||
{ method: 'POST', path: '/v1/kms/secrets', does: 'Stores or replaces one secret in the org.' },
|
||
],
|
||
sample: [
|
||
curl([
|
||
'curl https://api.hanzo.ai/v1/iam/oauth/token',
|
||
'-d grant_type=client_credentials',
|
||
'-d client_id=$CLIENT_ID',
|
||
'-d client_secret=$CLIENT_SECRET',
|
||
]),
|
||
'',
|
||
curl(['curl https://api.hanzo.ai/v1/iam/oauth/userinfo', '-H "Authorization: Bearer $ACCESS_TOKEN"']),
|
||
].join('\n'),
|
||
docs: [
|
||
{ label: 'IAM API', href: `${DOCS}/openapi/iam` },
|
||
{ label: 'KMS API', href: `${DOCS}/openapi/kms` },
|
||
{ label: 'IAM SDK', href: `${DOCS}/sdks/iam` },
|
||
],
|
||
pages: [
|
||
{ label: 'IAM', href: '/iam' },
|
||
{ label: 'Identity', href: '/identity' },
|
||
{ label: 'Authz', href: '/authz' },
|
||
{ label: 'KMS', href: '/kms' },
|
||
{ label: 'HSM', href: '/hsm' },
|
||
{ label: 'IDV', href: '/idv' },
|
||
],
|
||
},
|
||
{
|
||
id: 'machines',
|
||
name: phrase('Machines'),
|
||
glyph: 'cpu',
|
||
line: 'Real computers, leased by the org, for agents and for the software they ship.',
|
||
body:
|
||
'Lease a sandbox and run commands in it, launch a metered machine, or publish a function. Each is the org’s own and each is billed to it, so an agent that needs a computer asks for one the same way a person would.',
|
||
ops: [
|
||
{ method: 'POST', path: '/v1/sandbox', does: 'Leases a sandbox — a real computer — for the org.' },
|
||
{ method: 'POST', path: '/v1/sandbox/{id}/exec', does: 'Runs one command in a sandbox and answers with its exit code, stdout and stderr.' },
|
||
{ method: 'GET', path: '/v1/compute/sizes', does: 'Lists the machine sizes available to launch.' },
|
||
{ method: 'POST', path: '/v1/compute/machines', does: 'Launches a metered machine, or prices one first with dryRun.' },
|
||
{ method: 'POST', path: '/v1/function', does: 'Publishes a serverless function under the org.' },
|
||
{ method: 'POST', path: '/v1/function/{name}/invoke', does: 'Runs a function and records the invocation.' },
|
||
],
|
||
sample: [
|
||
curl(['curl https://api.hanzo.ai/v1/sandbox', KEY, JSON_BODY, `-d '{"class": "exec"}'`]),
|
||
'',
|
||
curl([
|
||
'curl https://api.hanzo.ai/v1/sandbox/$SANDBOX/exec',
|
||
KEY,
|
||
JSON_BODY,
|
||
`-d '{"argv": ["uname", "-a"]}'`,
|
||
]),
|
||
].join('\n'),
|
||
docs: [
|
||
{ label: 'Sandbox API', href: `${DOCS}/openapi/sandbox` },
|
||
{ label: 'Visor API', href: `${DOCS}/openapi/visor` },
|
||
{ label: 'Functions API', href: `${DOCS}/openapi/functions` },
|
||
],
|
||
pages: [
|
||
{ label: 'Machines', href: '/machines' },
|
||
{ label: 'Visor', href: '/visor' },
|
||
{ label: 'Functions', href: '/functions' },
|
||
{ label: 'Edge', href: '/edge' },
|
||
{ label: 'Registry', href: '/registry' },
|
||
{ label: 'Operator', href: '/operator' },
|
||
{ label: 'Ingress', href: '/ingress' },
|
||
{ label: 'DNS', href: '/dns' },
|
||
{ label: 'Tunnel', href: '/tunnel' },
|
||
{ label: 'ZAP', href: '/zap' },
|
||
{ label: 'PubSub', href: '/pubsub' },
|
||
{ label: 'Stream', href: '/stream' },
|
||
{ label: 'MQ', href: '/mq' },
|
||
],
|
||
},
|
||
{
|
||
id: 'record',
|
||
name: phrase('Record'),
|
||
glyph: 'pulse',
|
||
rail: true,
|
||
line: 'Every act on every layer, by a person or an agent, in one trail.',
|
||
body:
|
||
'The audit trail names who did what to which resource and how it came out. Events and usage say what the company did and what it cost. An agent’s run is recorded the same way a person’s request is, which is what lets a company read what its agents did before it gives them more room.',
|
||
ops: [
|
||
{ method: 'GET', path: '/v1/audit', does: 'Reads the org’s own audit trail, newest first.' },
|
||
{ method: 'POST', path: '/v1/event', does: 'Captures product events into the org’s warehouse.' },
|
||
{ method: 'GET', path: '/v1/usage/summary', does: 'The org’s usage footprint over one window.' },
|
||
{ method: 'GET', path: '/v1/agent/runs', does: 'The org’s agent runs across every agent, newest first.' },
|
||
],
|
||
sample: curl([
|
||
'curl "https://api.hanzo.ai/v1/audit?action=machine.create&since=2026-09-01T00:00:00Z"',
|
||
KEY,
|
||
]),
|
||
docs: [
|
||
{ label: 'Audit API', href: `${DOCS}/openapi/audit` },
|
||
{ label: 'Event API', href: `${DOCS}/openapi/event` },
|
||
{ label: 'Usage API', href: `${DOCS}/openapi/usage` },
|
||
],
|
||
pages: [
|
||
{ label: 'O11y', href: '/o11y' },
|
||
{ label: 'Metrics', href: '/metrics' },
|
||
{ label: 'Telemetry', href: '/telemetry' },
|
||
{ label: 'Analytics', href: '/analytics' },
|
||
{ label: 'Insights', href: '/insights' },
|
||
{ label: 'Dashboards', href: '/dashboards' },
|
||
{ label: 'Sentinel', href: '/sentinel' },
|
||
{ label: 'Console', href: '/console' },
|
||
{ label: 'World', href: '/world' },
|
||
],
|
||
},
|
||
]
|
||
|
||
/** The address of a layer's page. */
|
||
export const href = (l: Layer) => `/products/${l.id}`
|
||
|
||
/** The layer at an id. */
|
||
export const layer = (id: string): Layer | undefined => LAYERS.find((l) => l.id === id)
|
||
|