Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
56 changes: 51 additions & 5 deletions pmoves/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -1413,11 +1413,26 @@ up-legacy-both: ## Ensure v1 hi-rag gateway CPU+GPU are up
# always operate on the same stack regardless of cwd/path.
PROJECT ?= pmoves
export PROJECT
N8N_SUBMODULE_DIR ?= ../PMOVES-n8n
N8N_CANONICAL_FLOWS_DIR ?= $(N8N_SUBMODULE_DIR)/workflows

# n8n persistence mode:
# - sqlite: simplest local bring-up (default)
# - postgres: production-grade n8n DB (recommended for VPS)
N8N_DB ?= sqlite
# - postgres: production-grade n8n DB (default)
# - sqlite: legacy/local escape hatch only
N8N_DB ?= postgres
N8N_DB_NAME ?= n8n
N8N_DB_USER ?= n8n
N8N_DB_PASSWORD ?= pmoves_n8n_local
N8N_DB_SCHEMA ?= public
N8N_BASE_URL ?= http://localhost:5678
N8N_API_URL ?= $(N8N_BASE_URL)/api/v1
N8N_OWNER_EMAIL ?= $(if $(PMOVES_OPERATOR_EMAIL),$(PMOVES_OPERATOR_EMAIL),$(SUPABASE_BOOT_USER_EMAIL))
N8N_OWNER_FIRST_NAME ?= PMOVES
N8N_OWNER_LAST_NAME ?= Operator
N8N_API_KEY_LABEL ?= PMOVES.AI automation bootstrap
N8N_ENV_WRITE_FILE ?= .env.local
export N8N_DB N8N_DB_NAME N8N_DB_USER N8N_DB_PASSWORD N8N_DB_SCHEMA
export N8N_BASE_URL N8N_API_URL N8N_OWNER_EMAIL N8N_OWNER_FIRST_NAME N8N_OWNER_LAST_NAME N8N_API_KEY_LABEL
ifeq ($(N8N_DB),postgres)
N8N_DB_STACK_FILE := -f docker-compose.n8n.postgres.yml
else
Expand Down Expand Up @@ -2344,8 +2359,13 @@ up-agents-integrations: ## Start agents using your forks (builds from $(INTEGRAT
@$(DC) -f docker-compose.agents.integrations.yml --profile agents up -d nats agent-zero archon archon-ui mesh-agent publisher-discord
@echo "✔ Agents started from integrations workspace. Workspace: $(INTEGRATIONS_WORKSPACE)"

.PHONY: up-n8n
up-n8n: ensure-env-shared
.PHONY: up-n8n n8n-sync-submodule-flows n8n-api-bootstrap n8n-import-flows n8n-activate-flows n8n-sync-supabase-registry n8n-bootstrap n8n-export-repo-flows
n8n-sync-submodule-flows: ## Mirror canonical PMOVES-n8n workflows into pmoves/n8n/flows
@$(PYTHON) -c "from pathlib import Path; import shutil; src=Path(r'$(N8N_CANONICAL_FLOWS_DIR)'); dst=Path(r'$(CURDIR)/n8n/flows'); dst.mkdir(parents=True, exist_ok=True); [shutil.copy2(path, dst / path.name) for path in sorted(src.glob('*.json'))]"
@echo "✔ Mirrored PMOVES-n8n workflows into pmoves/n8n/flows"
Comment on lines +2363 to +2365

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

Make the mirror target actually sync, not just copy.

This target never removes JSON files deleted from PMOVES-n8n/workflows, so pmoves/n8n/flows can keep serving stale workflows after the canonical catalog drops them. It also prints success even when the source directory is missing, which makes drift hard to spot.

Suggested fix
 n8n-sync-submodule-flows: ## Mirror canonical PMOVES-n8n workflows into pmoves/n8n/flows
-	@$(PYTHON) -c "from pathlib import Path; import shutil; src=Path(r'$(N8N_CANONICAL_FLOWS_DIR)'); dst=Path(r'$(CURDIR)/n8n/flows'); dst.mkdir(parents=True, exist_ok=True); [shutil.copy2(path, dst / path.name) for path in sorted(src.glob('*.json'))]"
+	@$(PYTHON) - <<'PY'
+from pathlib import Path
+import shutil
+import sys
+
+src = Path(r'$(N8N_CANONICAL_FLOWS_DIR)')
+dst = Path(r'$(CURDIR)/n8n/flows')
+
+if not src.is_dir():
+    sys.exit(f"Missing canonical workflow directory: {src}")
+
+dst.mkdir(parents=True, exist_ok=True)
+for existing in dst.glob('*.json'):
+    existing.unlink()
+for path in sorted(src.glob('*.json')):
+    shutil.copy2(path, dst / path.name)
+PY
 	`@echo` "✔ Mirrored PMOVES-n8n workflows into pmoves/n8n/flows"
