cabinet-ai-knowledge-base

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Cabinet AI Knowledge Base

Cabinet AI 知识库

Skill by ara.so — Daily 2026 Skills collection.
Cabinet is an AI-first startup OS and knowledge base where everything lives as markdown files on disk. No database, no vendor lock-in — self-hosted with AI agents that have memory, scheduled jobs, embedded HTML apps, git-backed history, and a full web terminal.

ara.so 提供的Skill — 2026年度每日Skill合集。
Cabinet是一款以AI为核心的创业公司操作系统和知识库,所有内容都以markdown文件形式存储在磁盘上。无需数据库,无供应商锁定——支持自托管,具备带记忆功能的AI Agent、定时任务、嵌入式HTML应用、Git支撑的版本历史,以及完整的网页终端。

Installation

安装

Quick Start (recommended)

快速开始(推荐)

bash
npx create-cabinet@latest
cd cabinet
npm run dev:all
Open http://localhost:3000 — the onboarding wizard builds your AI team in 5 questions.
bash
npx create-cabinet@latest
cd cabinet
npm run dev:all
打开 http://localhost:3000 —— 引导向导仅需5个问题即可完成你的AI团队配置。

Manual Clone

手动克隆

bash
git clone https://github.com/hilash/cabinet.git
cd cabinet
npm install
cp .env.example .env.local
npm run dev:all
bash
git clone https://github.com/hilash/cabinet.git
cd cabinet
npm install
cp .env.example .env.local
npm run dev:all

Prerequisites

前置要求

  • Node.js 20+
  • Claude Code CLI:
    npm install -g @anthropic-ai/claude-code
  • macOS or Linux (Windows via WSL)

  • Node.js 20+
  • Claude Code CLI:
    npm install -g @anthropic-ai/claude-code
  • macOS 或 Linux(Windows 需通过WSL运行)

Environment Configuration

环境配置

bash
undefined
bash
undefined

.env.local

.env.local

KB_PASSWORD=your_optional_password # Leave empty for no auth DOMAIN=localhost # Or your custom domain

---
KB_PASSWORD=your_optional_password # 不需要鉴权可留空 DOMAIN=localhost # 或你的自定义域名

---

Key Commands

常用命令

bash
npm run dev          # Next.js dev server on port 3000
npm run dev:daemon   # WebSocket + job scheduler on port 3001
npm run dev:all      # Both servers together (use this for development)
npm run build        # Production build
npm run start        # Production mode (both servers)

bash
npm run dev          # Next.js 开发服务器,运行在3000端口
npm run dev:daemon   # WebSocket + 任务调度器,运行在3001端口
npm run dev:all      # 同时启动两个服务(开发环境推荐使用)
npm run build        # 生产环境构建
npm run start        # 生产模式运行(同时启动两个服务)

Architecture

架构

cabinet/
  src/
    app/api/         → Next.js API routes
    components/      → React components (sidebar, editor, agents, jobs, terminal)
    stores/          → Zustand state management
    lib/             → Storage, markdown, git, agents, jobs
  server/
    cabinet-daemon.ts → WebSocket + job scheduler + agent executor
  data/
    .agents/.library/ → 20 pre-built agent templates
    getting-started/  → Default KB pages
Tech stack: Next.js 16, TypeScript, Tailwind CSS, shadcn/ui, Tiptap, Zustand, xterm.js, node-cron

cabinet/
  src/
    app/api/         → Next.js API 路由
    components/      → React 组件(侧边栏、编辑器、Agent、任务、终端)
    stores/          → Zustand 状态管理
    lib/             → 存储、markdown、git、Agent、任务相关逻辑
  server/
    cabinet-daemon.ts → WebSocket + 任务调度器 + Agent 执行器
  data/
    .agents/.library/ → 20个预置Agent模板
    getting-started/  → 默认知识库页面
技术栈: Next.js 16, TypeScript, Tailwind CSS, shadcn/ui, Tiptap, Zustand, xterm.js, node-cron

