Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,13 @@ PMOVES.AI is a **production-ready multi-agent orchestration platform** featuring
- Auth: `nats://nats:pmoves@nats:4222` (always use authenticated URL)
- **Critical subjects:** See `.claude/context/nats-subjects.md`

**Supabase** [PostgREST Port 3010]
- Postgres with pgvector extension
**Supabase** [Kong Port 8000, PostgREST Port 3000, Studio Port 54323]
- Unified 13-service self-hosted stack (profile: `supabase-local`)
- Services: DB (Postgres 17.6.1), GoTrue, PostgREST v14.3, Kong 3.7.1, Realtime v2.72.0, Storage v1.37.1, Studio, imgproxy, pg-meta, Edge Functions, Analytics (Logflare), Vector, Supavisor
- Canonical consumer URL: `http://supabase-kong:8000/rest/v1` (via Kong gateway)
- Standard variable names: `JWT_SECRET`, `ANON_KEY`, `SERVICE_ROLE_KEY` (SUPABASE_* aliases for compat)
- Schema: `pmoves_core`, Archon prompts
- **Use for:** Metadata storage, content records, agent state
- **Use for:** Metadata storage, content records, agent state, auth, connection pooling

**Qdrant** [Port 6333]
- Vector embeddings for semantic search
Expand Down
47 changes: 47 additions & 0 deletions .claude/commands/tac/review.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# TAC Tree Review

Run a TAC (Task-Action-Context) tree audit for an integration submodule.

## Usage
Accepts a submodule name or tree path as argument:
- `/tac:review health-wger` — Review health integration
- `/tac:review firefly-iii` — Review wealth integration
- `/tac:review n8n` — Review n8n workflows
- `/tac:review pmoves/configs/tac_trees/custom.tac.yaml` — Custom tree

## Instructions

1. Resolve the argument to a TAC tree path:
- If arg matches a known name (`health-wger`, `firefly-iii`, `n8n`), map to `pmoves/configs/tac_trees/<name>.tac.yaml`
- If arg is a file path, use directly
- If no arg provided, list available trees in `pmoves/configs/tac_trees/`

2. Run the TAC runner in text mode:
```bash
python pmoves/tools/tac_runner.py --format text <tree-path>
```

3. Also run in JSON mode for structured analysis:
```bash
python pmoves/tools/tac_runner.py <tree-path>
```

4. Present results to the user with:
- Overall pass/fail summary
- Each failing node with its `agent_hint` (who should fix it)
- Suggested next actions for each failure
- If all pass, confirm the integration is audit-clean

5. For failing nodes, offer to fix them:
- `file_exists` failures → offer to create the missing file
- `grep` failures → offer to add the missing content
- `manual` items → flag for user review

## Agent Assignment Hints
Each TAC node includes an `agent_hint` field suggesting which agent should handle the fix:
- `codex` — Claude Code CLI (documentation, config, scripts)
- `archon` — Archon agent (Supabase, prompts)
- `tokenism` — CHIT encoding
- `n8n` — n8n workflow creation

$ARGUMENTS
2 changes: 1 addition & 1 deletion PMOVES-Wealth
2 changes: 1 addition & 1 deletion Pmoves-Health-wger
52 changes: 24 additions & 28 deletions pmoves/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ supa-start: check-tools ensure-env-shared ## Start Supabase stack for selected r
-e KONG_PG_USER=$${SUPABASE_DB_USER:-postgres} \
-e KONG_PG_PASSWORD=$${SUPABASE_DB_PASSWORD:-postgres} \
kong:3.7.1 kong migrations bootstrap --yes >/dev/null 2>&1 || true; \
$(DC) up -d supabase-postgrest supabase-gotrue supabase-kong supabase-realtime supabase-storage supabase-studio; \
$(DC) up -d supabase-postgrest supabase-gotrue supabase-kong supabase-realtime supabase-storage supabase-studio supabase-imgproxy supabase-meta supabase-edge-functions supabase-analytics supabase-vector supabase-pooler; \
fi
@$(MAKE) --no-print-directory supa-status
@$(MAKE) --no-print-directory supa-collation-refresh 2>/dev/null || true
Expand All @@ -321,14 +321,14 @@ supa-stop: ## Stop Supabase stack for selected runtime
@if [ "$(SUPABASE_RUNTIME)" = "cli" ]; then \
supabase stop --workdir "." >/dev/null 2>&1 || true; \
else \
$(DC) stop supabase-db supabase-postgrest supabase-gotrue supabase-kong supabase-realtime supabase-storage supabase-studio >/dev/null 2>&1 || true; \
$(DC) stop supabase-db supabase-postgrest supabase-gotrue supabase-kong supabase-realtime supabase-storage supabase-studio supabase-imgproxy supabase-meta supabase-edge-functions supabase-analytics supabase-vector supabase-pooler >/dev/null 2>&1 || true; \
fi
@echo "✅ Supabase stopped"