📝 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
n8n-sync-submodule-flows: ## Mirror canonical PMOVES-n8n workflows into pmoves/n8n/flows
@$(PYTHON) -c "from pathlib import Path; import shutil; src=Path(r'$(N8N_CANONICAL_FLOWS_DIR)'); dst=Path(r'$(CURDIR)/n8n/flows'); dst.mkdir(parents=True, exist_ok=True); [shutil.copy2(path, dst / path.name) for path in sorted(src.glob('*.json'))]"
@echo "✔ Mirrored PMOVES-n8n workflows into pmoves/n8n/flows"
n8n-sync-submodule-flows: ## Mirror canonical PMOVES-n8n workflows into pmoves/n8n/flows
@$(PYTHON) - <<'PY'
from pathlib import Path
import shutil
import sys
src = Path(r'$(N8N_CANONICAL_FLOWS_DIR)')
dst = Path(r'$(CURDIR)/n8n/flows')
if not src.is_dir():
sys.exit(f"Missing canonical workflow directory: {src}")
dst.mkdir(parents=True, exist_ok=True)
for existing in dst.glob('*.json'):
existing.unlink()
for path in sorted(src.glob('*.json')):
shutil.copy2(path, dst / path.name)
PY
`@echo` "✔ Mirrored PMOVES-n8n workflows into pmoves/n8n/flows"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/Makefile` around lines 2363 - 2365, Update the
n8n-sync-submodule-flows Make target so it performs a true sync instead of a
blind copy: in the Python snippet used by the target (referencing
N8N_CANONICAL_FLOWS_DIR and dst=Path(r'$(CURDIR)/n8n/flows')), first verify the
source directory exists and exit non‑zero with a clear error if missing, then
copy over all *.json files and remove any JSON files in dst that are not present
in the source (i.e., compute the set difference and unlink extras); keep
directory creation (dst.mkdir(...)) and print success only on a successful sync.


up-n8n: ensure-env-shared n8n-sync-submodule-flows
@docker network create cataclysm-net >/dev/null 2>&1 || true
@if [ "$(N8N_DB)" = "postgres" ]; then \
echo "→ n8n DB mode: postgres"; \
$(N8N_DC) up -d n8n-db n8n n8n-runners; \
Expand All @@ -2359,6 +2379,32 @@ down-n8n: ## Stop n8n workflow services
@$(N8N_DC) stop n8n n8n-runners n8n-db >/dev/null 2>&1 || true
@$(N8N_DC) rm -f n8n n8n-runners n8n-db >/dev/null 2>&1 || true

n8n-api-bootstrap: ## Create/login the n8n owner and mint a fresh Public API key into the local env file
@$(LOAD_ENV_SHARED); $(PYTHON) "$(N8N_SUBMODULE_DIR)/scripts/bootstrap_n8n_api.py" \
--base-url "$(N8N_BASE_URL)" \
--api-url "$(N8N_API_URL)" \
--email "$(N8N_OWNER_EMAIL)" \
--first-name "$(N8N_OWNER_FIRST_NAME)" \
--last-name "$(N8N_OWNER_LAST_NAME)" \
--label "$(N8N_API_KEY_LABEL)" \
--write-env "$(N8N_ENV_WRITE_FILE)"

n8n-import-flows: ## Import canonical PMOVES-n8n workflows into the live n8n instance
@$(LOAD_ENV_SHARED); $(PYTHON) "$(N8N_SUBMODULE_DIR)/scripts/import_repo_flows.py" --container pmoves-n8n --workflow-dir "$(N8N_CANONICAL_FLOWS_DIR)" --skip-activation

n8n-activate-flows: ## Publish canonical PMOVES-n8n workflows (keeps chat-platform voice flows inactive unless VOICE_PLATFORMS=1)
@$(LOAD_ENV_SHARED); $(PYTHON) "$(N8N_SUBMODULE_DIR)/scripts/import_repo_flows.py" --container pmoves-n8n --workflow-dir "$(N8N_CANONICAL_FLOWS_DIR)" --activate-only $(if $(VOICE_PLATFORMS),--voice-platforms,)
Comment on lines +2395 to +2396

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

VOICE_PLATFORMS=0 still enables voice-platform activation.

$(if $(VOICE_PLATFORMS),...) treats any non-empty value as truthy, so a caller passing VOICE_PLATFORMS=0 still emits --voice-platforms. That contradicts the documented opt-in behavior.

Suggested fix
 n8n-activate-flows: ## Publish canonical PMOVES-n8n workflows (keeps chat-platform voice flows inactive unless VOICE_PLATFORMS=1)
-	@$(LOAD_ENV_SHARED); $(PYTHON) "$(N8N_SUBMODULE_DIR)/scripts/import_repo_flows.py" --container pmoves-n8n --workflow-dir "$(N8N_CANONICAL_FLOWS_DIR)" --activate-only $(if $(VOICE_PLATFORMS),--voice-platforms,)
+	@$(LOAD_ENV_SHARED); $(PYTHON) "$(N8N_SUBMODULE_DIR)/scripts/import_repo_flows.py" --container pmoves-n8n --workflow-dir "$(N8N_CANONICAL_FLOWS_DIR)" --activate-only $(if $(filter 1 true yes,$(VOICE_PLATFORMS)),--voice-platforms,)
📝 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
n8n-activate-flows: ## Publish canonical PMOVES-n8n workflows (keeps chat-platform voice flows inactive unless VOICE_PLATFORMS=1)
@$(LOAD_ENV_SHARED); $(PYTHON) "$(N8N_SUBMODULE_DIR)/scripts/import_repo_flows.py" --container pmoves-n8n --workflow-dir "$(N8N_CANONICAL_FLOWS_DIR)" --activate-only $(if $(VOICE_PLATFORMS),--voice-platforms,)
n8n-activate-flows: ## Publish canonical PMOVES-n8n workflows (keeps chat-platform voice flows inactive unless VOICE_PLATFORMS=1)
@$(LOAD_ENV_SHARED); $(PYTHON) "$(N8N_SUBMODULE_DIR)/scripts/import_repo_flows.py" --container pmoves-n8n --workflow-dir "$(N8N_CANONICAL_FLOWS_DIR)" --activate-only $(if $(filter 1 true yes,$(VOICE_PLATFORMS)),--voice-platforms,)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/Makefile` around lines 2395 - 2396, The Makefile target
n8n-activate-flows incorrectly treats any non-empty VOICE_PLATFORMS as truthy
because it uses $(if $(VOICE_PLATFORMS),--voice-platforms,), so passing
VOICE_PLATFORMS=0 still emits --voice-platforms; change the conditional to only
emit --voice-platforms when VOICE_PLATFORMS is explicitly 1 (e.g., use a value
check such as $(if $(filter 1,$(VOICE_PLATFORMS)),--voice-platforms,) or
equivalent) so that VOICE_PLATFORMS=0 does not enable voice-platform activation.


