memdate 1.0.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.
- memdate-1.0.0/LICENSE +21 -0
- memdate-1.0.0/PKG-INFO +210 -0
- memdate-1.0.0/README.md +194 -0
- memdate-1.0.0/pyproject.toml +27 -0
- memdate-1.0.0/setup.cfg +4 -0
- memdate-1.0.0/src/memdate/__init__.py +78 -0
- memdate-1.0.0/src/memdate/adapters.py +174 -0
- memdate-1.0.0/src/memdate/capture.py +136 -0
- memdate-1.0.0/src/memdate/config.py +148 -0
- memdate-1.0.0/src/memdate/distill.py +142 -0
- memdate-1.0.0/src/memdate/drop.py +116 -0
- memdate-1.0.0/src/memdate/frontmatter.py +108 -0
- memdate-1.0.0/src/memdate/index.py +264 -0
- memdate-1.0.0/src/memdate.egg-info/PKG-INFO +210 -0
- memdate-1.0.0/src/memdate.egg-info/SOURCES.txt +20 -0
- memdate-1.0.0/src/memdate.egg-info/dependency_links.txt +1 -0
- memdate-1.0.0/src/memdate.egg-info/top_level.txt +1 -0
- memdate-1.0.0/tests/test_adapters_config.py +197 -0
- memdate-1.0.0/tests/test_capture.py +122 -0
- memdate-1.0.0/tests/test_distill.py +136 -0
- memdate-1.0.0/tests/test_drop.py +91 -0
- memdate-1.0.0/tests/test_index.py +164 -0
memdate-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ryan Wesley Hitchcock
|
|
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.
|
memdate-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: memdate
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: File-based memory system with a hard CAPTURE/DISTILL split: raw records are append-only evidence, distilled files are derived synthesis, and a cross-domain index keeps the connective tissue current
|
|
5
|
+
Author: Ryan Wesley Hitchcock
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/ohpersonperson/frontface
|
|
8
|
+
Keywords: memory,knowledge-management,journaling,capture,distillation,markdown
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# memdate — file-based memory with a hard CAPTURE/DISTILL split
|
|
18
|
+
|
|
19
|
+
Plain Markdown memory for people or agents. One load-bearing invariant:
|
|
20
|
+
|
|
21
|
+
**CAPTURE preserves. DISTILL interprets. Never mix them.**
|
|
22
|
+
|
|
23
|
+
- **CAPTURE** appends timestamped raw records. No summarizing, no
|
|
24
|
+
synthesis, no editing yesterday's entries. Raw is the permanent record.
|
|
25
|
+
- **DISTILL** consolidates raw into `distilled.md` — and the library
|
|
26
|
+
checksums raw before and after, voiding the run if anything touched it.
|
|
27
|
+
- **INDEX** regenerates the cross-domain connective tissue
|
|
28
|
+
(entities→domains, dependencies, open questions, hot zones) after any
|
|
29
|
+
multi-domain distill. Derived, never authoritative over raw.
|
|
30
|
+
|
|
31
|
+
No prerequisites. You don't need to know anything about the project's
|
|
32
|
+
history. The mechanism is the whole product.
|
|
33
|
+
|
|
34
|
+
*(Lineage: front-facing conversion of the `memdate-v2` skill from Ryan's
|
|
35
|
+
skill-suite, MIT. What changed is documented in CHANGELOG.md — the
|
|
36
|
+
decoupling record.)*
|
|
37
|
+
|
|
38
|
+
## What it does
|
|
39
|
+
|
|
40
|
+
A memory store is a directory:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
<root>/
|
|
44
|
+
├── INDEX-cross-domain.md ← regenerated after multi-domain distills
|
|
45
|
+
├── DROP/ ← ingestion: NEW / PROCESSED / PENDING / QUARANTINE
|
|
46
|
+
├── personal/
|
|
47
|
+
│ ├── raw.md ← append-only evidence log
|
|
48
|
+
│ └── distilled.md ← derived synthesis + provenance frontmatter
|
|
49
|
+
└── work/
|
|
50
|
+
├── raw.md
|
|
51
|
+
└── distilled.md
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The domain list is configuration, not identity. This package ships with
|
|
55
|
+
neutral defaults (`personal`, `work`, `projects`, `reference`, `misc`) —
|
|
56
|
+
define your own via constructor, JSON, or YAML. Storage is a
|
|
57
|
+
`StorageAdapter`: the local filesystem by default, Google Drive as an
|
|
58
|
+
optional seam you can implement (it fails loudly until you do, instead of
|
|
59
|
+
pretending to work).
|
|
60
|
+
|
|
61
|
+
## Why it works
|
|
62
|
+
|
|
63
|
+
Most memory systems rot because recording and interpreting happen in the
|
|
64
|
+
same motion: you write down what happened *and* what it means, and a
|
|
65
|
+
month later you can't tell which was which. The split is enforced in
|
|
66
|
+
code, not just in prose:
|
|
67
|
+
|
|
68
|
+
- **Capture isolation** — `capture()` only appends; it has no code path
|
|
69
|
+
that edits prior entries (tested: old content is always a strict prefix
|
|
70
|
+
of new content). Entry text is scanned for interpretation markers
|
|
71
|
+
("in summary", "overall,", … — configurable); a hit raises unless you
|
|
72
|
+
pass `force=True`, and then the bypass is stamped into the entry
|
|
73
|
+
header. The exception is visible, never silent.
|
|
74
|
+
- **Distill isolation** — `distill()` checksums `raw.md` before writing
|
|
75
|
+
`distilled.md` and re-checks after. If raw changed mid-run, the run is
|
|
76
|
+
void. A test adapter that sabotages raw mid-distill proves the check
|
|
77
|
+
fires.
|
|
78
|
+
- **Index discipline** — the four required sections and the 7-step
|
|
79
|
+
regeneration procedure are code. Single-domain distills skip the index
|
|
80
|
+
with a recorded reason. The verify pass asserts no orphan entities and
|
|
81
|
+
no sourceless questions.
|
|
82
|
+
- **Raw wins conflicts** — stated in the docs, enforced by the
|
|
83
|
+
architecture: nothing in the distill path can write to raw.
|
|
84
|
+
|
|
85
|
+
## Quickstart
|
|
86
|
+
|
|
87
|
+
Zero dependencies beyond Python 3.10+.
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
cd memdate
|
|
91
|
+
PYTHONPATH=src python3 -m unittest discover -s tests # 72 offline tests
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
export PYTHONPATH=src
|
|
96
|
+
python3 examples/run_local.py --root /tmp/memo init
|
|
97
|
+
python3 examples/run_local.py --root /tmp/memo capture \
|
|
98
|
+
--domain work --text "Acme Corp emailed: contract renews March 1." --source email
|
|
99
|
+
python3 examples/run_local.py --root /tmp/memo capture \
|
|
100
|
+
--domain work --text "In summary, the deal is safe."
|
|
101
|
+
# InterpretationError: Entry looks like interpretation, not capture —
|
|
102
|
+
# markers found: in summary. Rewrite as raw record, or pass force=True
|
|
103
|
+
# to record the bypass explicitly.
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Distill from a file holding your consolidated synthesis:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
python3 examples/run_local.py --root /tmp/memo distill --domain work \
|
|
110
|
+
--file /tmp/work-distilled.md \
|
|
111
|
+
--entities "Acme Corp,Priya" --informs personal \
|
|
112
|
+
--questions "Does the freeze delay the paperwork?"
|
|
113
|
+
python3 examples/run_local.py --root /tmp/memo index --touched work,personal
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Or use it as a library:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from memdate import (
|
|
120
|
+
MemoryConfig, default_adapter, ensure_layout,
|
|
121
|
+
capture, distill, regenerate_index,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
cfg = MemoryConfig(root="/tmp/memo", domains=("garden", "car"))
|
|
125
|
+
store = default_adapter(cfg.root)
|
|
126
|
+
ensure_layout(cfg, adapter=store)
|
|
127
|
+
|
|
128
|
+
capture(cfg, "garden", "Planted tomatoes, north bed.", adapter=store)
|
|
129
|
+
distill(cfg, "garden", "North bed: tomatoes planted.",
|
|
130
|
+
entities=["north bed"], lifecycle="ITERATIVE", adapter=store)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Drop a file in `DROP/NEW/` with a leading `domain: <name>` line and
|
|
134
|
+
`sweep` routes it — captured to the right domain's raw, or quarantined
|
|
135
|
+
with a reason file if it's unroutable or reads like synthesis:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
printf 'domain: work\n\nFixed the flaky test.\n' > /tmp/memo/DROP/NEW/note.md
|
|
139
|
+
python3 examples/run_local.py --root /tmp/memo sweep
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Inputs, outputs
|
|
143
|
+
|
|
144
|
+
- **Input (capture):** domain, text, optional source. Output: timestamped
|
|
145
|
+
entry appended to `<domain>/raw.md`.
|
|
146
|
+
- **Input (distill):** domain, consolidated body, optional entities /
|
|
147
|
+
entity notes / informs / open questions / lifecycle. Output:
|
|
148
|
+
`<domain>/distilled.md` with provenance frontmatter.
|
|
149
|
+
- **Input (index):** list of domains the distill touched. Output:
|
|
150
|
+
`INDEX-cross-domain.md`, or a recorded skip for single-domain distills.
|
|
151
|
+
|
|
152
|
+
## Distilled body conventions
|
|
153
|
+
|
|
154
|
+
Two line-prefixes the index understands:
|
|
155
|
+
|
|
156
|
+
- `? ` — uncertainty flag → collected into Hot Zones.
|
|
157
|
+
- `! ` — explicit raw↔distilled divergence note → collected into Hot Zones.
|
|
158
|
+
|
|
159
|
+
Entity note contradictions across domains (work says "reliable", personal
|
|
160
|
+
says "misses deadlines") also land in Hot Zones as `[tension]` entries.
|
|
161
|
+
|
|
162
|
+
## Evidence-taxonomy mapping
|
|
163
|
+
|
|
164
|
+
This package shares a vocabulary with the `adversarial-ifs` evidence
|
|
165
|
+
taxonomy (ten tiers). The mapping is explicit — memdate doesn't tag
|
|
166
|
+
evidence itself, but its artifacts sit at defined tiers:
|
|
167
|
+
|
|
168
|
+
| memdate artifact | IFS tier | Why |
|
|
169
|
+
|---|---|---|
|
|
170
|
+
| `raw.md` entry (logged event) | `OBSERVATION` | Reported/logged, not independently verified |
|
|
171
|
+
| `raw.md` entry (someone's assertion) | `CLAIM` | Explicit assertion by a source |
|
|
172
|
+
| `distilled.md` synthesis | `INFERENCE` | Conclusion drawn from raw evidence |
|
|
173
|
+
| `distilled.md` `? ` flags, index open questions | `UNKNOWN` | Flagged as not presently determinable |
|
|
174
|
+
| distiller-verified fact | `FACT` | Directly established ground truth |
|
|
175
|
+
| provisional model in a distillation | `HYPOTHESIS` | Needs stress-testing before use |
|
|
176
|
+
|
|
177
|
+
No code dependency between the packages — the table is the contract, so
|
|
178
|
+
neither taxonomy can silently fork.
|
|
179
|
+
|
|
180
|
+
## Worked example
|
|
181
|
+
|
|
182
|
+
`examples/example-1-two-domains.md` — a full CAPTURE → DISTILL → INDEX
|
|
183
|
+
cycle on two neutral domains, with the actual file contents shown at
|
|
184
|
+
each step.
|
|
185
|
+
|
|
186
|
+
*The field is constructed for teaching — it shows the mechanism's shape,
|
|
187
|
+
not real findings.*
|
|
188
|
+
|
|
189
|
+
## FAQ
|
|
190
|
+
|
|
191
|
+
**Where's Google Drive?** The original skill lived in a Drive folder.
|
|
192
|
+
This package defaults to the local filesystem; `GoogleDriveAdapter`
|
|
193
|
+
documents the seam and raises `DriveNotConfigured` with setup pointers
|
|
194
|
+
until you implement it. Drive is an adapter, not the root.
|
|
195
|
+
|
|
196
|
+
**Can a model do the distilling?** Yes — that's the intended shape. The
|
|
197
|
+
model supplies the consolidated body; the library stamps provenance and
|
|
198
|
+
enforces that raw wasn't touched. The library never calls a model itself.
|
|
199
|
+
|
|
200
|
+
**Does capture need the index?** No. Capture works from the first entry;
|
|
201
|
+
distill works per-domain; the index appears once two domains are
|
|
202
|
+
distilled.
|
|
203
|
+
|
|
204
|
+
**What about the memory interviewer?** The guided-capture interviewer
|
|
205
|
+
(`meminqu`) builds on this library's capture contract — it converts next
|
|
206
|
+
and shares this package's domain config.
|
|
207
|
+
|
|
208
|
+
## License
|
|
209
|
+
|
|
210
|
+
MIT. See LICENSE.
|
memdate-1.0.0/README.md
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# memdate — file-based memory with a hard CAPTURE/DISTILL split
|
|
2
|
+
|
|
3
|
+
Plain Markdown memory for people or agents. One load-bearing invariant:
|
|
4
|
+
|
|
5
|
+
**CAPTURE preserves. DISTILL interprets. Never mix them.**
|
|
6
|
+
|
|
7
|
+
- **CAPTURE** appends timestamped raw records. No summarizing, no
|
|
8
|
+
synthesis, no editing yesterday's entries. Raw is the permanent record.
|
|
9
|
+
- **DISTILL** consolidates raw into `distilled.md` — and the library
|
|
10
|
+
checksums raw before and after, voiding the run if anything touched it.
|
|
11
|
+
- **INDEX** regenerates the cross-domain connective tissue
|
|
12
|
+
(entities→domains, dependencies, open questions, hot zones) after any
|
|
13
|
+
multi-domain distill. Derived, never authoritative over raw.
|
|
14
|
+
|
|
15
|
+
No prerequisites. You don't need to know anything about the project's
|
|
16
|
+
history. The mechanism is the whole product.
|
|
17
|
+
|
|
18
|
+
*(Lineage: front-facing conversion of the `memdate-v2` skill from Ryan's
|
|
19
|
+
skill-suite, MIT. What changed is documented in CHANGELOG.md — the
|
|
20
|
+
decoupling record.)*
|
|
21
|
+
|
|
22
|
+
## What it does
|
|
23
|
+
|
|
24
|
+
A memory store is a directory:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
<root>/
|
|
28
|
+
├── INDEX-cross-domain.md ← regenerated after multi-domain distills
|
|
29
|
+
├── DROP/ ← ingestion: NEW / PROCESSED / PENDING / QUARANTINE
|
|
30
|
+
├── personal/
|
|
31
|
+
│ ├── raw.md ← append-only evidence log
|
|
32
|
+
│ └── distilled.md ← derived synthesis + provenance frontmatter
|
|
33
|
+
└── work/
|
|
34
|
+
├── raw.md
|
|
35
|
+
└── distilled.md
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The domain list is configuration, not identity. This package ships with
|
|
39
|
+
neutral defaults (`personal`, `work`, `projects`, `reference`, `misc`) —
|
|
40
|
+
define your own via constructor, JSON, or YAML. Storage is a
|
|
41
|
+
`StorageAdapter`: the local filesystem by default, Google Drive as an
|
|
42
|
+
optional seam you can implement (it fails loudly until you do, instead of
|
|
43
|
+
pretending to work).
|
|
44
|
+
|
|
45
|
+
## Why it works
|
|
46
|
+
|
|
47
|
+
Most memory systems rot because recording and interpreting happen in the
|
|
48
|
+
same motion: you write down what happened *and* what it means, and a
|
|
49
|
+
month later you can't tell which was which. The split is enforced in
|
|
50
|
+
code, not just in prose:
|
|
51
|
+
|
|
52
|
+
- **Capture isolation** — `capture()` only appends; it has no code path
|
|
53
|
+
that edits prior entries (tested: old content is always a strict prefix
|
|
54
|
+
of new content). Entry text is scanned for interpretation markers
|
|
55
|
+
("in summary", "overall,", … — configurable); a hit raises unless you
|
|
56
|
+
pass `force=True`, and then the bypass is stamped into the entry
|
|
57
|
+
header. The exception is visible, never silent.
|
|
58
|
+
- **Distill isolation** — `distill()` checksums `raw.md` before writing
|
|
59
|
+
`distilled.md` and re-checks after. If raw changed mid-run, the run is
|
|
60
|
+
void. A test adapter that sabotages raw mid-distill proves the check
|
|
61
|
+
fires.
|
|
62
|
+
- **Index discipline** — the four required sections and the 7-step
|
|
63
|
+
regeneration procedure are code. Single-domain distills skip the index
|
|
64
|
+
with a recorded reason. The verify pass asserts no orphan entities and
|
|
65
|
+
no sourceless questions.
|
|
66
|
+
- **Raw wins conflicts** — stated in the docs, enforced by the
|
|
67
|
+
architecture: nothing in the distill path can write to raw.
|
|
68
|
+
|
|
69
|
+
## Quickstart
|
|
70
|
+
|
|
71
|
+
Zero dependencies beyond Python 3.10+.
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
cd memdate
|
|
75
|
+
PYTHONPATH=src python3 -m unittest discover -s tests # 72 offline tests
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
export PYTHONPATH=src
|
|
80
|
+
python3 examples/run_local.py --root /tmp/memo init
|
|
81
|
+
python3 examples/run_local.py --root /tmp/memo capture \
|
|
82
|
+
--domain work --text "Acme Corp emailed: contract renews March 1." --source email
|
|
83
|
+
python3 examples/run_local.py --root /tmp/memo capture \
|
|
84
|
+
--domain work --text "In summary, the deal is safe."
|
|
85
|
+
# InterpretationError: Entry looks like interpretation, not capture —
|
|
86
|
+
# markers found: in summary. Rewrite as raw record, or pass force=True
|
|
87
|
+
# to record the bypass explicitly.
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Distill from a file holding your consolidated synthesis:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
python3 examples/run_local.py --root /tmp/memo distill --domain work \
|
|
94
|
+
--file /tmp/work-distilled.md \
|
|
95
|
+
--entities "Acme Corp,Priya" --informs personal \
|
|
96
|
+
--questions "Does the freeze delay the paperwork?"
|
|
97
|
+
python3 examples/run_local.py --root /tmp/memo index --touched work,personal
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Or use it as a library:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from memdate import (
|
|
104
|
+
MemoryConfig, default_adapter, ensure_layout,
|
|
105
|
+
capture, distill, regenerate_index,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
cfg = MemoryConfig(root="/tmp/memo", domains=("garden", "car"))
|
|
109
|
+
store = default_adapter(cfg.root)
|
|
110
|
+
ensure_layout(cfg, adapter=store)
|
|
111
|
+
|
|
112
|
+
capture(cfg, "garden", "Planted tomatoes, north bed.", adapter=store)
|
|
113
|
+
distill(cfg, "garden", "North bed: tomatoes planted.",
|
|
114
|
+
entities=["north bed"], lifecycle="ITERATIVE", adapter=store)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Drop a file in `DROP/NEW/` with a leading `domain: <name>` line and
|
|
118
|
+
`sweep` routes it — captured to the right domain's raw, or quarantined
|
|
119
|
+
with a reason file if it's unroutable or reads like synthesis:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
printf 'domain: work\n\nFixed the flaky test.\n' > /tmp/memo/DROP/NEW/note.md
|
|
123
|
+
python3 examples/run_local.py --root /tmp/memo sweep
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Inputs, outputs
|
|
127
|
+
|
|
128
|
+
- **Input (capture):** domain, text, optional source. Output: timestamped
|
|
129
|
+
entry appended to `<domain>/raw.md`.
|
|
130
|
+
- **Input (distill):** domain, consolidated body, optional entities /
|
|
131
|
+
entity notes / informs / open questions / lifecycle. Output:
|
|
132
|
+
`<domain>/distilled.md` with provenance frontmatter.
|
|
133
|
+
- **Input (index):** list of domains the distill touched. Output:
|
|
134
|
+
`INDEX-cross-domain.md`, or a recorded skip for single-domain distills.
|
|
135
|
+
|
|
136
|
+
## Distilled body conventions
|
|
137
|
+
|
|
138
|
+
Two line-prefixes the index understands:
|
|
139
|
+
|
|
140
|
+
- `? ` — uncertainty flag → collected into Hot Zones.
|
|
141
|
+
- `! ` — explicit raw↔distilled divergence note → collected into Hot Zones.
|
|
142
|
+
|
|
143
|
+
Entity note contradictions across domains (work says "reliable", personal
|
|
144
|
+
says "misses deadlines") also land in Hot Zones as `[tension]` entries.
|
|
145
|
+
|
|
146
|
+
## Evidence-taxonomy mapping
|
|
147
|
+
|
|
148
|
+
This package shares a vocabulary with the `adversarial-ifs` evidence
|
|
149
|
+
taxonomy (ten tiers). The mapping is explicit — memdate doesn't tag
|
|
150
|
+
evidence itself, but its artifacts sit at defined tiers:
|
|
151
|
+
|
|
152
|
+
| memdate artifact | IFS tier | Why |
|
|
153
|
+
|---|---|---|
|
|
154
|
+
| `raw.md` entry (logged event) | `OBSERVATION` | Reported/logged, not independently verified |
|
|
155
|
+
| `raw.md` entry (someone's assertion) | `CLAIM` | Explicit assertion by a source |
|
|
156
|
+
| `distilled.md` synthesis | `INFERENCE` | Conclusion drawn from raw evidence |
|
|
157
|
+
| `distilled.md` `? ` flags, index open questions | `UNKNOWN` | Flagged as not presently determinable |
|
|
158
|
+
| distiller-verified fact | `FACT` | Directly established ground truth |
|
|
159
|
+
| provisional model in a distillation | `HYPOTHESIS` | Needs stress-testing before use |
|
|
160
|
+
|
|
161
|
+
No code dependency between the packages — the table is the contract, so
|
|
162
|
+
neither taxonomy can silently fork.
|
|
163
|
+
|
|
164
|
+
## Worked example
|
|
165
|
+
|
|
166
|
+
`examples/example-1-two-domains.md` — a full CAPTURE → DISTILL → INDEX
|
|
167
|
+
cycle on two neutral domains, with the actual file contents shown at
|
|
168
|
+
each step.
|
|
169
|
+
|
|
170
|
+
*The field is constructed for teaching — it shows the mechanism's shape,
|
|
171
|
+
not real findings.*
|
|
172
|
+
|
|
173
|
+
## FAQ
|
|
174
|
+
|
|
175
|
+
**Where's Google Drive?** The original skill lived in a Drive folder.
|
|
176
|
+
This package defaults to the local filesystem; `GoogleDriveAdapter`
|
|
177
|
+
documents the seam and raises `DriveNotConfigured` with setup pointers
|
|
178
|
+
until you implement it. Drive is an adapter, not the root.
|
|
179
|
+
|
|
180
|
+
**Can a model do the distilling?** Yes — that's the intended shape. The
|
|
181
|
+
model supplies the consolidated body; the library stamps provenance and
|
|
182
|
+
enforces that raw wasn't touched. The library never calls a model itself.
|
|
183
|
+
|
|
184
|
+
**Does capture need the index?** No. Capture works from the first entry;
|
|
185
|
+
distill works per-domain; the index appears once two domains are
|
|
186
|
+
distilled.
|
|
187
|
+
|
|
188
|
+
**What about the memory interviewer?** The guided-capture interviewer
|
|
189
|
+
(`meminqu`) builds on this library's capture contract — it converts next
|
|
190
|
+
and shares this package's domain config.
|
|
191
|
+
|
|
192
|
+
## License
|
|
193
|
+
|
|
194
|
+
MIT. See LICENSE.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "memdate"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "File-based memory system with a hard CAPTURE/DISTILL split: raw records are append-only evidence, distilled files are derived synthesis, and a cross-domain index keeps the connective tissue current"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [{ name = "Ryan Wesley Hitchcock" }]
|
|
13
|
+
keywords = ["memory", "knowledge-management", "journaling", "capture", "distillation", "markdown"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.urls]
|
|
21
|
+
Homepage = "https://github.com/ohpersonperson/frontface"
|
|
22
|
+
|
|
23
|
+
[tool.setuptools.packages.find]
|
|
24
|
+
where = ["src"]
|
|
25
|
+
|
|
26
|
+
[tool.pytest.ini_options]
|
|
27
|
+
testpaths = ["tests"]
|
memdate-1.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""memdate — file-based memory with a hard CAPTURE/DISTILL split.
|
|
2
|
+
|
|
3
|
+
CAPTURE preserves raw records (append-only, timestamped, never
|
|
4
|
+
interpreted). DISTILL consolidates raw into derived distilled.md files
|
|
5
|
+
(never touching raw). INDEX regenerates the cross-domain connective
|
|
6
|
+
tissue after multi-domain distills.
|
|
7
|
+
|
|
8
|
+
Front-facing conversion of the ``memdate-v2`` skill (Ryan's
|
|
9
|
+
skill-suite, MIT). The original skill's Ryan-specific domains and Google
|
|
10
|
+
Drive root are configuration here, not defaults: domains come from
|
|
11
|
+
``MemoryConfig`` (neutral defaults shipped), storage is a
|
|
12
|
+
``StorageAdapter`` (local filesystem default, Drive an optional seam).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from .adapters import (
|
|
16
|
+
DriveNotConfigured,
|
|
17
|
+
GoogleDriveAdapter,
|
|
18
|
+
LocalFilesystemAdapter,
|
|
19
|
+
StorageAdapter,
|
|
20
|
+
StorageError,
|
|
21
|
+
default_adapter,
|
|
22
|
+
)
|
|
23
|
+
from .capture import (
|
|
24
|
+
CaptureError,
|
|
25
|
+
CaptureResult,
|
|
26
|
+
InterpretationError,
|
|
27
|
+
capture,
|
|
28
|
+
read_raw,
|
|
29
|
+
route,
|
|
30
|
+
scan_interpretation,
|
|
31
|
+
)
|
|
32
|
+
from .config import (
|
|
33
|
+
DEFAULT_DOMAINS,
|
|
34
|
+
ConfigError,
|
|
35
|
+
MemoryConfig,
|
|
36
|
+
)
|
|
37
|
+
from .distill import (
|
|
38
|
+
DistillError,
|
|
39
|
+
DistillResult,
|
|
40
|
+
distill,
|
|
41
|
+
read_distilled,
|
|
42
|
+
)
|
|
43
|
+
from .drop import SweepItem, ensure_layout, sweep_new
|
|
44
|
+
from .frontmatter import FrontmatterError
|
|
45
|
+
from .index import IndexError, IndexResult, read_index, regenerate_index
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
"MemoryConfig",
|
|
49
|
+
"ConfigError",
|
|
50
|
+
"DEFAULT_DOMAINS",
|
|
51
|
+
"StorageAdapter",
|
|
52
|
+
"StorageError",
|
|
53
|
+
"LocalFilesystemAdapter",
|
|
54
|
+
"GoogleDriveAdapter",
|
|
55
|
+
"DriveNotConfigured",
|
|
56
|
+
"default_adapter",
|
|
57
|
+
"CaptureError",
|
|
58
|
+
"CaptureResult",
|
|
59
|
+
"InterpretationError",
|
|
60
|
+
"capture",
|
|
61
|
+
"read_raw",
|
|
62
|
+
"route",
|
|
63
|
+
"scan_interpretation",
|
|
64
|
+
"DistillError",
|
|
65
|
+
"DistillResult",
|
|
66
|
+
"distill",
|
|
67
|
+
"read_distilled",
|
|
68
|
+
"SweepItem",
|
|
69
|
+
"ensure_layout",
|
|
70
|
+
"sweep_new",
|
|
71
|
+
"FrontmatterError",
|
|
72
|
+
"IndexError",
|
|
73
|
+
"IndexResult",
|
|
74
|
+
"read_index",
|
|
75
|
+
"regenerate_index",
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
__version__ = "1.0.0"
|