跳到正文
cccskills
免费在 GitHub 公开中文介绍

add-memory-kind

指导开发者新增可持久化的业务记忆类型:按需选择 Markdown、SQLite 和 LanceDB,确定 Markdown 文件策略,再配置所需的架构、仓库和写入器。

原文查看原文说明

Add a new business memory kind end-to-end. Pick the storage combination (Markdown / SQLite / LanceDB), pick the markdown strategy (daily-log / skill-named / single-file), then wire up the schema(s), repo(s), and writer(s).

EverMind-AI/EverOS星标 13,704(GitHub 13,704 + cccskills 0)

实测评分 未实测

查看安装方法

适用场景

  • 新增可持久化的业务记忆类型
  • 设计存储层组合
  • 连接 Markdown 原文与检索索引

中文介绍

功能

指导开发者为新的业务数据类型添加持久化能力,选择需要的存储层和实现位置。可组合使用 Markdown 作为便于阅读的原文、SQLite 保存结构化数据,以及 LanceDB 支持向量检索等搜索。若使用 Markdown,还需选择按日期追加记录、覆盖命名文件或重写单个文件的策略。之后添加相应的数据架构和写入逻辑,并按需增加数据库表和仓库。流程还包括重新导出新增组件,供项目其他部分使用。

适用场景

适合需要持久保存 Episode、Case 等新业务记录的开发者。它可以帮助判断数据是否需要检索、结构化状态或可由人编辑的原文,并将选定的存储层连接起来。

使用示例

  • “帮我为新的业务记忆类型选择存储方案。”
  • “添加按日记录的 Markdown 文件和 SQLite 表。”
  • “接入用于检索的 LanceDB 索引。”

注意事项

按日追加的 Markdown 方案提供了具体步骤。命名文件和单文件方案只有概略说明;在基础写入器可用之前,需要直接封装 MarkdownWriter。仅在确有需要时添加 SQLite 或 LanceDB。

本介绍由 AI(OpenAI Codex)根据公开的 SKILL.md 撰写。准确的规格请查看下方原文。

文档检查

AI 根据 SKILL.md 的内容检查了需要注意的操作和使用前提。评分只依据实际运行的结果(实测对比)。

安全性发送数据、删除文件、执行命令等是否有说明
A良好说明了文件覆盖策略,并将 SQLite 和 LanceDB 设为可选。
安装难易度所需工具和 API 密钥是否少且有说明
B部分不足列出 Markdown、SQLite 和 LanceDB 选项,但没有安装步骤。

不计入评分。 由 AI(OpenAI Codex)于 2026年10月29日 评估。仅供参考,安装前请同时查看原文。

如果您认为评估有误,请申请复核

请写明哪一项有误以及原因。无需登录。我们会对照 SKILL.md 重新评估,并在此处更新结果。

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

包含的文件(1)

  • SKILL.md11.2 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

/add-memory-kind — Add a new business memory kind

When to invoke

Adding a new persisted business entity (Episode, Case, Skill, AtomicFact, Foresight, Profile, or something custom). Multiple storage layers may be involved; this skill walks the decision then the wiring.

1. Decide the storage combination

A memory kind does not have to use all three layers. Pick by what the kind actually needs:

NeedMarkdownSQLiteLanceDB
Human-readable / agent-editable source-of-truth text✅
Structured state, ACID transactions, joins, predicates✅
Vector / BM25 / hybrid retrieval✅

Common combinations seen in EverOS:

ComboExampleRationale
md onlyscratch notes / dump binstext-of-truth, no index needed
md + lancedbepisode / memcell / casetext-of-truth + semantic retrieval
md + sqliteprofile / playbook / soul.md statetext-of-truth + structured state to query
md + sqlite + lancedbfull-blown business recordswhen you need both transactional state AND retrieval
sqlite onlyaudit log / task queue / LSN watermarksystem state, never user-facing
lancedb onlyrare; usually you still want mdderived embeddings without text-of-truth

Rule of thumb: markdown is the truth; sqlite and lancedb are derived indexes that can be rebuilt from md. Drop md only when the kind has no human-readable form (pure system state).

2. Pick the markdown storage strategy (if md is in your combo)

Three strategies — declared in the EverOS Markdown First spec:

StrategyFilenameMutationExamples
Daily-log append<prefix>-YYYY-MM-DD.mdappend entriesmemcell / episode / case / atomic_fact / foresight
Skill-named in-placeskill_<name>.mdoverwrite the fileskills (procedural memory)
Single-file rewriteuser.md / agent.md / soul.md / behaviors.md / tools.mdoverwrite the fileprofiles / playbooks

This skill currently has a complete recipe for daily-log append. Skill-named and single-file recipes are sketched at the bottom — their base writers (BaseSkillWriter / BaseProfileWriter) land later in the project; until then build a thin wrapper over MarkdownWriter directly.


3. Markdown daily-log: 4 steps