Project Structure (data directory)

项目结构(data目录)

Cabinet stores everything as markdown files under
data/
:
data/
  getting-started/
    index.md
  my-project/
    index.md
    research.md
    index.html        ← Embedded HTML app (auto-rendered as iframe)
  .agents/
    .library/
      ceo.md
      product-manager.md
      researcher.md
    active/
      my-ceo/
        index.md      ← Agent definition
        memory.md     ← Agent memory (auto-updated)

Cabinet将所有内容以markdown文件形式存储在
data/
目录下:
data/
  getting-started/
    index.md
  my-project/
    index.md
    research.md
    index.html        ← 嵌入式HTML应用(自动渲染为iframe)
  .agents/
    .library/
      ceo.md
      product-manager.md
      researcher.md
    active/
      my-ceo/
        index.md      ← Agent 定义
        memory.md     ← Agent 记忆(自动更新)

Agent Definition Format

Agent 定义格式

Agents are defined as markdown files with YAML frontmatter:
markdown
---
name: Research Scout
role: researcher
schedule: "0 */6 * * *"   # Cron: every 6 hours
skills:
  - web-search
  - summarization
  - reddit-scout
goals:
  - Monitor competitor activity
  - Surface trending topics in AI tooling
  - File weekly summary reports
---
Agent以附带YAML前置元数据的markdown文件定义:
markdown
---
name: Research Scout
role: researcher
schedule: "0 */6 * * *"   # Cron表达式:每6小时执行一次
skills:
  - web-search
  - summarization
  - reddit-scout
goals:
  - Monitor competitor activity
  - Surface trending topics in AI tooling
  - File weekly summary reports
---

Research Scout

Research Scout

You are a research agent for [Company Name]. Your job is to...
You are a research agent for [Company Name]. Your job is to...

Memory

Memory

<!-- Agent memory is auto-appended here by the daemon -->

---
<!-- Agent 记忆会由守护进程自动追加到此处 -->

---

Creating a Custom Agent

创建自定义Agent

Via the UI

通过UI界面

  1. Navigate to the Agents panel in the sidebar
  2. Click "New Agent" and select a template or start blank
  3. Fill in role, goals, and schedule
  4. Cabinet creates
    data/.agents/active/<agent-name>/index.md
  1. 导航到侧边栏的Agent面板
  2. 点击「新建Agent」,选择模板或从空白开始创建
  3. 填写角色、目标和执行 schedule
  4. Cabinet会自动创建
    data/.agents/active/<agent-name>/index.md
    文件

Programmatically

通过代码创建

typescript
// src/lib/agents.ts pattern — create an agent file directly
import fs from 'fs/promises'
import path from 'path'

const agentDir = path.join(process.cwd(), 'data', '.agents', 'active', 'my-agent')

await fs.mkdir(agentDir, { recursive: true })

await fs.writeFile(
  path.join(agentDir, 'index.md'),
  `---
name: My Custom Agent
role: analyst
schedule: "0 9 * * 1"
goals:
  - Analyze weekly metrics
  - Post summary to #reports channel
---
typescript
// src/lib/agents.ts 模式 —— 直接创建Agent文件
import fs from 'fs/promises'
import path from 'path'

const agentDir = path.join(process.cwd(), 'data', '.agents', 'active', 'my-agent')

await fs.mkdir(agentDir, { recursive: true })

await fs.writeFile(
  path.join(agentDir, 'index.md'),
  `---
name: My Custom Agent
role: analyst
schedule: "0 9 * * 1"
goals:
  - Analyze weekly metrics
  - Post summary to #reports channel
---

My Custom Agent

My Custom Agent

You are a data analyst agent. Every Monday at 9am you will... ` )

---
You are a data analyst agent. Every Monday at 9am you will... ` )

---

Scheduled Jobs (Cron)

定时任务(Cron)

