|
| 1 | +--- |
| 2 | +title: 'SPEC-15: Configuration Persistence via Tigris for Cloud Tenants' |
| 3 | +type: spec |
| 4 | +permalink: specs/spec-14-config-persistence-tigris |
| 5 | +tags: |
| 6 | +- persistence |
| 7 | +- tigris |
| 8 | +- multi-tenant |
| 9 | +- infrastructure |
| 10 | +- configuration |
| 11 | +status: draft |
| 12 | +--- |
| 13 | + |
| 14 | +# SPEC-15: Configuration Persistence via Tigris for Cloud Tenants |
| 15 | + |
| 16 | +## Why |
| 17 | + |
| 18 | +We need to persist Basic Memory configuration across Fly.io deployments without using persistent volumes or external databases. |
| 19 | + |
| 20 | +**Current Problems:** |
| 21 | +- `~/.basic-memory/config.json` lost on every deployment (project configuration) |
| 22 | +- `~/.basic-memory/memory.db` lost on every deployment (search index) |
| 23 | +- Persistent volumes break clean deployment workflow |
| 24 | +- External databases (Turso) require per-tenant token management |
| 25 | + |
| 26 | +**The Insight:** |
| 27 | +The SQLite database is just an **index cache** of the markdown files. It can be rebuilt in seconds from the source markdown files in Tigris. Only the small `config.json` file needs true persistence. |
| 28 | + |
| 29 | +**Solution:** |
| 30 | +- Store `config.json` in Tigris bucket (persistent, small file) |
| 31 | +- Rebuild `memory.db` on startup from markdown files (fast, ephemeral) |
| 32 | +- No persistent volumes, no external databases, no token management |
| 33 | + |
| 34 | +## What |
| 35 | + |
| 36 | +Store Basic Memory configuration in the Tigris bucket and rebuild the database index on tenant machine startup. |
| 37 | + |
| 38 | +**Affected Components:** |
| 39 | +- `basic-memory/src/basic_memory/config.py` - Add configurable config directory |
| 40 | + |
| 41 | +**Architecture:** |
| 42 | + |
| 43 | +```bash |
| 44 | +# Tigris Bucket (persistent, mounted at /mnt/tigris) |
| 45 | +/mnt/tigris/ |
| 46 | + ├── .basic-memory/ |
| 47 | + │ └── config.json # ← Project configuration (persistent, accessed via BASIC_MEMORY_CONFIG_DIR) |
| 48 | + └── projects/ # ← Markdown files (persistent) |
| 49 | + ├── project1/ |
| 50 | + └── project2/ |
| 51 | + |
| 52 | +# Fly Machine (ephemeral) |
| 53 | +~/.basic-memory/ |
| 54 | + └── memory.db # ← Rebuilt on startup (fast local disk) |
| 55 | +``` |
| 56 | + |
| 57 | +## How (High Level) |
| 58 | + |
| 59 | +### 1. Add Configurable Config Directory to Basic Memory |
| 60 | + |
| 61 | +Currently `ConfigManager` hardcodes `~/.basic-memory/config.json`. Add environment variable to override: |
| 62 | + |
| 63 | +```python |
| 64 | +# basic-memory/src/basic_memory/config.py |
| 65 | + |
| 66 | +class ConfigManager: |
| 67 | + """Manages Basic Memory configuration.""" |
| 68 | + |
| 69 | + def __init__(self) -> None: |
| 70 | + """Initialize the configuration manager.""" |
| 71 | + home = os.getenv("HOME", Path.home()) |
| 72 | + if isinstance(home, str): |
| 73 | + home = Path(home) |
| 74 | + |
| 75 | + # Allow override via environment variable |
| 76 | + if config_dir := os.getenv("BASIC_MEMORY_CONFIG_DIR"): |
| 77 | + self.config_dir = Path(config_dir) |
| 78 | + else: |
| 79 | + self.config_dir = home / DATA_DIR_NAME |
| 80 | + |
| 81 | + self.config_file = self.config_dir / CONFIG_FILE_NAME |
| 82 | + |
| 83 | + # Ensure config directory exists |
| 84 | + self.config_dir.mkdir(parents=True, exist_ok=True) |
| 85 | +``` |
| 86 | + |
| 87 | +### 2. Rebuild Database on Startup |
| 88 | + |
| 89 | +Basic Memory already has the sync functionality. Just ensure it runs on startup: |
| 90 | + |
| 91 | +```python |
| 92 | +# apps/api/src/basic_memory_cloud_api/main.py |
| 93 | + |
| 94 | +@app.on_event("startup") |
| 95 | +async def startup_sync(): |
| 96 | + """Rebuild database index from Tigris markdown files.""" |
| 97 | + logger.info("Starting database rebuild from Tigris") |
| 98 | + |
| 99 | + # Initialize file sync (rebuilds index from markdown files) |
| 100 | + app_config = ConfigManager().config |
| 101 | + await initialize_file_sync(app_config) |
| 102 | + |
| 103 | + logger.info("Database rebuild complete") |
| 104 | +``` |
| 105 | + |
| 106 | +### 3. Environment Configuration |
| 107 | + |
| 108 | +```bash |
| 109 | +# Machine environment variables |
| 110 | +BASIC_MEMORY_CONFIG_DIR=/mnt/tigris/.basic-memory # Config read/written directly to Tigris |
| 111 | +# memory.db stays in default location: ~/.basic-memory/memory.db (local ephemeral disk) |
| 112 | +``` |
| 113 | + |
| 114 | +## Implementation Task List |
| 115 | + |
| 116 | +### Phase 1: Basic Memory Changes ✅ |
| 117 | +- [x] Add `BASIC_MEMORY_CONFIG_DIR` environment variable support to `ConfigManager.__init__()` |
| 118 | +- [x] Test config loading from custom directory |
| 119 | +- [x] Update tests to verify custom config dir works |
| 120 | + |
| 121 | +### Phase 2: Tigris Bucket Structure |
| 122 | +- [ ] Ensure `.basic-memory/` directory exists in Tigris bucket on tenant creation |
| 123 | +- [ ] Initialize `config.json` in Tigris on first tenant deployment |
| 124 | +- [ ] Verify TigrisFS handles hidden directories correctly |
| 125 | + |
| 126 | +### Phase 3: Deployment Integration |
| 127 | +- [ ] Set `BASIC_MEMORY_CONFIG_DIR` environment variable in machine deployment |
| 128 | +- [ ] Ensure database rebuild runs on machine startup via initialization sync |
| 129 | +- [ ] Handle first-time tenant setup (no config exists yet) |
| 130 | +- [ ] Test deployment workflow with config persistence |
| 131 | + |
| 132 | +### Phase 4: Testing |
| 133 | +- [x] Unit tests for config directory override |
| 134 | +- [ ] Integration test: deploy → write config → redeploy → verify config persists |
| 135 | +- [ ] Integration test: deploy → add project → redeploy → verify project in config |
| 136 | +- [ ] Performance test: measure db rebuild time on startup |
| 137 | + |
| 138 | +### Phase 5: Documentation |
| 139 | +- [ ] Document config persistence architecture |
| 140 | +- [ ] Update deployment runbook |
| 141 | +- [ ] Document startup sequence and timing |
| 142 | + |
| 143 | +## How to Evaluate |
| 144 | + |
| 145 | +### Success Criteria |
| 146 | + |
| 147 | +1. **Config Persistence** |
| 148 | + - [ ] config.json persists across deployments |
| 149 | + - [ ] Projects list maintained across restarts |
| 150 | + - [ ] No manual configuration needed after redeploy |
| 151 | + |
| 152 | +2. **Database Rebuild** |
| 153 | + - [ ] memory.db rebuilt on startup in < 30 seconds |
| 154 | + - [ ] All entities indexed correctly |
| 155 | + - [ ] Search functionality works after rebuild |
| 156 | + |
| 157 | +3. **Performance** |
| 158 | + - [ ] SQLite queries remain fast (local disk) |
| 159 | + - [ ] Config reads acceptable (symlink to Tigris) |
| 160 | + - [ ] No noticeable performance degradation |
| 161 | + |
| 162 | +4. **Deployment Workflow** |
| 163 | + - [ ] Clean deployments without volumes |
| 164 | + - [ ] No new external dependencies |
| 165 | + - [ ] No secret management needed |
| 166 | + |
| 167 | +### Testing Procedure |
| 168 | + |
| 169 | +1. **Config Persistence Test** |
| 170 | + ```bash |
| 171 | + # Deploy tenant |
| 172 | + POST /tenants → tenant_id |
| 173 | + |
| 174 | + # Add a project |
| 175 | + basic-memory project add "test-project" ~/test |
| 176 | + |
| 177 | + # Verify config has project |
| 178 | + cat /mnt/tigris/.basic-memory/config.json |
| 179 | + |
| 180 | + # Redeploy machine |
| 181 | + fly deploy --app basic-memory-{tenant_id} |
| 182 | + |
| 183 | + # Verify project still exists |
| 184 | + basic-memory project list |
| 185 | + ``` |
| 186 | + |
| 187 | +2. **Database Rebuild Test** |
| 188 | + ```bash |
| 189 | + # Create notes |
| 190 | + basic-memory write "Test Note" --content "..." |
| 191 | + |
| 192 | + # Redeploy (db lost) |
| 193 | + fly deploy --app basic-memory-{tenant_id} |
| 194 | + |
| 195 | + # Wait for startup sync |
| 196 | + sleep 10 |
| 197 | + |
| 198 | + # Verify note is indexed |
| 199 | + basic-memory search "Test Note" |
| 200 | + ``` |
| 201 | + |
| 202 | +3. **Performance Benchmark** |
| 203 | + ```bash |
| 204 | + # Time the startup sync |
| 205 | + time basic-memory sync |
| 206 | + |
| 207 | + # Should be < 30 seconds for typical tenant |
| 208 | + ``` |
| 209 | + |
| 210 | +## Benefits Over Alternatives |
| 211 | + |
| 212 | +**vs. Persistent Volumes:** |
| 213 | +- ✅ Clean deployment workflow |
| 214 | +- ✅ No volume migration needed |
| 215 | +- ✅ Simpler infrastructure |
| 216 | + |
| 217 | +**vs. Turso (External Database):** |
| 218 | +- ✅ No per-tenant token management |
| 219 | +- ✅ No external service dependencies |
| 220 | +- ✅ No additional costs |
| 221 | +- ✅ Simpler architecture |
| 222 | + |
| 223 | +**vs. SQLite on FUSE:** |
| 224 | +- ✅ Fast local SQLite performance |
| 225 | +- ✅ Only slow reads for small config file |
| 226 | +- ✅ Database queries remain fast |
| 227 | + |
| 228 | +## Implementation Assignment |
| 229 | + |
| 230 | +**Primary Agent:** `python-developer` |
| 231 | +- Add `BASIC_MEMORY_CONFIG_DIR` environment variable to ConfigManager |
| 232 | +- Update deployment workflow to set environment variable |
| 233 | +- Ensure startup sync runs correctly |
| 234 | + |
| 235 | +**Review Agent:** `system-architect` |
| 236 | +- Validate architecture simplicity |
| 237 | +- Review performance implications |
| 238 | +- Assess startup timing |
| 239 | + |
| 240 | +## Dependencies |
| 241 | + |
| 242 | +- **Internal:** TigrisFS must be working and stable |
| 243 | +- **Internal:** Basic Memory sync must be reliable |
| 244 | +- **Internal:** SPEC-8 (TigrisFS Integration) must be complete |
| 245 | + |
| 246 | +## Open Questions |
| 247 | + |
| 248 | +1. Should we add a health check that waits for db rebuild to complete? |
| 249 | +2. Do we need to handle very large knowledge bases (>10k entities) differently? |
| 250 | +3. Should we add metrics for startup sync duration? |
| 251 | + |
| 252 | +## References |
| 253 | + |
| 254 | +- Basic Memory sync: `basic-memory/src/basic_memory/services/initialization.py` |
| 255 | +- Config management: `basic-memory/src/basic_memory/config.py` |
| 256 | +- TigrisFS integration: SPEC-8 |
| 257 | + |
| 258 | +--- |
| 259 | + |
| 260 | +**Status Updates:** |
| 261 | + |
| 262 | +- 2025-10-08: Pivoted from Turso to Tigris-based config persistence |
| 263 | +- 2025-10-08: Phase 1 complete - BASIC_MEMORY_CONFIG_DIR support added (PR #343) |
| 264 | +- Next: Implement Phases 2-3 in basic-memory-cloud repository |
0 commit comments