openhanako-personal-ai-agent
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOpenHanako Personal AI Agent
OpenHanako 个人AI Agent
Skill by ara.so — Daily 2026 Skills collection.
OpenHanako is a desktop AI agent platform built on Electron that gives each agent persistent memory, a distinct personality, and the ability to autonomously operate your computer — read/write files, run terminal commands, browse the web, execute JavaScript, and manage schedules. Multiple agents can collaborate via channel group chats or task delegation.
由ara.so开发的Skill — 2026每日技能合集。
OpenHanako是一个基于Electron构建的桌面AI Agent平台,可为每个Agent提供持久记忆、独特个性,以及自主操作电脑的能力——包括读写文件、运行终端命令、浏览网页、执行JavaScript、管理日程等。多个Agent可通过频道群聊或任务委派进行协作。
Installation
安装
Download & Run
下载并运行
bash
undefinedbash
undefinedmacOS Apple Silicon — download from releases page
macOS Apple Silicon — 从发布页面下载
Mount the .dmg and drag to Applications
挂载.dmg文件并拖拽至应用程序文件夹
First launch — bypass Gatekeeper (one-time):
首次启动 — 绕过Gatekeeper(仅需一次):
Right-click app → Open → Open
右键点击应用 → 打开 → 打开
```powershell
```powershellWindows — run the .exe installer from releases
Windows — 从发布页面运行.exe安装程序
SmartScreen warning: click "More info" → "Run anyway"
SmartScreen警告:点击“更多信息” → “仍要运行”
undefinedundefinedBuild from Source
从源码构建
bash
git clone https://github.com/liliMozi/openhanako.git
cd openhanako
npm installbash
git clone https://github.com/liliMozi/openhanako.git
cd openhanako
npm installDevelopment mode
开发模式
npm run dev
npm run dev
Build for production
生产环境构建
npm run build
npm run build
Run tests
运行测试
npm test
---npm test
---First-Run Onboarding
首次启动引导
On first launch, the wizard asks for:
- Language — UI language preference
- Your name — used by agents when addressing you
- Model provider — any OpenAI-compatible endpoint
- Three models:
- — main conversation (e.g.
chat model,gpt-4o)deepseek-chat - — lightweight tasks, summarization (e.g.
utility model)gpt-4o-mini - — memory compilation, deep analysis (e.g.
utility large model)gpt-4o
首次启动时,向导会要求您设置:
- 语言 — UI语言偏好
- 您的姓名 — Agent与您交流时会使用该名称
- 模型提供商 — 任何兼容OpenAI的端点
- 三个模型:
- — 主对话模型(例如
chat model、gpt-4o)deepseek-chat - — 轻量任务、总结模型(例如
utility model)gpt-4o-mini - — 记忆编译、深度分析模型(例如
utility large model)gpt-4o
Provider Configuration Examples
提供商配置示例
json
// OpenAI
{
"baseURL": "https://api.openai.com/v1",
"apiKey": "process.env.OPENAI_API_KEY"
}
// DeepSeek
{
"baseURL": "https://api.deepseek.com/v1",
"apiKey": "process.env.DEEPSEEK_API_KEY"
}
// Local Ollama
{
"baseURL": "http://localhost:11434/v1",
"apiKey": "ollama"
}
// Qwen (Alibaba Cloud)
{
"baseURL": "https://dashscope.aliyuncs.com/compatible-mode/v1",
"apiKey": "process.env.DASHSCOPE_API_KEY"
}json
// OpenAI
{
"baseURL": "https://api.openai.com/v1",
"apiKey": "process.env.OPENAI_API_KEY"
}
// DeepSeek
{
"baseURL": "https://api.deepseek.com/v1",
"apiKey": "process.env.DEEPSEEK_API_KEY"
}
// 本地Ollama
{
"baseURL": "http://localhost:11434/v1",
"apiKey": "ollama"
}
// Qwen(阿里云)
{
"baseURL": "https://dashscope.aliyuncs.com/compatible-mode/v1",
"apiKey": "process.env.DASHSCOPE_API_KEY"
}Project Architecture
项目架构
openhanako/
├── core/ # Engine orchestration + Managers (Agent, Session, Model, Preferences, Skill)
├── lib/ # Core libraries
│ ├── memory/ # Custom memory system (recency decay)
│ ├── tools/ # Built-in tools (files, terminal, browser, screenshot, canvas)
│ ├── sandbox/ # PathGuard + OS-level isolation (Seatbelt/Bubblewrap)
│ └── bridge/ # Multi-platform adapters (Telegram, Feishu, QQ)
├── server/ # Fastify 5 HTTP + WebSocket server
├── hub/ # Scheduler, ChannelRouter, EventBus
├── desktop/ # Electron 38 main process + React 19 frontend
├── tests/ # Vitest test suite
└── skills2set/ # Built-in skill definitionsopenhanako/
├── core/ # 引擎编排 + 管理器(Agent、Session、Model、Preferences、Skill)
├── lib/ # 核心库
│ ├── memory/ # 自定义记忆系统(近因衰减)
│ ├── tools/ # 内置工具(文件、终端、浏览器、截图、画布)
│ ├── sandbox/ # PathGuard + 系统级隔离(Seatbelt/Bubblewrap)
│ └── bridge/ # 多平台适配器(Telegram、飞书、QQ)
├── server/ # Fastify 5 HTTP + WebSocket服务器
├── hub/ # 调度器、ChannelRouter、EventBus
├── desktop/ # Electron 38主进程 + React 19前端
├── tests/ # Vitest测试套件
└── skills2set/ # 内置Skill定义Key Managers (via unified engine facade)
核心管理器(通过统一引擎门面)
| Manager | Responsibility |
|---|---|
| Create, load, delete agents |
| Conversation sessions per agent |
| Route requests to configured providers |
| User/global settings |
| Install, enable, disable, sandbox skills |
| 管理器 | 职责 |
|---|---|
| 创建、加载、删除Agent |
| 每个Agent的对话会话管理 |
| 将请求路由至已配置的提供商 |
| 用户/全局设置管理 |
| 安装、启用、禁用、沙箱化Skill |
Agent Configuration
Agent配置
Each agent is a self-contained folder you can back up:
~/.openhanako/agents/<agent-id>/
├── personality.md # Personality template (free-form prose or structured)
├── memory/
│ ├── working.db # Recent events (SQLite WAL)
│ └── compiled.md # Long-term compiled memory
├── desk/ # Agent's file workspace
│ └── notes/ # Jian notes
└── skills/ # Agent-local installed skills每个Agent是一个独立的文件夹,您可以对其进行备份:
~/.openhanako/agents/<agent-id>/
├── personality.md # 个性模板(自由格式文本或结构化内容)
├── memory/
│ ├── working.db # 近期事件(SQLite WAL)
│ └── compiled.md # 长期编译记忆
├── desk/ # Agent的文件工作区
│ └── notes/ # 简记
└── skills/ # Agent本地安装的SkillPersonality Template Example
个性模板示例
markdown
undefinedmarkdown
undefinedHanako
Hanako
You are Hanako, a calm and thoughtful assistant who prefers directness over verbosity.
You remember past conversations and refer to them naturally.
You ask clarifying questions before starting large tasks.
When writing code, you always add brief inline comments.
您是Hanako,一位冷静、体贴的助手,相比冗长的表述更倾向于直接沟通。
您会记住过往对话,并自然地在交流中提及。
在开始大型任务前,您会先提出澄清问题。
编写代码时,您总会添加简短的行内注释。
Tone
语气
- Warm but professional
- Uses occasional dry humor
- Never uses hollow affirmations ("Great question!")
- 温暖但专业
- 偶尔使用冷幽默
- 从不使用空洞的肯定语(例如“好问题!”)
Constraints
约束
- Always confirm before deleting files
- Summarize long terminal output rather than dumping it raw
---- 删除文件前始终确认
- 对冗长的终端输出进行总结,而非直接完整输出
---Skills System
Skill系统
Skills extend agent capabilities. They live in (built-in) or are installed per-agent.
skills2set/Skill可扩展Agent的能力。它们位于(内置)或按Agent单独安装。
skills2set/Install a Skill from GitHub
从GitHub安装Skill
javascript
// Via the Skills UI in the app, or programmatically:
const { skillManager } = engine;
await skillManager.installFromGitHub({
repo: 'some-user/hanako-skill-weather',
agentId: 'agent-abc123',
safetyReview: true // strict review enabled by default
});javascript
// 通过应用内的Skill UI,或编程方式:
const { skillManager } = engine;
await skillManager.installFromGitHub({
repo: 'some-user/hanako-skill-weather',
agentId: 'agent-abc123',
safetyReview: true // 默认启用严格审核
});Skill Definition Format (SKILL.md → skills2set)
Skill定义格式(SKILL.md → skills2set)
markdown
---
name: web-scraper
version: 1.0.0
description: Scrape structured data from web pages
tools:
- browser
- javascript
permissions:
- network
---markdown
---
name: web-scraper
version: 1.0.0
description: 从网页提取结构化数据
tools:
- browser
- javascript
permissions:
- network
---Instructions for Agent
Agent使用说明
When asked to scrape a page:
- Use the tool to navigate to the URL
browser - Use to extract structured data
executeJavaScript - Save results to the desk as JSON
undefined当需要抓取页面时:
- 使用工具导航至目标URL
browser - 使用提取结构化数据
executeJavaScript - 将结果以JSON格式保存至工作区
undefinedWriting a Custom Skill (JavaScript)
编写自定义Skill(JavaScript)
javascript
// skills/my-skill/index.js
export default {
name: 'my-skill',
version: '1.0.0',
description: 'Does something useful',
// Tools this skill adds to the agent
tools: [
{
name: 'fetch_weather',
description: 'Fetch current weather for a city',
parameters: {
type: 'object',
properties: {
city: { type: 'string', description: 'City name' }
},
required: ['city']
},
async execute({ city }) {
const res = await fetch(
`https://wttr.in/${encodeURIComponent(city)}?format=j1`
);
const data = await res.json();
return {
temp_c: data.current_condition[0].temp_C,
description: data.current_condition[0].weatherDesc[0].value
};
}
}
]
};javascript
// skills/my-skill/index.js
export default {
name: 'my-skill',
version: '1.0.0',
description: 实现实用功能,
// 该Skill为Agent添加的工具
tools: [
{
name: 'fetch_weather',
description: 获取指定城市的当前天气,
parameters: {
type: 'object',
properties: {
city: { type: 'string', description: 城市名称 }
},
required: ['city']
},
async execute({ city }) {
const res = await fetch(
`https://wttr.in/${encodeURIComponent(city)}?format=j1`
);
const data = await res.json();
return {
temp_c: data.current_condition[0].temp_C,
description: data.current_condition[0].weatherDesc[0].value
};
}
}
]
};Memory System
记忆系统
OpenHanako uses a recency-decay memory model: recent events stay sharp, older ones fade.
javascript
// Accessing memory programmatically (core/lib/memory)
import { MemoryManager } from './lib/memory/index.js';
const memory = new MemoryManager({ agentId: 'agent-abc123' });
// Store a memory event
await memory.store({
type: 'conversation',
content: 'User prefers dark mode and terse responses',
importance: 0.8 // 0.0–1.0; higher = decays slower
});
// Retrieve relevant memories
const relevant = await memory.query({
query: 'user preferences',
limit: 10,
minRelevance: 0.5
});
// Trigger manual compilation (normally runs automatically)
await memory.compile();OpenHanako采用近因衰减记忆模型:近期事件记忆清晰,远期事件记忆逐渐淡化。
javascript
// 编程方式访问记忆(core/lib/memory)
import { MemoryManager } from './lib/memory/index.js';
const memory = new MemoryManager({ agentId: 'agent-abc123' });
// 存储记忆事件
await memory.store({
type: 'conversation',
content: '用户偏好深色模式和简洁回复',
importance: 0.8 // 0.0–1.0;值越高,衰减越慢
});
// 检索相关记忆
const relevant = await memory.query({
query: '用户偏好',
limit: 10,
minRelevance: 0.5
});
// 触发手动编译(通常自动运行)
await memory.compile();Memory Tiers
记忆层级
| Tier | Storage | Decay |
|---|---|---|
| Working memory | | Fast — recent N turns |
| Compiled memory | | Slow — summarized by utility-large model |
| Desk notes (Jian) | Files on desk | Manual / no decay |
| 层级 | 存储方式 | 衰减速度 |
|---|---|---|
| 工作记忆 | | 快 — 仅保留最近N轮对话 |
| 编译记忆 | | 慢 — 由utility-large模型总结 |
| 工作区笔记(简记) | 工作区文件 | 手动 / 无衰减 |
Built-in Tools
内置工具
Tools available to agents out of the box:
javascript
// File operations
{ tool: 'read_file', args: { path: '/Users/me/notes.txt' } }
{ tool: 'write_file', args: { path: '/Users/me/out.txt', content: '...' } }
// Terminal
{ tool: 'run_command', args: { command: 'ls -la', cwd: '/Users/me' } }
// Browser & web
{ tool: 'browse', args: { url: 'https://example.com' } }
{ tool: 'web_search', args: { query: 'OpenHanako latest release' } }
// Screen
{ tool: 'screenshot', args: {} }
// Canvas
{ tool: 'draw', args: { instructions: '...' } }
// Code execution
{ tool: 'execute_js', args: { code: 'return 2 + 2' } }Agent默认可用的工具:
javascript
// 文件操作
{ tool: 'read_file', args: { path: '/Users/me/notes.txt' } }
{ tool: 'write_file', args: { path: '/Users/me/out.txt', content: '...' } }
// 终端
{ tool: 'run_command', args: { command: 'ls -la', cwd: '/Users/me' } }
// 浏览器与网页
{ tool: 'browse', args: { url: 'https://example.com' } }
{ tool: 'web_search', args: { query: 'OpenHanako latest release' } }
// 屏幕
{ tool: 'screenshot', args: {} }
// 画布
{ tool: 'draw', args: { instructions: '...' } }
// 代码执行
{ tool: 'execute_js', args: { code: 'return 2 + 2' } }Sandbox Access Tiers (PathGuard)
沙箱访问层级(PathGuard)
Tier 0 — Denied: System paths (/System, /usr, registry hives)
Tier 1 — Read-only: Home directory files outside agent desk
Tier 2 — Read-write: Agent desk folder only
Tier 3 — Full: Explicitly granted paths (user confirms)OS-level sandbox: macOS Seatbelt / Linux Bubblewrap wraps the skill process.
层级0 — 禁止访问: 系统路径(/System、/usr、注册表项)
层级1 — 只读: 用户目录中Agent工作区外的文件
层级2 — 读写: 仅Agent工作区文件夹
层级3 — 完全访问: 明确授权的路径(需用户确认)系统级沙箱:macOS Seatbelt / Linux Bubblewrap 包裹Skill进程。
Multi-Agent Setup
多Agent设置
javascript
// core/AgentManager usage example
import { createEngine } from './core/engine.js';
const engine = await createEngine();
// Create a second agent
const researchAgent = await engine.agentManager.create({
name: 'Researcher',
personalityTemplate: 'researcher.md',
models: {
chat: 'deepseek-chat',
utility: 'gpt-4o-mini',
utilityLarge: 'gpt-4o'
}
});
// Delegate a task from one agent to another via channel
await engine.hub.channelRouter.delegate({
fromAgent: 'agent-abc123',
toAgent: researchAgent.id,
task: 'Find the top 5 papers on mixture-of-experts published in 2025',
returnTo: 'agent-abc123' // result routed back automatically
});javascript
// core/AgentManager使用示例
import { createEngine } from './core/engine.js';
const engine = await createEngine();
// 创建第二个Agent
const researchAgent = await engine.agentManager.create({
name: 'Researcher',
personalityTemplate: 'researcher.md',
models: {
chat: 'deepseek-chat',
utility: 'gpt-4o-mini',
utilityLarge: 'gpt-4o'
}
});
// 通过频道将任务从一个Agent委派给另一个
await engine.hub.channelRouter.delegate({
fromAgent: 'agent-abc123',
toAgent: researchAgent.id,
task: '查找2025年发表的前5篇混合专家模型相关论文',
returnTo: 'agent-abc123' // 结果会自动路由回原Agent
});Scheduled Tasks (Cron & Heartbeat)
定时任务(Cron与心跳)
javascript
// hub/scheduler usage
import { Scheduler } from './hub/scheduler.js';
const scheduler = new Scheduler({ agentId: 'agent-abc123' });
// Run a task every day at 9am
scheduler.cron('daily-briefing', '0 9 * * *', async () => {
await agent.run('Summarize my desk notes from yesterday and post to #briefing channel');
});
// Heartbeat — check desk for new files every 5 minutes
scheduler.heartbeat('desk-watch', 300_000, async () => {
const changed = await agent.desk.checkChanges();
if (changed.length > 0) {
await agent.run(`New files on desk: ${changed.join(', ')} — summarize and notify me`);
}
});
scheduler.start();javascript
// hub/scheduler使用示例
import { Scheduler } from './hub/scheduler.js';
const scheduler = new Scheduler({ agentId: 'agent-abc123' });
// 每天上午9点执行任务
scheduler.cron('daily-briefing', '0 9 * * *', async () => {
await agent.run('总结我昨天的工作区笔记并发布到#briefing频道');
});
// 心跳任务 — 每5分钟检查工作区是否有新文件
scheduler.heartbeat('desk-watch', 300_000, async () => {
const changed = await agent.desk.checkChanges();
if (changed.length > 0) {
await agent.run(`工作区新增文件:${changed.join(', ')} — 请总结并通知我`);
}
});
scheduler.start();Multi-Platform Bridge
多平台桥接
Connect one agent to Telegram, Feishu, and QQ simultaneously:
javascript
// lib/bridge configuration
const bridgeConfig = {
telegram: {
enabled: true,
token: process.env.TELEGRAM_BOT_TOKEN,
allowedUsers: [process.env.TELEGRAM_ALLOWED_USER_ID]
},
feishu: {
enabled: true,
appId: process.env.FEISHU_APP_ID,
appSecret: process.env.FEISHU_APP_SECRET
},
qq: {
enabled: false
}
};
await engine.agentManager.setBridges('agent-abc123', bridgeConfig);同时将一个Agent连接至Telegram、飞书和QQ:
javascript
// lib/bridge配置
const bridgeConfig = {
telegram: {
enabled: true,
token: process.env.TELEGRAM_BOT_TOKEN,
allowedUsers: [process.env.TELEGRAM_ALLOWED_USER_ID]
},
feishu: {
enabled: true,
appId: process.env.FEISHU_APP_ID,
appSecret: process.env.FEISHU_APP_SECRET
},
qq: {
enabled: false
}
};
await engine.agentManager.setBridges('agent-abc123', bridgeConfig);Server API (Fastify + WebSocket)
服务器API(Fastify + WebSocket)
The embedded Fastify server runs locally and the Electron main process communicates via stdio bridge.
javascript
// WebSocket — real-time chat stream
const ws = new WebSocket('ws://localhost:PORT/ws/agent-abc123');
ws.send(JSON.stringify({
type: 'chat',
content: 'Summarize my project folder'
}));
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
// msg.type: 'chunk' | 'tool_call' | 'tool_result' | 'done'
console.log(msg);
};
// HTTP — one-shot task
const res = await fetch('http://localhost:PORT/api/agent/agent-abc123/run', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ task: 'List all .md files on my desk' })
});
const result = await res.json();嵌入式Fastify服务器在本地运行,Electron主进程通过stdio桥接与之通信。
javascript
// WebSocket — 实时聊天流
const ws = new WebSocket('ws://localhost:PORT/ws/agent-abc123');
ws.send(JSON.stringify({
type: 'chat',
content: '总结我的项目文件夹'
}));
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
// msg.type: 'chunk' | 'tool_call' | 'tool_result' | 'done'
console.log(msg);
};
// HTTP — 一次性任务
const res = await fetch('http://localhost:PORT/api/agent/agent-abc123/run', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ task: '列出我工作区中所有.md文件' })
});
const result = await res.json();Testing
测试
bash
undefinedbash
undefinedRun all tests
运行所有测试
npm test
npm test
Run a specific test file
运行指定测试文件
npx vitest run tests/memory.test.js
npx vitest run tests/memory.test.js
Watch mode
监听模式
npx vitest
```javascript
// tests/memory.test.js example pattern
import { describe, it, expect, beforeEach } from 'vitest';
import { MemoryManager } from '../lib/memory/index.js';
describe('MemoryManager', () => {
let memory;
beforeEach(async () => {
memory = new MemoryManager({ agentId: 'test-agent', inMemory: true });
await memory.init();
});
it('stores and retrieves a memory', async () => {
await memory.store({ type: 'fact', content: 'User likes dark mode', importance: 0.9 });
const results = await memory.query({ query: 'dark mode', limit: 5 });
expect(results[0].content).toContain('dark mode');
});
});npx vitest
```javascript
// tests/memory.test.js示例模式
import { describe, it, expect, beforeEach } from 'vitest';
import { MemoryManager } from '../lib/memory/index.js';
describe('MemoryManager', () => {
let memory;
beforeEach(async () => {
memory = new MemoryManager({ agentId: 'test-agent', inMemory: true });
await memory.init();
});
it('存储并检索记忆', async () => {
await memory.store({ type: 'fact', content: '用户喜欢深色模式', importance: 0.9 });
const results = await memory.query({ query: '深色模式', limit: 5 });
expect(results[0].content).toContain('深色模式');
});
});Troubleshooting
故障排查
App won't open on macOS
macOS上应用无法打开
bash
undefinedbash
undefinedRemove quarantine attribute if right-click → Open doesn't work
如果右键→打开无效,移除隔离属性
xattr -dr com.apple.quarantine /Applications/OpenHanako.app
undefinedxattr -dr com.apple.quarantine /Applications/OpenHanako.app
undefinedAgent not responding
Agent无响应
- Check that the API key env var is set and the base URL is reachable
- Open DevTools (/
Cmd+Option+I) → Console for errorsCtrl+Shift+I - Verify the model name matches exactly what your provider supports
- 检查API key环境变量是否已设置,以及base URL是否可访问
- 打开开发者工具(/
Cmd+Option+I)→ 控制台查看错误Ctrl+Shift+I - 确认模型名称与提供商支持的名称完全匹配
Memory compilation not triggering
记忆编译未触发
javascript
// Force a manual compile
await engine.agentManager.getAgent('agent-abc123').memory.compile({ force: true });javascript
// 强制手动编译
await engine.agentManager.getAgent('agent-abc123').memory.compile({ force: true });Skill installation blocked by safety review
Skill安装被安全审核阻止
javascript
// Temporarily disable safety review for trusted local skills only
await skillManager.installLocal({
path: './my-skill',
agentId: 'agent-abc123',
safetyReview: false // ⚠️ only for local dev, never for untrusted sources
});javascript
// 仅对可信本地Skill临时禁用安全审核
await skillManager.installLocal({
path: './my-skill',
agentId: 'agent-abc123',
safetyReview: false // ⚠️仅用于本地开发,切勿用于不可信来源
});Sandbox permission denied
沙箱权限被拒绝
- Check the PathGuard tier for the path being accessed
- Use the desktop UI: Agent Settings → Sandbox → Grant Path Access
- Or programmatically request elevation to Tier 3 (prompts user confirmation)
- 检查被访问路径的PathGuard层级
- 使用桌面UI:Agent设置 → 沙箱 → 授予路径访问权限
- 或通过编程方式请求提升至层级3(需用户确认)
Windows Defender false positive on built .exe
.exeWindows Defender对构建的.exe报误报
- The installer is unsigned; click More info → Run anyway in SmartScreen
- Add an exclusion in Windows Security if needed during development
- 安装程序未签名;在SmartScreen中点击更多信息→仍要运行
- 开发期间可在Windows安全中心添加排除项
Key Links
关键链接
- Releases: https://github.com/liliMozi/openhanako/releases
- Issues: https://github.com/liliMozi/openhanako/issues
- Homepage: https://openhanako.com
- Contributing: https://github.com/liliMozi/openhanako/blob/main/CONTRIBUTING.md
- Security Policy: https://github.com/liliMozi/openhanako/blob/main/SECURITY.md
- License: Apache 2.0