n8n-sync-supabase-registry: ## Upsert live n8n workflow state into pmoves_core.n8n_workflow_registry
@$(LOAD_ENV_SHARED); $(PYTHON) "$(N8N_SUBMODULE_DIR)/scripts/sync_supabase_registry.py" --workflow-dir "$(N8N_CANONICAL_FLOWS_DIR)"

n8n-bootstrap: up-n8n n8n-api-bootstrap n8n-import-flows n8n-activate-flows n8n-sync-supabase-registry ## Bring up n8n, bootstrap API access, import workflows, publish defaults, and sync Supabase tracking
@echo "✔ n8n bootstrap complete"
Comment on lines +2398 to +2402

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

n8n-bootstrap is missing the registry migration prerequisite.

The final step calls sync_supabase_registry.py, but the table it writes to is created in supabase/migrations/20260312130000_n8n_workflow_registry.sql. On a fresh environment, make -C pmoves n8n-bootstrap can therefore fail on the last step unless supabase-bootstrap already happened elsewhere.

Suggested fix
-n8n-bootstrap: up-n8n n8n-api-bootstrap n8n-import-flows n8n-activate-flows n8n-sync-supabase-registry ## Bring up n8n, bootstrap API access, import workflows, publish defaults, and sync Supabase tracking
+n8n-bootstrap: supabase-bootstrap up-n8n n8n-api-bootstrap n8n-import-flows n8n-activate-flows n8n-sync-supabase-registry ## Bring up n8n, bootstrap API access, import workflows, publish defaults, and sync Supabase tracking
 	`@echo` "✔ n8n bootstrap complete"