Agents use standard cron syntax in their frontmatter
schedule
field:
yaml
undefined
Agent在前置元数据的
schedule
字段中使用标准Cron语法定义执行时间:
yaml
undefined

Common schedule patterns

常用schedule配置示例

schedule: "0 */6 * * *" # Every 6 hours schedule: "0 9 * * 1" # Every Monday at 9am schedule: "0 8 * * " # Every day at 8am schedule: "/30 * * * *" # Every 30 minutes schedule: "0 0 * * 0" # Weekly on Sunday midnight

The Cabinet daemon (`server/cabinet-daemon.ts`) reads agent files and registers jobs via `node-cron`. Jobs run agent prompts through Claude Code and write results back to the agent's memory file.

---
schedule: "0 */6 * * *" # 每6小时 schedule: "0 9 * * 1" # 每周一上午9点 schedule: "0 8 * * " # 每天上午8点 schedule: "/30 * * * *" # 每30分钟 schedule: "0 0 * * 0" # 每周日午夜

Cabinet守护进程(`server/cabinet-daemon.ts`)会读取Agent文件,并通过`node-cron`注册任务。任务会将Agent提示词传给Claude Code执行,并将结果写回Agent的记忆文件。

---

Embedded HTML Apps

嵌入式HTML应用

Drop an
index.html
in any folder under
data/
— Cabinet automatically renders it as an embedded iframe with a full-screen toggle:
data/
  my-dashboard/
    index.html    ← Cabinet renders this as an embedded app
    data.json
    style.css
Example
data/my-dashboard/index.html
:
html
<!DOCTYPE html>
<html>
<head>
  <title>Metrics Dashboard</title>
  <style>
    body { font-family: sans-serif; padding: 20px; background: #1a1a1a; color: #eee; }
    .metric { font-size: 2rem; font-weight: bold; color: #55c938; }
  </style>
</head>
<body>
  <h1>Weekly Metrics</h1>
  <div class="metric" id="count">Loading...</div>
  <script>
    fetch('./data.json')
      .then(r => r.json())
      .then(d => document.getElementById('count').textContent = d.value)
  </script>
</body>
</html>
No build step required. Version controlled via git automatically.

data/
下的任意文件夹中放入
index.html
文件,Cabinet会自动将其渲染为支持全屏切换的嵌入式iframe:
data/
  my-dashboard/
    index.html    ← Cabinet会将其渲染为嵌入式应用
    data.json
    style.css
示例
data/my-dashboard/index.html
html
<!DOCTYPE html>
<html>
<head>
  <title>Metrics Dashboard</title>
  <style>
    body { font-family: sans-serif; padding: 20px; background: #1a1a1a; color: #eee; }
    .metric { font-size: 2rem; font-weight: bold; color: #55c938; }
  </style>
</head>
<body>
  <h1>Weekly Metrics</h1>
  <div class="metric" id="count">Loading...</div>
  <script>
    fetch('./data.json')
      .then(r => r.json())
      .then(d => document.getElementById('count').textContent = d.value)
  </script>
</body>
</html>
无需构建步骤,自动通过Git进行版本控制。

Git-Backed History

Git支撑的版本历史

Every save auto-commits. Cabinet wraps git operations in
src/lib/git.ts
:
typescript
// Auto-commit on every page save (Cabinet handles this internally)
// To access history via the UI:
// 1. Open any page
// 2. Click the history icon in the toolbar
// 3. Browse diffs and restore any version

// To inspect from the shell:
cd data
git log --oneline
git diff HEAD~1 HEAD -- my-project/research.md
git checkout HEAD~5 -- my-project/research.md  # Restore older version

每次保存都会自动提交。Cabinet在
src/lib/git.ts
中封装了Git操作:
typescript
// 每次页面保存自动提交(Cabinet内部自动处理)
// 要通过UI访问历史版本:
// 1. 打开任意页面
// 2. 点击工具栏的历史图标
// 3. 浏览差异并恢复任意版本

// 要通过shell查看历史:
cd data
git log --oneline
git diff HEAD~1 HEAD -- my-project/research.md
git checkout HEAD~5 -- my-project/research.md  # 恢复旧版本

Markdown Page Format

Markdown页面格式

Cabinet pages are standard markdown files with optional frontmatter:
markdown
---
title: Competitor Analysis
tags: [research, competitors, q2-2026]
created: 2026-04-07
agent: research-scout
---
Cabinet页面是标准的markdown文件,支持可选的前置元数据:
markdown
---
title: Competitor Analysis
tags: [research, competitors, q2-2026]
created: 2026-04-07
agent: research-scout
---

Competitor Analysis

竞品分析

Summary

摘要

...
...

Last Updated by Agent

Agent最后更新

<!-- Agent appends updates here -->

---
<!-- Agent会自动将更新追加到此处 -->

---

API Routes

API路由

Cabinet exposes Next.js API routes under
src/app/api/
:
typescript
// Read a page
GET /api/pages?path=my-project/research

// Save a page
POST /api/pages
Body: { path: "my-project/research", content: "# Research\n..." }

// List directory
GET /api/files?dir=my-project

// Run an agent manually
POST /api/agents/run
Body: { agentId: "research-scout" }

// Get agent status
GET /api/agents/status?id=research-scout

// Search all pages
GET /api/search?q=competitor+analysis
Cabinet在
src/app/api/
下暴露了Next.js API路由:
typescript
// 读取页面
GET /api/pages?path=my-project/research

// 保存页面
POST /api/pages
Body: { path: "my-project/research", content: "# Research\n..." }

// 列出目录内容
GET /api/files?dir=my-project

// 手动运行Agent
POST /api/agents/run
Body: { agentId: "research-scout" }

// 获取Agent运行状态
GET /api/agents/status?id=research-scout

// 搜索所有页面
GET /api/search?q=competitor+analysis

Example: Calling the API from TypeScript

示例:从TypeScript调用API

typescript
// Read a knowledge base page
const response = await fetch('/api/pages?path=my-project/research')
const { content, path } = await response.json()

// Save a page
await fetch('/api/pages', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    path: 'my-project/research',
    content: '# Research\n\nUpdated content...'
  })
})

// Trigger an agent run
await fetch('/api/agents/run', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ agentId: 'research-scout' })
})

