Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## 1.3.0

- Add explicit, disabled-by-default imports for Git commit history, GitHub pull requests and issues, Claude Web exports, ChatGPT exports, and Cursor transcripts.
- Keep external collection local, read-only, incremental, secret-redacted, and limited to user-registered paths.
- Surface each external source and Feishu Mail separately in the control center without exposing local paths.
- Include external-source deduplication state in portable recovery exports.
- Run enabled external sources through the normal orchestrator and report partial or failed collection honestly.
- Preserve every v1.1 Living Self, transaction, migration, recovery, and dashboard capability by releasing from the current `main` architecture.

## 1.1.1

- Mark a loaded daily LaunchAgent as requiring attention when its most recent exit code is nonzero, and expose the code as bounded scheduler evidence instead of showing a false healthy state.
Expand Down
38 changes: 34 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<div align="center">

![Version](https://img.shields.io/badge/version-v1.1.1-111827.svg)
![Version](https://img.shields.io/badge/version-v1.3.0-111827.svg)
![Python](https://img.shields.io/badge/python-3.9%2B-3776AB.svg?logo=python&logoColor=white)
![Platform](https://img.shields.io/badge/platform-Codex%20%7C%20Claude%20Code%20%7C%20Local%20Agent-0F766E.svg)
![License](https://img.shields.io/badge/license-MIT-059669.svg)
Expand All @@ -27,7 +27,7 @@

要让它说出像你会说的话、按你会做的判断去做事,只有一个办法:用**足够高密度的个人上下文**,把它从共识里硬拽出来。

Immortal Memory 就是干这件事的本地系统。它不是一句 prompt,也不只是一个 Codex 技能。v1.1 用五个可追溯层完成这件事:
Immortal Memory 就是干这件事的本地系统。它不是一句 prompt,也不只是一个 Codex 技能。v1.3 在 v1.1 Living Self 架构上,用五个可追溯层完成这件事:

1. **Claim**:把原始痕迹变成带出处、作用域、归因和隐私标签的可纠正主张。
2. **Living Self**:只用已确认 Claim 生成有版本的「当前自我」,旧版本永不原地覆盖。
Expand Down Expand Up @@ -110,6 +110,36 @@ immortal-memory agent-entry
immortal-memory agent-context "help me review this product idea" --print
```

### 自动接入你的高质量语料

v1.3 支持五类显式登记的外部来源。全部默认关闭,只有你登记的文件或目录才会被读取:

```bash
# 本地 Git 提交历史,只读取提交元数据和提交说明,不读取代码正文
immortal-memory source register git "/absolute/path/to/projects"

# GitHub PR 和 Issue,只读调用本机已登录的 gh CLI
immortal-memory source register github "/absolute/path/to/projects"

# 官方导出的对话文件或 Cursor transcript 目录
immortal-memory source register claude-web "/absolute/path/to/conversations.json"
immortal-memory source register chatgpt "/absolute/path/to/conversations.json"
immortal-memory source register cursor "/absolute/path/to/cursor/agent-transcripts"

# 检查登记范围并立即执行一次增量采集
immortal-memory source list --json
immortal-memory source collect --json
```

每条记录在写入前都会做凭证形态脱敏,并用本地 SQLite 状态去重。每日编排会自动调用已启用来源。控制台只展示来源健康、更新时间、新增数和错误数,不展示本机私有路径。飞书邮件继续保持显式授权,不会因为安装产品而自动采集。

### 支持环境与 Agent

- macOS:完整支持,包括 LaunchAgent 每日自动化、Codex 和 Claude Code 适配器。
- Linux:核心 CLI、HTTP Agent Bridge、MCP、采集和测试受支持;需要自行配置 systemd 或 cron 调度。
- Windows:当前不支持生产运行,因为索引锁依赖 `fcntl.flock`。建议使用 WSL2,并自行配置调度。
- Agent:Codex、Claude Code、终端 Agent,以及任何能调用 CLI、HTTP 或 MCP 的本地 Agent。适配器只负责发现入口,真实记忆仍由同一套核心权限和上下文合同控制。

打开本地控制台:

```bash
Expand Down Expand Up @@ -212,7 +242,7 @@ immortal-memory agent-context "release acceptance" --print
```bash
CLEAN_HOME="$(mktemp -d /tmp/immortal-clean-home.XXXXXX)"
python3 -m venv "$CLEAN_HOME/venv"
WHEEL="$(find "$(pwd)/dist" -maxdepth 1 -name 'immortal_memory-1.1.1-*.whl' | head -n 1)"
WHEEL="$(find "$(pwd)/dist" -maxdepth 1 -name 'immortal_memory-1.3.0-*.whl' | head -n 1)"
HOME="$CLEAN_HOME" "$CLEAN_HOME/venv/bin/python" -m pip install "$WHEEL"
HOME="$CLEAN_HOME" "$CLEAN_HOME/venv/bin/immortal-memory" init --owner-display-name "Clean Install" --alias "clean"
HOME="$CLEAN_HOME" "$CLEAN_HOME/venv/bin/immortal-memory" train --smoke
Expand Down Expand Up @@ -314,7 +344,7 @@ There is a sharper problem underneath. A large model is wired to produce **confi

To make it say what you would say and decide the way you would decide, there is only one move: push **high-density personal context** at it until it gets dragged out of the consensus prior.

Immortal Memory is the local system that does exactly that. It is not a prompt, and not only a Codex skill. v1.1 implements five traceable layers:
Immortal Memory is the local system that does exactly that. It is not a prompt, and not only a Codex skill. v1.3 builds on the v1.1 Living Self architecture and implements five traceable layers:

1. **Claim** turns source traces into correctable assertions with evidence, scope, attribution, and privacy labels.
2. **Living Self** builds a versioned current model from confirmed Claims without overwriting history.
Expand Down
2 changes: 1 addition & 1 deletion core/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.1.1
1.3.0
7 changes: 7 additions & 0 deletions core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@
},
},
"extra_sources": [],
"external_sources": {
"git": {"enabled": False, "paths": [], "max_commits": 200},
"github": {"enabled": False, "paths": [], "max_items": 50},
"claude-web": {"enabled": False, "paths": []},
"chatgpt": {"enabled": False, "paths": []},
"cursor": {"enabled": False, "paths": []},
},
}


Expand Down
38 changes: 38 additions & 0 deletions core/control_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,13 @@ def _source_status(value: Any, *, has_success: bool = False) -> str:
def sources(self) -> dict[str, Any]:
state = self._read_json(self.immortal_dir / "orchestrator_state.json")
web = self._read_json(self.immortal_dir / "web" / "state.json")
config = self._read_json(self.immortal_dir / "config.json")
feishu = config.get("feishu") if isinstance(config.get("feishu"), dict) else {}
daily_sources = {item.strip() for item in str(feishu.get("daily_sources") or "").split(",") if item.strip()}
external_config = config.get("external_sources") if isinstance(config.get("external_sources"), dict) else {}
external_state = self._read_json(self.immortal_dir / "external_sources" / "state.json")
external_results = external_state.get("sources") if isinstance(external_state.get("sources"), dict) else {}
external_last = str(external_state.get("generated_at") or "")
source_specs = [
{
"id": "local",
Expand All @@ -416,6 +423,37 @@ def sources(self) -> dict[str, Any]:
"errors": sum("feishu" in str(item) for item in (state.get("errors") or [])),
"evidence": "feishu/state.json",
},
{
"id": "feishu-mail",
"label": "飞书邮件(显式授权)",
"last": str(state.get("last_feishu_collect") or "") if "mail" in daily_sources else "",
"status": self._source_status(state.get("last_feishu_status"), has_success=bool(state.get("last_feishu_collect")))
if "mail" in daily_sources else "skipped",
"increment": 0,
"errors": 0,
"evidence": "config.json + feishu/state.json",
},
*[
{
"id": source_id,
"label": label,
"last": external_last if enabled else "",
"status": self._source_status(result.get("status"), has_success=bool(external_last)) if enabled else "skipped",
"increment": int(result.get("records_written") or 0),
"errors": int(result.get("error_count") or 0),
"evidence": "config.json + external_sources/state.json",
}
for kind, source_id, label in (
("git", "git-history", "Git 本地历史"),
("github", "github-history", "GitHub PR / Issue"),
("claude-web", "claude-web", "Claude Web 导出"),
("chatgpt", "chatgpt", "ChatGPT 导出"),
("cursor", "cursor", "Cursor 导出"),
)
for configured in [external_config.get(kind) if isinstance(external_config.get(kind), dict) else {}]
for enabled in [bool(configured.get("enabled") and configured.get("paths"))]
for result in [external_results.get(kind) if isinstance(external_results.get(kind), dict) else {}]
],
{
"id": "web",
"label": "网页访问",
Expand Down
1 change: 1 addition & 0 deletions core/export_restore.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"people",
"quality",
"relationships",
"external_sources",
# timeline.html / dashboard.html / brief 已于 2026-06-14 停用并删除;
# 留在白名单里会让每个新导出都带 missing 警告,strict 校验对完好数据永久 FAIL
"digests",
Expand Down
Loading
Loading