📝 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
n8n-sync-supabase-registry: ## Upsert live n8n workflow state into pmoves_core.n8n_workflow_registry
@$(LOAD_ENV_SHARED); $(PYTHON) "$(N8N_SUBMODULE_DIR)/scripts/sync_supabase_registry.py" --workflow-dir "$(N8N_CANONICAL_FLOWS_DIR)"
n8n-bootstrap: up-n8n n8n-api-bootstrap n8n-import-flows n8n-activate-flows n8n-sync-supabase-registry ## Bring up n8n, bootstrap API access, import workflows, publish defaults, and sync Supabase tracking
@echo "✔ n8n bootstrap complete"
n8n-sync-supabase-registry: ## Upsert live n8n workflow state into pmoves_core.n8n_workflow_registry
@$(LOAD_ENV_SHARED); $(PYTHON) "$(N8N_SUBMODULE_DIR)/scripts/sync_supabase_registry.py" --workflow-dir "$(N8N_CANONICAL_FLOWS_DIR)"
n8n-bootstrap: supabase-bootstrap up-n8n n8n-api-bootstrap n8n-import-flows n8n-activate-flows n8n-sync-supabase-registry ## Bring up n8n, bootstrap API access, import workflows, publish defaults, and sync Supabase tracking
`@echo` "✔ n8n bootstrap complete"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/Makefile` around lines 2398 - 2402, The n8n-bootstrap target can fail
because n8n-sync-supabase-registry writes to a table created by the migration
supabase/migrations/20260312130000_n8n_workflow_registry.sql; update the
Makefile so the registry migration runs before syncing by adding
supabase-bootstrap as a prerequisite (either add supabase-bootstrap to the
n8n-bootstrap prerequisite list or make n8n-sync-supabase-registry depend on
supabase-bootstrap) so the migration exists before sync_supabase_registry.py
runs.


n8n-export-repo-flows: ## Export live n8n workflows into PMOVES-n8n and refresh the compatibility mirror
@$(PYTHON) "$(N8N_SUBMODULE_DIR)/scripts/export_repo_flows.py" --container pmoves-n8n --workflow-dir "$(N8N_CANONICAL_FLOWS_DIR)"
@$(MAKE) n8n-sync-submodule-flows

.PHONY: up-comfyui comfyui-smoke
up-comfyui: ## Start ComfyUI (docker profile; used by n8n pmoves_comfy_gen flow)
@$(DC) --profile creator up -d comfyui
Expand Down
5 changes: 3 additions & 2 deletions pmoves/compose/docker-compose.core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ version: "3.9"
services:
n8n:
build:
context: ..
context: ../../PMOVES-n8n
dockerfile: compose/n8n/Dockerfile
image: pmoves/n8n:1.115.3-sqlite
restart: unless-stopped
Expand Down Expand Up @@ -42,8 +42,9 @@ services:
- "host.docker.internal:host-gateway"
volumes:
- n8n-data:/home/node/.n8n
- ../../PMOVES-n8n/workflows:/flows:ro
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://localhost:5678/rest/healthz').then(r=>r.ok?process.exit(0):process.exit(1)).catch(()=>process.exit(1))"]
test: ["CMD", "node", "-e", "fetch('http://localhost:5678/healthz').then(r=>r.ok?process.exit(0):process.exit(1)).catch(()=>process.exit(1))"]
interval: 10s
timeout: 5s
retries: 12
Expand Down
3 changes: 1 addition & 2 deletions pmoves/docker-compose.n8n.postgres.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ services:
- POSTGRES_PASSWORD=${N8N_DB_PASSWORD:?set N8N_DB_PASSWORD}
volumes:
- n8n-db-data:/var/lib/postgresql/data
networks: [cataclysm, api_tier]
networks: [cataclysm]
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 5s
Expand All @@ -32,4 +32,3 @@ services:

volumes:
n8n-db-data: {}

9 changes: 6 additions & 3 deletions pmoves/docker-compose.n8n.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ x-env-tier-worker: &env-tier-worker
services:
n8n:
build:
context: .
context: ../PMOVES-n8n
dockerfile: compose/n8n/Dockerfile
image: pmoves/n8n:2.1.0-sqlite
image: pmoves/n8n:2.1.0-runtime
container_name: pmoves-n8n
restart: unless-stopped
<<: *env-tier-worker
environment:
- N8N_PORT=5678
- N8N_PROTOCOL=http
- N8N_HOST=localhost
- N8N_SECURE_COOKIE=false
- N8N_DEFAULT_TIMEZONE=${TZ:-America/New_York}
- WEBHOOK_URL=http://localhost:5678
- GENERIC_TIMEZONE=${TZ:-America/New_York}
Expand Down Expand Up @@ -45,11 +46,12 @@ services:
- N8N_LOG_LEVEL=debug
- N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
ports: ["5678:5678"]
networks: [cataclysm]
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- n8n-data:/home/node/.n8n
- ./n8n/flows:/flows:ro
- ../PMOVES-n8n/workflows:/flows:ro
n8n-runners:
image: n8nio/runners:2.1.0
container_name: pmoves-n8n-runners
Expand All @@ -61,6 +63,7 @@ services:
- N8N_RUNNERS_AUTO_SHUTDOWN_TIMEOUT=300
depends_on:
- n8n
networks: [cataclysm]
volumes:
- n8n-data:/home/node/.n8n
volumes:
Expand Down
8 changes: 8 additions & 0 deletions pmoves/docs/NEXT_STEPS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ _Last updated: 2026-03-12_
- Added `pmoves/docs/PMOVES.AI PLANS/CREATOR_NETWORK_CONTROL_PLANE.md` to frame YouTube, Discord agents, transcribe-and-fetch, model routing, and Tokenism as one creator-network lane.
- Next focus: finish review cleanup, get PMOVES.YT/root checks green, and keep the creator/channel-monitor runbooks aligned with the authoritative runtime instead of the compatibility mirror.

### Latest changes (Mar 12, 2026) — n8n Production Control Plane Refresh

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

Fix the heading level jump.

This starts at ### even though the document has not introduced a ## section yet, which is why markdownlint is flagging MD001.

🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 6-6: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)

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

In `@pmoves/docs/NEXT_STEPS.md` at line 6, The heading "### Latest changes (Mar
12, 2026) — n8n Production Control Plane Refresh" jumps from no prior H2 and
triggers markdownlint MD001; change this heading to a level-2 header (replace
the leading "###" with "##") or insert an appropriate H2 section before it so
the document has a proper hierarchical order; target the exact heading text
"Latest changes (Mar 12, 2026) — n8n Production Control Plane Refresh" when
making the edit.

- `PMOVES-n8n` is now the authoritative n8n runtime/workflow lane; root `pmoves` consumes it instead of treating `pmoves/n8n/flows` as canon.
- n8n defaults to the dedicated `n8n-db` Postgres sidecar (`make -C pmoves up-n8n`), with SQLite reduced to a legacy escape hatch only.
- Added `make -C pmoves n8n-api-bootstrap` to automate owner bootstrap + Public API key rotation for n8n 2.1.
- Workflow activation/import now targets the n8n Public API path, replacing the failing CLI publish/unpublish fallback for the production lane.
- Added Supabase tracking schema `pmoves_core.n8n_workflow_registry` plus `make -C pmoves n8n-sync-supabase-registry` so PMOVES can inventory live workflow state.
- Next focus: validate the full bootstrap against Postgres-backed n8n, refresh PMOVES.YT from demo to production against the same automation lane, and decide which BotZ/MCP workflows join the shared canonical catalog.

### Latest changes (Mar 8, 2026) — CI Runner Migration + RG-3 Automation
- **AB-9 mitigation:** Migrated 10 lightweight CI jobs from `[self-hosted, Linux, X64]` to `ubuntu-latest`:
- `sql-policy-lint`, `python-tests`, `webhook-smoke`, `yt-dlp-bump`, `deploy-gateway-agent` (validate only)
Expand Down
13 changes: 13 additions & 0 deletions pmoves/docs/PMOVES.AI PLANS/MAKE_TARGETS.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,19 @@ Set `EXTERNAL_NEO4J|MEILI|QDRANT|SUPABASE=true` in `.env.local` to skip local in
- `make up-nats`
- Starts the NATS broker (`agents` profile) and rewrites `.env.local` so `YT_NATS_ENABLE=true` with `NATS_URL=nats://nats:pmoves@nats:4222`.
- Use this before opting into the agents profile (Agent Zero, Archon, mesh-agent, Discord publisher).
- `make up-n8n`
- Starts the production/default n8n stack: `n8n`, `n8n-runners`, and the dedicated `n8n-db` Postgres sidecar.
- Canonical workflows come from `PMOVES-n8n/workflows`; `pmoves/n8n/flows` is only a compatibility mirror.
- `make n8n-api-bootstrap`
- Creates or logs into the n8n owner account, rotates the bootstrap Public API key, validates it, and writes `N8N_API_KEY` plus owner credentials into `pmoves/.env.local`.
- `make n8n-import-flows`
- Upserts the canonical `PMOVES-n8n` workflow catalog into the live n8n instance.
- `make n8n-activate-flows`
- Activates the default workflow set through the n8n Public API; keeps chat-platform voice flows inactive unless `VOICE_PLATFORMS=1`.
- `make n8n-sync-supabase-registry`
- Mirrors live workflow state into `pmoves_core.n8n_workflow_registry` so PMOVES can track n8n activity in Supabase.
- `make n8n-bootstrap`
- Full production bootstrap: `up-n8n -> n8n-api-bootstrap -> n8n-import-flows -> n8n-activate-flows -> n8n-sync-supabase-registry`.
- `make mindmap-notebook-sync`
- Runs `python pmoves/scripts/mindmap_to_notebook.py` to pull `/mindmap/{constellation_id}` entries out of `hi-rag-gateway-v2` and mirror them into Open Notebook via `/api/sources/json`. Requires `MINDMAP_BASE`, `MINDMAP_CONSTELLATION_ID`, `MINDMAP_NOTEBOOK_ID`, and `OPEN_NOTEBOOK_API_TOKEN`.
- `make hirag-notebook-sync`
Expand Down
56 changes: 35 additions & 21 deletions pmoves/docs/PMOVES.AI PLANS/N8N_SETUP.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# n8n Setup Checklist (Supabase → Agent Zero → Discord)
_Last updated: 2025-12-14_
_Last updated: 2026-03-12_

