Skip to content

Commit e7e77ec

Browse files
committed
auto: 基础架构 at 2026/3/26 21:15:00
1 parent 78cea9a commit e7e77ec

File tree

6 files changed

+135
-14
lines changed

6 files changed

+135
-14
lines changed

AGENTS.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ cortexos brief
1515
- `soul.md` 定义 CortexOS 怎么做事
1616
- `~/Documents/memory/`**用户本人的唯一知识真源**
1717
- `CortexOS/.memory/`**CortexOS 自己的运行态与私有记忆**
18-
- `AetherFleet/.memory/`**AI 编排运行态**
1918

2019
硬规则:
2120

docs/agents/index.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
# AI 舰队 Agent 配置总览
1+
# Agent 接入总览
22

3-
> 🏴 **当前指挥官**: 栖月-Prime(Claude Sonnet 4.6 / OpenClaw)| 接管: 2026-03-05
4-
> **架构**: 栖月 = 战略层 / Codex + Gemini + Claude Code = 执行层
3+
> 本页只说明:不同 Agent 如何接入 `CortexOS` 中央大脑。
4+
> 它不是舰队编排页,也不是指挥链说明页。
55
66
---
77

8-
## 舰队能力速查
8+
## Agent 能力速查
99

1010
| Agent | 模型 | 配置位置 | 独家能力 | 花钱? |
1111
| :--- | :--- | :--- | :--- | :--- |
12-
| **🌸 栖月** (队长) | Claude Sonnet 4.6 | OpenClaw (`~/.openclaw/`) | 战略/任务书/质量把关 | 💸 是 |
12+
| **OpenClaw** | Claude Sonnet 4.6 | OpenClaw (`~/.openclaw/`) | 高强度执行 / 复杂上下文协作 | 💸 是 |
1313
| **Codex** | gpt-5.3-codex | `~/.codex/config.toml` | 全自动执行(approval=never) | 🆓 免费 |
1414
| **Gemini CLI** | Gemini 2.0 Flash | `~/.gemini/settings.json` | 图像生成(nanobanana-plus) | 🆓 免费 |
1515
| **Claude Code** | Claude v2.1.12 | `~/.claude/settings.json` | frontend-design/think skill | 🆓 Antigravity额度 |
1616
| **OpenCode** || `.opencode/` | 项目级执行 ||
1717

18-
**派单原则**: 图像→Gemini / 代码→Codex / 前端设计→Claude Code / 战略→栖月
18+
**推荐分工**: 图像→Gemini / 代码→Codex / 前端设计→Claude Code / 项目级执行→OpenClaw
1919

2020
---
2121

@@ -25,7 +25,7 @@
2525

2626
| Agent | 启动指令 |
2727
| :--- | :--- |
28-
| 栖月 | `cortexos brief`(OpenClaw 内直接调用) |
28+
| OpenClaw | `cortexos brief`(OpenClaw 内直接调用) |
2929
| Gemini CLI | `cortexos brief`(GEMINI.md 配置) |
3030
| Codex | `cortexos brief`(AGENTS.md 配置) |
3131
| Claude Code | `cortexos brief`(CLAUDE.md 配置) |
@@ -36,7 +36,8 @@
3636

3737
## 详细档案
3838

39-
- 🌸 [栖月档案](./qiyue/README.md) | [小龙虾手册](./qiyue/openclaw.md)
39+
- [OpenClaw / 小龙虾手册](./qiyue/openclaw.md)
40+
- CortexOS 身份真源:`IDENTITY.md`
4041
- [Gemini 配置档案](./gemini/README.md)
4142
- [Codex 配置档案](./codex/README.md)
4243
- [Claude Code 配置档案](./claude/README.md)
@@ -48,5 +49,4 @@
4849

4950
- 新增 Agent 时在 `docs/agents/<agent>/` 建目录并补 `README.md`
5051
- 各 Agent 的启动配置文件(GEMINI.md / AGENTS.md / CLAUDE.md)统一指向 `cortexos brief`
51-
- 配置变更后必须同步更新本页"舰队能力速查"表
52-
- 指挥官变更时更新页面顶部的"当前指挥官"字段
52+
- 配置变更后必须同步更新本页"Agent 能力速查"表

