Skip to content

Commit 79b3df4

Browse files
authored
docs(readme): polish launch highlights and banner (#261)
* docs: simplify README launch highlights * docs(readme): use six launch highlights * docs(readme): use optimized banner asset * ci: lint pull request titles
1 parent 0a99922 commit 79b3df4

6 files changed

Lines changed: 173 additions & 62 deletions

File tree

‎.github/workflows/commits.yml‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@ concurrency:
1313
cancel-in-progress: true
1414

1515
jobs:
16+
title:
17+
name: pull request title
18+
if: github.event_name == 'pull_request'
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v6
22+
23+
- name: Validate Conventional Commit PR title
24+
env:
25+
PR_TITLE: ${{ github.event.pull_request.title }}
26+
run: make check-pr-title
27+
1628
messages:
1729
name: commit messages
1830
runs-on: ubuntu-latest

‎Makefile‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: help install install-deps lint docs-check check-commits check-assets check-deprecated-names check-cjk check-datetime openapi check-openapi format test integration package cov ci clean
1+
.PHONY: help install install-deps lint docs-check check-commits check-pr-title check-assets check-deprecated-names check-cjk check-datetime openapi check-openapi format test integration package cov ci clean
22

33
help:
44
@echo "Targets:"
@@ -7,6 +7,7 @@ help:
77
@echo " lint ruff + import-linter + repo hygiene + datetime discipline + openapi drift"
88
@echo " docs-check Validate Markdown links, use-case banners, and issue template YAML"
99
@echo " check-commits Validate Conventional Commit subjects for a git range"
10+
@echo " check-pr-title Validate PR title uses Conventional Commit format"
1011
@echo " check-assets Block committed images, videos, and asset/media directories"
1112
@echo " check-deprecated-names Block deprecated product names"
1213
@echo " check-cjk Scan for CJK outside the language-policy allowlist (advisory)"
@@ -48,6 +49,9 @@ docs-check:
4849
check-commits:
4950
python3 scripts/check_commit_messages.py $(RANGE)
5051

52+
check-pr-title:
53+
python3 scripts/check_pr_title.py
54+
5155
# Repository media hygiene gate. Images/videos belong in external hosting,
5256
# release artifacts, or other approved storage, then linked from docs.
5357
check-assets:

‎README.md‎

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<div align="center" id="readme-top">
22

3-
![EverOS banner](https://github.com/EverMind-AI/EverOS/releases/download/v1.0.0/everos-readme-banner.jpg)
3+
![EverOS banner](https://github.com/EverMind-AI/EverOS/releases/download/v1.0.0/everos-readme-banner-optimized.jpg)
44

55
<p align="center">
66
<a href="https://x.com/evermind"><img src="https://img.shields.io/badge/EverMind-000000?labelColor=gray&style=for-the-badge&logo=x&logoColor=white" alt="X"></a>
@@ -54,53 +54,36 @@
5454
<table>
5555
<tr>
5656
<td width="33%" valign="top">
57-
<strong>Markdown-First Memory</strong><br>
58-
Memory is persisted as plain Markdown: visible, auditable, hand-editable,
59-
Git-friendly, and owned by the user.
57+
<strong>Markdown As Source Of Truth</strong><br>
58+
All memory is persisted as <code>.md</code> files: readable, editable,
59+
grep-able, Git-versioned, and openable directly in Obsidian.
6060
</td>
6161
<td width="33%" valign="top">
62-
<strong>Lightweight Local Stack</strong><br>
63-
Install with Python. SQLite tracks runtime state; LanceDB powers vector,
64-
BM25, and scalar-filter retrieval locally.
62+
<strong>Local Three-Part Stack</strong><br>
63+
Markdown + SQLite + LanceDB keep vectors, BM25, and scalar filters
64+
local. No MongoDB, Elasticsearch, or Redis required.
6565
</td>
6666
<td width="33%" valign="top">
67-
<strong>Layered Memory Model</strong><br>
68-
User memory and agent memory are first-class today. Wiki-style knowledge
69-
is the next layer in the roadmap.
67+
<strong>Dual-Track Memory</strong><br>
68+
Agent memory (<code>cases</code> / <code>skills</code>) and user memory
69+
(<code>episodes</code> / <code>profile</code>) are extracted independently.
7070
</td>
7171
</tr>
7272
<tr>
7373
<td width="33%" valign="top">
74-
<strong>Self-Evolving Agents</strong><br>
75-
Agent memory can extract reusable cases and skills from repeated
76-
experience, so workflows become smarter over time.
77-
</td>
78-
<td width="33%" valign="top">
7974
<strong>Multimodal Ingestion</strong><br>
80-
Text, image, audio, documents, PDF, HTML, and email can be parsed into
81-
memory through the optional multimodal pipeline.
82-
</td>
83-
<td width="33%" valign="top">
84-
<strong>Online And Offline Strategy Control</strong><br>
85-
Online extraction and offline evolution stay separate, with configurable
86-
prompts and models at each step. Dreaming is coming next.
87-
</td>
88-
</tr>
89-
<tr>
90-
<td width="33%" valign="top">
91-
<strong>Orthogonal Memory Scope</strong><br>
92-
Owner, memory type, and scope are independent: search by user, agent,
93-
app, project, session, and structured filters.
75+
Text, images, audio, documents, PDFs, HTML, and email are unified into
76+
searchable memory.
9477
</td>
9578
<td width="33%" valign="top">
96-
<strong>Progressive Disclosure</strong><br>
97-
Readable memory surfaces stay simple while deeper facts, cases, and
98-
skills remain available.
79+
<strong>Self-Evolution</strong><br>
80+
Common skills are extracted from real usage; repeated patterns become
81+
reusable workflows, no retraining required.
9982
</td>
10083
<td width="33%" valign="top">
101-
<strong>Modular By Design</strong><br>
102-
EverAlgo owns algorithms; EverOS owns runtime, persistence, online flows,
103-
and offline evolution.
84+
<strong>Orthogonal Retrieval</strong><br>
85+
Search independently by <code>user_id</code>, <code>agent_id</code>,
86+
<code>app_id</code>, <code>project_id</code>, and <code>session_id</code>.
10487
</td>
10588
</tr>
10689
</table>

‎README.zh-CN.md‎

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<div align="center" id="readme-top">
22

3-
![EverOS banner](https://github.com/EverMind-AI/EverOS/releases/download/v1.0.0/everos-readme-banner.jpg)
3+
![EverOS banner](https://github.com/EverMind-AI/EverOS/releases/download/v1.0.0/everos-readme-banner-optimized.jpg)
44

55
<p align="center">
66
<a href="https://x.com/evermind"><img src="https://img.shields.io/badge/EverMind-000000?labelColor=gray&style=for-the-badge&logo=x&logoColor=white" alt="X"></a>
@@ -54,44 +54,30 @@
5454
<table>
5555
<tr>
5656
<td width="33%" valign="top">
57-
<strong>Markdown-First Memory</strong><br>
58-
记忆以普通 Markdown 持久化:可见、可审计、可手动编辑、Git 友好,并由用户自己拥有。
57+
<strong>Markdown As Source Of Truth</strong><br>
58+
所有记忆持久化为 <code>.md</code> 文件:可读、可改、可 grep、可 Git 版本化,也可直接用 Obsidian 打开。
5959
</td>
6060
<td width="33%" valign="top">
61-
<strong>Lightweight Local Stack</strong><br>
62-
用 Python 即可安装。SQLite 负责运行时状态;LanceDB 在本地提供向量、BM25 和结构化过滤检索。
61+
<strong>Local Three-Part Stack</strong><br>
62+
Markdown + SQLite + LanceDB 在本地完成向量、BM25 和标量过滤检索,无需 MongoDB、Elasticsearch 或 Redis。
6363
</td>
6464
<td width="33%" valign="top">
65-
<strong>Layered Memory Model</strong><br>
66-
用户记忆和 Agent 记忆现在是一等公民。Wiki 式知识层是路线图中的下一层。
65+
<strong>Dual-Track Memory</strong><br>
66+
Agent 记忆(<code>cases</code> / <code>skills</code>)与用户记忆(<code>episodes</code> / <code>profile</code>)独立提取,互不污染。
6767
</td>
6868
</tr>
6969
<tr>
7070
<td width="33%" valign="top">
71-
<strong>Self-Evolving Agents</strong><br>
72-
Agent 记忆可以从重复经验中提取可复用的 cases 和 skills,让工作流随着时间变得更聪明。
73-
</td>
74-
<td width="33%" valign="top">
7571
<strong>Multimodal Ingestion</strong><br>
76-
文本、图片、音频、文档、PDF、HTML 和邮件都可以通过可选的多模态管线解析进记忆。
77-
</td>
78-
<td width="33%" valign="top">
79-
<strong>Online And Offline Strategy Control</strong><br>
80-
在线提取和离线进化保持分离,并且每一步都可以配置 prompts 和 models。Dreaming 即将到来。
81-
</td>
82-
</tr>
83-
<tr>
84-
<td width="33%" valign="top">
85-
<strong>Orthogonal Memory Scope</strong><br>
86-
Owner、memory type 和 scope 相互独立:可以按 user、agent、app、project、session 和结构化 filters 搜索。
72+
文本、图像、音频、文档、PDF、HTML 和邮件统一抽取为可检索的记忆形态。
8773
</td>
8874
<td width="33%" valign="top">
89-
<strong>Progressive Disclosure</strong><br>
90-
可读记忆界面保持简单,同时更深层的 facts、cases 和 skills 仍然可以被系统使用。
75+
<strong>Self-Evolution</strong><br>
76+
从真实使用经验中自动抽取共性 skills,重复模式沉淀为可复用流程,无需重训。
9177
</td>
9278
<td width="33%" valign="top">
93-
<strong>Modular By Design</strong><br>
94-
EverAlgo 负责算法;EverOS 负责运行时、持久化、在线流程和离线进化。
79+
<strong>Orthogonal Retrieval</strong><br>
80+
按 <code>user_id</code>、<code>agent_id</code>、<code>app_id</code>、<code>project_id</code> 和 <code>session_id</code> 五维独立检索。
9581
</td>
9682
</tr>
9783
</table>

‎scripts/check_pr_title.py‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""Validate pull request titles against the EverOS Conventional Commits policy."""
2+
3+
from __future__ import annotations
4+
5+
import importlib.util
6+
import os
7+
import sys
8+
from pathlib import Path
9+
from types import ModuleType
10+
11+
_SCRIPT_DIR = Path(__file__).resolve().parent
12+
13+
14+
def _load_commit_policy() -> ModuleType:
15+
policy_path = _SCRIPT_DIR / "check_commit_messages.py"
16+
spec = importlib.util.spec_from_file_location("_commit_message_policy", policy_path)
17+
if spec is None or spec.loader is None:
18+
raise RuntimeError(f"Unable to load commit policy from {policy_path}")
19+
20+
module = importlib.util.module_from_spec(spec)
21+
sys.modules[spec.name] = module
22+
spec.loader.exec_module(module)
23+
return module
24+
25+
26+
_POLICY = _load_commit_policy()
27+
ALLOWED_TYPES = _POLICY.ALLOWED_TYPES
28+
MAX_TITLE_LENGTH = _POLICY.MAX_TITLE_LENGTH
29+
TITLE_RE = _POLICY.TITLE_RE
30+
31+
32+
def validate_title(title: str) -> list[str]:
33+
title = title.strip()
34+
if not title:
35+
return ["missing PR title"]
36+
37+
if len(title) > MAX_TITLE_LENGTH:
38+
return [f"PR title is {len(title)} chars; max is {MAX_TITLE_LENGTH}: {title}"]
39+
40+
if not TITLE_RE.match(title):
41+
allowed = ", ".join(ALLOWED_TYPES)
42+
return [
43+
f"invalid PR title: {title}\n"
44+
" expected: <type>[(scope)][!]: <description>\n"
45+
f" allowed types: {allowed}"
46+
]
47+
48+
return []
49+
50+
51+
def _title_from_args_or_env(argv: list[str]) -> str:
52+
if argv:
53+
return " ".join(argv)
54+
return os.getenv("PR_TITLE", "")
55+
56+
57+
def main(argv: list[str] | None = None) -> int:
58+
title = _title_from_args_or_env(sys.argv[1:] if argv is None else argv)
59+
failures = validate_title(title)
60+
if failures:
61+
print("Pull request title check failed:")
62+
print("\n".join(failures))
63+
return 1
64+
65+
print("Pull request title follows Conventional Commits.")
66+
return 0
67+
68+
69+
if __name__ == "__main__":
70+
raise SystemExit(main())
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""Self-tests for ``scripts/check_pr_title.py``."""
2+
3+
from __future__ import annotations
4+
5+
import importlib.util
6+
import sys
7+
from pathlib import Path
8+
9+
_REPO_ROOT = Path(__file__).resolve().parents[3]
10+
_CHECKER_PATH = _REPO_ROOT / "scripts" / "check_pr_title.py"
11+
12+
13+
def _load_checker():
14+
assert _CHECKER_PATH.exists(), "PR title checker should exist"
15+
spec = importlib.util.spec_from_file_location("_pr_title_checker", _CHECKER_PATH)
16+
assert spec and spec.loader
17+
mod = importlib.util.module_from_spec(spec)
18+
sys.modules[spec.name] = mod
19+
spec.loader.exec_module(mod)
20+
return mod
21+
22+
23+
def test_conventional_pr_title_is_allowed() -> None:
24+
checker = _load_checker()
25+
26+
assert checker.validate_title("docs(readme): polish launch highlights") == []
27+
28+
29+
def test_bracketed_codex_pr_title_is_blocked() -> None:
30+
checker = _load_checker()
31+
32+
failures = checker.validate_title("[codex] simplify README launch highlights")
33+
34+
assert len(failures) == 1
35+
assert "invalid PR title" in failures[0]
36+
assert "expected: <type>[(scope)][!]: <description>" in failures[0]
37+
38+
39+
def test_long_pr_title_is_blocked() -> None:
40+
checker = _load_checker()
41+
title = (
42+
"docs(readme): polish launch highlights and banner with a title that is "
43+
"too long"
44+
)
45+
46+
failures = checker.validate_title(title)
47+
48+
assert len(failures) == 1
49+
assert "max is 72" in failures[0]
50+
51+
52+
def test_main_reads_pr_title_environment(monkeypatch) -> None:
53+
checker = _load_checker()
54+
monkeypatch.setenv("PR_TITLE", "docs(readme): polish launch highlights")
55+
56+
assert checker.main([]) == 0

0 commit comments

Comments
 (0)