Backend (Go, in this commit):
- migration 029_memory_dream_usage: per (date, owner) counters for
tokens_in/out, jobs_started/succeeded/failed/circuit_broken
- DreamUsageStore + UsageGate (internal/messaging/dream_usage.go).
Gate inspects today's usage against new env knobs:
- SYNAPBUS_DREAM_RECENT_WINDOW (default 336h / 14d)
- SYNAPBUS_DREAM_DAILY_TOKEN_LIMIT_IN (default 1M)
- SYNAPBUS_DREAM_DAILY_TOKEN_LIMIT_OUT (default 200k)
- SYNAPBUS_DREAM_DAILY_JOB_LIMIT (default 100)
- Consolidator now bounds watermarks + core_rewrite eligibility by the
recency window. core_rewrite skipped for owners with no in-window
activity. ForceRun honors the breaker.
- Recency fallback in BuildContextPacket + memory_list_unprocessed now
accept RecentWindowDays so injection and dream queries see the same
14d slice.
- Prometheus metrics registered (internal/metrics/metrics.go):
synapbus_dream_jobs_total{owner,job_type,status},
synapbus_dream_tokens_total{owner,direction},
synapbus_dream_job_duration_seconds{owner,job_type},
synapbus_dream_circuit_broken_total{owner,reason},
synapbus_injection_packets_total{tool},
synapbus_injection_memories_per_packet{tool},
synapbus_injection_packet_chars{tool},
synapbus_injection_skipped_total{tool,reason}.
- deploy/kubic/deployment.yaml: liveness/readiness timeoutSeconds: 1→5
(root-causes the "connection refused" mcpproxy errors at 13:02 today —
/readyz occasionally exceeded 1s under dream-worker tick load, so the
pod fell out of the Service endpoints intermittently).
Dream-claude agent (Python, in /dream-agent/):
- dream_runner.py uses claude-agent-sdk 0.1.48 to drive Claude Code
against SynapBus's MCP server. MCP transport carries
Authorization: Bearer <api_key> AND X-Synapbus-Dispatch-Token from env
via the SDK's McpHttpServerConfig.headers field — confirmed supported.
- Tools restricted via allowed_tools to mcp__synapbus__memory_*.
- Final JSON envelope reports tokens_in/out so harness.Usage stays
populated and the circuit breaker can count consumption.
- Dockerfile builds linux/amd64 at 189 MB, mirroring searcher's
agents/universal recipe.
- k8s-job-template.yaml: backoffLimit 0, ttl 600s, 512Mi/1CPU,
Anthropic credentials via secret-ref.
Grafana dashboard (deploy/kubic/grafana/):
- dream-dashboard.json — 14 panels across 5 rows (dream activity,
token usage vs limit, circuit breaker, injection layer, MCP
transport health), all templated to ${DS_PROMETHEUS}.
- import.sh: resolves the cluster's Prometheus DS uid and POSTs the
dashboard via Grafana API.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2.2 KiB
2.2 KiB
synapbus-dream-agent
A slim Python container that performs memory consolidation for
SynapBus, dispatched on demand by the in-server ConsolidatorWorker
via the k8sjob harness backend.
What it does
- Reads its job context from env vars (dispatch token, job id, job type, owner id, prompt).
- Connects to SynapBus's MCP endpoint over streamable-http, passing
the agent's API key (
Authorization: Bearer ...) and the dispatch token (X-Synapbus-Dispatch-Token: ...) on every request. - Runs Claude Code (via
claude-agent-sdk) constrained to the sixmemory_*MCP tools defined inspecs/020-proactive-memory-dream-worker/contracts/mcp-memory-tools.md. - Streams structured JSON logs to stdout (Loki-friendly) and emits a
final
{"final": true, ...}envelope so the harness can parse Usage.
How the worker invokes it
internal/messaging/consolidator.go builds an HarnessExecRequest
with:
| Env var | Set by |
|---|---|
SYNAPBUS_DISPATCH_TOKEN |
ConsolidatorWorker |
SYNAPBUS_CONSOLIDATION_JOB_ID |
ConsolidatorWorker |
SYNAPBUS_JOB_TYPE |
ConsolidatorWorker |
SYNAPBUS_OWNER_ID |
ConsolidatorWorker |
SYNAPBUS_DREAM_PROMPT |
ConsolidatorWorker |
SYNAPBUS_RUN_ID |
k8sjob harness |
SYNAPBUS_URL, SYNAPBUS_API_KEY, ANTHROPIC_API_KEY |
Pod spec / Secret |
Build
docker buildx build --platform=linux/amd64 \
-t kubic.home.arpa:32000/synapbus-dream-agent:v0.1.0 \
--load /Users/user/repos/synapbus/dream-agent/
Push:
docker push kubic.home.arpa:32000/synapbus-dream-agent:v0.1.0
Local smoke test
The --mock flag validates the env contract and exits without
invoking the SDK or hitting the network:
SYNAPBUS_URL=http://localhost:8080 \
SYNAPBUS_API_KEY=fake \
SYNAPBUS_DISPATCH_TOKEN=fake \
SYNAPBUS_CONSOLIDATION_JOB_ID=1 \
SYNAPBUS_JOB_TYPE=reflection \
SYNAPBUS_OWNER_ID=algis \
SYNAPBUS_DREAM_PROMPT="test" \
SYNAPBUS_RUN_ID=r-test \
python3 dream_runner.py --mock
Deploy
See k8s-job-template.yaml. The harness clones the template and
overlays req.Env into containers[0].env.