typescript
// 读取知识库页面
const response = await fetch('/api/pages?path=my-project/research')
const { content, path } = await response.json()

// 保存页面
await fetch('/api/pages', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    path: 'my-project/research',
    content: '# Research\n\nUpdated content...'
  })
})

// 触发Agent运行
await fetch('/api/agents/run', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ agentId: 'research-scout' })
})

Zustand State Management

Zustand状态管理

Cabinet uses Zustand stores in
src/stores/
. Key patterns:
typescript
// Access the page store in a component
import { usePageStore } from '@/stores/pageStore'

function MyComponent() {
  const { currentPage, savePage, pages } = usePageStore()

  const handleSave = async (content: string) => {
    await savePage({ path: currentPage.path, content })
  }

  return <div>{currentPage?.title}</div>
}

// Access agent store
import { useAgentStore } from '@/stores/agentStore'

function AgentPanel() {
  const { agents, runAgent, agentStatus } = useAgentStore()

  return (
    <ul>
      {agents.map(agent => (
        <li key={agent.id}>
          {agent.name}{agentStatus[agent.id]}
          <button onClick={() => runAgent(agent.id)}>Run</button>
        </li>
      ))}
    </ul>
  )
}

Cabinet在
src/stores/
目录下使用Zustand存储,核心用法:
typescript
// 在组件中访问页面存储
import { usePageStore } from '@/stores/pageStore'

function MyComponent() {
  const { currentPage, savePage, pages } = usePageStore()

  const handleSave = async (content: string) => {
    await savePage({ path: currentPage.path, content })
  }

  return <div>{currentPage?.title}</div>
}

// 访问Agent存储
import { useAgentStore } from '@/stores/agentStore'