## Overview
This guide streamlines importing and running the PMOVES approval and publish workflows in n8n. It targets Supabase CLI on the host, Agent Zero + NATS in Docker, and Discord webhooks.
This guide covers the production n8n path for PMOVES.AI. `PMOVES-n8n` is the authoritative runtime/workflow fork, n8n internals live on the dedicated `n8n-db` Postgres sidecar, and Supabase tracks PMOVES workflow state in `pmoves_core.n8n_workflow_registry`.

## Preflight (quick)
- Start stacks: `make up && make up-agents && make up-n8n`
Expand All @@ -14,8 +14,8 @@ This guide streamlines importing and running the PMOVES approval and publish wor
- Supabase CLI running locally: `supabase start` or `make supa-start`
- PMOVES stack up: `make up && make up-agents`
- n8n running:
- Local/dev (SQLite): `make up-n8n` (UI at `http://localhost:5678`, launches `n8n` + `n8n-runners`)
- VPS/prod (Postgres): `N8N_DB=postgres make up-n8n` (adds `n8n-db` Postgres for durable state)
- Production/default: `make -C pmoves up-n8n` (starts `n8n`, `n8n-runners`, and `n8n-db`)
- Legacy escape hatch only: `N8N_DB=sqlite make -C pmoves up-n8n`
- Secrets at hand: `SUPABASE_SERVICE_ROLE_KEY`, `DISCORD_WEBHOOK_URL`, `N8N_RUNNERS_AUTH_TOKEN`