3.1 Frontmatter schema — infra/persistence/markdown/mds/<name>.py

"""Episode daily-log frontmatter."""

from __future__ import annotations

import datetime as _dt
from typing import ClassVar, Literal

from everos.core.persistence.markdown import UserScopedFrontmatter


class UserEpisodeDailyFrontmatter(UserScopedFrontmatter):
    """``users/<u>/episodes/episode-<YYYY-MM-DD>.md``."""

    ENTRY_ID_PREFIX: ClassVar[str] = "ep"
    DIR_NAME: ClassVar[str] = "episodes"
    FILE_PREFIX: ClassVar[str] = "episode"

    type: Literal["user_episode_daily"] = "user_episode_daily"
    date: _dt.date
    entry_count: int = 0
    last_appended_at: _dt.datetime | None = None

For agent-track kinds subclass AgentScopedFrontmatter instead. If user-track and agent-track share a kind name (e.g. memcell), give each a distinct ENTRY_ID_PREFIX (e.g. umc vs amc) so reverse lookup is unambiguous.

3.2 Re-export — mds/__init__.py

from .episode import UserEpisodeDailyFrontmatter as UserEpisodeDailyFrontmatter

3.3 Business writer — infra/persistence/markdown/writers/<name>.py

"""Episode appender."""

from __future__ import annotations

from pathlib import Path

from everos.core.persistence import MarkdownReader

from ..mds import UserEpisodeDailyFrontmatter
from .base import BaseDailyWriter


class UserEpisodeAppender(BaseDailyWriter):
    schema = UserEpisodeDailyFrontmatter

    # OPTIONAL: override the count strategy. Default is len(entries);
    # override to trust the frontmatter field instead.
    def _current_count(self, path: Path) -> int:
        if not path.exists():
            return 0
        return MarkdownReader.read(path).frontmatter.get("entry_count", 0)

3.4 Re-export — writers/__init__.py

from .episode import UserEpisodeAppender as UserEpisodeAppender

Done — usage

from everos.infra.persistence.markdown.writers import UserEpisodeAppender

appender = UserEpisodeAppender(memory_root)
eid = appender.append("u_jason", "I went to the doctor today.")
# → users/u_jason/episodes/episode-<today>.md
# → entry markers carry an auto-generated EntryId (e.g. ep_20260507_001)

4. (Optional) SQLite table — 4 steps

Skip this section if the kind doesn't need structured state beyond markdown.

4.1 Schema — infra/persistence/sqlite/tables/<name>.py

from everos.core.persistence.sqlite import BaseTable, Field


class EpisodeState(BaseTable, table=True):
    __tablename__ = "episode_state"  # type: ignore[assignment]

    id: int | None = Field(default=None, primary_key=True)
    entry_id: str = Field(index=True, unique=True)
    cluster_id: str | None = Field(default=None, index=True)
    status: str = Field(default="active")

BaseTable already provides created_at / updated_at (auto-bumped).

4.2 Re-export — tables/__init__.py

from .episode import EpisodeState as EpisodeState

4.3 Repo — infra/persistence/sqlite/repos/<name>.py

from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker

from everos.core.persistence.sqlite import RepoBase

from ..sqlite_manager import get_session_factory
from ..tables import EpisodeState


class _EpisodeStateRepo(RepoBase[EpisodeState]):
    model = EpisodeState

    def _factory_lookup(self) -> async_sessionmaker[AsyncSession]:
        return get_session_factory()


episode_state_repo = _EpisodeStateRepo()

4.4 Re-export — repos/__init__.py

from .episode import episode_state_repo as episode_state_repo

5. (Optional) Derived index — 4 steps

Skip this section if the kind doesn't need vector / BM25 / hybrid retrieval.

5.1 Record declaration — infra/persistence/records/<name>.py

from typing import ClassVar

from everos.core.persistence.lancedb import BaseLanceTable, Vector


class EpisodeIndex(BaseLanceTable):
    TABLE_NAME: ClassVar[str] = "episode_index"
    PRIMARY_KEY: ClassVar[tuple[str, ...]] = ("app_id", "project_id", "id")

    id: str
    app_id: str = "default"
    project_id: str = "default"
    entry_id: str
    text: str
    tags: list[str]
    vector: Vector(1024) | None = None  # type: ignore[valid-type]

TABLE_NAME / BM25_FIELDS / PRIMARY_KEY are the backend-neutral declarations every index backend reads (IndexRecordMeta). PRIMARY_KEY has no default: check_primary_keys refuses to start, and LanceDB upsert refuses to write, a table that does not declare one. id is unique only within (app_id, project_id), so every business table declares the three-column key — LanceDB merges on it, Milvus keys the collection on a composed __pk and rejects key components containing /. Vector(N) must match your embedding dimension.

5.2 Re-export — records/__init__.py

from .episode import EpisodeIndex as EpisodeIndex

