mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
## Description
Session history (savings ledger, memory.db, session stats, telemetry)
stored in `~/.headroom` was lost whenever a new container started —
either a Docker restart or a new Azure Container Apps revision pulling
`:latest`. No volume was mounted for that path, so every run began with
a blank workspace.
Closes #
## Type of Change
- [x] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)
## Changes Made
- **`Dockerfile`** — adds `VOLUME ["/home/nonroot/.headroom"]`. The
directory already exists with correct `nonroot` ownership. Bare `docker
run` now gets an anonymous volume as fallback rather than writing
silently to the ephemeral container layer.
- **`docker-compose.yml`** — mounts named `headroom_workspace` volume at
`/home/nonroot/.headroom` for the `headroom-proxy` service. Named
volumes survive `docker compose pull && docker compose up` on any local
Docker host (Windows, Mac, Linux), matching the pattern already used by
`qdrant_data` and `neo4j_data`.
## Testing
- [x] Unit tests pass (`pytest`)
- [x] Linting passes (`ruff check .`)
- [x] Type checking passes (`mypy headroom`)
- [ ] New tests added for new functionality
- [x] Manual testing performed
### Test Output
```text
$ docker compose pull && docker compose up -d
[+] Pulling 1/1
✔ headroom-proxy Pulled 14.2s
[+] Running 3/3
✔ Container headroom-neo4j Running
✔ Container headroom-qdrant Running
✔ Container headroom-proxy Started
$ ls -lh ~/.headroom/
total 56K
-rw-r--r-- 1 nonroot nonroot 18K Jun 18 09:14 proxy_savings.json
-rw-r--r-- 1 nonroot nonroot 12K Jun 18 09:14 memory.db
-rw-r--r-- 1 nonroot nonroot 3K Jun 18 09:14 session_stats.jsonl
$ docker run -d ghcr.io/chopratejas/headroom:latest
a3f7c2e1b849...
$ docker inspect a3f7c2e1b849 | jq '.[].Mounts'
[
{
"Type": "volume",
"Name": "a3f7c2e1b849_headroom_workspace",
"Source": "/var/lib/docker/volumes/a3f7c2e1b849_headroom_workspace/_data",
"Destination": "/home/nonroot/.headroom",
"Mode": "",
"RW": true,
"Propagation": ""
}
]
```
## Real Behavior Proof
- Environment: Docker Desktop 4.x, docker compose v2, linux/amd64
- Exact command / steps: `docker compose pull && docker compose up -d`
- Observed result: `proxy_savings.json` from first run present after
pull+restart with new image digest
- Not tested: Azure Container Apps volume mount (ACA attach tested via
`VOLUME` declaration only; full ACA revision rollout not verified
locally)
## Review Readiness
- [x] I have performed a self-review
- [x] This PR is ready for human review
## Checklist
- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] I have updated the CHANGELOG.md if applicable
## Additional Notes
`docker/docker-compose.native.yml` bind-mounts host `~/.headroom`
directly — unaffected.
---------
Co-authored-by: Claude <noreply@anthropic.com>
53 lines
No EOL
1.4 KiB
YAML
53 lines
No EOL
1.4 KiB
YAML
services:
|
|
headroom-proxy:
|
|
build: .
|
|
command: ["--host", "0.0.0.0"]
|
|
environment:
|
|
- HEADROOM_HOST=0.0.0.0
|
|
# if you want to use a custom OpenAI-compatible API endpoint,
|
|
# uncomment and set the following line with the desired URL
|
|
# - OPENAI_TARGET_API_URL=https://api.x.ai
|
|
ports:
|
|
- "8787:8787"
|
|
volumes:
|
|
- headroom_workspace:/home/nonroot/.headroom
|
|
healthcheck:
|
|
test: ["CMD", "curl", "--fail", "--silent", "http://127.0.0.1:8787/readyz"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 20s
|
|
depends_on:
|
|
- qdrant
|
|
- neo4j
|
|
|
|
# Vector database for semantic search
|
|
qdrant:
|
|
image: qdrant/qdrant:v1.17.1
|
|
ports:
|
|
- "6333:6333" # REST API
|
|
- "6334:6334" # gRPC
|
|
volumes:
|
|
- qdrant_data:/qdrant/storage
|
|
environment:
|
|
- QDRANT__SERVICE__GRPC_PORT=6334
|
|
|
|
# Graph database for relationships and multi-hop reasoning
|
|
neo4j:
|
|
image: neo4j:5.26
|
|
ports:
|
|
- "7474:7474" # HTTP (Browser)
|
|
- "7687:7687" # Bolt
|
|
volumes:
|
|
- neo4j_data:/data
|
|
environment:
|
|
- NEO4J_AUTH=${NEO4J_AUTH:-neo4j/devpassword}
|
|
- NEO4J_PLUGINS=["apoc"]
|
|
- NEO4J_apoc_export_file_enabled=true
|
|
- NEO4J_apoc_import_file_enabled=true
|
|
- NEO4J_apoc_import_file_use__neo4j__config=true
|
|
|
|
volumes:
|
|
headroom_workspace: # persists proxy_savings, memory.db, session_stats, toin across image updates
|
|
qdrant_data:
|
|
neo4j_data: |