## Environment (n8n)
Expand All @@ -28,40 +28,50 @@ Set these in n8n (Settings → Variables) or via container env:
- `DISCORD_WEBHOOK_USERNAME` = `PMOVES Publisher`
- `N8N_RUNNERS_AUTH_TOKEN` = `<shared secret – must match the sidecar>`
- `N8N_DEFAULT_TIMEZONE` = `America/New_York` (aligns cron schedules with project TZ)
- `N8N_DB_NAME` / `N8N_DB_USER` / `N8N_DB_PASSWORD` = dedicated `n8n-db` credentials
- `N8N_OWNER_EMAIL` / `N8N_OWNER_PASSWORD` = owner bootstrap credentials used by `make -C pmoves n8n-api-bootstrap`
- `N8N_API_KEY` = Public API key minted by `make -C pmoves n8n-api-bootstrap`
Comment on lines +31 to +33

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

These bootstrap variables are documented in the wrong place.

N8N_OWNER_* and N8N_API_KEY are consumed by the host-side Make/Python bootstrap flow, not by n8n runtime variables. Telling operators to set them in n8n Settings → Variables means make -C pmoves n8n-api-bootstrap still will not see them.

As per coding guidelines, "Check docs for operational accuracy: Keep status claims aligned with evidence in runbooks and smokes."

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

In `@pmoves/docs/PMOVES.AI` PLANS/N8N_SETUP.md around lines 31 - 33, The
documented bootstrap variables are placed under n8n runtime variables but
N8N_OWNER_EMAIL / N8N_OWNER_PASSWORD and N8N_API_KEY are consumed by the
host-side bootstrap flow (invoked by make -C pmoves n8n-api-bootstrap) not by
n8n runtime; update the N8N_SETUP.md content to (a) remove or relocate
N8N_OWNER_* and N8N_API_KEY from the "n8n Settings → Variables"/runtime section,
(b) add a clear bootstrap section stating that N8N_OWNER_EMAIL /
N8N_OWNER_PASSWORD and N8N_API_KEY must be provided to the host bootstrap (e.g.,
environment or Make/Python bootstrap config) and not entered into n8n variables,
and (c) keep N8N_DB_NAME / N8N_DB_USER / N8N_DB_PASSWORD labelled as dedicated
n8n-db runtime credentials so operators know which variables are for runtime vs
bootstrap.


### n8n persistence mode (SQLite vs Postgres)
By default, `make up-n8n` runs n8n with SQLite for quick local bring-up.
By default, `make -C pmoves up-n8n` runs n8n on the dedicated Postgres sidecar.

For VPS/production, run n8n on Postgres:
- Set `N8N_DB=postgres`
- Set `N8N_DB_NAME`, `N8N_DB_USER`, `N8N_DB_PASSWORD` (in `pmoves/env.shared` or injected secrets)
- Bring up: `N8N_DB=postgres make -C pmoves up-n8n`
For production, keep n8n on Postgres:
- `N8N_DB=postgres`
- `N8N_DB_NAME`, `N8N_DB_USER`, `N8N_DB_PASSWORD`
- `make -C pmoves up-n8n`

This uses `pmoves/docker-compose.n8n.postgres.yml` to add a dedicated `n8n-db` container. It does **not** move your PMOVES app data into n8n — it only stores n8n’s own workflow/execution state in Postgres.

Supabase remains the PMOVES system of record for workflow tracking, approvals, publishing, and operator UI state.

> **Supabase runtime note:** The CLI runtime binds REST on port `65421` per `supabase/config.toml`. If you switch back to the docker-compose PostgREST service, update `SUPABASE_REST_URL` accordingly (typically `http://host.docker.internal:54321/rest/v1`).

Tip: These defaults are prewired in `docker-compose.n8n.yml`. If you use `make up-n8n`, populate `SUPABASE_SERVICE_ROLE_KEY`, `DISCORD_WEBHOOK_URL`, and `N8N_RUNNERS_AUTH_TOKEN` in `pmoves/env.shared` or `pmoves/.env.local`. The runner token is loaded via `env_file` (not compose-time interpolation) so recreating containers won’t accidentally desync the broker and sidecar.

