Skip to content

fix: Phase 2 hardening, persistence, and Python 3.11+ fixes - #345

Merged
POWERFULMOVES merged 5 commits into
mainfrom
fix/phase2-hardening-fixes
Dec 23, 2025
Merged

POWERFULMOVES merged 5 commits into
mainfrom
fix/phase2-hardening-fixes

Conversation

@POWERFULMOVES

@POWERFULMOVES POWERFULMOVES commented Dec 22, 2025

Copy link
Copy Markdown
Owner

Summary

  • fix(compose): Agent Zero settings persistence (/a0/tmp volume), Archon hostname normalization, health check fix
  • fix(deepresearch): Prometheus counter double-registration prevention
  • fix(flute-gateway): NamedTuple → dataclass for Python 3.11+ compatibility
  • fix(media): PYTHONPATH for media-audio/video analyzers
  • security(dockerfile): Harden notebook-sync and vibevoice-realtime (35/36, 97.2%)
  • chore(gitignore): Exclude agent-zero runtime data
  • feat(ui): Deploy PMOVES.AI Unified Portal as Docker service on port 4482

PMOVES.AI Unified Portal Deployment

NEW: The main PMOVES.AI dashboard is now deployable as a Docker service:

docker compose --profile ui up -d pmoves-ui
curl http://localhost:4482/api/health

Files Added

  • pmoves/ui/Dockerfile - Multi-stage build, Node 20, non-root user
  • pmoves/ui/app/api/health/route.ts - Health check endpoint
  • pmoves/ui/lib/fluteClient.ts - Flute-Gateway voice integration client

Files Modified

  • pmoves/docker-compose.yml - Added pmoves-ui service
  • pmoves/ui/next.config.mjs - Enabled standalone output

Test plan

  • make smoke passes
  • pytest -q passes (14/14)
  • Health endpoints return 200
  • CI workflows pass
  • pmoves-ui builds and runs on port 4482
  • /api/health returns healthy status

Dockerfile Hardening Status

Metric Value
Hardened 35/36 (97.2%)
Accepted Exception agent-zero (root init, drops to pmoves)

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added speech synthesis and audio streaming capabilities with WebSocket support for real-time audio processing
    • Enhanced monitoring dashboard with dynamic configuration for Grafana, Prometheus, and Loki integration
    • Implemented health check endpoints for system diagnostics and service availability monitoring
  • Bug Fixes

    • Improved authentication error handling with clearer guidance on credential configuration

✏️ Tip: You can customize this high-level summary in your review settings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Dec 22, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This PR introduces a complete UI service infrastructure with Docker deployment, a Flute Gateway client library for TTS streaming audio synthesis, health monitoring endpoints, and supporting documentation. Changes span Docker Compose configuration, multi-stage Dockerfiles, Next.js routing and configuration, client-side audio integration libraries, and dashboard monitoring enhancements.

Changes

Cohort / File(s) Summary
Docker Compose & Service Configuration
pmoves/docker-compose.yml
New pmoves-ui service with build context, port mapping (4482:3000), healthcheck (/api/health), network connectivity (app_tier, api_tier, supabase_net), env files, and ui profile.
Multi-Stage Dockerfiles
pmoves/ui/Dockerfile, pmoves/services/vibevoice-realtime/Dockerfile
UI Dockerfile: multi-stage build (builder + runner) using Node 20-slim, non-root user (uid/gid 65532), Next.js standalone server, healthcheck, and port 3000. VoiceRealtime Dockerfile: adds /models directory creation and ownership assignment alongside /app.
Health Check Endpoint
pmoves/ui/app/api/health/route.ts
New GET endpoint returning JSON with status, service name (pmoves-ui), ISO timestamp, and version from npm_package_version env var (fallback "0.1.0").
Flute Gateway Client Library
pmoves/ui/lib/fluteClient.ts
New TypeScript module exporting FluteClient class with HTTP synthesis (synthesize()), WebSocket streaming (connect(), connectWithSession()), session creation (createSession()), health checks (isHealthy()), and playback (playAudio()). Includes auto-reconnect logic, singleton pattern via getFluteClient(), and SynthesizeOptions/FluteSession interfaces.
Next.js Configuration
pmoves/ui/next.config.mjs
Added output: 'standalone' property to Next.js config for containerized deployment.
Monitor Dashboard
pmoves/ui/app/dashboard/monitor/page.tsx
Integrated periodic stats fetching (5s intervals) from /api/monitor/stats, dynamic monitoring URLs from NEXT_PUBLIC_* env vars with localhost fallbacks (Grafana, Prometheus, Loki), error handling, and lastUpdate timestamp display.
Presign Service Integration
pmoves/ui/lib/presign.ts
Simplified fetch logic by removing local helper and multi-hop retry mechanism; replaced with direct fetch call. Added explicit 401/403 authentication failure handling with guidance to configure PRESIGN_SHARED_SECRET.
Learning Documentation
.claude/learnings/docker-dns-casing-2025.md, .claude/learnings/dockerfile-permissions-2025.md, .claude/learnings/nextjs-env-vars-2025.md, .claude/learnings/prometheus-registry-2025.md
Four new documentation files covering Docker DNS case sensitivity, Dockerfile non-root permissions patterns, Next.js NEXT_PUBLIC_* variable handling in Docker, and Python Prometheus metric registration safety.

Sequence Diagram(s)

sequenceDiagram
    actor User as User/<br/>Browser
    participant UI as pmoves-ui
    participant FLUTE_HTTP as Flute HTTP<br/>Gateway (8055)
    participant WEB_AUDIO as Web Audio API

    User->>UI: Request audio synthesis
    UI->>FLUTE_HTTP: POST /synthesize<br/>(text, options)
    FLUTE_HTTP-->>FLUTE_HTTP: Synthesize audio
    FLUTE_HTTP-->>UI: ArrayBuffer
    UI->>WEB_AUDIO: playAudio(buffer)
    WEB_AUDIO-->>User: Play audio

    rect rgb(220, 245, 250)
        Note over UI,WEB_AUDIO: Health Check (Docker healthcheck)
    end
    UI->>FLUTE_HTTP: GET /health
    FLUTE_HTTP-->>UI: 200 OK
Loading
sequenceDiagram
    actor User as User/<br/>Browser
    participant UI as pmoves-ui
    participant FLUTE_WS as Flute WS<br/>Gateway (8056)
    participant WEB_AUDIO as Web Audio API

    User->>UI: Start streaming synthesis
    UI->>FLUTE_HTTP: POST /session
    Note over FLUTE_HTTP: (not shown:<br/>assumed HTTP)
    FLUTE_HTTP-->>UI: FluteSession<br/>(sessionId, wsUrl)
    
    UI->>FLUTE_WS: WebSocket connect<br/>(sessionId)
    FLUTE_WS-->>UI: Connected
    
    loop User sends text chunks
        User->>UI: sendText(chunk)
        UI->>FLUTE_WS: Text message
        FLUTE_WS-->>FLUTE_WS: Synthesize chunk
        FLUTE_WS-->>UI: Audio ArrayBuffer
        UI->>WEB_AUDIO: playAudio(buffer)
        WEB_AUDIO-->>User: Play audio
    end
    
    rect rgb(245, 220, 220)
        Note over UI,FLUTE_WS: Auto-Reconnect on<br/>Disconnect (max retries)
    end
    
    User->>UI: disconnect()
    UI->>FLUTE_WS: Close WebSocket
    FLUTE_WS-->>UI: Closed
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

The PR spans heterogeneous subsystems including Docker orchestration, multi-stage containerization, WebSocket-based streaming client with reconnection logic, health monitoring integration, environment variable handling for client-side networking, and presign authentication refactoring. The FluteClient class introduces non-trivial state management, auto-reconnect mechanisms, and session-based workflows requiring careful validation. Multiple interrelated changes across infrastructure, client libraries, and UI components demand systematic review of each cohort's correctness and integration points.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: Phase 2 hardening (Dockerfile security), persistence (Agent Zero volume mount), and Python 3.11+ fixes (NamedTuple to dataclass, PYTHONPATH additions), plus the new UI deployment feature.
Description check ✅ Passed The description provides a clear summary of changes across multiple areas (compose, deepresearch, flute-gateway, media, dockerfile, gitignore, ui), includes test results, and documents the UI deployment. However, it lacks explicit testing commands/scripts in a code block as required by the template.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/phase2-hardening-fixes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pmoves/services/notebook-sync/Dockerfile (1)

9-18: Entrypoint requires root privileges - cannot run as non-root user.

The Dockerfile sets USER pmoves before the entrypoint executes, but /entrypoint.sh contains operations requiring root:

  1. chown -R pmoves:pmoves "$db_dir" requires root privileges (errors suppressed with || true)
  2. su -s /bin/sh pmoves requires root to switch users

This will fail at runtime. Either:

  • Do NOT set USER pmoves in the Dockerfile; instead have the entrypoint drop privileges to pmoves after setup, OR
  • Move all directory creation and ownership setup to the Dockerfile before the USER pmoves directive
🧹 Nitpick comments (3)
pmoves/services/media-audio/Dockerfile (1)

5-13: Consider consolidating jsonschema in requirements.lock.

The build restructuring correctly separates dependencies from application code for better caching. However, installing jsonschema>=4.0.0 separately to avoid hash conflicts (line 12) bypasses the lock file's version pinning, potentially introducing version drift.

Consider addressing the root cause of the hash conflict by:

  1. Regenerating requirements.lock with jsonschema>=4.0.0 explicitly included
  2. Using a consistent hash algorithm across all dependencies
  3. If external index conflicts are unavoidable, document the specific conflict in a comment

This ensures reproducible builds and prevents future dependency resolution issues.

pmoves/services/flute-gateway/prosodic/types.py (1)

62-67: Optional: Consider extracting validation messages to class-level constants.

The inline error messages in __post_init__ work correctly but could be extracted to class-level constants for consistency with Ruff's TRY003 guideline. This is purely a style preference and not functionally necessary.

Example refactor (optional)
 @dataclass(frozen=True)
 class PauseConfig:
     """Configuration for prosodic pause behavior.
 
     Attributes:
         pause_ms: Duration of pause in milliseconds.
         can_breath: Whether breath sounds are allowed at this boundary.
         breath_probability: Probability [0,1] of inserting breath sound.
     """
+    _ERR_NEGATIVE_PAUSE = "PauseConfig.pause_ms must be non-negative, got {}"
+    _ERR_INVALID_PROBABILITY = "PauseConfig.breath_probability must be in [0.0, 1.0], got {}"
 
     pause_ms: float
     can_breath: bool
     breath_probability: float
 
     def __post_init__(self) -> None:
         """Validate invariants after initialization."""
         if self.pause_ms < 0:
-            raise ValueError(f"PauseConfig.pause_ms must be non-negative, got {self.pause_ms}")
+            raise ValueError(self._ERR_NEGATIVE_PAUSE.format(self.pause_ms))
         if not 0.0 <= self.breath_probability <= 1.0:
-            raise ValueError(
-                f"PauseConfig.breath_probability must be in [0.0, 1.0], got {self.breath_probability}"
-            )
+            raise ValueError(self._ERR_INVALID_PROBABILITY.format(self.breath_probability))

Based on learnings, Ruff hint noted but inline messages are acceptable for validation.

pmoves/services/media-video/Dockerfile (1)

5-25: Consider maintaining a lock file for reproducible builds.

The build restructuring correctly separates dependencies from code and skips PyTorch packages that the base image provides. However, replacing the lock file with explicit version pins (lines 11-24) makes dependency management more fragile:

  1. No hash verification for supply-chain security
  2. Manual version list is harder to maintain and audit
  3. Inconsistent with media-audio's approach (which uses requirements.lock)

If external index conflicts prevent using requirements.lock, consider:

  1. Using pip-compile with --generate-hashes to create a lock file that handles multiple indexes
  2. Documenting the specific PyTorch/PyPI index conflict
  3. Standardizing the approach across media-audio and media-video for maintainability
# Example: Use pip-tools with extra index
# requirements.in:
--extra-index-url https://download.pytorch.org/whl/cu121
fastapi==0.114.2
...

This maintains reproducibility while handling external indexes.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fcb541f and e4587f7.

📒 Files selected for processing (9)
  • pmoves/.gitignore
  • pmoves/docker-compose.yml
  • pmoves/services/deepresearch/worker.py
  • pmoves/services/flute-gateway/prosodic/types.py
  • pmoves/services/flute-gateway/requirements.txt
  • pmoves/services/media-audio/Dockerfile
  • pmoves/services/media-video/Dockerfile
  • pmoves/services/notebook-sync/Dockerfile
  • pmoves/services/vibevoice-realtime/Dockerfile
🧰 Additional context used
📓 Path-based instructions (5)
**/.gitignore

📄 CodeRabbit inference engine (CLAUDE.md)

When a launcher involves cloning 3rd party repositories, downloading files dynamically, or files generated during installation/running, include these file paths in .gitignore file (e.g., Sqlite Databases, environment variables, user-specific files)

Files:

  • pmoves/.gitignore
pmoves/services/**/*.py

📄 CodeRabbit inference engine (pmoves/AGENTS.md)

pmoves/services/**/*.py: Keep modules small and single-purpose; share helpers in services/common/
FastAPI routes: snake_case function names; path names kebab-case only in URLs
Validate payloads against schemas before publishing events using services/common/events.py

Files:

  • pmoves/services/deepresearch/worker.py
  • pmoves/services/flute-gateway/prosodic/types.py
pmoves/**/*.py

