tllongdev/chronicle
GitHub: tllongdev/chronicle
Chronicle 是一个纵向情报层工具,将重复采集的 OSINT 快照存入双时态数据库,支持变更检测、实体时间线重构和时间滑块回放,弥补传统情报工具缺乏时间维度的不足。
Stars: 0 | Forks: 0
```
_____ _ _ _
/ ____| | (_) | |
| | | |__ _ __ ___ _ __ _ ___| | ___
| | | '_ \| '__/ _ \| '_ \| |/ __| |/ _ \
| |____| | | | | | (_) | | | | | (__| | __/ longitudinal
\_____|_| |_|_| \___/|_| |_|_|\___|_|\___| intelligence
```
**纵向情报层。** 大多数 OSINT 和情报工具只为您提供一个快照:当前谁与谁有联系。Chronicle 添加了缺失的维度——**时间**。向其输入对同一目标重复捕获的数据,它会将其折叠到双时态存储中,然后告诉您出现了什么、发生了什么变化、什么消失了,并允许您在滑块上*重放整个过程*。
将其视为位于 [Scout](https://github.com/tllongdev/scout) 等**传感器**背后的**记忆**:Scout 负责收集;Chronicle 负责记忆并追踪变化。
- **设计上的双时态** - 每个实体、关系和属性都根据*其生效的时间*和*您获知它的时间*进行版本控制,并附带来源。没有任何内容会被覆盖。
- **变更检测** - 任意两次捕获之间的精确差异:包括添加/删除/更改的实体和关系,精确到字段。
- **实体时间线** - 重构任何实体的带日期历史:首次出现、每次更改、何时消失或重现。
- **时间擦除图** - 带有滑块(和播放按钮)的交互式 HTML 图表,以动画形式展示情报全貌的演变过程。
- **格式友好** - 开箱即用地支持 Scout 的 `mission.json`,或任何具有相同 `entities` / `edges` / `observations` 结构的 JSON 数据。
## 快速开始(60 秒,无需密钥,无需账户)
```
git clone https://github.com/tllongdev/chronicle.git
cd chronicle
pip install -e . # or: uv pip install -e .
# 摄取同一主体的两个时间点快照
chronicle ingest samples/acme-2026-01-15.json samples/acme-2026-04-20.json
# 它们之间发生了什么变化?
chronicle diff
# 一个实体是如何演进的?
chronicle timeline "Acme Robotics"
# 在时间滑块上重放全貌
chronicle graph && open output/timeline.html
```
内置示例讲述了一个逼真的故事:一家机器人初创公司在三个月内员工人数翻倍,更换了创始人 CEO,成立了一家国防子公司,经历了投资者更迭,并任命了一位**受制裁的董事**——这正是单次时间点扫描会遗漏的那种演变。
### 使用 Docker
```
./run.sh ingest samples/acme-2026-01-15.json samples/acme-2026-04-20.json
./run.sh diff
./run.sh graph # writes output/timeline.html on the host
```
## 命令
| 命令 | 功能描述 |
|---|---|
| `chronicle ingest ` | 将一个或多个快照合并到存储中(使用 `--label`、`--at` 进行覆盖) |
| `chronicle log` | 按时间顺序列出已摄入的快照 |
| `chronicle diff [FROM] [TO]` | 两个快照之间的变更报告(默认为最后两个;`--save report.md`) |
| `chronicle timeline ""` | 匹配实体的按时间排序的历史记录 |
| `chronicle graph` | 渲染时间擦除 HTML 图表(`--out path.html`) |
**快照引用**可以是标签、索引(`0`、`1`、`-1`)或 `first` / `latest`。
存储文件位于 `./chronicle.db`(使用 `CHRONICLE_DB` 进行覆盖)。
### 示例:`chronicle diff`
```
Change report acme-2026-01-15@2026-01-15 -> acme-2026-04-20@2026-04-20
Entities added (4)
• Mark Vale (person)
• Acme Defense LLC (organization)
• Orion Ventures (organization)
• Viktor Sokolov (person)
Entities removed (1)
• Nimbus Capital (organization)
Entities changed (2)
• Acme Robotics (organization): ceo: 'Jane Doe' -> 'Mark Vale'; employees: '120' -> '260'; ...
• Jane Doe (person): role: 'CEO' -> 'Board Member'
```
## 工作原理
```
Snapshot 1 Snapshot 2 Snapshot N
(Scout mission) (Scout mission) ...
| | |
+--------+--------+-----------------+
v
┌───────────────────────────┐
│ ingest / identity │ entity_key = type + name
│ resolution │ (pluggable: swap in a real id)
└───────────────────────────┘
v
┌───────────────────────────┐
│ bitemporal SQLite store │ append-only version rows
│ (observed vs valid time) │ + per-snapshot presence rows
└───────────────────────────┘
v
┌─────────────┬──────────────┬──────────────┐
v v v v
diff timeline graph log
(what (entity (time-scrub (snapshots
changed) history) HTML) over time)
```
**为什么采用仅追加 + 状态行的设计?** 版本行仅在值首次出现或实际发生更改时写入,因此历史记录既紧凑又无损。每个快照的*状态*行使得两次捕获之间添加/删除的检测变得精确,并允许 Chronicle 重构任意时间点*当时状况*的全貌。
**身份解析**目前依赖于归一化的 `type + name`。这是在生产环境中使用时需要扩展的唯一接缝——植入一个解析器(模糊匹配,或像 Tamr `tamr_id` 这样的共享主 ID),系统的其余部分保持不变。
## 项目结构
```
src/chronicle/
models.py # Snapshot inputs + diff/timeline result types (pydantic)
ingest.py # load a Scout mission.json (or compatible) into a Snapshot
store.py # the bitemporal SQLite store: ingest, point-in-time queries, diff, timeline
graph.py # time-scrub HTML (vis-network) rendering
report.py # rich console + markdown rendering of diffs and timelines
cli.py # ingest / log / diff / timeline / graph
samples/ # two snapshots that tell a story
```
## 适用场景
Chronicle 是**纵向情报**的概念验证——核心理念是:当您妥善保存、进行版本控制并观察其变化时,所收集情报的价值会不断累积。将其与收集器(如 Scout)按计划配对使用,您将获得一个动态的、可审计的全貌,而不是一堆互不相关的报告:变更警报、可重构的时间线,以及每项声明的来源。
这是一个早期的单操作员工具,而不是经过加固的生产级服务。它是构建这些理念的一个干净、可自托管的基础平台。
## 许可证
MIT - 请参阅 [LICENSE](LICENSE)。
标签:变更检测, 情报分析, 数据版本控制, 时序数据, 网络诊断, 请求拦截, 逆向工具