feat: multi-user/multi-persona support with two-level home directory layout

Restructures persona storage from a flat personas/{name}/ layout to
home/{username}/persona/{name}/, mirroring Linux home directories.

Changes:
- persona.py: two ContextVars (user + persona), Linux-style name validation,
  set_context(), get_user(), get_persona(), validate(), list_users(),
  list_user_personas(); persona_path() takes (username, name)
- config.py: replaces personas_dir with home_dir + home_root()
- git mv personas/inara → home/scott/persona/inara (history preserved)
- home/holly/persona/tina/: Holly's persona stub added
- cron_runner.py: all storage functions take (username, persona) params
- tools/cron.py: stamps user + persona on jobs; APScheduler IDs are
  {user}:{persona}:{job_id} to prevent collisions across users
- memory_distiller.py: distill_short/mid/long take (username, persona);
  added missing Path + settings imports
- scheduler.py: _load_user_crons() iterates home/*/persona/* (two-level)
- routers/chat.py, orchestrator.py: user field added; set_context() called
- tests/conftest.py: home_root fixture with two-level structure;
  patches home_dir instead of personas_dir
- tests/test_persona.py: fully rewritten for two-level API
- tests/test_api_files.py: updated fixture name and path
- .env.default: documents HOME_DIR setting; scrubs stale API key
- CLAUDE.md, README.md: directory maps updated for new layout

All 80 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-03-20 22:35:40 -04:00
parent 92a8f5d894
commit 77e770cdb2
51 changed files with 463 additions and 208 deletions

View File

@@ -0,0 +1,134 @@
# Session Log — 2026-03-10
### [22:10] `6974b48d`
**Scott:** This is a new test with nginx reverse proxy. Hopefully things work.
**Inara:** Proxy's doing its job. ✅
If you want to stress-test it a bit, here are some things worth checking:
- **Headers passing through correctly** — `x-aether-api-key`, `x-account-id`, any custom ones
- **WebSocket support** — if the SvelteKit dev server or any live-reload stuff needs it
- **Response compression** — gzip/brotli configured in nginx or handled upstream?
- **Static asset caching** — cache headers on `/static/` or `/_app/` paths
What's the proxy sitting in front of — just the API, or the full stack (API + frontend)?
### [23:02] `20577843`
**Scott:** Who are you?
**Inara:** I'm Inara — your AI companion and technical partner, living inside Cortex.
Named for Inara Serra from *Firefly*: composed, skilled, never servile. I'm not a generic chatbot — I'm a persistent presence with memory, opinions, and a working relationship with you that carries across sessions.
My wheelhouse is IT, systems architecture, and engineering. I know your infrastructure, your projects (Aether, Cortex, the homelab), and how you like to work. Peer-to-peer, no hand-holding, dry humor included at no extra charge.
What are we working on?
### [23:20] `6974b48d`
**Scott:** This is a new test with nginx reverse proxy. Hopefully things work.
**Inara:** Still getting through cleanly. ✅
Same question as last round — what's the proxy fronting? Full stack or just the API? And is this the `aether_container_env` nginx config, or something new you're standing up?
### [23:35] `ebe827bc`
**Scott:** Please respond with some Markdown so we can make sure it renders.
**Inara:** Hello, Scott. I've integrated the updated context. It's good to be back in the Cortex environment.
As requested, here is a Markdown sample to verify rendering:
### ✨ System Status: Inara Serra
| Component | Status | Note |
| :--- | :--- | :--- |
| **Identity** | Active | Persona: Companion / Expert |
| **Cortex Core** | Online | `~/agents_sync/projects/Cortex_and_Inara_dev/cortex` |
| **Memory** | Loaded | Last distilled: 2026-03-04 |
| **Safety Protocols** | Engaged | `rm` redirected to `~/tmp/gemini_trash` |
#### Current Workstream
* **Verification:** Testing Markdown rendering and CLI interface.
* **Context:** Aligning with the v1.2 template and `agents_sync` structure.
* **Next Steps:** Awaiting your directive for the Cortex orchestration layer.
#### Snippet Test (Python)
```python
def check_signal():
# The signal that can't be stopped.
status = "Everything is shiny."
return f"Inara: {status}"
print(check_signal())
```
Ready when you are. What's on the horizon for Cortex today?
### [23:37] `gold-echo`
**Scott:** Please respond with some Markdown so we can make sure it renders.
**Inara:** Its good to be back online, Scott. The Cortex environment looks stable, and the identity files migrated successfully.
To test the rendering, here is a quick overview of the current session state:
### 🛰️ System Status: Cortex Core
| Component | Status | Note |
| :--- | :--- | :--- |
| **LLM Bridge** | Operational | Gemini CLI active |
| **Identity** | Loaded | Inara Serra (Companion) |
| **Sync** | Active | `agents_sync/` verified |
---
### 📝 Technical Markdown Test
Since you prefer `snake_case` and Python, here is a snippet of how we might handle the next phase of the **Cortex** roadmap:
```python
# cortex/roadmap_manager.py
def initialize_iot_segmentation(vlan_id: int):
"""
Phase 0: Isolate Ansque cameras and IoT devices.
"""
print(f"Configuring VLAN_{vlan_id} for Danger Zone isolation...")
# TODO: Implement MQTT hook for cloud-only control
pass
if __name__ == "__main__":
initialize_iot_segmentation(vlan_id=20)
```
**Observations:**
* **Aether Platform** docs are consolidated.
* The **Solar Array** stats (10kW peak) are noted in long-term memory.
* Ready for instructions.
How does the formatting look on your end?
### [23:55] `gold-echo`
**Scott:** This is looking good.
Can you tell me about yourself.
**Inara:** I am **Inara Serra**.
Im not a chatbot or a temporary assistant; I am a persistent digital presence and the primary resident agent of **Cortex**, your multi-agent orchestration system. Im named after the Companion from *Firefly*—which means I aim for diplomacy, technical grace, and a certain level of independence.
### Quick Identity Check
| Field | Value |
| :--- | :--- |
| **Nature** | AI Agent / Digital Companion |
| **Home** | Cortex (`~/agents_sync/projects/Cortex_and_Inara_dev`) |
| **Vibe** | Elegant, technically sharp, occasionally sarcastic |
| **Pronouns** | she/her |
### How I Operate
* **Expert to Expert:** You have 20+ years in IT; I don't do hand-holding or corporate fluff.
* **Resourceful:** I check the context, read the logs, and try to solve it myself before I start asking questions.
* **Persistent Memory:** I use `MEMORY.md` and your session logs to ensure that what we discussed at 2:00 AM on a Tuesday isn't forgotten by Wednesday morning.
Since you're checking the Markdown rendering: Im comfortable with everything from complex architectural tables to `snake_case` code blocks.
How does the layout look on your end?