supa-stop-all: ## Stop both Supabase runtimes (CLI and compose) to clear mixed-state drift
@echo "🛑 Stopping all Supabase runtimes..."
@supabase stop --workdir "." >/dev/null 2>&1 || true
@$(DC) stop supabase-db supabase-postgrest supabase-gotrue supabase-kong supabase-realtime supabase-storage supabase-studio >/dev/null 2>&1 || true
@$(DC) stop supabase-db supabase-postgrest supabase-gotrue supabase-kong supabase-realtime supabase-storage supabase-studio supabase-imgproxy supabase-meta supabase-edge-functions supabase-analytics supabase-vector supabase-pooler >/dev/null 2>&1 || true
@echo "✅ All Supabase runtimes stopped"

supa-restart: ## Restart Supabase stack for selected runtime
Expand Down Expand Up @@ -384,7 +384,7 @@ supa-status: ## Show Supabase status for selected runtime and export env snapsho
echo " Auth: $$auth_url"; \
echo " Studio: $$studio_url"; \
else \
$(DC) ps supabase-db supabase-postgrest supabase-gotrue supabase-kong supabase-realtime supabase-storage supabase-studio 2>/dev/null || true; \
$(DC) ps supabase-db supabase-postgrest supabase-gotrue supabase-kong supabase-realtime supabase-storage supabase-studio supabase-imgproxy supabase-meta supabase-edge-functions supabase-analytics supabase-vector supabase-pooler 2>/dev/null || true; \
echo ""; \
echo "Expected local endpoints:"; \
echo " PostgREST: http://localhost:$${SUPABASE_POSTGREST_PORT:-3000}"; \
Expand Down Expand Up @@ -412,7 +412,7 @@ supa-logs: ## Tail logs for selected runtime (set SVC=<container/service> for a
docker logs --tail=80 "$$c" || true; \
done; \
else \
$(DC) logs --tail=120 supabase-db supabase-postgrest supabase-gotrue supabase-kong supabase-realtime supabase-storage supabase-studio || true; \
$(DC) logs --tail=120 supabase-db supabase-postgrest supabase-gotrue supabase-kong supabase-realtime supabase-storage supabase-studio supabase-imgproxy supabase-meta supabase-edge-functions supabase-analytics supabase-vector supabase-pooler || true; \
fi

supa-health: ## Health checks for selected runtime + active DB container readiness
Expand Down Expand Up @@ -630,21 +630,15 @@ else
endif
@$(MAKE) --no-print-directory auth-check

supabase-up: ## Compose fallback only: start gotrue/realtime/storage/studio sidecars
@if [ "$(SUPABASE_RUNTIME)" != "compose" ] && [ "$(SUPA_PROVIDER)" != "compose" ]; then \
echo "↷ SUPABASE_RUNTIME=$(SUPABASE_RUNTIME) (compose fallback skipped)"; \
exit 0; \
fi
@$(DC) -f docker-compose.supabase.yml up -d gotrue realtime storage studio
@echo "✅ Compose Supabase sidecars started (fallback mode)"
supabase-up: ## Alias for up-supabase (shim removed — all services in main compose)
@$(MAKE) --no-print-directory up-supabase

supabase-stop: ## Compose fallback only: stop gotrue/realtime/storage/studio sidecars
@$(DC) -f docker-compose.supabase.yml stop gotrue realtime storage studio >/dev/null 2>&1 || true
@echo "✅ Compose Supabase sidecars stopped"
supabase-stop: ## Alias for supa-stop (shim removed — all services in main compose)
@$(MAKE) --no-print-directory supa-stop

