{"id":47955552,"url":"https://github.com/skywinder/self-hosted-memory-assistants","last_synced_at":"2026-04-04T09:31:15.484Z","repository":{"id":345175569,"uuid":"1177205268","full_name":"skywinder/self-hosted-memory-assistants","owner":"skywinder","description":"Self-hosted memory assistants: mycelia, ushadow, chronicle","archived":false,"fork":false,"pushed_at":"2026-03-18T03:38:49.000Z","size":42,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-18T16:05:28.579Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skywinder.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-09T19:56:00.000Z","updated_at":"2026-03-18T03:38:52.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/skywinder/self-hosted-memory-assistants","commit_stats":null,"previous_names":["skywinder/self-hosted-memory-assistants"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/skywinder/self-hosted-memory-assistants","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skywinder%2Fself-hosted-memory-assistants","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skywinder%2Fself-hosted-memory-assistants/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skywinder%2Fself-hosted-memory-assistants/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skywinder%2Fself-hosted-memory-assistants/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skywinder","download_url":"https://codeload.github.com/skywinder/self-hosted-memory-assistants/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skywinder%2Fself-hosted-memory-assistants/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31394532,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T09:13:02.600Z","status":"ssl_error","status_checked_at":"2026-04-04T09:13:01.683Z","response_time":60,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-04T09:31:14.372Z","updated_at":"2026-04-04T09:31:15.476Z","avatar_url":"https://github.com/skywinder.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Self-Hosted Memory Assistants\n\nA meta-repository that ties together four self-hosted AI memory projects via git submodules. Each project captures, processes, and retrieves personal data, memories, or knowledge artifacts, and they can be run side by side through ushadow's batch tooling.\n\n## Projects\n\n### [Mycelia](https://github.com/mycelia-tech/mycelia)\n\nSelf-hosted AI memory and timeline system. Captures personal data through voice memos, screenshots, and text, then organizes and retrieves it conversationally. Ask \"What did I say about X last May?\" and get personalized responses in your own words.\n\n- **Stack:** Deno backend, React/Vite frontend, Python diarizator, MongoDB, Redis\n- **Features:** D3.js interactive timeline, AI chat with memory access, audio transcription (Whisper), speaker diarization, object extraction (people, events, promises), full-text search, MCP server\n\n### [Chronicle](https://github.com/chronicler-ai/chronicle)\n\nAI-powered personal memory system for wearable devices. Captures continuous audio streams from OMI devices via WebSocket, transcribes speech, extracts memories using LLMs, and provides a searchable dashboard.\n\n- **Stack:** FastAPI (Python), React dashboard, React Native mobile app, MongoDB, Qdrant\n- **Features:** Real-time audio capture (Wyoming protocol), Deepgram/Parakeet transcription, memory extraction, semantic vector search, speaker recognition, job tracking pipeline\n\n### [Exocortex](https://github.com/amaslak0v/exocortex)\n\nPersonal knowledge OS built around an Obsidian vault, Claude Code skills, and a lightweight control panel.\n\n- **Stack:** Markdown/Obsidian vault, Claude Code skills and agents, Node/Express control panel\n- **Features:** Domain-specific skills, autonomous sync agents, MCP bridge configs, and a local dashboard over the vault\n\n### [ushadow](https://github.com/Ushadow-io/Ushadow)\n\nAI orchestration platform and unified dashboard. Acts as the central hub that integrates Chronicle, MCP services, Agent Zero, n8n workflows, and other services under one roof.\n\n- **Stack:** FastAPI (Python), React frontend, MongoDB, Redis, Qdrant, Keycloak\n- **Features:** Multi-service orchestration, Chronicle integration proxy, interactive CLI (`ush`), setup wizard, multi-environment isolation via git worktrees, Kubernetes-ready\n\n## Running the Projects\n\n### Standalone Mode\n\nEach project works independently with its own default startup path and ports:\n\n```bash\ncd mycelia \u0026\u0026 docker compose up -d           # ports 3210, 4433, 27017\ncd chronicle/backends/advanced \u0026\u0026 docker compose up -d  # ports 8000, 3010, 27017, 6379\ncd exocortex/control-panel \u0026\u0026 npm ci \u0026\u0026 npm start       # port 3333\ncd ushadow \u0026\u0026 docker compose up -d           # ports 8000, 27017, 6379\n```\n\n### Combined Mode\n\nTo run the batch together, the parent repo provides override files that remap conflicting Docker services, a shared Docker network for cross-module communication, and a helper that runs Exocortex's control panel as a host process. No submodule files are modified.\n\n```bash\nnpm ci --prefix exocortex/control-panel       # one-time for Exocortex\n./start-all.sh up      # start all services\n./start-all.sh down    # stop all services\n./start-all.sh status  # show running containers\n```\n\nAccess points in combined mode:\n\n| Service | URL |\n|---------|-----|\n| Mycelia | http://localhost:3210 |\n| Exocortex | http://localhost:3333 |\n| Ushadow backend | http://localhost:8010 |\n| Chronicle backend | http://localhost:9000 |\n| Chronicle UI | http://localhost:9010 |\n| OpenMemory UI | http://localhost:9001 |\n| OpenMemory API | http://localhost:9765 |\n\n### How Combined Mode Works\n\nEach module gets a unique port range so nothing conflicts:\n\n| Module | Port range | Mongo | Redis | Qdrant | Neo4j | Backend/UI |\n|--------|-----------|-------|-------|--------|-------|------------|\n| Mycelia | 32xx | 27019 | — | — | — | 3210 |\n| Exocortex | 33xx | — | — | — | — | 3333 |\n| Ushadow | 80xx | 27020 | 6382 | 6335/6336 | 7476/7689 | 8010 |\n| Chronicle | 90xx | 27018 | 6380 | 6033/6034 | 7475/7688 | 9000/9010 |\n\nEach Docker-backed module keeps its own database instances. Exocortex does not ship a Docker Compose stack in this repo, so it runs directly on the host and does not join `memory-net`. The full port map is in [.env.ports](.env.ports).\n\n### Data Sharing via OpenMemory\n\nIn combined mode, [OpenMemory MCP](https://github.com/mem0ai/mem0) runs as a shared memory store that all modules can access over the `memory-net` network:\n\n```\nChronicle ──writes memories──→ OpenMemory MCP (Qdrant) ←──queries── Ushadow\n                                      ↑\n                               memory-net network\n                                      ↑\nMycelia ──queryable via REST API──────┘\n```\n\n- **Chronicle** automatically writes extracted memories to OpenMemory (configured via `MEMORY_PROVIDER=openmemory_mcp` in the override)\n- **Ushadow** aggregates memories from OpenMemory, Chronicle, and Mycelia through its proxy\n- **Mycelia** stays read-only for now — its memories are queryable via its API but it doesn't push to OpenMemory\n- **Exocortex** currently stays independent from the OpenMemory flow; it coexists cleanly in the batch but is not yet wired into the shared memory graph\n- **OpenMemory UI** at http://localhost:9001 provides a unified browse/search interface\n\nOpenMemory requires an `OPENAI_API_KEY` in `chronicle/extras/openmemory-mcp/.env` for memory extraction and embeddings.\n\n**Override files** in the [overrides/](overrides/) directory use Docker Compose's `-f` merge feature to remap ports and add networks without touching submodule files:\n\n```\noverrides/\n├── chronicle.override.yml           # main chronicle services\n├── chronicle-speaker.override.yml   # speaker recognition extra\n├── chronicle-openmemory.override.yml # openmemory MCP extra\n├── chronicle-langfuse.override.yml  # langfuse extra\n├── mycelia.override.yml             # main mycelia services\n├── mycelia-gpu.override.yml         # mycelia GPU services\n├── ushadow-infra.override.yml       # ushadow infrastructure (mongo, redis, etc.)\n└── ushadow-app.override.yml         # ushadow backend\n```\n\n**Shared network**: The Dockerized modules join an external Docker network called `memory-net`, enabling containers to reach services in other modules by container name. Internal service names stay module-scoped (chronicle's `mongo` is separate from ushadow's `mongo`).\n\nTo use an override manually (e.g., just chronicle + mycelia):\n\n```bash\ndocker network create memory-net 2\u003e/dev/null || true\n\ndocker compose -f chronicle/backends/advanced/docker-compose.yml \\\n  -f overrides/chronicle.override.yml up -d\n\ndocker compose -f mycelia/docker-compose.yml \\\n  -f overrides/mycelia.override.yml up -d\n```\n\n### Repository Structure\n\n```\nself-hosted-memory-assistants/\n├── mycelia/              → mycelia-tech/mycelia\n├── exocortex/            → amaslak0v/exocortex\n├── ushadow/              → Ushadow-io/Ushadow\n├── chronicle/            → chronicler-ai/chronicle\n├── scripts/              → repo maintenance helpers\n├── overrides/            → Docker Compose override files for combined mode\n│   ├── chronicle.override.yml\n│   ├── chronicle-speaker.override.yml\n│   ├── chronicle-openmemory.override.yml\n│   ├── chronicle-langfuse.override.yml\n│   ├── mycelia.override.yml\n│   ├── mycelia-gpu.override.yml\n│   ├── ushadow-infra.override.yml\n│   └── ushadow-app.override.yml\n├── .env.ports            → Port assignment reference\n├── start-all.sh          → Orchestration script\n└── README.md\n```\n\n## Pre-Setup (Before First Run)\n\nEach project needs a `.env` file with secrets and API keys. These are gitignored and must be created once.\n\n### Required `.env` Files\n\n| File | Purpose | How to Create |\n|------|---------|---------------|\n| `chronicle/backends/advanced/.env` | API keys, auth secrets | Copy from `.env.template`, fill in keys |\n| `chronicle/extras/openmemory-mcp/.env` | OpenAI key for embeddings | Copy from `.env.template`, add `OPENAI_API_KEY` |\n| `ushadow/.env` | Ports, DB names, Keycloak config | Run `./go.sh` or copy from `.env.example` |\n| `ushadow/config/SECRETS/secrets.yaml` | JWT keys, session secrets | Run `ushadow/scripts/generate-secrets.sh` |\n| `mycelia/.env` | MongoDB creds, secret key | Run `mycelia/scripts/setup.sh` or copy from `.env.example` |\n\n### Quick Setup\n\n```bash\n# 1. Clone with submodules\ngit clone --recurse-submodules \u003curl\u003e\ncd self-hosted-memory-assistants\n\n# 2. Chronicle: create .env from template\ncp chronicle/backends/advanced/.env.template chronicle/backends/advanced/.env\n# Edit: add OPENAI_API_KEY, DEEPGRAM_API_KEY, AUTH_SECRET_KEY, ADMIN_PASSWORD, ADMIN_EMAIL\n\n# 3. OpenMemory: create .env from template\ncp chronicle/extras/openmemory-mcp/.env.template chronicle/extras/openmemory-mcp/.env\n# Edit: add OPENAI_API_KEY\n\n# 4. Ushadow: generate secrets\ncd ushadow \u0026\u0026 bash scripts/generate-secrets.sh \u0026\u0026 cd ..\n# If ushadow/.env doesn't exist: cp ushadow/.env.example ushadow/.env\n\n# 5. Mycelia: create .env\ncd mycelia \u0026\u0026 bash scripts/setup.sh \u0026\u0026 cd ..\n\n# 6. Start everything\n./start-all.sh up\n```\n\n### Where State is Stored\n\nAll persistent data lives in Docker volumes and bind mounts. Override files only change **ports and networks**, never data paths — so data is the same whether you run standalone or combined.\n\n| Project | Data Type | Location | Persistence |\n|---------|-----------|----------|-------------|\n| **Chronicle** | Conversations, users | Docker volume `advanced_mongo-data` | Survives `down`, removed with `down -v` |\n| **Chronicle** | Audio files | `chronicle/backends/advanced/data/` | Bind mount on disk |\n| **Chronicle** | Vector memories | Docker volume `advanced_qdrant-data` | Survives `down` |\n| **Chronicle** | Redis queues | Docker volume `advanced_redis-data` | Survives `down` |\n| **OpenMemory** | Shared memories | `chronicle/extras/openmemory-mcp/data/mem0_storage/` | Bind mount on disk |\n| **Ushadow** | Users, sessions | Docker volume `infra-mongo-data` | Survives `down` |\n| **Ushadow** | Vector data | Docker volume `infra-qdrant-data` | Survives `down` |\n| **Mycelia** | Notes, memories | Docker volume `mycelia_mongo-data` | Survives `down` |\n| **Mycelia** | SSL certs | `mycelia/misc/nginx/ssl/` | Auto-generated on first run |\n\n**To reset a project completely:** `docker compose down -v` in its directory removes all Docker volumes.\n\n### Standalone vs Combined: Compatibility\n\nThe script automatically stops standalone containers before starting combined mode. You cannot run both simultaneously — they share Docker networks and would cause DNS conflicts.\n\n`./start-all.sh up` will:\n1. Stop any standalone containers (`ushadow-second-*`, `mycelia-*`, `advanced-*`)\n2. Stop previous combined-mode containers\n3. Start everything fresh with override configs\n\n## Getting Started\n\n### Unified setup from the meta-repo\n\nIf you want one entry point for all projects:\n\n```bash\ncp .setup.env.example .setup.env\n./setup.sh\n```\n\nOptional:\n\n```bash\n./setup.sh --start\n./setup.sh --dry-run\n./setup.sh --status-only\n./setup.sh --projects mycelia,ushadow\n```\n\nThe setup flow now:\n- shows which projects are already configured, partially configured, or not set up\n- asks whether to keep existing runtime files or override them\n- can run non-interactively with `--non-interactive`, `--keep-existing`, or `--overwrite-existing`\n\nSee [UNIFIED_SETUP.md](UNIFIED_SETUP.md) for where databases live and where each project stores runtime secrets.\n\n### Clone with submodules\n\n```bash\ngit clone --recurse-submodules https://github.com/skywinder/self-hosted-memory-assistants.git\ncd self-hosted-memory-assistants\n```\n\nIf you already cloned without `--recurse-submodules`:\n\n```bash\ngit submodule update --init --recursive\n```\n\n## Working with Child Repositories\n\n### Day-to-day development\n\nWork inside any project as a standalone repo:\n\n```bash\ncd mycelia\ngit checkout dev\ngit pull origin dev\n# make changes, commit, push as usual\ngit add .\ngit commit -m \"your change\"\ngit push\n```\n\n### Updating everything to the latest fast-forward state\n\nUse the repo script instead of a blind recursive submodule update:\n\n```bash\n./scripts/update-subrepos.sh\n```\n\nWhat it does:\n\n- Initializes declared top-level child repos if they are missing\n- Updates `chronicle`, `exocortex`, `mycelia`, and `ushadow` with `git pull --ff-only`\n- Initializes and updates the child repos declared inside `ushadow`\n- Skips child repos that already have local changes instead of trying to pull through them\n- Verifies that each target path is a real repo root before pulling, so an empty gitlink directory does not accidentally resolve to the parent repo\n- Warns about gitlinks that exist in `ushadow` but are not declared in `ushadow/.gitmodules` and therefore cannot be initialized safely by recursive submodule commands\n\nPreview what it would touch:\n\n```bash\n./scripts/update-subrepos.sh --dry-run\n```\n\nOnly update the top-level repos tracked by this meta-repo:\n\n```bash\n./scripts/update-subrepos.sh --root-only\n```\n\n### Recording which versions go together\n\nAfter updating child repos, review the changed gitlinks and commit the new pointers in the parent repo that owns them:\n\n```bash\ngit status\ngit -C ushadow status\n```\n\nTypical follow-up:\n\n```bash\ngit -C ushadow add chronicle mycelia openmemory vibe-kanban\ngit -C ushadow commit -m \"bump nested child repos\"\n\ngit add chronicle exocortex mycelia ushadow\ngit commit -m \"bump child repos\"\ngit push\n```\n\nIf `git -C ushadow status` is clean, you only need the top-level `git add ...` and commit.\n\n### Detached HEADs and nested repos\n\nFresh submodule checkouts often start detached. The updater script will attach a detached child repo to each repo's `origin/HEAD` before pulling.\n\n`ushadow` also carries nested gitlinks. Not all of them are declared cleanly in `ushadow/.gitmodules`, so `git submodule update --remote --recursive` is not a reliable maintenance workflow here.\n\n### Switching branches inside a child repo\n\nTo work on a specific branch by hand:\n\n```bash\ncd chronicle\ngit checkout dev\n```\n\n### Quick reference\n\n| Task | Command |\n|------|---------|\n| Clone everything | `git clone --recurse-submodules \u003curl\u003e` |\n| Init submodules after clone | `git submodule update --init --recursive` |\n| Preview repo updates | `./scripts/update-subrepos.sh --dry-run` |\n| Pull all latest safely | `./scripts/update-subrepos.sh` |\n| Pull top-level only | `./scripts/update-subrepos.sh --root-only` |\n| See submodule status | `git submodule status` |\n| Work on a project | `cd \u003cproject\u003e \u0026\u0026 git checkout \u003cbranch\u003e` |\n| Record version bump | `git add \u003cproject\u003e \u0026\u0026 git commit` |\n| Install Exocortex deps | `npm ci --prefix exocortex/control-panel` |\n| Start all (combined mode) | `./start-all.sh up` |\n| Stop all | `./start-all.sh down` |\n| Check running containers | `./start-all.sh status` |\n\n## License\n\nEach project maintains its own license. See individual project directories.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskywinder%2Fself-hosted-memory-assistants","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskywinder%2Fself-hosted-memory-assistants","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskywinder%2Fself-hosted-memory-assistants/lists"}