chore: initialize EverOS 1.0.0
md-first memory extraction framework for AI agents. Markdown is the single source of truth; SQLite holds state and LanceDB provides the rebuildable vector + BM25 + scalar index. The codebase follows a single-direction DDD layering (entrypoints -> service -> memory -> infra, with component / core / config cross-cutting) enforced by import-linter. Engineering surface: - Coding conventions in .claude/rules/ (path-scoped) and workflows in .claude/skills/ (/commit, /new-branch, /pr). - GitHub Actions CI runs make lint + test + integration; pre-commit mirrors the gates locally (ruff, hygiene hooks, gitlint commit-msg). - Commit messages follow Conventional Commits, enforced by gitlint. - make lint also enforces datetime two-zone discipline and OpenAPI drift.
This commit is contained in:
40
src/everos/infra/persistence/markdown/mds/__init__.py
Normal file
40
src/everos/infra/persistence/markdown/mds/__init__.py
Normal file
@ -0,0 +1,40 @@
|
||||
"""Business markdown frontmatter schemas (mds = "markdown schemas").
|
||||
|
||||
Each business record kind that is stored as markdown gets a concrete
|
||||
frontmatter class here, subclassing one of the chassis classes from
|
||||
:mod:`everos.core.persistence.markdown`:
|
||||
|
||||
* :class:`UserScopedFrontmatter` for user-track records
|
||||
* :class:`AgentScopedFrontmatter` for agent-track records
|
||||
* :class:`BaseFrontmatter` for scope-agnostic records (rare)
|
||||
|
||||
Schemas drive path resolution via ClassVars; each storage strategy has
|
||||
its own conventions:
|
||||
|
||||
- **Daily-log** schemas declare ``ENTRY_ID_PREFIX`` (token in
|
||||
``<prefix>_<date>_<seq>``), ``DIR_NAME`` (sub-directory under
|
||||
``<scope>/<id>/``) and ``FILE_PREFIX`` (leading token of the daily
|
||||
filename joined with ``-<YYYY-MM-DD>.md``).
|
||||
- **Skill** schemas (:class:`AgentSkillFrontmatter`) pin the directory
|
||||
layout via five ``SKILL_*`` ClassVars (container / dir prefix /
|
||||
main filename / references / scripts).
|
||||
- **Profile** schemas declare ``PROFILE_FILENAME`` (``"user.md"`` /
|
||||
``"agent.md"`` / …) and inherit ``SCOPE_DIR`` from a scope mixin; no
|
||||
profile base class — the writer/reader pair is duck-typed.
|
||||
"""
|
||||
|
||||
from .agent_case import AgentCaseDailyFrontmatter as AgentCaseDailyFrontmatter
|
||||
from .agent_skill import AgentSkillFrontmatter as AgentSkillFrontmatter
|
||||
from .atomic_fact import AtomicFactDailyFrontmatter as AtomicFactDailyFrontmatter
|
||||
from .episode import EpisodeDailyFrontmatter as EpisodeDailyFrontmatter
|
||||
from .foresight import ForesightDailyFrontmatter as ForesightDailyFrontmatter
|
||||
from .profile import UserProfileFrontmatter as UserProfileFrontmatter
|
||||
|
||||
__all__ = [
|
||||
"AgentCaseDailyFrontmatter",
|
||||
"AgentSkillFrontmatter",
|
||||
"AtomicFactDailyFrontmatter",
|
||||
"EpisodeDailyFrontmatter",
|
||||
"ForesightDailyFrontmatter",
|
||||
"UserProfileFrontmatter",
|
||||
]
|
||||
37
src/everos/infra/persistence/markdown/mds/agent_case.py
Normal file
37
src/everos/infra/persistence/markdown/mds/agent_case.py
Normal file
@ -0,0 +1,37 @@
|
||||
"""AgentCase frontmatter — daily-log markdown for agent-scoped cases.
|
||||
|
||||
Path: ``agents/<scope_id>/.cases/agent_case-<YYYY-MM-DD>.md``.
|
||||
|
||||
The directory is dotfile-hidden (``.cases``) so users only see the
|
||||
curated ``agent_skills/`` view, not the raw per-task case log — same
|
||||
convention as ``.atomic_facts`` / ``.foresights``.
|
||||
|
||||
Each entry records one task an agent worked on: intent, approach taken,
|
||||
quality score, and an optional pivotal insight. A MemCell extracted on
|
||||
the agent's own execution log yields at most one AgentCase.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime as _dt
|
||||
from typing import ClassVar, Literal
|
||||
|
||||
from everos.core.persistence.markdown import (
|
||||
AgentScopedFrontmatter,
|
||||
DailyLogPathMixin,
|
||||
)
|
||||
|
||||
|
||||
class AgentCaseDailyFrontmatter(DailyLogPathMixin, AgentScopedFrontmatter):
|
||||
"""Frontmatter for ``agents/<scope>/.cases/agent_case-<YYYY-MM-DD>.md``."""
|
||||
|
||||
ENTRY_ID_PREFIX: ClassVar[str] = "ac"
|
||||
DIR_NAME: ClassVar[str] = ".cases"
|
||||
FILE_PREFIX: ClassVar[str] = "agent_case"
|
||||
|
||||
type: Literal["agent_case_daily"] = "agent_case_daily"
|
||||
file_type: Literal["agent_case_daily"] = "agent_case_daily"
|
||||
date: _dt.date
|
||||
entry_count: int = 0
|
||||
created_at: _dt.datetime | None = None
|
||||
last_appended_at: _dt.datetime | None = None
|
||||
63
src/everos/infra/persistence/markdown/mds/agent_skill.py
Normal file
63
src/everos/infra/persistence/markdown/mds/agent_skill.py
Normal file
@ -0,0 +1,63 @@
|
||||
"""AgentSkill frontmatter — single SKILL.md inside a skill directory.
|
||||
|
||||
Path: ``agents/<scope_id>/skills/skill_<name>/SKILL.md`` (plus sibling
|
||||
``references/*.md`` and ``scripts/*.<ext>`` files that are not part of
|
||||
the frontmatter contract).
|
||||
|
||||
Skills are *named entities* rather than daily-log entries: the
|
||||
LanceDB primary key is ``<owner_id>_<skill_name>`` (no date / seq).
|
||||
Upserts replace the file wholesale; the cascade daemon recomputes the
|
||||
``content`` index column by concatenating ``SKILL.md`` body with every
|
||||
``references/*.md`` sibling.
|
||||
|
||||
Five directory-shape ClassVars pin the layout in one place so the
|
||||
writer / reader pair reads off them — no duplicated string literals.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime as _dt
|
||||
from typing import ClassVar, Literal
|
||||
|
||||
from everos.core.persistence.markdown import (
|
||||
AgentScopedFrontmatter,
|
||||
SkillPathMixin,
|
||||
)
|
||||
|
||||
|
||||
class AgentSkillFrontmatter(SkillPathMixin, AgentScopedFrontmatter):
|
||||
"""Frontmatter for ``agents/<scope>/skills/skill_<name>/SKILL.md``."""
|
||||
|
||||
SKILLS_CONTAINER_NAME: ClassVar[str] = "skills"
|
||||
SKILL_DIR_PREFIX: ClassVar[str] = "skill_"
|
||||
SKILL_MAIN_FILENAME: ClassVar[str] = "SKILL.md"
|
||||
SKILL_REFERENCES_DIR_NAME: ClassVar[str] = "references"
|
||||
SKILL_SCRIPTS_DIR_NAME: ClassVar[str] = "scripts"
|
||||
|
||||
type: Literal["agent_skill"] = "agent_skill"
|
||||
|
||||
name: str
|
||||
"""Skill identifier — also the directory suffix
|
||||
(``skills/skill_<name>/``). Keep snake_case so it is filesystem-safe
|
||||
and ID-stable."""
|
||||
|
||||
description: str
|
||||
"""One-line summary surfaced at Tier-1 prompt injection. Short — the
|
||||
agent's startup-time scanner reads ``(name, description)`` for every
|
||||
skill, so the token budget is tight."""
|
||||
|
||||
confidence: float
|
||||
"""LLM-emitted confidence in the skill's correctness, 0.0–1.0."""
|
||||
|
||||
maturity_score: float
|
||||
"""LLM-emitted maturity score, 0.0–1.0. The retrieval-time threshold
|
||||
(``maturity_threshold``) lives in MemorizeConfig, not on this file."""
|
||||
|
||||
source_case_ids: list[str] = []
|
||||
"""AgentCase ids that fed into this skill's synthesis (lineage)."""
|
||||
|
||||
cluster_id: str | None = None
|
||||
"""Optional MemScene clustering tag; may be unset early on."""
|
||||
|
||||
created_at: _dt.datetime | None = None
|
||||
updated_at: _dt.datetime | None = None
|
||||
38
src/everos/infra/persistence/markdown/mds/atomic_fact.py
Normal file
38
src/everos/infra/persistence/markdown/mds/atomic_fact.py
Normal file
@ -0,0 +1,38 @@
|
||||
"""AtomicFact frontmatter — daily-log markdown for user-scoped atomic facts.
|
||||
|
||||
Path: ``users/<scope_id>/.atomic_facts/atomic_fact-<YYYY-MM-DD>.md``.
|
||||
|
||||
The directory is dot-prefixed so it is hidden from end users (same
|
||||
convention as ``.index``); atomic facts are framework-internal derived md,
|
||||
not material the user is expected to read by hand.
|
||||
|
||||
Each entry carries one atomic fact extracted by the algo layer; the fact
|
||||
always hangs off the source MemCell (see ``parent_type`` in each entry's
|
||||
inline fields — handled at the StructuredEntry layer, not on the
|
||||
file-level frontmatter).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime as _dt
|
||||
from typing import ClassVar, Literal
|
||||
|
||||
from everos.core.persistence.markdown import (
|
||||
DailyLogPathMixin,
|
||||
UserScopedFrontmatter,
|
||||
)
|
||||
|
||||
|
||||
class AtomicFactDailyFrontmatter(DailyLogPathMixin, UserScopedFrontmatter):
|
||||
"""Frontmatter for ``users/<scope>/.atomic_facts/atomic_fact-<YYYY-MM-DD>.md``."""
|
||||
|
||||
ENTRY_ID_PREFIX: ClassVar[str] = "af"
|
||||
DIR_NAME: ClassVar[str] = ".atomic_facts"
|
||||
FILE_PREFIX: ClassVar[str] = "atomic_fact"
|
||||
|
||||
type: Literal["atomic_fact_daily"] = "atomic_fact_daily"
|
||||
file_type: Literal["atomic_fact_daily"] = "atomic_fact_daily"
|
||||
date: _dt.date
|
||||
entry_count: int = 0
|
||||
created_at: _dt.datetime | None = None
|
||||
last_appended_at: _dt.datetime | None = None
|
||||
33
src/everos/infra/persistence/markdown/mds/episode.py
Normal file
33
src/everos/infra/persistence/markdown/mds/episode.py
Normal file
@ -0,0 +1,33 @@
|
||||
"""Episode frontmatter — daily-log markdown for user-scoped episodes.
|
||||
|
||||
Path: ``users/<scope_id>/episodes/episode-<YYYY-MM-DD>.md``.
|
||||
|
||||
This milestone uses ``session_id`` as the scope key (since owner inference
|
||||
is out of scope). When owner inference lands the scope key will switch to
|
||||
``owner_id`` while the schema stays compatible.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime as _dt
|
||||
from typing import ClassVar, Literal
|
||||
|
||||
from everos.core.persistence.markdown import (
|
||||
DailyLogPathMixin,
|
||||
UserScopedFrontmatter,
|
||||
)
|
||||
|
||||
|
||||
class EpisodeDailyFrontmatter(DailyLogPathMixin, UserScopedFrontmatter):
|
||||
"""Frontmatter for ``users/<scope>/episodes/episode-<YYYY-MM-DD>.md``."""
|
||||
|
||||
ENTRY_ID_PREFIX: ClassVar[str] = "ep"
|
||||
DIR_NAME: ClassVar[str] = "episodes"
|
||||
FILE_PREFIX: ClassVar[str] = "episode"
|
||||
|
||||
type: Literal["episode_daily"] = "episode_daily"
|
||||
file_type: Literal["episode_daily"] = "episode_daily"
|
||||
date: _dt.date
|
||||
entry_count: int = 0
|
||||
created_at: _dt.datetime | None = None
|
||||
last_appended_at: _dt.datetime | None = None
|
||||
38
src/everos/infra/persistence/markdown/mds/foresight.py
Normal file
38
src/everos/infra/persistence/markdown/mds/foresight.py
Normal file
@ -0,0 +1,38 @@
|
||||
"""Foresight frontmatter — daily-log markdown for user-scoped foresights.
|
||||
|
||||
Path: ``users/<scope_id>/.foresights/foresight-<YYYY-MM-DD>.md``.
|
||||
|
||||
The directory is dot-prefixed so it is hidden from end users (same
|
||||
convention as ``.index``); foresights are framework-internal derived md,
|
||||
not material the user is expected to read by hand.
|
||||
|
||||
Each entry carries a forward-looking inference about the user (intent
|
||||
window, planned action, projected need) with ``start_time`` /
|
||||
``end_time`` describing the covered time range. ``parent_type`` always
|
||||
points back to a MemCell.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime as _dt
|
||||
from typing import ClassVar, Literal
|
||||
|
||||
from everos.core.persistence.markdown import (
|
||||
DailyLogPathMixin,
|
||||
UserScopedFrontmatter,
|
||||
)
|
||||
|
||||
|
||||
class ForesightDailyFrontmatter(DailyLogPathMixin, UserScopedFrontmatter):
|
||||
"""Frontmatter for ``users/<scope>/.foresights/foresight-<YYYY-MM-DD>.md``."""
|
||||
|
||||
ENTRY_ID_PREFIX: ClassVar[str] = "fs"
|
||||
DIR_NAME: ClassVar[str] = ".foresights"
|
||||
FILE_PREFIX: ClassVar[str] = "foresight"
|
||||
|
||||
type: Literal["foresight_daily"] = "foresight_daily"
|
||||
file_type: Literal["foresight_daily"] = "foresight_daily"
|
||||
date: _dt.date
|
||||
entry_count: int = 0
|
||||
created_at: _dt.datetime | None = None
|
||||
last_appended_at: _dt.datetime | None = None
|
||||
40
src/everos/infra/persistence/markdown/mds/profile.py
Normal file
40
src/everos/infra/persistence/markdown/mds/profile.py
Normal file
@ -0,0 +1,40 @@
|
||||
"""UserProfile frontmatter — single-file profile markdown for users.
|
||||
|
||||
Path: ``users/<user_id>/user.md``.
|
||||
|
||||
Carries the LLM-synthesised user profile: a free-form ``summary`` plus the
|
||||
two evidence buckets emitted by :class:`everalgo.user_memory.ProfileExtractor`
|
||||
(``explicit_info`` / ``implicit_traits``). ``profile_timestamp_ms``
|
||||
mirrors :attr:`everalgo.types.Profile.timestamp` so the
|
||||
``extract_user_profile`` strategy can compare per-user freshness against
|
||||
cluster ``last_ts`` without re-parsing the body.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, ClassVar, Literal
|
||||
|
||||
from everos.core.persistence.markdown import ProfilePathMixin, UserScopedFrontmatter
|
||||
|
||||
|
||||
class UserProfileFrontmatter(ProfilePathMixin, UserScopedFrontmatter):
|
||||
"""Frontmatter for ``users/<user_id>/user.md``."""
|
||||
|
||||
PROFILE_FILENAME: ClassVar[str] = "user.md"
|
||||
|
||||
type: Literal["user_profile"] = "user_profile"
|
||||
|
||||
summary: str = ""
|
||||
"""Free-form one-paragraph summary of the user — the retrieval anchor."""
|
||||
|
||||
explicit_info: list[Any] = []
|
||||
"""Algo-side ``explicit_info`` bucket (verbatim facts the user stated)."""
|
||||
|
||||
implicit_traits: list[Any] = []
|
||||
"""Algo-side ``implicit_traits`` bucket (LLM-inferred preferences)."""
|
||||
|
||||
profile_timestamp_ms: int = 0
|
||||
"""Algo-emitted profile timestamp (ms epoch); equals the timestamp of
|
||||
the most recent MemCell that fed into the synthesis. Compared with
|
||||
:attr:`everos.infra.persistence.sqlite.Cluster.last_ts_ms` to decide
|
||||
whether a cluster is fresh enough to drive a profile re-extraction."""
|
||||
Reference in New Issue
Block a user