supabase-clean: ## Compose fallback only: remove gotrue/realtime/storage/studio containers + volumes
@$(DC) -f docker-compose.supabase.yml down -v --remove-orphans >/dev/null 2>&1 || true
@echo "✅ Compose Supabase sidecars cleaned"
supabase-clean: ## Stop + remove Supabase containers and volumes
@$(DC) --profile supabase-local down -v --remove-orphans >/dev/null 2>&1 || true
@echo "✅ Supabase stack cleaned"
Comment on lines +639 to +641

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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, find the definition of $(DC) in the Makefile
rg "^\s*DC\s*:=" pmoves/Makefile

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 167


🏁 Script executed:

# Look at the docker-compose configuration to understand profiles
fd "docker-compose" pmoves/

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2625


🏁 Script executed:

# Search for compose files in the repository
fd -e yml -e yaml | grep -i compose

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2938


🏁 Script executed:

# Look for services in compose files and their profile definitions
rg "services:|profile:" pmoves/docker-compose.yml -A 2 -B 2 | head -100

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 724


🏁 Script executed:

# Search for Supabase-related services and profile definitions
rg "supabase-local" pmoves/

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2546


🏁 Script executed:

# Get a general overview of the main docker-compose.yml file
wc -l pmoves/docker-compose.yml && head -50 pmoves/docker-compose.yml

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2281


🏁 Script executed:

# Extract all service definitions and check which ones have profiles
python3 << 'EOF'
import yaml
import sys

with open('pmoves/docker-compose.yml', 'r') as f:
    content = yaml.safe_load(f)

services = content.get('services', {})
unprofiled_services = []
supabase_services = []

for service_name, service_def in services.items():
    profiles = service_def.get('profiles', [])
    if not profiles:
        unprofiled_services.append(service_name)
    elif 'supabase-local' in profiles:
        supabase_services.append(service_name)

print(f"Services with NO profile attribute ({len(unprofiled_services)}):")
for svc in sorted(unprofiled_services)[:20]:
    print(f"  - {svc}")

if len(unprofiled_services) > 20:
    print(f"  ... and {len(unprofiled_services) - 20} more")

print(f"\nServices in 'supabase-local' profile ({len(supabase_services)}):")
for svc in sorted(supabase_services):
    print(f"  - {svc}")
EOF

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 740


🏁 Script executed:

# Verify Docker Compose profile behavior by checking documentation/examples
# Let's also check if there's any STACK_FILES variable that might add extra services
rg "STACK_FILES" pmoves/Makefile -B 2 -A 2

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 808


🏁 Script executed:

# Check the full STACK_FILES definition in the Makefile
grep -A 30 "STACK_FILES \?=" pmoves/Makefile

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 49


🌐 Web query:

Docker Compose profile behavior default services no profile

💡 Result:

  • Services with no profiles: key are “default” services: if you run docker compose up without --profile (and without COMPOSE_PROFILES), Compose includes all services that have no profiles and excludes services that do declare profiles. [1][2]
  • Activating profiles doesn’t disable defaults: when you run docker compose --profile <name> up, Compose starts the default (no-profile) services plus the services in the enabled profile(s). [1][2]
  • Explicitly targeting a profiled service overrides profile activation: docker compose up myprofiledservice runs that service even if you didn’t enable its profile (Compose treats the service’s profile as active for that run). [1][2]
  • Dependencies matter: if an enabled service has depends_on a service that’s excluded by an inactive profile, the resulting model can be invalid (i.e., you must enable whatever profiles are needed to satisfy depends_on, or restructure). [2]

Sources: Docker Compose profiles docs. [1][2]


🏁 Script executed:

# Verify STACK_FILES more carefully
cat pmoves/Makefile | grep -A 40 "STACK_FILES"

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2095


supabase-clean tears down the entire stack, not just Supabase.

Services with no profile (qdrant, neo4j, meilisearch, nats, minio, hi-rag-gateway, tensorzero-gateway, and others) are default services that are always included when docker compose down runs. The --profile supabase-local flag activates the Supabase profile but does not exclude default services—it activates the profile in addition to running all unprofiled services. Therefore, $(DC) --profile supabase-local down -v --remove-orphans will stop and remove both the 13 Supabase services and the 19 core infrastructure services.