Note: n8n 1.115.3 already executes cron triggers in the main process. Avoid re-adding the deprecated `EXECUTIONS_PROCESS` flag—the service emits a warning and ignores it.

## Production Bootstrap
- `make -C pmoves up-n8n`
- `make -C pmoves n8n-api-bootstrap`
- `make -C pmoves n8n-import-flows`
- `make -C pmoves n8n-activate-flows`
- `make -C pmoves n8n-sync-supabase-registry`
- `make -C pmoves n8n-bootstrap`
Comment on lines +53 to +59

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

Don’t tell operators to run the umbrella bootstrap after every substep.

n8n-bootstrap already expands to up-n8n -> n8n-api-bootstrap -> n8n-import-flows -> n8n-activate-flows -> n8n-sync-supabase-registry, so listing it after those same commands reads like a sixth required step and can rotate the bootstrap API key twice.

As per coding guidelines, "Check docs for operational accuracy: Keep status claims aligned with evidence in runbooks and smokes."

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

In `@pmoves/docs/PMOVES.AI` PLANS/N8N_SETUP.md around lines 53 - 59, The docs list
the individual targets (up-n8n, n8n-api-bootstrap, n8n-import-flows,
n8n-activate-flows, n8n-sync-supabase-registry) and then repeat the umbrella
target n8n-bootstrap, which is misleading and can cause the bootstrap API key to
be rotated twice; update the section so it either removes the final `make -C
pmoves n8n-bootstrap` line or replaces it with a single clarifying sentence that
`n8n-bootstrap` is an umbrella target that runs `up-n8n -> n8n-api-bootstrap ->
n8n-import-flows -> n8n-activate-flows -> n8n-sync-supabase-registry` (so
operators should run either the individual steps or the `n8n-bootstrap` target,
not both).


`n8n-api-bootstrap` creates or logs into the n8n owner account, rotates the `PMOVES.AI automation bootstrap` Public API key, validates it against `/api/v1/workflows`, and writes the resulting `N8N_API_KEY` plus owner credentials into `pmoves/.env.local`.

## Container Tooling
- The custom image defined in `compose/n8n/Dockerfile` bakes in the `sqlite3` CLI so DB inspections persist across restarts.
- Run `make up-n8n` after pulling updates to rebuild the service when the Dockerfile changes.

## Import Workflows
1. Open n8n → Workflows → Import from File.
2. Import the core approvals stack:
- `pmoves/n8n/flows/approval_poller.json`
- `pmoves/n8n/flows/echo_publisher.json`
3. Import the creative webhooks (requires ComfyUI hosts prepared via [`pmoves/creator/README.md`](../creator/README.md)):
- `pmoves/n8n/flows/wan_to_cgp.webhook.json`
- `pmoves/n8n/flows/qwen_to_cgp.webhook.json`
- `pmoves/n8n/flows/vibevoice_to_cgp.webhook.json`
4. (Optional) Import the audio enrichment flows:
- `pmoves/n8n/flows/vibevoice_audio_ingest.json`
- `pmoves/n8n/flows/vibevoice_discord_preview.json`
5. Keep everything inactive until env is confirmed (Supabase keys, MinIO buckets, Discord webhooks).
Canonical workflow JSON now lives in `PMOVES-n8n/workflows/`.

- Recommended: `make -C pmoves n8n-import-flows`
- Activation: `make -C pmoves n8n-activate-flows`
- Full bootstrap: `make -C pmoves n8n-bootstrap`

The root `pmoves/n8n/flows/` directory is now only a compatibility mirror.

## Validate Env Bindings
- Approval Poller
Expand All @@ -85,6 +95,8 @@ Note: n8n 1.115.3 already executes cron triggers in the main process. Avoid re-a
5. Activate echo publisher → confirm Discord embed (title/link/thumbnail if provided)
6. Optional: Post directly to n8n webhook (flow must be active)
- `make n8n-webhook-demo`
7. Sync the live workflow registry back into Supabase:
- `make -C pmoves n8n-sync-supabase-registry`

### Voice platform flows (Discord/Telegram)
The repo includes optional chat-platform voice agent flows (Discord/Telegram) that require additional credentials and/or custom n8n nodes.
Expand Down Expand Up @@ -126,6 +138,8 @@ These flows extend the core approval automations so we can surface RVC voice out

