secondbrain-entity
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAdd Custom Entity
添加自定义实体
Create custom entity types with schema validation and VitePress integration.
创建带Schema验证和VitePress集成的自定义实体类型。
Prerequisites
前提条件
Verify secondbrain is initialized:
- Check for
.claude/data/config.yaml - If not found, suggest running first
secondbrain-init
确认secondbrain已初始化:
- 检查是否存在
.claude/data/config.yaml - 若未找到,建议先运行
secondbrain-init
Workflow
操作流程
Step 1: Gather Entity Information
步骤1:收集实体信息
Collect from user:
- Entity Name — Plural name (e.g., "contacts", "projects", "bookmarks")
- Singular Name — For display (e.g., "contact", "project", "bookmark")
- Fields — Custom fields for the entity:
- Field name (snake_case)
- Field type (string, integer, boolean, date, array, enum)
- Required or optional
- For enums: allowed values
- ID Format — How records are numbered/identified:
- Sequential ()
PREFIX-XXXX - Date-based ()
YYYY-MM-DD-slug - UUID
- Sequential (
- Status Workflow (optional) — If entity has status tracking
向用户收集以下信息:
- 实体名称 — 复数形式(例如:"contacts"、"projects"、"bookmarks")
- 单数名称 — 用于显示(例如:"contact"、"project"、"bookmark")
- 字段 — 实体的自定义字段:
- 字段名称(蛇形命名法snake_case)
- 字段类型(string、integer、boolean、date、array、enum)
- 必填或可选
- 若为枚举类型:允许的取值
- ID格式 — 记录的编号/标识方式:
- 序列式()
PREFIX-XXXX - 基于日期()
YYYY-MM-DD-slug - UUID
- 序列式(
- 状态工作流(可选)— 若实体需要状态追踪
Step 2: Generate Schema
步骤2:生成Schema
Create :
.claude/data/<entity>/schema.yamlyaml
type: object
required: [records]
properties:
last_number:
type: integer
description: Last assigned sequential number
records:
type: array
items:
type: object
required: [id, title, created, file]
properties:
id:
type: string
description: Unique identifier
title:
type: string
description: Display title
created:
type: string
format: date
file:
type: string
description: Path to markdown file
status:
type: string
enum: [active, archived]
# ... custom fields创建 :
.claude/data/<entity>/schema.yamlyaml
type: object
required: [records]
properties:
last_number:
type: integer
description: Last assigned sequential number
records:
type: array
items:
type: object
required: [id, title, created, file]
properties:
id:
type: string
description: Unique identifier
title:
type: string
description: Display title
created:
type: string
format: date
file:
type: string
description: Path to markdown file
status:
type: string
enum: [active, archived]
# ... custom fieldsStep 3: Initialize Records File
步骤3:初始化记录文件
Create :
.claude/data/<entity>/records.yamlyaml
last_number: 0
records: []创建 :
.claude/data/<entity>/records.yamlyaml
last_number: 0
records: []Step 4: Create Document Template
步骤4:创建文档模板
Create :
templates/entities/<entity>/TEMPLATE.mdmarkdown
---
id: {{id}}
title: {{title}}
created: {{date}}
status: active创建 :
templates/entities/<entity>/TEMPLATE.mdmarkdown
---
id: {{id}}
title: {{title}}
created: {{date}}
status: active... custom fields
... custom fields
{{title}}
{{title}}
Overview
Overview
[Description]
[Description]
Details
Details
[Content]
undefined[Content]
undefinedStep 5: Create VitePress Data Loader
步骤5:创建VitePress数据加载器
Create :
docs/.vitepress/data/<entity>.data.tstypescript
import { defineLoader } from 'vitepress'
import fs from 'fs'
import yaml from 'js-yaml'
interface Record {
id: string
title: string
created: string
file: string
status: string
// ... custom fields
}
export interface Data {
records: Record[]
lastNumber: number
}
declare const data: Data
export { data }
export default defineLoader({
watch: ['.claude/data/<entity>/*.yaml'],
async load(): Promise<Data> {
const recordsPath = '.claude/data/<entity>/records.yaml'
if (!fs.existsSync(recordsPath)) {
return { records: [], lastNumber: 0 }
}
const content = fs.readFileSync(recordsPath, 'utf-8')
const parsed = yaml.load(content) as any
return {
records: parsed.records || [],
lastNumber: parsed.last_number || 0
}
}
})创建 :
docs/.vitepress/data/<entity>.data.tstypescript
import { defineLoader } from 'vitepress'
import fs from 'fs'
import yaml from 'js-yaml'
interface Record {
id: string
title: string
created: string
file: string
status: string
// ... custom fields
}
export interface Data {
records: Record[]
lastNumber: number
}
declare const data: Data
export { data }
export default defineLoader({
watch: ['.claude/data/<entity>/*.yaml'],
async load(): Promise<Data> {
const recordsPath = '.claude/data/<entity>/records.yaml'
if (!fs.existsSync(recordsPath)) {
return { records: [], lastNumber: 0 }
}
const content = fs.readFileSync(recordsPath, 'utf-8')
const parsed = yaml.load(content) as any
return {
records: parsed.records || [],
lastNumber: parsed.last_number || 0
}
}
})Step 6: Create Documentation Index
步骤6:创建文档索引
Create :
docs/<entity>/index.mdmarkdown
---
title: <Entity> Index
---创建 :
docs/<entity>/index.mdmarkdown
---
title: <Entity> Index
---<Entity>
<Entity>
<script setup>
import { data } from '../.vitepress/data/<entity>.data'
import EntityTable from '../.vitepress/theme/components/EntityTable.vue'
const columns = [
{ key: 'id', label: 'ID', sortable: true },
{ key: 'title', label: 'Title', sortable: true },
{ key: 'created', label: 'Created', sortable: true },
{ key: 'status', label: 'Status', sortable: true }
]
</script>
<EntityTable :data="data.records" :columns="columns" />
```
<script setup>
import { data } from '../.vitepress/data/<entity>.data'
import EntityTable from '../.vitepress/theme/components/EntityTable.vue'
const columns = [
{ key: 'id', label: 'ID', sortable: true },
{ key: 'title', label: 'Title', sortable: true },
{ key: 'created', label: 'Created', sortable: true },
{ key: 'status', label: 'Status', sortable: true }
]
</script>
<EntityTable :data="data.records" :columns="columns" />
```
Step 7: Update Configuration
步骤7:更新配置
Add entity to :
.claude/data/config.yamlyaml
entities:
<entity>:
enabled: true
singular: <singular>
id_format: sequential # or date-based, uuid
prefix: PREFIX # for sequential IDs
freshness:
stale_after_days: 30
fields:
- name: field_name
type: string
required: true将实体添加至 :
.claude/data/config.yamlyaml
entities:
<entity>:
enabled: true
singular: <singular>
id_format: sequential # or date-based, uuid
prefix: PREFIX # for sequential IDs
freshness:
stale_after_days: 30
fields:
- name: field_name
type: string
required: trueStep 8: Update Sidebar
步骤8:更新侧边栏
Add to sidebar:
docs/.vitepress/config.tstypescript
{
text: '<Entity>',
collapsed: true,
items: [
{ text: 'Overview', link: '/<entity>/' }
]
}在 侧边栏中添加:
docs/.vitepress/config.tstypescript
{
text: '<Entity>',
collapsed: true,
items: [
{ text: 'Overview', link: '/<entity>/' }
]
}Step 9: Confirm Creation
步骤9:确认创建完成
undefinedundefinedEntity Created
Entity Created
Name: <entity>
Singular: <singular>
ID Format: sequential (PREFIX-XXXX)
Status Tracking: Yes
Name: <entity>
Singular: <singular>
ID Format: sequential (PREFIX-XXXX)
Status Tracking: Yes
Fields
Fields
| Field | Type | Required |
|---|---|---|
| title | string | Yes |
| description | string | No |
| priority | enum (low, medium, high) | No |
| Field | Type | Required |
|---|---|---|
| title | string | Yes |
| description | string | No |
| priority | enum (low, medium, high) | No |
Files Created
Files Created
.claude/data/<entity>/schema.yaml.claude/data/<entity>/records.yamldocs/.vitepress/data/<entity>.data.tsdocs/<entity>/index.md
.claude/data/<entity>/schema.yaml.claude/data/<entity>/records.yamldocs/.vitepress/data/<entity>.data.tsdocs/<entity>/index.md
Next Steps
Next Steps
- Create records using the new entity type
- Add entity-specific skills if needed
- Customize the index page layout
undefined- Create records using the new entity type
- Add entity-specific skills if needed
- Customize the index page layout
undefinedField Types
字段类型
| Type | YAML Schema | Example |
|---|---|---|
| string | | "Hello world" |
| integer | | 42 |
| number | | 3.14 |
| boolean | | true/false |
| date | | 2026-01-15 |
| datetime | | 2026-01-15T10:30:00Z |
| array | | [tag1, tag2] |
| enum | | "active" |
| Type | YAML Schema | Example |
|---|---|---|
| string | | "Hello world" |
| integer | | 42 |
| number | | 3.14 |
| boolean | | true/false |
| date | | 2026-01-15 |
| datetime | | 2026-01-15T10:30:00Z |
| array | | [tag1, tag2] |
| enum | | "active" |
ID Formats
ID格式
Sequential
序列式
Best for: Tasks, tickets, numbered records
PREFIX-0001, PREFIX-0002, PREFIX-0003最适合:任务、工单、编号记录
PREFIX-0001, PREFIX-0002, PREFIX-0003Date-based
基于日期
Best for: Notes, journal entries, time-sensitive content
2026-01-15-meeting-notes
2026-01-15-architecture-review最适合:笔记、日志条目、时间敏感内容
2026-01-15-meeting-notes
2026-01-15-architecture-reviewUUID
UUID
Best for: Globally unique, import/export scenarios
550e8400-e29b-41d4-a716-446655440000最适合:全局唯一、导入/导出场景
550e8400-e29b-41d4-a716-446655440000Tips
小贴士
- Keep fields minimal — Start with essential fields, add more later
- Use enums for fixed values — Better than free-form strings
- Consider status workflow — Most entities benefit from status tracking
- Plan ID format carefully — Hard to change after records exist
- Reuse existing patterns — Look at ADR, Task, Note for inspiration
- 字段尽量精简 — 从核心字段开始,后续再逐步添加
- 对固定值使用枚举类型 — 比自由格式字符串更优
- 考虑状态工作流 — 大多数实体都能从状态追踪中受益
- 谨慎规划ID格式 — 记录创建后难以更改
- 复用现有模式 — 可参考ADR、Task、Note的实现方式