diff --git a/apps/docs/public/figures/endor-purpose.svg b/apps/docs/public/figures/endor-purpose.svg
new file mode 100644
index 0000000..3909302
--- /dev/null
+++ b/apps/docs/public/figures/endor-purpose.svg
@@ -0,0 +1,320 @@
+
+
\ No newline at end of file
diff --git a/apps/docs/src/lib/navigation.ts b/apps/docs/src/lib/navigation.ts
index 6f2d298..a37681f 100644
--- a/apps/docs/src/lib/navigation.ts
+++ b/apps/docs/src/lib/navigation.ts
@@ -5,6 +5,13 @@ export type Section = {
symbol: string;
};
export function sectionFor(slug: string): Section {
+ if (slug.includes("endor-purpose"))
+ return {
+ group: "项目讨论",
+ label: "讨论草案",
+ symbol: "○",
+ description: "逐步讨论 Endor 的意义:从程序入口走向用户与 AI 的对象操作。",
+ };
if (slug.includes("endor-concepts"))
return {
group: "架构设计",
diff --git a/content/docs/04-endor-purpose-draft.md b/content/docs/04-endor-purpose-draft.md
new file mode 100644
index 0000000..7484f25
--- /dev/null
+++ b/content/docs/04-endor-purpose-draft.md
@@ -0,0 +1,42 @@
+# Endor 的意义:从程序入口到对象操作
+
+这篇文档用来逐步整理我们为什么要做 Endor。先记录一个切入点:**把对象的操作权交还给用户与 AI**。后续讨论可以在这里补充、修正,暂不把它写成一份已经定稿的项目宣言。
+
+> **讨论草案**:以下是希望探索的系统组织方式。图中进程和对象的数量、对象关系与操作路径都是示意,不表示当前实现或性能测量。
+
+## 一对图:我们希望改变什么
+
+
+
+### 第一张图:用户面对程序
+
+从 OS 出发,许多进程组成不同的程序。每个程序可以对应不同数量的进程;图中分别画了两个、四个和三个。进程区里的许多小圆圈表示对象,它们散布在各进程中。
+
+用户通常通过程序提供的界面访问能力,也可能通过 Web 或 API。这里想强调的是操作入口:用户先选择程序,再在程序提供的功能中寻找自己要做的事。图中的对象仍然存在,但通常隐藏在程序的组织和入口之后。
+
+这是一种用于对照的简化视角,并不是说现有程序都无法开放对象或让外部系统组合能力。
+
+### 第二张图:用户与 AI 面对对象
+
+仍然从 OS 出发,但这次只画少量进程,用来承载 Endorphin。接下来展开的是许多相互连接的小圆圈:对象不再只作为程序内部的实现细节出现,而成为可以被引用、选择和操作的基本单位。
+
+用户与 AI 的多条曲线分别指向部分对象,表达我们希望提供的能力:**在授权范围内,直接找到所需对象,对它们执行操作,并把不同对象的能力组合起来**。图中没有把所有对象都连向用户,因为操作权应当是有范围、可控制的。
+
+OS、进程区与 Endorphin 被共同框在 **Endor OS** 的边界内。这是此处对整体系统的命名;是否涉及内核层面的替换、哪些职责由底层 OS 保留,尚未在这张概念图中定义。
+
+## 先记录下来的主张
+
+我们希望讨论的变化,是让用户与 AI 不必总以一个个程序为唯一操作入口,而能以对象及其关系来组织工作。程序仍可以承担展示、交互和专业工作流;对象则有机会成为跨这些入口引用和组合能力的共同单位。
+
+“交还操作权”不是开放任意内存访问,也不是绕过权限。它需要对象能够被明确定位,需要操作接口与授权边界,也需要让用户知道一次操作改变了什么。这些能力怎样落地,还需要后续设计。
+
+## 接下来慢慢整理
+
+- **对象是什么**:哪些东西应该成为可操作对象,身份和生命周期如何定义?
+- **操作权是什么**:读取、修改、调用、组合与委托分别意味着什么,怎样授予和撤销?
+- **AI 如何参与**:如何发现对象能力、请求授权,并让操作结果可以检查?
+- **程序的位置**:Tessera、Web 与其他程序如何成为同一对象世界的不同入口?
+- **运行边界**:对象跨进程、设备、自部署和平台运行时,哪些语义需要保持一致?
+- **怎样验证意义**:用什么具体工作流说明这种组织方式给用户带来的变化?
+
+本文先保留这些问题,随讨论逐项展开。[系统架构](/docs/00-endor-concepts-draft)讨论部署与存储,[节点与对象挂载](/docs/02-mounting-draft)讨论运行位置和挂载边界;这里关注的是它们最终为什么值得做。
diff --git a/design/verification/purpose/comparison.png b/design/verification/purpose/comparison.png
new file mode 100644
index 0000000..66f00b1
Binary files /dev/null and b/design/verification/purpose/comparison.png differ
diff --git a/tools/figures/src/endor_figures/cli.py b/tools/figures/src/endor_figures/cli.py
index dc22dc2..fd5ff6e 100644
--- a/tools/figures/src/endor_figures/cli.py
+++ b/tools/figures/src/endor_figures/cli.py
@@ -3,6 +3,7 @@ from pathlib import Path
import drawsvg as draw
from .architecture import build_architecture
from .deployment import build_deployment
+from .purpose import build_purpose
def main() -> None:
@@ -41,3 +42,7 @@ def main() -> None:
deployment = output.parent / "endor-deployment.svg"
build_deployment(deployment)
print(f"Generated {deployment.relative_to(root)}")
+
+ purpose = output.parent / "endor-purpose.svg"
+ build_purpose(purpose)
+ print(f"Generated {purpose.relative_to(root)}")
diff --git a/tools/figures/src/endor_figures/purpose.py b/tools/figures/src/endor_figures/purpose.py
new file mode 100644
index 0000000..1ff315d
--- /dev/null
+++ b/tools/figures/src/endor_figures/purpose.py
@@ -0,0 +1,146 @@
+"""Paired concept views: application entry points versus authorized object operations."""
+from pathlib import Path
+import math
+import random
+import drawsvg as d
+from .architecture import INK, GREEN, BLUE, PURPLE, MUTED, LINE, FONT
+
+
+def build_purpose(output: Path) -> None:
+ svg = d.Drawing(1800, 1290)
+ svg.append_title('Endor 的意义:从访问程序到操作对象的对比示意')
+ svg.append(d.Rectangle(0,0,1800,1290,fill='#fcfdfb'))
+ rng = random.Random(20261028)
+
+ def text(s,x,y,size=16,color=INK,weight='400',anchor='start'):
+ svg.append(d.Text(s,size,x,y,fill=color,font_family=FONT,font_weight=weight,text_anchor=anchor))
+
+ def box(x,y,w,h,fill='white',stroke=LINE,r=12):
+ svg.append(d.Rectangle(x,y,w,h,rx=r,fill=fill,stroke=stroke,stroke_width=1.3))
+
+ def wire(points,color=GREEN,arrow=False,dash=None,width=1.5):
+ p=d.Path(fill='none',stroke=color,stroke_width=width,stroke_linejoin='round',stroke_dasharray=dash)
+ p.M(*points[0])
+ for pt in points[1:]: p.L(*pt)
+ svg.append(p)
+ if arrow:
+ x,y=points[-1]; px,py=points[-2]; a=math.atan2(y-py,x-px)
+ for sign in [-1,1]:
+ svg.append(d.Line(x-7*math.cos(a+sign*.48),y-7*math.sin(a+sign*.48),x,y,stroke=color,stroke_width=width))
+
+ def objects(x,y,w,h,count,color=GREEN,r=3.5):
+ points=[]
+ while len(points)r*3.7 for qx,qy in points): points.append((px,py))
+ for px,py in points:
+ svg.append(d.Circle(px,py,r,fill='#eff6f1',stroke=color,stroke_width=1.2))
+ return points
+
+ def os(x,y):
+ for dy in [-21,-3,15]:
+ svg.append(d.Rectangle(x-40,y+dy,80,13,rx=3,fill='white',stroke=MUTED,stroke_width=1.6))
+ svg.append(d.Circle(x-30,y+dy+6,1.5,fill=MUTED))
+ svg.append(d.Line(x-17,y+dy+6,x+25,y+dy+6,stroke=MUTED,stroke_width=1.2))
+ text('OS',x,y+65,24,INK,'600','middle')
+
+ def person(x,y,ai=False):
+ if ai:
+ box(x-20,y-25,40,36,'#f5f1fa',PURPLE,8)
+ for dx in [-8,8]: svg.append(d.Circle(x+dx,y-8,2,fill=PURPLE))
+ wire([(x-8,y+4),(x+8,y+4)],PURPLE)
+ wire([(x,y-25),(x,y-35)],PURPLE)
+ svg.append(d.Circle(x,y-38,3,fill='white',stroke=PURPLE))
+ else:
+ svg.append(d.Circle(x,y-20,13,fill='#f1f6f3',stroke=GREEN,stroke_width=1.8))
+ svg.append(d.Path(fill='none',stroke=GREEN,stroke_width=1.8).M(x-25,y+23).Q(x-25,y-1,x,y-1).Q(x+25,y-1,x+25,y+23).Z())
+ text('AI' if ai else '用户',x,y+57,18,PURPLE if ai else INK,'600','middle')
+
+ text('ENDOR / WHY OBJECTS',40,43,14,GREEN,'600')
+ text('从程序入口,到对象的操作权',40,90,31,INK,'600')
+ text('一对概念图:改变用户与 AI 接触系统的基本单位。',40,123,16,MUTED)
+
+ # Panel one: unequal groups of processes map to application boundaries.
+ text('01',40,181,20,BLUE,'600')
+ text('以程序为入口',95,181,24,INK,'600')
+ text('OS',135,225,13,MUTED,'600','middle')
+ text('进程区 · 圆圈为进程中的对象',585,225,14,MUTED,'500','middle')
+ text('程序',1100,225,14,MUTED,'600','middle')
+ text('用户入口',1615,225,14,MUTED,'600','middle')
+ os(135,414)
+ wire([(178,414),(250,414),(250,286),(300,286)],BLUE)
+ wire([(250,414),(250,545),(300,545)],BLUE)
+ wire([(250,414),(300,414)],BLUE)
+ for row,(count,cy) in enumerate([(2,286),(4,414),(3,545)]):
+ box(300,cy-49,570,98,'#f7f9fb')
+ text(f'{count} 个进程',315,cy-27,11,MUTED)
+ pw=112
+ start=585-(count*pw+(count-1)*16)/2
+ for i in range(count):
+ px=start+i*(pw+16)
+ box(px,cy-15,pw,53,'white','#c6d8e7',7)
+ objects(px,cy-14,pw,50,6+rng.randrange(4),BLUE,r=3)
+ wire([(870,cy),(999,cy)],BLUE,arrow=True)
+ box(1000,cy-33,200,66,'white','#bdcfdc')
+ wire([(1013,cy-15),(1187,cy-15)],BLUE,width=1)
+ text(f'程序 {chr(65+row)}',1100,cy+14,20,INK,'600','middle')
+ wire([(1568,414),(1400,414),(1400,cy),(1202,cy)],BLUE,arrow=True)
+ person(1615,414)
+ text('界面 / Web / API',1394,611,15,BLUE,anchor='middle')
+ text('用户通过程序提供的入口访问功能;对象的组织与操作通常藏在程序内部。',300,640,16,MUTED)
+
+ # Panel two: OS, a small process pool and Endorphin belong to Endor OS.
+ text('02',40,709,20,GREEN,'600')
+ text('以对象为操作单位',95,709,24,INK,'600')
+ box(40,742,1410,421,'#f8fbf8','#a9cbbd',18)
+ box(64,758,162,36,'#eaf3ec','none',5)
+ text('Endor OS',145,783,21,GREEN,'600','middle')
+ text('OS',135,837,13,MUTED,'600','middle')
+ text('少量进程',415,837,14,MUTED,'600','middle')
+ os(135,961)
+ wire([(178,961),(270,961),(270,886),(335,886)],GREEN)
+ wire([(270,961),(335,961)],GREEN)
+ wire([(270,961),(270,1036),(335,1036)],GREEN)
+ for cy in [886,961,1036]:
+ box(335,cy-22,160,44,'white','#bdd5c8',7)
+ text('进程',415,cy+6,15,MUTED,anchor='middle')
+ wire([(495,cy),(555,cy),(555,961),(615,961)],GREEN,arrow=True,width=1.2)
+ box(615,807,805,322,'white','#cbded1',14)
+ text('Endorphin',644,845,25,INK,'600')
+ text('对象运行与操作空间',644,874,14,MUTED)
+ # Seeded randomness gives an organic network and reproducible repository assets.
+ nodes=[]
+ for i in range(43):
+ while True:
+ px,py=rng.uniform(845,1380),rng.uniform(843,1090)
+ if all(math.hypot(px-qx,py-qy)>33 for qx,qy in nodes): break
+ nodes.append((px,py))
+ edges=set()
+ for i,(px,py) in enumerate(nodes):
+ nearest=sorted((math.hypot(px-qx,py-qy),j) for j,(qx,qy) in enumerate(nodes) if j!=i)
+ for _,j in nearest[:2 if i%3 else 3]: edges.add(tuple(sorted((i,j))))
+ for i,j in sorted(edges): wire([nodes[i],nodes[j]],'#c8dcd2',width=1)
+ selected=sorted(range(len(nodes)),key=lambda i:nodes[i][0],reverse=True)[:7]
+ for i,(px,py) in enumerate(nodes):
+ svg.append(d.Circle(px,py,7 if i in selected else 5,
+ fill='#e5f1e8' if i in selected else 'white',
+ stroke=GREEN,stroke_width=1.8 if i in selected else 1.2))
+ text('对象',647,1000,17,GREEN,'600')
+ text('可引用 · 可组合',647,1028,13,MUTED)
+ text('按权限操作',647,1053,13,MUTED)
+ person(1630,888)
+ person(1630,1055,ai=True)
+ # Users/AI reach selected objects with explicit cubic Bezier curves.
+ for k,i in enumerate(selected):
+ px,py=nodes[i]
+ sy=888 if k<4 else 1055
+ color=GREEN if k<4 else PURPLE
+ control_y=790+k*45
+ svg.append(d.Path(fill='none',stroke=color,stroke_width=1.7,opacity=.85)
+ .M(1597,sy).C(1505,control_y,px+90,py-35,px,py))
+ svg.append(d.Circle(px,py,10,fill='none',stroke=color,stroke_width=1,opacity=.6))
+ text('选择对象 · 发起操作',1620,1196,16,GREEN,anchor='middle')
+ text('进程数量仅作概念对比,不代表性能测量或固定部署要求。',40,1220,13,MUTED)
+ text('圆圈 = 对象 细线 = 对象关系 贝塞尔曲线 = 用户 / AI 对选定对象的操作',40,1253,14,MUTED)
+ text('讨论草案',1730,1253,13,MUTED,anchor='end')
+ svg.save_svg(str(output))