5.3 Repo — infra/persistence/lancedb/repos/<name>.py

from lancedb import AsyncTable

from everos.core.persistence.lancedb import LanceRepoBase
from everos.infra.persistence.records import EpisodeIndex

from ..lancedb_manager import get_table


class _EpisodeIndexRepo(LanceRepoBase[EpisodeIndex]):
    schema = EpisodeIndex

    async def _table_lookup(self) -> AsyncTable:
        return await get_table(self.schema.TABLE_NAME, self.schema)


episode_index_repo = _EpisodeIndexRepo()

Business code writes through the everos.infra.persistence.index facade: upsert(records) merges on the declared key and is the only write; look a row up with find_one_where(primary_key(app_id, project_id, row_id)).

5.4 Re-export — repos/__init__.py

from .episode import episode_index_repo as episode_index_repo

6. (Future) Skill-named & single-file markdown strategies

When the new memory kind needs:

  • skill-named files (one file per named skill, in-place rewrite) — wait for BaseSkillWriter, or use MarkdownWriter.write_markdown directly with a thin wrapper.
  • single-file rewrite (one fixed file like user.md) — wait for BaseProfileWriter, same fallback.

These strategies do not use entry markers; their frontmatter schema does not need ENTRY_ID_PREFIX (only id / type / schema_version plus the scope mixin fields).


7. Verification checklist

  • make lint — ruff + import-linter clean
  • make test — existing manager / lifespan / writer tests still pass
  • When the kind crosses multiple layers:
    • markdown entry id is the join key for the sqlite / lancedb rows
    • business code reads only via the repo singleton (no raw engine access in service / memory)
    • cascade daemon (when it lands) can rebuild sqlite / lancedb from md alone — keep md as the truth

Tests by layer:

Tests forLocation
Markdown frontmatter schematests/unit/test_infra/test_markdown/test_mds/
Markdown business appendertests/unit/test_infra/test_markdown/test_writers/
SQLite RepoBase logictests/unit/test_core/test_persistence/test_sqlite/
SQLite manager / lifespantests/unit/test_infra/test_sqlite/
LanceDB LanceRepoBase logictests/unit/test_core/test_persistence/test_lancedb/
LanceDB manager / lifespantests/unit/test_infra/test_lancedb/

8. Common pitfalls

MistakeSymptomFix
Forgot ENTRY_ID_PREFIX / DIR_NAME / FILE_PREFIX on a daily-log schemaBaseDailyWriter.__init__ raises TypeErrorAdd all three ClassVars
Same ENTRY_ID_PREFIX on user + agent variantsMemoryLayout.locate_for_entry collision errorUse distinct prefixes (e.g. umc vs amc)
Imported RepoBase from infra.persistence.sqliteImportErrorLives in core.persistence.sqlite (moved earlier)
Skipped one of the four files (schema / writer / table / repo)One side silently absentRe-export both/all from each __init__.py
Vector(N) mismatched with embedding dimLanceDB raises on insertMake N exactly match the model output
Imported MemoryLayout from a writer (infra)import-linter fails (infra → memory reverse dep)Use MemoryRoot (in core) and let the schema's ClassVars drive paths
Hand-rolling datetime.now() instead of today_with_timezone()Day-boundary drift across timezonesAlways go through everos.component.utils.datetime

Background

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

commit

免费有简介

检查当前 Git 改动和近期提交记录,再按 Conventional Commits 格式创建聚焦的提交。可只暂存相关文件,并处理钩子检查失败的问题。

  • 检查改动并创建提交
  • 从差异中选择相关文件
  • 按约定编写提交说明
EverMind-AI/EverOS1.4万2026年10月29日 更新

new-branch

免费有简介

在更新后的 `main` 分支上创建用途明确的 Git 分支,并按改动类型选择前缀,如功能、修复、文档、CI、维护或重构,再添加简短的小写连字符名称。

  • 为新功能创建分支
  • 为修复问题创建分支
  • 开始更新文档
EverMind-AI/EverOS1.4万2026年10月29日 更新

pr

免费有简介

使用 GitHub CLI `gh`,按仓库模板将当前分支的改动提交为面向 `main` 的拉取请求。创建前运行 `make ci`,通过后推送分支并填写改动摘要、所属领域、验证结果、检查清单和审阅备注。

  • 为已完成的改动创建拉取请求
  • 填写拉取请求模板各项内容
  • 记录持续集成和手动检查结果
EverMind-AI/EverOS1.4万2026年10月29日 更新

release

免费有简介

指导将 everos 新版本发布到 PyPI,包括更新版本号和变更日志、创建触发自动工作流的标签,并完成审批。工作流上传后,还需检查并发布 GitHub Release 草稿。

  • 发布补丁版或次要版本
  • 分发预发布版本
  • 根据变更日志整理发布页面
EverMind-AI/EverOS1.4万2026年10月29日 更新

查看 EverMind-AI 的全部技能

报告此技能的问题