agents-memory 0.42__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agents_memory-0.42/LICENSE +21 -0
- agents_memory-0.42/PKG-INFO +148 -0
- agents_memory-0.42/README.md +137 -0
- agents_memory-0.42/pyproject.toml +21 -0
- agents_memory-0.42/setup.cfg +4 -0
- agents_memory-0.42/src/agent_memory/__init__.py +18 -0
- agents_memory-0.42/src/agent_memory/__main__.py +92 -0
- agents_memory-0.42/src/agent_memory/cli_help.py +166 -0
- agents_memory-0.42/src/agent_memory/consolidate.py +22 -0
- agents_memory-0.42/src/agent_memory/extract_openai.py +102 -0
- agents_memory-0.42/src/agent_memory/ingest.py +110 -0
- agents_memory-0.42/src/agent_memory/ingest_catalog.py +346 -0
- agents_memory-0.42/src/agent_memory/ingest_chats.py +14 -0
- agents_memory-0.42/src/agent_memory/ingest_common.py +170 -0
- agents_memory-0.42/src/agent_memory/ingest_config.py +245 -0
- agents_memory-0.42/src/agent_memory/ingest_extractors.py +374 -0
- agents_memory-0.42/src/agent_memory/inventory.py +101 -0
- agents_memory-0.42/src/agent_memory/mcp_server.py +313 -0
- agents_memory-0.42/src/agent_memory/store.py +2211 -0
- agents_memory-0.42/src/agent_memory/sync.py +67 -0
- agents_memory-0.42/src/agents_memory.egg-info/PKG-INFO +148 -0
- agents_memory-0.42/src/agents_memory.egg-info/SOURCES.txt +34 -0
- agents_memory-0.42/src/agents_memory.egg-info/dependency_links.txt +1 -0
- agents_memory-0.42/src/agents_memory.egg-info/entry_points.txt +2 -0
- agents_memory-0.42/src/agents_memory.egg-info/requires.txt +1 -0
- agents_memory-0.42/src/agents_memory.egg-info/top_level.txt +1 -0
- agents_memory-0.42/tests/test_auto_triggering.py +163 -0
- agents_memory-0.42/tests/test_cli_comprehensive.py +97 -0
- agents_memory-0.42/tests/test_cli_help.py +52 -0
- agents_memory-0.42/tests/test_distill_benchmark.py +369 -0
- agents_memory-0.42/tests/test_extract_filters.py +125 -0
- agents_memory-0.42/tests/test_extract_openai.py +39 -0
- agents_memory-0.42/tests/test_ingest.py +103 -0
- agents_memory-0.42/tests/test_ingest_pipeline.py +114 -0
- agents_memory-0.42/tests/test_mcp_server.py +215 -0
- agents_memory-0.42/tests/test_store.py +402 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Felix Kempf, Fabian Schindler
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agents-memory
|
|
3
|
+
Version: 0.42
|
|
4
|
+
Summary: Local markdown memory for coding agents — ABI in abi/, Python MCP reference implementation
|
|
5
|
+
Author: Felix Kempf, Fabian Schindler
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: mcp>=1.0.0
|
|
10
|
+
Dynamic: license-file
|
|
11
|
+
|
|
12
|
+
# agent-memory
|
|
13
|
+
|
|
14
|
+
<p align="left">
|
|
15
|
+
<a href="https://github.com/Lolaplex/agent-memory/releases"><img src="https://img.shields.io/badge/version-0.42-blue.svg?style=flat-square" alt="Version 0.42"></a>
|
|
16
|
+
<a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-Standard-orange.svg?style=flat-square" alt="MCP"></a>
|
|
17
|
+
<a href="https://python.org"><img src="https://img.shields.io/badge/Python-3.10+-3776AB.svg?style=flat-square&logo=python&logoColor=white" alt="Python 3.10+"></a>
|
|
18
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg?style=flat-square" alt="License"></a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
**Local markdown memory & cross-agent context engine for AI coding assistants.**
|
|
22
|
+
One persistent identity, shared across **Claude Code**, **Cursor**, **Antigravity**, and **Zed**.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Why agent-memory?
|
|
27
|
+
|
|
28
|
+
Without a shared memory layout, **every AI tool lives in its own silo**:
|
|
29
|
+
- Each vendor locks chat history in proprietary local databases or remote clouds.
|
|
30
|
+
- Switching IDEs or agents means starting from scratch and repeating preferences.
|
|
31
|
+
- Vector DBs and RAG solutions add infrastructure complexity, drift out of date, and are not human-editable.
|
|
32
|
+
|
|
33
|
+
`agent-memory` solves this with a **pure Markdown-first architecture**:
|
|
34
|
+
- **Local & Offline:** Your identity and repo memory live in plain files (`~/.agents/memory/` and `<repo>/.agents/memory/`).
|
|
35
|
+
- **Human-Readable & Git-Friendly:** Edit with any text editor, diff with git, commit when you want.
|
|
36
|
+
- **Universal MCP Server:** Exposes memory tools (`search_memory`, `add_memory`, `get_project_memories`, `distill_batch`) to all modern agents.
|
|
37
|
+
- **Autonomous Ingest & Distillation:** Extracts durable rules and architecture decisions from session logs (OpenAI, Claude, Cursor, Copilot, Antigravity, Pi).
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Architecture & Flow
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
45
|
+
│ SESSION INGEST │
|
|
46
|
+
│ OpenAI Exports · Claude JSONL · Cursor · Antigravity · Pi │
|
|
47
|
+
└──────────────────────────────┬──────────────────────────────┘
|
|
48
|
+
│ ingest catalog / extract
|
|
49
|
+
▼
|
|
50
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
51
|
+
│ STAGING INBOX │
|
|
52
|
+
│ Raw captured bullets & noise-filtered facts │
|
|
53
|
+
└──────────────────────────────┬──────────────────────────────┘
|
|
54
|
+
│ distill_batch / skill
|
|
55
|
+
▼
|
|
56
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
57
|
+
│ LOCAL MEMORY STORE │
|
|
58
|
+
│ ~/.agents/memory/USER.md ~/.agents/memory/PROJECTS.md │
|
|
59
|
+
│ ~/.agents/memory/concepts/ <repo>/.agents/memory/ │
|
|
60
|
+
└──────────────┬───────────────────────────────┬──────────────┘
|
|
61
|
+
│ │
|
|
62
|
+
▼ ▼
|
|
63
|
+
┌─────────────────────────────┐ ┌─────────────────────────────┐
|
|
64
|
+
│ IDE INJECTION │ │ MCP SERVER & CLERK │
|
|
65
|
+
│ Cursor Rules · Zed Context │ │ search_memory · add_memory │
|
|
66
|
+
│ Antigravity AGENTS.md │ │ Universal Tool Integration │
|
|
67
|
+
└─────────────────────────────┘ └─────────────────────────────┘
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Quickstart
|
|
73
|
+
|
|
74
|
+
### 1. Installation
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Clone the repository
|
|
78
|
+
git clone https://github.com/Lolaplex/agent-memory.git
|
|
79
|
+
cd agent-memory
|
|
80
|
+
|
|
81
|
+
# Install in editable mode
|
|
82
|
+
python -m pip install -e .
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 2. Initialize & Sync
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Scaffold initial directories and wire into host IDEs / MCP configs
|
|
89
|
+
agent-memory sync --init
|
|
90
|
+
|
|
91
|
+
# Audit and register local repositories
|
|
92
|
+
agent-memory inventory
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Fill in `~/.agents/memory/USER.md` with your profile and stack preferences. Reload your agent to connect to the MCP server.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## CLI Reference
|
|
100
|
+
|
|
101
|
+
| Command | Purpose |
|
|
102
|
+
|---------|---------|
|
|
103
|
+
| `agent-memory sync` | Updates canonical `AGENTS.md`, host rules, and MCP registrations |
|
|
104
|
+
| `agent-memory sync --init` | First-time scaffolding and host discovery |
|
|
105
|
+
| `agent-memory inventory` | Discovers unregistered local repositories across workspace roots |
|
|
106
|
+
| `agent-memory inventory --register SLUG PATH ROLE STACK` | Registers a new repository |
|
|
107
|
+
| `agent-memory ingest catalog` | Indexes local chat transcripts across all supported providers |
|
|
108
|
+
| `agent-memory ingest extract` | Runs heuristic filters to extract durable facts into staging |
|
|
109
|
+
| `agent-memory consolidate` | Ensures no private state leaked into working repository |
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Supported Ecosystem
|
|
114
|
+
|
|
115
|
+
- **Claude Code:** Bound via symlink / canonical `AGENTS.md` and MCP server.
|
|
116
|
+
- **Google Antigravity:** Integrated via `.gemini/config` rules and `agent-memory` MCP.
|
|
117
|
+
- **Cursor:** Automatically injects rules and configures `.cursor/mcp.json`.
|
|
118
|
+
- **Zed:** Configures `context_servers` and mirrors assistant skills.
|
|
119
|
+
- **VS Code / Copilot:** Ingests session history from local state databases.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Open ABI Specification
|
|
124
|
+
|
|
125
|
+
The formal, implementation-agnostic layout specification lives in [`abi/`](abi/):
|
|
126
|
+
|
|
127
|
+
- [`abi/WHY.md`](abi/WHY.md) — Architecture decisions & why Markdown wins over RAG.
|
|
128
|
+
- [`abi/LAYOUT.md`](abi/LAYOUT.md) — Directory taxonomy and path contracts.
|
|
129
|
+
- [`abi/KINDS.md`](abi/KINDS.md) — Typed memory taxonomy (`concepts`, `facts`, `decisions`).
|
|
130
|
+
- [`abi/MCP.md`](abi/MCP.md) — Tool definitions and request/response specifications.
|
|
131
|
+
- [`abi/INGEST.md`](abi/INGEST.md) — Catalog, extract, and distillation pipeline.
|
|
132
|
+
- [`abi/INJECTION.md`](abi/INJECTION.md) — Host rule injection mechanisms.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Testing & Verification
|
|
137
|
+
|
|
138
|
+
Run the comprehensive test suite and distillation benchmark:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
python tests/run_all_tests.py
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## License
|
|
147
|
+
|
|
148
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# agent-memory
|
|
2
|
+
|
|
3
|
+
<p align="left">
|
|
4
|
+
<a href="https://github.com/Lolaplex/agent-memory/releases"><img src="https://img.shields.io/badge/version-0.42-blue.svg?style=flat-square" alt="Version 0.42"></a>
|
|
5
|
+
<a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-Standard-orange.svg?style=flat-square" alt="MCP"></a>
|
|
6
|
+
<a href="https://python.org"><img src="https://img.shields.io/badge/Python-3.10+-3776AB.svg?style=flat-square&logo=python&logoColor=white" alt="Python 3.10+"></a>
|
|
7
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg?style=flat-square" alt="License"></a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
**Local markdown memory & cross-agent context engine for AI coding assistants.**
|
|
11
|
+
One persistent identity, shared across **Claude Code**, **Cursor**, **Antigravity**, and **Zed**.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Why agent-memory?
|
|
16
|
+
|
|
17
|
+
Without a shared memory layout, **every AI tool lives in its own silo**:
|
|
18
|
+
- Each vendor locks chat history in proprietary local databases or remote clouds.
|
|
19
|
+
- Switching IDEs or agents means starting from scratch and repeating preferences.
|
|
20
|
+
- Vector DBs and RAG solutions add infrastructure complexity, drift out of date, and are not human-editable.
|
|
21
|
+
|
|
22
|
+
`agent-memory` solves this with a **pure Markdown-first architecture**:
|
|
23
|
+
- **Local & Offline:** Your identity and repo memory live in plain files (`~/.agents/memory/` and `<repo>/.agents/memory/`).
|
|
24
|
+
- **Human-Readable & Git-Friendly:** Edit with any text editor, diff with git, commit when you want.
|
|
25
|
+
- **Universal MCP Server:** Exposes memory tools (`search_memory`, `add_memory`, `get_project_memories`, `distill_batch`) to all modern agents.
|
|
26
|
+
- **Autonomous Ingest & Distillation:** Extracts durable rules and architecture decisions from session logs (OpenAI, Claude, Cursor, Copilot, Antigravity, Pi).
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Architecture & Flow
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
34
|
+
│ SESSION INGEST │
|
|
35
|
+
│ OpenAI Exports · Claude JSONL · Cursor · Antigravity · Pi │
|
|
36
|
+
└──────────────────────────────┬──────────────────────────────┘
|
|
37
|
+
│ ingest catalog / extract
|
|
38
|
+
▼
|
|
39
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
40
|
+
│ STAGING INBOX │
|
|
41
|
+
│ Raw captured bullets & noise-filtered facts │
|
|
42
|
+
└──────────────────────────────┬──────────────────────────────┘
|
|
43
|
+
│ distill_batch / skill
|
|
44
|
+
▼
|
|
45
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
46
|
+
│ LOCAL MEMORY STORE │
|
|
47
|
+
│ ~/.agents/memory/USER.md ~/.agents/memory/PROJECTS.md │
|
|
48
|
+
│ ~/.agents/memory/concepts/ <repo>/.agents/memory/ │
|
|
49
|
+
└──────────────┬───────────────────────────────┬──────────────┘
|
|
50
|
+
│ │
|
|
51
|
+
▼ ▼
|
|
52
|
+
┌─────────────────────────────┐ ┌─────────────────────────────┐
|
|
53
|
+
│ IDE INJECTION │ │ MCP SERVER & CLERK │
|
|
54
|
+
│ Cursor Rules · Zed Context │ │ search_memory · add_memory │
|
|
55
|
+
│ Antigravity AGENTS.md │ │ Universal Tool Integration │
|
|
56
|
+
└─────────────────────────────┘ └─────────────────────────────┘
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Quickstart
|
|
62
|
+
|
|
63
|
+
### 1. Installation
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Clone the repository
|
|
67
|
+
git clone https://github.com/Lolaplex/agent-memory.git
|
|
68
|
+
cd agent-memory
|
|
69
|
+
|
|
70
|
+
# Install in editable mode
|
|
71
|
+
python -m pip install -e .
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. Initialize & Sync
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Scaffold initial directories and wire into host IDEs / MCP configs
|
|
78
|
+
agent-memory sync --init
|
|
79
|
+
|
|
80
|
+
# Audit and register local repositories
|
|
81
|
+
agent-memory inventory
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Fill in `~/.agents/memory/USER.md` with your profile and stack preferences. Reload your agent to connect to the MCP server.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## CLI Reference
|
|
89
|
+
|
|
90
|
+
| Command | Purpose |
|
|
91
|
+
|---------|---------|
|
|
92
|
+
| `agent-memory sync` | Updates canonical `AGENTS.md`, host rules, and MCP registrations |
|
|
93
|
+
| `agent-memory sync --init` | First-time scaffolding and host discovery |
|
|
94
|
+
| `agent-memory inventory` | Discovers unregistered local repositories across workspace roots |
|
|
95
|
+
| `agent-memory inventory --register SLUG PATH ROLE STACK` | Registers a new repository |
|
|
96
|
+
| `agent-memory ingest catalog` | Indexes local chat transcripts across all supported providers |
|
|
97
|
+
| `agent-memory ingest extract` | Runs heuristic filters to extract durable facts into staging |
|
|
98
|
+
| `agent-memory consolidate` | Ensures no private state leaked into working repository |
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Supported Ecosystem
|
|
103
|
+
|
|
104
|
+
- **Claude Code:** Bound via symlink / canonical `AGENTS.md` and MCP server.
|
|
105
|
+
- **Google Antigravity:** Integrated via `.gemini/config` rules and `agent-memory` MCP.
|
|
106
|
+
- **Cursor:** Automatically injects rules and configures `.cursor/mcp.json`.
|
|
107
|
+
- **Zed:** Configures `context_servers` and mirrors assistant skills.
|
|
108
|
+
- **VS Code / Copilot:** Ingests session history from local state databases.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Open ABI Specification
|
|
113
|
+
|
|
114
|
+
The formal, implementation-agnostic layout specification lives in [`abi/`](abi/):
|
|
115
|
+
|
|
116
|
+
- [`abi/WHY.md`](abi/WHY.md) — Architecture decisions & why Markdown wins over RAG.
|
|
117
|
+
- [`abi/LAYOUT.md`](abi/LAYOUT.md) — Directory taxonomy and path contracts.
|
|
118
|
+
- [`abi/KINDS.md`](abi/KINDS.md) — Typed memory taxonomy (`concepts`, `facts`, `decisions`).
|
|
119
|
+
- [`abi/MCP.md`](abi/MCP.md) — Tool definitions and request/response specifications.
|
|
120
|
+
- [`abi/INGEST.md`](abi/INGEST.md) — Catalog, extract, and distillation pipeline.
|
|
121
|
+
- [`abi/INJECTION.md`](abi/INJECTION.md) — Host rule injection mechanisms.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Testing & Verification
|
|
126
|
+
|
|
127
|
+
Run the comprehensive test suite and distillation benchmark:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
python tests/run_all_tests.py
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## License
|
|
136
|
+
|
|
137
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "agents-memory"
|
|
7
|
+
version = "0.42"
|
|
8
|
+
description = "Local markdown memory for coding agents — ABI in abi/, Python MCP reference implementation"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "Felix Kempf" },
|
|
12
|
+
{ name = "Fabian Schindler" },
|
|
13
|
+
]
|
|
14
|
+
requires-python = ">=3.10"
|
|
15
|
+
dependencies = ["mcp>=1.0.0"]
|
|
16
|
+
|
|
17
|
+
[project.scripts]
|
|
18
|
+
agent-memory = "agent_memory.__main__:main"
|
|
19
|
+
|
|
20
|
+
[tool.setuptools.packages.find]
|
|
21
|
+
where = ["src"]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Local markdown memory — reference implementation of the agent-memory ABI."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
__all__ = ["ROOT", "__version__"]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _engine_root() -> Path:
|
|
10
|
+
here = Path(__file__).resolve().parent
|
|
11
|
+
for path in [here, *here.parents]:
|
|
12
|
+
if (path / "abi" / "VERSION").is_file():
|
|
13
|
+
return path
|
|
14
|
+
return here.parents[2]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
ROOT = _engine_root()
|
|
18
|
+
__version__ = (ROOT / "abi" / "VERSION").read_text(encoding="utf-8").strip()
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
# Bootstrap src/ on sys.path if invoked without editable install
|
|
5
|
+
_SRC_DIR = str(Path(__file__).resolve().parent.parent)
|
|
6
|
+
if _SRC_DIR not in sys.path:
|
|
7
|
+
sys.path.insert(0, _SRC_DIR)
|
|
8
|
+
|
|
9
|
+
if hasattr(sys.stdout, "reconfigure"):
|
|
10
|
+
try:
|
|
11
|
+
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
12
|
+
except Exception:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
USAGE = """Usage: python -m agent_memory COMMAND [args]
|
|
16
|
+
|
|
17
|
+
Commands:
|
|
18
|
+
sync Rewrite always-on injection
|
|
19
|
+
inventory Disk vs PROJECTS.md
|
|
20
|
+
ingest Catalog / extract pipeline
|
|
21
|
+
consolidate Move clone leaks into ~/.agents/memory
|
|
22
|
+
extract-openai Filter Open AI GDPR export into staging
|
|
23
|
+
distill Inspect staging inbox for distillation
|
|
24
|
+
mcp stdio MCP server
|
|
25
|
+
help-json Machine-readable CLI + injection spec
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def main(argv: list[str] | None = None) -> int:
|
|
30
|
+
args = list(argv if argv is not None else sys.argv[1:])
|
|
31
|
+
if not args or args[0] in ("-h", "--help"):
|
|
32
|
+
print(USAGE, end="")
|
|
33
|
+
return 0 if args else 2
|
|
34
|
+
if args[0] in ("--help-json", "help-json"):
|
|
35
|
+
from .cli_help import main as help_main
|
|
36
|
+
|
|
37
|
+
return help_main(["--help-json"])
|
|
38
|
+
cmd, rest = args[0], args[1:]
|
|
39
|
+
if cmd == "sync":
|
|
40
|
+
from .sync import main as run
|
|
41
|
+
|
|
42
|
+
return run(rest)
|
|
43
|
+
if cmd == "inventory":
|
|
44
|
+
from .inventory import main as run
|
|
45
|
+
|
|
46
|
+
return run(rest)
|
|
47
|
+
if cmd == "ingest":
|
|
48
|
+
from .ingest import main as run
|
|
49
|
+
|
|
50
|
+
return run(rest)
|
|
51
|
+
if cmd == "distill":
|
|
52
|
+
from .store import get_staging_inbox
|
|
53
|
+
|
|
54
|
+
inbox = get_staging_inbox(limit=15)
|
|
55
|
+
if inbox["total"] == 0:
|
|
56
|
+
print("Staging inbox is empty (all caught up).")
|
|
57
|
+
return 0
|
|
58
|
+
print(f"Staging inbox: {inbox['total']} bullets ({inbox['shown']} shown)")
|
|
59
|
+
for group in inbox["groups"]:
|
|
60
|
+
label = group.get("source") or group.get("file")
|
|
61
|
+
extra = ""
|
|
62
|
+
if group.get("truncated"):
|
|
63
|
+
extra = f" (showing {group['count']} of {group['count']}+)"
|
|
64
|
+
print(f"\n## {label}{extra}")
|
|
65
|
+
for item in group["bullets"]:
|
|
66
|
+
title = item.get("title") or ""
|
|
67
|
+
prefix = f"[{title}] " if title else ""
|
|
68
|
+
print(f"- {prefix}{item.get('text') or item.get('bullet')}")
|
|
69
|
+
print("\nTo distill, tell your Agent: 'run memory-distill' or use the memory-distill skill.")
|
|
70
|
+
return 0
|
|
71
|
+
if cmd in ("ingest-chats", "ingest_chats"):
|
|
72
|
+
from .ingest_chats import main as run
|
|
73
|
+
|
|
74
|
+
return run()
|
|
75
|
+
if cmd == "consolidate":
|
|
76
|
+
from .consolidate import main as run
|
|
77
|
+
|
|
78
|
+
return run()
|
|
79
|
+
if cmd in ("extract-openai", "extract_openai"):
|
|
80
|
+
from .extract_openai import main as run
|
|
81
|
+
|
|
82
|
+
return run(rest)
|
|
83
|
+
if cmd in ("mcp", "mcp-server", "mcp_server"):
|
|
84
|
+
from .mcp_server import main as run
|
|
85
|
+
|
|
86
|
+
return run()
|
|
87
|
+
print(f"unknown command: {cmd}\n{USAGE}", file=sys.stderr)
|
|
88
|
+
return 2
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
if __name__ == "__main__":
|
|
92
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"""Machine-readable CLI specs derived from argparse (source of truth)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
from typing import Any, List
|
|
8
|
+
|
|
9
|
+
from . import __version__ as ABI_VERSION
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _json_safe(value: Any) -> Any:
|
|
13
|
+
if value is None or isinstance(value, (bool, int, float, str)):
|
|
14
|
+
return value
|
|
15
|
+
if isinstance(value, (list, tuple)):
|
|
16
|
+
return [_json_safe(v) for v in value]
|
|
17
|
+
return str(value)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _action_spec(action: argparse.Action) -> dict[str, Any] | None:
|
|
21
|
+
if action.help is argparse.SUPPRESS:
|
|
22
|
+
return None
|
|
23
|
+
if action.option_strings and action.option_strings[0] in ("-h", "--help"):
|
|
24
|
+
return None
|
|
25
|
+
if action.dest in ("help", "func"):
|
|
26
|
+
return None
|
|
27
|
+
if isinstance(action, argparse._SubParsersAction):
|
|
28
|
+
return None
|
|
29
|
+
flags = list(action.option_strings)
|
|
30
|
+
is_option = bool(flags)
|
|
31
|
+
is_flag = action.nargs == 0 or isinstance(action, argparse._StoreTrueAction)
|
|
32
|
+
spec: dict[str, Any] = {
|
|
33
|
+
"name": action.metavar or action.dest,
|
|
34
|
+
"dest": action.dest,
|
|
35
|
+
"help": action.help or "",
|
|
36
|
+
"required": bool(action.required),
|
|
37
|
+
}
|
|
38
|
+
if is_option:
|
|
39
|
+
spec["flags"] = flags
|
|
40
|
+
spec["kind"] = "flag" if is_flag else "option"
|
|
41
|
+
else:
|
|
42
|
+
spec["kind"] = "argument"
|
|
43
|
+
if action.nargs is not None:
|
|
44
|
+
spec["nargs"] = str(action.nargs)
|
|
45
|
+
default = action.default
|
|
46
|
+
if default is not argparse.SUPPRESS and default is not None:
|
|
47
|
+
spec["default"] = _json_safe(default)
|
|
48
|
+
if action.choices:
|
|
49
|
+
spec["choices"] = [_json_safe(c) for c in action.choices]
|
|
50
|
+
return spec
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def cli_spec(parser: argparse.ArgumentParser, *, name: str, description: str = "") -> dict[str, Any]:
|
|
54
|
+
options: List[dict[str, Any]] = []
|
|
55
|
+
arguments: List[dict[str, Any]] = []
|
|
56
|
+
for action in parser._actions:
|
|
57
|
+
item = _action_spec(action)
|
|
58
|
+
if not item:
|
|
59
|
+
continue
|
|
60
|
+
if item["kind"] == "argument":
|
|
61
|
+
arguments.append(item)
|
|
62
|
+
else:
|
|
63
|
+
options.append(item)
|
|
64
|
+
return {
|
|
65
|
+
"name": name,
|
|
66
|
+
"abi_version": ABI_VERSION,
|
|
67
|
+
"description": description or parser.description or "",
|
|
68
|
+
"usage": parser.format_usage().strip(),
|
|
69
|
+
"options": options,
|
|
70
|
+
"arguments": arguments,
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def injection_spec() -> dict[str, Any]:
|
|
75
|
+
return {
|
|
76
|
+
"scan_skips": [".agents", ".cursor", ".git", "node_modules"],
|
|
77
|
+
"no_empty_folders": True,
|
|
78
|
+
"generated_on_sync": [
|
|
79
|
+
{
|
|
80
|
+
"path": "~/.agents/AGENTS.md",
|
|
81
|
+
"from": ["~/.agents/memory/USER.md", "~/.agents/memory/PROJECTS.md"],
|
|
82
|
+
"edit": "Edit USER.md / PROJECTS.md, then re-run python -m agent_memory sync",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"path": "~/.agents/CLAUDE.md",
|
|
86
|
+
"bind": "~/.agents/AGENTS.md",
|
|
87
|
+
"edit": "Edit AGENTS.md only",
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"path": "~/.agents/rules/<agent_rule_name>.mdc",
|
|
91
|
+
"hosts": ["~/.cursor/rules/<agent_rule_name>.mdc (bound on sync)"],
|
|
92
|
+
"config": "scan.json agent_rule_name (default user-rules.mdc)",
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"path": "<repo>/.agents/AGENTS.md + CLAUDE.md",
|
|
96
|
+
"when": "registered project with path on disk",
|
|
97
|
+
"marker": "<!-- agent-memory-sync -->",
|
|
98
|
+
"note": "No <repo>/.cursor/ — scan skips .cursor; no empty memory subfolders",
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"path": "<repo>/.agents/memory/README.md + staging/captured.md",
|
|
102
|
+
"when": "register_project",
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"path": "~/.agents/skills/memory-sync/SKILL.md",
|
|
106
|
+
"also": ["host skill dirs per INSTALL.md"],
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
"merged_on_init": [
|
|
110
|
+
{"path": "~/.cursor/mcp.json", "key": "mcpServers.agent-memory"},
|
|
111
|
+
{"path": "Zed settings.json", "key": "context_servers"},
|
|
112
|
+
],
|
|
113
|
+
"copied_not_generated": [
|
|
114
|
+
{"path": "~/.agents/memory/LAYOUT.md", "source": "abi/LAYOUT.md in engine clone"},
|
|
115
|
+
],
|
|
116
|
+
"marker": "<!-- agent-memory-sync -->",
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def full_spec() -> dict[str, Any]:
|
|
121
|
+
from .sync import build_parser as sync_parser
|
|
122
|
+
from .inventory import build_parser as inventory_parser
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
"name": "agent-memory",
|
|
126
|
+
"abi_version": ABI_VERSION,
|
|
127
|
+
"scripts": {
|
|
128
|
+
"sync": cli_spec(sync_parser(), name="sync", description="Rewrite always-on injection for your Agent."),
|
|
129
|
+
"inventory": cli_spec(
|
|
130
|
+
inventory_parser(),
|
|
131
|
+
name="inventory",
|
|
132
|
+
description="Compare scan.json roots to PROJECTS.md.",
|
|
133
|
+
),
|
|
134
|
+
},
|
|
135
|
+
"scripts_no_flags": {
|
|
136
|
+
"ingest": "Serial ingest: catalog (references) -> extract (staging) -> distill via MCP add_memory.",
|
|
137
|
+
"consolidate": "Move live markdown leaked into the engine clone into ~/.agents/memory.",
|
|
138
|
+
"extract-openai": "Thin wrapper: ingest extract for Open AI GDPR export (openai-export; --out = legacy JSON).",
|
|
139
|
+
"mcp": "MCP stdio server. Tools: see abi/MCP.md.",
|
|
140
|
+
},
|
|
141
|
+
"injection": injection_spec(),
|
|
142
|
+
"discover": "python -m agent_memory --help-json | python -m agent_memory sync --help-json | python -m agent_memory inventory --help-json",
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def emit_help_json(argv: list[str], parser: argparse.ArgumentParser, *, name: str, description: str = "") -> None:
|
|
147
|
+
payload = cli_spec(parser, name=name, description=description)
|
|
148
|
+
print(json.dumps(payload, indent=2, ensure_ascii=False))
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def main(argv: list[str] | None = None) -> int:
|
|
152
|
+
if hasattr(sys.stdout, "reconfigure"):
|
|
153
|
+
try:
|
|
154
|
+
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
155
|
+
except Exception:
|
|
156
|
+
pass
|
|
157
|
+
args = list(argv if argv is not None else sys.argv[1:])
|
|
158
|
+
if "--help-json" in args:
|
|
159
|
+
print(json.dumps(full_spec(), indent=2, ensure_ascii=False))
|
|
160
|
+
return 0
|
|
161
|
+
print("Usage: python -m agent_memory --help-json", file=sys.stderr)
|
|
162
|
+
return 2
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
if __name__ == "__main__":
|
|
166
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Move live markdown out of the engine clone into ~/.agents/memory."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from .store import consolidate_repo_leaks, ensure_memory_layout
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def main() -> int:
|
|
10
|
+
ensure_memory_layout()
|
|
11
|
+
moved = consolidate_repo_leaks()
|
|
12
|
+
if not moved:
|
|
13
|
+
print("nothing to consolidate")
|
|
14
|
+
return 0
|
|
15
|
+
print(f"consolidated {len(moved)} paths:")
|
|
16
|
+
for line in moved:
|
|
17
|
+
print(f" {line}")
|
|
18
|
+
return 0
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
if __name__ == "__main__":
|
|
22
|
+
sys.exit(main())
|