📄 CodeRabbit inference engine (pmoves/AGENTS.md)

Python 3.11+, 4-space indentation, prefer type hints

Files:

  • pmoves/services/deepresearch/worker.py
  • pmoves/services/flute-gateway/prosodic/types.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use Python 3.11+ with 4-space indentation and prefer type hints in all Python code

Files:

  • pmoves/services/deepresearch/worker.py
  • pmoves/services/flute-gateway/prosodic/types.py
pmoves/**/docker-compose.yml

📄 CodeRabbit inference engine (pmoves/AGENTS.md)

Use Compose profiles (data, workers) to scope what runs locally in docker-compose.yml

Files:

  • pmoves/docker-compose.yml
🧠 Learnings (28)
📓 Common learnings
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/services/{agent-zero,archon}/**/*.py : For Agents/Archon full-stack validation, follow the 'All Services Up, Then Tests' section in `pmoves/docs/SMOKETESTS.md` and use `make -C pmoves agents-headless-smoke`, `make -C pmoves smoke-gpu`, and `make -C pmoves verify-all`
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Applies to services/**/README.md : Update services/*/README.md and pmoves/docs/PMOVES.AI PLANS/ runbooks when touching service operational code
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Mandatory context before changes: read pmoves/docs/PMOVES.AI PLANS/ROADMAP.md and pmoves/docs/NEXT_STEPS.md to align with current sprint focus
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/**/environment.yml : Preferred Python: Conda 3.11+ (env name: `PMOVES.AI` or `pmoves-ai`); use `environment.yml` at repo root for setup

Applied to files:

  • pmoves/services/media-audio/Dockerfile
  • pmoves/services/media-video/Dockerfile
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Agents images: default uses published images set in `pmoves/env.shared`. For custom code, build a thin overlay FROM the published image and tag it

Applied to files:

  • pmoves/services/media-audio/Dockerfile
  • pmoves/services/notebook-sync/Dockerfile
  • pmoves/services/media-video/Dockerfile
📚 Learning: 2025-12-15T12:01:31.388Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/CLAUDE.md:0-0
Timestamp: 2025-12-15T12:01:31.388Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*.{js,json} : In shell.run API requests for Python apps, always use virtual environments via the venv attribute, which automatically creates or reuses existing virtual environments

Applied to files:

  • pmoves/services/media-audio/Dockerfile
📚 Learning: 2025-12-15T12:02:18.878Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/GEMINI.md:0-0
Timestamp: 2025-12-15T12:02:18.878Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*{install,start}.{js,json} : Always use virtual environments for Python apps via shell.run venv attribute in Pinokio launcher scripts

Applied to files:

  • pmoves/services/media-audio/Dockerfile
📚 Learning: 2025-12-15T12:04:26.230Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/AGENTS.md:0-0
Timestamp: 2025-12-15T12:04:26.230Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*.js : For Python apps, always use virtual environments via the venv attribute in shell.run. This attribute automatically creates a venv or uses if it already exists

Applied to files:

  • pmoves/services/media-audio/Dockerfile
📚 Learning: 2025-12-15T12:02:50.226Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/.windsurfrules:0-0
Timestamp: 2025-12-15T12:02:50.226Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/.gitignore : Project `.gitignore` must include entries for dynamically generated files, cloned repositories, downloaded files, virtual environments, and user-specific configurations

Applied to files:

  • pmoves/.gitignore
📚 Learning: 2025-12-15T12:01:03.100Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/.cursorrules:0-0
Timestamp: 2025-12-15T12:01:03.100Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/.gitignore : Include paths for cloned git repositories, downloaded files, and dynamically generated files (Sqlite Databases, environment variables, user-specific files) in .gitignore to prevent them from being committed

Applied to files:

  • pmoves/.gitignore
📚 Learning: 2025-12-15T12:03:41.584Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:41.584Z
Learning: Applies to pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/**/.gitignore : Include all generated files, downloaded repositories, and dynamic artifacts in .gitignore file to maintain clean repository state

Applied to files:

  • pmoves/.gitignore
📚 Learning: 2025-12-15T12:02:18.878Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/GEMINI.md:0-0
Timestamp: 2025-12-15T12:02:18.878Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/.gitignore : Include dynamically created or cloned files in .gitignore file such as repositories, downloaded files, databases, and user-specific files

Applied to files:

  • pmoves/.gitignore
📚 Learning: 2025-12-15T12:01:31.388Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/CLAUDE.md:0-0
Timestamp: 2025-12-15T12:01:31.388Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/.gitignore : When a launcher involves cloning 3rd party repositories, downloading files, or generating files dynamically, include these file paths in .gitignore (e.g., cloned repos, downloaded files, generated databases, user-specific environment variables)

Applied to files:

  • pmoves/.gitignore
📚 Learning: 2025-12-15T12:04:26.230Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/AGENTS.md:0-0
Timestamp: 2025-12-15T12:04:26.230Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/.gitignore : When a launcher involves cloning 3rd party repositories, downloading files dynamically, or generating files during installation, include these paths in .gitignore

Applied to files:

  • pmoves/.gitignore
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Mandatory context before changes: read pmoves/docs/PMOVES.AI PLANS/ROADMAP.md and pmoves/docs/NEXT_STEPS.md to align with current sprint focus

Applied to files:

  • pmoves/.gitignore
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Read `pmoves/docs/PMOVES.AI PLANS/ROADMAP.md` and `pmoves/docs/NEXT_STEPS.md` before making changes to align with current sprint focus

Applied to files:

  • pmoves/.gitignore
📚 Learning: 2025-12-15T12:01:31.388Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/CLAUDE.md:0-0
Timestamp: 2025-12-15T12:01:31.388Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*.json : When writing launcher projects for existing git repositories, do not modify the project app folder even if installations fail - instead create additional files in the launcher folder to work around issues, unless the user explicitly requests app modifications

Applied to files:

  • pmoves/.gitignore
📚 Learning: 2025-12-22T07:49:51.075Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-22T07:49:51.075Z
Learning: Applies to **/.gitignore : When a launcher involves cloning 3rd party repositories, downloading files dynamically, or files generated during installation/running, include these file paths in .gitignore file (e.g., Sqlite Databases, environment variables, user-specific files)

Applied to files:

  • pmoves/.gitignore
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Pin agent images by setting `AGENT_ZERO_IMAGE`, `ARCHON_IMAGE`, `ARCHON_UI_IMAGE`, and `PMOVES_YT_IMAGE` in `pmoves/env.shared`

Applied to files:

  • pmoves/.gitignore
📚 Learning: 2025-12-07T11:03:07.638Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-07T11:03:07.638Z
Learning: Core application code is located in the `pmoves/` directory; general documentation is located in `docs/` directory

Applied to files:

  • pmoves/.gitignore
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/**/docker-compose.yml : Use Compose profiles (`data`, `workers`) to scope what runs locally in docker-compose.yml

Applied to files:

  • pmoves/services/notebook-sync/Dockerfile
  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:04:26.230Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/AGENTS.md:0-0
Timestamp: 2025-12-15T12:04:26.230Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*.js : Try to find development options to launch apps without Docker. Use automatic installation and launch for the user's platform via scripts instead of Docker

Applied to files:

  • pmoves/services/notebook-sync/Dockerfile
  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Applies to requirements.{txt,lock} : Use uv pip compile --generate-hashes for Python dependency locks on Python 3.11 to ensure reproducible builds

Applied to files:

  • pmoves/services/flute-gateway/requirements.txt
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Applies to services/**/README.md : Update services/*/README.md and pmoves/docs/PMOVES.AI PLANS/ runbooks when touching service operational code

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:02:18.878Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/GEMINI.md:0-0
Timestamp: 2025-12-15T12:02:18.878Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/start.js : Use shell.run API with daemon: true, venv, env, path, message, and on event monitoring for launching servers in start.js

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:02:18.878Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/GEMINI.md:0-0
Timestamp: 2025-12-15T12:02:18.878Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*{install,start,update,reset}.{js,json} : Use Pinokio shell.run API features like env, venv, input, path, sudo, on to reduce script code instead of raw shell commands

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:03:41.584Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:41.584Z
Learning: Applies to pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/**/start.js : Set `daemon: true` at the root level of launcher scripts when launching long-running server processes to prevent process termination after script completion

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:03:41.584Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:41.584Z
Learning: Applies to pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/**/{install,start,update,reset,*.js} : Use `shell.run` API with relative paths (no absolute paths) for the `path` attribute to ensure cross-platform compatibility and correct working directory context

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:03:41.584Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:41.584Z
Learning: Applies to pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/**/{install,start,update,reset}.js : In shell.run API calls, minimize launch flags and parameters, preferring app defaults over explicit configuration unless necessary

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-07T11:03:07.638Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-07T11:03:07.638Z
Learning: Applies to **/pmoves/**/{media,analysis,pipeline}*.py : Implement `media-video` and `media-audio` analysis pipelines with GPU auto-detect for faster-whisper

Applied to files:

  • pmoves/services/media-video/Dockerfile
🪛 Ruff (0.14.8)
pmoves/services/flute-gateway/prosodic/types.py

63-63: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: tests (3.11)
🔇 Additional comments (12)
pmoves/services/flute-gateway/requirements.txt (2)

3-4: The requirements split is properly implemented.

The setup is correct and complete:

  • Hash verification works with pip's secure installs and supports multiple hash algorithms including sha256
  • requirements-pipecat.txt contains the removed dependencies: pipecat-ai[silero]==0.0.98, aiortc==1.12.0, av==14.4.0
  • requirements.lock (93508 bytes) provides hashed dependency pins for the main requirements
  • The Dockerfile correctly installs both files in sequence: first requirements.txt (with hash verification via requirements.lock), then requirements-pipecat.txt (without hashes to avoid conflicts)
  • Python 3.11 container is used as expected
  • The separation is intentionally documented to avoid hash verification conflicts between the locked and external packages

1-1: Lock files are properly configured with hash verification.

The requirements.lock file is correctly generated using uv pip compile --generate-hashes and properly referenced by requirements.txt. The split is intentional: main dependencies are locked with hashes for reproducibility, while optional pipecat dependencies in requirements-pipecat.txt remain unlocked to avoid hash verification conflicts—which is documented in the code comments.

pmoves/services/deepresearch/worker.py (2)

274-274: LGTM: Import required for registry lookup.

The REGISTRY import is necessary to support the new helper function that prevents duplicate metric registration.


319-329: Counter initialization correctly uses the helper function.

The updated counter creation prevents duplicate registration errors when the module is imported multiple times (e.g., via python -m). Both counters are initialized with appropriate names, descriptions, and labelnames.

Note: Robustness depends on the helper function validation improvements suggested above.

pmoves/.gitignore (1)

55-55: LGTM! Runtime data exclusion is appropriate.

The addition of pmoves/data/agent-zero/ correctly excludes Agent Zero's runtime settings from version control, aligning with the new volume mount in docker-compose.yml and the coding guideline to ignore dynamically generated files.

pmoves/services/media-audio/Dockerfile (1)

3-3: LGTM! PYTHONPATH addition enables shared module imports.

Adding PYTHONPATH=/app allows media-audio to import from services.common, resolving the ModuleNotFoundError mentioned in the PR objectives.

pmoves/services/flute-gateway/prosodic/types.py (1)

46-67: LGTM! Python 3.11+ compatibility correctly implemented.

The migration from NamedTuple to frozen dataclass with __post_init__ validation resolves Python 3.11+ compatibility issues while maintaining immutability and the same validation logic. The public API remains unchanged.

pmoves/services/media-video/Dockerfile (1)

3-3: LGTM! PYTHONPATH enables shared module imports.

Adding PYTHONPATH=/app allows media-video to import from services.common, consistent with the media-audio Dockerfile changes.

pmoves/docker-compose.yml (4)

341-341: LGTM! Hostname normalized to lowercase.

Standardizing SUPABASE_URL to lowercase pmoves.ai follows DNS conventions and aligns with the PR objective to normalize Archon SUPABASE_URL.


402-402: LGTM! Consistent hostname normalization.

The SUPABASE_URL hostname is correctly normalized to lowercase pmoves.ai, consistent with the chat-relay change.


448-450: LGTM! Build context correctly set for shared module access.

The explicit build context at pmoves root (.) and dockerfile paths enable these services to copy services/common during build, aligning with the Dockerfile restructuring changes.

Also applies to: 473-475


764-765: LGTM! Settings persistence correctly implemented.

The new volume mount for /a0/tmp ensures Agent Zero's settings.json persists between container restarts, addressing the PR objective for Agent Zero persistence.

Comment thread pmoves/docker-compose.yml
Comment thread pmoves/services/deepresearch/worker.py Outdated
Comment thread pmoves/services/vibevoice-realtime/Dockerfile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
pmoves/docker-compose.yml (1)

341-341: Hostname casing still inconsistent across services.

This line uses lowercase pmoves.ai, but lines 622, 727, 816-817 still use uppercase PMOVES.AI. This inconsistency should be resolved project-wide.

Applies to: 402, 858

🧹 Nitpick comments (5)
pmoves/ui/lib/fluteClient.ts (3)

131-141: Potential stale closure in auto-reconnect.

When setTimeout triggers reconnection, it captures the original onMessage, onError, and onClose callbacks. If the caller has updated these handlers between disconnection and reconnection, the old handlers will still be used.

Consider storing callbacks as instance properties to allow updates, or document this behavior.