Use a separate compose file or an explicit service list instead of relying on the profile to isolate the target.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/Makefile` around lines 639 - 641, The supabase-clean Makefile target
currently uses $(DC) --profile supabase-local down which also brings down
unprofiled default services; change it to target only Supabase by either
invoking compose with a Supabase-only file (e.g., use $(DC) -f
docker-compose.supabase.yml down -v --remove-orphans) or explicitly stop/remove
only the Supabase service names (use $(DC) stop <supabase-service-list> && $(DC)
rm -f <supabase-service-list>) instead of relying on --profile; update the
supabase-clean recipe (the target name supabase-clean and the $(DC) invocation)
to use one of these approaches so only Supabase containers/volumes are removed.


.PHONY: neo4j-bootstrap
neo4j-bootstrap: ## Seed Neo4j with persona aliases + CHIT geometry fixtures
Expand Down Expand Up @@ -1041,7 +1035,7 @@ down-supabase: ## Stop Supabase
@if [ "$(SUPABASE_RUNTIME)" = "cli" ]; then \
supabase stop --workdir "$(CURDIR)" >/dev/null 2>&1 || true; \
else \
$(DC) stop supabase-db supabase-postgrest supabase-gotrue supabase-kong supabase-realtime supabase-storage supabase-studio >/dev/null 2>&1 || true; \
$(DC) stop supabase-db supabase-postgrest supabase-gotrue supabase-kong supabase-realtime supabase-storage supabase-studio supabase-imgproxy supabase-meta supabase-edge-functions supabase-analytics supabase-vector supabase-pooler >/dev/null 2>&1 || true; \
fi

# =============================================================================
Expand Down Expand Up @@ -1316,15 +1310,17 @@ populate-tier-envs: bootstrap-tier-envs ## Populate tier env files with defaults
echo "✓ Populated env.tier-data"; \
fi; \
if [ -f "env.tier-supabase" ]; then \
sed -i "s|^SUPABASE_JWT_SECRET=.*|SUPABASE_JWT_SECRET=$${SUPABASE_JWT_SECRET:-$(shell openssl rand -base64 32)}|" env.tier-supabase; \
sed -i "s|^SUPABASE_ANON_KEY=.*|SUPABASE_ANON_KEY=$${SUPABASE_ANON_KEY:-$(shell openssl rand -base64 32)}|" env.tier-supabase; \
sed -i "s|^SUPABASE_SERVICE_ROLE_KEY=.*|SUPABASE_SERVICE_ROLE_KEY=$${SUPABASE_SERVICE_ROLE_KEY:-$(shell openssl rand -base64 32)}|" env.tier-supabase; \
sed -i "s|^SUPABASE_PUBLISHABLE_KEY=.*|SUPABASE_PUBLISHABLE_KEY=$${SUPABASE_PUBLISHABLE_KEY:-$(shell openssl rand -base64 32)}|" env.tier-supabase; \
sed -i "s|^SUPABASE_SECRET_KEY=.*|SUPABASE_SECRET_KEY=$${SUPABASE_SECRET_KEY:-$(shell openssl rand -base64 32)}|" env.tier-supabase; \
sed -i "s|^SUPABASE_REALTIME_SECRET=.*|SUPABASE_REALTIME_SECRET=$${SUPABASE_REALTIME_SECRET:-$(shell openssl rand -base64 32)}|" env.tier-supabase; \
sed -i "s|^SUPABASE_DB_PASSWORD=.*|SUPABASE_DB_PASSWORD=$${SUPABASE_DB_PASSWORD:-$(shell openssl rand -base64 24)}|" env.tier-supabase; \
sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$${POSTGRES_PASSWORD:-$(shell openssl rand -base64 24)}|" env.tier-supabase; \
echo "✓ Populated env.tier-supabase"; \
if grep -q "your_jwt_secret_here\|your_anon_key_here\|your_service_role_key_here" env.tier-supabase 2>/dev/null; then \
echo "Generating Supabase secrets with proper JWT tokens..."; \
if [ -x scripts/supabase/generate-keys.sh ]; then \
scripts/supabase/generate-keys.sh > env.tier-supabase; \
echo "✓ Populated env.tier-supabase (via generate-keys.sh with valid JWTs)"; \
else \
echo "⚠ scripts/supabase/generate-keys.sh not found — run 'make supa-init' to generate proper JWT keys"; \
fi; \
else \
echo "✓ env.tier-supabase already has real values, skipping"; \
fi; \
Comment on lines +1313 to +1323

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 | 🟠 Major

The Supabase placeholder probe won't repair upgraded env files.

This branch only looks for the old JWT/anon/service placeholders. An existing env.tier-supabase can pass that test while still missing new required keys like SECRET_KEY_BASE, VAULT_ENC_KEY, or PG_META_CRYPTO_KEY, so supa-start will still fail after populate-tier-envs says everything is fine.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/Makefile` around lines 1313 - 1323, The current Makefile check only
looks for legacy placeholders in env.tier-supabase and will skip regeneration
even when new required secrets are missing; update the populate logic that
checks env.tier-supabase to verify presence (and non-empty values) of the new
required keys SECRET_KEY_BASE, VAULT_ENC_KEY, and PG_META_CRYPTO_KEY in addition
to the old placeholders, and if any are absent or empty invoke
scripts/supabase/generate-keys.sh to regenerate/populate env.tier-supabase
(keeping the existing messaging flow and fallback that suggests running 'make
supa-init' if generate-keys.sh is missing).

fi; \
if [ -f "env.tier-api" ]; then \
sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$${POSTGRES_PASSWORD:-$(shell openssl rand -base64 24)}|" env.tier-api; \
Expand Down
10 changes: 5 additions & 5 deletions pmoves/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ This aggregates the entire onboarding sequence: env bootstrap, Supabase CLI brin
- Install the `supabase` CLI and run `make supa-init` once per repo.
- Start/stop with `make supa-start` / `make supa-stop`, inspect endpoints with `make supa-status`, then `make supa-use-local` to copy the CLI defaults into `.env.local` before starting the stack.
- Deep dive: `docs/SUPABASE_FULL.md` (CLI bootstrap) and `docs/SUPABASE_SWITCH.md` (switching between CLI vs. remote).
- **Compose-backed Supabase (lightweight alt.)**
- Run `make up-compose` to boot the core stack with compose Postgres/PostgREST enabled, then `make supabase-up` to add GoTrue/Realtime/Storage/Studio from `docker-compose.supabase.yml`.
- Stop the Supabase sidecars with `make supabase-stop` (or `make down` for everything) and clear data with `make supabase-clean`.
- **Compose-backed Supabase (unified stack)**
- All 13 Supabase services are in the main `docker-compose.yml` under the `supabase-local` profile.
- Run `make up-supabase` to start all services, `make supa-stop` to stop, `make supabase-clean` to remove containers + volumes.
- **Remote/self-hosted Supabase**
- Populate `.env.supa.remote` with your endpoints/keys (generate from `supa.md` via `make supa-extract-remote` if provided).
- Apply the remote profile with `make supa-use-remote` before running the main stack.
Expand Down Expand Up @@ -122,8 +122,8 @@ Agents Profile
- Wger and Firefly are started with PMOVES‑branded defaults driven by `WGER_BRAND_*` and related envs in `pmoves/env.shared`; the full set of seeded values is listed in `pmoves/docs/FIRST_RUN.md` under “Seeded & Branded Defaults”.
- Open Notebook’s branded login is configured via `OPEN_NOTEBOOK_PASSWORD`; keep `OPEN_NOTEBOOK_API_TOKEN` in lockstep so agents and CLI helpers reuse the same secret (see `pmoves/docs/services/open-notebook/README.md`).

Supabase (Full)
- Recommended: Supabase CLI (see `docs/SUPABASE_FULL.md`). Or use `docker-compose.supabase.yml` with `./scripts/pmoves.ps1 up-fullsupabase`.
Supabase (Full — 13 services)
- All services in main `docker-compose.yml` under `supabase-local` profile. Use `make up-supabase` or `./scripts/pmoves.ps1 up-fullsupabase`.
- Realtime demo: `http://localhost:8090/static/realtime.html` (subscribe to `studio_board`, `it_errors`; upload avatar and assign to a row).

## Codex VM Bootstrap
Expand Down
Loading
Loading