docs/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
layout: home
33
hero:
44
name: "CortexOS"
5-
text: " Agent 协同外部大脑"
6-
tagline: "让 Gemini、Claude、Codex 共享同一个大脑 —— 动态路由注入、上下文极简、多模型逻辑对齐。"
5+
text: "AI Agent 中央大脑"
6+
tagline: "让 Gemini、Claude、Codex 与各类 subagent 共享同一个中央大脑 —— 动态路由注入、上下文极简、多模型逻辑对齐。"
77
image:
88
src: /logo.svg
99
alt: CortexOS

docs/ops/brain-tui.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pnpm brain:tui
3434
- `r`:刷新一次
3535
- `n`:聚焦通知表
3636
- `t`:聚焦任务表
37+
- `i`:查看本机与远端节点清单
3738
- `s`:查看完整 Skills 清单
3839
- `m`:查看完整 MCP 清单
3940
- `a`:查看完整对外 API 接口与功能说明

services/brain-tui/src/brain_tui/app.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ class BrainTuiApp(App):
8787
("r", "refresh", "刷新"),
8888
("n", "focus_notifications", "通知"),
8989
("t", "focus_tasks", "任务"),
90+
("i", "show_nodes", "节点"),
9091
("a", "show_api", "API"),
9192
("s", "show_skills", "Skills"),
9293
("m", "show_mcp", "MCP"),
@@ -163,6 +164,10 @@ def action_show_api(self) -> None:
163164
self.detail_mode = "api"
164165
self.update_detail()
165166

167+
def action_show_nodes(self) -> None:
168+
self.detail_mode = "nodes"
169+
self.update_detail()
170+
166171
def refresh_snapshot(self) -> None:
167172
self.snapshot = build_snapshot()
168173
self.render_snapshot()
@@ -198,8 +203,15 @@ def render_snapshot(self) -> None:
198203
"运行态",
199204
[
200205
f"brain-cortex-pilot:{snapshot.pilot_status} · 重启 {snapshot.pilot_restarts} 次",
206+
f"本机:{snapshot.local_node.get('hostname')} · {snapshot.local_node.get('ip')}",
207+
(
208+
f"远端:{snapshot.remote_nodes[0].get('node_id')} · "
209+
f"{snapshot.remote_nodes[0].get('ip')}"
210+
if snapshot.remote_nodes
211+
else "远端:当前没有已上报节点"
212+
),
201213
"前台形态:终端 TUI(brain-tui)",
202-
"外部入口:CLI + HTTP API",
214+
"按 I 看完整节点清单",
203215
],
204216
)
205217
endpoint_lines = [f"Base URL:{snapshot.api_base_url}"]
@@ -331,6 +343,35 @@ def update_detail(self) -> None:
331343
)
332344
return
333345

