No description.

A local-first personal AI agent that runs on your own machine.
The shape of Claude Code, all-file storage (no DB · no account · no cloud), and a visual Workflow Studio.

Ginno turns the capabilities an AI agent should have into a complete desktop app, instead of scattering them across a terminal and a dozen browser tabs.
Full feature walkthrough:
docs/user-guide.md.
| Workflow Studio | Local knowledge base |
|---|---|
![]() | ![]() |
One design rule: your data should not leave your machine.
| Ginno | |
|---|---|
| Database | ❌ none — all state is JSON / JSONL / Markdown under ~/.ginno/ |
| Account | ❌ none — open it and go |
| Cloud sync | ❌ none — everything stays local |
| Portable | ✅ copy the folder to move it; readable, hand-editable, git-able |
You bring your own model key (OpenAI / Anthropic / DeepSeek, or any compatible endpoint). Ginno is just a client — it never takes custody of your key or your data.
Option A — download (macOS, Apple Silicon): grab the latest .dmg from Releases. It is not code-signed yet, so on first launch use right-click → Open to get past Gatekeeper.
Option B — build from source:
git clone https://github.com/robscc/ginno
cd ginno
pnpm install # web + desktop shell
cd packages/runtime && uv sync # Python runtime
cd ../..
pnpm dev # web + runtime + desktop shell, all at once
Requires: Node ≥ 20 · pnpm ≥ 9 · Python ≥ 3.11 (via uv) · Rust (Tauri).
Package a .app: make app → apps/desktop/target/release/bundle/dmg/Ginno_*.dmg (see docs/p3-packaging-notes.md).
| Layer | Choice |
|---|---|
| Shell | Tauri 2 (Rust) — process management + webview only |
| UI | Next.js 14 (static export) + React 18 + Tailwind |
| Runtime | Python + FastAPI + LangGraph (sidecar, bundled with PyInstaller) |
| Storage | plain files (no DB); optional LanceDB for semantic-search vectors |
Architecture and subsystem designs:
docs/architecture.md.
MIT © 2026 ChuanchuanSong
hooks/detached.mjs 13 lines1// A hook that returns BEFORE its detached async calls `$` — next-steps' shape.
2// The 30ms delay guarantees the hook settles first (the real mod's fork call
3// takes seconds: command.list + model.fork both land well after settle).
4export function register(on) {
5 on('turn.complete', async ($, e, next) => {
6 const result = await next(e)
7 setTimeout(() => {
8 void $.session.id().catch(() => {})
9 }, 30)
10 return result
11 })
12}
13