## Troubleshooting
- 404 from Supabase in n8n: ensure `/rest/v1` is included in `SUPABASE_REST_URL`.
- `401` from `/api/v1/workflows`: run `make -C pmoves n8n-api-bootstrap` to rotate the Public API key.
- Workflow import works but activation fails: use the Public API path (`n8n-api-bootstrap` + `n8n-activate-flows`) instead of the legacy CLI publish fallback.
- 503 from Agent Zero: confirm NATS + Agent Zero are running (`make up-agents`).
- Discord no messages: verify `DISCORD_WEBHOOK_URL` and check rate limits in n8n logs.
- n8n cannot reach host services on Linux: replace `host.docker.internal` with the host IP or Docker gateway (`172.17.0.1`).
Expand Down
6 changes: 6 additions & 0 deletions pmoves/docs/PMOVES.AI PLANS/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ A production-ready, self-hostable orchestration mesh for creative + agent worklo
- the Supabase docs sync contract was refreshed for the current CLI stack: `pmoves_core.tool_docs` writes now use schema-profile headers plus URL-encoded `on_conflict`.
- root `pmoves/services/pmoves-yt` remains as a compatibility shim so existing tests/import paths keep working while production moves to the submodule.
- downloader defaults are being normalized around the authoritative runtime: PMOVES.YT now documents the modern client/token path, root compose passes explicit companion wiring, and Jellyfin/channel-monitor docs are being moved off older MCP and future-work framing.
- March 12 n8n production-path remediation landed locally:
- `PMOVES-n8n` is now the authoritative runtime/workflow lane consumed by the root repo.
- `make -C pmoves up-n8n` now defaults to the dedicated `n8n-db` Postgres sidecar instead of SQLite.
- n8n owner/bootstrap automation is scripted (`n8n-api-bootstrap`) so Public API keys no longer depend on manual UI steps.
- workflow activation now targets the n8n 2.1 Public API (`/api/v1/workflows/{id}/activate|deactivate`) instead of the brittle CLI publish fallback.
- Supabase tracking contract added: `pmoves_core.n8n_workflow_registry` stores live workflow state synced from n8n.
Comment on lines +15 to +20

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

The section date is now misleading.

These bullets sit under ## Audit Snapshot (2026-03-07), but they describe the March 12 update. Either retitle the section or split out a new dated heading so the audit timeline stays trustworthy.

As per coding guidelines, "Check docs for operational accuracy: Keep status claims aligned with evidence in runbooks and smokes."

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

In `@pmoves/docs/PMOVES.AI` PLANS/ROADMAP.md around lines 9 - 14, The bullets
describing the March 12 changes are under the header "## Audit Snapshot
(2026-03-07)" which makes the timeline misleading; either add a new dated
heading (e.g., "March 12, 2026") above those bullets or move/retitle them so
they no longer sit under "## Audit Snapshot (2026-03-07)". Specifically update
the section containing the lines referencing `PMOVES-n8n`, `make -C pmoves
up-n8n`, `n8n-api-bootstrap`, `/api/v1/workflows/{id}/activate|deactivate`, and
`pmoves_core.n8n_workflow_registry` to appear under the correct date heading or
split them into a new dated subsection to keep the audit timeline accurate.

- March 7 merge wave completed on `main`: `#814`, `#815`, `#816`, `#817`, `#818`, `#819`, `#820`, `#821` (8 PRs, 3 batches).
- Chrome extension security hardening landed in `#821`: 9 CodeRabbit review items addressed (auth storage isolation, XSS remediation, mock server hardening, timeout guards, state management fixes, CSP).
- Distributed topology documentation + examples landed in `#820`.
Expand Down
15 changes: 15 additions & 0 deletions pmoves/env.shared.example
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,21 @@ NEXT_PUBLIC_SUPABASE_BOOT_USER_JWT=
AUTH_BOOTSTRAP_MODE=jwt
AUTH_BOOTSTRAP_STRICT=0

# n8n production defaults
# Keep n8n internals on the dedicated sidecar Postgres. PMOVES domain state still lives in Supabase.
N8N_DB=postgres
N8N_DB_NAME=n8n
N8N_DB_USER=n8n
N8N_DB_PASSWORD=CHANGE_ME_N8N_DB_PASSWORD
N8N_DB_SCHEMA=public
N8N_BASE_URL=http://localhost:5678
N8N_API_URL=${N8N_BASE_URL}/api/v1
N8N_OWNER_EMAIL=${SUPABASE_BOOT_USER_EMAIL}
N8N_OWNER_PASSWORD=
N8N_OWNER_FIRST_NAME=PMOVES
N8N_OWNER_LAST_NAME=Operator
N8N_API_KEY=

# Optional Google OAuth (Supabase Auth)
SUPABASE_AUTH_EXTERNAL_GOOGLE_ENABLED=false
SUPABASE_AUTH_EXTERNAL_GOOGLE_CLIENT_ID=
Expand Down
15 changes: 15 additions & 0 deletions pmoves/n8n/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# PMOVES n8n Mirror

`pmoves/n8n/flows/` is now a compatibility mirror.

Canonical n8n workflow ownership lives in [`PMOVES-n8n/workflows/`](../../PMOVES-n8n/workflows). The parent repo keeps this mirror so older docs, UI links, and operator muscle memory do not break during the transition.

Canonical edit path:

```bash
make -C pmoves n8n-api-bootstrap
make -C pmoves n8n-sync-submodule-flows
make -C pmoves n8n-import-flows
make -C pmoves n8n-activate-flows
make -C pmoves n8n-sync-supabase-registry
```
Loading
Loading