memfmt 0.1.0__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.
- memfmt-0.1.0/.gitignore +6 -0
- memfmt-0.1.0/LICENSE +21 -0
- memfmt-0.1.0/PKG-INFO +256 -0
- memfmt-0.1.0/README.md +235 -0
- memfmt-0.1.0/memfmt/__init__.py +32 -0
- memfmt-0.1.0/memfmt/__main__.py +3 -0
- memfmt-0.1.0/memfmt/cli.py +166 -0
- memfmt-0.1.0/memfmt/model.py +141 -0
- memfmt-0.1.0/memfmt/parse.py +337 -0
- memfmt-0.1.0/memfmt/serialize.py +302 -0
- memfmt-0.1.0/pyproject.toml +37 -0
- memfmt-0.1.0/tests/test_roundtrip.py +205 -0
memfmt-0.1.0/.gitignore
ADDED
memfmt-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ali Baizhanov
|
|
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.
|
memfmt-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: memfmt
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: An agent's memory as Markdown files you own — read, write and check the format.
|
|
5
|
+
Project-URL: Homepage, https://github.com/alibaizhanov/memfmt
|
|
6
|
+
Project-URL: Source, https://github.com/alibaizhanov/memfmt
|
|
7
|
+
Author: Ali Baizhanov
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: agent,format,llm,markdown,memory,obsidian
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
16
|
+
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Provides-Extra: dev
|
|
19
|
+
Requires-Dist: pytest>=7; extra == 'dev'
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# memfmt
|
|
23
|
+
|
|
24
|
+
**An agent's memory as Markdown files you own.**
|
|
25
|
+
|
|
26
|
+
Every agent that remembers anything invents its own way to store it: one
|
|
27
|
+
`MEMORY.md` that grows until it stops fitting in context, a bespoke JSON blob,
|
|
28
|
+
a folder of notes with no rules. Nobody can read anybody else's, nothing
|
|
29
|
+
diffs cleanly, and moving between tools means writing a converter.
|
|
30
|
+
|
|
31
|
+
memfmt is a small spec and a dependency-free Python library for the boring
|
|
32
|
+
version of that: memory as plain Markdown, one thing per file, relations as
|
|
33
|
+
`[[wikilinks]]`. Git gives you diffs, review and rollback. Obsidian draws the
|
|
34
|
+
graph with no configuration, because the links *are* the graph.
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
memory/
|
|
38
|
+
MEMORY.md index — what is in here
|
|
39
|
+
entities/Ali.md what is true
|
|
40
|
+
episodes/2026-07-30-deploy-failed.md what happened
|
|
41
|
+
procedures/deploy to Railway.md how to do it, and whether it works
|
|
42
|
+
profile.md
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
No account, no server, no network. This library reads and writes files.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install memfmt
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Use it
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
memfmt stat ./memory # what is in here
|
|
59
|
+
memfmt validate ./memory # would any file lose data if a tool rewrote it?
|
|
60
|
+
memfmt context ./memory "why did the deploy fail" # the relevant bits, to pipe into a model
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from memfmt import load, serialise, write_dir, canonical
|
|
65
|
+
|
|
66
|
+
memory = load("./memory")
|
|
67
|
+
|
|
68
|
+
for p in memory.procedures:
|
|
69
|
+
print(p.name, p.version, p.reliability) # deploy to Railway 3 92% reliable
|
|
70
|
+
|
|
71
|
+
write_dir(serialise(memory), "./memory")
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`memfmt context` is the one to try first. It picks the files relevant to a
|
|
75
|
+
question and prints them, so you can pipe your agent's own memory into a
|
|
76
|
+
prompt without a database:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
memfmt context ./memory "deploy railway pool" | pbcopy
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## The format
|
|
85
|
+
|
|
86
|
+
Three kinds of memory, because agents forget in three different ways.
|
|
87
|
+
|
|
88
|
+
### Entities — what is true
|
|
89
|
+
|
|
90
|
+
`memory/entities/<name>.md`
|
|
91
|
+
|
|
92
|
+
````markdown
|
|
93
|
+
---
|
|
94
|
+
memfmt_type: entity
|
|
95
|
+
entity_type: person
|
|
96
|
+
id: e1
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
# Ali
|
|
100
|
+
|
|
101
|
+
## Facts
|
|
102
|
+
|
|
103
|
+
- prefers Rust for memory safety
|
|
104
|
+
- based in Tokyo
|
|
105
|
+
|
|
106
|
+
## Relations
|
|
107
|
+
|
|
108
|
+
- works at → [[Mengram]] — since 2024
|
|
109
|
+
- mentored by ← [[Kenji]]
|
|
110
|
+
|
|
111
|
+
## Knowledge
|
|
112
|
+
|
|
113
|
+
**[snippet] deploy command** — how the service ships
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
railway up --detach
|
|
117
|
+
```
|
|
118
|
+
````
|
|
119
|
+
|
|
120
|
+
`→` is outgoing, `←` incoming. Text after ` — ` is a note on the relation.
|
|
121
|
+
When a name cannot be a filename, the link carries an alias and the real name
|
|
122
|
+
survives: `[[cloud-api.py|cloud/api.py]]`.
|
|
123
|
+
|
|
124
|
+
### Episodes — what happened
|
|
125
|
+
|
|
126
|
+
`memory/episodes/<date>-<summary>.md`
|
|
127
|
+
|
|
128
|
+
```markdown
|
|
129
|
+
---
|
|
130
|
+
memfmt_type: episode
|
|
131
|
+
id: ep1
|
|
132
|
+
happened: 2026-07-30
|
|
133
|
+
outcome: rolled back, raised pool_max
|
|
134
|
+
valence: negative
|
|
135
|
+
importance: 4
|
|
136
|
+
participants:
|
|
137
|
+
- Ali
|
|
138
|
+
- Railway
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
# deploy failed on a cold pool
|
|
142
|
+
|
|
143
|
+
Two workers booted at once and the session pooler refused the fourth client.
|
|
144
|
+
|
|
145
|
+
**Outcome** — rolled back, raised pool_max
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
An event with no outcome teaches nothing, so `outcome` is the field that earns
|
|
149
|
+
an episode its place.
|
|
150
|
+
|
|
151
|
+
### Procedures — how to do something, and whether it works
|
|
152
|
+
|
|
153
|
+
`memory/procedures/<name>.md`
|
|
154
|
+
|
|
155
|
+
```markdown
|
|
156
|
+
---
|
|
157
|
+
memfmt_type: procedure
|
|
158
|
+
id: p1
|
|
159
|
+
version: 3
|
|
160
|
+
success_count: 11
|
|
161
|
+
fail_count: 1
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
# deploy to Railway (v3 · 92% reliable)
|
|
165
|
+
|
|
166
|
+
**When** — a change lands on main
|
|
167
|
+
|
|
168
|
+
**Preconditions**
|
|
169
|
+
|
|
170
|
+
- tests pass
|
|
171
|
+
- pool_max is set
|
|
172
|
+
|
|
173
|
+
## Steps
|
|
174
|
+
|
|
175
|
+
1. push to main — the webhook does the rest
|
|
176
|
+
2. watch the boot log
|
|
177
|
+
3. verify /health — expect 200 within 60s
|
|
178
|
+
|
|
179
|
+
## Evolution
|
|
180
|
+
|
|
181
|
+
- v1 → v2 (2026-06-02): added the health check
|
|
182
|
+
- v2 → v3: wait for the pool before probing
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
This is the file the format exists for. A workflow on its own is a guess
|
|
186
|
+
somebody wrote down. With `11 ✓ / 1 ✗` and the revisions that produced it, it
|
|
187
|
+
is evidence — and an agent can tell the difference between a step that has
|
|
188
|
+
worked eleven times and one nobody has ever run.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Rules
|
|
193
|
+
|
|
194
|
+
A short list, because a format nobody can hold in their head gets implemented
|
|
195
|
+
wrong.
|
|
196
|
+
|
|
197
|
+
1. **Frontmatter is the source of truth.** The `(v3 · 92% reliable)` in a
|
|
198
|
+
heading is rendered from it for the reader. Edit the heading and the
|
|
199
|
+
numbers do not change — the parser reads the frontmatter.
|
|
200
|
+
2. **`memfmt_type` marks a file as ours.** Files without it are ignored, so a
|
|
201
|
+
memory folder can live inside a vault full of somebody's own notes.
|
|
202
|
+
3. **Unknown fields are left alone.** Nothing is silently dropped for being
|
|
203
|
+
unrecognised.
|
|
204
|
+
4. **Bullets are one line.** Facts, steps and relation notes are collapsed to
|
|
205
|
+
a single line when written, so what a file says and what a parser reads
|
|
206
|
+
back are the same thing.
|
|
207
|
+
5. **A folder is a set, not a list.** Reading a directory cannot recover the
|
|
208
|
+
order of the list that wrote it. Use `canonical()` to compare two memories,
|
|
209
|
+
and to keep git diffs to the lines that actually changed.
|
|
210
|
+
6. **Round-trip or it is not the format.** `parse(serialise(m)) == m`, and
|
|
211
|
+
serialising what you parsed is byte-identical. `memfmt validate` checks
|
|
212
|
+
exactly this against a real folder.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Why files
|
|
217
|
+
|
|
218
|
+
Because the alternative is that your agent's memory lives somewhere you cannot
|
|
219
|
+
read, cannot grep, cannot correct, and cannot take with you.
|
|
220
|
+
|
|
221
|
+
Files give you the things a database makes hard: `git diff` on what your agent
|
|
222
|
+
learned this week, a pull request when it learns something wrong, `git revert`
|
|
223
|
+
when it learns something harmful, and a graph view for free. And when the tool
|
|
224
|
+
that wrote them goes away, the memory does not.
|
|
225
|
+
|
|
226
|
+
## Where files stop being enough
|
|
227
|
+
|
|
228
|
+
Honestly: at a few hundred of them.
|
|
229
|
+
|
|
230
|
+
Word overlap is the best `memfmt context` can do without embeddings, and it
|
|
231
|
+
starts missing things that are phrased differently. Syncing a folder between
|
|
232
|
+
machines or a team is a real problem, not a `git pull` away. Deduplicating
|
|
233
|
+
facts that contradict each other needs a model.
|
|
234
|
+
|
|
235
|
+
That is a server's job, and memfmt does not pretend otherwise. If you get
|
|
236
|
+
there, [Mengram](https://mengram.io?utm_source=memfmt&utm_medium=readme)
|
|
237
|
+
writes this format today — `mengram export markdown ./memory` hands you a tree
|
|
238
|
+
this library reads — and adds the search, sync and deduplication that files
|
|
239
|
+
alone cannot do. Syncing a folder back into it is not built yet.
|
|
240
|
+
|
|
241
|
+
Either way the files stay yours, and if you never need a server, this library
|
|
242
|
+
does not expire.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Contributing
|
|
247
|
+
|
|
248
|
+
The test suite is the specification in executable form. If you are proposing a
|
|
249
|
+
change to the format, the change to `tests/test_roundtrip.py` is the proposal.
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
pip install -e ".[dev]"
|
|
253
|
+
pytest
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
MIT licensed.
|
memfmt-0.1.0/README.md
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# memfmt
|
|
2
|
+
|
|
3
|
+
**An agent's memory as Markdown files you own.**
|
|
4
|
+
|
|
5
|
+
Every agent that remembers anything invents its own way to store it: one
|
|
6
|
+
`MEMORY.md` that grows until it stops fitting in context, a bespoke JSON blob,
|
|
7
|
+
a folder of notes with no rules. Nobody can read anybody else's, nothing
|
|
8
|
+
diffs cleanly, and moving between tools means writing a converter.
|
|
9
|
+
|
|
10
|
+
memfmt is a small spec and a dependency-free Python library for the boring
|
|
11
|
+
version of that: memory as plain Markdown, one thing per file, relations as
|
|
12
|
+
`[[wikilinks]]`. Git gives you diffs, review and rollback. Obsidian draws the
|
|
13
|
+
graph with no configuration, because the links *are* the graph.
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
memory/
|
|
17
|
+
MEMORY.md index — what is in here
|
|
18
|
+
entities/Ali.md what is true
|
|
19
|
+
episodes/2026-07-30-deploy-failed.md what happened
|
|
20
|
+
procedures/deploy to Railway.md how to do it, and whether it works
|
|
21
|
+
profile.md
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
No account, no server, no network. This library reads and writes files.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install memfmt
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Use it
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
memfmt stat ./memory # what is in here
|
|
38
|
+
memfmt validate ./memory # would any file lose data if a tool rewrote it?
|
|
39
|
+
memfmt context ./memory "why did the deploy fail" # the relevant bits, to pipe into a model
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from memfmt import load, serialise, write_dir, canonical
|
|
44
|
+
|
|
45
|
+
memory = load("./memory")
|
|
46
|
+
|
|
47
|
+
for p in memory.procedures:
|
|
48
|
+
print(p.name, p.version, p.reliability) # deploy to Railway 3 92% reliable
|
|
49
|
+
|
|
50
|
+
write_dir(serialise(memory), "./memory")
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`memfmt context` is the one to try first. It picks the files relevant to a
|
|
54
|
+
question and prints them, so you can pipe your agent's own memory into a
|
|
55
|
+
prompt without a database:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
memfmt context ./memory "deploy railway pool" | pbcopy
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## The format
|
|
64
|
+
|
|
65
|
+
Three kinds of memory, because agents forget in three different ways.
|
|
66
|
+
|
|
67
|
+
### Entities — what is true
|
|
68
|
+
|
|
69
|
+
`memory/entities/<name>.md`
|
|
70
|
+
|
|
71
|
+
````markdown
|
|
72
|
+
---
|
|
73
|
+
memfmt_type: entity
|
|
74
|
+
entity_type: person
|
|
75
|
+
id: e1
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
# Ali
|
|
79
|
+
|
|
80
|
+
## Facts
|
|
81
|
+
|
|
82
|
+
- prefers Rust for memory safety
|
|
83
|
+
- based in Tokyo
|
|
84
|
+
|
|
85
|
+
## Relations
|
|
86
|
+
|
|
87
|
+
- works at → [[Mengram]] — since 2024
|
|
88
|
+
- mentored by ← [[Kenji]]
|
|
89
|
+
|
|
90
|
+
## Knowledge
|
|
91
|
+
|
|
92
|
+
**[snippet] deploy command** — how the service ships
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
railway up --detach
|
|
96
|
+
```
|
|
97
|
+
````
|
|
98
|
+
|
|
99
|
+
`→` is outgoing, `←` incoming. Text after ` — ` is a note on the relation.
|
|
100
|
+
When a name cannot be a filename, the link carries an alias and the real name
|
|
101
|
+
survives: `[[cloud-api.py|cloud/api.py]]`.
|
|
102
|
+
|
|
103
|
+
### Episodes — what happened
|
|
104
|
+
|
|
105
|
+
`memory/episodes/<date>-<summary>.md`
|
|
106
|
+
|
|
107
|
+
```markdown
|
|
108
|
+
---
|
|
109
|
+
memfmt_type: episode
|
|
110
|
+
id: ep1
|
|
111
|
+
happened: 2026-07-30
|
|
112
|
+
outcome: rolled back, raised pool_max
|
|
113
|
+
valence: negative
|
|
114
|
+
importance: 4
|
|
115
|
+
participants:
|
|
116
|
+
- Ali
|
|
117
|
+
- Railway
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
# deploy failed on a cold pool
|
|
121
|
+
|
|
122
|
+
Two workers booted at once and the session pooler refused the fourth client.
|
|
123
|
+
|
|
124
|
+
**Outcome** — rolled back, raised pool_max
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
An event with no outcome teaches nothing, so `outcome` is the field that earns
|
|
128
|
+
an episode its place.
|
|
129
|
+
|
|
130
|
+
### Procedures — how to do something, and whether it works
|
|
131
|
+
|
|
132
|
+
`memory/procedures/<name>.md`
|
|
133
|
+
|
|
134
|
+
```markdown
|
|
135
|
+
---
|
|
136
|
+
memfmt_type: procedure
|
|
137
|
+
id: p1
|
|
138
|
+
version: 3
|
|
139
|
+
success_count: 11
|
|
140
|
+
fail_count: 1
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
# deploy to Railway (v3 · 92% reliable)
|
|
144
|
+
|
|
145
|
+
**When** — a change lands on main
|
|
146
|
+
|
|
147
|
+
**Preconditions**
|
|
148
|
+
|
|
149
|
+
- tests pass
|
|
150
|
+
- pool_max is set
|
|
151
|
+
|
|
152
|
+
## Steps
|
|
153
|
+
|
|
154
|
+
1. push to main — the webhook does the rest
|
|
155
|
+
2. watch the boot log
|
|
156
|
+
3. verify /health — expect 200 within 60s
|
|
157
|
+
|
|
158
|
+
## Evolution
|
|
159
|
+
|
|
160
|
+
- v1 → v2 (2026-06-02): added the health check
|
|
161
|
+
- v2 → v3: wait for the pool before probing
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
This is the file the format exists for. A workflow on its own is a guess
|
|
165
|
+
somebody wrote down. With `11 ✓ / 1 ✗` and the revisions that produced it, it
|
|
166
|
+
is evidence — and an agent can tell the difference between a step that has
|
|
167
|
+
worked eleven times and one nobody has ever run.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Rules
|
|
172
|
+
|
|
173
|
+
A short list, because a format nobody can hold in their head gets implemented
|
|
174
|
+
wrong.
|
|
175
|
+
|
|
176
|
+
1. **Frontmatter is the source of truth.** The `(v3 · 92% reliable)` in a
|
|
177
|
+
heading is rendered from it for the reader. Edit the heading and the
|
|
178
|
+
numbers do not change — the parser reads the frontmatter.
|
|
179
|
+
2. **`memfmt_type` marks a file as ours.** Files without it are ignored, so a
|
|
180
|
+
memory folder can live inside a vault full of somebody's own notes.
|
|
181
|
+
3. **Unknown fields are left alone.** Nothing is silently dropped for being
|
|
182
|
+
unrecognised.
|
|
183
|
+
4. **Bullets are one line.** Facts, steps and relation notes are collapsed to
|
|
184
|
+
a single line when written, so what a file says and what a parser reads
|
|
185
|
+
back are the same thing.
|
|
186
|
+
5. **A folder is a set, not a list.** Reading a directory cannot recover the
|
|
187
|
+
order of the list that wrote it. Use `canonical()` to compare two memories,
|
|
188
|
+
and to keep git diffs to the lines that actually changed.
|
|
189
|
+
6. **Round-trip or it is not the format.** `parse(serialise(m)) == m`, and
|
|
190
|
+
serialising what you parsed is byte-identical. `memfmt validate` checks
|
|
191
|
+
exactly this against a real folder.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Why files
|
|
196
|
+
|
|
197
|
+
Because the alternative is that your agent's memory lives somewhere you cannot
|
|
198
|
+
read, cannot grep, cannot correct, and cannot take with you.
|
|
199
|
+
|
|
200
|
+
Files give you the things a database makes hard: `git diff` on what your agent
|
|
201
|
+
learned this week, a pull request when it learns something wrong, `git revert`
|
|
202
|
+
when it learns something harmful, and a graph view for free. And when the tool
|
|
203
|
+
that wrote them goes away, the memory does not.
|
|
204
|
+
|
|
205
|
+
## Where files stop being enough
|
|
206
|
+
|
|
207
|
+
Honestly: at a few hundred of them.
|
|
208
|
+
|
|
209
|
+
Word overlap is the best `memfmt context` can do without embeddings, and it
|
|
210
|
+
starts missing things that are phrased differently. Syncing a folder between
|
|
211
|
+
machines or a team is a real problem, not a `git pull` away. Deduplicating
|
|
212
|
+
facts that contradict each other needs a model.
|
|
213
|
+
|
|
214
|
+
That is a server's job, and memfmt does not pretend otherwise. If you get
|
|
215
|
+
there, [Mengram](https://mengram.io?utm_source=memfmt&utm_medium=readme)
|
|
216
|
+
writes this format today — `mengram export markdown ./memory` hands you a tree
|
|
217
|
+
this library reads — and adds the search, sync and deduplication that files
|
|
218
|
+
alone cannot do. Syncing a folder back into it is not built yet.
|
|
219
|
+
|
|
220
|
+
Either way the files stay yours, and if you never need a server, this library
|
|
221
|
+
does not expire.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Contributing
|
|
226
|
+
|
|
227
|
+
The test suite is the specification in executable form. If you are proposing a
|
|
228
|
+
change to the format, the change to `tests/test_roundtrip.py` is the proposal.
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
pip install -e ".[dev]"
|
|
232
|
+
pytest
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
MIT licensed.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""memfmt — an agent's memory as Markdown files you own.
|
|
2
|
+
|
|
3
|
+
from memfmt import load, serialise, write_dir
|
|
4
|
+
|
|
5
|
+
memory = load("./memory")
|
|
6
|
+
memory.procedures[0].reliability # '92% reliable'
|
|
7
|
+
write_dir(serialise(memory), "./memory")
|
|
8
|
+
|
|
9
|
+
Three kinds of memory: entities (what is true), episodes (what happened),
|
|
10
|
+
procedures (how to do something, with the record of it working). Plain
|
|
11
|
+
Markdown, `[[wikilinks]]` for relations, so Obsidian draws the graph with no
|
|
12
|
+
configuration and git gives you diffs, review and rollback for free.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from .model import (Entity, Episode, Knowledge, Memory, Procedure, Relation,
|
|
16
|
+
Revision, Step, canonical)
|
|
17
|
+
from .parse import (MemfmtError, file_type, load, parse, parse_frontmatter,
|
|
18
|
+
read_dir, write_dir)
|
|
19
|
+
from .serialize import INDEX, ROOT, TYPE_KEY, serialise, slugify
|
|
20
|
+
|
|
21
|
+
__version__ = "0.1.0"
|
|
22
|
+
|
|
23
|
+
#: American spelling, same function — the CLI and half the world write it this way.
|
|
24
|
+
serialize = serialise
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"Entity", "Episode", "Knowledge", "Memory", "Procedure", "Relation",
|
|
28
|
+
"Revision", "Step", "canonical",
|
|
29
|
+
"load", "parse", "parse_frontmatter", "read_dir", "write_dir", "file_type",
|
|
30
|
+
"serialise", "serialize", "slugify",
|
|
31
|
+
"MemfmtError", "TYPE_KEY", "ROOT", "INDEX", "__version__",
|
|
32
|
+
]
|