346+
if self.detail_mode == "nodes":
347+
local = snapshot.local_node
348+
remote = snapshot.remote_nodes
349+
lines = [
350+
"[b]节点清单[/b]",
351+
"",
352+
"本机节点:",
353+
f"1. {local.get('name')} · {local.get('hostname')}",
354+
f" IP:{local.get('ip')}",
355+
f" 环境:{local.get('environment')} · 区域:{local.get('region')}",
356+
"",
357+
"远端节点:",
358+
]
359+
if remote:
360+
for index, item in enumerate(remote, start=1):
361+
lines.extend(
362+
[
363+
f"{index}. {item.get('name')} · {item.get('node_id')}",
364+
f" IP:{item.get('ip')}",
365+
f" 主机:{item.get('hostname')}",
366+
f" 环境:{item.get('environment')} · 区域:{item.get('region')}",
367+
f" 模型:{item.get('model')} · 来源:{item.get('source')}",
368+
]
369+
)
370+
else:
371+
lines.append("当前没有远端节点汇报。")
372+
detail_widget.update("\n".join(lines))
373+
return
374+
334375
if self.selected_notification_id:
335376
selected_notification = next(
336377
(

services/brain-tui/src/brain_tui/data.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import json
44
import os
55
import re
6+
import socket
67
import subprocess
78
from dataclasses import dataclass
89
from pathlib import Path
@@ -26,6 +27,8 @@
2627
@dataclass
2728
class BrainSnapshot:
2829
api_base_url: str
30+
local_node: dict[str, str]
31+
remote_nodes: list[dict[str, str]]
2932
cloud_online: bool
3033
cloud_version: str
3134
notifications_total: int
@@ -221,6 +224,81 @@ def list_api_endpoints() -> list[tuple[str, str, str]]:
221224
]
222225

223226

227+
def get_local_node() -> dict[str, str]:
228+
hostname = socket.gethostname()
229+
ip = ""
230+
for iface in ("en0", "en1", "bridge0"):
231+
try:
232+
out = subprocess.check_output(["ipconfig", "getifaddr", iface], text=True).strip()
233+
if out:
234+
ip = out
235+
break
236+
except Exception:
237+
continue
238+
if not ip:
239+
try:
240+
ip = socket.gethostbyname(hostname)
241+
except Exception:
242+
ip = "未识别"
243+
return {
244+
"name": "本机终端",
245+
"node_id": "local-terminal",
246+
"hostname": hostname,
247+
"ip": ip or "未识别",
248+
"environment": "local",
249+
"region": "asia-shanghai",
250+
"source": "cortexos",
251+
}
252+
253+
254+
def _extract_public_ip(item: dict) -> str:
255+
metadata = item.get("metadata") or {}
256+
for key in ("publicIp", "public_ip", "nodeIp", "node_ip", "ip"):
257+
value = str(metadata.get(key) or "").strip()
258+
if value:
259+
return value
260+
content = str(item.get("content") or "")
261+
matches = re.findall(r"\b(?:\d{1,3}\.){3}\d{1,3}\b", content)
262+
for ip in matches:
263+
if not ip.startswith("127."):
264+
return ip
265+
return "未上报"
266+
267+
268+
def list_remote_nodes(notifications: list[dict], limit: int = 8) -> list[dict[str, str]]:
269+
seen: set[str] = set()
270+
nodes: list[dict[str, str]] = []
271+
for item in notifications:
272+
metadata = item.get("metadata") or {}
273+
node_id = str(
274+
metadata.get("nodeId")
275+
or metadata.get("node_id")
276+
or item.get("source")
277+
or item.get("agent")
278+
or ""
279+
).strip()
280+
if not node_id or node_id == "cortexos":
281+
continue
282+
if node_id in seen:
283+
continue
284+
seen.add(node_id)
285+
nodes.append(
286+
{
287+
"name": str(metadata.get("nodeName") or metadata.get("node_name") or item.get("source") or node_id),
288+
"node_id": node_id,
289+
"source": str(item.get("source") or item.get("agent") or "unknown"),
290+
"model": str(metadata.get("model") or item.get("agent") or "unknown"),
291+
"environment": str(metadata.get("environment") or "unknown"),
292+
"region": str(metadata.get("region") or "unknown"),
293+
"hostname": str(metadata.get("hostname") or "unknown"),
294+
"ip": _extract_public_ip(item),
295+
}
296+
)
297+
if len(nodes) >= limit:
298+
break
299+
return nodes
300+
301+
224302
def _parse_listen_name(name: str) -> tuple[str, str, str]:
225303
text = (name or "").strip()
226304
if not text:
@@ -304,6 +382,8 @@ def build_snapshot() -> BrainSnapshot:
304382

305383
return BrainSnapshot(
306384
api_base_url=BRAIN_API_URL,
385+
local_node=get_local_node(),
386+
remote_nodes=list_remote_nodes(notifications),
307387
cloud_online=cloud_online,
308388
cloud_version=cloud_version,
309389
notifications_total=len(notifications),

0 commit comments

Comments
 (0)