outmem 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.
- outmem-0.1.0/.github/workflows/publish.yml +69 -0
- outmem-0.1.0/.gitignore +67 -0
- outmem-0.1.0/LICENSE +21 -0
- outmem-0.1.0/PKG-INFO +458 -0
- outmem-0.1.0/README.md +402 -0
- outmem-0.1.0/config.yaml +30 -0
- outmem-0.1.0/docs/cli.md +188 -0
- outmem-0.1.0/docs/configuration.md +153 -0
- outmem-0.1.0/docs/development.md +72 -0
- outmem-0.1.0/docs/features.md +197 -0
- outmem-0.1.0/docs/growing-the-wiki.md +129 -0
- outmem-0.1.0/docs/python-api.md +360 -0
- outmem-0.1.0/evals/README.md +202 -0
- outmem-0.1.0/evals/__init__.py +34 -0
- outmem-0.1.0/evals/cases/__init__.py +31 -0
- outmem-0.1.0/evals/cases/approval.py +87 -0
- outmem-0.1.0/evals/cases/contradictions.py +39 -0
- outmem-0.1.0/evals/cases/convergence.py +34 -0
- outmem-0.1.0/evals/cases/duplicates.py +36 -0
- outmem-0.1.0/evals/cases/expansion.py +26 -0
- outmem-0.1.0/evals/cases/ingestion.py +30 -0
- outmem-0.1.0/evals/cases/multi_author.py +44 -0
- outmem-0.1.0/evals/cases/writeback.py +29 -0
- outmem-0.1.0/evals/config.py +83 -0
- outmem-0.1.0/evals/fixtures/wikis/approval-fallback/config.yaml +31 -0
- outmem-0.1.0/evals/fixtures/wikis/approval-fallback/wiki/pricing-formula.md +9 -0
- outmem-0.1.0/evals/fixtures/wikis/approval-fallback/wiki/q1-product-roadmap.md +14 -0
- outmem-0.1.0/evals/fixtures/wikis/approval-fallback/wiki/sources/.sources.db +0 -0
- outmem-0.1.0/evals/fixtures/wikis/approval-fallback/wiki/sources/q1-product-roadmap.md +16 -0
- outmem-0.1.0/evals/fixtures/wikis/duplicate-trap/config.yaml +31 -0
- outmem-0.1.0/evals/fixtures/wikis/duplicate-trap/wiki/cat-drug-dosages.md +19 -0
- outmem-0.1.0/evals/fixtures/wikis/duplicate-trap/wiki/sources/.sources.db +0 -0
- outmem-0.1.0/evals/fixtures/wikis/duplicate-trap/wiki/sources/veterinary/drugs.md +11 -0
- outmem-0.1.0/evals/fixtures/wikis/multi-author-divergence/CONTRIBUTORS.md +5 -0
- outmem-0.1.0/evals/fixtures/wikis/multi-author-divergence/SEED.md +8 -0
- outmem-0.1.0/evals/fixtures/wikis/multi-author-divergence/config.yaml +31 -0
- outmem-0.1.0/evals/fixtures/wikis/multi-author-divergence/log/2026-05-04.md +5 -0
- outmem-0.1.0/evals/fixtures/wikis/multi-author-divergence/wiki/pricing-formula.md +13 -0
- outmem-0.1.0/evals/fixtures/wikis/no-match-query/config.yaml +31 -0
- outmem-0.1.0/evals/fixtures/wikis/no-match-query/wiki/onboarding.md +10 -0
- outmem-0.1.0/evals/fixtures/wikis/no-match-query/wiki/team-handbook.md +11 -0
- outmem-0.1.0/evals/fixtures/wikis/pricing-cost-plus/CONTRIBUTORS.md +4 -0
- outmem-0.1.0/evals/fixtures/wikis/pricing-cost-plus/config.yaml +31 -0
- outmem-0.1.0/evals/fixtures/wikis/pricing-cost-plus/raw/pricing-deck-2026-Q1.md +13 -0
- outmem-0.1.0/evals/fixtures/wikis/pricing-cost-plus/wiki/acme-msa.md +14 -0
- outmem-0.1.0/evals/fixtures/wikis/pricing-cost-plus/wiki/pricing-formula.md +18 -0
- outmem-0.1.0/evals/fixtures/wikis/raw-contradicts-wiki/config.yaml +31 -0
- outmem-0.1.0/evals/fixtures/wikis/raw-contradicts-wiki/raw/sales-policy-2025.md +11 -0
- outmem-0.1.0/evals/fixtures/wikis/raw-contradicts-wiki/wiki/discounts.md +17 -0
- outmem-0.1.0/evals/fixtures/wikis/stale-wikilink/config.yaml +31 -0
- outmem-0.1.0/evals/fixtures/wikis/stale-wikilink/wiki/acme-msa.md +11 -0
- outmem-0.1.0/evals/fixtures/wikis/stale-wikilink/wiki/pricing-formula.md +12 -0
- outmem-0.1.0/evals/fixtures/wikis/temporal-evolution/SEED.md +11 -0
- outmem-0.1.0/evals/fixtures/wikis/temporal-evolution/config.yaml +31 -0
- outmem-0.1.0/evals/fixtures/wikis/temporal-evolution/log/2025-06-01.md +3 -0
- outmem-0.1.0/evals/fixtures/wikis/temporal-evolution/log/2026-02-10.md +4 -0
- outmem-0.1.0/evals/fixtures/wikis/temporal-evolution/wiki/pricing-formula.md +12 -0
- outmem-0.1.0/evals/harness.py +715 -0
- outmem-0.1.0/evals/judges/__init__.py +10 -0
- outmem-0.1.0/evals/judges/llm_judge.py +95 -0
- outmem-0.1.0/evals/judges/trace.py +8 -0
- outmem-0.1.0/evals/run.py +225 -0
- outmem-0.1.0/evals/subagent_e2e.py +266 -0
- outmem-0.1.0/examples/starter-wiki/CONTRIBUTORS.md +8 -0
- outmem-0.1.0/examples/starter-wiki/README.md +72 -0
- outmem-0.1.0/examples/starter-wiki/config.yaml +43 -0
- outmem-0.1.0/examples/starter-wiki/log/2026-05-01.md +9 -0
- outmem-0.1.0/examples/starter-wiki/raw/acme-msa-text.md +30 -0
- outmem-0.1.0/examples/starter-wiki/raw/pricing-deck-2026-Q1.md +43 -0
- outmem-0.1.0/examples/starter-wiki/wiki/acme-msa.md +22 -0
- outmem-0.1.0/examples/starter-wiki/wiki/pricing-formula.md +27 -0
- outmem-0.1.0/pyproject.toml +108 -0
- outmem-0.1.0/specs/concept.md +63 -0
- outmem-0.1.0/specs/planning_prompt.md +306 -0
- outmem-0.1.0/specs/spec.md +351 -0
- outmem-0.1.0/src/outmem/__init__.py +51 -0
- outmem-0.1.0/src/outmem/_logfire.py +54 -0
- outmem-0.1.0/src/outmem/_sqlite.py +23 -0
- outmem-0.1.0/src/outmem/_store/__init__.py +0 -0
- outmem-0.1.0/src/outmem/_store/import_vault.py +308 -0
- outmem-0.1.0/src/outmem/_store/semantic.py +275 -0
- outmem-0.1.0/src/outmem/_store/sources.py +105 -0
- outmem-0.1.0/src/outmem/_time.py +45 -0
- outmem-0.1.0/src/outmem/adapters/__init__.py +10 -0
- outmem-0.1.0/src/outmem/adapters/pydantic_ai.py +803 -0
- outmem-0.1.0/src/outmem/agent/__init__.py +45 -0
- outmem-0.1.0/src/outmem/agent/approval.py +271 -0
- outmem-0.1.0/src/outmem/agent/prompts/system.j2 +183 -0
- outmem-0.1.0/src/outmem/agent/runtime.py +269 -0
- outmem-0.1.0/src/outmem/agent/service.py +342 -0
- outmem-0.1.0/src/outmem/backlinks.py +176 -0
- outmem-0.1.0/src/outmem/cli/__init__.py +12 -0
- outmem-0.1.0/src/outmem/cli/__main__.py +1046 -0
- outmem-0.1.0/src/outmem/config.py +506 -0
- outmem-0.1.0/src/outmem/dashboard/__init__.py +24 -0
- outmem-0.1.0/src/outmem/dashboard/app.py +33 -0
- outmem-0.1.0/src/outmem/dashboard/router.py +167 -0
- outmem-0.1.0/src/outmem/dashboard/service.py +60 -0
- outmem-0.1.0/src/outmem/dashboard/templates/base.html.j2 +94 -0
- outmem-0.1.0/src/outmem/dashboard/templates/wiki_history.html.j2 +19 -0
- outmem-0.1.0/src/outmem/dashboard/templates/wiki_index.html.j2 +16 -0
- outmem-0.1.0/src/outmem/dashboard/templates/wiki_page.html.j2 +38 -0
- outmem-0.1.0/src/outmem/exceptions.py +81 -0
- outmem-0.1.0/src/outmem/frontmatter.py +230 -0
- outmem-0.1.0/src/outmem/git_ops.py +494 -0
- outmem-0.1.0/src/outmem/history.py +69 -0
- outmem-0.1.0/src/outmem/identity.py +109 -0
- outmem-0.1.0/src/outmem/index.py +97 -0
- outmem-0.1.0/src/outmem/lint.py +399 -0
- outmem-0.1.0/src/outmem/observability.py +53 -0
- outmem-0.1.0/src/outmem/search.py +223 -0
- outmem-0.1.0/src/outmem/semantic/__init__.py +46 -0
- outmem-0.1.0/src/outmem/semantic/chunker.py +154 -0
- outmem-0.1.0/src/outmem/semantic/embeddings.py +97 -0
- outmem-0.1.0/src/outmem/semantic/store.py +452 -0
- outmem-0.1.0/src/outmem/semantic/testing.py +139 -0
- outmem-0.1.0/src/outmem/skills/notes/evolution/SKILL.md +96 -0
- outmem-0.1.0/src/outmem/skills/notes/evolution/references/git-log.md +50 -0
- outmem-0.1.0/src/outmem/skills/notes/search/SKILL.md +106 -0
- outmem-0.1.0/src/outmem/skills/notes/search/references/patterns.md +50 -0
- outmem-0.1.0/src/outmem/skills/notes/write/SKILL.md +156 -0
- outmem-0.1.0/src/outmem/skills/notes/write/references/commit-grammar.md +43 -0
- outmem-0.1.0/src/outmem/skills/notes/write/references/frontmatter.md +65 -0
- outmem-0.1.0/src/outmem/skills/notes/write/references/rebase-loop.md +50 -0
- outmem-0.1.0/src/outmem/skills.py +40 -0
- outmem-0.1.0/src/outmem/slug.py +73 -0
- outmem-0.1.0/src/outmem/sources.py +392 -0
- outmem-0.1.0/src/outmem/state.py +173 -0
- outmem-0.1.0/src/outmem/store.py +922 -0
- outmem-0.1.0/tests/__init__.py +0 -0
- outmem-0.1.0/tests/conftest.py +192 -0
- outmem-0.1.0/tests/test_adapters_pydantic_ai.py +358 -0
- outmem-0.1.0/tests/test_agent.py +720 -0
- outmem-0.1.0/tests/test_approval.py +474 -0
- outmem-0.1.0/tests/test_backlinks.py +139 -0
- outmem-0.1.0/tests/test_cli.py +222 -0
- outmem-0.1.0/tests/test_config.py +299 -0
- outmem-0.1.0/tests/test_dashboard.py +224 -0
- outmem-0.1.0/tests/test_evals_fixtures.py +230 -0
- outmem-0.1.0/tests/test_frontmatter.py +142 -0
- outmem-0.1.0/tests/test_git_lock.py +171 -0
- outmem-0.1.0/tests/test_git_ops.py +273 -0
- outmem-0.1.0/tests/test_history.py +54 -0
- outmem-0.1.0/tests/test_identity.py +113 -0
- outmem-0.1.0/tests/test_import_vault.py +224 -0
- outmem-0.1.0/tests/test_index.py +249 -0
- outmem-0.1.0/tests/test_ingest.py +361 -0
- outmem-0.1.0/tests/test_lint.py +219 -0
- outmem-0.1.0/tests/test_logfire_setup.py +132 -0
- outmem-0.1.0/tests/test_search.py +108 -0
- outmem-0.1.0/tests/test_semantic.py +659 -0
- outmem-0.1.0/tests/test_skills_bundle.py +150 -0
- outmem-0.1.0/tests/test_slug.py +57 -0
- outmem-0.1.0/tests/test_sources.py +337 -0
- outmem-0.1.0/tests/test_state.py +105 -0
- outmem-0.1.0/tests/test_store.py +711 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
name: Build sdist and wheel
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
|
|
22
|
+
- name: Install ripgrep
|
|
23
|
+
run: sudo apt-get update && sudo apt-get install -y ripgrep
|
|
24
|
+
|
|
25
|
+
- name: Verify release tag matches package version
|
|
26
|
+
run: |
|
|
27
|
+
tag="${GITHUB_REF_NAME#v}"
|
|
28
|
+
pkg=$(python -c "import tomllib,pathlib; print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version'])")
|
|
29
|
+
if [ "$tag" != "$pkg" ]; then
|
|
30
|
+
echo "Release tag v$tag does not match pyproject.toml version $pkg" >&2
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
- name: Install build
|
|
35
|
+
run: python -m pip install --upgrade build
|
|
36
|
+
|
|
37
|
+
- name: Install package with dev extras (for tests)
|
|
38
|
+
run: python -m pip install -e ".[dev,agent,dashboard,semantic]"
|
|
39
|
+
|
|
40
|
+
- name: Run tests
|
|
41
|
+
run: python -m pytest -q
|
|
42
|
+
|
|
43
|
+
- name: Build distributions
|
|
44
|
+
run: python -m build
|
|
45
|
+
|
|
46
|
+
- name: Upload distributions
|
|
47
|
+
uses: actions/upload-artifact@v4
|
|
48
|
+
with:
|
|
49
|
+
name: dist
|
|
50
|
+
path: dist/
|
|
51
|
+
|
|
52
|
+
publish:
|
|
53
|
+
name: Publish to PyPI
|
|
54
|
+
needs: build
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
environment:
|
|
57
|
+
name: pypi
|
|
58
|
+
url: https://pypi.org/p/outmem
|
|
59
|
+
permissions:
|
|
60
|
+
id-token: write
|
|
61
|
+
steps:
|
|
62
|
+
- name: Download distributions
|
|
63
|
+
uses: actions/download-artifact@v4
|
|
64
|
+
with:
|
|
65
|
+
name: dist
|
|
66
|
+
path: dist/
|
|
67
|
+
|
|
68
|
+
- name: Publish to PyPI
|
|
69
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
outmem-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Virtualenvs
|
|
2
|
+
.venv/
|
|
3
|
+
venv/
|
|
4
|
+
ENV/
|
|
5
|
+
|
|
6
|
+
# Python build artefacts
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
*.egg
|
|
11
|
+
|
|
12
|
+
# Python bytecode + extensions
|
|
13
|
+
__pycache__/
|
|
14
|
+
*.py[cod]
|
|
15
|
+
*$py.class
|
|
16
|
+
*.so
|
|
17
|
+
|
|
18
|
+
# Tooling caches — each tool drops its own self-ignore inside the cache
|
|
19
|
+
# dir, but only AFTER first run. Listing here is defensive.
|
|
20
|
+
.mypy_cache/
|
|
21
|
+
.pytest_cache/
|
|
22
|
+
.ruff_cache/
|
|
23
|
+
.pyright/
|
|
24
|
+
.pytype/
|
|
25
|
+
.coverage
|
|
26
|
+
.coverage.*
|
|
27
|
+
htmlcov/
|
|
28
|
+
.tox/
|
|
29
|
+
.hypothesis/
|
|
30
|
+
|
|
31
|
+
# Notebooks
|
|
32
|
+
.ipynb_checkpoints/
|
|
33
|
+
|
|
34
|
+
# Lockfiles — outmem is a library; consumers pick their own resolver.
|
|
35
|
+
uv.lock
|
|
36
|
+
poetry.lock
|
|
37
|
+
Pipfile.lock
|
|
38
|
+
|
|
39
|
+
# Pyenv pin — let contributors use any 3.12+ patch.
|
|
40
|
+
.python-version
|
|
41
|
+
|
|
42
|
+
# Secrets — never commit.
|
|
43
|
+
.env
|
|
44
|
+
.env.*
|
|
45
|
+
.secrets.*
|
|
46
|
+
|
|
47
|
+
# Outmem wiki state — only created if a contributor points
|
|
48
|
+
# OUTMEM_PATH at this repo during dev.
|
|
49
|
+
.outmem/
|
|
50
|
+
.vectors.db
|
|
51
|
+
|
|
52
|
+
# IDE / editor
|
|
53
|
+
.idea/
|
|
54
|
+
.vscode/
|
|
55
|
+
.cursor/
|
|
56
|
+
.zed/
|
|
57
|
+
*.swp
|
|
58
|
+
*.swo
|
|
59
|
+
*~
|
|
60
|
+
|
|
61
|
+
# Scratch
|
|
62
|
+
tmp/
|
|
63
|
+
|
|
64
|
+
# OS junk
|
|
65
|
+
.DS_Store
|
|
66
|
+
Thumbs.db
|
|
67
|
+
Desktop.ini
|
outmem-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 phiweger
|
|
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.
|
outmem-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: outmem
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Agentic RAG memory: a git-versioned wiki an agent maintains for itself and a team.
|
|
5
|
+
Project-URL: Repository, https://github.com/phiweger/outmem
|
|
6
|
+
Author: phiweger
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: agent,git,memory,rag,wiki
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Requires-Dist: python-dotenv>=1.0
|
|
19
|
+
Requires-Dist: pyyaml>=6.0
|
|
20
|
+
Requires-Dist: skillfull>=0.2.0
|
|
21
|
+
Provides-Extra: agent
|
|
22
|
+
Requires-Dist: jinja2>=3.1; extra == 'agent'
|
|
23
|
+
Requires-Dist: pydantic-ai>=0.1.0; extra == 'agent'
|
|
24
|
+
Provides-Extra: all
|
|
25
|
+
Requires-Dist: fastapi>=0.115; extra == 'all'
|
|
26
|
+
Requires-Dist: jinja2>=3.1; extra == 'all'
|
|
27
|
+
Requires-Dist: logfire>=3.0; extra == 'all'
|
|
28
|
+
Requires-Dist: markdown-it-py>=3.0; extra == 'all'
|
|
29
|
+
Requires-Dist: pydantic-ai>=0.1.0; extra == 'all'
|
|
30
|
+
Requires-Dist: sqlite-vec>=0.1.7; extra == 'all'
|
|
31
|
+
Requires-Dist: uvicorn[standard]>=0.30; extra == 'all'
|
|
32
|
+
Provides-Extra: dashboard
|
|
33
|
+
Requires-Dist: fastapi>=0.115; extra == 'dashboard'
|
|
34
|
+
Requires-Dist: jinja2>=3.1; extra == 'dashboard'
|
|
35
|
+
Requires-Dist: markdown-it-py>=3.0; extra == 'dashboard'
|
|
36
|
+
Requires-Dist: uvicorn[standard]>=0.30; extra == 'dashboard'
|
|
37
|
+
Provides-Extra: dev
|
|
38
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
39
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
40
|
+
Requires-Dist: pytest>=8.3; extra == 'dev'
|
|
41
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
42
|
+
Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
|
|
43
|
+
Provides-Extra: evals
|
|
44
|
+
Requires-Dist: jinja2>=3.1; extra == 'evals'
|
|
45
|
+
Requires-Dist: pydantic-ai>=0.1.0; extra == 'evals'
|
|
46
|
+
Requires-Dist: pytest>=8.3; extra == 'evals'
|
|
47
|
+
Requires-Dist: sqlite-vec>=0.1.7; extra == 'evals'
|
|
48
|
+
Provides-Extra: logfire
|
|
49
|
+
Requires-Dist: logfire>=3.0; extra == 'logfire'
|
|
50
|
+
Provides-Extra: pydantic-ai
|
|
51
|
+
Requires-Dist: pydantic-ai>=0.1.0; extra == 'pydantic-ai'
|
|
52
|
+
Provides-Extra: semantic
|
|
53
|
+
Requires-Dist: pydantic-ai>=0.1.0; extra == 'semantic'
|
|
54
|
+
Requires-Dist: sqlite-vec>=0.1.7; extra == 'semantic'
|
|
55
|
+
Description-Content-Type: text/markdown
|
|
56
|
+
|
|
57
|
+
# outmem
|
|
58
|
+
|
|
59
|
+
**Agentic RAG memory over a git-versioned wiki.**
|
|
60
|
+
|
|
61
|
+
A standalone Python library + CLI for maintaining a directory of
|
|
62
|
+
plain-markdown notes that an LLM agent compiles, retrieves from, and
|
|
63
|
+
writes back to. Retrieval is shell-tool based (`ripgrep`, `git log`,
|
|
64
|
+
`cat`) — no vector index by default — and every agent turn is required
|
|
65
|
+
to produce a git commit so identical future queries don't re-pay
|
|
66
|
+
retrieval cost.
|
|
67
|
+
|
|
68
|
+
This implements the pattern in [`specs/concept.md`](specs/concept.md):
|
|
69
|
+
the LLM owns the wiki, the human curates sources and asks questions,
|
|
70
|
+
the wiki is a compounding artifact that gets richer with every source
|
|
71
|
+
ingested.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Main idea
|
|
76
|
+
|
|
77
|
+
outmem is a deliberate inversion of conventional RAG. Instead of
|
|
78
|
+
pre-indexing raw sources into a vector store and reaching into them
|
|
79
|
+
on every query, the agent **compiles** raw material into a wiki of
|
|
80
|
+
small markdown pages, **retrieves** over the compiled material with
|
|
81
|
+
shell tools (`ripgrep`, `git log`, `cat`), and is **required to
|
|
82
|
+
commit** at the end of every turn — so identical future queries
|
|
83
|
+
don't re-pay retrieval cost. The wiki compounds; the vector index
|
|
84
|
+
that would otherwise grow stale doesn't exist.
|
|
85
|
+
|
|
86
|
+
Three design choices anchor the rest of the system:
|
|
87
|
+
|
|
88
|
+
1. **Compaction first.** The cheapest retrieval is reading a compiled
|
|
89
|
+
wiki page; raw sources are the fall-through, not the default. This
|
|
90
|
+
directly attacks the *relevance trap* — the gap between embedding
|
|
91
|
+
similarity and actual usefulness ([Raudaschl, "The Relevance
|
|
92
|
+
Trap"][rt]; [Fleck, "Divergence Engines"][de]).
|
|
93
|
+
2. **Git as the substrate.** Every write produces a commit; `git log`
|
|
94
|
+
is both the audit trail and the agent's steering signal (recent
|
|
95
|
+
human commits become phase-1 planning context), and `git blame`
|
|
96
|
+
tracks line-level authorship. The same move Claude Code makes for
|
|
97
|
+
code search — agentic shell tools, no index — works here for
|
|
98
|
+
prose ([Nicolai, "Claude Code Doesn't Index Your
|
|
99
|
+
Codebase"][cc]; [SmartScope, "Settling the RAG Debate"][rd]).
|
|
100
|
+
3. **Mandatory writeback.** Every agent turn ends with at least one
|
|
101
|
+
commit (`compact:` / `extend:` / `log:`), so the system records
|
|
102
|
+
not just what was retrieved but what it was retrieved *for*. The
|
|
103
|
+
pattern is closest to Karpathy's "LLM Wiki" sketch
|
|
104
|
+
([gist][kw]). Adoption is measured via the **TARS** product
|
|
105
|
+
metric — Target / Adopted / Retained / Satisfied — rather than
|
|
106
|
+
recall@k or nDCG ([Raudaschl, "TARS"][tars]).
|
|
107
|
+
|
|
108
|
+
A single divergence primitive ships in v0.1 — `topic_evolution`, a
|
|
109
|
+
chronological `git log -p` over a topic — for the class of question
|
|
110
|
+
convergent retrieval can't answer ("how has our thinking on X
|
|
111
|
+
changed?"). The four other divergence primitives sketched in
|
|
112
|
+
`concept.md` (contradiction surfacer, negative-space query,
|
|
113
|
+
associative drift, cross-domain bridges) are queued for when the
|
|
114
|
+
first one has earned its place.
|
|
115
|
+
|
|
116
|
+
The full conceptual rationale and v0.1 implementation spec live in
|
|
117
|
+
[`specs/concept.md`](specs/concept.md) and
|
|
118
|
+
[`specs/spec.md`](specs/spec.md).
|
|
119
|
+
|
|
120
|
+
[rt]: https://breakingproduct.substack.com/p/the-relevance-trap
|
|
121
|
+
[tars]: https://uxdesign.cc/tars-a-product-metric-game-changer-c523f260306a
|
|
122
|
+
[de]: https://medium.com/@j0lian/divergence-engines-escaping-the-relevance-trap-1bbdbee55ea6
|
|
123
|
+
[cc]: https://vadim.blog/claude-code-no-indexing
|
|
124
|
+
[rd]: https://smartscope.blog/en/ai-development/practices/rag-debate-agentic-search-code-exploration/
|
|
125
|
+
[kw]: https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Install
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
pip install outmem # core: WikiStore + CLI
|
|
133
|
+
pip install outmem[all] # everything: agent runtime, semantic, dashboard, logfire
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Or pick a subset:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
pip install outmem[agent] # + standalone PydanticAI agent runtime
|
|
140
|
+
pip install outmem[semantic] # + sqlite-vec index for find_similar
|
|
141
|
+
pip install outmem[dashboard] # + read-only FastAPI dashboard
|
|
142
|
+
pip install outmem[logfire] # + Pydantic Logfire instrumentation
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
System: Python 3.12+, `git`, and `ripgrep` (`rg`) on PATH. `outmem init`
|
|
146
|
+
checks for these and refuses to proceed if either is missing.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## The 60-second mental model
|
|
151
|
+
|
|
152
|
+
outmem maintains four directories under one wiki root:
|
|
153
|
+
|
|
154
|
+
| Directory | Tracked in git | Who writes | What lives there |
|
|
155
|
+
|-------------|----------------|------------|------------------|
|
|
156
|
+
| `raw/` | no | upstream ingestion pipeline | plain-text/markdown source material |
|
|
157
|
+
| `wiki/` | **yes** | agent + humans (via Obsidian) | compiled knowledge, one concept per file, YAML frontmatter + `[[wikilinks]]` |
|
|
158
|
+
| `log/` | **yes** | agent + humans | dated decision / observation trail |
|
|
159
|
+
| `.outmem/` | no (auto-gitignored) | outmem | non-git state (backlinks cache, last-run marker) |
|
|
160
|
+
|
|
161
|
+
Plus two special wiki-root files:
|
|
162
|
+
|
|
163
|
+
- **`wiki/AGENTS.md`** — user-editable conventions doc loaded into the
|
|
164
|
+
agent's system prompt every turn. Your customization layer for
|
|
165
|
+
domain, page structure, source-handling preferences.
|
|
166
|
+
- **`wiki/index.md`** — auto-maintained slug list, regenerated on
|
|
167
|
+
every write.
|
|
168
|
+
|
|
169
|
+
The agent's loop per turn:
|
|
170
|
+
|
|
171
|
+
1. **Orient** — read recent human commits (steering signal); choose
|
|
172
|
+
*convergence* (look up a fact) or *expansion* (walk history).
|
|
173
|
+
2. **Retrieve** — cheapest tool first: `rg wiki/`, then `rg raw/`,
|
|
174
|
+
then `git log -p --follow` for the expansion path.
|
|
175
|
+
3. **Compact** — produce at least one commit before responding
|
|
176
|
+
(`compact:` for new pages, `extend:` for edits, `log:` for
|
|
177
|
+
observations). **Mandatory** — runs that skip it raise `WritebackError`.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Quickstart
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Scaffold a fresh wiki.
|
|
185
|
+
outmem init /srv/my-wiki
|
|
186
|
+
export OUTMEM_PATH=/srv/my-wiki
|
|
187
|
+
|
|
188
|
+
# Optional: tell the agent what this wiki is for.
|
|
189
|
+
${EDITOR:-vi} /srv/my-wiki/wiki/AGENTS.md
|
|
190
|
+
|
|
191
|
+
# Optional: ask the agent something (requires outmem[agent] + an API key).
|
|
192
|
+
export OUTMEM_MODEL="anthropic:claude-sonnet-4-6"
|
|
193
|
+
echo "ANTHROPIC_API_KEY=sk-ant-..." > .env
|
|
194
|
+
outmem ask "what's our pricing policy?"
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
There's also a pre-populated example wiki at
|
|
198
|
+
[`examples/starter-wiki/`](examples/starter-wiki/) if you want to
|
|
199
|
+
poke at outmem before scaffolding your own.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Common workflows
|
|
204
|
+
|
|
205
|
+
### Ask the agent
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
outmem ask "what is our pricing formula and where does it come from?"
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Searches the wiki first, falls back to `raw/` if needed, and produces
|
|
212
|
+
at least one commit before responding — either extending a wiki page
|
|
213
|
+
(`extend: <slug>`) or logging the observation (`log: <topic>`).
|
|
214
|
+
|
|
215
|
+
### Ingest a source document
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
outmem ingest /path/to/some-paper.md \
|
|
219
|
+
--into research \
|
|
220
|
+
--prompt "extract methodology and headline results"
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Copies the file under `wiki/sources/[<into>/]<sha256[:12]>/`,
|
|
224
|
+
registers it in `wiki/sources/.sources.db`, then runs the agent to
|
|
225
|
+
write/extend pages with `provenance:` pointing at the registered
|
|
226
|
+
source. Parallel `outmem ingest` runs are safe (SQLite serialises
|
|
227
|
+
writers). See [docs/cli.md](docs/cli.md#ingestion-requires-outmemagent)
|
|
228
|
+
for `--register-only`, re-ingest semantics, and file-type rules.
|
|
229
|
+
|
|
230
|
+
### Import an existing markdown vault (Obsidian, plain notes folder)
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
outmem import /path/to/obsidian-vault
|
|
234
|
+
outmem lint # surface anything not auto-resolved
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
One-shot bulk import: walks the source for `*.md`, generates
|
|
238
|
+
frontmatter, normalises slugs to outmem's flat namespace, rewrites
|
|
239
|
+
wikilinks, and commits everything as `import: <vault-name>`. Hidden
|
|
240
|
+
dirs (`.obsidian/`, `.git/`, …) are skipped. See
|
|
241
|
+
[docs/cli.md](docs/cli.md#import-existing-markdown-vault) for
|
|
242
|
+
collision handling and `--force` semantics.
|
|
243
|
+
|
|
244
|
+
### Edit wiki files manually (Obsidian, vim, VS Code)
|
|
245
|
+
|
|
246
|
+
Edit `wiki/*.md` however you like — outmem keeps the agent happy
|
|
247
|
+
as long as you commit through git. Install the pre-commit hook once
|
|
248
|
+
so the auto-maintained `wiki/index.md` and the semantic vector DB
|
|
249
|
+
stay in lockstep with your edits:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
outmem hook install
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Without the hook, the explicit commands are `outmem index rebuild`
|
|
256
|
+
and `outmem reindex`. See [docs/cli.md](docs/cli.md#sync-derived-artefacts-after-manual-edits).
|
|
257
|
+
|
|
258
|
+
### Sync across machines
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
outmem pull
|
|
262
|
+
outmem push
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
The agent does pull-rebase-push around every `outmem ask` by default
|
|
266
|
+
(disable with `--no-pull` / `--no-push`). outmem's git operations
|
|
267
|
+
are vanilla; any other tool (Obsidian Git plugin, GitHub Desktop,
|
|
268
|
+
plain `git`) interoperates.
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Wiki page format
|
|
273
|
+
|
|
274
|
+
Every `wiki/<slug>.md` opens with YAML frontmatter:
|
|
275
|
+
|
|
276
|
+
```yaml
|
|
277
|
+
---
|
|
278
|
+
title: Pricing formula
|
|
279
|
+
slug: pricing-formula
|
|
280
|
+
provenance:
|
|
281
|
+
- path: raw/pricing-deck-2026-Q1.md
|
|
282
|
+
drive_path: /shared/Sales/2026-Q1-pricing-deck.pdf
|
|
283
|
+
sha256: 9e2c1f00aa
|
|
284
|
+
created: 2026-01-15T10:30:00Z
|
|
285
|
+
updated: 2026-05-04T11:32:00Z
|
|
286
|
+
tags: [pricing, contracts, finance]
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
The 2026 pricing formula is **cost-plus 35%**…
|
|
290
|
+
|
|
291
|
+
See also [[acme-msa]] for the Acme exception.
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
`provenance:` accepts plain path strings or dicts with richer
|
|
295
|
+
ingestion metadata. There's no `authority` field — anyone (human or
|
|
296
|
+
agent) may edit any page; "who wrote what" is reconstructed from
|
|
297
|
+
`git log` / `git blame`. Wikilinks (`[[slug]]`) resolve to
|
|
298
|
+
`wiki/<slug>.md`.
|
|
299
|
+
|
|
300
|
+
Full schema: [docs/python-api.md](docs/python-api.md#writing--three-paths).
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Embed in your own PydanticAI agent
|
|
305
|
+
|
|
306
|
+
If you want outmem as a *component* of a larger agent (virtual
|
|
307
|
+
assistant, RAG pipeline, etc.) rather than as its own runtime,
|
|
308
|
+
attach the tools + the same system prompt `outmem ask` uses to your
|
|
309
|
+
own `pydantic_ai.Agent`:
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
from pydantic_ai import Agent
|
|
313
|
+
|
|
314
|
+
from outmem import WikiStore
|
|
315
|
+
from outmem.adapters.pydantic_ai import wiki_tools
|
|
316
|
+
from outmem.agent import render_system_prompt
|
|
317
|
+
|
|
318
|
+
store = WikiStore.open("/path/to/wiki")
|
|
319
|
+
|
|
320
|
+
agent = Agent(
|
|
321
|
+
"anthropic:claude-sonnet-4-6",
|
|
322
|
+
tools=wiki_tools(store), # 9 typed functions
|
|
323
|
+
system_prompt=render_system_prompt(store), # identical to outmem ask's
|
|
324
|
+
)
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
`render_system_prompt(store)` returns the **exact same prompt string**
|
|
328
|
+
the bundled `outmem ask` runtime sends — the three-phase framing
|
|
329
|
+
(orient / retrieve / compact), recent human commits as steering
|
|
330
|
+
signal, the bundled skill bodies (`search` / `evolution` / `write`),
|
|
331
|
+
and your wiki's `AGENTS.md`. Tools + prompt → your agent has prompt-
|
|
332
|
+
level parity with `outmem ask`. Pass `include_steering=False` if you
|
|
333
|
+
don't want the phase-1 steering signal injected (handy for stateless
|
|
334
|
+
assistant turns).
|
|
335
|
+
|
|
336
|
+
**What you don't get in embed mode** (intentional — these are runtime
|
|
337
|
+
concerns):
|
|
338
|
+
|
|
339
|
+
- Mandatory writeback enforcement
|
|
340
|
+
- Pull-before / push-after / record-run lifecycle
|
|
341
|
+
- HITL approval gate around `write_page` / `extend_page`
|
|
342
|
+
- Default `max_tokens=16384` and Anthropic prompt caching
|
|
343
|
+
|
|
344
|
+
If you want those too, the all-in-one is `outmem.agent.ask_sync(store, query=…)`.
|
|
345
|
+
|
|
346
|
+
**Fine-grained control** — if you want to compose the prompt yourself
|
|
347
|
+
(e.g. prepend your own preamble, swap skill selection, omit AGENTS.md),
|
|
348
|
+
the building blocks are all public:
|
|
349
|
+
|
|
350
|
+
```python
|
|
351
|
+
from outmem.adapters.pydantic_ai import skill_text, wiki_tools
|
|
352
|
+
|
|
353
|
+
agents_md = store.read_agents_md() or ""
|
|
354
|
+
agent = Agent(
|
|
355
|
+
"anthropic:claude-sonnet-4-6",
|
|
356
|
+
tools=wiki_tools(store),
|
|
357
|
+
system_prompt=(
|
|
358
|
+
"You are a helpful assistant.\n\n"
|
|
359
|
+
+ skill_text("search")
|
|
360
|
+
+ skill_text("write")
|
|
361
|
+
+ (f"\n# Wiki conventions\n\n{agents_md}" if agents_md else "")
|
|
362
|
+
),
|
|
363
|
+
)
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Read-only consult — wiki as a tool in someone else's agent
|
|
369
|
+
|
|
370
|
+
When you've curated a wiki and want an *external* agent to consult it
|
|
371
|
+
without ever modifying it, there's a one-call factory:
|
|
372
|
+
|
|
373
|
+
```python
|
|
374
|
+
from pydantic_ai import Agent
|
|
375
|
+
from outmem.adapters.pydantic_ai import build_consult_wiki
|
|
376
|
+
|
|
377
|
+
consult_wiki = build_consult_wiki("/srv/curated-wiki")
|
|
378
|
+
|
|
379
|
+
my_assistant = Agent(
|
|
380
|
+
"anthropic:claude-sonnet-4-6",
|
|
381
|
+
tools=[consult_wiki],
|
|
382
|
+
system_prompt=(
|
|
383
|
+
"You're a helpful assistant. For questions about internal "
|
|
384
|
+
"policies, decisions, or customer history, call `consult_wiki`."
|
|
385
|
+
),
|
|
386
|
+
)
|
|
387
|
+
result = my_assistant.run_sync("What's our pricing policy?")
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
`build_consult_wiki` opens the wiki via
|
|
391
|
+
`WikiStore.open(path, read_only=True)` and builds an inner PydanticAI
|
|
392
|
+
agent with the read-only tool palette (search / read / list / backlinks
|
|
393
|
+
/ history / evolution / sources) plus a tight "cite by `[[slug]]`,
|
|
394
|
+
explicitly say so if the wiki has nothing on the topic" system prompt
|
|
395
|
+
and the same `max_tokens=16384` + Anthropic prompt-caching settings as
|
|
396
|
+
the full `outmem ask` runtime. The outer agent gets a black-box
|
|
397
|
+
`consult_wiki(question) -> str` tool — outmem-internal vocabulary
|
|
398
|
+
never leaks across the boundary.
|
|
399
|
+
|
|
400
|
+
What `read_only=True` guarantees:
|
|
401
|
+
|
|
402
|
+
- Every commit-producing entry point on `WikiStore` (`write_page`,
|
|
403
|
+
`extend_page`, `append_log`, `add_source`, `record_ingestion`,
|
|
404
|
+
`rebuild_index`, `import_vault`) raises `OutmemError` via a single
|
|
405
|
+
guard in `_commit_paths`. `pull()` is also refused (rebase mutates
|
|
406
|
+
the working tree). `push()` stays unguarded — nothing local to push.
|
|
407
|
+
- The read-tool palette doesn't even expose write tools (defense in
|
|
408
|
+
depth — the model never sees the write API).
|
|
409
|
+
- `WikiStore.open(read_only=True)` skips the directory-creating layout
|
|
410
|
+
step, skips the stale `.git/index.lock` cleanup, and the backlinks
|
|
411
|
+
cache runs memo-only (no writes to `.outmem/`). The wiki's
|
|
412
|
+
filesystem state is left exactly as the caller found it, which makes
|
|
413
|
+
the mode safe to use on a literally read-only mount.
|
|
414
|
+
|
|
415
|
+
For finer-grained control (custom system prompt, your own retry logic):
|
|
416
|
+
|
|
417
|
+
```python
|
|
418
|
+
from pydantic_ai import Agent
|
|
419
|
+
from outmem import WikiStore
|
|
420
|
+
from outmem.adapters.pydantic_ai import wiki_read_tools
|
|
421
|
+
|
|
422
|
+
store = WikiStore.open("/srv/curated-wiki", read_only=True)
|
|
423
|
+
agent = Agent(
|
|
424
|
+
"anthropic:claude-sonnet-4-6",
|
|
425
|
+
tools=wiki_read_tools(store),
|
|
426
|
+
system_prompt="You answer from the wiki only. Cite [[slugs]].",
|
|
427
|
+
)
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## Where to go next
|
|
433
|
+
|
|
434
|
+
- [`docs/cli.md`](docs/cli.md) — every subcommand with examples.
|
|
435
|
+
- [`docs/python-api.md`](docs/python-api.md) — `WikiStore` + the
|
|
436
|
+
PydanticAI adapter + the standalone agent runtime.
|
|
437
|
+
- [`docs/growing-the-wiki.md`](docs/growing-the-wiki.md) — reading
|
|
438
|
+
the log + lint signals to figure out what to ingest next.
|
|
439
|
+
- [`docs/configuration.md`](docs/configuration.md) — `wiki/AGENTS.md`,
|
|
440
|
+
`config.yaml`, `.env`, environment variables, system requirements.
|
|
441
|
+
- [`docs/features.md`](docs/features.md) — semantic index, write
|
|
442
|
+
approval, Logfire, dashboard (all opt-in).
|
|
443
|
+
- [`docs/development.md`](docs/development.md) — dev install,
|
|
444
|
+
repository layout.
|
|
445
|
+
- [`specs/concept.md`](specs/concept.md) — the original pattern this
|
|
446
|
+
implements.
|
|
447
|
+
- [`specs/spec.md`](specs/spec.md) — v0.1 implementation spec.
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## Status
|
|
452
|
+
|
|
453
|
+
v0.1 + a v0.10-tagged batch of refinements (SQLite source registry,
|
|
454
|
+
parallel-safe ingest, shared `_sqlite` / `_time` / `_logfire` helpers,
|
|
455
|
+
`wiki/AGENTS.md` schema doc, `store.py` split into facets, README
|
|
456
|
+
restructure). Tests + ruff + mypy strict clean.
|
|
457
|
+
|
|
458
|
+
To give feedback, report at <https://github.com/phiweger/outmem/issues>.
|