function AgentPanel() {
  const { agents, runAgent, agentStatus } = useAgentStore()

  return (
    <ul>
      {agents.map(agent => (
        <li key={agent.id}>
          {agent.name}{agentStatus[agent.id]}
          <button onClick={() => runAgent(agent.id)}>运行</button>
        </li>
      ))}
    </ul>
  )
}

Pre-Built Agent Templates

预置Agent模板

Located in
data/.agents/.library/
. Available roles:
DepartmentAgents
LeadershipCEO, COO, CFO, CTO
ProductProduct Manager, UX Designer
MarketingContent Marketer, SEO Specialist, Social Media, Growth Marketer, Copywriter
EngineeringEditor, QA Agent, DevOps Engineer
Sales & SupportSales Agent, Customer Success
AnalyticsData Analyst
OperationsPeople Ops, Legal Advisor, Researcher
To activate a template:
bash
undefined
位于
data/.agents/.library/
目录下,可用角色:
部门Agent
管理层CEO, COO, CFO, CTO
产品产品经理, UX设计师
营销内容营销, SEO专家, 社交媒体运营, 增长营销, 文案
研发编辑器, QA Agent, DevOps工程师
销售与支持销售Agent, 客户成功
分析数据分析师
运营人力运营, 法律顾问, 研究员
要激活一个模板:
bash
undefined

Copy a template to active agents

复制模板到活跃Agent目录

cp data/.agents/.library/researcher.md data/.agents/active/my-researcher/index.md
cp data/.agents/.library/researcher.md data/.agents/active/my-researcher/index.md

Then edit goals and schedule in the copied file

然后编辑复制后文件中的目标和schedule


---

---

Adding a New Agent Template

添加新的Agent模板

markdown
<!-- data/.agents/.library/custom-scout.md -->
---
name: Custom Scout
role: researcher
schedule: "0 8 * * *"
skills:
  - web-search
  - summarization
goals:
  - Monitor industry news daily
  - Summarize top 5 findings
  - Append to data/research/daily-digest.md
---
markdown
<!-- data/.agents/.library/custom-scout.md -->
---
name: Custom Scout
role: researcher
schedule: "0 8 * * *"
skills:
  - web-search
  - summarization
goals:
  - Monitor industry news daily
  - Summarize top 5 findings
  - Append to data/research/daily-digest.md
---

Custom Scout

Custom Scout

You are a research agent. Each morning you will search for recent developments in [TOPIC] and append a dated summary to the daily digest.
You are a research agent. Each morning you will search for recent developments in [TOPIC] and append a dated summary to the daily digest.

Instructions

说明

  1. Search for "[TOPIC] news" from the last 24 hours
  2. Select the 5 most relevant items
  3. Write a 2-3 sentence summary per item
  4. Append to
    data/research/daily-digest.md
    with today's date as a heading
  1. 搜索过去24小时内的「[TOPIC] 新闻」
  2. 选择5个最相关的条目
  3. 每个条目写2-3句话的摘要
  4. 以当天日期为标题,追加到
    data/research/daily-digest.md

Memory

记忆

<!-- Populated automatically -->

---
<!-- 自动填充 -->

---

Common Patterns

常用场景

Pattern 1: Knowledge Base with Agent Automation

场景1:带Agent自动化的知识库

data/
  company/
    overview.md          ← Human-maintained
    competitors/
      analysis.md        ← Agent-updated weekly
      index.html         ← Auto-generated dashboard
  agents/
    competitor-scout/
      index.md           ← Runs every Monday
      memory.md          ← Tracks what it found last week
data/
  company/
    overview.md          ← 人工维护
    competitors/
      analysis.md        ← Agent每周更新
      index.html         ← 自动生成的仪表盘
  agents/
    competitor-scout/
      index.md           ← 每周一运行
      memory.md          ← 记录上周发现的内容

Pattern 2: Research Pipeline

场景2:研究流水线