🔎 Alternative: Store callbacks as instance properties
 export class FluteClient {
   private ws: WebSocket | null = null;
   private readonly httpUrl: string;
   private readonly wsUrl: string;
   private reconnectAttempts = 0;
   private maxReconnectAttempts = 3;
+  private onMessageHandler?: (data: ArrayBuffer) => void;
+  private onErrorHandler?: (error: Event) => void;
+  private onCloseHandler?: (event: CloseEvent) => void;

   // In connect():
+  this.onMessageHandler = onMessage;
+  this.onErrorHandler = onError;
+  this.onCloseHandler = onClose;

   // In onclose handler:
-  setTimeout(() => this.connect(onMessage, onError, onClose), 1000 * this.reconnectAttempts);
+  setTimeout(() => this.connect(this.onMessageHandler!, this.onErrorHandler, this.onCloseHandler), 1000 * this.reconnectAttempts);

177-191: AudioContext resource leak on repeated calls.

Each playAudio call creates a new AudioContext. While it's closed after playback, browsers limit concurrent AudioContexts (typically 6). Rapid successive calls before playback completes could exhaust this limit.

Consider reusing a single AudioContext or adding a queue mechanism for production use.

🔎 Proposed fix: Reuse AudioContext
+let sharedAudioContext: AudioContext | null = null;
+
+function getAudioContext(): AudioContext {
+  if (!sharedAudioContext || sharedAudioContext.state === 'closed') {
+    sharedAudioContext = new AudioContext();
+  }
+  return sharedAudioContext;
+}
+
 export async function playAudio(audioData: ArrayBuffer): Promise<void> {
-  const audioContext = new AudioContext();
+  const audioContext = getAudioContext();
   const audioBuffer = await audioContext.decodeAudioData(audioData);
   const source = audioContext.createBufferSource();
   source.buffer = audioBuffer;
   source.connect(audioContext.destination);
   source.start(0);

   return new Promise((resolve) => {
     source.onended = () => {
-      audioContext.close();
       resolve();
     };
   });
 }

193-201: Singleton lacks reset capability for testing.

The singleton pattern is convenient but makes testing difficult. Consider adding a resetFluteClient() function or using dependency injection patterns for testability.

pmoves/ui/Dockerfile (2)

8-9: Curl is unnecessary in the builder stage.

The builder stage only performs the build and doesn't need curl. Installing it adds ~15MB and extends build time. Remove it from the builder stage.

🔎 Proposed fix
 WORKDIR /app

-# Install curl for health checks
-RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/*
-
 # Install dependencies
 COPY package*.json ./

12-13: Use npm ci instead of npm install for reproducible builds.

npm ci is preferred in CI/Docker builds as it:

  • Installs exact versions from package-lock.json
  • Removes existing node_modules first
  • Fails if package-lock.json is out of sync
🔎 Proposed fix
 # Install dependencies
 COPY package*.json ./
-RUN npm install
+RUN npm ci
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e4587f7 and d33da33.

📒 Files selected for processing (5)
  • pmoves/docker-compose.yml
  • pmoves/ui/Dockerfile
  • pmoves/ui/app/api/health/route.ts
  • pmoves/ui/lib/fluteClient.ts
  • pmoves/ui/next.config.mjs
🧰 Additional context used
📓 Path-based instructions (2)
pmoves/ui/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (pmoves/AGENTS.md)

UI updates: run make -C pmoves notebook-workbench-smoke ARGS="--thread=<uuid>" to lint the Next.js bundle and validate Supabase connectivity; reference pmoves/docs/UI_NOTEBOOK_WORKBENCH.md

Files:

  • pmoves/ui/app/api/health/route.ts
  • pmoves/ui/lib/fluteClient.ts
pmoves/**/docker-compose.yml

📄 CodeRabbit inference engine (pmoves/AGENTS.md)

Use Compose profiles (data, workers) to scope what runs locally in docker-compose.yml

Files:

  • pmoves/docker-compose.yml
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/services/{agent-zero,archon}/**/*.py : For Agents/Archon full-stack validation, follow the 'All Services Up, Then Tests' section in `pmoves/docs/SMOKETESTS.md` and use `make -C pmoves agents-headless-smoke`, `make -C pmoves smoke-gpu`, and `make -C pmoves verify-all`
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Mandatory context before changes: read pmoves/docs/PMOVES.AI PLANS/ROADMAP.md and pmoves/docs/NEXT_STEPS.md to align with current sprint focus
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Agents/Archon: for full-stack validation, follow the 'All Services Up, Then Tests' section in pmoves/docs/SMOKETESTS.md and the Archon service guide
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: UI updates: run make -C pmoves notebook-workbench-smoke ARGS='--thread=<uuid>' to lint the Next.js bundle and validate Supabase connectivity; reference pmoves/docs/UI_NOTEBOOK_WORKBENCH.md
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/ui/**/*.{js,jsx,ts,tsx} : UI updates: run `make -C pmoves notebook-workbench-smoke ARGS="--thread=<uuid>"` to lint the Next.js bundle and validate Supabase connectivity; reference `pmoves/docs/UI_NOTEBOOK_WORKBENCH.md`

Applied to files:

  • pmoves/ui/next.config.mjs
  • pmoves/ui/Dockerfile
  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: UI updates: run make -C pmoves notebook-workbench-smoke ARGS='--thread=<uuid>' to lint the Next.js bundle and validate Supabase connectivity; reference pmoves/docs/UI_NOTEBOOK_WORKBENCH.md

Applied to files:

  • pmoves/ui/Dockerfile
  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:04:26.230Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/AGENTS.md:0-0
Timestamp: 2025-12-15T12:04:26.230Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*.js : Try to find development options to launch apps without Docker. Use automatic installation and launch for the user's platform via scripts instead of Docker

Applied to files:

  • pmoves/ui/Dockerfile
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Agents images: default uses published images set in `pmoves/env.shared`. For custom code, build a thin overlay FROM the published image and tag it

Applied to files:

  • pmoves/ui/Dockerfile
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/**/docker-compose.yml : Use Compose profiles (`data`, `workers`) to scope what runs locally in docker-compose.yml

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Applies to services/**/README.md : Update services/*/README.md and pmoves/docs/PMOVES.AI PLANS/ runbooks when touching service operational code

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Mandatory context before changes: read pmoves/docs/PMOVES.AI PLANS/ROADMAP.md and pmoves/docs/NEXT_STEPS.md to align with current sprint focus

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/services/{agent-zero,archon}/**/*.py : For Agents/Archon full-stack validation, follow the 'All Services Up, Then Tests' section in `pmoves/docs/SMOKETESTS.md` and use `make -C pmoves agents-headless-smoke`, `make -C pmoves smoke-gpu`, and `make -C pmoves verify-all`

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Agents/Archon: for full-stack validation, follow the 'All Services Up, Then Tests' section in pmoves/docs/SMOKETESTS.md and the Archon service guide

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Applies to {Dockerfile,docker-compose.yml,docker-compose.*.yml,pmoves/docker-compose.*.override.yml} : Dockerfile and docker-compose.yml must follow multi-arch build practices (amd64+arm64) with Trivy scanning for HIGH/CRITICAL vulnerabilities

Applied to files:

  • pmoves/docker-compose.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: tests (3.11)
🔇 Additional comments (10)
pmoves/ui/lib/fluteClient.ts (2)

45-53: LGTM on constructor with environment fallbacks.

The constructor properly chains optional parameters → environment variables → localhost defaults, which is appropriate for local development and containerized deployment.


83-93: Verify browser support requirements before using AbortSignal.timeout().

AbortSignal.timeout() works across the latest devices and browser versions since April 2024, but may not work in older devices or browsers. If support for older browsers is needed, implement a fallback using AbortController with manual timeout handling.

pmoves/ui/next.config.mjs (1)

8-8: LGTM - Standalone output aligns with Dockerfile.

The output: 'standalone' configuration correctly supports the containerized deployment approach in the Dockerfile, which runs node server.js from the standalone build output.

pmoves/ui/Dockerfile (2)

26-38: LGTM - Good security hardening with non-root user.

The non-root user configuration with explicit UID/GID 65532 follows security best practices and aligns with other PMOVES services as mentioned in the comments.


46-47: LGTM - Healthcheck properly configured.

The healthcheck configuration (30s interval, 10s timeout, 60s start period, 3 retries) is appropriate for a Next.js application and matches the docker-compose configuration.

pmoves/docker-compose.yml (4)

421-447: LGTM - Well-structured pmoves-ui service definition.

The new UI service is properly configured with:

  • Appropriate profile (ui) per coding guidelines
  • Correct network memberships (app_tier, api_tier, supabase_net)
  • Health check matching the Dockerfile and route implementation
  • Environment variables for service discovery

792-793: LGTM - Agent-zero settings persistence added.

The new volume mapping for /a0/tmp enables persistence of settings.json between container restarts, addressing the PR objective.


862-863: LGTM - PYTHONPATH addition for archon vendor sources.

Adding /app/vendor/archon/python to PYTHONPATH allows proper module resolution for the archon service.


476-478: LGTM - Explicit build context for media services.

The explicit context: . and dockerfile: services/media-video/Dockerfile pattern properly enables the services to access the shared services/ modules via PYTHONPATH as mentioned in the PR objectives.

Applies to: 501-503

pmoves/ui/app/api/health/route.ts (1)

7-14: Ensure npm_package_version is explicitly injected at build time for the health endpoint.

The process.env.npm_package_version variable is only available within npm scripts context and won't be present in standalone production builds unless explicitly set. The fallback to '0.1.0' prevents crashes but means the endpoint will always return a default version rather than the actual application version. Set this environment variable during the build step (in your build script or Dockerfile) or read the version from package.json at build time.

Comment thread pmoves/docker-compose.yml Outdated
Comment thread pmoves/docker-compose.yml
POWERFULMOVES pushed a commit that referenced this pull request Dec 22, 2025
Critical fixes:
- Add error logging to isHealthy() catch block (was silent failure)
- Fix WebSocket message type: 'synthesize' → 'text'
- Add error handling to playAudio() with proper cleanup

Improvements:
- Add onReconnectExhausted callback for connection failure notification
- Implement session management using FluteSession interface
- Add createSession() and connectWithSession() methods
- Add @throws JSDoc annotations and browser-only warnings

Session API reference: POST /v1/sessions returns session_id, websocket_url

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
pmoves/ui/lib/fluteClient.ts (2)

193-244: Guard against concurrent connection attempts.

The check at line 200 only prevents reconnection if the WebSocket is already OPEN. If readyState is CONNECTING (0), CLOSING (2), or CLOSED (3), the guard passes and a new WebSocket is created, potentially leaking the previous instance.

🔎 Suggested enhancement
-    if (this.ws?.readyState === WebSocket.OPEN) {
+    if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) {
       console.warn('FluteClient: Already connected');
       return;
     }
+
+    // Clean up any existing WebSocket in other states
+    if (this.ws) {
+      this.ws.close();
+      this.ws = null;
+    }

This prevents creating a new connection while one is in progress and cleans up stale connections.


288-309: Add runtime guard for SSR compatibility.

The function instantiates AudioContext directly, which will throw in server-side rendering contexts. While the @warning annotation documents this limitation, a runtime check would prevent unexpected errors if the function is inadvertently called server-side.

🔎 Suggested enhancement
 export async function playAudio(audioData: ArrayBuffer): Promise<void> {
+  if (typeof window === 'undefined' || typeof AudioContext === 'undefined') {
+    throw new Error('playAudio() is only available in browser environments');
+  }
+
   const audioContext = new AudioContext();

This provides a clearer error message and prevents unexpected SSR failures.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d33da33 and 3cbe8e7.

📒 Files selected for processing (1)
  • pmoves/ui/lib/fluteClient.ts
🧰 Additional context used
📓 Path-based instructions (1)
pmoves/ui/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (pmoves/AGENTS.md)

UI updates: run make -C pmoves notebook-workbench-smoke ARGS="--thread=<uuid>" to lint the Next.js bundle and validate Supabase connectivity; reference pmoves/docs/UI_NOTEBOOK_WORKBENCH.md

Files:

  • pmoves/ui/lib/fluteClient.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/services/{agent-zero,archon}/**/*.py : For Agents/Archon full-stack validation, follow the 'All Services Up, Then Tests' section in `pmoves/docs/SMOKETESTS.md` and use `make -C pmoves agents-headless-smoke`, `make -C pmoves smoke-gpu`, and `make -C pmoves verify-all`
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: tests (3.11)
  • GitHub Check: Analyze (python)
🔇 Additional comments (10)
pmoves/ui/lib/fluteClient.ts (10)

1-44: Well-structured interfaces and documentation.

The file header, JSDoc examples, and type definitions are clear and comprehensive. The interface design properly separates concerns between synthesis options and session management.


66-74: Clean constructor with environment-aware defaults.

The use of NEXT_PUBLIC_* environment variables is appropriate for Next.js, and the localhost fallbacks are sensible for development.


85-104: Solid HTTP synthesis implementation.

Error handling includes status codes and response text, which aids debugging. The ArrayBuffer return type aligns with the Web Audio API requirements.


114-131: Proper session creation with field mapping.

The snake_case to camelCase transformation and Date parsing align with TypeScript conventions. Error handling is consistent with other methods.


138-149: Robust health check with timeout.

The use of AbortSignal.timeout(5000) prevents hanging requests, and graceful error handling returns a boolean status without throwing.


254-259: Clear connection state validation.

The method correctly checks the WebSocket state before sending and provides a helpful error message directing users to call connect() or connectWithSession() first.


264-270: Proper cleanup on disconnect.

The method uses the standard close code 1000 for normal closure and cleans up both the WebSocket reference and stored callbacks.


275-277: Simple and correct connection state getter.


311-325: Convenient singleton pattern for simple use cases.

The lazy initialization is straightforward and provides a shared instance for applications that don't need multiple client instances or custom URLs.


1-325: Verify UI integration with smoke tests.

As per the coding guidelines, UI updates should be validated with the notebook workbench smoke tests to ensure Next.js bundle integrity and Supabase connectivity.

#!/bin/bash
# Run the UI notebook workbench smoke tests with a test thread UUID
# This validates the Next.js build and integration points

make -C pmoves notebook-workbench-smoke ARGS="--thread=$(uuidgen)"

Reference pmoves/docs/UI_NOTEBOOK_WORKBENCH.md for additional context on the test suite.

POWERFULMOVES pushed a commit that referenced this pull request Dec 22, 2025
Critical:
- archon-agent-work-orders healthcheck: /health → /healthz
  (service exposes /healthz per main.py:248)

Major:
- pmoves-ui NEXT_PUBLIC env vars: use localhost fallback
  (NEXT_PUBLIC vars are build-time embedded for browser use)
- deepresearch Prometheus: add try/except with type validation
  (safer than direct private _names_to_collectors access)

Minor:
- Normalize supabase_kong hostname to lowercase (4 occurrences)
  (Docker DNS is case-sensitive on some configurations)
- vibevoice-realtime: create /models directory with ownership
  (entrypoint.sh writes to /models via snapshot_download)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
pmoves/services/deepresearch/worker.py (1)

302-320: Consider validating labelnames to prevent subtle mismatches.

The function validates metric type but not labelnames. If an existing Counter was registered with different labelnames, .labels() calls will fail at runtime with confusing errors.

🔎 Proposed enhancement to validate labelnames
 def _get_or_create_counter(name: str, description: str, labelnames: tuple) -> Counter:
     """Get existing counter or create new one (safe for module reimport via -m flag).
 
     The python -m flag can cause module double-import, which would register
     Prometheus metrics twice. This function uses try/except to handle duplicate
     registration and validates the existing metric type.
     """
     try:
         return Counter(name, description, labelnames=labelnames)
     except ValueError as e:
         if "Duplicated timeseries" in str(e):
             # Metric already exists; retrieve and validate type
             existing = REGISTRY._names_to_collectors.get(name)
             if existing is not None and isinstance(existing, Counter):
+                # Validate labelnames match to prevent runtime errors
+                if hasattr(existing, '_labelnames') and existing._labelnames != labelnames:
+                    raise ValueError(
+                        f"Metric '{name}' exists with labelnames {existing._labelnames}, "
+                        f"but requested {labelnames}"
+                    ) from e
                 return existing
             raise TypeError(
                 f"Metric '{name}' exists but is {type(existing).__name__}, not Counter"
             ) from e
         raise
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3cbe8e7 and f9194b1.

📒 Files selected for processing (3)
  • pmoves/docker-compose.yml
  • pmoves/services/deepresearch/worker.py
  • pmoves/services/vibevoice-realtime/Dockerfile
🧰 Additional context used
📓 Path-based instructions (4)
pmoves/**/docker-compose.yml

📄 CodeRabbit inference engine (pmoves/AGENTS.md)

Use Compose profiles (data, workers) to scope what runs locally in docker-compose.yml

Files:

  • pmoves/docker-compose.yml
pmoves/services/**/*.py

📄 CodeRabbit inference engine (pmoves/AGENTS.md)

pmoves/services/**/*.py: Keep modules small and single-purpose; share helpers in services/common/
FastAPI routes: snake_case function names; path names kebab-case only in URLs
Validate payloads against schemas before publishing events using services/common/events.py

Files:

  • pmoves/services/deepresearch/worker.py
pmoves/**/*.py

📄 CodeRabbit inference engine (pmoves/AGENTS.md)

Python 3.11+, 4-space indentation, prefer type hints

Files:

  • pmoves/services/deepresearch/worker.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use Python 3.11+ with 4-space indentation and prefer type hints in all Python code

Files:

  • pmoves/services/deepresearch/worker.py
🧠 Learnings (20)
📓 Common learnings
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/services/{agent-zero,archon}/**/*.py : For Agents/Archon full-stack validation, follow the 'All Services Up, Then Tests' section in `pmoves/docs/SMOKETESTS.md` and use `make -C pmoves agents-headless-smoke`, `make -C pmoves smoke-gpu`, and `make -C pmoves verify-all`
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Mandatory context before changes: read pmoves/docs/PMOVES.AI PLANS/ROADMAP.md and pmoves/docs/NEXT_STEPS.md to align with current sprint focus
📚 Learning: 2025-12-15T12:04:26.230Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/AGENTS.md:0-0
Timestamp: 2025-12-15T12:04:26.230Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*.js : Try to find development options to launch apps without Docker. Use automatic installation and launch for the user's platform via scripts instead of Docker

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Applies to {Dockerfile,docker-compose.yml,docker-compose.*.yml,pmoves/docker-compose.*.override.yml} : Dockerfile and docker-compose.yml must follow multi-arch build practices (amd64+arm64) with Trivy scanning for HIGH/CRITICAL vulnerabilities

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:02:18.878Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/GEMINI.md:0-0
Timestamp: 2025-12-15T12:02:18.878Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*{install,start}.{js,json} : Always use virtual environments for Python apps via shell.run venv attribute in Pinokio launcher scripts

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:01:31.388Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/CLAUDE.md:0-0
Timestamp: 2025-12-15T12:01:31.388Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/{install,start,update,reset}.js : Scripts must be able to replicate install and launch steps 100% - include all 3rd party package installations and repository downloads in scripts, do not assume end user's system state, and make everything self-contained

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:02:18.878Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/GEMINI.md:0-0
Timestamp: 2025-12-15T12:02:18.878Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*{install,start,update,reset}.{js,json} : Scripts must be able to replicate install and launch steps 100% for end users, do not assume system state and make everything self-contained

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:03:41.584Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:41.584Z
Learning: Applies to pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/**/{install,start,update,reset}.js : Always use the `venv` attribute in shell.run API calls for Python projects instead of manually managing virtual environments

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:04:26.230Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/AGENTS.md:0-0
Timestamp: 2025-12-15T12:04:26.230Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/install.js : Install scripts should work for each specific operating system. Ignore Docker related instructions and use platform-specific install/launch instructions instead

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:02:18.878Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/GEMINI.md:0-0
Timestamp: 2025-12-15T12:02:18.878Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*{install,start,update,reset}.{js,json} : Use Pinokio shell.run API features like env, venv, input, path, sudo, on to reduce script code instead of raw shell commands

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:03:41.584Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:41.584Z
Learning: Applies to pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/**/start.js : Set `daemon: true` at the root level of launcher scripts when launching long-running server processes to prevent process termination after script completion

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:02:50.226Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/.windsurfrules:0-0
Timestamp: 2025-12-15T12:02:50.226Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/install.js : Install scripts should avoid modifying the cloned project folder (app directory) and instead create additional files in launcher folder to work around installation issues without touching app logic

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:02:18.878Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/GEMINI.md:0-0
Timestamp: 2025-12-15T12:02:18.878Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/start.js : Use shell.run API with daemon: true, venv, env, path, message, and on event monitoring for launching servers in start.js

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:04:26.230Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/AGENTS.md:0-0
Timestamp: 2025-12-15T12:04:26.230Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*.js : When running shell commands, take full advantage of the Pinokio shell.run API features like env, venv, input, path, sudo, and on to reduce script code

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/**/docker-compose.yml : Use Compose profiles (`data`, `workers`) to scope what runs locally in docker-compose.yml

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Applies to services/**/README.md : Update services/*/README.md and pmoves/docs/PMOVES.AI PLANS/ runbooks when touching service operational code

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: UI updates: run make -C pmoves notebook-workbench-smoke ARGS='--thread=<uuid>' to lint the Next.js bundle and validate Supabase connectivity; reference pmoves/docs/UI_NOTEBOOK_WORKBENCH.md

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/services/{agent-zero,archon}/**/*.py : For Agents/Archon full-stack validation, follow the 'All Services Up, Then Tests' section in `pmoves/docs/SMOKETESTS.md` and use `make -C pmoves agents-headless-smoke`, `make -C pmoves smoke-gpu`, and `make -C pmoves verify-all`

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:02:50.226Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/.windsurfrules:0-0
Timestamp: 2025-12-15T12:02:50.226Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/start.js : Server launchers should configure apps to run at localhost (127.0.0.1) instead of 0.0.0.0 by using environment variables or startup flags

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:03:41.584Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:41.584Z
Learning: Applies to pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/**/start.js : Always attempt to configure servers to launch at 127.0.0.1 or localhost rather than 0.0.0.0 using launch flags or environment variables

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Agents/Archon: for full-stack validation, follow the 'All Services Up, Then Tests' section in pmoves/docs/SMOKETESTS.md and the Archon service guide

Applied to files:

  • pmoves/docker-compose.yml
🪛 Ruff (0.14.10)
pmoves/services/deepresearch/worker.py

317-319: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: tests (3.11)
  • GitHub Check: Analyze (python)
🔇 Additional comments (7)
pmoves/services/vibevoice-realtime/Dockerfile (1)

37-44: Excellent security hardening implementation; previous concern addressed.

The non-root user setup follows security best practices:

  • High-numbered UID/GID (65532) is appropriate for container service accounts
  • /sbin/nologin shell prevents interactive access
  • Comprehensive ownership changes cover all runtime directories (/app, /app/vibevoice, /models)
  • Correct ordering with chown before USER directive

The /models directory creation and ownership that was flagged in the previous review has been properly implemented (line 40-41), ensuring the entrypoint can write model downloads without permission errors.

pmoves/services/deepresearch/worker.py (1)

327-337: LGTM!

The Prometheus counter creation now safely handles module reimport via the try/except wrapper. The labelnames are appropriate for tracking fallback reasons and request status.

pmoves/docker-compose.yml (5)

432-433: LGTM!

The Flute Gateway URLs now use localhost fallbacks that are accessible from the browser. Ports 8055 and 8056 are exposed on the host (line 415), so client-side connections will work correctly.


792-793: LGTM!

The new tmp directory mount provides persistence for Agent Zero's settings.json, allowing runtime configuration to survive container restarts. The host path is configurable via AGENT_ZERO_TMP_DIR for flexibility.


476-478: LGTM!

The explicit build context at repository root (.) allows media service Dockerfiles to access services/common/ for shared imports, aligning with the PR objective to fix import resolution.

Also applies to: 501-503


862-863: LGTM!

The PYTHONPATH addition allows archon-agent-work-orders to import vendored Archon Python modules, ensuring dependency resolution works correctly.


341-341: LGTM!

All SUPABASE_URL and SUPABASE_REALTIME_URL references now consistently use the lowercase supabase_kong_pmoves.ai hostname for container-to-container communication. This normalization addresses Docker DNS case-sensitivity concerns.

Also applies to: 402-402, 622-622, 727-727, 816-817, 858-858

Comment thread pmoves/docker-compose.yml Outdated
POWERFULMOVES pushed a commit that referenced this pull request Dec 22, 2025
- NEXT_PUBLIC_SUPABASE_URL: Use localhost:8000 fallback for browser-side
  Supabase access (internal Docker hostnames don't resolve in browser)
- archon-agent-work-orders: Fix healthcheck endpoint /healthz → /health
  (service exposes /health, not /healthz)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
POWERFULMOVES pushed a commit that referenced this pull request Dec 22, 2025
Phase 1 - Environment Variables:
- Add 20+ missing NEXT_PUBLIC_* environment variables
- Configure all agent service URLs (Agent Zero, Archon, Hi-RAG)
- Add TensorZero, Open Notebook, monitoring stack URLs
- Add server-side POSTGREST_URL, PRESIGN_SHARED_SECRET
- Fix variable naming: NEXT_PUBLIC_OPEN_NOTEBOOK_API_URL

Phase 2 - Hardcoded URL Fixes:
- monitor/page.tsx: Use NEXT_PUBLIC_GRAFANA/PROMETHEUS/LOKI_URL
- presign.ts: Remove insecure 'change_me' fallback (security fix)
  Now throws actionable error when PRESIGN_SHARED_SECRET missing

Documentation:
- Add learnings for Docker DNS casing, NEXT_PUBLIC patterns
- Add learnings for Dockerfile permissions, Prometheus registry

Fixes: PMOVES UI not connected to backend services
Refs: PR #345

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
pmoves/ui/app/dashboard/monitor/page.tsx (1)

143-143: Consider defensive URL parsing for misconfigured env vars.

If NEXT_PUBLIC_GRAFANA_URL (or the other URL vars) is set to an invalid URL, new URL(...) will throw at render time. While the fallbacks protect against unset vars, a malformed override would crash the component.

This is a minor edge case—misconfiguration would surface immediately—but if you want defensive handling:

🔎 Optional: safe port extraction helper
// At module level
function getPort(url: string): string {
  try {
    return new URL(url).port || '80';
  } catch {
    return '80';
  }
}

Then use {getPort(GRAFANA_URL)} in JSX.

pmoves/ui/lib/presign.ts (1)

70-76: Error message should clarify optional authentication requirements.

The error message at lines 73-74 suggests PRESIGN_SHARED_SECRET is always required, but the code at lines 46-49 correctly allows requests without it. The service's check_auth() function (api.py:32-34) skips authentication if PRESIGN_SHARED_SECRET is not configured on the server, meaning the secret is optional for both client and server. When authentication fails with 401/403, the error message should clarify that the secret is only required if the server has it configured, or that client and server secrets must match if both are present. Consider updating the error message to be more accurate about the optional nature of this credential.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3d6a5b and 16ece27.

📒 Files selected for processing (7)
  • .claude/learnings/docker-dns-casing-2025.md
  • .claude/learnings/dockerfile-permissions-2025.md
  • .claude/learnings/nextjs-env-vars-2025.md
  • .claude/learnings/prometheus-registry-2025.md
  • pmoves/docker-compose.yml
  • pmoves/ui/app/dashboard/monitor/page.tsx
  • pmoves/ui/lib/presign.ts
✅ Files skipped from review due to trivial changes (2)
  • .claude/learnings/docker-dns-casing-2025.md
  • .claude/learnings/dockerfile-permissions-2025.md
🧰 Additional context used
📓 Path-based instructions (3)
.claude/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

Mirror service/endpoint changes in .claude/context/services-catalog.md and add command stubs in .claude/commands/ when relevant

Files:

  • .claude/learnings/prometheus-registry-2025.md
  • .claude/learnings/nextjs-env-vars-2025.md
pmoves/ui/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (pmoves/AGENTS.md)

UI updates: run make -C pmoves notebook-workbench-smoke ARGS="--thread=<uuid>" to lint the Next.js bundle and validate Supabase connectivity; reference pmoves/docs/UI_NOTEBOOK_WORKBENCH.md

Files:

  • pmoves/ui/app/dashboard/monitor/page.tsx
  • pmoves/ui/lib/presign.ts
pmoves/**/docker-compose.yml

📄 CodeRabbit inference engine (pmoves/AGENTS.md)

Use Compose profiles (data, workers) to scope what runs locally in docker-compose.yml

Files:

  • pmoves/docker-compose.yml
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: UI updates: run make -C pmoves notebook-workbench-smoke ARGS='--thread=<uuid>' to lint the Next.js bundle and validate Supabase connectivity; reference pmoves/docs/UI_NOTEBOOK_WORKBENCH.md
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/services/{agent-zero,archon}/**/*.py : For Agents/Archon full-stack validation, follow the 'All Services Up, Then Tests' section in `pmoves/docs/SMOKETESTS.md` and use `make -C pmoves agents-headless-smoke`, `make -C pmoves smoke-gpu`, and `make -C pmoves verify-all`
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/ui/**/*.{js,jsx,ts,tsx} : UI updates: run `make -C pmoves notebook-workbench-smoke ARGS="--thread=<uuid>"` to lint the Next.js bundle and validate Supabase connectivity; reference `pmoves/docs/UI_NOTEBOOK_WORKBENCH.md`
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Mandatory context before changes: read pmoves/docs/PMOVES.AI PLANS/ROADMAP.md and pmoves/docs/NEXT_STEPS.md to align with current sprint focus
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/ui/**/*.{js,jsx,ts,tsx} : UI updates: run `make -C pmoves notebook-workbench-smoke ARGS="--thread=<uuid>"` to lint the Next.js bundle and validate Supabase connectivity; reference `pmoves/docs/UI_NOTEBOOK_WORKBENCH.md`

Applied to files:

  • pmoves/ui/app/dashboard/monitor/page.tsx
  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: UI updates: run make -C pmoves notebook-workbench-smoke ARGS='--thread=<uuid>' to lint the Next.js bundle and validate Supabase connectivity; reference pmoves/docs/UI_NOTEBOOK_WORKBENCH.md

Applied to files:

  • pmoves/ui/app/dashboard/monitor/page.tsx
  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Applies to services/**/README.md : Update services/*/README.md and pmoves/docs/PMOVES.AI PLANS/ runbooks when touching service operational code

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/**/docker-compose.yml : Use Compose profiles (`data`, `workers`) to scope what runs locally in docker-compose.yml

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/services/{agent-zero,archon}/**/*.py : For Agents/Archon full-stack validation, follow the 'All Services Up, Then Tests' section in `pmoves/docs/SMOKETESTS.md` and use `make -C pmoves agents-headless-smoke`, `make -C pmoves smoke-gpu`, and `make -C pmoves verify-all`

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:02:50.226Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/.windsurfrules:0-0
Timestamp: 2025-12-15T12:02:50.226Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/start.js : Server launchers should configure apps to run at localhost (127.0.0.1) instead of 0.0.0.0 by using environment variables or startup flags

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:03:41.584Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:41.584Z
Learning: Applies to pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/**/start.js : Always attempt to configure servers to launch at 127.0.0.1 or localhost rather than 0.0.0.0 using launch flags or environment variables

Applied to files:

  • pmoves/docker-compose.yml
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Agents/Archon: for full-stack validation, follow the 'All Services Up, Then Tests' section in pmoves/docs/SMOKETESTS.md and the Archon service guide

Applied to files:

  • pmoves/docker-compose.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: tests (3.11)
🔇 Additional comments (11)
.claude/learnings/prometheus-registry-2025.md (1)

1-52: Well-documented pattern for safe Prometheus metric registration.

The learning document clearly articulates the problem with direct private API access and provides a sound solution using try/except with type validation. The pattern correctly handles the "Duplicated timeseries" error case and validates both existence and type using isinstance(), preventing silent failures when metric types conflict. The anti-pattern comparison effectively illustrates the risks of the naive approach.

Please verify that the pattern documented here matches the implementation now in use at pmoves/services/deepresearch/worker.py (referenced in the AI summary as introducing _get_or_create_counter()). If the implementation deviates (e.g., in handling labelnames validation or error messages), this documentation should be updated to reflect the actual code.

.claude/learnings/nextjs-env-vars-2025.md (1)

1-46: Well-documented learning on Next.js environment variable pitfalls.

This document clearly explains the build-time embedding behavior of NEXT_PUBLIC_* variables and provides an actionable pattern with localhost fallbacks. The detection script is a helpful addition for catching misconfigurations.

pmoves/ui/app/dashboard/monitor/page.tsx (2)

6-9: Good use of environment variables with localhost fallbacks.

This pattern correctly handles the client-side URL resolution issue documented in .claude/learnings/nextjs-env-vars-2025.md. The fallback defaults are appropriate for local development.


17-42: Clean polling implementation with proper cleanup.

The active flag pattern correctly prevents state updates after unmount, and the error handling is well-structured. The 5-second polling interval is reasonable for monitoring data.

As per coding guidelines, ensure you've validated the UI changes:

make -C pmoves notebook-workbench-smoke ARGS="--thread=<uuid>"
pmoves/ui/lib/presign.ts (1)

62-66: LGTM: Simplified fetch call improves maintainability.

Removing the retry logic and making a direct fetch call reduces complexity while maintaining the same functionality.

pmoves/docker-compose.yml (6)

341-341: LGTM: Hostname normalization to lowercase is correct.

All SUPABASE_URL references now consistently use lowercase pmoves.ai hostname, which aligns with DNS standards and resolves previous inconsistencies.

Based on learnings, DNS hostnames should use consistent casing.

Also applies to: 402-402, 644-644, 749-749, 838-839, 880-880


814-815: LGTM: Agent Zero settings persistence is correctly configured.

The new volume mount for /a0/tmp enables persistence of settings.json across container restarts, following the same pattern as other Agent Zero mounts. The PR objectives indicate that .gitignore has been updated to exclude pmoves/data/agent-zero/ from version control.


906-906: No action required. The healthcheck endpoint is correctly configured to probe /health for the archon-agent-work-orders service, which is different from the main archon service's /healthz endpoint. These services have separate health check implementations appropriate to their configurations.


498-500: Build context change correctly enables shared module access with proper Dockerfile configuration.

The build context path is resolved relative to the docker-compose.yml file location, and dockerfile paths are resolved relative to the build context. The implementation is correct:

Both media-video and media-audio services set context: . and use COPY instructions that properly account for the repository-level context (e.g., COPY services/common /app/services/common). PYTHONPATH environment variables are set in both Dockerfiles to specify directories Python should search for modules, enabling the services to access shared modules as intended.

The services are correctly assigned to ["workers", "orchestration"] profiles, complying with the guideline to use Compose profiles for scoping local execution.


421-470: LGTM: pmoves-ui service configuration is correct.

The new UI service properly separates client-side (NEXT_PUBLIC_*) and server-side environment variables:

  • Client-side vars correctly use localhost URLs (accessible from browser)
  • Server-side vars correctly use Docker hostnames (container-to-container)

Port mapping 4482:3000 exposes the UI on the host, and the healthcheck endpoint is appropriate.

As per coding guidelines, UI updates should be validated with smoke tests:

#!/bin/bash
# Verify UI service health endpoint and configuration
# Reference: pmoves/docs/UI_NOTEBOOK_WORKBENCH.md

# Check if UI service health endpoint is defined
echo "=== Checking UI health endpoint ==="
fd -t f "route.ts" pmoves/ui/app/api/health/ --exec cat {}

# Check UI Dockerfile for standalone output
echo -e "\n=== Verifying UI Dockerfile configuration ==="
rg -n "standalone|OUTPUT" pmoves/ui/Dockerfile -A 2 -B 2

# Check Next.js config for standalone output
echo -e "\n=== Verifying Next.js config ==="
rg -n "output.*standalone" pmoves/ui/next.config.mjs -A 2 -B 2

Additionally, run make -C pmoves notebook-workbench-smoke ARGS="--thread=<uuid>" to validate the Next.js bundle and connectivity.


884-885: PYTHONPATH configuration for archon-work-orders is correctly set.

The PYTHONPATH=/app/vendor/archon/python environment variable is properly placed in the archon-work-orders service. The Dockerfile confirms the vendor sources are cloned/copied to /app/vendor/archon/python, matching the path in the environment variable. The main archon service omits this setting because it starts via -m services.archon.main (which may handle sys.path internally), while archon-work-orders starts directly with python -m uvicorn, requiring explicit PYTHONPATH for module resolution.

POWERFULMOVES pushed a commit that referenced this pull request Dec 23, 2025
- Normalize Supabase Kong hostnames to lowercase (DNS convention)
- Remove duplicate ARCHON_SUPABASE_BASE_URL env var definition
- Fix notebook-sync Dockerfile: remove USER directive so entrypoint
  can run chown/su as root before dropping privileges
- Improve deepresearch _get_or_create_counter: use module-level cache
  to avoid private prometheus_client API dependency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Codex Agent and others added 5 commits December 22, 2025 23:30
Add Docker deployment for the PMOVES.AI Unified Portal (pmoves/ui):

- **Dockerfile**: Multi-stage build with Node 20, standalone output,
  non-root user (pmoves:65532), and health check
- **docker-compose.yml**: Add pmoves-ui service on port 4482 with
  Flute-Gateway, Agent Zero, Archon, and Hi-RAG environment variables
- **next.config.mjs**: Enable standalone output for minimal production image
- **Health API**: Add /api/health endpoint for container orchestration
- **Flute Client**: Add WebSocket/HTTP client for voice integration

Port allocation:
- 4482: Production pmoves-ui
- 3001: Local dev only (not Docker)

Start with: docker compose --profile ui up -d pmoves-ui
Access at: http://localhost:4482

Resolves: PMOVES.AI Unified Portal deployment gap
Related: docs/Unified and Modular PMOVES UI Design.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Critical fixes:
- Add error logging to isHealthy() catch block (was silent failure)
- Fix WebSocket message type: 'synthesize' → 'text'
- Add error handling to playAudio() with proper cleanup

Improvements:
- Add onReconnectExhausted callback for connection failure notification
- Implement session management using FluteSession interface
- Add createSession() and connectWithSession() methods
- Add @throws JSDoc annotations and browser-only warnings

Session API reference: POST /v1/sessions returns session_id, websocket_url

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Critical:
- archon-agent-work-orders healthcheck: /health → /healthz
  (service exposes /healthz per main.py:248)

Major:
- pmoves-ui NEXT_PUBLIC env vars: use localhost fallback
  (NEXT_PUBLIC vars are build-time embedded for browser use)
- deepresearch Prometheus: add try/except with type validation
  (safer than direct private _names_to_collectors access)

Minor:
- Normalize supabase_kong hostname to lowercase (4 occurrences)
  (Docker DNS is case-sensitive on some configurations)
- vibevoice-realtime: create /models directory with ownership
  (entrypoint.sh writes to /models via snapshot_download)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- NEXT_PUBLIC_SUPABASE_URL: Use localhost:8000 fallback for browser-side
  Supabase access (internal Docker hostnames don't resolve in browser)
- archon-agent-work-orders: Fix healthcheck endpoint /healthz → /health
  (service exposes /health, not /healthz)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 1 - Environment Variables:
- Add 20+ missing NEXT_PUBLIC_* environment variables
- Configure all agent service URLs (Agent Zero, Archon, Hi-RAG)
- Add TensorZero, Open Notebook, monitoring stack URLs
- Add server-side POSTGREST_URL, PRESIGN_SHARED_SECRET
- Fix variable naming: NEXT_PUBLIC_OPEN_NOTEBOOK_API_URL

Phase 2 - Hardcoded URL Fixes:
- monitor/page.tsx: Use NEXT_PUBLIC_GRAFANA/PROMETHEUS/LOKI_URL
- presign.ts: Remove insecure 'change_me' fallback (security fix)
  Now throws actionable error when PRESIGN_SHARED_SECRET missing

Documentation:
- Add learnings for Docker DNS casing, NEXT_PUBLIC patterns
- Add learnings for Dockerfile permissions, Prometheus registry

Fixes: PMOVES UI not connected to backend services
Refs: PR #345

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@POWERFULMOVES
POWERFULMOVES force-pushed the fix/phase2-hardening-fixes branch from 16ece27 to 9fd7a53 Compare December 23, 2025 04:31
@POWERFULMOVES
POWERFULMOVES merged commit b23e37d into main Dec 23, 2025
6 of 7 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pmoves/services/vibevoice-realtime/Dockerfile (1)

1-1: Update PyTorch base image to 2.6.0 or later due to critical RCE vulnerability.

PyTorch version 2.5.1 contains a critical Remote Command Execution (RCE) vulnerability (CVE-2025-32434) affecting the torch.load() function when used with weights_only=True. This flaw has been assigned a critical CVSS v4 score of 9.3 and has been patched in PyTorch version 2.6.0. Multiple newer versions are available: 2.9.1 (Nov 2025), 2.9.0 (Oct 2025), 2.8.0 (Aug 2025), 2.7.1 (Jun 2025), and 2.7.0 (Apr 2025).

Additionally, huggingface_hub 0.27.1 (Dec 16, 2024) is outdated; the latest version is 1.2.3 (released Dec 12, 2025).

🧹 Nitpick comments (7)
.claude/learnings/prometheus-registry-2025.md (2)

23-23: Document the rationale for still using the private API in the exception path.

While the documentation criticizes direct REGISTRY._names_to_collectors access, the recommended pattern still uses it on line 27 within the exception handler: existing = REGISTRY._names_to_collectors.get(name). This appears contradictory. Consider either:

  1. Explicitly documenting that the private API is acceptable in the error path with type validation as a safeguard, or
  2. Exploring if prometheus_client provides a public API for metric lookup by name (e.g., REGISTRY._get_names_to_collectors() or similar).

Also applies to: 27-28


50-52: Add specific code references and link to PR changes.

The "Related" section is vague. Consider adding:

  • Direct links to the prometheus_client documentation sections on REGISTRY and Counter.
  • Specific file and line references to where this pattern is applied (e.g., deepresearch module mentioned in PR #345).
  • Link to python python -m documentation explaining double-import behavior.
pmoves/services/vibevoice-realtime/Dockerfile (1)

21-23: Consider pinning to a specific commit SHA for reproducible builds.

Currently cloning from the main branch allows upstream changes to affect builds unpredictably. For better supply chain security and build reproducibility, consider pinning VIBEVOICE_GIT_REF to a specific commit SHA rather than a branch name.

🔎 Example approach
 ARG VIBEVOICE_GIT_REMOTE=https://github.com/microsoft/VibeVoice.git
-ARG VIBEVOICE_GIT_REF=main
+ARG VIBEVOICE_GIT_REF=<commit-sha>
 RUN git clone --depth 1 --single-branch --branch "${VIBEVOICE_GIT_REF}" "${VIBEVOICE_GIT_REMOTE}" /app/vibevoice
pmoves/ui/Dockerfile (2)

8-9: Unnecessary curl installation in builder stage.

The curl package is installed in the builder stage but is only used for health checks in the runner stage. This adds unnecessary bloat to the builder layer.

🔎 Proposed fix
-# Install curl for health checks
-RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/*
-
 # Install dependencies
 COPY package*.json ./

11-13: Prefer npm ci over npm install for reproducible builds.

Using npm ci ensures deterministic installs from package-lock.json, which is critical for CI/CD reproducibility and security (prevents unexpected dependency updates).

🔎 Proposed fix
 # Install dependencies
 COPY package*.json ./
-RUN npm install
+RUN npm ci
pmoves/ui/lib/fluteClient.ts (2)

288-309: AudioContext resource leak risk on rapid calls.

Each playAudio() call creates a new AudioContext. Browsers limit concurrent AudioContext instances (typically 4-6). Rapid successive calls could exhaust this limit before previous contexts close.

🔎 Proposed fix using shared AudioContext
+// Shared AudioContext for playback (browsers limit concurrent instances)
+let sharedAudioContext: AudioContext | null = null;
+
+function getAudioContext(): AudioContext {
+  if (!sharedAudioContext || sharedAudioContext.state === 'closed') {
+    sharedAudioContext = new AudioContext();
+  }
+  return sharedAudioContext;
+}
+
 export async function playAudio(audioData: ArrayBuffer): Promise<void> {
-  const audioContext = new AudioContext();
+  const audioContext = getAudioContext();
+  
+  // Resume if suspended (autoplay policy)
+  if (audioContext.state === 'suspended') {
+    await audioContext.resume();
+  }
+  
   try {
     const audioBuffer = await audioContext.decodeAudioData(audioData);
     const source = audioContext.createBufferSource();
     source.buffer = audioBuffer;
     source.connect(audioContext.destination);
     source.start(0);
 
     return new Promise((resolve, reject) => {
       source.onended = () => {
-        audioContext.close();
         resolve();
       };
     });
   } catch (error) {
-    await audioContext.close();
     throw error;
   }
 }

297-304: Promise in playAudio never rejects after decoding succeeds.

The Promise created for playback completion only resolves via onended—if playback fails after starting (e.g., context closed externally), the Promise hangs indefinitely. Consider adding a timeout or relying on the outer catch.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 16ece27 and 9fd7a53.

📒 Files selected for processing (12)
  • .claude/learnings/docker-dns-casing-2025.md
  • .claude/learnings/dockerfile-permissions-2025.md
  • .claude/learnings/nextjs-env-vars-2025.md
  • .claude/learnings/prometheus-registry-2025.md
  • pmoves/docker-compose.yml
  • pmoves/services/vibevoice-realtime/Dockerfile
  • pmoves/ui/Dockerfile
  • pmoves/ui/app/api/health/route.ts
  • pmoves/ui/app/dashboard/monitor/page.tsx
  • pmoves/ui/lib/fluteClient.ts
  • pmoves/ui/lib/presign.ts
  • pmoves/ui/next.config.mjs
✅ Files skipped from review due to trivial changes (1)
  • .claude/learnings/dockerfile-permissions-2025.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • .claude/learnings/docker-dns-casing-2025.md
  • pmoves/ui/next.config.mjs
  • pmoves/docker-compose.yml
🧰 Additional context used
📓 Path-based instructions (2)
pmoves/ui/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (pmoves/AGENTS.md)

UI updates: run make -C pmoves notebook-workbench-smoke ARGS="--thread=<uuid>" to lint the Next.js bundle and validate Supabase connectivity; reference pmoves/docs/UI_NOTEBOOK_WORKBENCH.md

Files:

  • pmoves/ui/app/dashboard/monitor/page.tsx
  • pmoves/ui/app/api/health/route.ts
  • pmoves/ui/lib/fluteClient.ts
  • pmoves/ui/lib/presign.ts
.claude/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

Mirror service/endpoint changes in .claude/context/services-catalog.md and add command stubs in .claude/commands/ when relevant

Files:

  • .claude/learnings/nextjs-env-vars-2025.md
  • .claude/learnings/prometheus-registry-2025.md
🧠 Learnings (16)
📓 Common learnings
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/services/{agent-zero,archon}/**/*.py : For Agents/Archon full-stack validation, follow the 'All Services Up, Then Tests' section in `pmoves/docs/SMOKETESTS.md` and use `make -C pmoves agents-headless-smoke`, `make -C pmoves smoke-gpu`, and `make -C pmoves verify-all`
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: UI updates: run make -C pmoves notebook-workbench-smoke ARGS='--thread=<uuid>' to lint the Next.js bundle and validate Supabase connectivity; reference pmoves/docs/UI_NOTEBOOK_WORKBENCH.md
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Mandatory context before changes: read pmoves/docs/PMOVES.AI PLANS/ROADMAP.md and pmoves/docs/NEXT_STEPS.md to align with current sprint focus
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/ui/**/*.{js,jsx,ts,tsx} : UI updates: run `make -C pmoves notebook-workbench-smoke ARGS="--thread=<uuid>"` to lint the Next.js bundle and validate Supabase connectivity; reference `pmoves/docs/UI_NOTEBOOK_WORKBENCH.md`

Applied to files:

  • pmoves/ui/Dockerfile
  • pmoves/ui/app/dashboard/monitor/page.tsx
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: UI updates: run make -C pmoves notebook-workbench-smoke ARGS='--thread=<uuid>' to lint the Next.js bundle and validate Supabase connectivity; reference pmoves/docs/UI_NOTEBOOK_WORKBENCH.md

Applied to files:

  • pmoves/ui/Dockerfile
  • pmoves/ui/app/dashboard/monitor/page.tsx
📚 Learning: 2025-12-15T12:04:26.230Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/AGENTS.md:0-0
Timestamp: 2025-12-15T12:04:26.230Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*.js : Try to find development options to launch apps without Docker. Use automatic installation and launch for the user's platform via scripts instead of Docker

Applied to files:

  • pmoves/ui/Dockerfile
  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Agents images: default uses published images set in `pmoves/env.shared`. For custom code, build a thin overlay FROM the published image and tag it

Applied to files:

  • pmoves/ui/Dockerfile
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Applies to {Dockerfile,docker-compose.yml,docker-compose.*.yml,pmoves/docker-compose.*.override.yml} : Dockerfile and docker-compose.yml must follow multi-arch build practices (amd64+arm64) with Trivy scanning for HIGH/CRITICAL vulnerabilities

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:02:18.878Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/GEMINI.md:0-0
Timestamp: 2025-12-15T12:02:18.878Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*{install,start}.{js,json} : Always use virtual environments for Python apps via shell.run venv attribute in Pinokio launcher scripts

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:01:31.388Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/CLAUDE.md:0-0
Timestamp: 2025-12-15T12:01:31.388Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/{install,start,update,reset}.js : Scripts must be able to replicate install and launch steps 100% - include all 3rd party package installations and repository downloads in scripts, do not assume end user's system state, and make everything self-contained

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:02:18.878Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/GEMINI.md:0-0
Timestamp: 2025-12-15T12:02:18.878Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*{install,start,update,reset}.{js,json} : Scripts must be able to replicate install and launch steps 100% for end users, do not assume system state and make everything self-contained

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:03:41.584Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:41.584Z
Learning: Applies to pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/**/{install,start,update,reset}.js : Always use the `venv` attribute in shell.run API calls for Python projects instead of manually managing virtual environments

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:04:26.230Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/AGENTS.md:0-0
Timestamp: 2025-12-15T12:04:26.230Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/install.js : Install scripts should work for each specific operating system. Ignore Docker related instructions and use platform-specific install/launch instructions instead

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:02:18.878Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/GEMINI.md:0-0
Timestamp: 2025-12-15T12:02:18.878Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/*{install,start,update,reset}.{js,json} : Use Pinokio shell.run API features like env, venv, input, path, sudo, on to reduce script code instead of raw shell commands

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:03:41.584Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:41.584Z
Learning: Applies to pmoves/docs/ARTSTUFF/Ultimate-TTS-Studio.git/**/start.js : Set `daemon: true` at the root level of launcher scripts when launching long-running server processes to prevent process termination after script completion

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:02:50.226Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/docs/ARTSTUFF/realtime/.windsurfrules:0-0
Timestamp: 2025-12-15T12:02:50.226Z
Learning: Applies to pmoves/docs/ARTSTUFF/realtime/**/install.js : Install scripts should avoid modifying the cloned project folder (app directory) and instead create additional files in launcher folder to work around installation issues without touching app logic

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-07T11:03:53.415Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: pmoves/AGENTS.md:0-0
Timestamp: 2025-12-07T11:03:53.415Z
Learning: Applies to pmoves/**/docker-compose.yml : Use Compose profiles (`data`, `workers`) to scope what runs locally in docker-compose.yml

Applied to files:

  • pmoves/services/vibevoice-realtime/Dockerfile
📚 Learning: 2025-12-15T12:03:17.291Z
Learnt from: CR
Repo: POWERFULMOVES/PMOVES.AI PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T12:03:17.291Z
Learning: Applies to .claude/**/*.md : Mirror service/endpoint changes in .claude/context/services-catalog.md and add command stubs in .claude/commands/ when relevant

Applied to files:

  • .claude/learnings/nextjs-env-vars-2025.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (python)
🔇 Additional comments (12)
.claude/learnings/prometheus-registry-2025.md (2)

1-52: Verify alignment with .claude/ guidelines.

Per the coding guidelines, .claude/**/*.md files should mirror service/endpoint changes in .claude/context/services-catalog.md and add command stubs in .claude/commands/ when relevant. This file documents a Prometheus registration pattern related to the deepresearch service mentioned in PR #345. Confirm whether:

  1. .claude/context/services-catalog.md was updated to reflect deepresearch changes.
  2. Command stubs were added to .claude/commands/ for testing or validating the Prometheus pattern (e.g., a smoke test for metric registration).

24-33: The pattern correctly identifies duplicate metrics by checking the actual error message from prometheus_client. This approach is reliable and not brittle—the error message has remained stable across versions and is integral to the library's public behavior.

pmoves/services/vibevoice-realtime/Dockerfile (1)

40-41: LGTM! The /models directory setup correctly addresses the previous review.

The addition of mkdir -p /models and including /models in the ownership change ensures the entrypoint script can write model downloads without permission errors, all while maintaining non-root execution.

pmoves/ui/Dockerfile (1)

26-50: LGTM! Solid security hardening.

Good practices observed:

  • Non-root user with explicit UID/GID (65532)
  • Ownership properly transferred before USER directive
  • Health check with reasonable intervals and start period for Next.js cold start
  • Standalone server deployment pattern is correct
pmoves/ui/app/api/health/route.ts (1)

7-14: LGTM! Clean health endpoint implementation.

The endpoint correctly returns all necessary fields for container orchestration. Minor note: process.env.npm_package_version is only set when running via npm run scripts and won't be available in the standalone server context—the '0.1.0' fallback appropriately handles this.

Based on learnings, consider running make -C pmoves notebook-workbench-smoke ARGS='--thread=<uuid>' to lint the Next.js bundle and validate connectivity.

pmoves/ui/lib/presign.ts (1)

62-77: LGTM! Good security hardening.

The removal of the insecure 'change_me' fallback and addition of actionable error messaging for auth failures is a solid security improvement. The explicit 401/403 handling with configuration guidance will help developers diagnose misconfiguration quickly.

pmoves/ui/app/dashboard/monitor/page.tsx (2)

17-42: LGTM! Proper cleanup pattern for polling.

The active flag prevents state updates after unmount, and clearInterval properly cleans up the timer. The 5-second polling interval is reasonable for a monitoring dashboard.


133-176: Code already uses host-accessible monitoring URLs.

The monitoring service URLs are correctly configured with localhost and published ports (Grafana: 3002, Prometheus: 9090, Loki: 3100), not internal Docker hostnames. Although NEXT_PUBLIC_* variables are inlined at build time and do not respond to changes after build, the current configuration is already appropriate for browser access. No changes needed.

Likely an incorrect or invalid review comment.

pmoves/ui/lib/fluteClient.ts (3)

66-74: LGTM! Clean constructor with environment fallbacks.

Good pattern using optional constructor parameters with env var fallbacks for flexibility between configured deployments and local development.


138-149: LGTM! Health check with proper timeout.

Using AbortSignal.timeout(5000) ensures the health check doesn't hang indefinitely—good defensive coding for service availability checks.


227-244: LGTM! Solid reconnection logic with backoff.

The auto-reconnect implementation correctly:

  • Uses linear backoff (1s × attempt count)
  • Limits retries via maxReconnectAttempts
  • Resets counter on successful connection
  • Notifies via onReconnectExhausted callback
.claude/learnings/nextjs-env-vars-2025.md (1)

1-46: LGTM! Valuable documentation for common Next.js Docker pitfall.

This learning captures a real issue with clear explanation and actionable pattern. The detection command is useful for CI/CD validation.

As per coding guidelines, consider mirroring any new service/endpoint changes in .claude/context/services-catalog.md if the Flute Gateway or other services documented here aren't already catalogued.

Comment on lines +20 to +33
def _get_or_create_counter(name: str, description: str, labelnames: tuple) -> Counter:
"""Get existing counter or create new one (safe for module reimport via -m flag)."""
try:
return Counter(name, description, labelnames=labelnames)
except ValueError as e:
if "Duplicated timeseries" in str(e):
# Metric already exists; retrieve and validate type
existing = REGISTRY._names_to_collectors.get(name)
if existing is not None and isinstance(existing, Counter):
return existing
raise TypeError(
f"Metric '{name}' exists but is {type(existing).__name__}, not Counter"
) from e
raise

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Address labelnames mismatch scenarios.

The function accepts a labelnames tuple but does not validate that an existing metric's labelnames match. If a metric with the same name but different labelnames exists, isinstance(existing, Counter) will pass, but the returned metric may have incompatible labelnames. Consider documenting:

  • Whether prometheus_client raises an error for labelnames mismatches, or
  • Adding explicit labelnames validation when retrieving an existing metric.
🤖 Prompt for AI Agents
In .claude/learnings/prometheus-registry-2025.md around lines 20 to 33, the
helper returns an existing Counter without verifying its labelnames, which can
silently return a metric with incompatible labels; when retrieving the existing
collector, compare the provided labelnames tuple to the collector's labelnames
(e.g., existing._labelnames or existing._labelnames property) and if they differ
raise a clear TypeError indicating the name exists with different labelnames, or
alternatively log the mismatch and re-raise ValueError; also add a short comment
documenting the chosen behavior and why labelname validation is required.

Comment on lines +6 to +9
// Monitoring service URLs (configured via NEXT_PUBLIC_* env vars for client-side access)
const GRAFANA_URL = process.env.NEXT_PUBLIC_GRAFANA_URL || 'http://localhost:3002';
const PROMETHEUS_URL = process.env.NEXT_PUBLIC_PROMETHEUS_URL || 'http://localhost:9090';
const LOKI_URL = process.env.NEXT_PUBLIC_LOKI_URL || 'http://localhost:3100';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add defensive URL parsing to prevent runtime crashes.

new URL() throws on invalid input. If an environment variable contains a malformed URL or is set to an internal Docker hostname that the browser can't parse, the component will crash during render.

🔎 Proposed fix with safe URL helpers
+// Safe URL helpers to prevent runtime crashes from invalid env vars
+function safeGetPort(urlString: string, fallbackPort = '80'): string {
+  try {
+    return new URL(urlString).port || fallbackPort;
+  } catch {
+    return fallbackPort;
+  }
+}
+
 // Monitoring service URLs (configured via NEXT_PUBLIC_* env vars for client-side access)
 const GRAFANA_URL = process.env.NEXT_PUBLIC_GRAFANA_URL || 'http://localhost:3002';
 const PROMETHEUS_URL = process.env.NEXT_PUBLIC_PROMETHEUS_URL || 'http://localhost:9090';
 const LOKI_URL = process.env.NEXT_PUBLIC_LOKI_URL || 'http://localhost:3100';

Then replace inline new URL(...).port || '80' calls with safeGetPort(GRAFANA_URL), etc.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Monitoring service URLs (configured via NEXT_PUBLIC_* env vars for client-side access)
const GRAFANA_URL = process.env.NEXT_PUBLIC_GRAFANA_URL || 'http://localhost:3002';
const PROMETHEUS_URL = process.env.NEXT_PUBLIC_PROMETHEUS_URL || 'http://localhost:9090';
const LOKI_URL = process.env.NEXT_PUBLIC_LOKI_URL || 'http://localhost:3100';
// Safe URL helpers to prevent runtime crashes from invalid env vars
function safeGetPort(urlString: string, fallbackPort = '80'): string {
try {
return new URL(urlString).port || fallbackPort;
} catch {
return fallbackPort;
}
}
// Monitoring service URLs (configured via NEXT_PUBLIC_* env vars for client-side access)
const GRAFANA_URL = process.env.NEXT_PUBLIC_GRAFANA_URL || 'http://localhost:3002';
const PROMETHEUS_URL = process.env.NEXT_PUBLIC_PROMETHEUS_URL || 'http://localhost:9090';
const LOKI_URL = process.env.NEXT_PUBLIC_LOKI_URL || 'http://localhost:3100';
🤖 Prompt for AI Agents
In pmoves/ui/app/dashboard/monitor/page.tsx around lines 6 to 9, the code uses
process.env NEXT_PUBLIC_* URLs directly and callers use new URL(...) which can
throw for malformed or unresolvable values; add a small defensive helper (e.g.,
safeParseUrl(url?: string): URL | null and safeGetPort(url?: string,
defaultPort='80'): string) that catches errors from new URL and returns null or
a default, validate/normalize the env values using that helper at module init,
and replace all inline new URL(...).port or similar calls with
safeGetPort(GRAFANA_URL) / safeGetPort(PROMETHEUS_URL) / safeGetPort(LOKI_URL)
so rendering won’t throw on bad env vars.

POWERFULMOVES added a commit that referenced this pull request Jan 2, 2026
Phase 2 hardening: Docker security, Prometheus patterns, DNS fixes
POWERFULMOVES pushed a commit that referenced this pull request Jan 2, 2026
- Normalize Supabase Kong hostnames to lowercase (DNS convention)
- Remove duplicate ARCHON_SUPABASE_BASE_URL env var definition
- Fix notebook-sync Dockerfile: remove USER directive so entrypoint
  can run chown/su as root before dropping privileges
- Improve deepresearch _get_or_create_counter: use module-level cache
  to avoid private prometheus_client API dependency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
POWERFULMOVES pushed a commit that referenced this pull request Jan 3, 2026
- Normalize Supabase Kong hostnames to lowercase (DNS convention)
- Remove duplicate ARCHON_SUPABASE_BASE_URL env var definition
- Fix notebook-sync Dockerfile: remove USER directive so entrypoint
  can run chown/su as root before dropping privileges
- Improve deepresearch _get_or_create_counter: use module-level cache
  to avoid private prometheus_client API dependency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
POWERFULMOVES added a commit that referenced this pull request Jan 3, 2026
…tion (#443)

* refactor(env): Phase 2 - Migrate API tier to env-tier-api anchor (#350)

Phase 2 of env consolidation: API tier migration

Changes:
- Fix tier anchor syntax (block-style env_file with required: false)
- Migrate postgrest, presign, retrieval-eval to <<: *env-tier-api
- Create env.tier-api.example with secure defaults

API tier services receive data tier URLs and internal credentials only,
no external API keys (OPENAI_API_KEY, etc.)

Services migrated:
- postgrest: PostgREST database gateway
- presign: MinIO URL presigner
- retrieval-eval: Hi-RAG evaluation service

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Codex Agent <codex-agent@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(env): Phase 3 - Migrate LLM tier to env-tier-llm anchor (#351)

Phase 3 of env consolidation: LLM tier migration

Changes:
- Fix tier anchor syntax (block-style env_file with required: false)
- Migrate tensorzero-ui to <<: *env-tier-llm
- Create env.tier-llm.example with all LLM provider API keys

CRITICAL: LLM tier is the ONLY tier with access to external API keys.
All other services call TensorZero internally, not providers directly.

Services in LLM tier:
- tensorzero-gateway: Already using <<: *env-tier-llm
- tensorzero-ui: Migrated from legacy env_file
- tensorzero-clickhouse: Uses inline env (no API keys needed)
- pmoves-ollama: Uses inline env (no API keys needed)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Codex Agent <codex-agent@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(env): Phase 6 - Migrate agent tier + API additions (#354)

Completes the 6-tier environment consolidation by migrating:

**Agent Tier (10 services):**
- mesh-agent, deepresearch, supaserch, consciousness-service
- archon-agent-work-orders, botz-gateway, publisher-discord
- messaging-gateway, jellyfin-bridge, chat-relay

**API Tier Additions (4 services):**
- postgrest-cli, hi-rag-gateway, hi-rag-gateway-gpu, hi-rag-gateway-v2-gpu

**Worker Tier (6 services) - included in this commit:**
- render-webhook, comfy-watcher, pdf-ingest, langextract
- notebook-sync, session-context-worker

**Media Tier (10 services) - included in this commit:**
- ultimate-tts-studio, flute-gateway, ffmpeg-whisper
- media-video, media-audio, channel-monitor
- invidious, invidious-companion, grayjay-plugin-host, grayjay-server

Security improvement: 30 services now use tier-based env_file anchors
instead of legacy x-env-legacy pattern.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Codex Agent <codex-agent@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* fix(security): GPU access + production hardening (health checks, image pins, required password) (#355)

* docs: address PR review comments for env tier consolidation

- Add GPU Orchestrator and E2B Runner to services-catalog.md
- Add gpu-orchestrator to env.tier-api.example service list
- Create learnings file documenting 6-tier env architecture
- Add env.tier-*.example files for worker, media, agent tiers

Addresses nitpick comments from PRs #349-354.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(gpu): ensure GPU access for all CUDA-enabled services

- gpu-orchestrator: Add GPU deploy section + NVIDIA_VISIBLE_DEVICES
- ultimate-tts-studio: Add NVIDIA_VISIBLE_DEVICES env var
- hi-rag-gateway-gpu: Add NVIDIA_VISIBLE_DEVICES env var
- hi-rag-gateway-v2-gpu: Add NVIDIA_VISIBLE_DEVICES env var
- media-audio: Change base image to nvidia/cuda:12.4.1-runtime-ubuntu22.04
  (was python:3.11-slim which caused silent CPU fallback)

This fixes silent CPU fallbacks where PyTorch CUDA packages were installed
but the CUDA runtime was not available in the container.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(security): production hardening - health checks and image pinning

Critical security and reliability fixes:

1. **POSTGRES_PASSWORD now required** - Changed from insecure default
   `:-pmoves` to required syntax `${VAR:?error}`. Compose will fail if
   POSTGRES_PASSWORD is not set (lines 59, 78, 937).

2. **Pinned 8 :latest images to specific versions:**
   - postgrest/postgrest:latest → v12.2.3
   - minio/minio:latest → RELEASE.2024-12-18T13-15-44Z
   - ollama/ollama:latest → 0.5.4
   - tensorzero/gateway:latest → 2024.12.18
   - tensorzero/ui:latest → 2024.12.18
   - invidious:latest → 2024.12.09
   - invidious-companion:latest → 2024.12.20
   - grayjay:latest → 2024.11.01

3. **Added health checks to 37 services** (52 total, up from 15):
   - Data tier: qdrant, meilisearch, minio
   - API tier: hi-rag-*, retrieval-eval, presign, render-webhook
   - Worker tier: extract-worker, pdf-ingest, langextract, notebook-sync,
     ffmpeg-whisper, media-video, media-audio, pmoves-yt, channel-monitor
   - Agent tier: agent-zero, mesh-agent, deepresearch, supaserch
   - TensorZero: gateway, ui, ollama
   - Others: publisher-discord, messaging-gateway, jellyfin-bridge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(health): address PR review critical issues

Fixes critical issues identified by PR review:

MinIO:
- Change health check from `mc ready local` to curl-based
  (minio/minio image doesn't include mc binary)

NATS:
- Add `-m 8222` flag to enable HTTP monitoring port
  (health check was targeting port that wasn't enabled)

Health checks:
- comfy-watcher: verify module imports instead of just `import sys`
- mesh-agent: verify main module and NATS client availability

Missing start_period:
- postgres: add 15s start_period
- chat-relay: add 30s start_period
- n8n-agent: add 30s start_period
- invidious-postgres: add 15s start_period

All 52 health checks now have start_period defined.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Codex Agent <codex-agent@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* security(dockerfile): Harden notebook-sync and vibevoice-realtime

Increase Dockerfile hardening from 33/36 (91.7%) to 35/36 (97.2%):

- notebook-sync: Add USER pmoves (user creation already existed)
- vibevoice-realtime: Add full hardening with UID/GID 65532

Accepted exception: agent-zero uses root for initialization then
drops to pmoves via 'su' for the service process. This pattern is
required by upstream Agent Zero's prepare.py and /ins/copy_A0.sh.

Pattern reference: flute-gateway/Dockerfile

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(infra): Address PR #345 CodeRabbit review comments

- Normalize Supabase Kong hostnames to lowercase (DNS convention)
- Remove duplicate ARCHON_SUPABASE_BASE_URL env var definition
- Fix notebook-sync Dockerfile: remove USER directive so entrypoint
  can run chown/su as root before dropping privileges
- Improve deepresearch _get_or_create_counter: use module-level cache
  to avoid private prometheus_client API dependency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(infra): Archon Supabase connectivity and UI dashboard fixes

Changes:
- Archon health check: Add Kong gateway hostname support for internal
  Docker networking (supabase_kong_pmoves.ai:8000)
- UI dashboard: Add /dashboard redirect page to /dashboard/services
- Grafana: Fix env var placeholders and job name mismatches in queries
- Docs: Add placeholder for Jellyfin service documentation

The Archon health check now properly handles both:
- Supabase CLI endpoint (host.docker.internal:65421)
- Internal Kong gateway (supabase_kong_pmoves.ai:8000)

This resolves the 404 errors in Archon health checks when using
internal Docker DNS names instead of host.docker.internal.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(gitignore): Exclude agent-zero runtime data directory

Add pmoves/data/agent-zero/ to gitignore. This directory contains
runtime settings (settings.json) that persist via Docker volume mount.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(deepresearch): Prometheus counter double-registration

Use registry lookup pattern instead of try/except for counter
registration. Prevents 'Duplicated timeseries' error when container
restarts with existing registry state.

Before: try/except around Counter() creation
After: REGISTRY._names_to_collectors.get() for existing lookup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(flute-gateway): add logging to silent exception handlers (#323)

- Add warning log to Supabase health check exception handler
- Improve persona fetch error logging with status code and truncated body
- Add metrics tracking for non-200 persona fetch responses

Closes #322

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Codex Agent <codex-agent@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* docs: add comprehensive service documentation (#338)

Merged after rebase to resolve Jellyfin README conflict

* fix(compose): Agent Zero settings persistence and Archon hostname

- Add volume mount ./data/agent-zero/tmp:/a0/tmp for settings.json
  Root cause: PMOVES-Agent-Zero/python/helpers/settings.py:162 stores
  settings at /a0/tmp/settings.json but path was not mounted

- Normalize Archon SUPABASE_URL to lowercase supabase_kong_pmoves.ai
  Root cause: Docker DNS is case-sensitive on some configurations

- Fix archon-agent-work-orders health check: /healthz → /health
  Root cause: Service exposes /health, not /healthz

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Codex Agent <codex-agent@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
POWERFULMOVES added a commit that referenced this pull request Jan 18, 2026
…tion (#443)

* refactor(env): Phase 2 - Migrate API tier to env-tier-api anchor (#350)

Phase 2 of env consolidation: API tier migration

Changes:
- Fix tier anchor syntax (block-style env_file with required: false)
- Migrate postgrest, presign, retrieval-eval to <<: *env-tier-api
- Create env.tier-api.example with secure defaults

API tier services receive data tier URLs and internal credentials only,
no external API keys (OPENAI_API_KEY, etc.)

Services migrated:
- postgrest: PostgREST database gateway
- presign: MinIO URL presigner
- retrieval-eval: Hi-RAG evaluation service

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Codex Agent <codex-agent@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(env): Phase 3 - Migrate LLM tier to env-tier-llm anchor (#351)

Phase 3 of env consolidation: LLM tier migration

Changes:
- Fix tier anchor syntax (block-style env_file with required: false)
- Migrate tensorzero-ui to <<: *env-tier-llm
- Create env.tier-llm.example with all LLM provider API keys

CRITICAL: LLM tier is the ONLY tier with access to external API keys.
All other services call TensorZero internally, not providers directly.

Services in LLM tier:
- tensorzero-gateway: Already using <<: *env-tier-llm
- tensorzero-ui: Migrated from legacy env_file
- tensorzero-clickhouse: Uses inline env (no API keys needed)
- pmoves-ollama: Uses inline env (no API keys needed)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Codex Agent <codex-agent@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(env): Phase 6 - Migrate agent tier + API additions (#354)

Completes the 6-tier environment consolidation by migrating:

**Agent Tier (10 services):**
- mesh-agent, deepresearch, supaserch, consciousness-service
- archon-agent-work-orders, botz-gateway, publisher-discord
- messaging-gateway, jellyfin-bridge, chat-relay

**API Tier Additions (4 services):**
- postgrest-cli, hi-rag-gateway, hi-rag-gateway-gpu, hi-rag-gateway-v2-gpu

**Worker Tier (6 services) - included in this commit:**
- render-webhook, comfy-watcher, pdf-ingest, langextract
- notebook-sync, session-context-worker

**Media Tier (10 services) - included in this commit:**
- ultimate-tts-studio, flute-gateway, ffmpeg-whisper
- media-video, media-audio, channel-monitor
- invidious, invidious-companion, grayjay-plugin-host, grayjay-server

Security improvement: 30 services now use tier-based env_file anchors
instead of legacy x-env-legacy pattern.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Codex Agent <codex-agent@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* fix(security): GPU access + production hardening (health checks, image pins, required password) (#355)

* docs: address PR review comments for env tier consolidation

- Add GPU Orchestrator and E2B Runner to services-catalog.md
- Add gpu-orchestrator to env.tier-api.example service list
- Create learnings file documenting 6-tier env architecture
- Add env.tier-*.example files for worker, media, agent tiers

Addresses nitpick comments from PRs #349-354.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(gpu): ensure GPU access for all CUDA-enabled services

- gpu-orchestrator: Add GPU deploy section + NVIDIA_VISIBLE_DEVICES
- ultimate-tts-studio: Add NVIDIA_VISIBLE_DEVICES env var
- hi-rag-gateway-gpu: Add NVIDIA_VISIBLE_DEVICES env var
- hi-rag-gateway-v2-gpu: Add NVIDIA_VISIBLE_DEVICES env var
- media-audio: Change base image to nvidia/cuda:12.4.1-runtime-ubuntu22.04
  (was python:3.11-slim which caused silent CPU fallback)

This fixes silent CPU fallbacks where PyTorch CUDA packages were installed
but the CUDA runtime was not available in the container.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(security): production hardening - health checks and image pinning

Critical security and reliability fixes:

1. **POSTGRES_PASSWORD now required** - Changed from insecure default
   `:-pmoves` to required syntax `${VAR:?error}`. Compose will fail if
   POSTGRES_PASSWORD is not set (lines 59, 78, 937).

2. **Pinned 8 :latest images to specific versions:**
   - postgrest/postgrest:latest → v12.2.3
   - minio/minio:latest → RELEASE.2024-12-18T13-15-44Z
   - ollama/ollama:latest → 0.5.4
   - tensorzero/gateway:latest → 2024.12.18
   - tensorzero/ui:latest → 2024.12.18
   - invidious:latest → 2024.12.09
   - invidious-companion:latest → 2024.12.20
   - grayjay:latest → 2024.11.01

3. **Added health checks to 37 services** (52 total, up from 15):
   - Data tier: qdrant, meilisearch, minio
   - API tier: hi-rag-*, retrieval-eval, presign, render-webhook
   - Worker tier: extract-worker, pdf-ingest, langextract, notebook-sync,
     ffmpeg-whisper, media-video, media-audio, pmoves-yt, channel-monitor
   - Agent tier: agent-zero, mesh-agent, deepresearch, supaserch
   - TensorZero: gateway, ui, ollama
   - Others: publisher-discord, messaging-gateway, jellyfin-bridge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(health): address PR review critical issues

Fixes critical issues identified by PR review:

MinIO:
- Change health check from `mc ready local` to curl-based
  (minio/minio image doesn't include mc binary)

NATS:
- Add `-m 8222` flag to enable HTTP monitoring port
  (health check was targeting port that wasn't enabled)

Health checks:
- comfy-watcher: verify module imports instead of just `import sys`
- mesh-agent: verify main module and NATS client availability

Missing start_period:
- postgres: add 15s start_period
- chat-relay: add 30s start_period
- n8n-agent: add 30s start_period
- invidious-postgres: add 15s start_period

All 52 health checks now have start_period defined.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Codex Agent <codex-agent@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* security(dockerfile): Harden notebook-sync and vibevoice-realtime

Increase Dockerfile hardening from 33/36 (91.7%) to 35/36 (97.2%):

- notebook-sync: Add USER pmoves (user creation already existed)
- vibevoice-realtime: Add full hardening with UID/GID 65532

Accepted exception: agent-zero uses root for initialization then
drops to pmoves via 'su' for the service process. This pattern is
required by upstream Agent Zero's prepare.py and /ins/copy_A0.sh.

Pattern reference: flute-gateway/Dockerfile

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(infra): Address PR #345 CodeRabbit review comments

- Normalize Supabase Kong hostnames to lowercase (DNS convention)
- Remove duplicate ARCHON_SUPABASE_BASE_URL env var definition
- Fix notebook-sync Dockerfile: remove USER directive so entrypoint
  can run chown/su as root before dropping privileges
- Improve deepresearch _get_or_create_counter: use module-level cache
  to avoid private prometheus_client API dependency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(infra): Archon Supabase connectivity and UI dashboard fixes

Changes:
- Archon health check: Add Kong gateway hostname support for internal
  Docker networking (supabase_kong_pmoves.ai:8000)
- UI dashboard: Add /dashboard redirect page to /dashboard/services
- Grafana: Fix env var placeholders and job name mismatches in queries
- Docs: Add placeholder for Jellyfin service documentation

The Archon health check now properly handles both:
- Supabase CLI endpoint (host.docker.internal:65421)
- Internal Kong gateway (supabase_kong_pmoves.ai:8000)

This resolves the 404 errors in Archon health checks when using
internal Docker DNS names instead of host.docker.internal.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(gitignore): Exclude agent-zero runtime data directory

Add pmoves/data/agent-zero/ to gitignore. This directory contains
runtime settings (settings.json) that persist via Docker volume mount.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(deepresearch): Prometheus counter double-registration

Use registry lookup pattern instead of try/except for counter
registration. Prevents 'Duplicated timeseries' error when container
restarts with existing registry state.

Before: try/except around Counter() creation
After: REGISTRY._names_to_collectors.get() for existing lookup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(flute-gateway): add logging to silent exception handlers (#323)

- Add warning log to Supabase health check exception handler
- Improve persona fetch error logging with status code and truncated body
- Add metrics tracking for non-200 persona fetch responses

Closes #322

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Codex Agent <codex-agent@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* docs: add comprehensive service documentation (#338)

Merged after rebase to resolve Jellyfin README conflict

* fix(compose): Agent Zero settings persistence and Archon hostname

- Add volume mount ./data/agent-zero/tmp:/a0/tmp for settings.json
  Root cause: PMOVES-Agent-Zero/python/helpers/settings.py:162 stores
  settings at /a0/tmp/settings.json but path was not mounted

- Normalize Archon SUPABASE_URL to lowercase supabase_kong_pmoves.ai
  Root cause: Docker DNS is case-sensitive on some configurations

- Fix archon-agent-work-orders health check: /healthz → /health
  Root cause: Service exposes /health, not /healthz

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Codex Agent <codex-agent@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
POWERFULMOVES pushed a commit that referenced this pull request Jan 18, 2026
- Normalize Supabase Kong hostnames to lowercase (DNS convention)
- Remove duplicate ARCHON_SUPABASE_BASE_URL env var definition
- Fix notebook-sync Dockerfile: remove USER directive so entrypoint
  can run chown/su as root before dropping privileges
- Improve deepresearch _get_or_create_counter: use module-level cache
  to avoid private prometheus_client API dependency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
POWERFULMOVES added a commit that referenced this pull request Jan 18, 2026
Phase 2 hardening: Docker security, Prometheus patterns, DNS fixes
POWERFULMOVES added a commit that referenced this pull request Jan 18, 2026
Phase 2 hardening: Docker security, Prometheus patterns, DNS fixes
POWERFULMOVES pushed a commit that referenced this pull request Jan 18, 2026
- Normalize Supabase Kong hostnames to lowercase (DNS convention)
- Remove duplicate ARCHON_SUPABASE_BASE_URL env var definition
- Fix notebook-sync Dockerfile: remove USER directive so entrypoint
  can run chown/su as root before dropping privileges
- Improve deepresearch _get_or_create_counter: use module-level cache
  to avoid private prometheus_client API dependency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant