--- license: mit tags: - openclaw - sidecar - session-review - fastapi --- # Session Amplifier Lightweight OpenClaw sidecar for transcript spooling and session review. ## What it does - **Spooler** — walks `~/.openclaw/agents//sessions/*.jsonl`, cleans/redacts tool results, stores summaries to SQLite - **Reviewer** — scores sessions for quality/failure patterns, detects unused tools/skills, surfaces recommendations - **Snapshot adapter** — exposes canonical `openclaw.session.v1` session snapshots for dashboards/reviewers without gateway core patches - **API** — FastAPI server on port 8477 with 4 endpoints ## Quick start ```bash # Install deps pip install -r requirements.txt # Init DB python main.py init # Run once (spool or review) python main.py spool python main.py review # Start API server python main.py serve # Watch transcript files and spool on changes python main.py watch --interval 5 ``` ## Running Tests The application uses `pytest` for testing. The tests use an in-memory SQLite database and do not require filesystem access. ```bash # Run all tests pytest tests/ ``` ## Docker / container run path ```bash cd sidecar/session-amplifier docker compose up -d --build ``` Manual equivalent: ```bash docker build -t session-amplifier sidecar/session-amplifier/ docker run -p 8477:8477 \ -v ~/.openclaw:/openclaw:ro \ -v session_amplifier_state:/data/session-amplifier \ -e OPENCLAW_AGENTS_ROOT=/openclaw/agents \ -e OPENCLAW_STATE_DIR=/data/session-amplifier \ session-amplifier serve ``` Host note: the bare host Python environment may not have `uvicorn` / `fastapi` installed. The intended live-service path is the container. Gateway integration note: when OpenClaw runs in Docker, gateway-side scripts should target the sidecar by container hostname, not `localhost`. Default wrapper target is `SESSION_AMPLIFIER_BASE_URL=http://session-amplifier:8477`. The sidecar compose file joins the external `librechat_default` network so the gateway container can resolve it. ## API endpoints | Method | Path | Description | |--------|------|-------------| | GET | `/health` | Container health + version | | POST | `/spool` | Trigger incremental spooling | | GET | `/review/report` | Fetch latest review report | | GET | `/review/skills` | Fetch skill/MCP coverage report | | GET | `/sessions/recent` | Recent sessions with activity/error counts | | GET | `/sessions/snapshots` | Recent sessions as canonical `openclaw.session.v1` snapshots | | GET | `/session/{id}/snapshot` | One canonical `openclaw.session.v1` snapshot | | GET | `/session/{id}/activity` | Normalized per-session activity feed | ## Config (env) | Var | Default | Description | |-----|---------|-------------| | `OPENCLAW_AGENTS_ROOT` | `~/.openclaw/agents` | Transcript source | | `OPENCLAW_STATE_DIR` | `~/.openclaw/workspace/ops/state` | SQLite + artifacts output | | `MAX_TOOLRESULT_CHARS` | `2000` | Truncate threshold | | `SPOOLER_BATCH_SIZE` | `100` | DB insert batch size | | `REVIEW_CONFIDENCE_THRESHOLD` | `0.5` | Min confidence for recommendations | | `API_PORT` | `8477` | HTTP server port | ## Package layout ``` session-amplifier/ ├── config.py # Env/config loading ├── main.py # CLI entrypoint (init/serve/serve-watch/spool/review/watch) ├── requirements.txt ├── Dockerfile ├── spooler/ │ ├── processor.py # JSONL → spooled rows │ ├── redaction.py # API key / path / base64 redaction │ ├── noise_filter.py # Drop known-noise tool output │ └── store.py # SQLite read/write ├── reviewer/ │ ├── scorer.py # Session quality scoring │ ├── pattern_detector.py # Recurring failure detection │ ├── skill_analyzer.py # MCP/skill coverage │ └── report.py # Report generation + persistence ├── api/ │ └── routes.py # FastAPI route handlers └── tests/ └── ... # pytest suite ``` ## Architecture notes - Reads-only from `OPENCLAW_AGENTS_ROOT`; never modifies transcripts - Idempotent spooling via `UNIQUE(session_id, entry_idx)` constraint - **Incremental spooling**: Uses tracked `last_entry_idx` file state to only parse lines appending to existing files, drastically reducing processing time overhead. - Reviewer is deterministic (no LLM required in v1); recommendations scored by confidence threshold - Watch mode is polling-based in v1 for simplicity; `python main.py watch --interval 5` or `serve-watch` - By default `serve-watch` / `watch` only triggers spooling. To optionally trigger the reviewer append `--review-every `. - Manual trigger remains available for cron/recovery: `POST /spool` → wait → `GET /review/report` - A simple CLI-style live monitor is available at `/home/node/.openclaw/workspace/ops/scripts/session_amplifier_live_monitor.py` - Snapshot endpoints are read-only and sidecar-local. Rollback is removing `reviewer/session_snapshot.py`, the two route handlers/imports in `api/routes.py`, and the snapshot smoke test; no gateway config change is required unless the service was rebuilt/redeployed. ## Troubleshooting - **API keys exposed in tool outputs?** Check `SPOOLER_REDACT_PATTERNS`. - **Database lock errors?** Multiple cron instances might be racing. Restart with a clean volume or disable concurrent spool calls. - **Reporting "No data"?** Ensure `OPENCLAW_AGENTS_ROOT` path exists inside the container and matches host volume bindings.