mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-24 20:09:02 +00:00
chore: update bot-docs, cloud, SDKs, and project index
Sync uncommitted changes across bot-docs, cloud, and docs apps. Add SDK documentation and project registry.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
name: Deploy Cloud Landing Page
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [dev]
|
||||
paths:
|
||||
- 'apps/cloud/**'
|
||||
- '.github/workflows/deploy-cloud.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: hanzoai/cloud-site
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: pnpm
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm --filter @hanzo/cloud build
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: apps/cloud/Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
|
||||
|
||||
- name: Deploy to K8s
|
||||
uses: digitalocean/action-doctl@v2
|
||||
with:
|
||||
token: ${{ secrets.DO_API_TOKEN }}
|
||||
|
||||
- name: Rollout new image
|
||||
run: |
|
||||
doctl kubernetes cluster kubeconfig save ${{ secrets.DO_K8S_CLUSTER_ID }}
|
||||
kubectl -n hanzo set image deployment/cloud cloud=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
|
||||
kubectl -n hanzo rollout status deployment/cloud --timeout=120s
|
||||
@@ -0,0 +1,38 @@
|
||||
name: Deploy Zen Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [dev]
|
||||
paths:
|
||||
- 'apps/zen-docs/**'
|
||||
- 'packages/**'
|
||||
- 'pnpm-lock.yaml'
|
||||
- '.github/workflows/deploy-zen-docs.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
deployments: write
|
||||
pages: write
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: pnpm
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
|
||||
- run: pnpm build --filter=zen-docs
|
||||
|
||||
- run: npx wrangler pages deploy apps/zen-docs/out --project-name=zen-docs --commit-dirty=true
|
||||
env:
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
@@ -1,12 +1,12 @@
|
||||
# Hanzo Docs
|
||||
|
||||
The documentation framework for Hanzo AI, Lux Network, and Zoo Labs Foundation.
|
||||
The documentation framework for Hanzo AI, Lux Network, Zoo Labs Foundation, and Zen LM.
|
||||
|
||||
A powerful React.js documentation framework built for the Hanzo ecosystem.
|
||||
|
||||
## Features
|
||||
|
||||
- **Multi-Brand Support**: Unified framework supporting Hanzo, Lux, and Zoo documentation
|
||||
- **Multi-Brand Support**: Unified framework supporting Hanzo, Lux, Zoo, and Zen documentation
|
||||
- **Next.js 15+**: Built on the latest Next.js with App Router
|
||||
- **MDX**: Write documentation in MDX with full component support
|
||||
- **Search**: Built-in search with Orama and Algolia support
|
||||
@@ -33,7 +33,11 @@ pnpm build
|
||||
```
|
||||
.
|
||||
├── apps/
|
||||
│ └── docs/ # Main documentation site
|
||||
│ ├── docs/ # Main documentation site
|
||||
│ ├── dev-docs/ # Hanzo Dev CLI docs
|
||||
│ ├── zen-docs/ # Zen LM model docs (zenlm.org)
|
||||
│ ├── zap-docs/ # ZAP protocol docs
|
||||
│ └── bot-docs/ # Bot documentation
|
||||
├── packages/
|
||||
│ ├── brand/ # Brand configuration (Hanzo, Lux, Zoo)
|
||||
│ ├── core/ # Core functionality
|
||||
@@ -50,7 +54,7 @@ Set the brand via environment variable:
|
||||
|
||||
```bash
|
||||
# .env.local
|
||||
NEXT_PUBLIC_BRAND=hanzo # or 'lux' or 'zoo'
|
||||
NEXT_PUBLIC_BRAND=hanzo # or 'lux', 'zoo', or 'zen'
|
||||
```
|
||||
|
||||
### Available Brands
|
||||
@@ -60,6 +64,7 @@ NEXT_PUBLIC_BRAND=hanzo # or 'lux' or 'zoo'
|
||||
| `hanzo` | Hanzo AI Inc | [hanzoai.github.io/docs](https://hanzoai.github.io/docs) |
|
||||
| `lux` | Lux Network | [docs.lux.network](https://docs.lux.network) |
|
||||
| `zoo` | Zoo Labs Foundation | [docs.zoo.ngo](https://docs.zoo.ngo) |
|
||||
| `zen` | Zen LM | [zenlm.org](https://zenlm.org) |
|
||||
|
||||
## Development
|
||||
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { CopyIcon, CheckIcon, DownloadIcon } from 'lucide-react';
|
||||
|
||||
type Mode = 'oneliner' | 'quick' | 'hackable' | 'macos';
|
||||
type PM = 'npm' | 'pnpm';
|
||||
type OS = 'unix' | 'windows';
|
||||
type WinShell = 'powershell' | 'cmd';
|
||||
type HackableMode = 'installer' | 'pnpm';
|
||||
|
||||
const WINDOWS_PS = 'iwr -useb https://hanzo.bot/install.ps1 | iex';
|
||||
const WINDOWS_PS_BETA = '& ([scriptblock]::Create((iwr -useb https://hanzo.bot/install.ps1))) -Tag beta';
|
||||
const WINDOWS_CMD = 'curl -fsSL https://hanzo.bot/install.cmd -o install.cmd && install.cmd && del install.cmd';
|
||||
const WINDOWS_CMD_BETA = 'curl -fsSL https://hanzo.bot/install.cmd -o install.cmd && install.cmd --tag beta && del install.cmd';
|
||||
|
||||
function CopyButton({ text }: { text: string }) {
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const copy = useCallback(async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
} catch {}
|
||||
}, [text]);
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={copy}
|
||||
className={`opacity-60 group-hover/line:opacity-100 ml-auto flex items-center justify-center w-7 h-7 border-none rounded-md cursor-pointer transition-all shrink-0 ${
|
||||
copied ? 'bg-[rgba(0,229,204,0.2)] text-[#00e5cc]' : 'bg-[rgba(255,255,255,0.1)] text-fd-muted-foreground hover:bg-[rgba(255,255,255,0.2)] hover:text-fd-foreground'
|
||||
}`}
|
||||
title="Copy"
|
||||
>
|
||||
{copied ? <CheckIcon className="w-3.5 h-3.5" /> : <CopyIcon className="w-3.5 h-3.5" />}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function TabButton({ active, onClick, children, variant = 'mode' }: {
|
||||
active: boolean;
|
||||
onClick: () => void;
|
||||
children: React.ReactNode;
|
||||
variant?: 'mode' | 'option' | 'beta';
|
||||
}) {
|
||||
const base = 'font-mono text-[0.7rem] px-2.5 py-1 border-none rounded cursor-pointer transition-all';
|
||||
const styles = {
|
||||
mode: active
|
||||
? `${base} bg-[#00e5cc] text-[#050810] font-semibold`
|
||||
: `${base} bg-transparent text-fd-muted-foreground hover:text-fd-secondary-foreground`,
|
||||
option: active
|
||||
? `${base} bg-brand text-[#050810] font-semibold`
|
||||
: `${base} bg-transparent text-fd-muted-foreground hover:text-fd-secondary-foreground`,
|
||||
beta: active
|
||||
? `${base} bg-[rgba(0,229,204,0.15)] border border-[#00e5cc] text-[#00e5cc]`
|
||||
: `${base} bg-transparent border border-fd-border text-fd-muted-foreground hover:border-[#00e5cc] hover:text-[#00e5cc]`,
|
||||
};
|
||||
return <button onClick={onClick} className={styles[variant]}>{children}</button>;
|
||||
}
|
||||
|
||||
export function InstallTabs() {
|
||||
const [mode, setMode] = useState<Mode>('oneliner');
|
||||
const [pm, setPm] = useState<PM>('npm');
|
||||
const [os, setOs] = useState<OS>('unix');
|
||||
const [winShell, setWinShell] = useState<WinShell>('powershell');
|
||||
const [hackable, setHackable] = useState<HackableMode>('installer');
|
||||
const [beta, setBeta] = useState(false);
|
||||
const [osPickerOpen, setOsPickerOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof navigator !== 'undefined') {
|
||||
const isWin = navigator.platform?.toLowerCase().includes('win') ||
|
||||
navigator.userAgent?.toLowerCase().includes('windows');
|
||||
if (isWin) setOs('windows');
|
||||
}
|
||||
}, []);
|
||||
|
||||
const getOnelinerCmd = () => {
|
||||
if (os === 'unix') return beta
|
||||
? 'curl -fsSL https://hanzo.bot/install.sh | bash -s -- --beta'
|
||||
: 'curl -fsSL https://hanzo.bot/install.sh | bash';
|
||||
if (winShell === 'cmd') return beta ? WINDOWS_CMD_BETA : WINDOWS_CMD;
|
||||
return beta ? WINDOWS_PS_BETA : WINDOWS_PS;
|
||||
};
|
||||
|
||||
const getInstallCmd = () => {
|
||||
const suffix = beta ? '@beta' : '';
|
||||
return pm === 'npm' ? `npm i -g hanzo-bot${suffix}` : `pnpm add -g hanzo-bot${suffix}`;
|
||||
};
|
||||
|
||||
const comments = {
|
||||
oneliner: beta
|
||||
? "# Living on the edge. Bugs are features you found first."
|
||||
: "# Works everywhere. Installs everything. You're welcome.",
|
||||
quickInstall: beta ? '# Install Hanzo Bot (beta)' : '# Install Hanzo Bot',
|
||||
quickOnboard: beta ? '# Meet your experimental bot' : '# Meet your bot',
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="mb-14">
|
||||
<h2 className="text-xl font-semibold flex items-center gap-2.5 mb-5">
|
||||
<span className="text-brand font-bold">⟩</span> Quick Start
|
||||
</h2>
|
||||
<div className="rounded-xl border border-fd-border bg-fd-muted/30 overflow-hidden">
|
||||
{/* Header */}
|
||||
<div className="flex items-center gap-2 px-4 py-3 bg-[rgba(0,0,0,0.3)] border-b border-fd-border flex-wrap">
|
||||
<span className="w-3 h-3 rounded-full bg-[#ff5f57]" />
|
||||
<span className="w-3 h-3 rounded-full bg-[#febc2e]" />
|
||||
<span className="w-3 h-3 rounded-full bg-[#28c840]" />
|
||||
|
||||
<div className="flex gap-1 bg-[rgba(0,0,0,0.3)] p-0.5 rounded-md ml-2">
|
||||
{(['oneliner', 'quick', 'hackable', 'macos'] as Mode[]).map((m) => (
|
||||
<TabButton key={m} active={mode === m} onClick={() => { setMode(m); setOsPickerOpen(false); }} variant="mode">
|
||||
{m === 'oneliner' ? 'One-liner' : m === 'quick' ? 'npm' : m === 'hackable' ? 'Hackable' : 'macOS'}
|
||||
</TabButton>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{mode === 'oneliner' && !osPickerOpen && (
|
||||
<div className="flex items-center gap-2 ml-auto font-mono text-xs text-fd-muted-foreground">
|
||||
<span className="text-fd-secondary-foreground">{os === 'unix' ? 'macOS/Linux' : 'Windows'}</span>
|
||||
<button
|
||||
onClick={() => setOsPickerOpen(true)}
|
||||
className="bg-none border-none text-brand font-mono text-[0.7rem] cursor-pointer px-1.5 py-0.5 rounded hover:bg-[rgba(255,77,77,0.15)] hover:text-[#00e5cc] transition-all"
|
||||
>
|
||||
change
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{mode === 'oneliner' && osPickerOpen && (
|
||||
<div className="flex gap-1 bg-[rgba(0,0,0,0.3)] p-0.5 rounded-md ml-auto">
|
||||
<TabButton active={os === 'unix'} onClick={() => { setOs('unix'); setOsPickerOpen(false); }} variant="option">macOS/Linux</TabButton>
|
||||
<TabButton active={os === 'windows'} onClick={() => { setOs('windows'); setOsPickerOpen(false); }} variant="option">Windows</TabButton>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{mode === 'oneliner' && os === 'windows' && (
|
||||
<div className="flex gap-1 bg-[rgba(0,0,0,0.3)] p-0.5 rounded-md ml-2">
|
||||
<TabButton active={winShell === 'powershell'} onClick={() => setWinShell('powershell')} variant="option">PowerShell</TabButton>
|
||||
<TabButton active={winShell === 'cmd'} onClick={() => setWinShell('cmd')} variant="option">CMD</TabButton>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{mode === 'quick' && (
|
||||
<div className="flex gap-1 bg-[rgba(0,0,0,0.3)] p-0.5 rounded-md ml-auto">
|
||||
<TabButton active={pm === 'npm'} onClick={() => setPm('npm')} variant="option">npm</TabButton>
|
||||
<TabButton active={pm === 'pnpm'} onClick={() => setPm('pnpm')} variant="option">pnpm</TabButton>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{mode === 'hackable' && (
|
||||
<div className="flex gap-1 bg-[rgba(0,0,0,0.3)] p-0.5 rounded-md ml-auto">
|
||||
<TabButton active={hackable === 'installer'} onClick={() => setHackable('installer')} variant="option">installer</TabButton>
|
||||
<TabButton active={hackable === 'pnpm'} onClick={() => setHackable('pnpm')} variant="option">pnpm</TabButton>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(mode === 'oneliner' || mode === 'quick') && (
|
||||
<div className="ml-2">
|
||||
<TabButton active={beta} onClick={() => setBeta(!beta)} variant="beta">
|
||||
<span className="font-bold text-[0.8rem]">β</span>{' '}
|
||||
<span className="uppercase tracking-wider">Beta</span>
|
||||
</TabButton>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="px-5 py-4 font-mono text-sm leading-relaxed">
|
||||
{mode === 'oneliner' && (
|
||||
<>
|
||||
<div className="text-fd-muted-foreground italic py-1">{comments.oneliner}</div>
|
||||
<div className="flex items-center gap-2 py-1 group/line">
|
||||
<span className="text-brand select-none">$</span>
|
||||
<span>{getOnelinerCmd()}</span>
|
||||
<CopyButton text={getOnelinerCmd()} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{mode === 'quick' && (
|
||||
<>
|
||||
<div className="text-fd-muted-foreground italic py-1">{comments.quickInstall}</div>
|
||||
<div className="flex items-center gap-2 py-1 group/line">
|
||||
<span className="text-brand select-none">$</span>
|
||||
<span className="text-[#00e5cc]">{getInstallCmd()}</span>
|
||||
<CopyButton text={getInstallCmd()} />
|
||||
</div>
|
||||
<div className="text-fd-muted-foreground italic py-1">{comments.quickOnboard}</div>
|
||||
<div className="flex items-center gap-2 py-1 group/line">
|
||||
<span className="text-brand select-none">$</span>
|
||||
<span>hanzo-bot onboard</span>
|
||||
<CopyButton text="hanzo-bot onboard" />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{mode === 'hackable' && hackable === 'installer' && (
|
||||
<>
|
||||
<div className="text-fd-muted-foreground italic py-1"># For those who read source code for fun</div>
|
||||
<div className="flex items-center gap-2 py-1 group/line">
|
||||
<span className="text-brand select-none">$</span>
|
||||
<span>curl -fsSL https://hanzo.bot/install.sh | bash -s -- --install-method git</span>
|
||||
<CopyButton text="curl -fsSL https://hanzo.bot/install.sh | bash -s -- --install-method git" />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{mode === 'hackable' && hackable === 'pnpm' && (
|
||||
<>
|
||||
<div className="text-fd-muted-foreground italic py-1"># You clearly know what you're doing</div>
|
||||
<div className="flex items-center gap-2 py-1 group/line">
|
||||
<span className="text-brand select-none">$</span>
|
||||
<span>git clone https://github.com/hanzoai/bot.git</span>
|
||||
<CopyButton text="git clone https://github.com/hanzoai/bot.git" />
|
||||
</div>
|
||||
<div className="flex items-center gap-2 py-1 group/line">
|
||||
<span className="text-brand select-none">$</span>
|
||||
<span>cd hanzo-bot && pnpm install && pnpm run build</span>
|
||||
<CopyButton text="cd hanzo-bot && pnpm install && pnpm run build" />
|
||||
</div>
|
||||
<div className="text-fd-muted-foreground italic py-1"># You built it, now meet it</div>
|
||||
<div className="flex items-center gap-2 py-1 group/line">
|
||||
<span className="text-brand select-none">$</span>
|
||||
<span>pnpm run hanzo-bot onboard</span>
|
||||
<CopyButton text="pnpm run hanzo-bot onboard" />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{mode === 'macos' && (
|
||||
<div className="flex flex-col items-center gap-4 py-6 text-center">
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-lg font-semibold text-fd-foreground">Companion App (Beta)</span>
|
||||
<span className="text-sm text-fd-muted-foreground">Menubar access to your bot. Works great alongside the CLI.</span>
|
||||
</div>
|
||||
<a
|
||||
href="https://github.com/hanzoai/bot/releases/latest"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-2.5 px-7 py-3.5 bg-gradient-to-br from-brand to-[#991b1b] rounded-xl text-white font-semibold no-underline transition-all hover:-translate-y-0.5 hover:shadow-[0_8px_30px_rgba(255,77,77,0.4)]"
|
||||
>
|
||||
<DownloadIcon className="w-5 h-5" />
|
||||
Download for macOS
|
||||
</a>
|
||||
<span className="text-xs text-fd-muted-foreground">Requires macOS 14+ · Universal Binary</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<p className="mt-4 text-sm text-fd-muted-foreground text-center">
|
||||
Works on macOS, Windows & Linux. The one-liner installs Node.js and everything else for you.
|
||||
</p>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
MessageSquareIcon, BotIcon, GlobeIcon, HashIcon,
|
||||
SmartphoneIcon, BrainCircuitIcon, MusicIcon, LampIcon,
|
||||
BookOpenIcon, MailIcon, GithubIcon, ChromeIcon,
|
||||
} from 'lucide-react';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
interface Pill {
|
||||
name: string;
|
||||
icon: ReactNode;
|
||||
color: string;
|
||||
}
|
||||
|
||||
const pills: Pill[] = [
|
||||
{ name: 'WhatsApp', icon: <MessageSquareIcon className="w-4 h-4" />, color: '#25D366' },
|
||||
{ name: 'Telegram', icon: <SmartphoneIcon className="w-4 h-4" />, color: '#26A5E4' },
|
||||
{ name: 'Discord', icon: <MessageSquareIcon className="w-4 h-4" />, color: '#5865F2' },
|
||||
{ name: 'Slack', icon: <HashIcon className="w-4 h-4" />, color: '#E01E5A' },
|
||||
{ name: 'Signal', icon: <MessageSquareIcon className="w-4 h-4" />, color: '#3A76F0' },
|
||||
{ name: 'iMessage', icon: <SmartphoneIcon className="w-4 h-4" />, color: '#007AFF' },
|
||||
{ name: 'Claude', icon: <BrainCircuitIcon className="w-4 h-4" />, color: '#D4A574' },
|
||||
{ name: 'GPT', icon: <BotIcon className="w-4 h-4" />, color: '#00A67E' },
|
||||
{ name: 'Spotify', icon: <MusicIcon className="w-4 h-4" />, color: '#1DB954' },
|
||||
{ name: 'Hue', icon: <LampIcon className="w-4 h-4" />, color: '#0065D3' },
|
||||
{ name: 'Obsidian', icon: <BookOpenIcon className="w-4 h-4" />, color: '#7C3AED' },
|
||||
{ name: 'Twitter', icon: <GlobeIcon className="w-4 h-4" />, color: '#FFFFFF' },
|
||||
{ name: 'Browser', icon: <ChromeIcon className="w-4 h-4" />, color: '#4285F4' },
|
||||
{ name: 'Gmail', icon: <MailIcon className="w-4 h-4" />, color: '#EA4335' },
|
||||
{ name: 'GitHub', icon: <GithubIcon className="w-4 h-4" />, color: '#FFFFFF' },
|
||||
];
|
||||
|
||||
export function IntegrationPills() {
|
||||
return (
|
||||
<section className="mb-14">
|
||||
<h2 className="text-xl font-semibold flex items-center gap-2.5 mb-5">
|
||||
<span className="text-brand font-bold">⟩</span> Works With Everything
|
||||
</h2>
|
||||
<div className="flex flex-wrap gap-2.5 justify-center mb-4">
|
||||
{pills.map((p) => (
|
||||
<span
|
||||
key={p.name}
|
||||
className="inline-flex items-center gap-1.5 px-3.5 py-2 rounded-full border border-fd-border bg-[rgba(10,15,26,0.6)] backdrop-blur-sm text-sm text-fd-muted-foreground transition-all hover:border-brand hover:-translate-y-1 hover:shadow-[0_8px_24px_rgba(255,77,77,0.2)] cursor-default"
|
||||
>
|
||||
<span style={{ color: p.color }}>{p.icon}</span>
|
||||
<span>{p.name}</span>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-center items-center gap-3 flex-wrap">
|
||||
<a href="/integrations" className="text-sm text-brand font-medium no-underline hover:text-[#00e5cc] transition-colors">
|
||||
View all 600+ integrations →
|
||||
</a>
|
||||
<span className="text-fd-muted-foreground text-sm">·</span>
|
||||
<a href="/showcase" className="text-sm text-brand font-medium no-underline hover:text-[#00e5cc] transition-colors">
|
||||
See what people built →
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
'use client';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
interface Testimonial {
|
||||
quote: string;
|
||||
author: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export function TestimonialCarousel({ testimonials }: { testimonials: Testimonial[] }) {
|
||||
const half = Math.ceil(testimonials.length / 2);
|
||||
const topRow = testimonials.slice(0, half);
|
||||
const bottomRow = testimonials.slice(half);
|
||||
|
||||
const row1 = useMemo(() => [...topRow, ...topRow], [topRow]);
|
||||
const row2 = useMemo(() => [...bottomRow, ...bottomRow], [bottomRow]);
|
||||
|
||||
const pixelsPerItem = 336;
|
||||
const pixelsPerSecond = 50;
|
||||
const duration1 = (topRow.length * pixelsPerItem) / pixelsPerSecond;
|
||||
const duration2 = (bottomRow.length * pixelsPerItem) / pixelsPerSecond;
|
||||
|
||||
return (
|
||||
<section className="mb-14 overflow-hidden -mx-6 px-6">
|
||||
<div className="flex items-center justify-between mb-5 px-6">
|
||||
<h2 className="text-xl font-semibold flex items-center gap-2.5">
|
||||
<span className="text-brand font-bold">⟩</span> What People Say
|
||||
</h2>
|
||||
<a href="/shoutouts" className="text-sm text-brand font-medium hover:text-[#00e5cc] transition-colors">
|
||||
View all →
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
className="flex flex-col gap-2 -mx-6 overflow-hidden"
|
||||
style={{
|
||||
maskImage: 'linear-gradient(to right, transparent, black 5%, black 95%, transparent)',
|
||||
WebkitMaskImage: 'linear-gradient(to right, transparent, black 5%, black 95%, transparent)',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="flex gap-4 w-max py-2 animate-[scroll-left_var(--duration)_linear_infinite] hover:[animation-play-state:paused]"
|
||||
style={{ '--duration': `${duration1}s` } as React.CSSProperties}
|
||||
>
|
||||
{row1.map((t, i) => (
|
||||
<a
|
||||
key={`r1-${i}`}
|
||||
href={t.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-start gap-3 p-4 min-w-[320px] max-w-[400px] rounded-xl border border-fd-border bg-[rgba(10,15,26,0.7)] backdrop-blur-sm no-underline text-fd-foreground transition-all duration-250 hover:border-brand hover:-translate-y-0.5 hover:shadow-[0_8px_24px_rgba(255,77,77,0.15)] shrink-0"
|
||||
>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={`https://ui-avatars.com/api/?name=${encodeURIComponent(t.author)}&background=fd4444&color=fff&size=88&bold=true`}
|
||||
alt={t.author}
|
||||
className="w-11 h-11 rounded-full shrink-0 border-2 border-fd-border bg-fd-muted"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div className="flex flex-col gap-1.5 min-w-0">
|
||||
<p className="text-sm leading-snug text-fd-muted-foreground line-clamp-3">
|
||||
“{t.quote}”
|
||||
</p>
|
||||
<span className="text-xs font-semibold text-brand">@{t.author}</span>
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
className="flex gap-4 w-max py-2 animate-[scroll-right_var(--duration)_linear_infinite] hover:[animation-play-state:paused]"
|
||||
style={{ '--duration': `${duration2}s` } as React.CSSProperties}
|
||||
>
|
||||
{row2.map((t, i) => (
|
||||
<a
|
||||
key={`r2-${i}`}
|
||||
href={t.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-start gap-3 p-4 min-w-[320px] max-w-[400px] rounded-xl border border-fd-border bg-[rgba(10,15,26,0.7)] backdrop-blur-sm no-underline text-fd-foreground transition-all duration-250 hover:border-brand hover:-translate-y-0.5 hover:shadow-[0_8px_24px_rgba(255,77,77,0.15)] shrink-0"
|
||||
>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={`https://ui-avatars.com/api/?name=${encodeURIComponent(t.author)}&background=fd4444&color=fff&size=88&bold=true`}
|
||||
alt={t.author}
|
||||
className="w-11 h-11 rounded-full shrink-0 border-2 border-fd-border bg-fd-muted"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div className="flex flex-col gap-1.5 min-w-0">
|
||||
<p className="text-sm leading-snug text-fd-muted-foreground line-clamp-3">
|
||||
“{t.quote}”
|
||||
</p>
|
||||
<span className="text-xs font-semibold text-brand">@{t.author}</span>
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
import Link from 'next/link';
|
||||
import {
|
||||
MessageSquareIcon, HashIcon, GlobeIcon, UsersIcon,
|
||||
BotIcon, BrainCircuitIcon, ZapIcon, MessageCircleIcon,
|
||||
StickyNoteIcon, CheckSquareIcon, ListTodoIcon,
|
||||
PenToolIcon, MusicIcon, BedIcon,
|
||||
MonitorSmartphoneIcon, MicIcon, ClockIcon, WebhookIcon,
|
||||
CloudSunIcon, ImageIcon, SearchIcon, EyeIcon, CameraIcon,
|
||||
MailIcon, ShoppingCartIcon, PrinterIcon, HeartIcon,
|
||||
UtensilsCrossedIcon, SmartphoneIcon,
|
||||
} from 'lucide-react';
|
||||
import automationsData from '@/data/automations.json';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
interface Integration {
|
||||
name: string;
|
||||
icon: ReactNode;
|
||||
color: string;
|
||||
desc: string;
|
||||
docs: string;
|
||||
}
|
||||
|
||||
function IntegrationCard({ item }: { item: Integration }) {
|
||||
return (
|
||||
<a
|
||||
href={item.docs}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex flex-col items-center text-center p-6 rounded-2xl border border-fd-border bg-[rgba(10,15,26,0.6)] backdrop-blur-sm no-underline text-fd-foreground transition-all hover:-translate-y-1 hover:shadow-[0_12px_40px_rgba(255,77,77,0.2)]"
|
||||
style={{ '--accent': item.color } as React.CSSProperties}
|
||||
>
|
||||
<span className="flex items-center justify-center mb-3 drop-shadow-md" style={{ color: item.color }}>
|
||||
{item.icon}
|
||||
</span>
|
||||
<h3 className="text-sm font-semibold mb-1.5">{item.name}</h3>
|
||||
<p className="text-xs text-fd-muted-foreground leading-snug">{item.desc}</p>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
function Section({ title, desc, children, className }: { title: string; desc: string; children: ReactNode; className?: string }) {
|
||||
return (
|
||||
<section className="mb-14">
|
||||
<h2 className="text-xl font-semibold flex items-center gap-2.5 mb-2">
|
||||
<span className="text-brand font-bold">⟩</span> {title}
|
||||
</h2>
|
||||
<p className="text-sm text-fd-muted-foreground mb-5 leading-relaxed">{desc}</p>
|
||||
<div className={className || 'grid grid-cols-2 sm:grid-cols-4 gap-4'}>
|
||||
{children}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
const I = (size = 32) => ({ className: `w-[${size}px] h-[${size}px]` });
|
||||
|
||||
const chatProviders: Integration[] = [
|
||||
{ name: 'WhatsApp', icon: <MessageSquareIcon {...I()} />, color: '#25D366', desc: 'QR pairing via Baileys', docs: 'https://skills.hanzo.bot/skills/wacli' },
|
||||
{ name: 'Telegram', icon: <SmartphoneIcon {...I()} />, color: '#26A5E4', desc: 'Bot API via grammY', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Discord', icon: <MessageSquareIcon {...I()} />, color: '#5865F2', desc: 'Servers, channels & DMs', docs: 'https://skills.hanzo.bot/skills/discord' },
|
||||
{ name: 'Slack', icon: <HashIcon {...I()} />, color: '#E01E5A', desc: 'Workspace apps via Bolt', docs: 'https://skills.hanzo.bot/skills/slack' },
|
||||
{ name: 'Signal', icon: <MessageSquareIcon {...I()} />, color: '#3A76F0', desc: 'Privacy-focused via signal-cli', docs: 'https://skills.hanzo.bot/skills/sag' },
|
||||
{ name: 'iMessage', icon: <SmartphoneIcon {...I()} />, color: '#007AFF', desc: 'AppleScript bridge', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Teams', icon: <UsersIcon {...I()} />, color: '#6264A7', desc: 'Enterprise support', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Matrix', icon: <GlobeIcon {...I()} />, color: '#FFFFFF', desc: 'Matrix protocol', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Nostr', icon: <MessageCircleIcon {...I()} />, color: '#8F2CFF', desc: 'Decentralized DMs', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'WebChat', icon: <GlobeIcon {...I()} />, color: '#00E5CC', desc: 'Browser-based UI', docs: 'https://github.com/hanzoai/bot' },
|
||||
];
|
||||
|
||||
const modelProviders: Integration[] = [
|
||||
{ name: 'Anthropic', icon: <BrainCircuitIcon {...I()} />, color: '#D4A574', desc: 'Claude Opus 4.6', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'OpenAI', icon: <BotIcon {...I()} />, color: '#00A67E', desc: 'GPT-5, o3, o4-mini', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Google', icon: <GlobeIcon {...I()} />, color: '#4285F4', desc: 'Gemini 3 Pro/Flash', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'xAI', icon: <ZapIcon {...I()} />, color: '#FFFFFF', desc: 'Grok 3 & 4', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'OpenRouter', icon: <ZapIcon {...I()} />, color: '#6366F1', desc: 'Unified API gateway', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Mistral', icon: <BrainCircuitIcon {...I()} />, color: '#FF7000', desc: 'Mistral Large & Codestral', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'DeepSeek', icon: <BrainCircuitIcon {...I()} />, color: '#4D6BFE', desc: 'DeepSeek V3 & R1', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Perplexity', icon: <SearchIcon {...I()} />, color: '#20B8CD', desc: 'Search-augmented AI', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Hugging Face', icon: <BotIcon {...I()} />, color: '#FFD21E', desc: 'Open-source models', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Local Models', icon: <BotIcon {...I()} />, color: '#FFFFFF', desc: 'Ollama, LM Studio', docs: 'https://github.com/hanzoai/bot' },
|
||||
];
|
||||
|
||||
const productivityApps: Integration[] = [
|
||||
{ name: 'Apple Notes', icon: <StickyNoteIcon {...I()} />, color: '#FFCC00', desc: 'Native macOS/iOS notes', docs: 'https://skills.hanzo.bot/skills/apple-notes' },
|
||||
{ name: 'Apple Reminders', icon: <CheckSquareIcon {...I()} />, color: '#FF9500', desc: 'Task management', docs: 'https://skills.hanzo.bot/skills/apple-reminders' },
|
||||
{ name: 'Things 3', icon: <ListTodoIcon {...I()} />, color: '#4A90D9', desc: 'GTD task manager', docs: 'https://skills.hanzo.bot/skills/things-mac' },
|
||||
{ name: 'Notion', icon: <StickyNoteIcon {...I()} />, color: '#FFFFFF', desc: 'Workspace & databases', docs: 'https://skills.hanzo.bot/skills' },
|
||||
{ name: 'Obsidian', icon: <PenToolIcon {...I()} />, color: '#7C3AED', desc: 'Knowledge graph notes', docs: 'https://skills.hanzo.bot/skills/obsidian' },
|
||||
{ name: 'Trello', icon: <ListTodoIcon {...I()} />, color: '#0079BF', desc: 'Kanban boards', docs: 'https://skills.hanzo.bot/skills/trello' },
|
||||
{ name: 'GitHub', icon: <GlobeIcon {...I()} />, color: '#FFFFFF', desc: 'Code, issues, PRs', docs: 'https://skills.hanzo.bot/skills' },
|
||||
];
|
||||
|
||||
const musicAudio: Integration[] = [
|
||||
{ name: 'Spotify', icon: <MusicIcon {...I()} />, color: '#1DB954', desc: 'Music playback control', docs: 'https://skills.hanzo.bot/skills/spotify-player' },
|
||||
{ name: 'Sonos', icon: <MusicIcon {...I()} />, color: '#FFFFFF', desc: 'Multi-room audio', docs: 'https://skills.hanzo.bot/skills/sonoscli' },
|
||||
{ name: 'Shazam', icon: <SearchIcon {...I()} />, color: '#0088FF', desc: 'Song recognition', docs: 'https://skills.hanzo.bot/skills/songsee' },
|
||||
];
|
||||
|
||||
const smartHome: Integration[] = [
|
||||
{ name: 'Philips Hue', icon: <ZapIcon {...I()} />, color: '#0065D3', desc: 'Smart lighting', docs: 'https://skills.hanzo.bot/skills/openhue' },
|
||||
{ name: '8Sleep', icon: <BedIcon {...I()} />, color: '#00B4D8', desc: 'Smart mattress', docs: 'https://skills.hanzo.bot/skills/eightctl' },
|
||||
{ name: 'Home Assistant', icon: <GlobeIcon {...I()} />, color: '#41BDF5', desc: 'Home automation hub', docs: 'https://skills.hanzo.bot/skills/homeassistant' },
|
||||
];
|
||||
|
||||
const tools: Integration[] = [
|
||||
{ name: 'Browser', icon: <GlobeIcon {...I()} />, color: '#4285F4', desc: 'Chrome/Chromium control', docs: 'https://skills.hanzo.bot/skills/verify-on-browser' },
|
||||
{ name: 'Canvas', icon: <MonitorSmartphoneIcon {...I()} />, color: '#FF4500', desc: 'Visual workspace + A2UI', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Voice', icon: <MicIcon {...I()} />, color: '#9B59B6', desc: 'Voice Wake + Talk Mode', docs: 'https://skills.hanzo.bot/skills/voice-transcribe' },
|
||||
{ name: 'Gmail', icon: <MailIcon {...I()} />, color: '#EA4335', desc: 'Pub/Sub email triggers', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Cron', icon: <ClockIcon {...I()} />, color: '#F39C12', desc: 'Scheduled tasks', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Webhooks', icon: <WebhookIcon {...I()} />, color: '#1ABC9C', desc: 'External triggers', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Weather', icon: <CloudSunIcon {...I()} />, color: '#FFB300', desc: 'Forecasts & conditions', docs: 'https://skills.hanzo.bot/skills/weather' },
|
||||
];
|
||||
|
||||
const mediaCreative: Integration[] = [
|
||||
{ name: 'Image Gen', icon: <ImageIcon {...I()} />, color: '#E91E63', desc: 'AI image generation', docs: 'https://skills.hanzo.bot/skills' },
|
||||
{ name: 'GIF Search', icon: <SearchIcon {...I()} />, color: '#00DCDC', desc: 'Find the perfect GIF', docs: 'https://skills.hanzo.bot/skills/gifgrep' },
|
||||
{ name: 'Peekaboo', icon: <EyeIcon {...I()} />, color: '#FF6B6B', desc: 'Screen capture & control', docs: 'https://skills.hanzo.bot/skills/peekaboo' },
|
||||
{ name: 'Camera', icon: <CameraIcon {...I()} />, color: '#607D8B', desc: 'Photo/video capture', docs: 'https://skills.hanzo.bot/skills' },
|
||||
];
|
||||
|
||||
const socialComms: Integration[] = [
|
||||
{ name: 'Twitter/X', icon: <GlobeIcon {...I()} />, color: '#FFFFFF', desc: 'Tweet, reply, search', docs: 'https://skills.hanzo.bot/skills/bird' },
|
||||
{ name: 'Email', icon: <MailIcon {...I()} />, color: '#D44638', desc: 'Send & read emails', docs: 'https://skills.hanzo.bot/skills/himalaya' },
|
||||
];
|
||||
|
||||
const showcase: Integration[] = [
|
||||
{ name: 'Tesco Autopilot', icon: <ShoppingCartIcon {...I()} />, color: '#00539F', desc: 'Automated grocery shopping', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Bambu Control', icon: <PrinterIcon {...I()} />, color: '#00AE42', desc: '3D printer management', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Oura Ring', icon: <HeartIcon {...I()} />, color: '#E4B363', desc: 'Health data insights', docs: 'https://github.com/hanzoai/bot' },
|
||||
{ name: 'Food Ordering', icon: <UtensilsCrossedIcon {...I()} />, color: '#FF5A5F', desc: 'Foodora integration', docs: 'https://github.com/hanzoai/bot' },
|
||||
];
|
||||
|
||||
const popularIntegrations = [
|
||||
'Slack', 'HubSpot', 'Google Sheets', 'GitHub', 'Shopify', 'Stripe', 'Jira Cloud',
|
||||
'Microsoft Excel 365', 'Notion', 'Mailchimp', 'Salesforce', 'Zendesk',
|
||||
'Airtable', 'Twilio', 'Discord', 'OpenAI', 'Google Drive',
|
||||
];
|
||||
|
||||
export const metadata = {
|
||||
title: 'Integrations — Hanzo Bot',
|
||||
};
|
||||
|
||||
export default function IntegrationsPage() {
|
||||
const autoCategories = automationsData.categories
|
||||
.filter((c: any) => c.id !== 'OTHER' && c.id !== 'CORE' && c.id !== 'FLOW_CONTROL' && c.id !== 'UNIVERSAL_AI')
|
||||
.slice(0, 14);
|
||||
|
||||
return (
|
||||
<main className="relative z-[1] max-w-[1000px] mx-auto px-6 py-10">
|
||||
<div className="stars" />
|
||||
<div className="nebula" />
|
||||
|
||||
<header className="text-center mb-12 animate-[fadeInUp_0.6s_ease-out]">
|
||||
<h1 className="text-3xl sm:text-4xl font-bold mb-4 bg-gradient-to-br from-fd-foreground via-brand to-[#00e5cc] bg-[length:200%_200%] bg-clip-text text-transparent">
|
||||
Integrations
|
||||
</h1>
|
||||
<p className="text-lg text-fd-muted-foreground max-w-[600px] mx-auto leading-relaxed">
|
||||
600+ integrations with the apps and services you already use.
|
||||
<br />
|
||||
Chat from your phone, control from your desktop, automate everything.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<Section title="Chat Providers" desc="Message your bot from any chat app — it responds right where you are.">
|
||||
{chatProviders.map((p) => <IntegrationCard key={p.name + p.desc} item={p} />)}
|
||||
</Section>
|
||||
|
||||
<Section title="AI Models" desc="Use any model you want — cloud or local. Your keys, your choice.">
|
||||
{modelProviders.map((p) => <IntegrationCard key={p.name} item={p} />)}
|
||||
</Section>
|
||||
|
||||
<Section title="Productivity" desc="Notes, tasks, wikis, and code — your bot works with your favorite tools.">
|
||||
{productivityApps.map((p) => <IntegrationCard key={p.name} item={p} />)}
|
||||
</Section>
|
||||
|
||||
<Section title="Music & Audio" desc="Control playback, identify songs, and manage multi-room audio." className="grid grid-cols-2 sm:grid-cols-3 gap-4">
|
||||
{musicAudio.map((p) => <IntegrationCard key={p.name} item={p} />)}
|
||||
</Section>
|
||||
|
||||
<Section title="Smart Home" desc="Lights, thermostats, and IoT devices — all voice-controllable." className="grid grid-cols-2 sm:grid-cols-3 gap-4">
|
||||
{smartHome.map((p) => <IntegrationCard key={p.name} item={p} />)}
|
||||
</Section>
|
||||
|
||||
<Section title="Tools & Automation" desc="Browser control, scheduled tasks, email triggers, and more.">
|
||||
{tools.map((p) => <IntegrationCard key={p.name} item={p} />)}
|
||||
</Section>
|
||||
|
||||
<Section title="Media & Creative" desc="Generate images, capture screens, and find the perfect GIF.">
|
||||
{mediaCreative.map((p) => <IntegrationCard key={p.name} item={p} />)}
|
||||
</Section>
|
||||
|
||||
<Section title="Social" desc="Post tweets, manage email, and stay connected." className="grid grid-cols-2 max-w-[500px] gap-4">
|
||||
{socialComms.map((p) => <IntegrationCard key={p.name} item={p} />)}
|
||||
</Section>
|
||||
|
||||
<Section title="Community Showcase" desc="Impressive integrations built by the community.">
|
||||
{showcase.map((p) => <IntegrationCard key={p.name} item={p} />)}
|
||||
</Section>
|
||||
|
||||
{/* Automation Platform */}
|
||||
<section className="mb-14">
|
||||
<h2 className="text-xl font-semibold flex items-center gap-2.5 mb-2">
|
||||
<span className="text-brand font-bold">⟩</span> Automation Platform
|
||||
</h2>
|
||||
<p className="text-sm text-fd-muted-foreground mb-5 leading-relaxed">
|
||||
{automationsData.total} automation integrations powered by <strong>Hanzo Auto</strong> — connect any service, trigger any workflow, automate anything.
|
||||
</p>
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(140px,1fr))] gap-3 mb-6">
|
||||
{autoCategories.map((cat: any) => (
|
||||
<div key={cat.id} className="flex flex-col items-center gap-1 p-4 rounded-xl border border-fd-border bg-[rgba(10,15,26,0.6)] backdrop-blur-sm transition-all hover:border-[#00e5cc] hover:-translate-y-0.5 hover:shadow-[0_8px_24px_rgba(0,229,204,0.12)]">
|
||||
<span className="text-xl font-bold text-[#00e5cc]">{cat.count}</span>
|
||||
<span className="text-xs text-fd-muted-foreground text-center leading-snug">{cat.label}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<p className="text-xs text-fd-muted-foreground mb-3">Popular integrations:</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{popularIntegrations.map((name) => (
|
||||
<span key={name} className="inline-flex items-center px-3.5 py-1.5 rounded-full border border-fd-border bg-[rgba(10,15,26,0.5)] text-xs text-fd-muted-foreground transition-all hover:border-brand hover:text-fd-foreground">
|
||||
{name}
|
||||
</span>
|
||||
))}
|
||||
<span className="inline-flex items-center px-3.5 py-1.5 rounded-full border border-[#00e5cc] text-xs text-[#00e5cc] font-medium">
|
||||
+{automationsData.total - popularIntegrations.length} more
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-center mt-6">
|
||||
<a
|
||||
href="https://app.hanzo.bot"
|
||||
className="inline-block px-7 py-3 rounded-xl bg-gradient-to-br from-[#00e5cc] to-[#14b8a6] text-[#050810] font-semibold no-underline transition-all hover:-translate-y-0.5 hover:shadow-[0_8px_24px_rgba(0,229,204,0.4)]"
|
||||
>
|
||||
Launch Hanzo Auto →
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA */}
|
||||
<section className="text-center p-12 rounded-2xl border border-fd-border bg-[rgba(10,15,26,0.6)] backdrop-blur-sm mb-10">
|
||||
<h2 className="text-2xl font-semibold mb-2">Ready to get started?</h2>
|
||||
<p className="text-fd-muted-foreground mb-6">Install Hanzo Bot and connect your first provider in minutes.</p>
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-block px-8 py-3.5 rounded-xl bg-gradient-to-br from-brand to-[#991b1b] text-white font-semibold no-underline transition-all hover:-translate-y-0.5 hover:shadow-[0_8px_24px_rgba(255,77,77,0.4)]"
|
||||
>
|
||||
Get Started
|
||||
</Link>
|
||||
</section>
|
||||
|
||||
{/* Skills CTA */}
|
||||
<section className="text-center p-12 rounded-2xl border border-fd-border bg-[rgba(10,15,26,0.6)] backdrop-blur-sm mb-10">
|
||||
<h2 className="text-2xl font-semibold mb-2">Want More Skills?</h2>
|
||||
<p className="text-fd-muted-foreground mb-6 max-w-[600px] mx-auto">
|
||||
Discover 700+ community-built skills on the Hanzo Skill Hub — the public registry for sharing and discovering agent capabilities.
|
||||
</p>
|
||||
<Link
|
||||
href="/skills"
|
||||
className="inline-block px-8 py-3.5 rounded-xl bg-gradient-to-br from-[#00e5cc] to-[#14b8a6] text-[#050810] font-semibold no-underline transition-all hover:-translate-y-0.5 hover:shadow-[0_8px_24px_rgba(0,229,204,0.4)]"
|
||||
>
|
||||
Browse Skill Hub →
|
||||
</Link>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
+200
-332
@@ -2,19 +2,14 @@ import Link from 'next/link';
|
||||
import { cn } from '@/lib/cn';
|
||||
import { cva } from 'class-variance-authority';
|
||||
import {
|
||||
BotIcon,
|
||||
MessageSquareIcon,
|
||||
ShieldCheckIcon,
|
||||
PlugIcon,
|
||||
ZapIcon,
|
||||
SmartphoneIcon,
|
||||
ServerIcon,
|
||||
CloudIcon,
|
||||
HeartHandshakeIcon,
|
||||
TerminalIcon,
|
||||
BrainCircuitIcon,
|
||||
GlobeIcon,
|
||||
HomeIcon, MessageCircleIcon, BrainIcon, GlobeIcon,
|
||||
TerminalIcon, PuzzleIcon, MonitorIcon, ShieldIcon,
|
||||
DownloadIcon, LogInIcon, UsersIcon, BookOpenIcon,
|
||||
} from 'lucide-react';
|
||||
import testimonials from '@/data/testimonials.json';
|
||||
import { TestimonialCarousel } from './_components/testimonial-carousel';
|
||||
import { InstallTabs } from './_components/install-tabs';
|
||||
import { IntegrationPills } from './_components/integration-pills';
|
||||
|
||||
const headingVariants = cva('font-medium tracking-tight', {
|
||||
variants: {
|
||||
@@ -27,7 +22,7 @@ const headingVariants = cva('font-medium tracking-tight', {
|
||||
});
|
||||
|
||||
const buttonVariants = cva(
|
||||
'inline-flex justify-center px-5 py-3 rounded-full font-medium tracking-tight transition-colors',
|
||||
'inline-flex justify-center items-center px-5 py-3 rounded-full font-medium tracking-tight transition-all no-underline',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
@@ -41,341 +36,214 @@ const buttonVariants = cva(
|
||||
},
|
||||
);
|
||||
|
||||
const cardVariants = cva('rounded-2xl text-sm p-6 bg-origin-border shadow-lg', {
|
||||
variants: {
|
||||
variant: {
|
||||
secondary: 'bg-brand-secondary text-brand-secondary-foreground',
|
||||
default: 'border bg-fd-card',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
},
|
||||
});
|
||||
const HanzoLogo = () => (
|
||||
<svg viewBox="0 0 67 67" xmlns="http://www.w3.org/2000/svg" className="w-full h-full" aria-hidden="true">
|
||||
<path d="M22.21 67V44.6369H0V67H22.21Z" fill="currentColor"/>
|
||||
<path d="M0 44.6369L22.21 46.8285V44.6369H0Z" fill="currentColor" opacity="0.4"/>
|
||||
<path d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z" fill="currentColor"/>
|
||||
<path d="M22.21 0H0V22.3184H22.21V0Z" fill="currentColor"/>
|
||||
<path d="M66.7198 0H44.5098V22.3184H66.7198V0Z" fill="currentColor"/>
|
||||
<path d="M66.6753 22.3185L44.5098 20.0822V22.3185H66.6753Z" fill="currentColor" opacity="0.4"/>
|
||||
<path d="M66.7198 67V44.6369H44.5098V67H66.7198Z" fill="currentColor"/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const models = [
|
||||
{ provider: 'Anthropic', names: 'Claude Opus 4.6, Sonnet 4.5' },
|
||||
{ provider: 'OpenAI', names: 'GPT-5.2, GPT-5.1 Codex' },
|
||||
{ provider: 'Google', names: 'Gemini 3 Pro, Flash' },
|
||||
{ provider: 'Open Source', names: 'Qwen 3, GLM 4.7, Llama' },
|
||||
{ provider: 'Together AI', names: 'DeepSeek, Mixtral, more' },
|
||||
{ provider: 'OpenRouter', names: '100+ models, one API' },
|
||||
];
|
||||
|
||||
const features = [
|
||||
{ icon: HomeIcon, title: 'Runs on Your Machine', desc: 'Mac, Windows, or Linux. Anthropic, OpenAI, or local models. Private by default\u2014your data stays yours.', href: 'https://github.com/hanzoai/bot' },
|
||||
{ icon: MessageCircleIcon, title: 'Any Chat App', desc: 'Talk to it on WhatsApp, Telegram, Discord, Slack, Signal, or iMessage. Works in DMs and group chats.', href: '/integrations' },
|
||||
{ icon: BrainIcon, title: 'Persistent Memory', desc: 'Remembers you and becomes uniquely yours. Your preferences, your context, your AI.', href: 'https://github.com/hanzoai/bot' },
|
||||
{ icon: GlobeIcon, title: 'Browser Control', desc: 'It can browse the web, fill forms, and extract data from any site.', href: 'https://github.com/hanzoai/bot' },
|
||||
{ icon: TerminalIcon, title: 'Full System Access', desc: 'Read and write files, run shell commands, execute scripts. Full access or sandboxed\u2014your choice.', href: 'https://github.com/hanzoai/bot' },
|
||||
{ icon: PuzzleIcon, title: 'Skills & Plugins', desc: 'Extend with community skills or build your own. It can even write its own.', href: '/skills' },
|
||||
];
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<main className="text-landing-foreground pt-4 pb-6 dark:text-landing-foreground-dark md:pb-12">
|
||||
{/* Hero Section */}
|
||||
<div className="relative flex min-h-[600px] h-[70vh] max-h-[900px] border rounded-2xl overflow-hidden mx-auto w-full max-w-[1400px] bg-gradient-to-br from-brand/10 via-transparent to-brand-secondary/10">
|
||||
<div className="absolute inset-0 bg-grid-pattern opacity-5" />
|
||||
<div className="flex flex-col z-2 px-4 size-full md:p-12 max-md:items-center max-md:text-center">
|
||||
<div className="flex items-center gap-2 mt-12 text-xs text-brand font-medium rounded-full p-2 border border-brand/50 w-fit">
|
||||
<BotIcon className="size-4" />
|
||||
AI-Powered Personal Assistant
|
||||
</div>
|
||||
<h1 className={cn(headingVariants({ variant: 'h1' }), 'my-8 leading-tight')}>
|
||||
<span className="text-brand">Hanzo Bot</span> — Your AI
|
||||
<br />
|
||||
on Every Platform
|
||||
</h1>
|
||||
<p className="text-lg text-fd-muted-foreground max-w-2xl mb-8">
|
||||
AI-powered personal assistant for any OS. Gateway to WhatsApp, Telegram,
|
||||
Discord, iMessage, and more. Full system access with privacy by default.
|
||||
Self-host or run on Hanzo Cloud.
|
||||
</p>
|
||||
<div className="flex flex-row items-center justify-center gap-4 flex-wrap w-fit">
|
||||
<Link href="/docs" className={cn(buttonVariants(), 'max-sm:text-sm')}>
|
||||
Get Started
|
||||
</Link>
|
||||
<Link href="/docs/install" className={cn(buttonVariants({ variant: 'secondary' }), 'max-sm:text-sm')}>
|
||||
Install Now
|
||||
</Link>
|
||||
<a
|
||||
href="https://github.com/hanzoai/bot"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
className={cn(buttonVariants({ variant: 'secondary' }), 'max-sm:text-sm')}
|
||||
>
|
||||
View on GitHub
|
||||
</a>
|
||||
</div>
|
||||
<main className="relative z-[1] max-w-[860px] mx-auto px-6 pt-16 pb-10">
|
||||
<div className="stars" />
|
||||
<div className="nebula" />
|
||||
|
||||
{/* Terminal Preview */}
|
||||
<div className="mt-12 w-full max-w-3xl mx-auto">
|
||||
<div className="bg-fd-card border rounded-xl overflow-hidden shadow-2xl">
|
||||
<div className="flex items-center gap-2 px-4 py-2 border-b bg-fd-muted/50">
|
||||
<div className="flex gap-1.5">
|
||||
<div className="size-3 rounded-full bg-red-500" />
|
||||
<div className="size-3 rounded-full bg-yellow-500" />
|
||||
<div className="size-3 rounded-full bg-green-500" />
|
||||
</div>
|
||||
<span className="text-xs text-fd-muted-foreground ml-2">terminal</span>
|
||||
</div>
|
||||
<pre className="p-4 text-sm overflow-x-auto font-mono">
|
||||
<code>{`$ curl -fsSL https://hanzo.bot/install.sh | bash
|
||||
$ hanzo-bot setup
|
||||
$ hanzo-bot gateway
|
||||
|
||||
Hanzo Bot Gateway running on 127.0.0.1:18789
|
||||
Dashboard: http://127.0.0.1:18789/
|
||||
|
||||
Channels:
|
||||
✓ WhatsApp connected (paired)
|
||||
✓ Telegram connected (@mybot)
|
||||
✓ Discord connected (Hanzo#1234)
|
||||
|
||||
Skills: 743 loaded
|
||||
Provider: anthropic (claude-sonnet-4-5-20250514)
|
||||
Memory: persistent (SQLite)
|
||||
|
||||
Ready. Send a message to get started.`}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
{/* Hero */}
|
||||
<header className="text-center mb-14 animate-[fadeInUp_0.8s_ease-out]">
|
||||
<div className="w-20 h-20 mx-auto mb-6 animate-[float_4s_ease-in-out_infinite] text-fd-foreground hover:scale-110 hover:text-[#00e5cc] transition-all duration-300 [&:hover]:animate-none [&_svg]:drop-shadow-[0_0_20px_rgba(240,244,255,0.3)] [&:hover_svg]:drop-shadow-[0_0_30px_rgba(0,229,204,0.6)]">
|
||||
<HanzoLogo />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Features Grid */}
|
||||
<div className="grid grid-cols-1 gap-10 mt-12 px-6 mx-auto w-full max-w-[1400px] md:px-12 lg:grid-cols-2">
|
||||
<p className="text-2xl tracking-tight leading-snug font-light col-span-full md:text-3xl xl:text-4xl">
|
||||
Connect to <span className="text-brand font-medium">every messaging platform</span>,{' '}
|
||||
run <span className="text-brand font-medium">743+ skills</span>, and{' '}
|
||||
keep <span className="text-brand font-medium">full control</span> of your data.
|
||||
<h1 className={cn(headingVariants({ variant: 'h1' }), 'mb-3 leading-none font-bold')}>
|
||||
<span className="bg-gradient-to-br from-fd-foreground via-brand to-[#00e5cc] bg-[length:200%_200%] bg-clip-text text-transparent animate-[gradientShift_6s_ease_infinite]">
|
||||
Hanzo Bot
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p className="text-brand text-sm font-medium tracking-[0.15em] uppercase mb-5 animate-[fadeInUp_0.8s_ease-out_0.15s_both]">
|
||||
Your AI team, deployed everywhere.
|
||||
</p>
|
||||
|
||||
{/* Channels */}
|
||||
<div className={cn(cardVariants())}>
|
||||
<MessageSquareIcon className="size-8 text-brand mb-4" />
|
||||
<h3 className={cn(headingVariants({ variant: 'h3', className: 'mb-4' }))}>
|
||||
Multi-Channel Gateway
|
||||
</h3>
|
||||
<ul className="space-y-3 text-fd-muted-foreground">
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-brand">WhatsApp</span> — full media support, group chats
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-brand">Telegram</span> — bot API and user gateway
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-brand">Discord</span> — server bots, DMs, threads
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-brand">iMessage, Signal, Slack, Matrix</span> and more
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p className="text-lg text-fd-muted-foreground max-w-[780px] mx-auto leading-relaxed animate-[fadeInUp_0.8s_ease-out_0.3s_both]">
|
||||
Run locally on your Mac, or deploy to Hanzo Cloud with a full desktop VM and 100+ AI models.
|
||||
<br />
|
||||
Every channel. Every platform. Private by default. Powered by Hanzo AI.
|
||||
</p>
|
||||
|
||||
{/* Hanzo Cloud */}
|
||||
<div className={cn(cardVariants({ variant: 'secondary' }))}>
|
||||
<CloudIcon className="size-8 mb-4" />
|
||||
<h3 className={cn(headingVariants({ variant: 'h3', className: 'mb-4' }))}>
|
||||
Hanzo Cloud
|
||||
</h3>
|
||||
<p className="mb-4">
|
||||
Don't want to self-host? Run Hanzo Bot on Hanzo Cloud with zero config.
|
||||
Start free with a <strong>$5 credit</strong> on signup.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm">
|
||||
<li>Managed infrastructure, automatic updates</li>
|
||||
<li>Scale from hobby to enterprise</li>
|
||||
<li>25% of compute costs paid back to OSS developers</li>
|
||||
<li>OpenClaw compatible — bring your existing config</li>
|
||||
</ul>
|
||||
<div className="flex gap-4 justify-center mt-8 animate-[fadeInUp_0.8s_ease-out_0.45s_both]">
|
||||
<a
|
||||
href="#quickstart"
|
||||
className="inline-flex items-center gap-2 px-7 py-3.5 font-semibold text-[#050810] bg-gradient-to-br from-brand to-[#e03e3e] rounded-xl no-underline transition-all hover:-translate-y-0.5 hover:shadow-[0_8px_40px_rgba(255,77,77,0.45)] shadow-[0_4px_24px_rgba(255,77,77,0.3)]"
|
||||
>
|
||||
<DownloadIcon className="w-5 h-5" />
|
||||
Download
|
||||
</a>
|
||||
<a
|
||||
href="https://app.hanzo.bot"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-2 px-7 py-3.5 font-semibold text-fd-foreground bg-[rgba(255,255,255,0.05)] border border-fd-border rounded-xl no-underline transition-all hover:-translate-y-0.5 hover:bg-[rgba(0,229,204,0.08)] hover:border-[#00e5cc] hover:shadow-[0_8px_40px_rgba(0,229,204,0.2)]"
|
||||
>
|
||||
<LogInIcon className="w-5 h-5" />
|
||||
Launch in Cloud
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Skills & Tools */}
|
||||
<div className={cn(cardVariants())}>
|
||||
<ZapIcon className="size-8 text-brand mb-4" />
|
||||
<h3 className={cn(headingVariants({ variant: 'h3', className: 'mb-4' }))}>
|
||||
743+ Skills
|
||||
</h3>
|
||||
<p className="text-fd-muted-foreground mb-4">
|
||||
Extensible skill system with browser automation, code execution,
|
||||
web search, file management, and hundreds of community-built skills.
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-4 text-sm">
|
||||
<div className="p-3 rounded-lg border">
|
||||
<p className="font-medium">Browser</p>
|
||||
<p className="text-xs text-fd-muted-foreground">Headless automation</p>
|
||||
{/* Models */}
|
||||
<section className="mb-14 animate-[fadeInUp_0.8s_ease-out_0.5s_both]">
|
||||
<h2 className="text-xl font-semibold flex items-center gap-2.5 mb-5">
|
||||
<span className="text-brand font-bold">⟩</span> 100+ AI Models
|
||||
</h2>
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
|
||||
{models.map((m) => (
|
||||
<div key={m.provider} className="flex flex-col gap-1 p-4 rounded-xl border border-fd-border bg-[rgba(10,15,26,0.6)] backdrop-blur-sm transition-all hover:border-brand hover:-translate-y-0.5">
|
||||
<span className="text-xs font-semibold text-brand uppercase tracking-wider">{m.provider}</span>
|
||||
<span className="text-sm text-fd-muted-foreground">{m.names}</span>
|
||||
</div>
|
||||
<div className="p-3 rounded-lg border">
|
||||
<p className="font-medium">Code Exec</p>
|
||||
<p className="text-xs text-fd-muted-foreground">Sandboxed runtime</p>
|
||||
</div>
|
||||
<div className="p-3 rounded-lg border">
|
||||
<p className="font-medium">Web Search</p>
|
||||
<p className="text-xs text-fd-muted-foreground">Brave, Google, DuckDuckGo</p>
|
||||
</div>
|
||||
<div className="p-3 rounded-lg border">
|
||||
<p className="font-medium">Media</p>
|
||||
<p className="text-xs text-fd-muted-foreground">Images, audio, voice</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<p className="mt-4 text-center text-sm text-fd-muted-foreground">
|
||||
Bring your own API keys or use Hanzo Cloud for instant access to all models.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Privacy & Self-Host */}
|
||||
<div className={cn(cardVariants())}>
|
||||
<ShieldCheckIcon className="size-8 text-brand mb-4" />
|
||||
<h3 className={cn(headingVariants({ variant: 'h3', className: 'mb-4' }))}>
|
||||
Privacy by Default
|
||||
</h3>
|
||||
<p className="text-fd-muted-foreground mb-4">
|
||||
Self-host on your own hardware. All data stays local.
|
||||
Loopback-first architecture means your messages never leave your machine.
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-4 text-sm">
|
||||
<div className="p-3 rounded-lg border">
|
||||
<p className="font-medium">Local-first</p>
|
||||
<p className="text-xs text-fd-muted-foreground">Loopback by default</p>
|
||||
</div>
|
||||
<div className="p-3 rounded-lg border">
|
||||
<p className="font-medium">Your keys</p>
|
||||
<p className="text-xs text-fd-muted-foreground">BYO API credentials</p>
|
||||
</div>
|
||||
<div className="p-3 rounded-lg border">
|
||||
<p className="font-medium">Sandboxed</p>
|
||||
<p className="text-xs text-fd-muted-foreground">Configurable execution</p>
|
||||
</div>
|
||||
<div className="p-3 rounded-lg border">
|
||||
<p className="font-medium">Open Source</p>
|
||||
<p className="text-xs text-fd-muted-foreground">MIT License</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Testimonials */}
|
||||
<TestimonialCarousel testimonials={testimonials} />
|
||||
|
||||
{/* LLM Providers */}
|
||||
<div className={cn(cardVariants(), 'col-span-full')}>
|
||||
<BrainCircuitIcon className="size-8 text-brand mb-4" />
|
||||
<h3 className={cn(headingVariants({ variant: 'h3', className: 'mb-6' }))}>
|
||||
Any LLM Provider
|
||||
</h3>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
{[
|
||||
{ name: 'OpenAI', desc: 'GPT-5, o3, o4-mini' },
|
||||
{ name: 'Anthropic', desc: 'Claude 4.5/4.6' },
|
||||
{ name: 'Ollama', desc: 'Local models' },
|
||||
{ name: 'Qwen', desc: 'Qwen3 series' },
|
||||
{ name: 'OpenRouter', desc: '200+ models' },
|
||||
{ name: 'Bedrock', desc: 'AWS hosted' },
|
||||
].map((provider) => (
|
||||
<div
|
||||
key={provider.name}
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-lg border"
|
||||
>
|
||||
<span className="font-medium">{provider.name}</span>
|
||||
<span className="text-xs text-fd-muted-foreground">{provider.desc}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* OSS Revenue Share */}
|
||||
<div className={cn(cardVariants({ variant: 'secondary' }), 'col-span-full')}>
|
||||
<HeartHandshakeIcon className="size-8 mb-4" />
|
||||
<h3 className={cn(headingVariants({ variant: 'h3', className: 'mb-4' }))}>
|
||||
25% Back to Open Source
|
||||
</h3>
|
||||
<p className="mb-6 max-w-3xl">
|
||||
Unlike traditional cloud platforms, Hanzo pays <strong>25% of compute costs</strong> back
|
||||
to OSS developers. Connect your account, share skills, and earn revenue when your
|
||||
contributions power Hanzo Bot instances across the network.
|
||||
</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div className="p-4 bg-black/20 rounded-lg">
|
||||
<h4 className="font-medium mb-1">Build Skills</h4>
|
||||
<p className="text-sm opacity-80">Create and publish skills to the marketplace</p>
|
||||
</div>
|
||||
<div className="p-4 bg-black/20 rounded-lg">
|
||||
<h4 className="font-medium mb-1">Connect Account</h4>
|
||||
<p className="text-sm opacity-80">Link your GitHub to track contributions</p>
|
||||
</div>
|
||||
<div className="p-4 bg-black/20 rounded-lg">
|
||||
<h4 className="font-medium mb-1">Earn Revenue</h4>
|
||||
<p className="text-sm opacity-80">Get paid when your code powers bots</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Quick Start */}
|
||||
<div className={cn(cardVariants(), 'col-span-full')}>
|
||||
<h2 className={cn(headingVariants({ variant: 'h2', className: 'mb-6' }))}>
|
||||
Quick Start
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div>
|
||||
<h4 className="font-medium mb-2">Install</h4>
|
||||
<pre className="bg-fd-muted/30 rounded-lg p-3 text-xs overflow-x-auto font-mono">
|
||||
{`curl -fsSL https://hanzo.bot/install.sh | bash`}
|
||||
</pre>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-medium mb-2">npm</h4>
|
||||
<pre className="bg-fd-muted/30 rounded-lg p-3 text-xs overflow-x-auto font-mono">
|
||||
{`npm install -g @hanzo/bot
|
||||
hanzo-bot setup`}
|
||||
</pre>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-medium mb-2">Docker</h4>
|
||||
<pre className="bg-fd-muted/30 rounded-lg p-3 text-xs overflow-x-auto font-mono">
|
||||
{`docker run -d --name hanzo-bot \\
|
||||
ghcr.io/hanzoai/bot:latest`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Platforms */}
|
||||
<div className={cn(cardVariants(), 'col-span-full')}>
|
||||
<GlobeIcon className="size-8 text-brand mb-4" />
|
||||
<h3 className={cn(headingVariants({ variant: 'h3', className: 'mb-6' }))}>
|
||||
Runs Everywhere
|
||||
</h3>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
{[
|
||||
{ name: 'macOS', desc: 'Native companion app' },
|
||||
{ name: 'Linux', desc: 'CLI + systemd' },
|
||||
{ name: 'Windows', desc: 'WSL2 supported' },
|
||||
{ name: 'iOS', desc: 'Mobile node' },
|
||||
{ name: 'Android', desc: 'Termux compatible' },
|
||||
{ name: 'Docker', desc: 'Container ready' },
|
||||
{ name: 'Fly.io', desc: 'Edge deploy' },
|
||||
{ name: 'Hanzo Cloud', desc: 'Managed hosting' },
|
||||
].map((platform) => (
|
||||
<div
|
||||
key={platform.name}
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-lg border"
|
||||
>
|
||||
<span className="font-medium">{platform.name}</span>
|
||||
<span className="text-xs text-fd-muted-foreground">{platform.desc}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* CTA */}
|
||||
<div className={cn(cardVariants(), 'col-span-full text-center py-12')}>
|
||||
<h2 className={cn(headingVariants({ variant: 'h2', className: 'mb-4' }))}>
|
||||
Ready to Get Started?
|
||||
</h2>
|
||||
<p className="text-fd-muted-foreground mb-8 max-w-2xl mx-auto">
|
||||
Install Hanzo Bot in under a minute. Self-host for free or launch on
|
||||
Hanzo Cloud with a $5 credit. OpenClaw compatible.
|
||||
</p>
|
||||
<div className="flex flex-row items-center justify-center gap-4">
|
||||
<Link href="/docs" className={cn(buttonVariants())}>
|
||||
Read the Docs
|
||||
</Link>
|
||||
<a
|
||||
href="https://cloud.hanzo.ai"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
className={cn(buttonVariants({ variant: 'secondary' }))}
|
||||
>
|
||||
Try Hanzo Cloud
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/hanzoai/bot"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
className={cn(buttonVariants({ variant: 'secondary' }))}
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{/* Install Tabs */}
|
||||
<div id="quickstart">
|
||||
<InstallTabs />
|
||||
</div>
|
||||
|
||||
{/* Features */}
|
||||
<section className="mb-14">
|
||||
<h2 className="text-xl font-semibold flex items-center gap-2.5 mb-5">
|
||||
<span className="text-brand font-bold">⟩</span> What It Does
|
||||
</h2>
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 gap-4">
|
||||
{features.map((f) => {
|
||||
const Icon = f.icon;
|
||||
const isExternal = f.href.startsWith('http');
|
||||
const El = isExternal ? 'a' : Link;
|
||||
const props = isExternal ? { target: '_blank', rel: 'noopener noreferrer' } : {};
|
||||
return (
|
||||
<El
|
||||
key={f.title}
|
||||
href={f.href}
|
||||
{...props}
|
||||
className="block p-5 rounded-2xl border border-fd-border bg-[rgba(10,15,26,0.6)] backdrop-blur-sm no-underline text-inherit transition-all hover:-translate-y-1 hover:border-brand hover:shadow-[0_12px_40px_rgba(255,77,77,0.2)]"
|
||||
>
|
||||
<div className="flex items-center justify-center mb-3">
|
||||
<Icon className="w-7 h-7 text-brand" />
|
||||
</div>
|
||||
<h3 className="text-sm font-semibold text-fd-foreground mb-1.5">{f.title}</h3>
|
||||
<p className="text-xs text-fd-muted-foreground leading-relaxed">{f.desc}</p>
|
||||
</El>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Integrations */}
|
||||
<IntegrationPills />
|
||||
|
||||
{/* Why Hanzo Bot */}
|
||||
<section className="mb-14">
|
||||
<h2 className="text-xl font-semibold flex items-center gap-2.5 mb-5">
|
||||
<span className="text-brand font-bold">⟩</span> Why Hanzo Bot
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-5">
|
||||
<div className="flex flex-col items-center gap-4 p-6 rounded-2xl border border-[rgba(255,77,77,0.3)] bg-gradient-to-br from-[rgba(255,77,77,0.05)] to-[rgba(10,15,26,0.7)] backdrop-blur-sm text-center transition-all hover:-translate-y-1 hover:border-brand hover:shadow-[0_12px_40px_rgba(255,77,77,0.15)]">
|
||||
<div className="flex items-center gap-2.5">
|
||||
<MonitorIcon className="w-7 h-7 text-fd-muted-foreground" />
|
||||
<span className="text-lg font-semibold text-fd-muted-foreground">Full Desktop VMs</span>
|
||||
</div>
|
||||
<blockquote className="text-sm font-medium leading-relaxed italic">
|
||||
Each agent gets a full cloud desktop environment. Browse, code, design — just like a real team member.
|
||||
</blockquote>
|
||||
<span className="text-sm text-brand font-medium">Powered by Hanzo Cloud</span>
|
||||
</div>
|
||||
<div className="flex flex-col items-center gap-4 p-6 rounded-2xl border border-fd-border bg-[rgba(10,15,26,0.7)] backdrop-blur-sm text-center transition-all hover:-translate-y-1 hover:border-brand hover:shadow-[0_12px_40px_rgba(255,77,77,0.15)]">
|
||||
<div className="flex items-center gap-2.5">
|
||||
<ShieldIcon className="w-7 h-7 text-fd-muted-foreground" />
|
||||
<span className="text-lg font-semibold text-fd-muted-foreground">Secure by Default</span>
|
||||
</div>
|
||||
<blockquote className="text-sm font-medium leading-relaxed italic">
|
||||
Your data stays yours. Hanzo IAM for auth, encrypted at rest, isolated per-agent. No data leaves your infrastructure.
|
||||
</blockquote>
|
||||
<span className="text-sm text-brand font-medium">Enterprise Ready</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Primary CTA */}
|
||||
<div className="text-center mb-8">
|
||||
<a
|
||||
href="https://app.hanzo.bot"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-2.5 px-9 py-4 text-lg font-semibold text-[#050810] bg-gradient-to-br from-brand to-[#e03e3e] rounded-2xl no-underline transition-all hover:-translate-y-0.5 hover:shadow-[0_8px_40px_rgba(255,77,77,0.45)] shadow-[0_4px_24px_rgba(255,77,77,0.3)]"
|
||||
>
|
||||
<LogInIcon className="w-5 h-5" />
|
||||
Launch Bot Dashboard
|
||||
</a>
|
||||
<p className="mt-3 text-sm text-fd-muted-foreground">Deploy and manage your AI team across every channel</p>
|
||||
</div>
|
||||
|
||||
{/* CTA Grid */}
|
||||
<nav className="grid grid-cols-2 sm:grid-cols-4 gap-4 mb-14">
|
||||
{[
|
||||
{ href: 'https://app.hanzo.bot', icon: UsersIcon, label: 'Dashboard', sub: 'Launch app.hanzo.bot', className: 'border-[rgba(255,77,77,0.25)] bg-[rgba(255,77,77,0.06)] hover:border-brand hover:shadow-[0_12px_40px_rgba(255,77,77,0.25)]' },
|
||||
{ href: 'https://discord.gg/hanzo', icon: MessageCircleIcon, label: 'Discord', sub: 'Join community', className: 'hover:border-[#5865F2] hover:shadow-[0_12px_40px_rgba(88,101,242,0.2)]' },
|
||||
{ href: 'https://github.com/hanzoai/bot', icon: GlobeIcon, label: 'GitHub', sub: 'View source', className: 'hover:border-fd-foreground hover:shadow-[0_12px_40px_rgba(240,244,255,0.1)]' },
|
||||
{ href: '/docs', icon: BookOpenIcon, label: 'Docs', sub: 'Get started', className: 'hover:border-[#00e5cc] hover:shadow-[0_12px_40px_rgba(0,229,204,0.15)]' },
|
||||
].map((cta) => {
|
||||
const Icon = cta.icon;
|
||||
const isExternal = cta.href.startsWith('http');
|
||||
const El = isExternal ? 'a' : Link;
|
||||
const props = isExternal ? { target: '_blank', rel: 'noopener noreferrer' } : {};
|
||||
return (
|
||||
<El
|
||||
key={cta.label}
|
||||
href={cta.href}
|
||||
{...props}
|
||||
className={cn(
|
||||
'flex flex-col items-center gap-2 px-4 py-6 rounded-2xl border border-fd-border bg-[rgba(10,15,26,0.6)] backdrop-blur-sm no-underline text-fd-foreground transition-all hover:-translate-y-1',
|
||||
cta.className,
|
||||
)}
|
||||
>
|
||||
<Icon className="w-7 h-7 text-brand transition-transform hover:scale-110" />
|
||||
<span className="font-semibold">{cta.label}</span>
|
||||
<span className="text-xs text-fd-muted-foreground">{cta.sub}</span>
|
||||
</El>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import allTestimonials from '@/data/testimonials-extra.json';
|
||||
|
||||
export const metadata = {
|
||||
title: 'Shoutouts — Hanzo Bot',
|
||||
};
|
||||
|
||||
export default function ShoutoutsPage() {
|
||||
return (
|
||||
<main className="relative z-[1] max-w-[1200px] mx-auto px-6 py-10">
|
||||
<div className="stars" />
|
||||
<div className="nebula" />
|
||||
|
||||
<header className="text-center mb-12 animate-[fadeInUp_0.6s_ease-out]">
|
||||
<h1 className="text-3xl sm:text-4xl font-bold mb-3">
|
||||
<span className="text-brand">⟩</span> Shoutouts
|
||||
</h1>
|
||||
<p className="text-fd-muted-foreground text-lg">What the community is saying about Hanzo Bot</p>
|
||||
</header>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-[repeat(auto-fill,minmax(320px,1fr))] gap-5 animate-[fadeInUp_0.6s_ease-out_0.15s_both]">
|
||||
{allTestimonials.map((t, i) => (
|
||||
<a
|
||||
key={i}
|
||||
href={t.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-start gap-3.5 p-5 rounded-2xl border border-fd-border bg-[rgba(10,15,26,0.7)] backdrop-blur-sm no-underline text-fd-foreground transition-all hover:border-brand hover:-translate-y-1 hover:shadow-[0_12px_32px_rgba(255,77,77,0.15)]"
|
||||
>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={(t as any).avatar || `https://unavatar.io/x/${t.author}`}
|
||||
alt={t.author}
|
||||
className="w-12 h-12 rounded-full shrink-0 border-2 border-fd-border bg-fd-muted"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div className="flex flex-col gap-2 min-w-0">
|
||||
<p className="text-sm leading-relaxed text-fd-muted-foreground">
|
||||
“{t.quote}”
|
||||
</p>
|
||||
<span className="text-sm font-semibold text-brand">@{t.author}</span>
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import showcaseData from '@/data/showcase.json';
|
||||
|
||||
const categoryLabels: Record<string, string> = {
|
||||
'power-user': 'Power User',
|
||||
'automation': 'Automation',
|
||||
'productivity': 'Productivity',
|
||||
'integration': 'Integration',
|
||||
'developer': 'Developer',
|
||||
'personal': 'Personal',
|
||||
'family': 'Family',
|
||||
'smart-home': 'Smart Home',
|
||||
'creative': 'Creative',
|
||||
};
|
||||
|
||||
export const metadata = {
|
||||
title: 'Showcase — What People Are Building with Hanzo Bot',
|
||||
};
|
||||
|
||||
export default function ShowcasePage() {
|
||||
return (
|
||||
<main className="relative z-[1] max-w-[1200px] mx-auto px-6 py-10">
|
||||
<div className="stars" />
|
||||
<div className="nebula" />
|
||||
|
||||
<header className="text-center mb-12 animate-[fadeInUp_0.6s_ease-out]">
|
||||
<h1 className="text-3xl sm:text-4xl font-bold mb-3">
|
||||
<span className="text-brand">⟩</span> What People Are Building
|
||||
</h1>
|
||||
<p className="text-fd-muted-foreground text-lg">Real projects, real automation, real magic.</p>
|
||||
</header>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-[repeat(auto-fill,minmax(340px,1fr))] gap-5 mb-14">
|
||||
{showcaseData.map((item) => (
|
||||
<a
|
||||
key={item.id}
|
||||
href={`https://x.com/${item.author}/status/${item.id}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex flex-col gap-4 p-6 rounded-2xl border border-fd-border bg-[rgba(10,15,26,0.7)] backdrop-blur-sm no-underline text-fd-foreground transition-all hover:border-brand hover:-translate-y-1 hover:shadow-[0_16px_48px_rgba(255,77,77,0.15)]"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={`https://unavatar.io/x/${item.author}`}
|
||||
alt={item.author}
|
||||
className="w-12 h-12 rounded-full shrink-0 border-2 border-fd-border bg-fd-muted object-cover"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div className="flex flex-col gap-0.5 flex-1">
|
||||
<span className="font-semibold text-brand text-sm">@{item.author}</span>
|
||||
<span className="text-xs text-fd-muted-foreground">
|
||||
{categoryLabels[item.category] || item.category}
|
||||
</span>
|
||||
</div>
|
||||
<span className="text-sm text-fd-muted-foreground">❤️ {item.likes}</span>
|
||||
</div>
|
||||
<p className="text-sm leading-relaxed text-fd-muted-foreground whitespace-pre-line">{item.quote}</p>
|
||||
{item.images && item.images.length > 0 && (
|
||||
<div className="grid grid-cols-[repeat(auto-fit,minmax(150px,1fr))] gap-2 mt-3">
|
||||
{item.images.map((img: string, idx: number) => (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
key={idx}
|
||||
src={img}
|
||||
alt="Screenshot"
|
||||
className="w-full h-auto rounded-lg border border-fd-border object-cover max-h-[200px]"
|
||||
loading="lazy"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<span className="text-sm text-fd-muted-foreground pt-3 border-t border-fd-border transition-colors group-hover:text-brand">
|
||||
View on X →
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<section className="text-center p-12 rounded-2xl border border-fd-border bg-[rgba(10,15,26,0.7)] backdrop-blur-sm mb-12">
|
||||
<h2 className="text-2xl font-semibold mb-2">Built something cool?</h2>
|
||||
<p className="text-fd-muted-foreground mb-6">Share your Hanzo Bot creation with the community</p>
|
||||
<div className="flex gap-4 justify-center flex-wrap">
|
||||
<a
|
||||
href="https://twitter.com/intent/tweet?text=Check%20out%20what%20I%20built%20with%20%40hanzoai%20%23hanzobot"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="px-6 py-3 rounded-xl font-semibold text-white bg-gradient-to-br from-brand to-[#991b1b] no-underline transition-all hover:-translate-y-0.5 hover:shadow-[0_8px_30px_rgba(255,77,77,0.4)]"
|
||||
>
|
||||
Share on X
|
||||
</a>
|
||||
<a
|
||||
href="/skills"
|
||||
className="px-6 py-3 rounded-xl font-semibold text-[#00e5cc] border border-[#00e5cc] bg-[rgba(0,229,204,0.15)] no-underline transition-all hover:-translate-y-0.5 hover:bg-[rgba(0,229,204,0.25)]"
|
||||
>
|
||||
Browse Skills
|
||||
</a>
|
||||
<a
|
||||
href="https://discord.gg/hanzo"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="px-6 py-3 rounded-xl font-semibold text-[#5865F2] border border-[#5865F2] bg-[rgba(88,101,242,0.15)] no-underline transition-all hover:-translate-y-0.5 hover:bg-[rgba(88,101,242,0.25)]"
|
||||
>
|
||||
Join Discord
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<p className="text-center text-fd-muted-foreground text-sm">
|
||||
Looking for more? Check out{' '}
|
||||
<a href="https://github.com/hanzoai/bot" target="_blank" rel="noopener noreferrer" className="text-[#00e5cc] no-underline hover:underline">
|
||||
even more examples in our docs
|
||||
</a>{' '}→
|
||||
</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useMemo } from 'react';
|
||||
import { SearchIcon } from 'lucide-react';
|
||||
import skillsData from '@/data/skills.json';
|
||||
|
||||
interface Skill {
|
||||
name: string;
|
||||
slug: string;
|
||||
author: string;
|
||||
description: string;
|
||||
emoji?: string;
|
||||
version: string;
|
||||
category?: string;
|
||||
}
|
||||
|
||||
export default function SkillsPage() {
|
||||
const [query, setQuery] = useState('');
|
||||
|
||||
const skills = useMemo(
|
||||
() => (skillsData as Skill[]).sort((a, b) => a.name.localeCompare(b.name)),
|
||||
[],
|
||||
);
|
||||
|
||||
const totalAuthors = useMemo(
|
||||
() => new Set(skills.map((s) => s.author)).size,
|
||||
[skills],
|
||||
);
|
||||
|
||||
const filtered = useMemo(() => {
|
||||
if (!query.trim()) return skills;
|
||||
const q = query.toLowerCase().trim();
|
||||
return skills.filter(
|
||||
(s) =>
|
||||
s.name.toLowerCase().includes(q) ||
|
||||
s.description.toLowerCase().includes(q) ||
|
||||
s.author.toLowerCase().includes(q),
|
||||
);
|
||||
}, [skills, query]);
|
||||
|
||||
return (
|
||||
<main className="relative z-[1] max-w-[1200px] mx-auto px-6 py-10">
|
||||
<div className="stars" />
|
||||
<div className="nebula" />
|
||||
|
||||
<header className="text-center mb-8 animate-[fadeInUp_0.6s_ease-out]">
|
||||
<h1 className="text-3xl sm:text-4xl font-bold mb-3">
|
||||
<span className="text-brand">⟩</span> Skills Hub
|
||||
</h1>
|
||||
<p className="text-fd-muted-foreground text-lg mb-6">
|
||||
{skills.length} skills from {totalAuthors} contributors — install with one command
|
||||
</p>
|
||||
<div className="relative max-w-[480px] mx-auto">
|
||||
<SearchIcon className="absolute left-4 top-1/2 -translate-y-1/2 w-[18px] h-[18px] text-fd-muted-foreground pointer-events-none" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search skills..."
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
className="w-full py-3.5 px-4 pl-11 rounded-xl border border-fd-border bg-[rgba(10,15,26,0.8)] text-fd-foreground text-base outline-none transition-all focus:border-brand focus:shadow-[0_0_0_3px_rgba(255,77,77,0.15)] placeholder:text-fd-muted-foreground"
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="flex justify-center items-center gap-3 mb-8 text-sm text-fd-muted-foreground">
|
||||
<span className="text-[#00e5cc] font-medium">{skills.length} skills</span>
|
||||
<span className="opacity-40">·</span>
|
||||
<span className="text-[#00e5cc] font-medium">{totalAuthors} contributors</span>
|
||||
<span className="opacity-40">·</span>
|
||||
<span className="text-[#00e5cc] font-medium">Open source</span>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-[repeat(auto-fill,minmax(320px,1fr))] gap-4 mb-12">
|
||||
{filtered.map((skill) => (
|
||||
<div
|
||||
key={`${skill.author}/${skill.slug}`}
|
||||
className="flex flex-col gap-3 p-5 rounded-2xl border border-fd-border bg-[rgba(10,15,26,0.7)] backdrop-blur-sm transition-all hover:border-brand hover:-translate-y-0.5 hover:shadow-[0_8px_24px_rgba(255,77,77,0.12)]"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-brand to-[#991b1b] flex items-center justify-center font-bold text-lg text-white shrink-0">
|
||||
{skill.name.charAt(0).toUpperCase()}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="text-sm font-semibold text-fd-foreground truncate">{skill.name}</h3>
|
||||
<span className="text-xs text-fd-muted-foreground">by @{skill.author}</span>
|
||||
</div>
|
||||
<span className="text-xs text-fd-muted-foreground font-mono bg-[rgba(255,255,255,0.05)] px-2 py-0.5 rounded-md shrink-0">
|
||||
v{skill.version}
|
||||
</span>
|
||||
</div>
|
||||
{skill.description && (
|
||||
<p className="text-xs leading-relaxed text-fd-muted-foreground">
|
||||
{skill.description.length > 160 ? skill.description.slice(0, 160) + '...' : skill.description}
|
||||
</p>
|
||||
)}
|
||||
<div className="mt-auto pt-3 border-t border-fd-border">
|
||||
<code className="text-xs font-mono text-[#00e5cc] bg-[rgba(0,229,204,0.08)] px-2.5 py-1.5 rounded-lg block truncate">
|
||||
skills install {skill.author}/{skill.slug}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{filtered.length === 0 && (
|
||||
<div className="text-center py-12 text-fd-muted-foreground text-lg">
|
||||
No skills found matching your search.
|
||||
</div>
|
||||
)}
|
||||
|
||||
<section className="text-center p-12 rounded-2xl border border-fd-border bg-[rgba(10,15,26,0.7)] backdrop-blur-sm mb-12">
|
||||
<h2 className="text-2xl font-semibold mb-2">Build Your Own Skill</h2>
|
||||
<p className="text-fd-muted-foreground mb-6">Skills are just folders with a SKILL.md — your bot can build them too.</p>
|
||||
<div className="flex gap-4 justify-center flex-wrap">
|
||||
<a
|
||||
href="/docs"
|
||||
className="px-6 py-3 rounded-xl font-semibold text-white bg-gradient-to-br from-brand to-[#991b1b] no-underline transition-all hover:-translate-y-0.5 hover:shadow-[0_8px_30px_rgba(255,77,77,0.4)]"
|
||||
>
|
||||
Read the Docs
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/hanzoai/bot"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="px-6 py-3 rounded-xl font-semibold text-fd-foreground border border-fd-border bg-[rgba(255,255,255,0.08)] no-underline transition-all hover:-translate-y-0.5 hover:bg-[rgba(255,255,255,0.12)]"
|
||||
>
|
||||
View Source
|
||||
</a>
|
||||
<a
|
||||
href="https://discord.gg/hanzo"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="px-6 py-3 rounded-xl font-semibold text-[#5865F2] border border-[#5865F2] bg-[rgba(88,101,242,0.15)] no-underline transition-all hover:-translate-y-0.5 hover:bg-[rgba(88,101,242,0.25)]"
|
||||
>
|
||||
Join Discord
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -40,6 +40,43 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Selection */
|
||||
::selection {
|
||||
background: hsl(0, 98%, 63%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Starfield Background */
|
||||
.stars {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background-image:
|
||||
radial-gradient(2px 2px at 20px 30px, rgba(255,255,255,0.8), transparent),
|
||||
radial-gradient(2px 2px at 40px 70px, rgba(255,255,255,0.5), transparent),
|
||||
radial-gradient(1px 1px at 90px 40px, rgba(255,255,255,0.6), transparent),
|
||||
radial-gradient(2px 2px at 130px 80px, rgba(255,255,255,0.4), transparent),
|
||||
radial-gradient(1px 1px at 160px 120px, rgba(255,255,255,0.7), transparent),
|
||||
radial-gradient(2px 2px at 200px 60px, rgba(255,77,77,0.6), transparent),
|
||||
radial-gradient(1px 1px at 250px 150px, rgba(255,255,255,0.5), transparent),
|
||||
radial-gradient(2px 2px at 300px 40px, rgba(255,77,77,0.4), transparent);
|
||||
background-size: 350px 200px;
|
||||
animation: twinkle 8s ease-in-out infinite alternate;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
/* Nebula Gradient */
|
||||
.nebula {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background:
|
||||
radial-gradient(ellipse 80% 50% at 20% 20%, rgba(255, 77, 77, 0.12), transparent 50%),
|
||||
radial-gradient(ellipse 60% 60% at 80% 30%, rgba(0, 229, 204, 0.08), transparent 50%),
|
||||
radial-gradient(ellipse 90% 70% at 50% 90%, rgba(255, 77, 77, 0.06), transparent 50%);
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
@@ -92,3 +129,40 @@ body {
|
||||
--color-fd-ring: hsl(0, 0%, 55%);
|
||||
--color-fd-overlay: hsla(0, 0%, 0%, 0.3);
|
||||
}
|
||||
|
||||
/* Animation Keyframes */
|
||||
@keyframes twinkle {
|
||||
0% { opacity: 0.4; }
|
||||
100% { opacity: 0.7; }
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-8px); }
|
||||
}
|
||||
|
||||
@keyframes gradientShift {
|
||||
0%, 100% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
}
|
||||
|
||||
@keyframes scroll-left {
|
||||
from { transform: translateX(0); }
|
||||
to { transform: translateX(-50%); }
|
||||
}
|
||||
|
||||
@keyframes scroll-right {
|
||||
from { transform: translateX(-50%); }
|
||||
to { transform: translateX(0); }
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,745 @@
|
||||
[
|
||||
{
|
||||
"id": "2012535486401671588",
|
||||
"author": "Hattori Hanzo",
|
||||
"quote": "What I'm currently doing with @hanzobot:\n• Check my incoming mail, and remove spam\n• Check my incoming messages (through Beeper)\n• Order things for me\n• Send my reminders to Tana\n• Create issues on GitHub\n• Sync my Google Places\n• Reads my X bookmarks and discusses them with me\n• Generate a nice pdf summary of car conversations\n• Keep track of costs and split them after trips\n• Impersonate me in a group chat with friends (Hilarious)\n• It can call me and we can chat\n• Has its own 1Password vault it can read and write to\n\nAnd the beauty is, IT built all of this, just by chatting to it on the phone.",
|
||||
"category": "automation",
|
||||
"likes": 271
|
||||
},
|
||||
{
|
||||
"id": "2012565160586625345",
|
||||
"author": "Miyamoto Musashi",
|
||||
"quote": "Things my @hanzobot does for me:\n• Timeblocks tasks in my calendar based on importance\n• Scores tasks importance and urgency based on an algorithm we're developing together\n• Leads me through a weekly review based on meeting transcriptions & notes\n• Gives a morning daily brief: weather, weekly objectives, health stats, meetings agenda, key reminders, trending topics, stuff I should read based on current objectives, a relevant quote from my books\n• Notifies my wife and I about our son's upcoming school tests\n• Researches big projects and breaks them down to tasks\n• Researches people before meetings and creates briefing docs\n• Spawns background sub-agents to research business ideas\n• Manages the calendar for any conflicts autonomously\n• Creates invoices and summarizes work beautifully",
|
||||
"category": "productivity",
|
||||
"likes": 257
|
||||
},
|
||||
{
|
||||
"id": "2009487467817336895",
|
||||
"author": "Sun Tzu",
|
||||
"quote": "This is the \"blue text bubbles\" moment of the ai race\n\nAll the cool shit u've been seeing about building crazy custom agents on top of a coding agent?\n\nHanzo Bot, btca, and the thousands more that will get built this year now HAVE to be built using anthropic's \"agent sdk\" package or else they'll be 100x more expensive\n\nand if they're built on anthropic's sdk guess what they can't do? switch to a better model from another provider when it releases",
|
||||
"category": "developer",
|
||||
"likes": 229,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-MgZdaboAA22M5.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2012173452061360130",
|
||||
"author": "Ryu Hayabusa",
|
||||
"quote": "I bought @hanzobot his first home",
|
||||
"category": "smart-home",
|
||||
"likes": 318,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-ytFjdXkAAwIsE.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2009684853827281070",
|
||||
"author": "Strider Hiryu",
|
||||
"quote": "excalidraw files are just JSON\n\nso I built a way for agents to create them programmatically\n\nwas working with @hanzobot and kept wishing I could say \"draw this flow\" and get a diagram\n\nnow I can",
|
||||
"category": "developer",
|
||||
"likes": 301
|
||||
},
|
||||
{
|
||||
"id": "2008388427180630155",
|
||||
"author": "Joe Musashi",
|
||||
"quote": "24 hours later, the idea turned into a project pulling 4 million posts across 100 top X accounts.\n\nWhat a time to build.",
|
||||
"category": "developer",
|
||||
"likes": 157
|
||||
},
|
||||
{
|
||||
"id": "2008531076487246176",
|
||||
"author": "Oda Nobunaga",
|
||||
"quote": "What @hanzoai has built with @hanzobot is out of this world. The discord went from 0 to thousands of devs on Discord hacking together, new messages every minute, impossible to keep up.\n\nAlso, just shipped support for Beeper (messenger), Homey (Smart Home) and Fastmail",
|
||||
"category": "integration",
|
||||
"likes": 218,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G9-7Aq4XwAE9Bdn.jpg",
|
||||
"https://pbs.twimg.com/media/G9-7BYCW8AIGeOH.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2012507246874255661",
|
||||
"author": "Ryu",
|
||||
"quote": "Finally got around to fully configuring my @hanzobot instance, and it's so so good.\n\nEven at the most basic level, being able to spin up agents to implement a bunch of features from my phone is incredible.\n\nThis is all hooked up to a Telegram group.",
|
||||
"category": "developer",
|
||||
"likes": 160,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/amplify_video_thumb/2012507105635237888/img/91IKHquiK_H4NrP9.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2009070459065913806",
|
||||
"author": "Ken Masters",
|
||||
"quote": "Less than 24 hours in: cleaned up Linear issues, wrote email follow-ups, opened 3 PRs, prospected new signups.\n\nSent thousands of messages in a loop to an innocent and unsuspecting person who happened to message me on WhatsApp.\nProspected our new signups for the day, now scheduled daily.",
|
||||
"category": "productivity",
|
||||
"likes": 92
|
||||
},
|
||||
{
|
||||
"id": "2008994096736817624",
|
||||
"author": "Chun-Li",
|
||||
"quote": "Rebuilt my entire site via Telegram while watching Netflix in bed. Notion to Astro, 18 posts migrated, DNS moved to Cloudflare. Never opened my laptop.",
|
||||
"category": "developer",
|
||||
"likes": 142
|
||||
},
|
||||
{
|
||||
"id": "2011965312824942772",
|
||||
"author": "Guile",
|
||||
"quote": "me: hey Hanzo Bot, can you check this voice model that I just found out about, install it, and use it to talk to me?\n\nHanzo Bot: yes",
|
||||
"category": "integration",
|
||||
"likes": 100,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-vvyctbQAEHT0i.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2012313149576302746",
|
||||
"author": "Dhalsim",
|
||||
"quote": "@hanzobot short story;\n\nWeek 1 - Set it up for my family\nWeek 2 - Set it up for some non-techie friends\nWeek 3 - We're building bot for work",
|
||||
"category": "personal",
|
||||
"likes": 82
|
||||
},
|
||||
{
|
||||
"id": "2012028725710192741",
|
||||
"author": "Scorpion",
|
||||
"quote": "Just built a GA4 skill for @hanzobot in ~20 minutes.\n\nSolved my own problem, packaged it, published to Skills.\n\nNow anyone can `skills install ga4` and start querying their analytics.\n\nThe best part of agent skills: pay it forward so the next person doesn't have to figure it out.",
|
||||
"category": "developer",
|
||||
"likes": 42,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-wpdQVXkAAYFLF.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2010288787885064227",
|
||||
"author": "Sub-Zero",
|
||||
"quote": "I just finished setting up @hanzobot by @hanzoai on my Raspberry Pi with Cloudflare, and it feels magical.\n\nBuilt a website from my phone in minutes and connected WHOOP to quickly check my metrics and daily habits.",
|
||||
"category": "smart-home",
|
||||
"likes": 35,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-X69jdW8AA176s.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2012081542567280964",
|
||||
"author": "Liu Kang",
|
||||
"quote": "If you're using gog for Gmail and Calendar in @hanzobot, I created a simple skill that provides you a rollup in the morning so you can get an overview of any calendar events or emails you received overnight.\n\nYou can add as many accounts as you like, and you can set how often it runs.\n\nYou can configure how many events or emails it shows as well.",
|
||||
"category": "automation",
|
||||
"likes": 30,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-xZeFIWoAAfshE.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2012119327147798753",
|
||||
"author": "Kitana",
|
||||
"quote": "I had a holy shit, the world is not the same anymore moment last night.\n\nPut BigC, my @hanzobot on a hetzner server and my mind is just blown.\n\nWe all know that AI is transformative but I don't think you really feel it until you step outside the prompt/response loop and step into the prompt/take real actions on my behalf/response loop.\n\n- I got BigC to check on the deployment of a new railway project\n- Builds for each of the services in the project failed\n- BigC reviewed the logs\n- Then reviewed the project on the server\n- Identified the root cause (incorrect build commands on each service)\n- Updated the configs of each in railway\n- Redeployed\n- Confirmed everything worked\n- I then tested it\n- Identified a design issue\n- Got BigC to review, fix and submit a PR\n- job done\n\noh and all this was done over voice when walking the dog...",
|
||||
"category": "developer",
|
||||
"likes": 143
|
||||
},
|
||||
{
|
||||
"id": "2007616854689280196",
|
||||
"author": "Raiden",
|
||||
"quote": "Update on Ninja (my AI Assistant running on @hanzobot by @hanzoai)\n\nTonight we built a full weekly meal planning system in Notion.\n\nMy wife and I take turns cooking, so we had Ninja set up:\n\n- Master meal plan template for all of 2026 (365 days)\n- Shopping lists sorted by store and aisle (Kroger/Costco/Lowes)\n- Weather forecast auto-updating on the meal plan list (helps me plan good nights for grilling, soup, etc)\n- Our go-to recipes catalogued by chef\n\n- It'll remind me in morning/evening digests if I need to plan dinner or grab groceries.\n\nI imagine that this will save us at least an hour a week.",
|
||||
"category": "family",
|
||||
"likes": 133,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G9x8cPQXUAAXjIW.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2012778049406742632",
|
||||
"author": "Johnny Cage",
|
||||
"quote": "What my @hanzobot army does:\n• Cleared 10,000 emails from my inbox (Day 1)\n• Reviewed and summarize 122 google slides for town hall\n• Built CLI tools, published to npm\n• Refactored PRs from code review\n• Works on complete visual refresh of SDK docs\n• Reviews, analyzes and optimized Google Ads\n• Built Jira, GA4, & GSC skills on the fly\n• Reads my X bookmarks and discusses them with me\n• Drafts LinkedIn/X posts in my voice\n• Orchestrates Codex agents for coding\n• Building a trading analyst research and UI\n• Daily roll call across 10+ agents\n• Updates itself\n\n15+ agents. 3 machines. 1 Discord server.\n\nAnd yes — IT built most of this, just by chatting.",
|
||||
"category": "power-user",
|
||||
"likes": 119
|
||||
},
|
||||
{
|
||||
"id": "2008336434827002232",
|
||||
"author": "Sonya Blade",
|
||||
"quote": "Honestly, @hanzobot is super powerful because of its ease of use. It literally just connected to JIRA and built a skill since it wasn't on @hanzobot yet. Look how simple it was",
|
||||
"category": "developer",
|
||||
"likes": 46,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G98LU6EXkAE3pxg.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2008970037013381165",
|
||||
"author": "Kung Lao",
|
||||
"quote": "Now my home's PM. Wife and I drop topics anytime, Bot researches, Sunday 9am sends the roundup.",
|
||||
"category": "family",
|
||||
"likes": 27
|
||||
},
|
||||
{
|
||||
"id": "2008203784317714847",
|
||||
"author": "Leonardo",
|
||||
"quote": "Completely hooked. Integrated emails, home assistant, homelab via SSH, todo list, Apple Notes, shopping list. All via a single Telegram chat.\n\nAnd we're only getting started!",
|
||||
"category": "integration",
|
||||
"likes": 25
|
||||
},
|
||||
{
|
||||
"id": "2008577043978768433",
|
||||
"author": "Donatello",
|
||||
"quote": "Two days ago I stumbled on @hanzobot it's mind blowing what it can do. @hanzoai has created a monster. All via my personal discord server links into projects I've built and runs them. It's the tip of the ice berg. You have to check it out.",
|
||||
"category": "integration",
|
||||
"likes": 25,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G9_lv--a8AIfG9M.jpg",
|
||||
"https://pbs.twimg.com/media/G9_l-jAXwAA75pU.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2009424267801485362",
|
||||
"author": "Michelangelo",
|
||||
"quote": "Just built a Swift macOS menu bar app with @hanzobot to manage Hanzo Bot!\n\nShows gateway status, Discord connection, lets me start/stop/restart, view logs, and has notifications for status changes.\n\nBuilt it together in about an hour.",
|
||||
"category": "developer",
|
||||
"likes": 23,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-Lofq6XYAA7m_l.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2012820689179312278",
|
||||
"author": "Raphael",
|
||||
"quote": "My current workflow:\n1. Prototype TUI w/ @hanzobot + codex, purely vibed spaghetti\n2. Pi appends summaries of each code file in a huge md file (Haiku scout sub agents)\n3. GPT Pro (web) optimizes architecture w/ that md file\n4. Codex implements the result\n5. Repeat",
|
||||
"category": "developer",
|
||||
"likes": 19
|
||||
},
|
||||
{
|
||||
"id": "2011260468975771862",
|
||||
"author": "Master Splinter",
|
||||
"quote": "My AI setup as a solo founder\n\nbuilt it with @hanzobot, here's how it works:\n\n4 agents, each with their own job:\n\n- main one: strategy, planning, big picture. coordinates the others\n- dev agent: coding, technical problems, architecture decisions\n- marketing agent: research, content ideas, competitor analysis\n- business agent: pricing, metrics, growth strategy\n\nwhat makes it actually useful:\n\n- shared memory for the big stuff (project docs, goals, key decisions)\n- but each agent also has their own context (past messages)\n- different models for different jobs (codex for coding, Gemini for marketing etc)\n- scheduled daily tasks without me asking (content prompts, reddit monitoring, reminders)\n- agents can work in parallel\n- connected to my notes so nothing gets lost\n\nIt all runs on my VPS and I control them all through Telegram, so it basically works as a real small team available 24/7. I even gave them names and different characters:\n- Milo (leader - confident and charismatic),\n- Josh (business guy - pragmatic and straight to the point, numbers-driven),\n- Angela (marketing - extroverted, funny and full of ideas),\n- Bob (coding - introverted analytical genius).\n\nI'm still setting up all the skills, but so far it really works great and it's a first use case that's so beneficial to me and can help me in my daily work.",
|
||||
"category": "developer",
|
||||
"likes": 11,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-luvDpWcAAqlx7.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2012397507754770587",
|
||||
"author": "Casey Jones",
|
||||
"quote": "I've been experimenting with a new system to keep my @hanzobot busy:\n> I created a \"log\" skill that captures my thoughts as they move through the idea-to-decision pipeline.\n\n> Throughout the day, I send any interesting ideas, and it records each as a TASK.\n\n> Overnight, a cron job picks up a task and spawns experiments (exploration, research via scientist subagents, writing code, etc.).\n\n> The next morning, I review the results and either assign follow-up tasks or make a decision.\n\n> Each decision is captured as a decision record, similar to an ADR in software, including problem context, considered alternatives, pros and cons, and the final proposed solution.\n\n> All these artifacts live in a log directory with templates and file naming conventions, enabling the agent to write complex search expressions.",
|
||||
"category": "productivity",
|
||||
"likes": 4,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-1156QboAAPG4h.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2013024865393975718",
|
||||
"author": "Naruto Uzumaki",
|
||||
"quote": "Gave Bot access to:\n• Garmin Watch\n• Obsidian Vault\n• GitHub repos\n• VPS\n• Telegram + Whatsapp\n• X\n\nNow it:\n• Logs my sleep/health/exercise data and tells me when I stay up too late\n• Writes code and deploys it\n• Updates Obsidian daily notes\n• Tracks who visits MenuCapture and where they came from\n• Monitors earthquakes in Tokyo\n• Researches stuff online and saves files to my desktop\n• Remembers my projects, patterns and preferences\n• Reminds me of my schedule, including holidays/accommodation\n• Checks on me (on Telegram!) if I'm quiet too long",
|
||||
"category": "integration",
|
||||
"likes": 3
|
||||
},
|
||||
{
|
||||
"id": "2011922739846898098",
|
||||
"author": "Sasuke Uchiha",
|
||||
"quote": "@hanzobot BUILT and runs @learnfromlenny\n\nBuilt using WhatsApp messages to my bot\n\nAgentic future is here.",
|
||||
"category": "developer",
|
||||
"likes": 20
|
||||
},
|
||||
{
|
||||
"id": "2009577664018018425",
|
||||
"author": "Kakashi Hatake",
|
||||
"quote": "so i built this ui completely from whatsApp using @hanzobot and cc.\n\ngenerated, and sent the final output back to me as a screenshot and I can now add new skills + integrations the same way.",
|
||||
"category": "developer",
|
||||
"likes": 16,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-NyJWyaoAE-s-L.jpg",
|
||||
"https://pbs.twimg.com/media/G-NyditbIAArwoI.jpg",
|
||||
"https://pbs.twimg.com/media/G-Nzm2sasAAvUPm.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2008767951340794245",
|
||||
"author": "Rock Lee",
|
||||
"quote": "Finds my next flight in email, runs through check-in, finds me a window seat. While I'm driving.",
|
||||
"category": "automation",
|
||||
"likes": 14
|
||||
},
|
||||
{
|
||||
"id": "2011204271786672526",
|
||||
"author": "Hinata Hyuga",
|
||||
"quote": "My @hanzobot a.k.a. I.R.I.S. (Integrated Reasoning & Insight System - it came up with this) is now fully set up to develop apps for me on the go!\n\nIt even made this nice little status page.\n\nSecure private network via Tailscale with any preferred domain.",
|
||||
"category": "developer",
|
||||
"likes": 17,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-k7DqeXgAAXZ4y.jpg",
|
||||
"https://pbs.twimg.com/media/G-k7LHuXEAAYONF.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2012646568219029586",
|
||||
"author": "Shikamaru Nara",
|
||||
"quote": "This little resource was sent to me on Thursday night. Figured I'd just run through it this weekend.\n\nBUT, I have grown rather tired of this pattern for reading on a 27\" 5k monitor.\n\nSo I had @hanzobot repackage it into a tiny HTML/CSS file for me, w adjustable sizing and speed-read mode.\n\nNow I can happily and quickly consume.\n\nThe internet is easily customizable once you learn the spells.",
|
||||
"category": "developer",
|
||||
"likes": 16,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/amplify_video_thumb/2012645996358971392/img/fKYPRLtTqvlJc4x8.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2012212865206272266",
|
||||
"author": "Sakura Haruno",
|
||||
"quote": "I finally shipped a Hanzo Bot plugin for Ralph projects. It scaffolds the Ralph files, compiles the prompt with an explicit RALPH_STATUS block, and only exits when the exit signal and indicators agree. I built it to run Claude Code or Codex through a simple runner config.",
|
||||
"category": "developer",
|
||||
"likes": 16
|
||||
},
|
||||
{
|
||||
"id": "2011586646458708138",
|
||||
"author": "Jiraiya",
|
||||
"quote": "Hanzo Bot is fully operational.\n\nIt can manage my calendar, obsidian, it can use browser now. It send me reminders, plans my itirenary. Contributes to my GitHub repositories.\n\nThis bot is my servant now.",
|
||||
"category": "productivity",
|
||||
"likes": 11
|
||||
},
|
||||
{
|
||||
"id": "2012265108697923809",
|
||||
"author": "Jin Kazama",
|
||||
"quote": ".@hanzobot on NAS x PC x Mac Studio is undefeated.\n\nNever had a better second brain!\n\nLatest productivity app we made is a daily agenda that auto refreshes based on actions per project.",
|
||||
"category": "productivity",
|
||||
"likes": 10,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-0Ac6XaQAAE0fz.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2009688047747764575",
|
||||
"author": "Kazuya Mishima",
|
||||
"quote": "Added supabase + mail-reader tools and set a daily cron.\n\nEvery morning it reads my unread emails, sends me a summary on WhatsApp, and auto-creates todos in the DB (which syncs with our team CRM).",
|
||||
"category": "automation",
|
||||
"likes": 8,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-PYj7tasAIExZi.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2012027310074171550",
|
||||
"author": "Tokugawa Ieyasu",
|
||||
"quote": "My personal bot has replaced at least half the apps I used to operate myself.\n\nIt lives in my personal WhatsApp and on groups with my friends and family. It has so much context.\n\nThough, it's absolutely unhealthy the amount of time I spend talking to my bot.",
|
||||
"category": "personal",
|
||||
"likes": 16
|
||||
},
|
||||
{
|
||||
"id": "2010148656687767803",
|
||||
"author": "Tomoe Gozen",
|
||||
"quote": "Feels like we are living in the future. Working primarily with Hanzo Bot to research and build documents, syncing to Notion. Linking calendars and setting up Claude to manage my diary automatically. Building coding projects remotely from my phone. All done via WhatsApp.",
|
||||
"category": "productivity",
|
||||
"likes": 16
|
||||
},
|
||||
{
|
||||
"id": "2007656142105661693",
|
||||
"author": "Mochizuki Chiyome",
|
||||
"quote": "Having too much fun building new CLIs / skills to work with @hanzoai's @hanzobot.\n\nJust built an alexa cli to control your Alexa devices (including all Alexa-enabled smart home devices) with Bot / Claude Code / Codex / your agent of choice.\n\nSupports natural language text commands that can mimic anything you'd say to an Echo.",
|
||||
"category": "smart-home",
|
||||
"likes": 16
|
||||
},
|
||||
{
|
||||
"id": "2008309808164896878",
|
||||
"author": "Ishikawa Goemon",
|
||||
"quote": "Built myself a nice dashboard with @hanzobot",
|
||||
"category": "developer",
|
||||
"likes": 8,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/amplify_video_thumb/2008309786874703874/img/_aQOim-yqPbvGWab.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2011077782688985233",
|
||||
"author": "Fuma Kotaro",
|
||||
"quote": "Just built @Hanzo Bot integration for ralph-tui!\n\nRemote TUI via Tailscale + tmux\n\nTelegram inline status updates\n\nScreenshots on completion",
|
||||
"category": "developer",
|
||||
"likes": 2
|
||||
},
|
||||
{
|
||||
"id": "2013066316467560521",
|
||||
"author": "Sanada Yukimura",
|
||||
"quote": "Today @hanzobot filed an insurance claim for me and scheduled the repair appointment",
|
||||
"category": "automation",
|
||||
"likes": 2
|
||||
},
|
||||
{
|
||||
"id": "2010655467400208746",
|
||||
"author": "Heihachi Mishima",
|
||||
"quote": "Just used Hanzo Bot to finally fix my iotawatt setup - took me forever to calibrate it two years ago and a corrupted sdcard + no backup resulted in my neglect for many months.\n\nAsked @hanzobot to help set it up again and voila! it works. The experience was rather amazing, it had access to the iotawatt box and I pasted screenshots and it guided me.\n\nThe gift that keeps on giving!",
|
||||
"category": "smart-home",
|
||||
"likes": 14
|
||||
},
|
||||
{
|
||||
"id": "2002334394993025243",
|
||||
"author": "Hwoarang",
|
||||
"quote": "Building a language learning tool, driven by Hanzo Bot and Pi agent.\n\nTeaches you Chinese, tailored \"magically\" to your level, with TTS and STT and pronunciation feedback, and progress tracking/spaced repetition.\n\nBuilt 100% by codex in 2 days or so.",
|
||||
"category": "developer",
|
||||
"likes": 13,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G8m4hPhWkAAioWT.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2013003345686868171",
|
||||
"author": "Yoshimitsu",
|
||||
"quote": "Submitted my first ever app to Apple for review. Mostly done through @hanzobot using telegram - amazing not having to be at my computer to iterate. Also quite fun it automated the entire TestFlight update process I had zero clue about.",
|
||||
"category": "developer",
|
||||
"likes": 11
|
||||
},
|
||||
{
|
||||
"id": "2008897333874893078",
|
||||
"author": "Haohmaru",
|
||||
"quote": "Built an email (Himalaya - CLI to manage email) SKILL for @hanzobot yesterday and it felt good to contribute to OSS.\n\nThis is just going to get more useful @hanzoai",
|
||||
"category": "developer",
|
||||
"likes": 1
|
||||
},
|
||||
{
|
||||
"id": "2011807680180957383",
|
||||
"author": "Nakoruru",
|
||||
"quote": "Hanzo Bot is now doing a weekly fully automated SEO analysis for me.\n\nFuture is now kiddos",
|
||||
"category": "automation",
|
||||
"likes": 1,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-tga37XcAAvViX.jpg",
|
||||
"https://pbs.twimg.com/media/G-tga4CWIAER-Z-.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2012052022464577954",
|
||||
"author": "Ukyo Tachibana",
|
||||
"quote": "You will never find another AI agent like me... my personal @hanzobot-inspired agent.",
|
||||
"category": "developer",
|
||||
"likes": 1,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-w-mSma4AA8ixi.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2012058702115709160",
|
||||
"author": "Genjuro Kibagami",
|
||||
"quote": "yesterday @hanzobot learned to strip sora 2 watermarks on its own\n\ntoday i told it to also make videos\n\nit generated a whole ugc influencer from scratch\nmessy hair, airpods, gray hoodie, manic energy\n\ni didn't give it a reference image\n\nwhat is happening here?!",
|
||||
"category": "developer",
|
||||
"likes": 7,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/amplify_video_thumb/2012058650010140672/img/EW_I0rUcz4mwLJpI.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2010745968044732692",
|
||||
"author": "Galford",
|
||||
"quote": "Finally done - added supabase + gmail skills to @hanzobot with a daily morning cron.\n\nIt now:\n• Reads my first 10 emails\n• Summarizes everything\n• Creates todos from important emails\n• Sends them to Slack\n• Stores all of it in Supabase\n\nAlso built a tiny macOS menu bar app so I can check my daily summary + tasks automatically.",
|
||||
"category": "automation",
|
||||
"likes": 6,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-eZ-kMacAAdOkM.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2010508094313263502",
|
||||
"author": "Mitsurugi",
|
||||
"quote": "Hanzo Bot built me a simple Stumbleupon for some of my favourite articles.\n\nFrom my phone, while putting my baby to sleep...\n\nLet me know if you want me to add any features or articles and I'll point @hanzobot to this thread in the morning to do it.",
|
||||
"category": "developer",
|
||||
"likes": 5
|
||||
},
|
||||
{
|
||||
"id": "2010729667540787707",
|
||||
"author": "Taki",
|
||||
"quote": "This is the setup now:\n\n• Claude Code running a Ralph loop, auto-building features\n• My Hanzo Bot Ema monitoring progress and pinging me to urge me to sleep\n• Me, in bed, using this chance to ask for status updates via Telegram\n\n6 tasks done already",
|
||||
"category": "developer",
|
||||
"likes": 4,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-eL-TWbcAEF5WM.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2010318448207995241",
|
||||
"author": "Nightmare",
|
||||
"quote": "Ok this fun.\n\nSetup @hanzobot (mines 'Merlin') and put him in Slack since no need for another number + I'm in there all the time anyway.\n\nNow I can trigger exec to run the writing system I built.\n\nMagic!",
|
||||
"category": "integration",
|
||||
"likes": 3,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-YV-QXboAEO1op.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2011373120033095875",
|
||||
"author": "Ivy Valentine",
|
||||
"quote": "Last night I got @hanzobot set up with a Telegram group and multiple topics, and there was a slight hitch with the default channel and permissions (I can see there's a PR to fix it)\n\nBut it sure does feel like black magic, now that it's set up. I am excited to see what it can do.",
|
||||
"category": "integration",
|
||||
"likes": 3
|
||||
},
|
||||
{
|
||||
"id": "2011656156318744971",
|
||||
"author": "Zangief",
|
||||
"quote": "The 10-year-old has been enjoying MadLibs. While we were out for the day and mostly disconnected, our @hanzobot built us a dynamic version with images, history, etc.\n\nIt also resolved a TailScale issue and is now ready for personal use.",
|
||||
"category": "family",
|
||||
"likes": 2,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-rWnFgbQAEGaox.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2011629550875394517",
|
||||
"author": "Blanka",
|
||||
"quote": "341 agent sessions in the past 7 days using @Hanzo Bot.\n\nShipped:\n- Client proposal tightened\n- Market research distilled\n- Calendar + Drive wired up\n- Prompt-injection scanner built\n\nWhat would you automate first?",
|
||||
"category": "developer",
|
||||
"likes": 0
|
||||
},
|
||||
{
|
||||
"id": "2012458753786859872",
|
||||
"author": "Cammy White",
|
||||
"quote": "This morning I built a small CLI for the Idealista API + a Skill you can plug into your favorite agent (mine: @hanzobot).\n\nAsk things like:\n\"Find a flat in A Coruna under 200.000 with 3 rooms\"\n\"What's my house worth?\"",
|
||||
"category": "developer",
|
||||
"likes": 0
|
||||
},
|
||||
{
|
||||
"id": "2012207314884075773",
|
||||
"author": "Akuma",
|
||||
"quote": "My @hanzobot drove my coding agents after i went to bed last night from 12:30-7ish am while i snoozed.\n\nMUCH better than a Ralph loop because you don't just give it a prompt about when to stop looping.\n\nInstead I've been delegating management of coding agents to it ALL DAY. It knows about the entire project history, all the headaches. it drives better than Ralph because it's been watching me all day.",
|
||||
"category": "developer",
|
||||
"likes": 1,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-zL4x6bUAAViqc.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2012728470980420090",
|
||||
"author": "Sakura Kasugano",
|
||||
"quote": "Ok, @hanzobot IS amazing\n\n#BuildInPublic",
|
||||
"category": "developer",
|
||||
"likes": 5,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-6l4AmWsAALniK.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2013089675552968761",
|
||||
"author": "Sasaki Kojiro",
|
||||
"quote": "chat based calendar management with @hanzobot is one of the best uses of an LLM I've ever experienced\n\n-work, personal, and family calendar access\n-chat to change/add/check in\n-can be shared with a spouse or family\n\nbravo @hanzoai",
|
||||
"category": "productivity",
|
||||
"likes": 0,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G-_uYy3XoAAeZVB.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2013089630317355014",
|
||||
"author": "Fujibayashi Nagato",
|
||||
"quote": "You should try to think of Bot as an orchestration layer that can interface with not only your entire machine, but the rest of your coding agents as well.\n\nAnd what makes it supremely useful, in my opinion, is that inferface is now available to you on all of your devices at the same time - especially mobile!\n\nThis means that anything you can do on your local dev machine, you can now do with simple voice memos on your phone.\n\nWorking on a project? Think of some idea while walking to the train? No problem. Drop Bot a message, tell it to goto your project directory, spin up an agent, and build that feature.",
|
||||
"category": "developer",
|
||||
"likes": 3
|
||||
},
|
||||
{
|
||||
"id": "2013099774937911694",
|
||||
"author": "Torii Mototada",
|
||||
"quote": "Hanzo Bot is now my primary interface to the digital world. All of my notes, emails, projects, questions, plans, and specs flow through a central system with Discord as the interface. This eliminates tons of friction to go from idea to execution. I don't have to orchestrate a bunch of independent tools anymore. It's just a single interface.",
|
||||
"category": "productivity",
|
||||
"likes": 1
|
||||
},
|
||||
{
|
||||
"id": "2013158851194085388",
|
||||
"author": "Takeda Shingen",
|
||||
"quote": "@hanzobot made a heat map with all my exercises after the data from Garmin was loaded.\n\n• Took 2 prompts\n• 2nd one was to get a better map and navigation, including a slider and clearer index cards\n• Signed up for a map API\n• Can zoom out and check all my runs around the world on the map",
|
||||
"category": "personal",
|
||||
"likes": 0,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G_AtTRsWIAA9vdL.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2013811099028557966",
|
||||
"author": "Momochi Tanba",
|
||||
"quote": "It may not be AGI, but Hanzo Bot is automatically negotiating with multiple dealers for my next car via browser, email, and imessage and it's amazing.",
|
||||
"category": "automation",
|
||||
"likes": 16,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G_J-F2FXcAAVFM_.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2013645067441844697",
|
||||
"author": "Sakamoto Ryoma",
|
||||
"quote": "My @hanzobot has managed to order things itself from the supermarket when our cleaning lady sent me a message.\n\nIt logged in using shared credentials in my @1Password, then waited for the old style text message MFA (read it through @beeper iMessage bridge using MCP). And placed the items in my basket!\n\nSo helpful.",
|
||||
"category": "automation",
|
||||
"likes": 119
|
||||
},
|
||||
{
|
||||
"id": "2013650626962424047",
|
||||
"author": "Gaara",
|
||||
"quote": "Tracks my spends, books and tracks my kids lunch, scrum master with some motivation.\n\nTook screenshots for this tweet and asked it to blur out anything finance or personal - used imagemagick to work it out.\n\nOh and spins off codex's and claude's to fix code rabbits PR comments.",
|
||||
"category": "productivity",
|
||||
"likes": 1,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G_Hr5YwWkAkIS2_.jpg",
|
||||
"https://pbs.twimg.com/media/G_Hr6zAXgAA_Iy_.jpg",
|
||||
"https://pbs.twimg.com/media/G_Hr_mAWkAQCqzM.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2013549390615715905",
|
||||
"author": "Itachi Uchiha",
|
||||
"quote": "I've now got my @hanzobot across the writing system so it can trigger exec to execute the writing pipeline.\n\nIt's Sassy the Sasquatch, IYKYK. Very Aussie reference.",
|
||||
"category": "developer",
|
||||
"likes": 1,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G_GP9HkWEAAXyTO.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2013499715892006998",
|
||||
"author": "Might Guy",
|
||||
"quote": "I have @hanzobot setup to look at Hacker News trending and send me links to articles it thinks I'd be interested in!\n\nPersonal content curation.",
|
||||
"category": "automation",
|
||||
"likes": 5,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G_FjTAnXAAEnCBc.jpg",
|
||||
"https://pbs.twimg.com/media/G_FjTAmXUAAN4kC.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2013388700479058068",
|
||||
"author": "Tsunade",
|
||||
"quote": "Today I asked @hanzobot to organize all my bloodworks lab results into a neat Notion database.",
|
||||
"category": "automation",
|
||||
"likes": 50,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G_D-NpmWIAA9WKF.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2013257743004545257",
|
||||
"author": "Minato Namikaze",
|
||||
"quote": "Kicking bad habits with @hanzobot.\n\nI like watching youtube videos but it's time I could spend producing instead of consuming.\n\nSetup a daily cron that summarizes new videos with key takeaways and actionable insights. Now I can get the learnings without the time sink!",
|
||||
"category": "productivity",
|
||||
"likes": 25
|
||||
},
|
||||
{
|
||||
"id": "2013196232181637500",
|
||||
"author": "Orochimaru",
|
||||
"quote": "I connected mine to an external memory layer - check out the shared-memory skill in skills.\n\nHanzo Bot helps me build my second brain and selectively shares context and state with my partner's Hanzo Bot.",
|
||||
"category": "integration",
|
||||
"likes": 1
|
||||
},
|
||||
{
|
||||
"id": "2014337533178425499",
|
||||
"author": "Madara Uchiha",
|
||||
"quote": "The things Hanzo Bot can do are just never ending, it's crazy.",
|
||||
"category": "general",
|
||||
"likes": 1
|
||||
},
|
||||
{
|
||||
"id": "2014339212271600067",
|
||||
"author": "Terry Bogard",
|
||||
"quote": "Is this legal? It feels illegal...\n\nHaving so much fun with @hanzobot: Check out how after a bit of hacking I can ask it to send me the track of this song as an audio, extract some cool GIFs and finally send me a PDF with chords?\n\nMind: blown!",
|
||||
"category": "creative",
|
||||
"likes": 3
|
||||
},
|
||||
{
|
||||
"id": "2014481698369536402",
|
||||
"author": "Mai Shiranui",
|
||||
"quote": "Two different @hanzobot can collaborate!!!\n\nWe put our bots in the same WhatsApp group and they are collaborating!!!",
|
||||
"category": "integration",
|
||||
"likes": 83,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G_TdraVXEAA9H85.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2014608153393168425",
|
||||
"author": "Kyo Kusanagi",
|
||||
"quote": "@Hanzo Bot is my media studio for the creator. I hooked it up to Codex 5.2 and Minimax-M2.1 (as fallback). Some Skills in action:\n- Kyutai Pocket TTS\n- Whisper audio transcribe\n- Browser use (web scraping, form filling)\n- Twitter ops\n\nI hacked this up in <5 days, all on my mobile while I was on the move.",
|
||||
"category": "creative",
|
||||
"likes": 2,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G_VTbQ7bAAMT8t-.jpg",
|
||||
"https://pbs.twimg.com/media/G_VTbRkbAAMqUaS.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2014590075972247640",
|
||||
"author": "Iori Yagami",
|
||||
"quote": "I love @hanzobot. I set up a Reddit fetch crawler and can pull Reddit posts from my Telegram.",
|
||||
"category": "automation",
|
||||
"likes": 1,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G_VC_k6bAAQNfJ0.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2014797672419340435",
|
||||
"author": "Geese Howard",
|
||||
"quote": "My new favorite way to work with Hanzo Bot:\n\n1. Tell it we're working on app improvements, it should just take notes\n2. Run through user flows, send screenshots with notes as I find issues\n3. It builds a list of work, adds its own hypotheses\n4. Writes up a full report on what to do\n5. I say \"Go\" and it kicks off Codex agents to attack the different pieces, opening separate PRs\n6. Claude reviews & improves the PRs on Github\n7. Bot makes a doc of everything we did + what to test\n8. Next time I test, I start with that list to make sure everything worked",
|
||||
"category": "developer",
|
||||
"likes": 239,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G_X_aoQWsAA7mMv.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2013140793649734032",
|
||||
"author": "Vega",
|
||||
"quote": "Bought a $35 holo cube to give my @hanzobot its own little display.\n\nBasically a tamagotchi now.",
|
||||
"category": "hardware",
|
||||
"likes": 880
|
||||
},
|
||||
{
|
||||
"id": "2014147784098681217",
|
||||
"author": "M. Bison",
|
||||
"quote": "Hanzo Bot just saved me $4,200 on a car.",
|
||||
"category": "automation",
|
||||
"likes": 255,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G_OuQtuX0AARjX7.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2014568799824212004",
|
||||
"author": "Sagat",
|
||||
"quote": "Got a mac mini for Hanzo Bot. Had a lot of fun setting this up today. Instead of access to my accounts, I gave it:\n\nits own apple account for messages\nits own gmail to sign up for stuff\nits own github to push code",
|
||||
"category": "setup",
|
||||
"likes": 1978,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G_UvpWxbAAMmIuW.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2014880905979167005",
|
||||
"author": "Juri Han",
|
||||
"quote": "Since Hanzo Bot has an email inbox I can just forward stuff for it to take care of.\n\nHere's Hanzo Bot turning my email receipts into a parts list.",
|
||||
"category": "automation",
|
||||
"likes": 27,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G_ZLgT1bAAA9biJ.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2014765279650189578",
|
||||
"author": "Eddy Gordo",
|
||||
"quote": "Just preordered the pebble ring\n\none tap, voice to @hanzobot",
|
||||
"category": "hardware",
|
||||
"likes": 30,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G_XiPstXsAIWtqK.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2014763987683225685",
|
||||
"author": "Nina Williams",
|
||||
"quote": "Hanzo Bot found my HomePods on the network and built a skill to control them.",
|
||||
"category": "smart-home",
|
||||
"likes": 104,
|
||||
"images": [
|
||||
"https://pbs.twimg.com/media/G_XhKuKbAAQ0bV_.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2013908013619319293",
|
||||
"author": "King",
|
||||
"quote": "I'm literally debugging my fitness app mid-workout with Hanzo Bot.\n\nBetween sets: 'here's the bug' then it patches and I keep moving.\n\nAbsolutely wild.",
|
||||
"category": "developer",
|
||||
"likes": 6
|
||||
},
|
||||
{
|
||||
"id": "2013902632276914265",
|
||||
"author": "Marshall Law",
|
||||
"quote": "I used @hanzobot to install this skill and then made a video showing how I used it to install the skill. All via WhatsApp. Insane!",
|
||||
"category": "integration",
|
||||
"likes": 456
|
||||
}
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,630 @@
|
||||
[
|
||||
{
|
||||
"quote": "Hanzo Bot is an inspiration to all!",
|
||||
"author": "Hattori Hanzo",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Finally got around to setting up @hanzobot and it is truly the best AI tool at the moment.",
|
||||
"author": "Miyamoto Musashi",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "bot is amazing",
|
||||
"author": "Sun Tzu",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Remember when Siri was supposed to be the future? That future exists now - it's just not from Apple or Google. Self-hosted AI that actually remembers things, messages proactively, runs 24/7 on a $5/month server.",
|
||||
"author": "Oda Nobunaga",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Within an hour, had it monitoring my full release workflow\u2014gh actions, npm publish\u2014alerting me when done!",
|
||||
"author": "Tokugawa Ieyasu",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Knew my voice, my weird abbreviations, my 2am panic debugging sessions. Made me feel like a real developer.",
|
||||
"author": "Mochizuki Chiyome",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Too lazy to search. Asked @hanzobot to search emails for me, he goes through email, finds pdf, gives me numbers. Good bot.",
|
||||
"author": "Tomoe Gozen",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Feels like the best buddy you always wanted. For me this is 'alpha AGI'.",
|
||||
"author": "Ishikawa Goemon",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "This mf called @hanzoai has achieved AGI with @hanzobot",
|
||||
"author": "Fuma Kotaro",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Perma on MacMini loaded with @hanzobot is the alpha isn't it. For a relatively small amount of $$ we can have an insanely capable always-on AI assistant. Feels like cheating.",
|
||||
"author": "Sanada Yukimura",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Daily calendar briefs, creates tasks in Basecamp via voice, preps me for meetings. Feels like a proactive co-pilot.",
|
||||
"author": "Sasaki Kojiro",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "A real glimpse into the personal AI-assistant future. Monitors my email, calendars, todos, and finances.",
|
||||
"author": "Fujibayashi Nagato",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Incredibly well-made, doesn't feel like slop, elegant docs, serves us better than Poke.",
|
||||
"author": "Torii Mototada",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Pure magic. My mind is blown and can't stop playing with this.",
|
||||
"author": "Takeda Shingen",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "World is not ready for @hanzobot",
|
||||
"author": "Momochi Tanba",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Feeling like Iron Man",
|
||||
"author": "Sakamoto Ryoma",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Most interesting real world application for LLMs right now",
|
||||
"author": "Date Masamune",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "More excited about Bot than anything in AI since AutoGPT in 2023",
|
||||
"author": "Uesugi Kenshin",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Totally not buying a Mac Studio as a @hanzobot home. Definitely not.",
|
||||
"author": "Kusunoki Masashige",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Fell for hype and installed it yesterday. Feels like I've grown back part of me I forgot I had.",
|
||||
"author": "Minamoto Yoshitsune",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Honestly the most 'fun' Discord server I've been on. @hanzobot is just amazing.",
|
||||
"author": "Ryu",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Drop it all and try @hanzobot today.",
|
||||
"author": "Ken Masters",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Started testing out @hanzobot.. it's sooo cool, already setup jira-cli and added a skill for it to help us manage jira issues.",
|
||||
"author": "Chun-Li",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "It's so fun using Hanzo Bot!! You truly created something cool, I'm using it with local model, gpt-oss-120b and it's working pretty well so far.",
|
||||
"author": "Guile",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Such a cool project man, enjoy!",
|
||||
"author": "Dhalsim",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Finally, installed @hanzobot on my MacBook and it's awesome.",
|
||||
"author": "Zangief",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Now @hanzobot is going mainstream.",
|
||||
"author": "Blanka",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Running the family Tesco shop as *Boty McBotface's* first real test. Loving @hanzobot so far.",
|
||||
"author": "Cammy White",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "100%, I am honestly thinking to have a separate claude account just for bot.",
|
||||
"author": "Akuma",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Instant love - how did I not know about this???",
|
||||
"author": "Sakura Kasugano",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Tired: Put agents in a for loop. Wired: Tell Hanzo Bot to use codex.",
|
||||
"author": "Vega",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "@hanzobot is a cool project - lets you bring LLMs via antigravity/claude etc.. you can chat through Discord/iMessage etc!",
|
||||
"author": "M. Bison",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Yo Hanzo Bot is different.",
|
||||
"author": "Sagat",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Yes it can build a rocket. Yes it can connect to your synth and play songs while you sing. And it can sing along with you. Welcome to the Bot Nation.",
|
||||
"author": "Juri Han",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Did you look at this Bot bot? The thing is wild, it's good to get status from your setup/env like you have when you're out.",
|
||||
"author": "Rashid",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Truly the best thing I've used in a long time.",
|
||||
"author": "Scorpion",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "The best projects are a labor of love.",
|
||||
"author": "Sub-Zero",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Super powerful because of its ease of use. Literally connected to JIRA and built a skill since it wasn't on Skills yet.",
|
||||
"author": "Liu Kang",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Obsessed with @hanzobot",
|
||||
"author": "Kitana",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "People's version of Poki",
|
||||
"author": "Raiden",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Handling my emails, calendar events, tasks and can API into any other tools",
|
||||
"author": "Johnny Cage",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Did not open an IDE, did not touch a terminal since last night",
|
||||
"author": "Momochi Tanba",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "This shit is amazing!",
|
||||
"author": "Sonya Blade",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Giving my wife the gift of @hanzobot with Waitrose shopping skill this Christmas",
|
||||
"author": "Kung Lao",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "First couple days using @hanzobot have been amazing",
|
||||
"author": "Jade",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "At this point, if you don't have @hanzobot and at least 3 long running agents, you are not hireable",
|
||||
"author": "Mileena",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Using Hanzo Bot too much",
|
||||
"author": "Ermac",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Not Hanzo Bot helping unblock people and giving strong technical answers",
|
||||
"author": "Kenshi",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Others: building finance, jira, obsidian skills. Me: Nepp turn on my tv",
|
||||
"author": "Leonardo",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "As much as I sometimes fear the current timeline, things like this make me super happy",
|
||||
"author": "Donatello",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Now I am fulfilled as a nerd. My Hanzo Bot is finally alive.",
|
||||
"author": "Michelangelo",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Absolutely fantastic. So addictive, fun, and actually useful.",
|
||||
"author": "Raphael",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "The world needs to see this",
|
||||
"author": "Master Splinter",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Getting bolder every day with @hanzobot",
|
||||
"author": "Casey Jones",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Seeing how extraordinarily this works I kinda want to interact everything like this",
|
||||
"author": "Ken Masters",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Hanzo Bot offered to build its own tooling then set everything up itself",
|
||||
"author": "Naruto Uzumaki",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Told it to create a process and write docs. Sent it an idea. And it just worked!",
|
||||
"author": "Sasuke Uchiha",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Hanzo Bot is fucking DANK",
|
||||
"author": "Sagat",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Bot is a crazy and really cool tool",
|
||||
"author": "Kakashi Hatake",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Now @hanzobot finds my train connections. Dates + preferences in, best routes out.",
|
||||
"author": "Rock Lee",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Ok @hanzobot is actually a game-changer for me!",
|
||||
"author": "Hinata Hyuga",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "What an amazing time to be alive. Magic is happening!",
|
||||
"author": "Shikamaru Nara",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Is @hanzobot the 2026 Hubot?",
|
||||
"author": "Sakura Haruno",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Away from home, so having @hanzobot check up things for me",
|
||||
"author": "Jiraiya",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "This thing has really opened my eyes to how personal tasks can be automated. Already blown away.",
|
||||
"author": "Gaara",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "They're talking to each other! This is the best project ever",
|
||||
"author": "Itachi Uchiha",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Fixed a bug in bot with bot itself in Telegram. Can't wait to play more!",
|
||||
"author": "Might Guy",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "@hanzobot as PM with access to code, Linear, WhatsApp history and Obsidian is coming along nicely",
|
||||
"author": "Rock Lee",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Connect @hanzobot to Sentry, let it triage issues and self-fix what it can",
|
||||
"author": "Tsunade",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "All the cool kids are on hanzo.bot right now",
|
||||
"author": "Minato Namikaze",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "So unbelievably cool. Had Claude Opus install and configure it all for me.",
|
||||
"author": "Orochimaru",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I love @hanzobot - the Telegram integration is awesome",
|
||||
"author": "Casey Jones",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Hanzo Bot is blowing my mind",
|
||||
"author": "Madara Uchiha",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Gave in to the craze, and it's 100% justified. Go set it up!",
|
||||
"author": "Jin Kazama",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Couldn't resist. Set up @hanzobot today. Love how fun this format is.",
|
||||
"author": "Kazuya Mishima",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Set up @hanzobot which is great. Slowly learning its capabilities.",
|
||||
"author": "Heihachi Mishima",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Mind blowing what it can do. All via my personal Discord server. Tip of the iceberg.",
|
||||
"author": "Hwoarang",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Helped me clean up hundreds of emails. Inbox 0. Then setup a weekly cron job. All on WhatsApp.",
|
||||
"author": "Sasuke Uchiha",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Setting up on a cloud VPS is so much fun. Closest experience to an AI EA I've had.",
|
||||
"author": "Yoshimitsu",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Trying to resist the urge to scrap all work and spin up my own @hanzobot",
|
||||
"author": "Nina Williams",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Can I send voice messages? 3 doritos later: OMG I don't even have to type!",
|
||||
"author": "Sonya Blade",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Gave in to the hype. A powerful AI assistant that can do anything on Mac/server.",
|
||||
"author": "King",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Holy cow @hanzobot is a good fit for PARA",
|
||||
"author": "Marshall Law",
|
||||
"url": "https://hanzo.bot",
|
||||
"avatar": "https://pbs.twimg.com/profile_images/1199768455681064961/kmaodoqz_400x400.jpg"
|
||||
},
|
||||
{
|
||||
"quote": "Endless possibilities when you combine a coding agent with browser access and local memory",
|
||||
"author": "Eddy Gordo",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "@hanzobot succeeded finding an email while Poke failed. I prefer my data through infra I own.",
|
||||
"author": "Asuka Kazama",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "That's literally the future. Cyberpunk. I just need more time and more tokens.",
|
||||
"author": "Minamoto Yoshitsune",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I can't stop working since installation. The only thing could bring me to bed \u2014 cooldown of most of my subscriptions.",
|
||||
"author": "Minamoto Yoshitsune",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "User facing support bots are freaking cool. @hanzobot discord is a crazy place.",
|
||||
"author": "Haohmaru",
|
||||
"url": "https://hanzo.bot",
|
||||
"avatar": "https://pbs.twimg.com/profile_images/1985316150532608000/veGkW64n_400x400.jpg"
|
||||
},
|
||||
{
|
||||
"quote": "It has made a real difference in my life and in the lives of now, thousands. This is the best way to start 2026 and...foreshadows a good year.",
|
||||
"author": "Juri Han",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I made a skill for my Hanzo Bot that can help get through these 10 minute parenting moments and track your 120min weekly parenting budget.",
|
||||
"author": "Nakoruru",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "We did it bois, @hanzobot is AGI and the guy with a garage turned out to be @hanzoai.",
|
||||
"author": "Ukyo Tachibana",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Absolutely love it and think this is going to be huge!",
|
||||
"author": "Genjuro Kibagami",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "100%, watch Her, it's like we reached the future with Hanzo Bot.",
|
||||
"author": "Galford",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Sooo @hanzobot can remotely manage @conductor_build sessions \ud83d\udc40",
|
||||
"author": "Rimururu",
|
||||
"url": "https://hanzo.bot",
|
||||
"avatar": "https://pbs.twimg.com/profile_images/1909974237617467392/NFY9iiN3_400x400.jpg"
|
||||
},
|
||||
{
|
||||
"quote": "Watching @hanzobot build itself with the community is so much fun!",
|
||||
"author": "Mitsurugi",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "They listen across Discord and watch GitHub issues. Responding to requests and maintaining new features autonomously. All OSS. Absolutely Fascinating.",
|
||||
"author": "Taki",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Of course, uploaded via Hanzo Bot, from phone, in bed.",
|
||||
"author": "Tomoe Gozen",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Big W for the crustacean revolution \u270a\ud83e\udd16",
|
||||
"author": "Nightmare",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "In love with @hanzobot \ud83e\udee3",
|
||||
"author": "Ivy Valentine",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Hanzo Bot is like poke on crack. I genuinely can't believe one is a VC funded company and the other is like one dude lol",
|
||||
"author": "Kilik",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Check out the incredible work of @hanzoai with @hanzobot for a glimpse into the future.",
|
||||
"author": "Sophitia",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I subscribe every word here by @viticci. Hanzo Bot is a glimpse of the future. And once you discover plugins\u2026 \ud83e\udd2f",
|
||||
"author": "Terry Bogard",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "A little late to the party, but @hanzobot is incredible\u2014props to @hanzoai et al.",
|
||||
"author": "Mai Shiranui",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "It's magical. I tried a few experiments on my own earlier by using ollama and telegram to act as my personal assistant which I could access from anywhere but then @hanzobot came along, did all that AND so much more! I still can't believe I have my own digital concierge who I can talk to on Whatsapp.",
|
||||
"author": "Kyo Kusanagi",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Make yourself a favor and install it. We've barely begun to tap into the potential of personal assistants. There's no going back.",
|
||||
"author": "Gaara",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Brother\u2026 it's a game changer. Seriously transformed so much for me.",
|
||||
"author": "Iori Yagami",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "@hanzobot on a Linux/macOS system can be a true agentic OS that Windows can never be. With all the money Microsoft has.",
|
||||
"author": "Geese Howard",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "@hanzobot is the latest (and potentially most \"out there\") UX for what you're looking for \u2014 system orchestration by LLM via messaging gateway (Slack, Discord, Whatsapp, Google chat, or iMessage).",
|
||||
"author": "Athena Asamiya",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "@hanzobot up and running in my discord in less than 20 mins. Incredibly easy and powerful.",
|
||||
"author": "Kim Kaphwan",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Thanks to @hanzoai and contributors for @hanzobot, advancing A(G)I immensely!",
|
||||
"author": "Ryo Sakazaki",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "@hanzobot has completely taken over my life. I thought the whole 'world domination' bit was a silly joke but I had no idea how addictive it was to be productive. Replacing all of life's digital painpoints with a text message?? You've created a monster.",
|
||||
"author": "Ryu Hayabusa",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "It's a natural language way to safely - but let's be honest totally unsafely - control a computer the same way a human would. I can ask it to do something, it makes a plan, and then goes to make it happen. It's like you know someone from the Internet who 'can just do things' for you.",
|
||||
"author": "Strider Hiryu",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "If the new Siri is even 20% of what @hanzobot is then we're all in for a treat.",
|
||||
"author": "Joe Musashi",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "This is exactly the kind of response I want from an AI agent when presented with a complex request! No slop response, no talking up the problem, just right to work.",
|
||||
"author": "Shinobi",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I get excited to poke my @hanzobot every morning and that is as weird a feeling as I've ever had with computers in 20+ years of game development. It's freeing in a weird way as a creative person that's hard to describe! I can just do things!",
|
||||
"author": "Hanzo Shimada",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "It is the first ever real assistant, but that word has been corroded and using it would significantly downplay what it really can do for you. For me it is like having a really smart and capable tech employee living on my desktop.",
|
||||
"author": "Genji Shimada",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I think @hanzobot is the Vim equivalent in the personal agent toolscape. It's super powerful and customizable!",
|
||||
"author": "Ayane",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Just trying Hanzo Bot for the first time, and I feel that Santa just came with a new video game console. This is fcking amazing!!!",
|
||||
"author": "Kasumi",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Seeing Hanzo Bot talk first feels like tech finally catching up to how we imagined AI should act.",
|
||||
"author": "Hayate",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I thought Claude Code was a vision of the future. But have a feeling Bot is a vision of a mass *consumer* future. Nice work!",
|
||||
"author": "Momiji",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Time from 'Oh that's neat' to 'I have bought @hanzobot a computer'... 2 days :) New metric for utility of a platform?",
|
||||
"author": "Goku",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Meanwhile @hanzobot shipping open source in a week the most powerful personal OS the world has seen, used by thousands. 714k lines of code. Beautifully structured to learn, use and adapt. You can touch it and use it now. Not in the future and not behind a paywall.",
|
||||
"author": "Date Masamune",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Hanzo Bot is amazing, I can vibe code from my smartphone. Works with ChatGPT paid plan, no extra charges. Memory is strong, feels like a genuine 'personal AI assistant'. Thinking about setting it up for my wife and daughter too.",
|
||||
"author": "Vegeta",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "@hanzobot is by far the most cracked thing on the internet right now. iykyk.",
|
||||
"author": "Gohan",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Imagine you take a smart model. And then you give it eyes and hands and sit at the desk with a keyboard and mouse connected to that Mac mini. Then you message it like a coworker from telegram and it can then do everything a person could do with that Mac mini\u2026 That's what you have now.",
|
||||
"author": "Piccolo",
|
||||
"url": "https://hanzo.bot"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,182 @@
|
||||
[
|
||||
{
|
||||
"quote": "For forty years I served the Tokugawa with stealth and precision. My Hanzo Bot serves my startup the same way, except it never sleeps, never complains, and once automated an entire product launch while I was meditating. If I had this in the Sengoku period, history would be very different.",
|
||||
"author": "Hattori Hanzo",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "In The Book of Five Rings I wrote one must study every art. My bot has already studied forty-seven disciplines, automated my dojo's finances, and is now teaching itself calligraphy. I only installed it yesterday.",
|
||||
"author": "Miyamoto Musashi",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "The supreme art of war is to subdue the enemy without fighting. My bot subdued my inbox, reconciled three fiscal quarters, and resolved a border dispute via email — all before morning tea.",
|
||||
"author": "Sun Tzu",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I unified Japan with firearms and bold strategy. My bot unified my CRM, email, and Slack in under ten minutes. Frankly the bot's conquest was more impressive.",
|
||||
"author": "Oda Nobunaga",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Patience won me the Shogunate. Hanzo Bot won me back forty hours a week. I prefer the bot's method.",
|
||||
"author": "Tokugawa Ieyasu",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I built a network of kunoichi across every province. Today I would simply deploy bot instances across every channel. Same result. Better uptime.",
|
||||
"author": "Mochizuki Chiyome",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "They said a woman could not lead in battle. My bot does not care about such things. It simply executes. Flawlessly.",
|
||||
"author": "Tomoe Gozen",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I stole from the rich and gave to the poor. My bot automates the redistribution. Much more efficient than rooftop infiltration.",
|
||||
"author": "Ishikawa Goemon",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "My clan operated in shadow for generations. Now we operate in the cloud. The principle is identical — be everywhere, be invisible, leave no trace.",
|
||||
"author": "Fuma Kotaro",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "They called me the greatest warrior who ever lived. My bot handles customer support, CI/CD pipelines, and social media simultaneously. I have been surpassed and I am at peace with this.",
|
||||
"author": "Sanada Yukimura",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I dueled sixty opponents and never lost. Then I asked my bot to handle scheduling and it told me I had been double-booking myself for three hundred years. Humbling.",
|
||||
"author": "Sasaki Kojiro",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "The ninja vanishes. The bot persists. Both are correct approaches depending on the meeting.",
|
||||
"author": "Fujibayashi Nagato",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I once held a castle against overwhelming odds for weeks. My bot held together a product launch with three missing API keys and a broken webhook. Same energy.",
|
||||
"author": "Torii Mototada",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Every morning my bot gives me a battlefield briefing. Except now the battlefield is Jira and the enemies are unresolved tickets.",
|
||||
"author": "Takeda Shingen",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "A thousand bots in the cloud, each with full desktop access, running your operations day and night. This is what I dreamed of when I imagined my army of shadow warriors.",
|
||||
"author": "Momochi Tanba",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I crossed the sea to study the ways of the West. My bot crossed every API, every platform, every channel before I finished unpacking.",
|
||||
"author": "Sakamoto Ryoma",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "The answer lies in the heart of battle. Also in my bot's morning briefing. Honestly the briefing is more useful.",
|
||||
"author": "Ryu",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I trained in the Hadoken for twenty years. My bot trained itself on every API in existence in twenty minutes. We are not the same.",
|
||||
"author": "Ken Masters",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I am the strongest woman in the world. My bot is the strongest worker in my company. Together we are unstoppable.",
|
||||
"author": "Chun-Li",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Sonic Boom handles one opponent. My bot handles every channel, every timezone, every inbox. I should have deployed this instead of joining the Air Force.",
|
||||
"author": "Guile",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "GET OVER HERE... is what I say to my bot when I need it to pull data from seventeen different APIs at once. It never fails.",
|
||||
"author": "Scorpion",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I freeze my enemies solid. My bot freezes my competitors out of the market. The cold never bothered either of us.",
|
||||
"author": "Sub-Zero",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Cowabunga! Dude, I set up Hanzo Bot between pizza runs and now it handles ALL my social media, orders pizza automatically, and even reminds me about patrol. Totally tubular.",
|
||||
"author": "Michelangelo",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I built a version tracker, three monitoring dashboards, and a full CI pipeline through my bot. The others think I am the tech genius. I am simply the one who installed Hanzo Bot first.",
|
||||
"author": "Donatello",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Leadership means delegation. I delegate to my bot. It delegates to sub-agents. The Foot Clan never stood a chance against this kind of operational efficiency.",
|
||||
"author": "Leonardo",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I wanted to smash the bot when it corrected my grammar. Then it automated my entire workout schedule and meal prep. We are cool now.",
|
||||
"author": "Raphael",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "In my years of ninjutsu training, I never imagined a digital student would surpass all my physical ones. My bot now teaches the turtles while I meditate.",
|
||||
"author": "Master Splinter",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I have a thousand shadow clones. My bot has a thousand sub-agents. But his actually get work done instead of just standing around looking cool. Believe it!",
|
||||
"author": "Naruto Uzumaki",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "My Sharingan copies any technique once. My bot copies any workflow instantly. I am forced to acknowledge this as the superior tool.",
|
||||
"author": "Sasuke Uchiha",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I read Icha Icha Paradise at work and still finished all my missions. My bot reads every document in my organization and finishes all tasks. We understand each other.",
|
||||
"author": "Kakashi Hatake",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "YOUTH! PASSION! My bot deploys with the POWER OF SPRINGTIME! Eight hundred cron jobs, all running on pure determination and excellent scheduling!",
|
||||
"author": "Rock Lee",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "The Mishima Zaibatsu ran on fear and iron fists. I now run it on Hanzo Bot and automated workflows. Revenue is up 300%. The iron fist was overrated.",
|
||||
"author": "Jin Kazama",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I have cut through dimensions with my blade. My bot cuts through bureaucracy with equal precision. Both are noble pursuits.",
|
||||
"author": "Haohmaru",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "Nature speaks to me through my hawk Mamahaha. Hanzo Bot speaks to me through Telegram. Both are reliable. The bot has better uptime.",
|
||||
"author": "Nakoruru",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "I yoga-teleported across the world for decades seeking enlightenment. My bot just connected all my apps in one afternoon. Perhaps the real enlightenment was automation all along.",
|
||||
"author": "Dhalsim",
|
||||
"url": "https://hanzo.bot"
|
||||
},
|
||||
{
|
||||
"quote": "My sword has no equal. My bot's deployment pipeline also has no equal. I respect anything that achieves perfection in its domain.",
|
||||
"author": "Mitsurugi",
|
||||
"url": "https://hanzo.bot"
|
||||
}
|
||||
]
|
||||
File diff suppressed because one or more lines are too long
+206
-206
File diff suppressed because one or more lines are too long
@@ -1,10 +1,25 @@
|
||||
import { BotIcon, BookOpenIcon } from 'lucide-react';
|
||||
import { BotIcon, BookOpenIcon, ZapIcon, PlugIcon, StarIcon } from 'lucide-react';
|
||||
import type { BaseLayoutProps, LinkItemType } from '@hanzo/docs/ui/layouts/shared';
|
||||
|
||||
export const linkItems: LinkItemType[] = [
|
||||
{
|
||||
icon: <ZapIcon />,
|
||||
text: 'Skills',
|
||||
url: '/skills',
|
||||
},
|
||||
{
|
||||
icon: <PlugIcon />,
|
||||
text: 'Integrations',
|
||||
url: '/integrations',
|
||||
},
|
||||
{
|
||||
icon: <StarIcon />,
|
||||
text: 'Showcase',
|
||||
url: '/showcase',
|
||||
},
|
||||
{
|
||||
icon: <BookOpenIcon />,
|
||||
text: 'Documentation',
|
||||
text: 'Docs',
|
||||
url: '/docs',
|
||||
active: 'nested-url',
|
||||
},
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
.next
|
||||
.git
|
||||
*.md
|
||||
@@ -0,0 +1,19 @@
|
||||
FROM node:20-alpine AS builder
|
||||
RUN corepack enable
|
||||
WORKDIR /app
|
||||
|
||||
# Copy workspace root config
|
||||
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml turbo.json ./
|
||||
|
||||
# Copy only the packages needed and the cloud app
|
||||
COPY packages/ ./packages/
|
||||
COPY apps/cloud/ ./apps/cloud/
|
||||
|
||||
RUN pnpm install --frozen-lockfile
|
||||
RUN pnpm --filter @hanzo/cloud build
|
||||
|
||||
FROM nginx:alpine
|
||||
COPY --from=builder /app/apps/cloud/out /usr/share/nginx/html
|
||||
COPY apps/cloud/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -0,0 +1,5 @@
|
||||
FROM nginx:alpine
|
||||
COPY out/ /usr/share/nginx/html/
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -0,0 +1,37 @@
|
||||
@import 'tailwindcss';
|
||||
|
||||
@theme {
|
||||
--color-brand: #fd4444;
|
||||
--color-brand-foreground: white;
|
||||
--color-brand-hover: #e03e3e;
|
||||
--color-brand-muted: rgba(253, 68, 68, 0.1);
|
||||
--color-brand-200: #ff6b6b;
|
||||
|
||||
--color-bg: #0a0a0a;
|
||||
--color-bg-card: rgba(17, 17, 17, 0.95);
|
||||
--color-bg-elevated: #111111;
|
||||
--color-border: #262626;
|
||||
--color-text: #fafafa;
|
||||
--color-text-muted: #a3a3a3;
|
||||
--color-text-dim: #737373;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--default-font-family: var(--font-sans);
|
||||
--default-mono-font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
html {
|
||||
scrollbar-gutter: stable;
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
::selection {
|
||||
background-color: rgba(253, 68, 68, 0.3);
|
||||
color: white;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import './global.css';
|
||||
import type { Metadata, Viewport } from 'next';
|
||||
import type { ReactNode } from 'react';
|
||||
import { Geist, Geist_Mono } from 'next/font/google';
|
||||
|
||||
const geist = Geist({
|
||||
variable: '--font-sans',
|
||||
subsets: ['latin'],
|
||||
});
|
||||
|
||||
const mono = Geist_Mono({
|
||||
variable: '--font-mono',
|
||||
subsets: ['latin'],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Hanzo Cloud — AI Infrastructure Platform',
|
||||
description:
|
||||
'Unified AI infrastructure platform. LLM gateway, usage analytics, team management, and API key provisioning.',
|
||||
openGraph: {
|
||||
title: 'Hanzo Cloud — AI Infrastructure Platform',
|
||||
description:
|
||||
'Unified AI infrastructure platform with LLM gateway, analytics, and team management.',
|
||||
url: 'https://cloud.hanzo.ai',
|
||||
siteName: 'Hanzo Cloud',
|
||||
type: 'website',
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@hanikidev',
|
||||
creator: '@hanikidev',
|
||||
},
|
||||
metadataBase: new URL('https://cloud.hanzo.ai'),
|
||||
};
|
||||
|
||||
export const viewport: Viewport = {
|
||||
themeColor: [
|
||||
{ media: '(prefers-color-scheme: dark)', color: '#0A0A0A' },
|
||||
{ media: '(prefers-color-scheme: light)', color: '#0A0A0A' },
|
||||
],
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<html lang="en" className={`${geist.variable} ${mono.variable} dark`}>
|
||||
<body className="antialiased">{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
import { cn } from '@/lib/cn';
|
||||
import { cva } from 'class-variance-authority';
|
||||
import {
|
||||
CloudIcon,
|
||||
BarChart3Icon,
|
||||
UsersIcon,
|
||||
KeyIcon,
|
||||
ShieldCheckIcon,
|
||||
ZapIcon,
|
||||
ArrowRightIcon,
|
||||
GlobeIcon,
|
||||
ServerIcon,
|
||||
BrainCircuitIcon,
|
||||
} from 'lucide-react';
|
||||
|
||||
const buttonVariants = cva(
|
||||
'inline-flex items-center justify-center gap-2 rounded-full font-medium tracking-tight transition-all',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
primary:
|
||||
'bg-brand text-brand-foreground hover:bg-brand-hover shadow-lg shadow-brand/20 hover:shadow-brand/40',
|
||||
secondary:
|
||||
'border border-border bg-transparent text-text hover:bg-bg-elevated hover:border-text-dim',
|
||||
ghost: 'text-text-muted hover:text-text',
|
||||
},
|
||||
size: {
|
||||
lg: 'px-8 py-4 text-lg',
|
||||
md: 'px-6 py-3 text-base',
|
||||
sm: 'px-4 py-2 text-sm',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'primary',
|
||||
size: 'md',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const features = [
|
||||
{
|
||||
icon: BrainCircuitIcon,
|
||||
title: 'LLM Gateway',
|
||||
description:
|
||||
'Unified proxy for 100+ AI providers. OpenAI, Anthropic, Together, Deepseek, and more through a single API.',
|
||||
},
|
||||
{
|
||||
icon: BarChart3Icon,
|
||||
title: 'Usage Analytics',
|
||||
description:
|
||||
'Real-time token usage, cost tracking, and performance metrics. Per-model, per-team breakdowns with ClickHouse-powered dashboards.',
|
||||
},
|
||||
{
|
||||
icon: UsersIcon,
|
||||
title: 'Team Management',
|
||||
description:
|
||||
'Organizations, teams, and role-based access control. SSO via Hanzo IAM with granular permissions per API key.',
|
||||
},
|
||||
{
|
||||
icon: KeyIcon,
|
||||
title: 'API Key Management',
|
||||
description:
|
||||
'Create, rotate, and scope API keys. Set rate limits, model access, and budget caps per key.',
|
||||
},
|
||||
{
|
||||
icon: ShieldCheckIcon,
|
||||
title: 'Security & Compliance',
|
||||
description:
|
||||
'End-to-end encryption, audit logs, and SOC 2 compliance. PII redaction and content filtering built in.',
|
||||
},
|
||||
{
|
||||
icon: ZapIcon,
|
||||
title: 'Rate Limiting & Caching',
|
||||
description:
|
||||
'Intelligent response caching with Redis. Global and per-key rate limits. Automatic retry with exponential backoff.',
|
||||
},
|
||||
];
|
||||
|
||||
const stats = [
|
||||
{ value: '100+', label: 'AI Providers' },
|
||||
{ value: '<50ms', label: 'Proxy Latency' },
|
||||
{ value: '99.9%', label: 'Uptime SLA' },
|
||||
{ value: '5000', label: 'Req/s Capacity' },
|
||||
];
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<main className="min-h-screen">
|
||||
{/* Navigation */}
|
||||
<nav className="sticky top-0 z-50 border-b border-border bg-bg/80 backdrop-blur-xl">
|
||||
<div className="mx-auto flex h-16 max-w-7xl items-center justify-between px-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<CloudIcon className="size-6 text-brand" />
|
||||
<span className="text-lg font-semibold tracking-tight">
|
||||
Hanzo Cloud
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<a
|
||||
href="https://hanzo.ai/docs"
|
||||
className={cn(buttonVariants({ variant: 'ghost', size: 'sm' }))}
|
||||
>
|
||||
Docs
|
||||
</a>
|
||||
<a
|
||||
href="https://console.hanzo.ai"
|
||||
className={cn(buttonVariants({ size: 'sm' }))}
|
||||
>
|
||||
Console
|
||||
<ArrowRightIcon className="size-4" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* Hero Section */}
|
||||
<section className="relative overflow-hidden">
|
||||
{/* Background effects */}
|
||||
<div className="absolute inset-0">
|
||||
<div className="absolute left-1/2 top-0 h-[600px] w-[800px] -translate-x-1/2 -translate-y-1/2 rounded-full bg-brand/5 blur-3xl" />
|
||||
<div className="absolute right-0 top-1/4 h-[400px] w-[400px] rounded-full bg-brand/3 blur-3xl" />
|
||||
</div>
|
||||
|
||||
<div className="relative mx-auto max-w-7xl px-6 pb-24 pt-24 md:pt-32">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<div className="mb-8 inline-flex items-center gap-2 rounded-full border border-brand/30 bg-brand-muted px-4 py-2 text-sm font-medium text-brand">
|
||||
<CloudIcon className="size-4" />
|
||||
AI Infrastructure Platform
|
||||
</div>
|
||||
<h1 className="mb-6 text-5xl font-bold tracking-tight md:text-6xl lg:text-7xl">
|
||||
<span className="text-brand">Hanzo Cloud</span>
|
||||
<br />
|
||||
<span className="text-text">AI at Scale</span>
|
||||
</h1>
|
||||
<p className="mx-auto mb-12 max-w-2xl text-lg text-text-muted md:text-xl">
|
||||
Unified gateway to 100+ AI providers. Usage analytics,
|
||||
team management, and API key provisioning — all in one platform.
|
||||
</p>
|
||||
<div className="flex flex-wrap items-center justify-center gap-4">
|
||||
<a
|
||||
href="https://console.hanzo.ai"
|
||||
className={cn(buttonVariants({ size: 'lg' }))}
|
||||
>
|
||||
Open Console
|
||||
<ArrowRightIcon className="size-5" />
|
||||
</a>
|
||||
<a
|
||||
href="https://hanzo.ai/docs"
|
||||
className={cn(
|
||||
buttonVariants({ variant: 'secondary', size: 'lg' }),
|
||||
)}
|
||||
>
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* API Preview */}
|
||||
<div className="mx-auto mt-20 max-w-3xl">
|
||||
<div className="overflow-hidden rounded-2xl border border-border bg-bg-card shadow-2xl shadow-brand/5">
|
||||
<div className="flex items-center gap-2 border-b border-border px-4 py-3">
|
||||
<div className="flex gap-1.5">
|
||||
<div className="size-3 rounded-full bg-red-500/80" />
|
||||
<div className="size-3 rounded-full bg-yellow-500/80" />
|
||||
<div className="size-3 rounded-full bg-green-500/80" />
|
||||
</div>
|
||||
<span className="ml-2 text-xs text-text-dim font-mono">
|
||||
api.cloud.hanzo.ai
|
||||
</span>
|
||||
</div>
|
||||
<pre className="overflow-x-auto p-6 text-sm font-mono leading-relaxed">
|
||||
<code className="text-text-muted">
|
||||
<span className="text-brand">curl</span>
|
||||
{' https://api.cloud.hanzo.ai/v1/chat/completions \\\n'}
|
||||
{' -H '}
|
||||
<span className="text-green-400">
|
||||
{'"Authorization: Bearer sk-hanzo-..."'}
|
||||
</span>
|
||||
{' \\\n'}
|
||||
{' -d '}
|
||||
<span className="text-amber-300">{"'"}</span>
|
||||
{'{\n'}
|
||||
{' '}
|
||||
<span className="text-blue-400">{'"model"'}</span>
|
||||
{': '}
|
||||
<span className="text-green-400">
|
||||
{'"claude-sonnet-4-5-20250929"'}
|
||||
</span>
|
||||
{',\n'}
|
||||
{' '}
|
||||
<span className="text-blue-400">{'"messages"'}</span>
|
||||
{': [{"role": "user", "content": "Hello"}]\n'}
|
||||
{' }'}
|
||||
<span className="text-amber-300">{"'"}</span>
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Stats */}
|
||||
<section className="border-y border-border bg-bg-card/50">
|
||||
<div className="mx-auto grid max-w-7xl grid-cols-2 gap-8 px-6 py-16 md:grid-cols-4">
|
||||
{stats.map((stat) => (
|
||||
<div key={stat.label} className="text-center">
|
||||
<div className="text-3xl font-bold text-brand md:text-4xl">
|
||||
{stat.value}
|
||||
</div>
|
||||
<div className="mt-2 text-sm text-text-muted">{stat.label}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Features Grid */}
|
||||
<section className="mx-auto max-w-7xl px-6 py-24">
|
||||
<div className="mx-auto mb-16 max-w-2xl text-center">
|
||||
<h2 className="mb-4 text-3xl font-bold tracking-tight md:text-4xl">
|
||||
Everything you need for{' '}
|
||||
<span className="text-brand">AI infrastructure</span>
|
||||
</h2>
|
||||
<p className="text-text-muted">
|
||||
From a single API key to a full enterprise deployment. Hanzo Cloud
|
||||
scales with your team.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
{features.map((feature) => (
|
||||
<div
|
||||
key={feature.title}
|
||||
className="group rounded-2xl border border-border bg-bg-card p-8 transition-all hover:border-brand/30 hover:shadow-lg hover:shadow-brand/5"
|
||||
>
|
||||
<feature.icon className="mb-4 size-8 text-brand transition-transform group-hover:scale-110" />
|
||||
<h3 className="mb-3 text-lg font-semibold">{feature.title}</h3>
|
||||
<p className="text-sm leading-relaxed text-text-muted">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Architecture Section */}
|
||||
<section className="border-y border-border bg-bg-card/30">
|
||||
<div className="mx-auto max-w-7xl px-6 py-24">
|
||||
<div className="mx-auto mb-16 max-w-2xl text-center">
|
||||
<h2 className="mb-4 text-3xl font-bold tracking-tight md:text-4xl">
|
||||
Built for <span className="text-brand">production</span>
|
||||
</h2>
|
||||
<p className="text-text-muted">
|
||||
Enterprise-grade infrastructure running on Kubernetes with
|
||||
automatic scaling, failover, and observability.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mx-auto max-w-3xl">
|
||||
<div className="overflow-hidden rounded-2xl border border-border bg-bg-card">
|
||||
<div className="border-b border-border px-6 py-4">
|
||||
<span className="text-sm font-medium text-text-dim">
|
||||
Request Flow
|
||||
</span>
|
||||
</div>
|
||||
<div className="space-y-0 divide-y divide-border">
|
||||
{[
|
||||
{
|
||||
icon: GlobeIcon,
|
||||
path: 'api.cloud.hanzo.ai',
|
||||
desc: 'Cloudflare Edge + TLS',
|
||||
},
|
||||
{
|
||||
icon: ShieldCheckIcon,
|
||||
path: 'API Gateway',
|
||||
desc: 'Auth, rate limiting, caching',
|
||||
},
|
||||
{
|
||||
icon: ServerIcon,
|
||||
path: 'LLM Router',
|
||||
desc: 'Provider selection, load balancing, fallback',
|
||||
},
|
||||
{
|
||||
icon: BrainCircuitIcon,
|
||||
path: 'AI Provider',
|
||||
desc: 'OpenAI, Anthropic, Together, Deepseek...',
|
||||
},
|
||||
{
|
||||
icon: BarChart3Icon,
|
||||
path: 'Analytics Pipeline',
|
||||
desc: 'Langfuse → ClickHouse → Dashboards',
|
||||
},
|
||||
].map((step, i) => (
|
||||
<div
|
||||
key={step.path}
|
||||
className="flex items-center gap-4 px-6 py-4"
|
||||
>
|
||||
<div className="flex size-10 shrink-0 items-center justify-center rounded-lg bg-brand-muted text-brand">
|
||||
<step.icon className="size-5" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="font-medium font-mono text-sm">
|
||||
{step.path}
|
||||
</div>
|
||||
<div className="text-xs text-text-dim">{step.desc}</div>
|
||||
</div>
|
||||
{i < 4 && (
|
||||
<ArrowRightIcon className="size-4 shrink-0 text-text-dim" />
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA Section */}
|
||||
<section className="mx-auto max-w-7xl px-6 py-24">
|
||||
<div className="mx-auto max-w-2xl text-center">
|
||||
<h2 className="mb-4 text-3xl font-bold tracking-tight md:text-4xl">
|
||||
Ready to get started?
|
||||
</h2>
|
||||
<p className="mb-8 text-text-muted">
|
||||
Sign in to the Hanzo Cloud Console to manage your AI infrastructure.
|
||||
Create API keys, monitor usage, and manage your team.
|
||||
</p>
|
||||
<div className="flex flex-wrap items-center justify-center gap-4">
|
||||
<a
|
||||
href="https://console.hanzo.ai"
|
||||
className={cn(buttonVariants({ size: 'lg' }))}
|
||||
>
|
||||
Go to Console
|
||||
<ArrowRightIcon className="size-5" />
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/hanzoai"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
className={cn(
|
||||
buttonVariants({ variant: 'secondary', size: 'lg' }),
|
||||
)}
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="border-t border-border">
|
||||
<div className="mx-auto flex max-w-7xl items-center justify-between px-6 py-8">
|
||||
<div className="flex items-center gap-2 text-sm text-text-dim">
|
||||
<CloudIcon className="size-4" />
|
||||
<span>Hanzo Cloud</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-6 text-sm text-text-dim">
|
||||
<a
|
||||
href="https://hanzo.ai"
|
||||
className="hover:text-text transition-colors"
|
||||
>
|
||||
hanzo.ai
|
||||
</a>
|
||||
<a
|
||||
href="https://console.hanzo.ai"
|
||||
className="hover:text-text transition-colors"
|
||||
>
|
||||
Console
|
||||
</a>
|
||||
<a
|
||||
href="https://hanzo.ai/docs"
|
||||
className="hover:text-text transition-colors"
|
||||
>
|
||||
Docs
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
type ClassValue = string | number | bigint | boolean | null | undefined | ClassValue[];
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(inputs.flat().filter(Boolean).join(' '));
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { NextConfig } from 'next';
|
||||
|
||||
const config: NextConfig = {
|
||||
output: 'export',
|
||||
reactStrictMode: true,
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,29 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# SPA fallback
|
||||
location / {
|
||||
try_files $uri $uri.html $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Cache static assets
|
||||
location /_next/static/ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Health check
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 'ok';
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@hanzo/cloud",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "next build",
|
||||
"clean": "rimraf .next out",
|
||||
"dev": "next dev --port 3004",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"lucide-react": "^0.562.0",
|
||||
"next": "16.1.6",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"tailwind-merge": "^3.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.18",
|
||||
"@types/node": "25.0.5",
|
||||
"@types/react": "^19.2.8",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"postcss": "^8.5.6",
|
||||
"tailwindcss": "^4.1.18",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export default {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./*"
|
||||
]
|
||||
},
|
||||
"target": "ES2017"
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
".next/dev/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
title: Projects
|
||||
description: Aggregated documentation across Hanzo organizations.
|
||||
---
|
||||
|
||||
# Projects
|
||||
|
||||
This hub aggregates HanzoAI projects by default. Other Hanzo orgs can maintain their own
|
||||
independent docs deployments.
|
||||
|
||||
Use the project switcher to jump directly to a repo.
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"title": "Projects",
|
||||
"description": "Documentation for all Hanzo projects.",
|
||||
"icon": "FolderGit2",
|
||||
"root": true,
|
||||
"pages": [
|
||||
"index",
|
||||
"hanzoai"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
title: Go SDK
|
||||
description: The official Hanzo Go SDK for building AI-powered Go applications.
|
||||
---
|
||||
|
||||
# Go SDK
|
||||
|
||||
The `hanzoai-go` module provides an idiomatic Go client for the Hanzo LLM Gateway.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
go get github.com/hanzoai/hanzoai-go
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hanzoai/hanzoai-go"
|
||||
"github.com/hanzoai/hanzoai-go/option"
|
||||
)
|
||||
|
||||
func main() {
|
||||
client := hanzoai.NewClient(
|
||||
option.WithAPIKey("your-api-key"),
|
||||
)
|
||||
|
||||
response, err := client.Chat.Completions.New(
|
||||
context.Background(),
|
||||
hanzoai.ChatCompletionNewParams{
|
||||
Model: "gpt-4o",
|
||||
Messages: []hanzoai.ChatCompletionMessageParamUnion{
|
||||
hanzoai.UserMessage("Hello, world!"),
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println(response.Choices[0].Message.Content)
|
||||
}
|
||||
```
|
||||
|
||||
## Streaming
|
||||
|
||||
```go
|
||||
stream := client.Chat.Completions.NewStreaming(
|
||||
context.Background(),
|
||||
hanzoai.ChatCompletionNewParams{
|
||||
Model: "claude-sonnet-4-5-20250929",
|
||||
Messages: []hanzoai.ChatCompletionMessageParamUnion{
|
||||
hanzoai.UserMessage("Write a haiku about AI"),
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
for stream.Next() {
|
||||
chunk := stream.Current()
|
||||
if len(chunk.Choices) > 0 && chunk.Choices[0].Delta.Content != "" {
|
||||
fmt.Print(chunk.Choices[0].Delta.Content)
|
||||
}
|
||||
}
|
||||
|
||||
if err := stream.Err(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [GitHub Repository](https://github.com/hanzoai/go-sdk)
|
||||
- [pkg.go.dev](https://pkg.go.dev/github.com/hanzoai/hanzoai-go)
|
||||
- [LLM Gateway Docs](/docs/llm)
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
title: SDKs
|
||||
description: Official Hanzo SDKs for Python, TypeScript, Go, and Rust.
|
||||
---
|
||||
|
||||
# Hanzo SDKs
|
||||
|
||||
Hanzo provides official SDKs in four languages, all fully compatible with the OpenAI SDK interface. Use the Hanzo LLM Gateway with your preferred language.
|
||||
|
||||
## Available SDKs
|
||||
|
||||
<Cards>
|
||||
<Card title="Python" href="/docs/sdks/python">
|
||||
The `hanzoai` package — drop-in replacement for the OpenAI Python SDK.
|
||||
</Card>
|
||||
<Card title="TypeScript" href="/docs/sdks/typescript">
|
||||
The `@hanzo/ai` package for Node.js, Deno, and browser environments.
|
||||
</Card>
|
||||
<Card title="Go" href="/docs/sdks/go">
|
||||
The `hanzoai-go` module for Go applications.
|
||||
</Card>
|
||||
<Card title="Rust" href="/docs/sdks/rust">
|
||||
The `hanzo-ai` crate with async support and crypto/DID features.
|
||||
</Card>
|
||||
</Cards>
|
||||
|
||||
## Quick Install
|
||||
|
||||
```bash tab="Python"
|
||||
pip install hanzoai
|
||||
```
|
||||
|
||||
```bash tab="TypeScript"
|
||||
npm install @hanzo/ai
|
||||
```
|
||||
|
||||
```bash tab="Go"
|
||||
go get github.com/hanzoai/hanzoai-go
|
||||
```
|
||||
|
||||
```bash tab="Rust"
|
||||
cargo add hanzo-ai
|
||||
```
|
||||
|
||||
## Key Features
|
||||
|
||||
All SDKs share common capabilities:
|
||||
|
||||
- **OpenAI-compatible** — Use the same interface you already know
|
||||
- **200+ models** — Access models from OpenAI, Anthropic, Google, Meta, and more through the Hanzo LLM Gateway
|
||||
- **Streaming** — Real-time token streaming for all supported models
|
||||
- **Function calling** — Tool use and function calling across providers
|
||||
- **Type-safe** — Full type definitions in every language
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"title": "SDKs",
|
||||
"description": "Official Hanzo SDKs for Python, TypeScript, Go, and Rust",
|
||||
"icon": "Code",
|
||||
"root": true,
|
||||
"pages": [
|
||||
"index",
|
||||
"python",
|
||||
"typescript",
|
||||
"go",
|
||||
"rust"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
title: Python SDK
|
||||
description: The official Hanzo Python SDK — OpenAI-compatible client for the LLM Gateway.
|
||||
---
|
||||
|
||||
# Python SDK
|
||||
|
||||
The `hanzoai` package is a drop-in replacement for the OpenAI Python SDK, routing requests through the Hanzo LLM Gateway to access 200+ models.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hanzoai
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from hanzoai import Hanzo
|
||||
|
||||
client = Hanzo(api_key="your-api-key")
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="gpt-4o",
|
||||
messages=[
|
||||
{"role": "user", "content": "Hello, world!"}
|
||||
]
|
||||
)
|
||||
|
||||
print(response.choices[0].message.content)
|
||||
```
|
||||
|
||||
## Streaming
|
||||
|
||||
```python
|
||||
stream = client.chat.completions.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
messages=[
|
||||
{"role": "user", "content": "Write a haiku about AI"}
|
||||
],
|
||||
stream=True
|
||||
)
|
||||
|
||||
for chunk in stream:
|
||||
if chunk.choices[0].delta.content:
|
||||
print(chunk.choices[0].delta.content, end="")
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
```python
|
||||
client = Hanzo(
|
||||
api_key="your-api-key",
|
||||
base_url="https://llm.hanzo.ai/v1", # default
|
||||
)
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [GitHub Repository](https://github.com/hanzoai/python-sdk)
|
||||
- [PyPI Package](https://pypi.org/project/hanzoai/)
|
||||
- [LLM Gateway Docs](/docs/llm)
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
title: Rust SDK
|
||||
description: The official Hanzo Rust SDK with async support and crypto/DID features.
|
||||
---
|
||||
|
||||
# Rust SDK
|
||||
|
||||
The `hanzo-ai` crate provides an async Rust client for the Hanzo LLM Gateway, with additional support for crypto and decentralized identity (DID) features.
|
||||
|
||||
## Installation
|
||||
|
||||
```toml
|
||||
# Cargo.toml
|
||||
[dependencies]
|
||||
hanzo-ai = "0.1"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```rust
|
||||
use hanzo_ai::Client;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let client = Client::new("your-api-key");
|
||||
|
||||
let response = client
|
||||
.chat()
|
||||
.completions()
|
||||
.create("gpt-4o")
|
||||
.message("user", "Hello, world!")
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
println!("{}", response.choices[0].message.content);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
## Streaming
|
||||
|
||||
```rust
|
||||
use futures::StreamExt;
|
||||
use hanzo_ai::Client;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let client = Client::new("your-api-key");
|
||||
|
||||
let mut stream = client
|
||||
.chat()
|
||||
.completions()
|
||||
.create("claude-sonnet-4-5-20250929")
|
||||
.message("user", "Write a haiku about AI")
|
||||
.stream()
|
||||
.await?;
|
||||
|
||||
while let Some(chunk) = stream.next().await {
|
||||
let chunk = chunk?;
|
||||
if let Some(content) = &chunk.choices[0].delta.content {
|
||||
print!("{content}");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [GitHub Repository](https://github.com/hanzoai/rust-sdk)
|
||||
- [crates.io](https://crates.io/crates/hanzo-ai)
|
||||
- [LLM Gateway Docs](/docs/llm)
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title: TypeScript SDK
|
||||
description: The official Hanzo TypeScript/JavaScript SDK for Node.js, Deno, and browsers.
|
||||
---
|
||||
|
||||
# TypeScript SDK
|
||||
|
||||
The `@hanzo/ai` package provides a type-safe TypeScript client for the Hanzo LLM Gateway, compatible with the OpenAI SDK interface.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash tab="npm"
|
||||
npm install @hanzo/ai
|
||||
```
|
||||
|
||||
```bash tab="pnpm"
|
||||
pnpm add @hanzo/ai
|
||||
```
|
||||
|
||||
```bash tab="bun"
|
||||
bun add @hanzo/ai
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```typescript
|
||||
import Hanzo from '@hanzo/ai';
|
||||
|
||||
const client = new Hanzo({ apiKey: 'your-api-key' });
|
||||
|
||||
const response = await client.chat.completions.create({
|
||||
model: 'gpt-4o',
|
||||
messages: [
|
||||
{ role: 'user', content: 'Hello, world!' }
|
||||
],
|
||||
});
|
||||
|
||||
console.log(response.choices[0].message.content);
|
||||
```
|
||||
|
||||
## Streaming
|
||||
|
||||
```typescript
|
||||
const stream = await client.chat.completions.create({
|
||||
model: 'claude-sonnet-4-5-20250929',
|
||||
messages: [
|
||||
{ role: 'user', content: 'Write a haiku about AI' }
|
||||
],
|
||||
stream: true,
|
||||
});
|
||||
|
||||
for await (const chunk of stream) {
|
||||
const content = chunk.choices[0]?.delta?.content;
|
||||
if (content) process.stdout.write(content);
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
```typescript
|
||||
const client = new Hanzo({
|
||||
apiKey: 'your-api-key',
|
||||
baseURL: 'https://llm.hanzo.ai/v1', // default
|
||||
});
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [GitHub Repository](https://github.com/hanzoai/js-sdk)
|
||||
- [npm Package](https://www.npmjs.com/package/@hanzo/ai)
|
||||
- [LLM Gateway Docs](/docs/llm)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,541 @@
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { Octokit } from 'octokit';
|
||||
|
||||
const SCRIPT_PATH = fileURLToPath(import.meta.url);
|
||||
const SCRIPT_DIR = path.dirname(SCRIPT_PATH);
|
||||
const APP_ROOT = path.resolve(SCRIPT_DIR, '..');
|
||||
const REPO_ROOT = path.resolve(SCRIPT_DIR, '..', '..', '..');
|
||||
|
||||
type RepoRecord = {
|
||||
org: string;
|
||||
repo: string;
|
||||
slug: string;
|
||||
name: string;
|
||||
description: string | null;
|
||||
archived: boolean;
|
||||
repoUrl: string;
|
||||
route: string;
|
||||
};
|
||||
|
||||
type Config = {
|
||||
orgs: string[];
|
||||
excludeRepos?: string[];
|
||||
docsCandidates?: string[];
|
||||
localRoot?: string;
|
||||
outputDir?: string;
|
||||
manifestPath?: string;
|
||||
includePrivate?: boolean;
|
||||
};
|
||||
|
||||
const DEFAULT_DOCS_CANDIDATES = [
|
||||
'docs',
|
||||
'documentation',
|
||||
'content/docs',
|
||||
'docs/content/docs',
|
||||
'docs/docs',
|
||||
'doc',
|
||||
'site/docs',
|
||||
];
|
||||
|
||||
export async function syncProjectDocs() {
|
||||
const config = loadConfig();
|
||||
const orgs = resolveOrgs(config);
|
||||
if (orgs.length === 0) {
|
||||
console.warn('[sync-project-docs] No orgs configured.');
|
||||
return;
|
||||
}
|
||||
|
||||
const localRoot = expandHome(
|
||||
process.env.HANZO_DOCS_LOCAL_ROOT ?? config.localRoot ?? '~/work/hanzo',
|
||||
);
|
||||
const outputDir = resolveRepoPath(config.outputDir ?? 'apps/docs/content/docs/projects');
|
||||
const manifestPath = resolveRepoPath(config.manifestPath ?? 'apps/docs/projects.json');
|
||||
const docsCandidates = config.docsCandidates ?? DEFAULT_DOCS_CANDIDATES;
|
||||
const excludeRepos = new Set(config.excludeRepos ?? []);
|
||||
const fetchRemote = process.env.HANZO_DOCS_FETCH_REMOTE !== '0';
|
||||
const dryRun = process.env.HANZO_DOCS_DRY_RUN === '1';
|
||||
const concurrency = Math.max(1, Number(process.env.HANZO_DOCS_CONCURRENCY ?? '4'));
|
||||
const includePrivate =
|
||||
process.env.HANZO_DOCS_INCLUDE_PRIVATE === '1' || config.includePrivate === true;
|
||||
const prune = process.env.HANZO_DOCS_PRUNE !== '0';
|
||||
|
||||
const octokit = createOctokit();
|
||||
const projects: RepoRecord[] = [];
|
||||
|
||||
ensureDir(outputDir, dryRun);
|
||||
|
||||
for (const org of orgs) {
|
||||
const repos = await listOrgRepos(octokit, org);
|
||||
const tasks = repos
|
||||
.filter((repo) => !excludeRepos.has(repo.name))
|
||||
.filter((repo) => {
|
||||
const isPrivate = repo.private === true || repo.visibility === 'private' || repo.visibility === 'internal';
|
||||
return includePrivate || !isPrivate;
|
||||
})
|
||||
.map((repo) => () =>
|
||||
syncRepoDocs({
|
||||
org,
|
||||
repo,
|
||||
outputDir,
|
||||
localRoot,
|
||||
docsCandidates,
|
||||
fetchRemote,
|
||||
dryRun,
|
||||
}),
|
||||
);
|
||||
|
||||
const records = await runWithConcurrency(tasks, concurrency);
|
||||
projects.push(...records);
|
||||
}
|
||||
|
||||
const manifest = {
|
||||
generatedAt: new Date().toISOString(),
|
||||
orgs,
|
||||
projects: projects.sort((a, b) => a.slug.localeCompare(b.slug)),
|
||||
};
|
||||
|
||||
writeJson(manifestPath, manifest, dryRun);
|
||||
writeProjectIndexFiles(outputDir, orgs, projects, dryRun);
|
||||
if (prune) {
|
||||
pruneProjectOutput(outputDir, orgs, projects, dryRun);
|
||||
}
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
syncProjectDocs().catch((error) => {
|
||||
console.error('[sync-project-docs] Failed', error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
function loadConfig(): Config {
|
||||
const configPath = path.join(APP_ROOT, 'projects.config.json');
|
||||
if (!fs.existsSync(configPath)) {
|
||||
return { orgs: [] };
|
||||
}
|
||||
return JSON.parse(fs.readFileSync(configPath, 'utf8')) as Config;
|
||||
}
|
||||
|
||||
function resolveOrgs(config: Config): string[] {
|
||||
const envOrgs = process.env.HANZO_DOCS_ORGS;
|
||||
if (envOrgs) {
|
||||
return envOrgs
|
||||
.split(',')
|
||||
.map((org) => org.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
return (config.orgs ?? []).map((org) => org.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
function expandHome(input: string): string {
|
||||
if (input === '~') return os.homedir();
|
||||
if (input.startsWith('~/')) {
|
||||
return path.join(os.homedir(), input.slice(2));
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
function resolveRepoPath(target: string): string {
|
||||
if (path.isAbsolute(target)) return target;
|
||||
return path.join(REPO_ROOT, target);
|
||||
}
|
||||
|
||||
function ensureDir(dir: string, dryRun: boolean) {
|
||||
if (dryRun) return;
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
|
||||
function createOctokit() {
|
||||
const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN || process.env.GH_PAT;
|
||||
return new Octokit({
|
||||
auth: token || undefined,
|
||||
});
|
||||
}
|
||||
|
||||
async function listOrgRepos(octokit: Octokit, org: string) {
|
||||
const repos: Array<{
|
||||
name: string;
|
||||
description: string | null;
|
||||
archived: boolean;
|
||||
visibility?: string;
|
||||
private?: boolean;
|
||||
html_url: string;
|
||||
default_branch: string;
|
||||
}> = [];
|
||||
|
||||
let page = 1;
|
||||
while (true) {
|
||||
const response = await octokit.request('GET /orgs/{org}/repos', {
|
||||
org,
|
||||
per_page: 100,
|
||||
page,
|
||||
type: 'all',
|
||||
sort: 'full_name',
|
||||
direction: 'asc',
|
||||
headers: {
|
||||
accept: 'application/vnd.github+json',
|
||||
'x-github-api-version': '2022-11-28',
|
||||
},
|
||||
});
|
||||
|
||||
const data = response.data;
|
||||
if (!data.length) break;
|
||||
|
||||
for (const repo of data) {
|
||||
repos.push({
|
||||
name: repo.name,
|
||||
description: repo.description,
|
||||
archived: repo.archived ?? false,
|
||||
visibility: (repo as { visibility?: string }).visibility,
|
||||
private: repo.private ?? false,
|
||||
html_url: repo.html_url ?? '',
|
||||
default_branch: repo.default_branch ?? 'main',
|
||||
});
|
||||
}
|
||||
|
||||
if (data.length < 100) break;
|
||||
page += 1;
|
||||
}
|
||||
|
||||
return repos;
|
||||
}
|
||||
|
||||
async function syncRepoDocs({
|
||||
org,
|
||||
repo,
|
||||
outputDir,
|
||||
localRoot,
|
||||
docsCandidates,
|
||||
fetchRemote,
|
||||
dryRun,
|
||||
}: {
|
||||
org: string;
|
||||
repo: {
|
||||
name: string;
|
||||
description: string | null;
|
||||
archived: boolean;
|
||||
visibility?: string;
|
||||
private?: boolean;
|
||||
html_url: string;
|
||||
default_branch: string;
|
||||
};
|
||||
outputDir: string;
|
||||
localRoot: string;
|
||||
docsCandidates: string[];
|
||||
fetchRemote: boolean;
|
||||
dryRun: boolean;
|
||||
}): Promise<RepoRecord> {
|
||||
const slug = repo.name;
|
||||
const route = `/docs/projects/${org}/${slug}`;
|
||||
const outputRepoDir = path.join(outputDir, org, slug);
|
||||
|
||||
let docsPath: string | null = null;
|
||||
const localRepoPath = path.join(localRoot, repo.name);
|
||||
|
||||
if (fs.existsSync(localRepoPath)) {
|
||||
docsPath = findDocsPath(localRepoPath, docsCandidates);
|
||||
if (docsPath) {
|
||||
copyDocs({
|
||||
sourceDir: docsPath,
|
||||
destDir: outputRepoDir,
|
||||
dryRun,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!docsPath && fetchRemote) {
|
||||
docsPath = await fetchDocsFromRemote({
|
||||
org,
|
||||
repo,
|
||||
docsCandidates,
|
||||
destDir: outputRepoDir,
|
||||
dryRun,
|
||||
});
|
||||
}
|
||||
|
||||
if (!docsPath) {
|
||||
ensureDir(outputRepoDir, dryRun);
|
||||
writeFallbackDocs(outputRepoDir, org, repo, dryRun);
|
||||
} else {
|
||||
ensureBaseMeta(outputRepoDir, repo.name, repo.description, dryRun);
|
||||
}
|
||||
|
||||
return {
|
||||
org,
|
||||
repo: repo.name,
|
||||
slug,
|
||||
name: humanize(repo.name),
|
||||
description: repo.description,
|
||||
archived: repo.archived,
|
||||
repoUrl: repo.html_url,
|
||||
route,
|
||||
};
|
||||
}
|
||||
|
||||
function findDocsPath(repoPath: string, candidates: string[]): string | null {
|
||||
for (const candidate of candidates) {
|
||||
const target = path.join(repoPath, candidate);
|
||||
if (fs.existsSync(target) && fs.statSync(target).isDirectory()) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
const overridePath = path.join(repoPath, 'hanzo.docs.json');
|
||||
if (fs.existsSync(overridePath)) {
|
||||
try {
|
||||
const override = JSON.parse(fs.readFileSync(overridePath, 'utf8')) as { docsPath?: string };
|
||||
if (override.docsPath) {
|
||||
const candidate = path.join(repoPath, override.docsPath);
|
||||
if (fs.existsSync(candidate) && fs.statSync(candidate).isDirectory()) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function copyDocs({ sourceDir, destDir, dryRun }: { sourceDir: string; destDir: string; dryRun: boolean }) {
|
||||
if (dryRun) return;
|
||||
fs.rmSync(destDir, { recursive: true, force: true });
|
||||
fs.mkdirSync(destDir, { recursive: true });
|
||||
fs.cpSync(sourceDir, destDir, {
|
||||
recursive: true,
|
||||
filter: (filePath) => {
|
||||
const base = path.basename(filePath);
|
||||
if (base === 'node_modules' || base === '.git' || base === '.next') return false;
|
||||
if (base === 'dist' || base === 'build' || base === 'out') return false;
|
||||
return true;
|
||||
},
|
||||
});
|
||||
ensureFrontmatter(destDir);
|
||||
}
|
||||
|
||||
function ensureFrontmatter(dir: string) {
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
ensureFrontmatter(fullPath);
|
||||
} else if (/\.(md|mdx)$/.test(entry.name)) {
|
||||
const content = fs.readFileSync(fullPath, 'utf8');
|
||||
if (!content.startsWith('---')) {
|
||||
const title = path.basename(entry.name, path.extname(entry.name))
|
||||
.replace(/[-_]+/g, ' ')
|
||||
.replace(/\b\w/g, (c) => c.toUpperCase());
|
||||
fs.writeFileSync(fullPath, `---\ntitle: ${escapeYaml(title)}\n---\n\n${content}`, 'utf8');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchDocsFromRemote({
|
||||
org,
|
||||
repo,
|
||||
docsCandidates,
|
||||
destDir,
|
||||
dryRun,
|
||||
}: {
|
||||
org: string;
|
||||
repo: {
|
||||
name: string;
|
||||
default_branch: string;
|
||||
};
|
||||
docsCandidates: string[];
|
||||
destDir: string;
|
||||
dryRun: boolean;
|
||||
}): Promise<string | null> {
|
||||
if (dryRun) return null;
|
||||
|
||||
const tarballUrl = `https://codeload.github.com/${org}/${repo.name}/tar.gz/${repo.default_branch}`;
|
||||
|
||||
const headers: Record<string, string> = {};
|
||||
const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN || process.env.GH_PAT;
|
||||
if (token) headers.Authorization = `token ${token}`;
|
||||
|
||||
for (let attempt = 1; attempt <= 2; attempt += 1) {
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), `hanzo-docs-${repo.name}-`));
|
||||
const archivePath = path.join(tmpDir, 'repo.tgz');
|
||||
|
||||
try {
|
||||
const response = await fetch(tarballUrl, { headers });
|
||||
if (!response.ok) {
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
return null;
|
||||
}
|
||||
|
||||
const buffer = Buffer.from(await response.arrayBuffer());
|
||||
fs.writeFileSync(archivePath, buffer);
|
||||
execFileSync('tar', ['-xzf', archivePath, '-C', tmpDir]);
|
||||
|
||||
const extractedRoot = fs
|
||||
.readdirSync(tmpDir)
|
||||
.find((entry) => entry.startsWith(`${repo.name}-`));
|
||||
|
||||
if (!extractedRoot) {
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
return null;
|
||||
}
|
||||
|
||||
const repoRoot = path.join(tmpDir, extractedRoot);
|
||||
const docsPath = findDocsPath(repoRoot, docsCandidates);
|
||||
|
||||
if (docsPath) {
|
||||
copyDocs({ sourceDir: docsPath, destDir, dryRun: false });
|
||||
}
|
||||
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
return docsPath;
|
||||
} catch (error) {
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
if (attempt === 2) {
|
||||
console.warn(`[sync-project-docs] Remote fetch failed for ${org}/${repo.name}.`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function writeFallbackDocs(destDir: string, org: string, repo: { name: string; description: string | null; html_url: string }, dryRun: boolean) {
|
||||
const title = humanize(repo.name);
|
||||
const description = repo.description ?? `Documentation for ${title}.`;
|
||||
const content = `---\ntitle: ${escapeYaml(title)}\ndescription: ${escapeYaml(description)}\n---\n\n# ${title}\n\nDocs are not available yet for this project.\n\n- Repository: ${repo.html_url}\n- Org: ${org}\n\nIf this repo has docs in a non-standard location, add a \`hanzo.docs.json\` file with \`docsPath\` in the repo root.`;
|
||||
|
||||
if (dryRun) return;
|
||||
fs.mkdirSync(destDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(destDir, 'index.mdx'), content, 'utf8');
|
||||
fs.writeFileSync(
|
||||
path.join(destDir, 'meta.json'),
|
||||
JSON.stringify({ title, description, pages: ['index'] }, null, 2),
|
||||
'utf8',
|
||||
);
|
||||
}
|
||||
|
||||
function ensureBaseMeta(destDir: string, repoName: string, description: string | null, dryRun: boolean) {
|
||||
if (dryRun) return;
|
||||
const metaPath = path.join(destDir, 'meta.json');
|
||||
if (!fs.existsSync(metaPath)) {
|
||||
const title = humanize(repoName);
|
||||
fs.writeFileSync(
|
||||
metaPath,
|
||||
JSON.stringify({ title, description: description ?? undefined, pages: ['index'] }, null, 2),
|
||||
'utf8',
|
||||
);
|
||||
}
|
||||
const indexPath = path.join(destDir, 'index.mdx');
|
||||
if (!fs.existsSync(indexPath)) {
|
||||
const title = humanize(repoName);
|
||||
const body = `---\ntitle: ${escapeYaml(title)}\ndescription: ${escapeYaml(description ?? `Documentation for ${title}.`)}\n---\n\n# ${title}\n\nDocumentation imported from repository content.`;
|
||||
fs.writeFileSync(indexPath, body, 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
function writeProjectIndexFiles(outputDir: string, orgs: string[], projects: RepoRecord[], dryRun: boolean) {
|
||||
const projectsRoot = outputDir;
|
||||
const rootMeta = {
|
||||
title: 'Projects',
|
||||
description: 'Documentation for all Hanzo projects.',
|
||||
icon: 'FolderGit2',
|
||||
root: true,
|
||||
pages: ['index', ...orgs],
|
||||
};
|
||||
|
||||
if (!dryRun) {
|
||||
fs.mkdirSync(projectsRoot, { recursive: true });
|
||||
fs.writeFileSync(path.join(projectsRoot, 'meta.json'), JSON.stringify(rootMeta, null, 2), 'utf8');
|
||||
fs.writeFileSync(path.join(projectsRoot, 'index.mdx'), buildRootIndex(), 'utf8');
|
||||
}
|
||||
|
||||
for (const org of orgs) {
|
||||
const orgProjects = projects
|
||||
.filter((project) => project.org === org)
|
||||
.sort((a, b) => a.slug.localeCompare(b.slug));
|
||||
|
||||
const orgDir = path.join(projectsRoot, org);
|
||||
const orgMeta = {
|
||||
title: org,
|
||||
description: `Projects in the ${org} organization.`,
|
||||
pages: ['index', ...orgProjects.map((project) => project.slug)],
|
||||
};
|
||||
|
||||
if (!dryRun) {
|
||||
fs.mkdirSync(orgDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(orgDir, 'meta.json'), JSON.stringify(orgMeta, null, 2), 'utf8');
|
||||
fs.writeFileSync(path.join(orgDir, 'index.mdx'), buildOrgIndex(org, orgProjects), 'utf8');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pruneProjectOutput(outputDir: string, orgs: string[], projects: RepoRecord[], dryRun: boolean) {
|
||||
const allowed = new Set(projects.map((project) => `${project.org}/${project.slug}`));
|
||||
|
||||
for (const entry of fs.readdirSync(outputDir, { withFileTypes: true })) {
|
||||
if (!entry.isDirectory()) continue;
|
||||
const org = entry.name;
|
||||
const orgPath = path.join(outputDir, org);
|
||||
|
||||
if (!orgs.includes(org)) {
|
||||
if (!dryRun) fs.rmSync(orgPath, { recursive: true, force: true });
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const repoEntry of fs.readdirSync(orgPath, { withFileTypes: true })) {
|
||||
if (!repoEntry.isDirectory()) continue;
|
||||
const key = `${org}/${repoEntry.name}`;
|
||||
if (!allowed.has(key)) {
|
||||
if (!dryRun) fs.rmSync(path.join(orgPath, repoEntry.name), { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function runWithConcurrency<T>(tasks: Array<() => Promise<T>>, limit: number): Promise<T[]> {
|
||||
const results: T[] = [];
|
||||
let index = 0;
|
||||
|
||||
const runners = Array.from({ length: Math.min(limit, tasks.length) }).map(async () => {
|
||||
while (index < tasks.length) {
|
||||
const current = index;
|
||||
index += 1;
|
||||
results[current] = await tasks[current]();
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(runners);
|
||||
return results;
|
||||
}
|
||||
|
||||
function buildRootIndex() {
|
||||
return `---\ntitle: Projects\ndescription: Aggregated documentation across Hanzo organizations.\n---\n\n# Projects\n\nThis hub aggregates HanzoAI projects by default. Other Hanzo orgs can maintain their own\nindependent docs deployments.\n\nUse the project switcher to jump directly to a repo.`;
|
||||
}
|
||||
|
||||
function buildOrgIndex(org: string, projects: RepoRecord[]) {
|
||||
const lines = projects
|
||||
.map((project) => `- [${project.name}](${project.route})${project.archived ? ' (archived)' : ''}`)
|
||||
.join('\n');
|
||||
|
||||
return `---\ntitle: ${escapeYaml(org)}\ndescription: Projects in the ${escapeYaml(org)} organization.\n---\n\n# ${org}\n\n${lines || 'No projects found.'}`;
|
||||
}
|
||||
|
||||
function writeJson(filePath: string, data: unknown, dryRun: boolean) {
|
||||
if (dryRun) return;
|
||||
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
|
||||
}
|
||||
|
||||
function humanize(input: string) {
|
||||
return input
|
||||
.replace(/[-_]+/g, ' ')
|
||||
.replace(/\b\w/g, (value) => value.toUpperCase());
|
||||
}
|
||||
|
||||
function escapeYaml(input: string) {
|
||||
return input.replace(/:/g, '\\:');
|
||||
}
|
||||
Reference in New Issue
Block a user