1. Researcher agent scouts Reddit/HN every 6h → writes to data/inbox/
2. Analyst agent summarizes inbox daily → writes to data/research/weekly.md
3. CEO agent reads weekly.md every Monday → writes strategic notes
1. 研究员Agent每6小时扫描Reddit/HN → 写入data/inbox/
2. 分析师Agent每天汇总收件箱内容 → 写入data/research/weekly.md
3. CEO Agent每周一读取weekly.md → 输出战略笔记

Pattern 3: Using the Web Terminal

场景3:使用网页终端

The web terminal (xterm.js + node-pty) gives full shell access inside the browser:
  • Press `Ctrl+`` or click the terminal icon in the sidebar
  • Run Claude Code directly:
    claude "analyze the data in research/competitors.md"
  • Full shell: edit files, run scripts, commit to git

网页终端(xterm.js + node-pty)支持在浏览器中直接访问完整的shell:
  • 按`Ctrl+``或点击侧边栏的终端图标
  • 直接运行Claude Code:
    claude "analyze the data in research/competitors.md"
  • 完整shell能力:编辑文件、运行脚本、提交Git变更

Troubleshooting

故障排查

Daemon not starting

守护进程无法启动

bash
undefined
bash
undefined

Check if port 3001 is in use

检查3001端口是否被占用

lsof -i :3001
lsof -i :3001

Kill if needed

如果需要,杀死占用进程

kill -9 $(lsof -t -i:3001)
kill -9 $(lsof -t -i:3001)

Restart

重启

npm run dev:all
undefined
npm run dev:all
undefined

Claude Code not found

找不到Claude Code

bash
npm install -g @anthropic-ai/claude-code
bash
npm install -g @anthropic-ai/claude-code

Verify

验证安装

claude --version
undefined
claude --version
undefined

Agent jobs not running

Agent任务不运行

bash
undefined
bash
undefined

Check daemon logs

查看守护进程日志

npm run dev:daemon
npm run dev:daemon

Check agent frontmatter has valid schedule field

检查Agent前置元数据中是否有合法的schedule字段

undefined
undefined

Git history not working

Git历史不工作

bash
cd data
git status
bash
cd data
git status

If not initialized:

如果没有初始化:

git init git add . git commit -m "initial"
undefined
git init git add . git commit -m "initial"
undefined

Port conflicts

端口冲突

bash
undefined
bash
undefined

Next.js uses 3000, daemon uses 3001

Next.js默认使用3000端口,守护进程默认使用3001端口

Override in package.json scripts or set PORT env var

可以在package.json脚本中覆盖,或者设置PORT环境变量

PORT=3002 npm run dev
undefined
PORT=3002 npm run dev
undefined

Embedded HTML app not rendering

嵌入式HTML应用不渲染

  • File must be named exactly
    index.html
  • Must be inside a folder under
    data/
  • Check browser console for CSP/iframe errors
  • Try accessing directly:
    http://localhost:3000/apps/my-folder

  • 文件名必须严格为
    index.html
  • 必须放在
    data/
    目录下的某个子文件夹中
  • 检查浏览器控制台是否有CSP/iframe错误
  • 尝试直接访问:
    http://localhost:3000/apps/my-folder

Self-Hosting in Production

生产环境自托管

bash
npm run build
npm run start   # Runs both Next.js and daemon in production mode
bash
npm run build
npm run start   # 生产模式同时运行Next.js和守护进程

With PM2

使用PM2托管

pm2 start npm --name "cabinet" -- run start pm2 save pm2 startup

```nginx
pm2 start npm --name "cabinet" -- run start pm2 save pm2 startup

```nginx

Nginx reverse proxy

Nginx反向代理配置

server { listen 80; server_name yourdomain.com;
location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; }
location /ws { proxy_pass http://localhost:3001; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; } }

---
server { listen 80; server_name yourdomain.com;
location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; }
location /ws { proxy_pass http://localhost:3001; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; } }

---

Resources

资源