From 708c28f694f7cb4ca1c9ad4a5f1c9ea9e503d3db Mon Sep 17 00:00:00 2001 From: POWERFULMOVES Date: Tue, 21 Jul 2026 05:47:42 -0400 Subject: [PATCH] chore(pbnj): convert to submodule of PMOVES-pinokio + fix path refs (pbnj/pinokio/api -> pbnj/api) --- .gitmodules | 4 + deploy/runbooks/pinokio-pbnj-install.md | 8 +- pbnj | 1 + pbnj/README.md | 321 ------------ pbnj/pinokio/api/pmoves-agent-zero/.gitignore | 2 - pbnj/pinokio/api/pmoves-agent-zero/README.md | 94 ---- pbnj/pinokio/api/pmoves-agent-zero/icon.svg | 6 - pbnj/pinokio/api/pmoves-agent-zero/install.js | 36 -- pbnj/pinokio/api/pmoves-agent-zero/pinokio.js | 96 ---- .../api/pmoves-agent-zero/pinokio.json | 5 - pbnj/pinokio/api/pmoves-agent-zero/reset.js | 36 -- pbnj/pinokio/api/pmoves-agent-zero/start.js | 36 -- pbnj/pinokio/api/pmoves-agent-zero/status.js | 25 - pbnj/pinokio/api/pmoves-agent-zero/update.js | 39 -- pbnj/pinokio/api/pmoves-cipher-beats/SKILL.md | 223 -------- pbnj/pinokio/api/pmoves-discord-bot/README.md | 66 --- .../api/pmoves-discord-bot/app/.gitignore | 1 - .../app/config/channel-structure.yaml | 145 ------ .../api/pmoves-discord-bot/app/package.json | 14 - .../api/pmoves-discord-bot/app/src/config.js | 12 - .../api/pmoves-discord-bot/app/src/index.js | 96 ---- .../api/pmoves-discord-bot/app/src/secure.js | 153 ------ .../api/pmoves-discord-bot/app/src/setup.js | 153 ------ .../pinokio/api/pmoves-discord-bot/install.js | 9 - .../pinokio/api/pmoves-discord-bot/pinokio.js | 66 --- .../api/pmoves-discord-bot/pinokio.json | 6 - pbnj/pinokio/api/pmoves-discord-bot/setup.js | 9 - pbnj/pinokio/api/pmoves-discord-bot/start.js | 19 - .../api/pmoves-holographic-blocks/SKILL.md | 119 ----- .../api/pmoves-model-registry/SKILL.md | 134 ----- .../api/pmoves-model-selector/.gitignore | 3 - .../api/pmoves-model-selector/README.md | 144 ------ .../api/pmoves-model-selector/icon.svg | 8 - .../api/pmoves-model-selector/install.js | 70 --- .../api/pmoves-model-selector/pinokio.js | 111 ---- .../api/pmoves-model-selector/pinokio.json | 6 - .../api/pmoves-model-selector/reset.js | 21 - .../api/pmoves-model-selector/select-model.js | 129 ----- .../api/pmoves-model-selector/start.js | 55 -- .../api/pmoves-model-selector/update.js | 32 -- pbnj/pinokio/api/pmoves-notebooklm/icon.svg | 1 - pbnj/pinokio/api/pmoves-notebooklm/install.js | 15 - pbnj/pinokio/api/pmoves-notebooklm/pinokio.js | 17 - pbnj/pinokio/api/pmoves-notebooklm/start.js | 16 - pbnj/pinokio/api/pmoves-pbnj/.gitignore | 8 - pbnj/pinokio/api/pmoves-pbnj/4090-deploy.json | 54 -- pbnj/pinokio/api/pmoves-pbnj/4090-models.json | 74 --- pbnj/pinokio/api/pmoves-pbnj/4090-status.json | 52 -- pbnj/pinokio/api/pmoves-pbnj/AGENTS.md | 474 ------------------ pbnj/pinokio/api/pmoves-pbnj/CLAUDE.md | 474 ------------------ pbnj/pinokio/api/pmoves-pbnj/ENVIRONMENT | 98 ---- pbnj/pinokio/api/pmoves-pbnj/GEMINI.md | 474 ------------------ pbnj/pinokio/api/pmoves-pbnj/QWEN.md | 474 ------------------ pbnj/pinokio/api/pmoves-pbnj/README.md | 126 ----- pbnj/pinokio/api/pmoves-pbnj/SKILL.md | 140 ------ pbnj/pinokio/api/pmoves-pbnj/demo.js | 57 --- pbnj/pinokio/api/pmoves-pbnj/icon.png | 1 - pbnj/pinokio/api/pmoves-pbnj/kvm2-deploy.json | 17 - .../api/pmoves-pbnj/kvm4-1-deploy.json | 18 - .../api/pmoves-pbnj/kvm4-2-deploy.json | 18 - pbnj/pinokio/api/pmoves-pbnj/kvm4-down.json | 11 - pbnj/pinokio/api/pmoves-pbnj/kvm4-up.json | 11 - pbnj/pinokio/api/pmoves-pbnj/lab-down.json | 11 - pbnj/pinokio/api/pmoves-pbnj/lab-up.json | 11 - pbnj/pinokio/api/pmoves-pbnj/local-down.json | 11 - pbnj/pinokio/api/pmoves-pbnj/local-logs.json | 11 - pbnj/pinokio/api/pmoves-pbnj/local-up.json | 11 - .../api/pmoves-pbnj/nats-launch-hook.js | 27 - .../api/pmoves-pbnj/nats-session-hook.js | 29 -- pbnj/pinokio/api/pmoves-pbnj/pinokio.js | 286 ----------- pbnj/pinokio/api/pmoves-pbnj/status.json | 11 - pbnj/pinokio/api/pmoves-pbnj/vps-status.json | 27 - pbnj/pinokio/api/pmoves-remote/README.md | 108 ---- pbnj/pinokio/api/pmoves-remote/SKILL.md | 63 --- pbnj/pinokio/api/pmoves-remote/icon.png | Bin 1545 -> 0 bytes pbnj/pinokio/api/pmoves-remote/install.js | 30 -- pbnj/pinokio/api/pmoves-remote/pinokio.js | 70 --- pbnj/pinokio/api/pmoves-remote/pinokio.json | 5 - pbnj/pinokio/api/pmoves-remote/start.js | 24 - pbnj/pinokio/api/pmoves-remote/status.js | 21 - pbnj/pinokio/api/pmoves-services/README.md | 231 --------- pbnj/pinokio/api/pmoves-services/SKILL.md | 101 ---- pbnj/pinokio/api/pmoves-services/icon.png | Bin 1545 -> 0 bytes pbnj/pinokio/api/pmoves-services/install.js | 27 - pbnj/pinokio/api/pmoves-services/pinokio.js | 166 ------ pbnj/pinokio/api/pmoves-services/pinokio.json | 5 - pbnj/pinokio/api/pmoves-services/reset.js | 38 -- .../pinokio/api/pmoves-services/start-core.js | 29 -- .../api/pmoves-services/start-external.js | 18 - .../api/pmoves-services/start-monitoring.js | 24 - .../api/pmoves-services/start-voice.js | 24 - pbnj/pinokio/api/pmoves-services/status.js | 31 -- pbnj/pinokio/api/pmoves-services/stop.js | 38 -- pbnj/pinokio/api/pmoves-services/update.js | 30 -- .../plugin/code/pmoves-codex/README.md | 42 -- .../pinokio/plugin/code/pmoves-codex/icon.svg | 6 - .../plugin/code/pmoves-codex/pinokio.js | 51 -- 97 files changed, 9 insertions(+), 6751 deletions(-) create mode 160000 pbnj delete mode 100644 pbnj/README.md delete mode 100644 pbnj/pinokio/api/pmoves-agent-zero/.gitignore delete mode 100644 pbnj/pinokio/api/pmoves-agent-zero/README.md delete mode 100644 pbnj/pinokio/api/pmoves-agent-zero/icon.svg delete mode 100644 pbnj/pinokio/api/pmoves-agent-zero/install.js delete mode 100644 pbnj/pinokio/api/pmoves-agent-zero/pinokio.js delete mode 100644 pbnj/pinokio/api/pmoves-agent-zero/pinokio.json delete mode 100644 pbnj/pinokio/api/pmoves-agent-zero/reset.js delete mode 100644 pbnj/pinokio/api/pmoves-agent-zero/start.js delete mode 100644 pbnj/pinokio/api/pmoves-agent-zero/status.js delete mode 100644 pbnj/pinokio/api/pmoves-agent-zero/update.js delete mode 100644 pbnj/pinokio/api/pmoves-cipher-beats/SKILL.md delete mode 100644 pbnj/pinokio/api/pmoves-discord-bot/README.md delete mode 100644 pbnj/pinokio/api/pmoves-discord-bot/app/.gitignore delete mode 100644 pbnj/pinokio/api/pmoves-discord-bot/app/config/channel-structure.yaml delete mode 100644 pbnj/pinokio/api/pmoves-discord-bot/app/package.json delete mode 100644 pbnj/pinokio/api/pmoves-discord-bot/app/src/config.js delete mode 100644 pbnj/pinokio/api/pmoves-discord-bot/app/src/index.js delete mode 100644 pbnj/pinokio/api/pmoves-discord-bot/app/src/secure.js delete mode 100644 pbnj/pinokio/api/pmoves-discord-bot/app/src/setup.js delete mode 100644 pbnj/pinokio/api/pmoves-discord-bot/install.js delete mode 100644 pbnj/pinokio/api/pmoves-discord-bot/pinokio.js delete mode 100644 pbnj/pinokio/api/pmoves-discord-bot/pinokio.json delete mode 100644 pbnj/pinokio/api/pmoves-discord-bot/setup.js delete mode 100644 pbnj/pinokio/api/pmoves-discord-bot/start.js delete mode 100644 pbnj/pinokio/api/pmoves-holographic-blocks/SKILL.md delete mode 100644 pbnj/pinokio/api/pmoves-model-registry/SKILL.md delete mode 100644 pbnj/pinokio/api/pmoves-model-selector/.gitignore delete mode 100644 pbnj/pinokio/api/pmoves-model-selector/README.md delete mode 100644 pbnj/pinokio/api/pmoves-model-selector/icon.svg delete mode 100644 pbnj/pinokio/api/pmoves-model-selector/install.js delete mode 100644 pbnj/pinokio/api/pmoves-model-selector/pinokio.js delete mode 100644 pbnj/pinokio/api/pmoves-model-selector/pinokio.json delete mode 100644 pbnj/pinokio/api/pmoves-model-selector/reset.js delete mode 100644 pbnj/pinokio/api/pmoves-model-selector/select-model.js delete mode 100644 pbnj/pinokio/api/pmoves-model-selector/start.js delete mode 100644 pbnj/pinokio/api/pmoves-model-selector/update.js delete mode 100644 pbnj/pinokio/api/pmoves-notebooklm/icon.svg delete mode 100644 pbnj/pinokio/api/pmoves-notebooklm/install.js delete mode 100644 pbnj/pinokio/api/pmoves-notebooklm/pinokio.js delete mode 100644 pbnj/pinokio/api/pmoves-notebooklm/start.js delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/.gitignore delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/4090-deploy.json delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/4090-models.json delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/4090-status.json delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/AGENTS.md delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/CLAUDE.md delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/ENVIRONMENT delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/GEMINI.md delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/QWEN.md delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/README.md delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/SKILL.md delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/demo.js delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/icon.png delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/kvm2-deploy.json delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/kvm4-1-deploy.json delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/kvm4-2-deploy.json delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/kvm4-down.json delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/kvm4-up.json delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/lab-down.json delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/lab-up.json delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/local-down.json delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/local-logs.json delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/local-up.json delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/nats-launch-hook.js delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/nats-session-hook.js delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/pinokio.js delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/status.json delete mode 100644 pbnj/pinokio/api/pmoves-pbnj/vps-status.json delete mode 100644 pbnj/pinokio/api/pmoves-remote/README.md delete mode 100644 pbnj/pinokio/api/pmoves-remote/SKILL.md delete mode 100644 pbnj/pinokio/api/pmoves-remote/icon.png delete mode 100644 pbnj/pinokio/api/pmoves-remote/install.js delete mode 100644 pbnj/pinokio/api/pmoves-remote/pinokio.js delete mode 100644 pbnj/pinokio/api/pmoves-remote/pinokio.json delete mode 100644 pbnj/pinokio/api/pmoves-remote/start.js delete mode 100644 pbnj/pinokio/api/pmoves-remote/status.js delete mode 100644 pbnj/pinokio/api/pmoves-services/README.md delete mode 100644 pbnj/pinokio/api/pmoves-services/SKILL.md delete mode 100644 pbnj/pinokio/api/pmoves-services/icon.png delete mode 100644 pbnj/pinokio/api/pmoves-services/install.js delete mode 100644 pbnj/pinokio/api/pmoves-services/pinokio.js delete mode 100644 pbnj/pinokio/api/pmoves-services/pinokio.json delete mode 100644 pbnj/pinokio/api/pmoves-services/reset.js delete mode 100644 pbnj/pinokio/api/pmoves-services/start-core.js delete mode 100644 pbnj/pinokio/api/pmoves-services/start-external.js delete mode 100644 pbnj/pinokio/api/pmoves-services/start-monitoring.js delete mode 100644 pbnj/pinokio/api/pmoves-services/start-voice.js delete mode 100644 pbnj/pinokio/api/pmoves-services/status.js delete mode 100644 pbnj/pinokio/api/pmoves-services/stop.js delete mode 100644 pbnj/pinokio/api/pmoves-services/update.js delete mode 100644 pbnj/pinokio/plugin/code/pmoves-codex/README.md delete mode 100644 pbnj/pinokio/plugin/code/pmoves-codex/icon.svg delete mode 100644 pbnj/pinokio/plugin/code/pmoves-codex/pinokio.js diff --git a/.gitmodules b/.gitmodules index 87186d612b..de621bffd1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -352,3 +352,7 @@ path = pmoves-hirag-mcp url = https://github.com/POWERFULMOVES/pmoves-hirag-mcp.git branch = main +[submodule "pbnj"] + path = pbnj + url = https://github.com/POWERFULMOVES/PMOVES-pinokio.git + branch = PMOVES.AI-Edition-Hardened diff --git a/deploy/runbooks/pinokio-pbnj-install.md b/deploy/runbooks/pinokio-pbnj-install.md index bab65e97a1..cfbe3134fd 100644 --- a/deploy/runbooks/pinokio-pbnj-install.md +++ b/deploy/runbooks/pinokio-pbnj-install.md @@ -32,11 +32,11 @@ vncserver :1 -geometry 1920x1080 -depth 24 ### 2. Configure PBNJ Launchers -PBNJ launcher configs are at `pbnj/pinokio/api/pmoves-services/`. +PBNJ launcher configs are at `pbnj/api/pmoves-services/`. If the submodule is populated: ```bash -cd pbnj/pinokio/api/pmoves-services/ +cd pbnj/api/pmoves-services/ # Each service has a pinokio.js launcher file ls *.js ``` @@ -92,7 +92,7 @@ Configure launcher startup order in Pinokio or use Docker Compose `depends_on`. | Service | Launcher | Status | Notes | |---------|----------|--------|-------| -| Gateway | pbnj/pinokio/api/pmoves-services/ | Check submodule | CHIT signing enabled | +| Gateway | pbnj/api/pmoves-services/ | Check submodule | CHIT signing enabled | | Postgres | docker-compose | Existing | Tier data | | MinIO | docker-compose | Existing | Tier data | | NATS | docker-compose | Existing | Message bus | @@ -110,7 +110,7 @@ Configure launcher startup order in Pinokio or use Docker Compose `depends_on`. ## References - Pinokio: https://pinokio.computer/ -- PBNJ configs: `pbnj/pinokio/api/pmoves-services/` +- PBNJ configs: `pbnj/api/pmoves-services/` - Docker Compose: `pmoves/docker/docker-compose.yml` - Tier configs: `pmoves/env.tier-*.example` diff --git a/pbnj b/pbnj new file mode 160000 index 0000000000..40a6295907 --- /dev/null +++ b/pbnj @@ -0,0 +1 @@ +Subproject commit 40a6295907b94ecaaca582311ecd259a129f577f diff --git a/pbnj/README.md b/pbnj/README.md deleted file mode 100644 index 4b1263ac45..0000000000 --- a/pbnj/README.md +++ /dev/null @@ -1,321 +0,0 @@ -# PBnJ - Pinokio-Based N-tier Deployment for PMOVES.AI - -**PBnJ** (Pinokio-Based N-tier) is a one-click deployment interface for PMOVES.AI, providing graphical controls for managing multi-environment orchestration via [Pinokio](https://pinokio.computer). - -## What is PBnJ? - -PBnJ bridges the gap between complex multi-cluster Kubernetes deployments and simple one-click management. It provides: - -- **Graphical Interface**: Click to deploy/teardown entire PMOVES stacks -- **Multi-Target Support**: AI Lab (K8s), KVM4 Gateway (K8s), Local Dev (Docker Compose) -- **Zero Configuration**: Works out-of-box with PMOVES deployment scripts -- **Integrated Monitoring**: Status checks and log streaming - -## Architecture - -``` -┌─────────────────────────────────────────────────────────────┐ -│ Pinokio UI (PBnJ App) │ -├─────────────────────────────────────────────────────────────┤ -│ [Start AI Lab] [Stop AI Lab] [Start KVM4] [Stop KVM4] │ -│ [Local Up] [Local Down] [Local Logs] [Cluster Status] │ -└────────────────────────┬────────────────────────────────────┘ - │ - ┌────────────────┼────────────────┐ - │ │ │ - ▼ ▼ ▼ - deploy-k8s.sh deploy-k8s.sh deploy-compose.sh - (AI Lab) (KVM4) (Local) - │ │ │ - ▼ ▼ ▼ - ┌─────────┐ ┌─────────┐ ┌──────────────┐ - │ AI Lab │ │ KVM4 │ │ Docker │ - │ K8s │ │ K8s │ │ Compose │ - │ Cluster │ │ Gateway │ │ (localhost) │ - └─────────┘ └─────────┘ └──────────────┘ -``` - -## Installation - -### Prerequisites -- [Pinokio](https://pinokio.computer) installed and running -- For K8s: `kubectl` configured with cluster access -- For Local: Docker Engine with Compose plugin - -### Installation Steps - -1. **Install Pinokio** (if not already installed): - ```bash - # Visit https://pinokio.computer and download for your platform - ``` - -2. **Link PBnJ to Pinokio**: - - **Option A: Symlink (Recommended)** - ```bash - # macOS/Linux - ln -s /path/to/PMOVES.AI/pbnj/pinokio/api/pmoves-pbnj \ - ~/pinokio/api/pmoves-pbnj - - # Windows (PowerShell as Admin) - New-Item -ItemType SymbolicLink ` - -Path "$env:USERPROFILE\pinokio\api\pmoves-pbnj" ` - -Target "C:\path\to\PMOVES.AI\pbnj\pinokio\api\pmoves-pbnj" - ``` - - **Option B: Copy** - ```bash - cp -r pbnj/pinokio/api/pmoves-pbnj ~/pinokio/api/ - ``` - -3. **Restart Pinokio** to detect the new application - -4. **Launch PBnJ** from the Pinokio dashboard - -## Usage - -### AI Lab Cluster (Kubernetes) - -**Start AI Lab:** -1. Click "Start AI Lab (K8s)" in PBnJ menu -2. Wait for deployment completion (~2-3 minutes) -3. Verify with "Cluster Status (AI Lab)" - -**Stop AI Lab:** -1. Click "Stop AI Lab (K8s)" -2. Confirms all resources deleted - -**What it does:** -- Applies Kustomize manifests from `deploy/k8s/ai-lab/` -- Deploys 5 replicas of PMOVES core -- Configures ingress at `pmoves.lab.local` -- Uses hardened image tag: `v1.0.0-lab-hardened` - -### KVM4 Gateway (Kubernetes) - -**Start KVM4:** -1. Click "Start KVM4 Stack (K8s)" -2. Gateway deploys to edge cluster - -**Stop KVM4:** -1. Click "Stop KVM4 Stack (K8s)" - -**What it does:** -- Applies Kustomize manifests from `deploy/k8s/kvm4/` -- Deploys 2 replicas for HA -- Configures ingress at `pmoves.kvm4.yourdomain.tld` -- Uses hardened image tag: `v1.0.0-kvm4-hardened` - -### Local Development (Docker Compose) - -**Start Local Stack:** -1. Click "Local Dev (Docker) - Up" -2. All PMOVES services start via Docker Compose -3. Access at `http://localhost:*` (see service ports) - -**View Logs:** -1. Click "Local Dev (Docker) Logs" -2. Real-time log streaming from all containers - -**Stop Local Stack:** -1. Click "Local Dev (Docker) - Down" -2. Containers stopped and removed - -**What it does:** -- Runs `deploy/scripts/deploy-compose.sh` -- Uses compose file: `pmoves/docker-compose.yml` -- Project name: `pmoves_local` - -## Configuration - -### Environment Variables - -Create `.env` file in PMOVES.AI root or set in your shell: - -```bash -# Kubernetes Contexts -export PMOVES_K8S_CONTEXT_AI_LAB=ai-lab -export PMOVES_K8S_CONTEXT_KVM4=kvm4 -export PMOVES_K8S_CONTEXT_LOCAL=kind-pmoves - -# Kubernetes Namespaces -export PMOVES_K8S_NS_AI_LAB=pmoves -export PMOVES_K8S_NS_KVM4=pmoves -export PMOVES_K8S_NS_LOCAL=pmoves-dev - -# Docker Compose -export PMOVES_COMPOSE_FILE=/home/pmoves/PMOVES.AI/pmoves/docker-compose.yml -export PMOVES_COMPOSE_PROJECT=pmoves_local -``` - -### Customizing Workflows - -PBnJ workflows are JSON files in `pinokio/api/pmoves-pbnj/`. Edit these to customize behavior: - -**Example: Add pre-deployment health check** - -Edit `lab-up.json`: -```json -{ - "run": [ - { - "method": "shell.run", - "params": { - "path": "{{local.root}}", - "cmd": ["kubectl", "cluster-info"] - } - }, - { - "method": "shell.run", - "params": { - "path": "{{local.root}}", - "cmd": [ - "bash", - "deploy/scripts/deploy-k8s.sh", - "apply", - "--target", - "ai-lab" - ] - } - } - ] -} -``` - -### Adding Custom Icon - -Replace `pinokio/api/pmoves-pbnj/icon.png` with your custom icon: -- Recommended: 512x512 PNG -- Transparent background -- PMOVES.AI branding - -## Workflow Files - -| File | Description | Command | -|------|-------------|---------| -| `lab-up.json` | Deploy AI Lab | `deploy-k8s.sh apply --target ai-lab` | -| `lab-down.json` | Teardown AI Lab | `deploy-k8s.sh delete --target ai-lab` | -| `kvm4-up.json` | Deploy KVM4 | `deploy-k8s.sh apply --target kvm4` | -| `kvm4-down.json` | Teardown KVM4 | `deploy-k8s.sh delete --target kvm4` | -| `status.json` | Cluster status | `deploy-k8s.sh status --target ai-lab` | -| `local-up.json` | Start local stack | `deploy-compose.sh up` | -| `local-down.json` | Stop local stack | `deploy-compose.sh down` | -| `local-logs.json` | Stream logs | `deploy-compose.sh logs` | - -## Troubleshooting - -### "Command not found: kubectl" -**Solution:** Install kubectl and add to PATH -```bash -# macOS -brew install kubectl - -# Ubuntu/Debian -sudo apt-get install -y kubectl - -# Verify -kubectl version --client -``` - -### "Context not found: ai-lab" -**Solution:** Set correct context name via environment variable -```bash -export PMOVES_K8S_CONTEXT_AI_LAB=your-actual-context -kubectl config get-contexts # List available contexts -``` - -### "docker compose: command not found" -**Solution:** Install Docker Compose v2 or use docker-compose -```bash -# Install Docker Desktop (includes Compose v2) -# OR install standalone: -sudo apt-get install docker-compose-plugin -``` - -### Workflow appears but doesn't run -1. Check Pinokio console for errors -2. Verify scripts are executable: - ```bash - chmod +x deploy/scripts/*.sh - ``` -3. Test script manually: - ```bash - bash deploy/scripts/deploy-k8s.sh status --target ai-lab - ``` - -### Changes not reflected in Pinokio -- Restart Pinokio application -- Or: Click "Reload" in Pinokio settings - -## Integration with WorkOS IAM - -PBnJ is designed to integrate with WorkOS for identity-aware deployments (see Cloud School IAM strategy): - -1. **User Authentication**: Pinokio user → WorkOS SSO -2. **Role-Based Access**: - - Developers: Local dev only - - DevOps: All environments - - Admins: Full control + monitoring -3. **Audit Logging**: All PBnJ actions logged to WorkOS audit stream - -*Note: WorkOS integration requires additional configuration. See `/docs/Cloud School IAM and Onboarding Strategy.pdf`* - -## Development - -### Testing New Workflows - -1. Create new JSON workflow in `pinokio/api/pmoves-pbnj/` -2. Add menu entry to `pinokio.js`: - ```javascript - { text: "My Workflow", href: "my-workflow.json" } - ``` -3. Restart Pinokio to load changes - -### Workflow Template - -```json -{ - "run": [ - { - "method": "shell.run", - "params": { - "path": "{{local.root}}", - "cmd": ["bash", "path/to/script.sh", "arg1", "arg2"] - } - } - ] -} -``` - -Variables: -- `{{local.root}}`: PMOVES.AI repository root -- `{{os.platform}}`: OS platform (darwin, linux, win32) -- `{{env.VAR}}`: Environment variable - -## Security Considerations - -- **Credential Management**: Never hardcode credentials in workflow files -- **Script Validation**: Ensure deployment scripts validate inputs -- **Least Privilege**: Grant kubectl/docker permissions only as needed -- **Audit Trail**: Enable command logging in Pinokio settings - -See `/docs/Security-Hardening-Roadmap.md` for comprehensive security guidelines. - -## Related Documentation - -- [Deployment Scripts](/deploy/README.md) -- [PMOVES Architecture](/.claude/CLAUDE.md) -- [Kubernetes Manifests](/deploy/k8s/) -- [Pinokio Documentation](https://docs.pinokio.computer) - -## Support - -For issues or questions: -1. Test deployment scripts directly (bypass Pinokio) -2. Check Pinokio console for error messages -3. Review logs: `./deploy/scripts/deploy-compose.sh logs` -4. Verify environment variables are set - -## License - -Part of the PMOVES.AI project. See repository root for license details. diff --git a/pbnj/pinokio/api/pmoves-agent-zero/.gitignore b/pbnj/pinokio/api/pmoves-agent-zero/.gitignore deleted file mode 100644 index 0496b810cf..0000000000 --- a/pbnj/pinokio/api/pmoves-agent-zero/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -logs/ -repo-root.txt diff --git a/pbnj/pinokio/api/pmoves-agent-zero/README.md b/pbnj/pinokio/api/pmoves-agent-zero/README.md deleted file mode 100644 index ad816255a0..0000000000 --- a/pbnj/pinokio/api/pmoves-agent-zero/README.md +++ /dev/null @@ -1,94 +0,0 @@ -# PMOVES Agent Zero - -Pinokio launcher for the PMOVES Agent Zero mesh entrypoint. - -This launcher is a thin wrapper over the repo-supported PMOVES startup flow. It does not fork Agent Zero application logic into a separate Pinokio app folder. Instead, it targets a user-selected local `PMOVES.AI` checkout, launches the current PMOVES stack from `/pmoves`, seeds the runtime MCP map, and exposes the Agent Zero UI and API endpoints through Pinokio. - -## Quick Start - -1. Click **Install** and select the local `PMOVES.AI` repo root. -2. The launcher stores that selection in `repo-root.txt`. -3. Pinokio bootstraps `pmoves/env.shared` and seeds Agent Zero MCP defaults from that selected checkout. -4. Click **Start Agent Tier** to launch Agent Zero plus the supported PMOVES agent stack. -5. Open the **Agent Zero UI** at `http://localhost:8081`. -6. Use **Status** to inspect health and current MCP commands. - -## Scripts - -| Script | Purpose | -|--------|---------| -| `install.js` | Select a PMOVES checkout, bootstrap env files, and seed `data/agent-zero/runtime/mcp/servers.env` | -| `start.js` | Start the supported PMOVES agent tier and tail Agent Zero logs | -| `status.js` | Show container status, `/healthz`, and `/mcp/commands` | -| `update.js` | Pull latest PMOVES changes, refresh submodules, and reseed MCP runtime | -| `reset.js` | Stop Agent Zero and clear runtime/log state before reseeding | - -## What Start Launches - -The launcher uses the repo-supported `make up-agents-ui` path from `pmoves/Makefile`. That brings up: - -- NATS + JetStream bootstrap -- Agent Zero API and UI -- Archon API and UI -- DeepResearch -- SupaSerch -- Mesh Agent -- Publisher-Discord - -That matches the current PMOVES control-plane bring-up better than a fake standalone Agent Zero package. - -## API Reference - -### Agent Zero API - -| Endpoint | Method | Description | -|----------|--------|-------------| -| `http://localhost:8080/healthz` | GET | Health check and controller status | -| `http://localhost:8080/config/environment` | GET | Resolved runtime configuration | -| `http://localhost:8080/mcp/commands` | GET | List MCP helpers and runtime metadata | -| `http://localhost:8080/mcp/execute` | POST | Execute an MCP command | -| `http://localhost:8080/docs` | GET | FastAPI docs | -| `http://localhost:8081` | GET | Agent Zero UI | - -**Curl** - -```bash -curl http://localhost:8080/healthz -curl http://localhost:8080/mcp/commands -curl -X POST http://localhost:8080/mcp/execute \ - -H "Content-Type: application/json" \ - -d '{"cmd":"geometry.jump","arguments":{"point_id":"demo"}}' -``` - -**Python** - -```python -import requests - -print(requests.get("http://localhost:8080/healthz").json()) -print(requests.get("http://localhost:8080/mcp/commands").json()) -result = requests.post( - "http://localhost:8080/mcp/execute", - json={"cmd": "geometry.jump", "arguments": {"point_id": "demo"}}, -) -print(result.json()) -``` - -**JavaScript** - -```javascript -const health = await fetch("http://localhost:8080/healthz").then(r => r.json()) -const commands = await fetch("http://localhost:8080/mcp/commands").then(r => r.json()) -const result = await fetch("http://localhost:8080/mcp/execute", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ cmd: "geometry.jump", arguments: { point_id: "demo" } }) -}).then(r => r.json()) -``` - -## Notes - -- MCP defaults are seeded into `pmoves/data/agent-zero/runtime/mcp/servers.env`. -- This launcher intentionally tracks a selected PMOVES repo checkout instead of a separate `app/` clone. -- Re-run **Install** any time you want to point Pinokio at a different PMOVES checkout. -- Provider-specific agent customization belongs in Pinokio plugins such as `pmoves-codex`, not inside this launcher. diff --git a/pbnj/pinokio/api/pmoves-agent-zero/icon.svg b/pbnj/pinokio/api/pmoves-agent-zero/icon.svg deleted file mode 100644 index 61df5dec7a..0000000000 --- a/pbnj/pinokio/api/pmoves-agent-zero/icon.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/pbnj/pinokio/api/pmoves-agent-zero/install.js b/pbnj/pinokio/api/pmoves-agent-zero/install.js deleted file mode 100644 index 3965ae44e3..0000000000 --- a/pbnj/pinokio/api/pmoves-agent-zero/install.js +++ /dev/null @@ -1,36 +0,0 @@ -module.exports = { - run: [{ - method: "filepicker.open", - params: { - title: "Select PMOVES.AI repository root", - type: "folder" - } - }, { - method: "local.set", - params: { - repo_root: "{{input.paths[0]}}" - } - }, { - method: "fs.write", - params: { - path: "repo-root.txt", - text: "{{local.repo_root}}" - } - }, { - method: "shell.run", - params: { - path: "{{path.resolve(local.repo_root, 'pmoves')}}", - message: [ - "if not exist Makefile ( echo Expected pmoves/Makefile under the selected PMOVES.AI repo root & exit /b 1 )", - "py -3 tools/env_setup_unified.py", - "make a0-mcp-seed" - ] - } - }, { - method: "notify", - params: { - html: "PMOVES environment bootstrapped for Agent Zero. Start the agent tier when ready.", - type: "success" - } - }] -} diff --git a/pbnj/pinokio/api/pmoves-agent-zero/pinokio.js b/pbnj/pinokio/api/pmoves-agent-zero/pinokio.js deleted file mode 100644 index 39eb5e9c93..0000000000 --- a/pbnj/pinokio/api/pmoves-agent-zero/pinokio.js +++ /dev/null @@ -1,96 +0,0 @@ -module.exports = { - version: "5.0", - title: "PMOVES Agent Zero", - description: "Launch Agent Zero from the PMOVES mesh and seed its MCP runtime.", - icon: "icon.svg", - menu: async (kernel, info) => { - let configured = info.exists("repo-root.txt") - let running = { - install: info.running("install.js"), - start: info.running("start.js"), - status: info.running("status.js"), - reset: info.running("reset.js"), - update: info.running("update.js") - } - - if (running.install) { - return [{ - default: true, - icon: "fa-solid fa-plug", - text: "Bootstrapping Agent Zero...", - href: "install.js" - }] - } - - if (running.reset) { - return [{ - default: true, - icon: "fa-solid fa-broom", - text: "Resetting Agent Zero...", - href: "reset.js" - }] - } - - if (running.update) { - return [{ - default: true, - icon: "fa-solid fa-arrows-rotate", - text: "Updating Agent Zero...", - href: "update.js" - }] - } - - if (!configured) { - return [{ - default: true, - icon: "fa-solid fa-plug", - text: "Install (Select PMOVES Repo)", - href: "install.js" - }] - } - - let local = info.local("start.js") - let uiUrl = local && local.url ? local.url : "http://localhost:8081" - - let items = [{ - default: true, - icon: running.start ? "fa-solid fa-terminal" : "fa-solid fa-play", - text: running.start ? "Agent Zero Terminal" : "Start Agent Tier", - href: "start.js" - }, { - icon: "fa-solid fa-globe", - text: "Open Agent Zero UI", - href: uiUrl - }, { - icon: "fa-solid fa-book", - text: "Open API Docs", - href: "http://localhost:8080/docs" - }, { - icon: "fa-solid fa-heart-pulse", - text: "Health Check", - href: "http://localhost:8080/healthz" - }, { - icon: "fa-solid fa-diagram-project", - text: "MCP Commands", - href: "http://localhost:8080/mcp/commands" - }, { - icon: "fa-solid fa-folder-tree", - text: "Re-select PMOVES Repo", - href: "install.js" - }, { - icon: "fa-solid fa-circle-info", - text: "Status", - href: "status.js" - }, { - icon: "fa-solid fa-arrows-rotate", - text: "Update + Reseed MCP", - href: "update.js" - }, { - icon: "fa-solid fa-broom", - text: "Reset Runtime", - href: "reset.js" - }] - - return items - } -} diff --git a/pbnj/pinokio/api/pmoves-agent-zero/pinokio.json b/pbnj/pinokio/api/pmoves-agent-zero/pinokio.json deleted file mode 100644 index 522e26774e..0000000000 --- a/pbnj/pinokio/api/pmoves-agent-zero/pinokio.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "title": "PMOVES Agent Zero", - "description": "One-click PMOVES Agent Zero launcher with API/UI startup and MCP runtime seeding.", - "icon": "icon.svg" -} diff --git a/pbnj/pinokio/api/pmoves-agent-zero/reset.js b/pbnj/pinokio/api/pmoves-agent-zero/reset.js deleted file mode 100644 index c0b6fadc00..0000000000 --- a/pbnj/pinokio/api/pmoves-agent-zero/reset.js +++ /dev/null @@ -1,36 +0,0 @@ -module.exports = { - run: [{ - method: "fs.read", - params: { - path: "repo-root.txt", - encoding: "utf8" - } - }, { - method: "local.set", - params: { - repo_root: "{{input.trim()}}" - } - }, { - method: "shell.run", - params: { - path: "{{path.resolve(local.repo_root, 'pmoves')}}", - message: [ - "docker compose stop agent-zero || echo agent-zero already stopped", - "if exist data\\agent-zero\\runtime rmdir /s /q data\\agent-zero\\runtime", - "if exist data\\agent-zero\\logs rmdir /s /q data\\agent-zero\\logs", - "if not exist data\\agent-zero mkdir data\\agent-zero", - "mkdir data\\agent-zero\\runtime", - "mkdir data\\agent-zero\\runtime\\mcp", - "mkdir data\\agent-zero\\logs", - "make a0-mcp-seed" - ] - } - }, { - method: "notify", - params: { - html: "Agent Zero runtime reset complete. Start again to relaunch the service and UI.", - type: "warning" - } - }] -} - diff --git a/pbnj/pinokio/api/pmoves-agent-zero/start.js b/pbnj/pinokio/api/pmoves-agent-zero/start.js deleted file mode 100644 index 04856070f6..0000000000 --- a/pbnj/pinokio/api/pmoves-agent-zero/start.js +++ /dev/null @@ -1,36 +0,0 @@ -module.exports = { - daemon: true, - run: [{ - method: "fs.read", - params: { - path: "repo-root.txt", - encoding: "utf8" - } - }, { - method: "local.set", - params: { - repo_root: "{{input.trim()}}" - } - }, { - method: "shell.run", - params: { - path: "{{path.resolve(local.repo_root, 'pmoves')}}", - message: [ - "make up-agents-ui", - "make a0-mcp-seed", - "echo http://localhost:8081", - "docker compose logs -f --tail=100 agent-zero" - ], - on: [{ - event: "/(http:\\/\\/[0-9.:]+)/", - done: true - }] - } - }, { - method: "local.set", - params: { - url: "{{input.event[1]}}" - } - }] -} - diff --git a/pbnj/pinokio/api/pmoves-agent-zero/status.js b/pbnj/pinokio/api/pmoves-agent-zero/status.js deleted file mode 100644 index 54394b791b..0000000000 --- a/pbnj/pinokio/api/pmoves-agent-zero/status.js +++ /dev/null @@ -1,25 +0,0 @@ -module.exports = { - run: [{ - method: "fs.read", - params: { - path: "repo-root.txt", - encoding: "utf8" - } - }, { - method: "local.set", - params: { - repo_root: "{{input.trim()}}" - } - }, { - method: "shell.run", - params: { - path: "{{path.resolve(local.repo_root, 'pmoves')}}", - message: [ - "docker compose ps agent-zero", - "py -3 -c \"import urllib.request,sys; sys.stdout.write(urllib.request.urlopen('http://localhost:8080/healthz').read().decode())\" 2>nul || echo healthz unavailable", - "py -3 -c \"import urllib.request,sys; sys.stdout.write(urllib.request.urlopen('http://localhost:8080/mcp/commands').read().decode())\" 2>nul || echo mcp commands unavailable" - ] - } - }] -} - diff --git a/pbnj/pinokio/api/pmoves-agent-zero/update.js b/pbnj/pinokio/api/pmoves-agent-zero/update.js deleted file mode 100644 index d37ac06c4f..0000000000 --- a/pbnj/pinokio/api/pmoves-agent-zero/update.js +++ /dev/null @@ -1,39 +0,0 @@ -module.exports = { - run: [{ - method: "fs.read", - params: { - path: "repo-root.txt", - encoding: "utf8" - } - }, { - method: "local.set", - params: { - repo_root: "{{input.trim()}}" - } - }, { - method: "shell.run", - params: { - path: "{{local.repo_root}}", - message: [ - "git pull --ff-only origin main", - "git submodule update --init --recursive" - ] - } - }, { - method: "shell.run", - params: { - path: "{{path.resolve(local.repo_root, 'pmoves')}}", - message: [ - "py -3 tools/env_setup_unified.py", - "make a0-mcp-seed" - ] - } - }, { - method: "notify", - params: { - html: "PMOVES Agent Zero launcher updated and MCP runtime reseeded.", - type: "success" - } - }] -} - diff --git a/pbnj/pinokio/api/pmoves-cipher-beats/SKILL.md b/pbnj/pinokio/api/pmoves-cipher-beats/SKILL.md deleted file mode 100644 index ead70bee75..0000000000 --- a/pbnj/pinokio/api/pmoves-cipher-beats/SKILL.md +++ /dev/null @@ -1,223 +0,0 @@ ---- -name: PMOVES Cipher Beats Analyst -description: | - Level 11 Cipher Gateway Specialist. Extracts mathematically rigorous sonic fingerprints - from DARKXSIDE audio archives using ffprobe / ffmpeg lavfi (ebur128 R128 loudness, - aspectralstats, silencedetect). Groups tracks by sound analysis — NOT by file metadata — - into named sonic constellations, writes M3U8 playlists, checkpoints into Cipher Memory, - and emits geometry events on the NATS Geometry Bus for Holographic CHIT Block generation. -keywords: beats, audio analysis, darkxside, cipher, ffmpeg, lavfi, ebur128, spectral, chit, holographic, m3u8, playlists, glances, nats -version: 2.0.0 -category: Media/Analysis/Cipher -tier: 5 -agent_class: Specialized -agent_id: cipher_beats_analyst ---- - -# PMOVES Cipher Beats Analyst - -**Agent Class**: `Specialized (Pmoves-)` -**Category**: Media/Analysis/Cipher -**Version**: 2.0.0 -**Tier**: 5 (Media) + 6 (Agent/Cipher) -**Status**: Level 11 — Cipher Gateway Specialist -**Cipher Category**: `agent_checkpoint` + `beats_fingerprint` - ---- - -## Mission Statement - -> *"The beats are not music files. They are 15 years of mathematically tuned geometry— -> EQ'd for emotional resonance at BPM-dependent scales, compressed for holographic listening -> across every speaker set. This agent reads that geometry. It does not rename your files. -> It reveals their structure."* - -This specialist treats every audio file as a **dimensional object**: -- `ebur128` — loudness integrated across time (the feeling) -- `aspectralstats` — spectral centroid / flatness / entropy (the color) -- Cluster distance — the relational geometry between tracks - -Output: named sonic constellations → **M3U8 playlists + CHIT geometry events**. - ---- - -## Capabilities - -| Command | What It Does | -|---------|-------------| -| `analyze` | Full ffmpeg lavfi fingerprint → cluster → playlists → Cipher checkpoint | -| `groups` | Display existing sonic groups from last run | - ---- - -## Trigger Phrases (Pinokio 7 Interpreter — zero config) - -| Phrase | Action | Backend | -|--------|--------|---------| -| `"analyze my beats"` | Full pipeline on default input dir | `analyze` | -| `"analyze beats in [path]"` | Full pipeline on specified path | `analyze --input [path]` | -| `"show beat groups"` | Display existing clusters | `groups` | -| `"check beats agent status"` | Cipher + Glances health probe | `status` | -| `"re-analyze with [N] groups"` | Re-cluster with different K | `analyze --groups N --cache` | - ---- - -## The ffmpeg Analysis Stack (No External ML Deps) - -Instead of bloated Python audio ML libraries, this agent uses **ffmpeg 8.x lavfi** directly. -This means it runs natively alongside every PMOVES service that already depends on ffmpeg. - -```text -Audio File (.wav / .opus / .mp3 / .flac / .m4a) - │ - ├── ffprobe → duration, bit_rate, sample_rate, channels, title tags - │ - ├── ffmpeg -af "ebur128" → R128 Integrated Loudness (LUFS), LRA, True Peak - │ └── [emotional weight / perceived intensity] - │ - └── ffmpeg -af "aspectralstats,ametadata=print:file=-" (first 30s sample) - ├── Centroid → timbral character (bass-heavy / warm / electric / airy) - └── Flatness → texture (tonal / textured / noisy) -``` - -### Future Upgrade Path (Phase 11 — Holographic Blocks) -When Hi-RAG multimodal Gemini embeddings go live, replace the spectral heuristics with -`/hirag/ingest/audio` → true multi-dimensional embedding → better cluster geometry. -The same M3U8 + Cipher output interface is preserved. - ---- - -## Sonic Group Naming Convention - -Each group is named: `{TempoZone}_{TimbreZone}_{EnergyZone}` - -| Dimension | Values | -|-----------|--------| -| **TempoZone** | Largo / Andante / Moderato / Allegro / Presto | -| **TimbreZone** | bass-heavy / warm / balanced / electric / airy | -| **EnergyZone** | Deep / Mid / Bright (from R128 LUFS) | - -Example: `Andante_warm_Deep` — slow, rich-toned, quiet-intensity track group. - ---- - -## Output Files - -```text -pmoves/data/beats/playlists/ - ├── Andante_warm_Deep.m3u8 ← sorted by BPM ascending within group - ├── Allegro_electric_Bright.m3u8 - ├── Moderato_balanced_Mid.m3u8 - ├── ... - └── groups_summary.json ← machine-readable group manifest -pmoves/data/beats/soundcloud/darkxside/ - └── .fingerprints.json ← cached ffmpeg analysis results (use --cache to reuse) -``` - ---- - -## Pipeline Integration - -### Cipher Memory (port 8105) -Checkpoints are written at two stages: -1. `fingerprint_complete` — all files analyzed, before clustering -2. `grouping_complete` — full group manifest (resumable if interrupted) - -```bash -# Query latest checkpoint -curl http://localhost:8105/api/memory/search?q=analyze_beats&category=agent_checkpoint -``` - -### NATS Geometry Bus -After grouping, each constellation is published to the Geometry Bus: - -```json -Subject: pmoves.darkxside.beats.group.v1 -Payload: { "group": "Andante_warm_Deep", "count": 12, "tracks": [...] } -``` - -The `chit_a2ui_bridge.py` consumes these to generate Holographic CHIT Blocks. - -### Glances Live Monitoring (port 61208) -Pushes `analyze_beats.tracks_done=N` events to Glances REST API during extraction -so you can watch GPU/CPU usage in real-time while the analysis runs across the mesh. - -```bash -# Start Glances (if not already running) -glances -w --port 61208 -``` - ---- - -## Full Usage Reference - -```bash -# One-shot: analyze the 82 SoundCloud tracks (sample dataset) -uv run pmoves/tools/analyze_beats.py analyze \ - --input pmoves/data/beats/soundcloud/darkxside \ - --output pmoves/data/beats/playlists \ - --groups 8 \ - --glances http://localhost:61208 - -# Use cached fingerprints (re-cluster only — much faster) -uv run pmoves/tools/analyze_beats.py analyze --cache --groups 12 - -# View groups table -uv run pmoves/tools/analyze_beats.py groups - -# Check Cipher + Glances health -uv run pmoves/tools/analyze_beats.py status -``` - ---- - -## Environment Variables - -```env -BEATS_INPUT=pmoves/data/beats/soundcloud/darkxside -BEATS_OUTPUT=pmoves/data/beats/playlists -NATS_URL=nats://localhost:4222 -CIPHER_URL=http://localhost:8105 -GLANCES_URL=http://localhost:61208 -``` - ---- - -## Cross-Machine Invocation (Tailscale Mesh) - -The analysis is CPU/IO-bound. Delegate to the 5090 node for large archives: - -```bash -# From any machine on pmoves-net via SSH/Tailscale: -ssh 5090 "cd PMOVES.AI && uv run pmoves/tools/analyze_beats.py analyze \ - --input /data/beats/gdrive \ - --output /data/beats/playlists \ - --nats nats://z890:4222 \ ---cipher http://z890:8105" -``` - ---- - -## Agent Registry Entry - -```yaml -agent_id: cipher_beats_analyst -class: Specialized -tier: [5, 6] -cipher_categories: [agent_checkpoint, beats_fingerprint] -nats_subjects: - publish: [pmoves.darkxside.beats.group.v1, media.ingest.request.v1] - subscribe: [] -tool_path: pmoves/tools/analyze_beats.py -runtime: uv run -``` - ---- - -## See Also - -- [`analyze_beats.py`](../../../../pmoves/tools/analyze_beats.py) — the Typer agent -- [`chit_a2ui_bridge.py`](../../../../pmoves/tools/chit_a2ui_bridge.py) — CGP → A2UI visualization -- [`pmoves-holographic-blocks/SKILL.md`](../pmoves-holographic-blocks/SKILL.md) — full beats → CHIT geometry pipeline -- [`AGNOTE4482.BEATS.md`](../../../../pmoves/docs/AGENTS/AGNOTE4482.BEATS.md) — DARKXSIDE audio context -- [`AGENT_RESILIENCE_PATTERNS.md`](../../../../pmoves/docs/AGENTS/AGENT_RESILIENCE_PATTERNS.md) — Cipher checkpoint protocol diff --git a/pbnj/pinokio/api/pmoves-discord-bot/README.md b/pbnj/pinokio/api/pmoves-discord-bot/README.md deleted file mode 100644 index 7a711e9f11..0000000000 --- a/pbnj/pinokio/api/pmoves-discord-bot/README.md +++ /dev/null @@ -1,66 +0,0 @@ -# PMOVES Discord Bot - -CATACLYSM STUDIOS INC community playground bot for Discord. Creates and manages the server structure, routes PMOVES.AI services to channels, and handles agent interactions. - -## What it does - -- **Server Setup**: Creates categories, channels, roles, webhooks from `channel-structure.yaml` -- **Knowledge Search**: `!ask ` routes to Hi-RAG v2 for knowledge retrieval -- **Voice Synthesis**: `!voice ` synthesizes speech via Flute-Gateway (14 TTS engines) -- **Auto-Role**: Assigns "Student" role to new members on join -- **Webhook Routing**: Generates webhook URLs for Publisher-Discord NATS event wiring - -## Usage - -### Via Pinokio -1. Click **Install** to install dependencies -2. Set `DISCORD_BOT_TOKEN` and `DISCORD_GUILD_ID` in environment -3. Click **Setup Server** to create channels/roles (idempotent, safe to re-run) -4. Click **Start Bot** to run the bot - -### Environment Variables -| Variable | Required | Description | -|----------|----------|-------------| -| `DISCORD_BOT_TOKEN` | Yes | Discord bot token (from Discord Developer Portal) | -| `DISCORD_GUILD_ID` | Yes | Discord server ID | - -### API (via Discord commands) - -**JavaScript:** -```js -// Send a message to trigger search -channel.send('!ask What is CHIT?'); - -// Trigger voice synthesis -channel.send('!voice Hello from PMOVES'); -``` - -**Python:** -```python -import requests -# Use Publisher-Discord REST API to read messages -resp = requests.get('http://localhost:8094/channels/{channel_id}/messages') -``` - -**Curl:** -```bash -# Check Publisher-Discord health -curl http://localhost:8094/healthz - -# Read channel messages via REST -curl http://localhost:8094/channels/{channel_id}/messages?limit=10 -``` - -## Channel Structure - -See `app/config/channel-structure.yaml` for the full declarative server layout. - -## Architecture - -``` -Discord Server ← discord.js bot (this app) - ↕ -Publisher-Discord (port 8094) ← NATS events - ↕ -PMOVES Services (Hi-RAG, Flute-Gateway, Agent Zero, etc.) -``` diff --git a/pbnj/pinokio/api/pmoves-discord-bot/app/.gitignore b/pbnj/pinokio/api/pmoves-discord-bot/app/.gitignore deleted file mode 100644 index c2658d7d1b..0000000000 --- a/pbnj/pinokio/api/pmoves-discord-bot/app/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules/ diff --git a/pbnj/pinokio/api/pmoves-discord-bot/app/config/channel-structure.yaml b/pbnj/pinokio/api/pmoves-discord-bot/app/config/channel-structure.yaml deleted file mode 100644 index 696cee287d..0000000000 --- a/pbnj/pinokio/api/pmoves-discord-bot/app/config/channel-structure.yaml +++ /dev/null @@ -1,145 +0,0 @@ -# CATACLYSM STUDIOS INC — Discord Server Structure -# This file drives idempotent server setup via setup.js -# Categories, channels, roles, and NATS event routing - -roles: - - name: DARKXSIDE - color: "#E11D48" - permissions: ["Administrator"] - hoist: true - position: 5 - - name: Faculty - color: "#7C3AED" - permissions: ["ManageChannels", "ManageMessages", "MoveMembers", "MuteMembers"] - hoist: true - position: 4 - - name: Builder - color: "#2563EB" - permissions: ["SendMessages", "ReadMessageHistory", "Connect", "Speak", "AttachFiles"] - hoist: true - position: 3 - - name: Contributor - color: "#059669" - permissions: ["SendMessages", "ReadMessageHistory", "Connect", "Speak", "AttachFiles"] - hoist: true - position: 2 - - name: Student - color: "#6B7280" - permissions: ["SendMessages", "ReadMessageHistory"] - hoist: false - position: 1 - -categories: - - name: WELCOME - min_role: null # public - channels: - - name: welcome - topic: "Welcome to CATACLYSM STUDIOS INC — agent card gallery + onboarding" - type: text - - name: waitlist - topic: "Join the waitlist — email capture for gated access" - type: text - - name: announcements - topic: "Automated feed from PMOVES.AI services" - type: text - webhook: true - nats_subjects: - - "content.published.v1" - - "ingest.summary.ready.v1" - - "ingest.transcript.ready.v1" - - - name: AGENTS - min_role: Student - channels: - - name: agent-trails - topic: "Graphiti signed trails — agent attribution + provenance" - type: text - webhook: true - nats_subjects: - - "agent.graphiti.signed.v1" - - name: agent-cards - topic: "ComfyUI-rendered agent identity cards" - type: text - - name: agent-chat - topic: "Interactive agent — MCP-routed via BoTZ Gateway" - type: text - - name: agent-status - topic: "Service health feed" - type: text - webhook: true - nats_subjects: - - "ops.health.check.v1" - - - name: CREATIVE - min_role: Contributor - channels: - - name: beats-lab - topic: "Upload beats for CHIT analysis + visualization" - type: text - - name: render-lab - topic: "ComfyUI render requests + results" - type: text - webhook: true - nats_subjects: - - "render.complete.v1" - - name: voice-lab - topic: "TTS demos — 14 engines via Flute-Gateway" - type: text - - name: song-lab - topic: "Music generation — ACE-Step + SongGeneration-Studio" - type: text - - - name: RESEARCH - min_role: Contributor - channels: - - name: deep-research - topic: "DeepResearch results + video content reviews" - type: text - webhook: true - nats_subjects: - - "research.deepresearch.result.v1" - - name: knowledge-base - topic: "Hi-RAG query bot — !ask your question" - type: text - - name: cipher-memory - topic: "Agent memory queries + knowledge graph exploration" - type: text - - name: tokenism-lab - topic: "Tokenism simulation results + validated ideas" - type: text - webhook: true - nats_subjects: - - "tokenism.simulation.result.v1" - - "tokenism.cgp.ready.v1" - - - name: BUILDERS - min_role: Builder - channels: - - name: dev-updates - topic: "CI/CD notifications + PR status" - type: text - webhook: true - nats_subjects: - - "ops.pr.monitor.completed.v1" - - name: pinokio-apps - topic: "Launcher links + Pinokio app discovery" - type: text - - name: docker-status - topic: "Container health + deployment status" - type: text - - name: pr-review - topic: "PR monitor + CodeRabbit review threads" - type: text - - - name: VOICE - min_role: Contributor - channels: - - name: agent-voice - topic: "Live agent TTS/STT — voice interaction" - type: voice - - name: beats-room - topic: "Audio playback + beat analysis" - type: voice - - name: research-lab - topic: "Voice-driven research queries" - type: voice diff --git a/pbnj/pinokio/api/pmoves-discord-bot/app/package.json b/pbnj/pinokio/api/pmoves-discord-bot/app/package.json deleted file mode 100644 index 15a865b9ad..0000000000 --- a/pbnj/pinokio/api/pmoves-discord-bot/app/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "pmoves-discord-bot", - "version": "1.0.0", - "description": "CATACLYSM STUDIOS INC community playground bot", - "main": "src/index.js", - "scripts": { - "start": "node src/index.js", - "setup": "node src/setup.js" - }, - "dependencies": { - "discord.js": "^14.16.0", - "js-yaml": "^4.1.0" - } -} diff --git a/pbnj/pinokio/api/pmoves-discord-bot/app/src/config.js b/pbnj/pinokio/api/pmoves-discord-bot/app/src/config.js deleted file mode 100644 index fc08a46e12..0000000000 --- a/pbnj/pinokio/api/pmoves-discord-bot/app/src/config.js +++ /dev/null @@ -1,12 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const yaml = require('js-yaml'); - -const CONFIG_PATH = path.join(__dirname, '..', 'config', 'channel-structure.yaml'); - -function loadConfig() { - const raw = fs.readFileSync(CONFIG_PATH, 'utf8'); - return yaml.load(raw); -} - -module.exports = { loadConfig, CONFIG_PATH }; diff --git a/pbnj/pinokio/api/pmoves-discord-bot/app/src/index.js b/pbnj/pinokio/api/pmoves-discord-bot/app/src/index.js deleted file mode 100644 index 5879e177ff..0000000000 --- a/pbnj/pinokio/api/pmoves-discord-bot/app/src/index.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * PMOVES Discord Bot — CATACLYSM STUDIOS INC community playground. - * Connects to Discord gateway, listens for events, routes to PMOVES services. - */ -const { Client, GatewayIntentBits, Events } = require('discord.js'); - -const TOKEN = process.env.DISCORD_BOT_TOKEN; -const GUILD_ID = process.env.DISCORD_GUILD_ID; - -if (!TOKEN) { - console.error('Set DISCORD_BOT_TOKEN environment variable'); - process.exit(1); -} - -const client = new Client({ - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.MessageContent, - GatewayIntentBits.GuildMembers, - GatewayIntentBits.GuildVoiceStates, - ], -}); - -client.once(Events.ClientReady, (c) => { - // This line is captured by start.js event regex - console.log(`Bot ready as ${c.user.tag}`); - console.log(`Guilds: ${c.guilds.cache.map(g => g.name).join(', ')}`); -}); - -client.on(Events.MessageCreate, async (message) => { - if (message.author.bot) return; - - // !ask command — route to Hi-RAG - if (message.content.startsWith('!ask ')) { - const query = message.content.slice(5).trim(); - if (!query) return; - try { - const resp = await fetch('http://host.docker.internal:8086/hirag/query', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ query, top_k: 5, rerank: true }), - }); - const data = await resp.json(); - const results = (data.results || []).slice(0, 3); - if (results.length === 0) { - await message.reply('No results found.'); - return; - } - const formatted = results.map((r, i) => - `**${i + 1}.** ${r.text?.substring(0, 200) || 'No text'}...` - ).join('\n\n'); - await message.reply(formatted); - } catch (err) { - await message.reply(`Search error: ${err.message}`); - } - } - - // !voice command — route to Flute-Gateway TTS - if (message.content.startsWith('!voice ')) { - const text = message.content.slice(7).trim(); - if (!text) return; - try { - const resp = await fetch('http://host.docker.internal:8055/v1/voice/synthesize/audio', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ text, intent: 'narrate' }), - }); - if (!resp.ok) { - await message.reply(`TTS error: ${resp.status}`); - return; - } - const buffer = Buffer.from(await resp.arrayBuffer()); - await message.reply({ - files: [{ attachment: buffer, name: 'voice.wav' }], - }); - } catch (err) { - await message.reply(`Voice error: ${err.message}`); - } - } -}); - -client.on(Events.GuildMemberAdd, async (member) => { - // Auto-assign Student role on join - try { - const studentRole = member.guild.roles.cache.find(r => r.name === 'Student'); - if (studentRole) { - await member.roles.add(studentRole); - console.log(`Assigned Student role to ${member.user.tag}`); - } - } catch (err) { - console.error(`Failed to assign role: ${err.message}`); - } -}); - -client.login(TOKEN); diff --git a/pbnj/pinokio/api/pmoves-discord-bot/app/src/secure.js b/pbnj/pinokio/api/pmoves-discord-bot/app/src/secure.js deleted file mode 100644 index 39a189e178..0000000000 --- a/pbnj/pinokio/api/pmoves-discord-bot/app/src/secure.js +++ /dev/null @@ -1,153 +0,0 @@ -/** - * Discord server security hardening. - * Configures AutoMod rules, verification level, content filters, and 2FA. - * Idempotent — safe to re-run. - */ -const { - Client, - GatewayIntentBits, - GuildVerificationLevel, - GuildExplicitContentFilter, - GuildDefaultMessageNotifications, - AutoModerationRuleTriggerType, - AutoModerationRuleEventType, - AutoModerationActionType, -} = require('discord.js'); - -const TOKEN = process.env.DISCORD_BOT_TOKEN; -const GUILD_ID = process.env.DISCORD_GUILD_ID; - -if (!TOKEN || !GUILD_ID) { - console.error('Set DISCORD_BOT_TOKEN and DISCORD_GUILD_ID environment variables'); - process.exit(1); -} - -async function main() { - const client = new Client({ intents: [GatewayIntentBits.Guilds] }); - await client.login(TOKEN); - console.log(`Logged in as ${client.user.tag}`); - - const guild = await client.guilds.fetch(GUILD_ID); - console.log(`Guild: ${guild.name}\n`); - - // --- Guild-Level Settings --- - console.log('--- Guild Security Settings ---'); - - await guild.setVerificationLevel(GuildVerificationLevel.High); - console.log(' [set] Verification level: HIGH (must be member for 10 min)'); - - await guild.setExplicitContentFilter(GuildExplicitContentFilter.AllMembers); - console.log(' [set] Explicit content filter: ALL MEMBERS'); - - await guild.setDefaultMessageNotifications(GuildDefaultMessageNotifications.OnlyMentions); - console.log(' [set] Default notifications: ONLY MENTIONS'); - - // --- AutoMod Rules --- - console.log('\n--- AutoMod Rules ---'); - - const existingRules = await guild.autoModerationRules.fetch(); - const ruleNames = existingRules.map(r => r.name); - - // Rule 1: Mention spam protection - if (!ruleNames.includes('PMOVES: Mention Spam')) { - await guild.autoModerationRules.create({ - name: 'PMOVES: Mention Spam', - eventType: AutoModerationRuleEventType.MessageSend, - triggerType: AutoModerationRuleTriggerType.MentionSpam, - triggerMetadata: { - mentionTotalLimit: 5, - mentionRaidProtectionEnabled: true, - }, - actions: [ - { - type: AutoModerationActionType.BlockMessage, - metadata: { customMessage: 'Too many mentions. Please keep it respectful.' }, - }, - { - type: AutoModerationActionType.Timeout, - metadata: { durationSeconds: 300 }, - }, - ], - enabled: true, - reason: 'PMOVES Discord Bot — mention spam protection', - }); - console.log(' [created] Mention Spam (limit: 5, timeout: 5min, raid protection: on)'); - } else { - console.log(' [exists] Mention Spam'); - } - - // Rule 2: Keyword filter (links, scam, phishing patterns) - if (!ruleNames.includes('PMOVES: Link & Scam Filter')) { - await guild.autoModerationRules.create({ - name: 'PMOVES: Link & Scam Filter', - eventType: AutoModerationRuleEventType.MessageSend, - triggerType: AutoModerationRuleTriggerType.Keyword, - triggerMetadata: { - keywordFilter: [ - 'free nitro', - 'steam gift', - 'claim your prize', - 'click here to verify', - 'discord.gg/free', - 'earn money fast', - 'dm me for', - ], - regexPatterns: [ - 'https?://discord\\.gift/[a-zA-Z0-9]+', - 'https?://dis[ck]ord[.-]\\w+\\.\\w+', - ], - allowList: [ - 'discord.gg', - 'github.com', - 'youtube.com', - 'pmoves.ai', - 'cataclysmstudios.com', - ], - }, - actions: [ - { - type: AutoModerationActionType.BlockMessage, - metadata: { customMessage: 'This message was blocked by PMOVES security filters.' }, - }, - ], - enabled: true, - reason: 'PMOVES Discord Bot — scam/phishing protection', - }); - console.log(' [created] Link & Scam Filter (7 keywords, 2 regex, 5 allowlist)'); - } else { - console.log(' [exists] Link & Scam Filter'); - } - - // Rule 3: Discord preset filters (profanity, slurs, sexual content) - if (!ruleNames.includes('PMOVES: Content Moderation')) { - await guild.autoModerationRules.create({ - name: 'PMOVES: Content Moderation', - eventType: AutoModerationRuleEventType.MessageSend, - triggerType: AutoModerationRuleTriggerType.KeywordPreset, - triggerMetadata: { - presets: [1, 2, 3], // Profanity, SexualContent, Slurs - allowList: [], - }, - actions: [ - { - type: AutoModerationActionType.BlockMessage, - metadata: { customMessage: 'Please keep conversations respectful and professional.' }, - }, - ], - enabled: true, - reason: 'PMOVES Discord Bot — content moderation presets', - }); - console.log(' [created] Content Moderation (profanity + sexual + slurs presets)'); - } else { - console.log(' [exists] Content Moderation'); - } - - console.log('\nSecurity hardening complete.'); - client.destroy(); - process.exit(0); -} - -main().catch(err => { - console.error('Security setup failed:', err.message); - process.exit(1); -}); diff --git a/pbnj/pinokio/api/pmoves-discord-bot/app/src/setup.js b/pbnj/pinokio/api/pmoves-discord-bot/app/src/setup.js deleted file mode 100644 index e143a0b616..0000000000 --- a/pbnj/pinokio/api/pmoves-discord-bot/app/src/setup.js +++ /dev/null @@ -1,153 +0,0 @@ -/** - * Idempotent Discord server setup from channel-structure.yaml. - * Creates categories, channels, roles, and webhooks. - * Safe to re-run — skips existing resources. - */ -const { Client, GatewayIntentBits, PermissionFlagsBits, ChannelType } = require('discord.js'); -const { loadConfig } = require('./config'); - -const TOKEN = process.env.DISCORD_BOT_TOKEN; -const GUILD_ID = process.env.DISCORD_GUILD_ID; - -if (!TOKEN || !GUILD_ID) { - console.error('Set DISCORD_BOT_TOKEN and DISCORD_GUILD_ID environment variables'); - process.exit(1); -} - -const PERMISSION_MAP = { - Administrator: PermissionFlagsBits.Administrator, - ManageChannels: PermissionFlagsBits.ManageChannels, - ManageMessages: PermissionFlagsBits.ManageMessages, - MoveMembers: PermissionFlagsBits.MoveMembers, - MuteMembers: PermissionFlagsBits.MuteMembers, - SendMessages: PermissionFlagsBits.SendMessages, - ReadMessageHistory: PermissionFlagsBits.ReadMessageHistory, - Connect: PermissionFlagsBits.Connect, - Speak: PermissionFlagsBits.Speak, - AttachFiles: PermissionFlagsBits.AttachFiles, -}; - -async function main() { - const config = loadConfig(); - const client = new Client({ intents: [GatewayIntentBits.Guilds] }); - - await client.login(TOKEN); - console.log(`Logged in as ${client.user.tag}`); - - const guild = await client.guilds.fetch(GUILD_ID); - console.log(`Guild: ${guild.name} (${guild.id})`); - - // --- Roles --- - console.log('\n--- Roles ---'); - const createdRoles = {}; - for (const roleDef of config.roles || []) { - let role = guild.roles.cache.find(r => r.name === roleDef.name); - if (role) { - console.log(` [exists] ${roleDef.name} (${role.id})`); - createdRoles[roleDef.name] = role; - continue; - } - // Skip roles with Administrator — bot can't create roles above its own - const perms = (roleDef.permissions || []).reduce((acc, p) => { - if (PERMISSION_MAP[p]) acc |= PERMISSION_MAP[p]; - return acc; - }, 0n); - if (perms & PermissionFlagsBits.Administrator) { - console.log(` [skip] ${roleDef.name} (requires Administrator — create manually)`); - continue; - } - try { - // Parse hex color to integer - const colorInt = roleDef.color ? parseInt(roleDef.color.replace('#', ''), 16) : null; - role = await guild.roles.create({ - name: roleDef.name, - color: colorInt, - hoist: roleDef.hoist || false, - permissions: perms, - reason: 'PMOVES Discord Bot setup', - }); - console.log(` [created] ${roleDef.name} (${role.id})`); - createdRoles[roleDef.name] = role; - } catch (err) { - console.log(` [error] ${roleDef.name}: ${err.message}`); - } - } - - // --- Categories + Channels --- - console.log('\n--- Categories & Channels ---'); - const webhookUrls = {}; - - for (const catDef of config.categories || []) { - // Find or create category - let category = guild.channels.cache.find( - c => c.type === ChannelType.GuildCategory && c.name.toUpperCase() === catDef.name.toUpperCase() - ); - if (!category) { - category = await guild.channels.create({ - name: catDef.name, - type: ChannelType.GuildCategory, - reason: 'PMOVES Discord Bot setup', - }); - console.log(` [created] Category: ${catDef.name}`); - } else { - console.log(` [exists] Category: ${catDef.name}`); - } - - // Channels in category - for (const chDef of catDef.channels || []) { - const channelType = chDef.type === 'voice' ? ChannelType.GuildVoice : ChannelType.GuildText; - let channel = guild.channels.cache.find( - c => c.name === chDef.name && c.parentId === category.id - ); - if (!channel) { - const createOpts = { - name: chDef.name, - type: channelType, - parent: category.id, - reason: 'PMOVES Discord Bot setup', - }; - // Voice channels don't support topic - if (channelType !== ChannelType.GuildVoice && chDef.topic) { - createOpts.topic = chDef.topic; - } - channel = await guild.channels.create(createOpts); - console.log(` [created] #${chDef.name} (${channelType === ChannelType.GuildVoice ? 'voice' : 'text'})`); - } else { - console.log(` [exists] #${chDef.name}`); - } - - // Create webhook if needed - if (chDef.webhook && channelType === ChannelType.GuildText) { - const webhooks = await channel.fetchWebhooks(); - let webhook = webhooks.find(w => w.name === 'PMOVES Publisher'); - if (!webhook) { - webhook = await channel.createWebhook({ - name: 'PMOVES Publisher', - reason: 'PMOVES Discord Bot — event routing', - }); - console.log(` [webhook] Created for #${chDef.name}: ${webhook.url.substring(0, 60)}...`); - } else { - console.log(` [webhook] Exists for #${chDef.name}`); - } - webhookUrls[chDef.name] = { - url: webhook.url, - channel_id: channel.id, - nats_subjects: chDef.nats_subjects || [], - }; - } - } - } - - // --- Output webhook mapping --- - console.log('\n--- Webhook Routing Map ---'); - console.log(JSON.stringify(webhookUrls, null, 2)); - - console.log('\nSetup complete.'); - client.destroy(); - process.exit(0); -} - -main().catch(err => { - console.error('Setup failed:', err); - process.exit(1); -}); diff --git a/pbnj/pinokio/api/pmoves-discord-bot/install.js b/pbnj/pinokio/api/pmoves-discord-bot/install.js deleted file mode 100644 index 81cf052c92..0000000000 --- a/pbnj/pinokio/api/pmoves-discord-bot/install.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - run: [{ - method: "shell.run", - params: { - path: "app", - message: ["npm install"] - } - }] -} diff --git a/pbnj/pinokio/api/pmoves-discord-bot/pinokio.js b/pbnj/pinokio/api/pmoves-discord-bot/pinokio.js deleted file mode 100644 index da94651247..0000000000 --- a/pbnj/pinokio/api/pmoves-discord-bot/pinokio.js +++ /dev/null @@ -1,66 +0,0 @@ -module.exports = { - version: "5.0", - title: "PMOVES Discord Bot", - description: "CATACLYSM STUDIOS INC community playground bot", - icon: "icon.png", - menu: async (kernel, info) => { - let installing = info.running("install.js") - let installed = info.exists("app/node_modules") - let running = info.running("start.js") - let settingUp = info.running("setup.js") - - if (installing) { - return [{ - default: true, - icon: "fa-solid fa-plug", - text: "Installing...", - href: "install.js" - }] - } - - if (settingUp) { - return [{ - default: true, - icon: "fa-solid fa-gear", - text: "Setting up server...", - href: "setup.js" - }] - } - - if (installed) { - if (running) { - let local = info.local("start.js") - return [{ - icon: "fa-solid fa-terminal", - text: local && local.bot_name ? `Bot: ${local.bot_name}` : "Terminal", - href: "start.js" - }, { - icon: "fa-solid fa-gear", - text: "Setup Server", - href: "setup.js" - }] - } - return [{ - default: true, - icon: "fa-solid fa-power-off", - text: "Start Bot", - href: "start.js" - }, { - icon: "fa-solid fa-gear", - text: "Setup Server", - href: "setup.js" - }, { - icon: "fa-solid fa-plug", - text: "Reinstall", - href: "install.js" - }] - } - - return [{ - default: true, - icon: "fa-solid fa-plug", - text: "Install", - href: "install.js" - }] - } -} diff --git a/pbnj/pinokio/api/pmoves-discord-bot/pinokio.json b/pbnj/pinokio/api/pmoves-discord-bot/pinokio.json deleted file mode 100644 index 3fa8f10c32..0000000000 --- a/pbnj/pinokio/api/pmoves-discord-bot/pinokio.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "title": "PMOVES Discord Bot", - "description": "CATACLYSM STUDIOS INC community playground bot — org setup, agent routing, NATS event wiring", - "icon": "icon.png", - "gpu": false -} diff --git a/pbnj/pinokio/api/pmoves-discord-bot/setup.js b/pbnj/pinokio/api/pmoves-discord-bot/setup.js deleted file mode 100644 index 8c3cb85e6c..0000000000 --- a/pbnj/pinokio/api/pmoves-discord-bot/setup.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - run: [{ - method: "shell.run", - params: { - path: "app", - message: ["node src/setup.js"] - } - }] -} diff --git a/pbnj/pinokio/api/pmoves-discord-bot/start.js b/pbnj/pinokio/api/pmoves-discord-bot/start.js deleted file mode 100644 index 9e62b53091..0000000000 --- a/pbnj/pinokio/api/pmoves-discord-bot/start.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - daemon: true, - run: [{ - method: "shell.run", - params: { - path: "app", - message: ["node src/index.js"], - on: [{ - event: "/Bot ready as (.+)/", - done: true - }] - } - }, { - method: "local.set", - params: { - bot_name: "{{input.event[1]}}" - } - }] -} diff --git a/pbnj/pinokio/api/pmoves-holographic-blocks/SKILL.md b/pbnj/pinokio/api/pmoves-holographic-blocks/SKILL.md deleted file mode 100644 index 9cc06a38c0..0000000000 --- a/pbnj/pinokio/api/pmoves-holographic-blocks/SKILL.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -name: PMOVES Holographic Blocks -description: | - Quantize DARKXSIDE audio beats into Holographic CHIT Geometric Blocks via the Gemini - multimodal embedding pipeline. Embeds raw .wav/.mp3 files as multi-dimensional topological - arrays on the geometry.cgp.v1 bus, transpiles them to A2UI animation specs for Remotion, - and optionally feeds the geometry into Unsloth or PMOVES-autoresearch for model fine-tuning. -keywords: chit, geometry, beats, audio, holographic, multimodal, gemini, unsloth, autoresearch, hi-rag, a2ui -version: 1.0.0 -category: Media/AI/Geometry ---- - -# PMOVES Holographic Blocks - -**Category**: Media/AI/Geometry -**Version**: 1.0.0 -**Status**: Phase 11 — Active Development -**Aligns With**: DARKXSIDE / Cataclysm Studios Three-Entity Doctrine - -## Overview - -Transforms mathematically engineered audio (beats, scales, BPM, EQ, compression topology) -from the DARKXSIDE archive into reusable **Holographic CHIT Geometric Blocks** stored in -the Neo4j/Supabase ShapeStore. - -The pipeline is: -```text -Audio File (.wav/.mp3) - → Gemini Multimodal Embedding (Hi-RAG) - → geometry.cgp.v1 NATS event (Holographic Block) - → ShapeStore (Neo4j + Supabase) - → chit_a2ui_bridge.py (A2UI spec) - → Remotion Renderer (a2ui-renderer) [optional: visual proof] - → Unsloth fine-tune OR autoresearch seed [optional: model builder] -``` - -These geometric blocks are **structural** — not decorative. Agents (Agent Zero, Gemini CLI) -can read them as foundational topology for UI construction, smart contract flows, or DAO -proposal scaffolding. - -## Capabilities - -- Ingest a single `.wav` or `.mp3` file and emit a `geometry.cgp.v1` Holographic Block to NATS -- Batch-ingest a folder of beats (e.g., Google Drive archive) -- Transpile an existing CGP block into an `a2ui.animation.v1` spec via `chit_a2ui_bridge.py` -- Push CGP constellations into Unsloth for audio-geometry model fine-tuning -- Seed PMOVES-autoresearch with block coordinates for hypothesis generation - -## Trigger Phrases - -| Natural Language Phrase | Action | Script | -|-------------------------|--------|--------| -| "ingest beat [file]" | Embed single .wav/.mp3 → ShapeStore | `ingest-beat.js` | -| "ingest beats folder [path]" | Batch embed folder → ShapeStore | `ingest-batch.js` | -| "visualize block [block_id]" | CGP block → A2UI spec | `visualize-block.js` | -| "tune unsloth with beats" | Feed ShapeStore coords → Unsloth | `unsloth-geotune.js` | -| "seed autoresearch with beats" | Feed coords → autoresearch | `autoresearch-seed.js` | -| "list holographic blocks" | Query ShapeStore for existing CGPs | `list-blocks.js` | - -## Mathematical Geometry Mapping - -Each beat is decomposed along these axes before embedding: - -| Audio Feature | Geometric Axis | CGP Property | -|--------------------|---------------|----------------------| -| BPM / Tempo | Phase velocity | `geometry.delta` | -| Root Scale / Key | Topology class | `anchors[].coords.x` | -| Emotional register | Curvature κ | `geometry.kappa` | -| EQ high-shelf dB | Spectral freq | `spectral_signatures[].frequency_hz` | -| Compression ratio | Amplitude ρ | `spectral_signatures[].amplitude` | -| Timbre character | Holographic signature | `metadata.timbre_vector` | - -> A sad scale at 60 BPM produces a different geometric knot than the same scale at 120 BPM. -> Both are valid, distinct, reusable building blocks. - -## API Endpoints Required - -| Service | Endpoint | Purpose | -|---------|----------|---------| -| Hi-RAG v2 GPU | `http://localhost:8087/hirag/ingest/audio` | Multimodal embedding | -| NATS | `nats://localhost:4222` | Publish `geometry.cgp.v1` | -| Supabase | `http://host.docker.internal:65421/rest/v1` | ShapeStore persistence | -| Neo4j | `bolt://localhost:7687` | Constellation graph storage | - -## Environment Variables Required - -```env -HI_RAG_GPU_URL=http://localhost:8087 -NATS_URL=nats://nats:pmoves@localhost:4222 -SUPABASE_URL=http://host.docker.internal:65421 -SUPABASE_SERVICE_ROLE_KEY= -NEO4J_URL=bolt://localhost:7687 -NEO4J_PASSWORD= -CHIT_PROD_PASSPHRASE= -``` - -## Cross-Machine Access (Tailscale Mesh) - -The Gemini CLI Pinokio instance on any machine in the mesh can run this skill: -```text -5090 (GPU embed): http://100.x.x.x:8087/hirag/ingest/audio -z890 (Neo4j): bolt://100.x.x.x:7687 -4090 (orchestrate): Runs Gemini CLI → invokes skill via P7 Interpreter -``` - -## Integration Points - -- **NATS Subject**: `geometry.cgp.v1` (emit), `geometry.visualization.request.v1` (visualize) -- **A2UI Bridge**: `pmoves/tools/chit_a2ui_bridge.py` -- **ShapeStore**: Supabase `pmoves_core.chit_shapes` table + Neo4j `(:CHITBlock)` nodes -- **Unsloth Fine-tune**: Feeds `(bpm, scale_root, kappa, amplitude)` tuples as training geometry - -## See Also - -- [`chit_a2ui_bridge.py`](../../../../pmoves/tools/chit_a2ui_bridge.py) -- [`AGNOTE4482.BEATS.md`](../../../../pmoves/docs/AGENTS/AGNOTE4482.BEATS.md) -- [`CATACLYSM_STUDIOS_INC.md`](../../../../pmoves/docs/PMOVESCHIT/CATACLYSM_STUDIOS_INC.md) -- [`botz-skills.md`](../../../../pmoves/docs/geometry-bus/services/botz-skills.md) -- [`pmoves-services/SKILL.md`](../pmoves-services/SKILL.md) diff --git a/pbnj/pinokio/api/pmoves-model-registry/SKILL.md b/pbnj/pinokio/api/pmoves-model-registry/SKILL.md deleted file mode 100644 index f971e070d9..0000000000 --- a/pbnj/pinokio/api/pmoves-model-registry/SKILL.md +++ /dev/null @@ -1,134 +0,0 @@ ---- -name: PMOVES Model Registry -description: | - Query, discover, and enrich the PMOVES.AI model catalog. Manages all AI model - metadata (LLM, embedding, TTS, vision), HuggingFace enrichment, TensorZero - TOML config export, and GPU deployment tracking across the fleet. -keywords: models, registry, catalog, embedding, llm, tensorzero, huggingface, gpu, deployment, discovery -version: 1.0.0 -category: Infrastructure/AI -tier: 1 -agent_class: Standard -agent_id: pmoves_model_registry ---- - -# PMOVES Model Registry - -**Agent Class**: `Standard (Pmoves-)` -**Category**: Infrastructure/AI -**Version**: 1.0.0 -**Tier**: 1 (Core Infrastructure) -**Status**: Active — Supabase-backed model catalog + HuggingFace enrichment -**Port**: 8110 - ---- - -## Capabilities - -| Command | What It Does | -|---------|-------------| -| `list-models` | List all active models with optional type/provider filter | -| `get-model` | Get detailed metadata for a single model by ID | -| `enrich-hf` | Fetch dimensions, tags, CUDA support from HuggingFace API | -| `enrich-hf-bulk` | Batch-enrich all models that have hf_id in metadata | -| `export-tensorzero` | Generate TensorZero TOML config from catalog | -| `list-deployments` | Show active GPU model deployments across fleet | -| `register-deployment` | Register/update a model deployment (GPU Orchestrator) | -| `service-models` | List models mapped to a specific service | - ---- - -## Trigger Phrases (Pinokio 7 Interpreter) - -| Phrase | Action | Endpoint | -|--------|--------|----------| -| `"list available models"` | Show full model catalog | `GET /api/models` | -| `"show embedding models"` | Filter catalog by type | `GET /api/models?model_type=embedding` | -| `"show LLM models"` | Filter catalog by type | `GET /api/models?model_type=llm` | -| `"get model details for [id]"` | Single model lookup | `GET /api/models/{id}` | -| `"enrich model from huggingface"` | Fetch HF metadata + dimensions | `POST /api/models/{id}/enrich-hf` | -| `"enrich all embedding models"` | Batch HF enrichment | `POST /api/models/enrich-hf-bulk` | -| `"export tensorzero config"` | Download TensorZero TOML | `GET /api/tensorzero/config` | -| `"show GPU deployments"` | List active model deployments | `GET /api/deployments` | -| `"which models are on 5090"` | Filter deployments by node | `GET /api/deployments?node_id=5090` | -| `"what models does hi-rag use"` | Service-specific model lookup | `GET /api/services/hi-rag/models` | - ---- - -## API Reference - -### Model Catalog - -```bash -# List all models -curl http://localhost:8110/api/models - -# Filter by type (embedding, llm, tts, vision, audio) -curl http://localhost:8110/api/models?model_type=embedding - -# Filter by provider (ollama, openai, anthropic, venice) -curl http://localhost:8110/api/models?provider=ollama - -# Get single model -curl http://localhost:8110/api/models/{model_id} - -# Models for a service -curl http://localhost:8110/api/services/hi-rag/models -``` - -### HuggingFace Enrichment - -```bash -# Enrich a single model (requires metadata.hf_id set) -curl -X POST http://localhost:8110/api/models/{model_id}/enrich-hf - -# Batch-enrich all embedding models -curl -X POST http://localhost:8110/api/models/enrich-hf-bulk?model_type=embedding -``` - -### TensorZero Config Export - -```bash -# Generate TOML config from catalog -curl http://localhost:8110/api/tensorzero/config -o tensorzero.toml -``` - -### GPU Deployments - -```bash -# List active deployments -curl http://localhost:8110/api/deployments - -# Filter by node -curl http://localhost:8110/api/deployments?node_id=5090 - -# Filter by status -curl http://localhost:8110/api/deployments?status=loaded -``` - ---- - -## Health Check - -```bash -curl http://localhost:8110/healthz -# → {"status": "healthy", "timestamp": "...", "services": {"supabase": "...", "nats": "..."}} -``` - ---- - -## Integration Points - -- **Supabase** — `pmoves_core.models`, `pmoves_core.model_service_mapping`, `pmoves_core.v_active_deployments` -- **NATS** — Publishes `model.registry.updated.v1` on catalog mutations (model enriched, deployment registered) -- **GPU Orchestrator** — Calls `POST /api/deployments` when models are loaded/unloaded on GPU nodes -- **TensorZero Gateway** — Consumes exported TOML config for model provider routing -- **HuggingFace API** — Fetches model cards, config.json for embedding dimensions, tags, CUDA support - ---- - -## Prerequisites - -- Supabase running with `pmoves_core` schema seeded -- NATS message bus at port 4222 (optional — catalog changes still work without NATS) -- HuggingFace API accessible (no auth required for public models) diff --git a/pbnj/pinokio/api/pmoves-model-selector/.gitignore b/pbnj/pinokio/api/pmoves-model-selector/.gitignore deleted file mode 100644 index 9f55c87db0..0000000000 --- a/pbnj/pinokio/api/pmoves-model-selector/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -logs/ -llama.cpp-rdna4-gfx1201/ -models/ diff --git a/pbnj/pinokio/api/pmoves-model-selector/README.md b/pbnj/pinokio/api/pmoves-model-selector/README.md deleted file mode 100644 index 2b8cc21e61..0000000000 --- a/pbnj/pinokio/api/pmoves-model-selector/README.md +++ /dev/null @@ -1,144 +0,0 @@ -# PMOVES Model Selector (Pinokio launcher) - -A **UI over the live PMOVES model plane** — it does not embed any model ids. It -reads the model catalog from the registry and gpu-orchestrator APIs at runtime, -lets you pick a model, and drives load/unload through the gpu-orchestrator. It -also launches a local **GGUF serving lane** (`llama-server`, gfx1201/RDNA4 fork) -on the fixed port **8090**, which TensorZero consumes as the `llamacpp_rocm` -provider. - -> No hardcoded model ids live anywhere in this launcher. Every model that -> appears in a picker comes from an API response evaluated at click time. - -## What it does - -| Menu item | Script | Effect | -|-----------|--------|--------| -| Install (build llama.cpp gfx1201) | `install.js` | Clone `tlee933/llama.cpp-rdna4-gfx1201`, `cmake -B build -DGGML_HIP=ON -DAMDGPU_TARGETS=gfx1201`, build `llama-server`. Optional operator-supplied `hf.download` (never a default id). | -| Start llama-server (GGUF, :8090) | `start.js` | `filepicker` a `*.gguf`, then serve it with `HIP_VISIBLE_DEVICES=0,1 llama-server --host 127.0.0.1 --port 8090 --tensor-split 0.5,0.5`. Captures the http URL. | -| Select & Load Model | `select-model.js` | GET registry `:8110/api/models` + gpu-orchestrator `:8200/api/gpu/models` → `input` select picker → POST `:8200/api/gpu/models/load`. | -| Unload Model | `select-model.js` (`action: unload`) | GET `:8200/api/gpu/models/loaded` → picker → POST `:8200/api/gpu/models/unload/{provider}/{model_id}`. | -| Update / Reset | `update.js` / `reset.js` | Rebuild / remove the gfx1201 fork. Downloaded `models/` are left untouched. | - -## API contract - -``` -registry GET http://127.0.0.1:8110/api/models - → { "items": [ { "model_id": "...", "provider_type": "...", ... } ] } -gpu-orchestrator GET http://127.0.0.1:8200/api/gpu/models - → { "loaded": [...], "registry": [ { "id": "...", "provider": "..." } ] } -gpu-orchestrator GET http://127.0.0.1:8200/api/gpu/models/loaded → { "models": [...] } -gpu-orchestrator POST http://127.0.0.1:8200/api/gpu/models/load body { "model_id": "...", "provider": "..." } -gpu-orchestrator POST http://127.0.0.1:8200/api/gpu/models/unload/{provider}/{model_id} -llama-server (GGUF) GET http://127.0.0.1:8090/v1/models → TensorZero `llamacpp_rocm` provider (http://:8090/v1) -``` - -The picker builds each option's value as `{"provider": ..., "model_id": ...}`. -For registry entries the loadable id is `model_id` (e.g. `qwen3-coder:30b`), **not** -the catalog UUID `id`; for gpu-orchestrator registry entries it is `id`. Items -are deduped on `provider/model_id`. - -### Intentional fixed port 8090 (exception to `{{port}}`) - -The Pinokio best-practice is to allocate `{{port}}` to avoid conflicts. This -launcher **intentionally pins 8090** because: - -- TensorZero's `llamacpp_rocm` provider is configured for `http://:8090/v1` - (`pmoves/tensorzero/config/tensorzero.toml`), so the serving port cannot float. -- Port 8080 is reserved fleet-wide for Agent Zero (`HERMES_AGENT_INTEGRATION.md`), - which is why the GGUF lane moved to 8090. - -This is the documented deviation from the `{{port}}` convention. - -## Usage examples - -### curl - -```bash -# What can I load? -curl -s http://127.0.0.1:8110/api/models | jq '.items[] | {model_id, provider_type}' -curl -s http://127.0.0.1:8200/api/gpu/models | jq '{loaded, registry}' - -# Load / unload -curl -s -X POST http://127.0.0.1:8200/api/gpu/models/load \ - -H 'content-type: application/json' \ - -d '{"model_id":"qwen3-coder:30b","provider":"ollama"}' -curl -s -X POST http://127.0.0.1:8200/api/gpu/models/unload/ollama/qwen3-coder:30b - -# GGUF lane (once start.js is running) -curl -s http://127.0.0.1:8090/v1/models -``` - -### Python - -```python -import requests - -catalog = requests.get("http://127.0.0.1:8110/api/models").json()["items"] -pick = catalog[0] # choose interactively in real use — never hardcode -requests.post( - "http://127.0.0.1:8200/api/gpu/models/load", - json={"model_id": pick["model_id"], "provider": pick["provider_type"]}, -) -``` - -### JavaScript - -```js -const catalog = (await (await fetch("http://127.0.0.1:8110/api/models")).json()).items; -const pick = catalog[0]; // choose interactively — never hardcode -await fetch("http://127.0.0.1:8200/api/gpu/models/load", { - method: "POST", - headers: { "content-type": "application/json" }, - body: JSON.stringify({ model_id: pick.model_id, provider: pick.provider_type }), -}); -``` - -## Post-merge operator step (live symlink) - -This launcher currently lives inside a temporary git worktree, so a symlink from -`~/pinokio/api/` would dangle. **After this branch merges to `main`**, the operator -should create the live link from the canonical repo checkout: - -```bash -# Replace /path/to/your/checkout with wherever this repo is cloned on the operator machine. -ln -sfn /path/to/your/checkout/pbnj/pinokio/api/pmoves-model-selector \ - "$HOME/pinokio/api/pmoves-model-selector" -``` - -## Launcher conformance (exit-checklist confirmations) - -Mirrored against `/home/pmoves-knuckles/pinokio/prototype/system/examples/mochi/start.js` -and `.claude/PINOKIO_LAUNCHER_GUIDE.md`: - -- **URL capture (guide "Critical Pattern Lock" + mochi lines 21-40):** `start.js` - step 3 uses `on: [{ event: "/(http:\\/\\/[0-9.:]+)/", done: true }]`, and step 4 - sets `local.set { url: "{{input.event[1]}}" }` — the mandated pattern exactly. -- **Example lock-in:** `start.js`'s `daemon: true` + `shell.run` + capture + `local.set` - shape mirrors mochi `start.js` lines 1-42; the sibling `pbnj/.../pmoves-agent-zero/start.js` - (lines using `event: "/(http:\\/\\/[0-9.:]+)/"` + `{{input.event[1]}}`) was the - in-repo cross-check. -- **Dynamic menu (guide best-practice #7):** `pinokio.js` returns menu items from - `info.exists(...)` / `info.running(...)` / `info.local("start.js")`, mirroring - `pmoves-agent-zero/pinokio.js`; `default: true` set on the active step. -- **AI bundle (guide "AI Libraries"):** `install.js` declares `requires: { bundle: "ai" }` - so ROCm/HIP prerequisites install before the build. -- **`{{port}}` exception:** documented above — 8090 is pinned by TensorZero. -- **No hardcoded models:** verified — every picker item is derived from a live API - response; the merge logic was unit-checked against the real `:8110/api/models` - payload and yields `{provider:"ollama", model_id:"qwen3-coder:30b"}`. -- **Cross-platform note:** the GGUF/ROCm build is Linux-only (gfx1201/AMD), so - `pinokio.json` declares `"platform": ["linux"]`. The select/load/unload UI is - transport-only and portable. - -## Smoke results (recorded at author time, honest) - -- `registry :8110` — container `pmoves-model-registry-1` **Up (healthy)** but its - port is **not published to the host** in the current compose run - (`8110/tcp`, no host mapping). Verified in-container: `/healthz` → `{"status":"healthy"}`, - `/api/models` → `{"items":[{"model_id":"qwen3-coder:30b","provider_type":"ollama",...}]}` - (1 model; catalog being populated in parallel). -- `gpu-orchestrator :8200` — **down** (no container running); load/unload round-trip - not exercised. -- `llama-server :8090` — **down** (fork not yet built; the long GPU build was - intentionally not run — `install.js` only encodes it). diff --git a/pbnj/pinokio/api/pmoves-model-selector/icon.svg b/pbnj/pinokio/api/pmoves-model-selector/icon.svg deleted file mode 100644 index bfba1dc706..0000000000 --- a/pbnj/pinokio/api/pmoves-model-selector/icon.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/pbnj/pinokio/api/pmoves-model-selector/install.js b/pbnj/pinokio/api/pmoves-model-selector/install.js deleted file mode 100644 index a33b3eaea2..0000000000 --- a/pbnj/pinokio/api/pmoves-model-selector/install.js +++ /dev/null @@ -1,70 +0,0 @@ -// install.js — build llama.cpp (gfx1201 / RDNA4 fork) with HIP for the GGUF lane. -// No model downloads by default: models arrive via the registry / gpu-orchestrator. -// An optional hf.download step exists but ONLY runs when the operator supplies a -// repo id at the prompt — there is never a hardcoded/default model id. -module.exports = { - requires: { - // Triggers Pinokio's machine-level AI prerequisites (ROCm/HIP toolchain, hf CLI). - bundle: "ai" - }, - run: [ - // 1) Clone the gfx1201 RDNA4 fork (skip if already present). - { - method: "shell.run", - when: "{{!exists('llama.cpp-rdna4-gfx1201')}}", - params: { - message: [ - "git clone https://github.com/tlee933/llama.cpp-rdna4-gfx1201" - ] - } - }, - // 2) Configure + build with HIP for gfx1201. - { - method: "shell.run", - params: { - path: "llama.cpp-rdna4-gfx1201", - message: [ - "cmake -B build -DGGML_HIP=ON -DAMDGPU_TARGETS=gfx1201 -DCMAKE_BUILD_TYPE=Release", - "cmake --build build --config Release -j" - ] - } - }, - // 3) OPTIONAL: pull a GGUF from HuggingFace. Leave the repo id blank to skip. - // The id comes entirely from operator input — no default is ever assumed. - { - method: "input", - params: { - title: "Optional: download a GGUF from HuggingFace", - description: "Leave blank to skip. Models normally arrive via the registry / gpu-orchestrator.", - form: [{ - key: "hf_repo", - title: "HF repo id", - description: "e.g. TheBloke/Some-Model-GGUF (blank = skip)", - placeholder: "", - default: "" - }, { - key: "hf_file", - title: "GGUF filename (optional)", - description: "Specific *.gguf file inside the repo (blank = whole repo)", - placeholder: "", - default: "" - }] - } - }, - { - method: "hf.download", - when: "{{input.hf_repo && input.hf_repo.trim().length > 0}}", - params: { - path: "models", - _: "{{input.hf_file && input.hf_file.trim().length > 0 ? [input.hf_repo.trim(), input.hf_file.trim()] : [input.hf_repo.trim()]}}", - "local-dir": "{{input.hf_repo.trim().split('/').pop()}}" - } - }, - { - method: "notify", - params: { - html: "llama.cpp (gfx1201) built. Start the llama-server GGUF lane on :8090, or use Select & Load Model to drive the registry / gpu-orchestrator." - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-model-selector/pinokio.js b/pbnj/pinokio/api/pmoves-model-selector/pinokio.js deleted file mode 100644 index af53900711..0000000000 --- a/pbnj/pinokio/api/pmoves-model-selector/pinokio.js +++ /dev/null @@ -1,111 +0,0 @@ -module.exports = { - version: "5.0", - title: "PMOVES Model Selector", - description: "UI over the model-registry (:8110) + gpu-orchestrator (:8200) APIs, plus a gfx1201 llama-server GGUF lane on :8090. No hardcoded models.", - icon: "icon.svg", - menu: async (kernel, info) => { - // "Installed" == the gfx1201 llama.cpp fork has been cloned + built. - let built = info.exists("llama.cpp-rdna4-gfx1201/build/bin/llama-server") - - let running = { - install: info.running("install.js"), - start: info.running("start.js"), - select: info.running("select-model.js"), - reset: info.running("reset.js"), - update: info.running("update.js") - } - - if (running.install) { - return [{ - default: true, - icon: "fa-solid fa-hammer", - text: "Building llama.cpp (gfx1201)...", - href: "install.js" - }] - } - if (running.reset) { - return [{ - default: true, - icon: "fa-solid fa-broom", - text: "Resetting...", - href: "reset.js" - }] - } - if (running.update) { - return [{ - default: true, - icon: "fa-solid fa-arrows-rotate", - text: "Updating...", - href: "update.js" - }] - } - - // The select/load + unload UI is always available (it only needs the - // registry :8110 / gpu-orchestrator :8200 services, not the local build). - let selectItems = [{ - icon: "fa-solid fa-layer-group", - text: "Select & Load Model", - href: "select-model.js" - }, { - icon: "fa-solid fa-eject", - text: "Unload Model", - href: "select-model.js", - params: { action: "unload" } - }] - - if (!built) { - return [{ - default: true, - icon: "fa-solid fa-hammer", - text: "Install (build llama.cpp gfx1201)", - href: "install.js" - }].concat(selectItems, [{ - icon: "fa-solid fa-book", - text: "gpu-orchestrator loaded models", - href: "http://127.0.0.1:8200/api/gpu/models/loaded" - }, { - icon: "fa-solid fa-list", - text: "registry catalog (:8110)", - href: "http://127.0.0.1:8110/api/models" - }]) - } - - let local = info.local("start.js") - let uiUrl = local && local.url ? local.url : "http://127.0.0.1:8090" - - let items = [{ - default: true, - icon: running.start ? "fa-solid fa-terminal" : "fa-solid fa-play", - text: running.start ? "llama-server Terminal (:8090)" : "Start llama-server (GGUF, :8090)", - href: "start.js" - }, { - icon: "fa-solid fa-globe", - text: "Open llama-server UI", - href: uiUrl - }, { - icon: "fa-solid fa-diagram-project", - text: "llama-server /v1/models", - href: "http://127.0.0.1:8090/v1/models" - }] - .concat(selectItems) - .concat([{ - icon: "fa-solid fa-book", - text: "gpu-orchestrator loaded models", - href: "http://127.0.0.1:8200/api/gpu/models/loaded" - }, { - icon: "fa-solid fa-list", - text: "registry catalog (:8110)", - href: "http://127.0.0.1:8110/api/models" - }, { - icon: "fa-solid fa-arrows-rotate", - text: "Update", - href: "update.js" - }, { - icon: "fa-solid fa-broom", - text: "Reset (remove build)", - href: "reset.js" - }]) - - return items - } -} diff --git a/pbnj/pinokio/api/pmoves-model-selector/pinokio.json b/pbnj/pinokio/api/pmoves-model-selector/pinokio.json deleted file mode 100644 index 227a5b7d42..0000000000 --- a/pbnj/pinokio/api/pmoves-model-selector/pinokio.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "title": "PMOVES Model Selector", - "description": "UI over the PMOVES model-registry (:8110) + gpu-orchestrator (:8200) APIs, plus a gfx1201 llama-server GGUF lane on :8090. No hardcoded models.", - "icon": "icon.svg", - "platform": ["linux"] -} diff --git a/pbnj/pinokio/api/pmoves-model-selector/reset.js b/pbnj/pinokio/api/pmoves-model-selector/reset.js deleted file mode 100644 index 0d15572762..0000000000 --- a/pbnj/pinokio/api/pmoves-model-selector/reset.js +++ /dev/null @@ -1,21 +0,0 @@ -// reset.js — remove the built llama.cpp fork so install.js rebuilds from scratch. -// Does NOT touch downloaded models under models/ (those come from the registry). -module.exports = { - run: [ - { - method: "shell.run", - params: { - message: [ - "rm -rf llama.cpp-rdna4-gfx1201" - ] - } - }, - { - method: "notify", - params: { - html: "llama.cpp (gfx1201) build removed. Run Install to clone + rebuild.", - type: "warning" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-model-selector/select-model.js b/pbnj/pinokio/api/pmoves-model-selector/select-model.js deleted file mode 100644 index 170078d747..0000000000 --- a/pbnj/pinokio/api/pmoves-model-selector/select-model.js +++ /dev/null @@ -1,129 +0,0 @@ -// select-model.js — the model-selection UI. Pure UI over the live APIs: -// registry GET http://127.0.0.1:8110/api/models -// gpu-orchestrator GET http://127.0.0.1:8200/api/gpu/models (loaded + registry known) -// gpu-orchestrator POST http://127.0.0.1:8200/api/gpu/models/load {model_id, provider} -// gpu-orchestrator POST http://127.0.0.1:8200/api/gpu/models/unload/{provider}/{model_id} -// -// The gpu-orchestrator router is mounted under APIRouter(prefix="/api/gpu") -// (pmoves/services/gpu-orchestrator/api/routes.py), so every gpu-orchestrator -// URL below is prefixed with /api/gpu. -// -// There are NO hardcoded model ids anywhere: the picker is built entirely from -// the API responses at runtime. Both services must be reachable for the load -// flow (the launcher is a thin UI, not a cache). -// -// Invoke from pinokio.js: -// { href: "select-model.js" } -> load flow (default) -// { href: "select-model.js", params: { action: "unload" } } -> unload flow -module.exports = { - run: [ - // ================= LOAD FLOW (default) ================= - { - method: "net", - when: "{{args.action != 'unload'}}", - params: { url: "http://127.0.0.1:8200/api/gpu/models", method: "get" } - }, - { - method: "local.set", - when: "{{args.action != 'unload'}}", - params: { gpu_models: "{{input}}" } - }, - { - method: "net", - when: "{{args.action != 'unload'}}", - params: { url: "http://127.0.0.1:8110/api/models", method: "get" } - }, - { - method: "local.set", - when: "{{args.action != 'unload'}}", - params: { registry_models: "{{input}}" } - }, - { - method: "input", - when: "{{args.action != 'unload'}}", - params: { - title: "Load a model", - description: "Pick a model to load via the gpu-orchestrator (:8200). List is built live from :8200/api/gpu/models + registry :8110.", - form: [{ - type: "select", - key: "selection", - title: "Model (provider/model_id)", - // Merge gpu-orchestrator (registry + loaded) with the registry :8110 - // catalog, dedupe on provider/model_id, carry a JSON {provider,model_id} - // value so the load POST needs no hardcoded ids. - items: "{{ (() => { const seen={}; const out=[]; const push=(id,prov,tag)=>{ if(!id) return; prov=prov||'ollama'; const k=prov+'/'+id; if(seen[k]) return; seen[k]=1; out.push({ text:k+(tag?' '+tag:''), value:JSON.stringify({provider:prov,model_id:id}) }); }; const g=local.gpu_models||{}; (g.registry||[]).forEach(m=>push(m.id||m.model_id, m.provider, m.vram_mb?('['+m.vram_mb+'MB]'):'')); (g.loaded||[]).forEach(m=>push(m.id||m.model_id||m.model_key, m.provider, '[loaded]')); const r=local.registry_models; const rl=Array.isArray(r)?r:((r&&(r.items||r.models||r.data))||[]); rl.forEach(m=>push(m.model_id||m.id||m.name, m.provider_type||m.provider, '(catalog)')); return out.length?out:[{text:'(no models reachable — is registry :8110 / gpu-orchestrator :8200 up?)', value:'{}'}]; })() }}" - }] - } - }, - { - method: "local.set", - when: "{{args.action != 'unload'}}", - params: { sel: "{{JSON.parse(input.selection)}}" } - }, - { - method: "net", - when: "{{args.action != 'unload'}}", - params: { - url: "http://127.0.0.1:8200/api/gpu/models/load", - method: "post", - data: { - model_id: "{{local.sel.model_id}}", - provider: "{{local.sel.provider}}" - } - } - }, - { - method: "notify", - when: "{{args.action != 'unload'}}", - params: { - html: "Load requested: {{local.sel.provider}}/{{local.sel.model_id}} — {{input.message || 'queued'}}" - } - }, - - // ================= UNLOAD FLOW ================= - { - method: "net", - when: "{{args.action == 'unload'}}", - params: { url: "http://127.0.0.1:8200/api/gpu/models/loaded", method: "get" } - }, - { - method: "local.set", - when: "{{args.action == 'unload'}}", - params: { loaded_models: "{{input}}" } - }, - { - method: "input", - when: "{{args.action == 'unload'}}", - params: { - title: "Unload a model", - description: "Pick a currently-loaded model to unload (gpu-orchestrator :8200).", - form: [{ - type: "select", - key: "usel", - title: "Loaded model (provider/model_id)", - items: "{{ (() => { const out=[]; const r=local.loaded_models; const ll=Array.isArray(r)?r:((r&&(r.models||r.loaded))||[]); ll.forEach(m=>{ const id=m.id||m.model_id||m.model_key; const prov=m.provider||'ollama'; if(!id) return; out.push({ text:prov+'/'+id, value:JSON.stringify({provider:prov,model_id:id}) }); }); return out.length?out:[{text:'(no loaded models — nothing to unload)', value:'{}'}]; })() }}" - }] - } - }, - { - method: "local.set", - when: "{{args.action == 'unload'}}", - params: { sel: "{{JSON.parse(input.usel)}}" } - }, - { - method: "net", - when: "{{args.action == 'unload'}}", - params: { - url: "http://127.0.0.1:8200/api/gpu/models/unload/{{encodeURIComponent(local.sel.provider)}}/{{encodeURIComponent(local.sel.model_id)}}", - method: "post" - } - }, - { - method: "notify", - when: "{{args.action == 'unload'}}", - params: { - html: "Unload requested: {{local.sel.provider}}/{{local.sel.model_id}} — {{input.message || 'done'}}" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-model-selector/start.js b/pbnj/pinokio/api/pmoves-model-selector/start.js deleted file mode 100644 index 5e3364e3a7..0000000000 --- a/pbnj/pinokio/api/pmoves-model-selector/start.js +++ /dev/null @@ -1,55 +0,0 @@ -// start.js — GGUF lane: launch the gfx1201 llama-server on the fixed port 8090. -// -// Port 8090 is INTENTIONALLY fixed (not {{port}}): the TensorZero `llamacpp_rocm` -// provider pins http://:8090/v1, and 8080 is reserved for Agent Zero -// fleet-wide. This is the documented exception to the {{port}} convention -// (see README "Intentional fixed port" + PINOKIO guide best-practice #1). -// -// Model path: selected via filepicker over models/ (the registry/gpu-orchestrator -// fallback). URL capture mirrors prototype/system/examples/mochi/start.js lines -// 21-40 and the PINOKIO_LAUNCHER_GUIDE "Critical Pattern Lock". -module.exports = { - daemon: true, - run: [ - { - method: "filepicker.open", - params: { - title: "Select a GGUF model file to serve", - type: "file", - path: "models", - filetypes: [["GGUF models", "*.gguf"]] - } - }, - { - method: "local.set", - params: { - model_path: "{{input.paths[0]}}" - } - }, - { - method: "shell.run", - params: { - path: "llama.cpp-rdna4-gfx1201", - // Dual-GPU tensor split across both R9700 (gfx1201) cards. - env: { - HIP_VISIBLE_DEVICES: "0,1" - }, - message: [ - "./build/bin/llama-server -m \"{{local.model_path}}\" --host 127.0.0.1 --port 8090 --tensor-split 0.5,0.5" - ], - on: [{ - // Generic http URL capture (mirrors the guide's mandated pattern). - event: "/(http:\\/\\/[0-9.:]+)/", - done: true - }] - } - }, - { - // Surface the captured URL as a local var for pinokio.js "Open ... UI". - method: "local.set", - params: { - url: "{{input.event[1]}}" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-model-selector/update.js b/pbnj/pinokio/api/pmoves-model-selector/update.js deleted file mode 100644 index 8e03fd70bb..0000000000 --- a/pbnj/pinokio/api/pmoves-model-selector/update.js +++ /dev/null @@ -1,32 +0,0 @@ -// update.js — pull the latest gfx1201 fork and rebuild the llama-server binary. -module.exports = { - run: [ - { - method: "shell.run", - when: "{{exists('llama.cpp-rdna4-gfx1201')}}", - params: { - path: "llama.cpp-rdna4-gfx1201", - message: [ - "git pull --ff-only", - "cmake -B build -DGGML_HIP=ON -DAMDGPU_TARGETS=gfx1201 -DCMAKE_BUILD_TYPE=Release", - "cmake --build build --config Release -j" - ] - } - }, - { - method: "notify", - when: "{{exists('llama.cpp-rdna4-gfx1201')}}", - params: { - html: "llama.cpp (gfx1201) updated and rebuilt." - } - }, - { - method: "notify", - when: "{{!exists('llama.cpp-rdna4-gfx1201')}}", - params: { - html: "Nothing to update — the gfx1201 fork is not installed. Run Install first.", - type: "warning" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-notebooklm/icon.svg b/pbnj/pinokio/api/pmoves-notebooklm/icon.svg deleted file mode 100644 index 0557efb6d9..0000000000 --- a/pbnj/pinokio/api/pmoves-notebooklm/icon.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/pbnj/pinokio/api/pmoves-notebooklm/install.js b/pbnj/pinokio/api/pmoves-notebooklm/install.js deleted file mode 100644 index 6c94282cc3..0000000000 --- a/pbnj/pinokio/api/pmoves-notebooklm/install.js +++ /dev/null @@ -1,15 +0,0 @@ -// Prepare the PMOVES env for the NotebookLM MCP agent. Picks the repo root once, -// then runs the CANONICAL secrets pipeline (make secrets-funnel) so COMPOSE_ENV_FILES -// / tier env files exist before launch. Does NOT call docker compose directly. -module.exports = { - run: [ - { method: "filepicker.open", params: { title: "Select PMOVES.AI repository root", type: "folder" } }, - { method: "local.set", params: { repo_root: "{{input.paths[0]}}" } }, - { method: "fs.write", params: { path: "repo-root.txt", text: "{{local.repo_root}}" } }, - { method: "shell.run", params: { - path: "{{path.resolve(local.repo_root, 'pmoves')}}", - message: [ "make secrets-funnel" ] - } }, - { method: "notify", params: { html: "PMOVES secrets funneled. Start the NotebookLM MCP agent when ready.", type: "success" } } - ] -} diff --git a/pbnj/pinokio/api/pmoves-notebooklm/pinokio.js b/pbnj/pinokio/api/pmoves-notebooklm/pinokio.js deleted file mode 100644 index 72a01f1011..0000000000 --- a/pbnj/pinokio/api/pmoves-notebooklm/pinokio.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - version: "5.0", - title: "PMOVES NotebookLM Agent", - description: "Build + launch the NotebookLM MCP agent (stdio) on the PMOVES agents tier via the canonical make pipeline. Reached over docker exec; set GOOGLE_REFRESH_TOKEN for live queries.", - icon: "icon.svg", - menu: async (kernel, info) => { - const configured = info.exists("repo-root.txt") - const running = { install: info.running("install.js"), start: info.running("start.js") } - if (running.install) return [{ default: true, icon: "fa-solid fa-plug", text: "Funneling secrets...", href: "install.js" }] - if (running.start) return [{ default: true, icon: "fa-solid fa-terminal", text: "Starting NotebookLM agent...", href: "start.js" }] - if (configured) return [ - { default: true, icon: "fa-solid fa-play", text: "Start NotebookLM Agent", href: "start.js" }, - { icon: "fa-solid fa-arrows-rotate", text: "Re-funnel secrets", href: "install.js" } - ] - return [{ default: true, icon: "fa-solid fa-download", text: "Set up NotebookLM Agent", href: "install.js" }] - } -} diff --git a/pbnj/pinokio/api/pmoves-notebooklm/start.js b/pbnj/pinokio/api/pmoves-notebooklm/start.js deleted file mode 100644 index 35e6490482..0000000000 --- a/pbnj/pinokio/api/pmoves-notebooklm/start.js +++ /dev/null @@ -1,16 +0,0 @@ -// Launch the NotebookLM MCP agent through the CANONICAL make pipeline: -// (1) make secrets-funnel (2) make up-notebooklm (= $(DC) --profile agents up -d --build) -// $(DC) injects COMPOSE_ENV_FILES/tier env files — never raw `docker compose up`. -// It's a stdio MCP server (no web URL); the MCP client reaches it via docker exec -// per pmoves/config/mcp/notebooklm-agent.yaml. -module.exports = { - run: [ - { method: "fs.read", params: { path: "repo-root.txt", encoding: "utf8" } }, - { method: "local.set", params: { repo_root: "{{input.trim()}}" } }, - { method: "shell.run", params: { - path: "{{path.resolve(local.repo_root, 'pmoves')}}", - message: [ "make secrets-funnel", "make up-notebooklm" ] - } }, - { method: "notify", params: { html: "NotebookLM MCP agent up (detached, stdio via docker exec). Set GOOGLE_REFRESH_TOKEN in env.shared for live queries.", type: "success" } } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/.gitignore b/pbnj/pinokio/api/pmoves-pbnj/.gitignore deleted file mode 100644 index 79a6a59c09..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Pinokio runtime logs -logs/ - -# Per-user AI tool configs -.clinerules -.cursorrules -.windsurfrules -.geminiignore diff --git a/pbnj/pinokio/api/pmoves-pbnj/4090-deploy.json b/pbnj/pinokio/api/pmoves-pbnj/4090-deploy.json deleted file mode 100644 index cd3338845d..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/4090-deploy.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "run": [ - { - "method": "shell.run", - "params": { - "message": [ - "echo '\u2550\u2550\u2550 Deploying 4090 Coding Workstation \u2550\u2550\u2550'", - "echo 'Target: pmoves-4090 (RTX 4090 Laptop, 16GB VRAM)'", - "echo ''", - "echo 'Step 1: Pull latest code...'", - "ssh root@pmoves-4090 'cd /opt/pmoves && git pull --ff-only origin main'", - "echo ''", - "echo 'Step 2: Start services with 4090 GPU overrides...'", - "ssh root@pmoves-4090 'cd /opt/pmoves/pmoves && docker compose -f docker-compose.yml -f docker-compose.gpu.yml -f docker-compose.gpu-4090.yml pull pmoves-ollama gpu-orchestrator tensorzero-gateway mesh-agent && docker compose -f docker-compose.yml -f docker-compose.gpu.yml -f docker-compose.gpu-4090.yml up -d pmoves-ollama gpu-orchestrator tensorzero-gateway mesh-agent'", - "echo ''", - "echo 'Step 3: Verify health...'", - "ssh root@pmoves-4090 'curl -sf http://localhost:11434/api/tags && echo \" Ollama: OK\" || echo \" Ollama: FAIL\"'", - "ssh root@pmoves-4090 'curl -sf http://localhost:3030/health && echo \" TensorZero: OK\" || echo \" TensorZero: FAIL\"'", - "ssh root@pmoves-4090 'curl -sf http://localhost:8200/healthz && echo \" GPU Orchestrator: OK\" || echo \" GPU Orchestrator: FAIL\"'", - "echo ''", - "echo '\u2550\u2550\u2550 4090 Coding Workstation deployed \u2550\u2550\u2550'" - ], - "shell": "{{kernel.path('bin/miniconda/Library/bin/bash.exe')}}", - "conda": { - "skip": true - } - }, - "when": "{{platform === 'win32'}}" - }, - { - "method": "shell.run", - "params": { - "message": [ - "echo '\u2550\u2550\u2550 Deploying 4090 Coding Workstation \u2550\u2550\u2550'", - "echo 'Target: pmoves-4090 (RTX 4090 Laptop, 16GB VRAM)'", - "echo ''", - "echo 'Step 1: Pull latest code...'", - "ssh root@pmoves-4090 'cd /opt/pmoves && git pull --ff-only origin main'", - "echo ''", - "echo 'Step 2: Start services with 4090 GPU overrides...'", - "ssh root@pmoves-4090 'cd /opt/pmoves/pmoves && docker compose -f docker-compose.yml -f docker-compose.gpu.yml -f docker-compose.gpu-4090.yml pull pmoves-ollama gpu-orchestrator tensorzero-gateway mesh-agent && docker compose -f docker-compose.yml -f docker-compose.gpu.yml -f docker-compose.gpu-4090.yml up -d pmoves-ollama gpu-orchestrator tensorzero-gateway mesh-agent'", - "echo ''", - "echo 'Step 3: Verify health...'", - "ssh root@pmoves-4090 'curl -sf http://localhost:11434/api/tags && echo \" Ollama: OK\" || echo \" Ollama: FAIL\"'", - "ssh root@pmoves-4090 'curl -sf http://localhost:3030/health && echo \" TensorZero: OK\" || echo \" TensorZero: FAIL\"'", - "ssh root@pmoves-4090 'curl -sf http://localhost:8200/healthz && echo \" GPU Orchestrator: OK\" || echo \" GPU Orchestrator: FAIL\"'", - "echo ''", - "echo '\u2550\u2550\u2550 4090 Coding Workstation deployed \u2550\u2550\u2550'" - ] - }, - "when": "{{platform !== 'win32'}}" - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/4090-models.json b/pbnj/pinokio/api/pmoves-pbnj/4090-models.json deleted file mode 100644 index 8782da0fd6..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/4090-models.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "run": [ - { - "method": "shell.run", - "params": { - "message": [ - "echo '\u2550\u2550\u2550 Pulling Coding Workstation Models to 4090 \u2550\u2550\u2550'", - "echo 'This will pull ~50GB of models. Ensure adequate disk space.'", - "echo ''", - "echo 'Pulling qwen3:14b (general orchestrator)...'", - "ssh root@pmoves-4090 'ollama pull qwen3:14b'", - "echo ''", - "echo 'Pulling qwen3:8b (fast/auditor)...'", - "ssh root@pmoves-4090 'ollama pull qwen3:8b'", - "echo ''", - "echo 'Pulling qwen3-coder:30b (MoE coding \u2014 SWE-Bench SOTA)...'", - "ssh root@pmoves-4090 'ollama pull qwen3-coder:30b'", - "echo ''", - "echo 'Pulling deepseek-r1:14b (reasoning)...'", - "ssh root@pmoves-4090 'ollama pull deepseek-r1:14b'", - "echo ''", - "echo 'Pulling qwen3-embedding:4b (always-resident embeddings)...'", - "ssh root@pmoves-4090 'ollama pull qwen3-embedding:4b'", - "echo ''", - "echo 'Pulling qwen3-vl:4b (vision)...'", - "ssh root@pmoves-4090 'ollama pull qwen3-vl:4b'", - "echo ''", - "echo 'Pulling qwen3-reranker:4b (HiRAG rerank)...'", - "ssh root@pmoves-4090 'ollama pull qwen3-reranker:4b'", - "echo ''", - "echo '\u2550\u2550\u2550 All models pulled. Ready for coding workstation. \u2550\u2550\u2550'" - ], - "shell": "{{kernel.path('bin/miniconda/Library/bin/bash.exe')}}", - "conda": { - "skip": true - } - }, - "when": "{{platform === 'win32'}}" - }, - { - "method": "shell.run", - "params": { - "message": [ - "echo '\u2550\u2550\u2550 Pulling Coding Workstation Models to 4090 \u2550\u2550\u2550'", - "echo 'This will pull ~50GB of models. Ensure adequate disk space.'", - "echo ''", - "echo 'Pulling qwen3:14b (general orchestrator)...'", - "ssh root@pmoves-4090 'ollama pull qwen3:14b'", - "echo ''", - "echo 'Pulling qwen3:8b (fast/auditor)...'", - "ssh root@pmoves-4090 'ollama pull qwen3:8b'", - "echo ''", - "echo 'Pulling qwen3-coder:30b (MoE coding \u2014 SWE-Bench SOTA)...'", - "ssh root@pmoves-4090 'ollama pull qwen3-coder:30b'", - "echo ''", - "echo 'Pulling deepseek-r1:14b (reasoning)...'", - "ssh root@pmoves-4090 'ollama pull deepseek-r1:14b'", - "echo ''", - "echo 'Pulling qwen3-embedding:4b (always-resident embeddings)...'", - "ssh root@pmoves-4090 'ollama pull qwen3-embedding:4b'", - "echo ''", - "echo 'Pulling qwen3-vl:4b (vision)...'", - "ssh root@pmoves-4090 'ollama pull qwen3-vl:4b'", - "echo ''", - "echo 'Pulling qwen3-reranker:4b (HiRAG rerank)...'", - "ssh root@pmoves-4090 'ollama pull qwen3-reranker:4b'", - "echo ''", - "echo '\u2550\u2550\u2550 All models pulled. Ready for coding workstation. \u2550\u2550\u2550'" - ] - }, - "when": "{{platform !== 'win32'}}" - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/4090-status.json b/pbnj/pinokio/api/pmoves-pbnj/4090-status.json deleted file mode 100644 index 6c41fe215f..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/4090-status.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "run": [ - { - "method": "shell.run", - "params": { - "message": [ - "echo '\u2550\u2550\u2550 4090 Coding Workstation Status \u2550\u2550\u2550'", - "echo ''", - "echo '\u2500\u2500 Services \u2500\u2500'", - "ssh root@pmoves-4090 'curl -sf http://localhost:11434/api/tags | python3 -c \"import sys,json; models=json.load(sys.stdin).get(\\\"models\\\",[]); print(f\\\" Ollama: {len(models)} models loaded\\\"); [print(f\\\" - {m[\\\"name\\\"]}\\\") for m in models]\" 2>/dev/null || echo \" Ollama: OFFLINE\"'", - "ssh root@pmoves-4090 'curl -sf http://localhost:3030/health > /dev/null && echo \" TensorZero: OK\" || echo \" TensorZero: OFFLINE\"'", - "ssh root@pmoves-4090 'curl -sf http://localhost:8200/healthz > /dev/null && echo \" GPU Orchestrator: OK\" || echo \" GPU Orchestrator: OFFLINE\"'", - "echo ''", - "echo '\u2500\u2500 GPU \u2500\u2500'", - "ssh root@pmoves-4090 'nvidia-smi --query-gpu=name,memory.used,memory.total,temperature.gpu,utilization.gpu --format=csv,noheader 2>/dev/null || echo \" nvidia-smi: unavailable\"'", - "echo ''", - "echo '\u2500\u2500 NATS Mesh \u2500\u2500'", - "ssh root@pmoves-4090 'nats sub mesh.node.announce.v2 --count=1 --timeout=3s 2>/dev/null | head -5 || echo \" NATS: no announcement within 3s\"'", - "echo ''", - "echo '\u2550\u2550\u2550 End Status \u2550\u2550\u2550'" - ], - "shell": "{{kernel.path('bin/miniconda/Library/bin/bash.exe')}}", - "conda": { - "skip": true - } - }, - "when": "{{platform === 'win32'}}" - }, - { - "method": "shell.run", - "params": { - "message": [ - "echo '\u2550\u2550\u2550 4090 Coding Workstation Status \u2550\u2550\u2550'", - "echo ''", - "echo '\u2500\u2500 Services \u2500\u2500'", - "ssh root@pmoves-4090 'curl -sf http://localhost:11434/api/tags | python3 -c \"import sys,json; models=json.load(sys.stdin).get(\\\"models\\\",[]); print(f\\\" Ollama: {len(models)} models loaded\\\"); [print(f\\\" - {m[\\\"name\\\"]}\\\") for m in models]\" 2>/dev/null || echo \" Ollama: OFFLINE\"'", - "ssh root@pmoves-4090 'curl -sf http://localhost:3030/health > /dev/null && echo \" TensorZero: OK\" || echo \" TensorZero: OFFLINE\"'", - "ssh root@pmoves-4090 'curl -sf http://localhost:8200/healthz > /dev/null && echo \" GPU Orchestrator: OK\" || echo \" GPU Orchestrator: OFFLINE\"'", - "echo ''", - "echo '\u2500\u2500 GPU \u2500\u2500'", - "ssh root@pmoves-4090 'nvidia-smi --query-gpu=name,memory.used,memory.total,temperature.gpu,utilization.gpu --format=csv,noheader 2>/dev/null || echo \" nvidia-smi: unavailable\"'", - "echo ''", - "echo '\u2500\u2500 NATS Mesh \u2500\u2500'", - "ssh root@pmoves-4090 'nats sub mesh.node.announce.v2 --count=1 --timeout=3s 2>/dev/null | head -5 || echo \" NATS: no announcement within 3s\"'", - "echo ''", - "echo '\u2550\u2550\u2550 End Status \u2550\u2550\u2550'" - ] - }, - "when": "{{platform !== 'win32'}}" - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/AGENTS.md b/pbnj/pinokio/api/pmoves-pbnj/AGENTS.md deleted file mode 100644 index f5dcf6b4a8..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/AGENTS.md +++ /dev/null @@ -1,474 +0,0 @@ -# Development Guide for Pinokio Projects - -## Non-Negotiable Execution Workflow - -To guarantee every contribution follows this guide precisely, obey this checklist **before any edits** and **again before finalizing**. Do not skip or reorder. -1. **AGENTS Snapshot:** Re-open this file and write down (in your working notes or response draft) the exact sections relevant to the requested task. No work begins until this snapshot exists. -2. **Example Lock-in:** Identify the closest matching script in `D:\pinokio\prototype\system\examples`. Record its path and keep it open while editing. Every launcher change must mirror that reference unless the user explicitly instructs otherwise. -3. **Pre-flight Checklist:** Convert the applicable rules from this document and `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md into a task-specific checklist (install/start/reset/update structure, regex patterns, menu defaults, log checks, etc.). Confirm each item is ticked **before** making changes. -4. **Mid-task Verification:** Any time you touch a Pinokio script, cross-check the corresponding example line to ensure syntax and structure match. Document the reference (example path + line) in your reasoning. -5. **Exit Checklist:** Before responding to the user, revisit the pre-flight checklist and explicitly confirm every item is satisfied. If anything diverges from the example or these rules, fix it first. - -If any step cannot be completed, stop immediately and ask the user how to proceed. These five steps are mandatory for every session. - -### Critical Pattern Lock: Capturing Web UI URLs - -When writing `start.js` (or any script that needs to surface a web URL for a server): - -1. **Always copy the capture block from an example such as `system/examples/mochi/start.js`.** -```javascript -on: [{ - event: "/(http:\\/\\/[0-9.:]+)/", - done: true -}] -``` - -2. **Set the local variable using the captured match exactly as below (The regex capture object is passed in as `input.event`, so need to use the index 1 inside the parenthesis):** -```javascript -{ - method: "local.set", - params: { - url: "{{input.event[1]}}" - } -} -``` - -3. Always try to come up with the most generic regex. -4. During the exit checklist, explicitly confirm that the `url` local variable is set via `local.set` API by using the captured regex object as passed in as `input.event` from the previous `shell.run` step. - -Deviation from this pattern requires written approval from the user. - -- Make sure to keep this entire document and `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md in memory with high priority before making any decision. Pinokio is a system that makes it easy to write launchers through scripting by providing various cross-platform APIs, so whenever possible you should prioritize using Pinokio API over lower level APIs. -- When writing pinokio scripts, ALWAYS check the examples folder (in D:\pinokio\prototype\system\examples folder) to see if there are existing example scripts you can imitate, instead of assuming syntax. -- When implementing pinokio script APIs and you cannot infer the syntax just based on the examples, always search the API documentation `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md to use the correct syntax instead of assuming the syntax. -- When trying to fix something or figure out what's going on, ALWAYS start by checking the `logs` folder before doing anything else, as mentioned in the "Troubleshooting with Logs" section. -- Finally, make sure to ALWAYS follow all the items in the "best practices" section below. - -## Determine User Intent -If the initial prompt is simply a URL and nothing else, check the website content and determine the intent, and ask the user to confirm. For example a URL may point to - -1. A Tutorial: the intent may be to implement a demo for the tutorial and build a launcher. -2. A Demo: the intent may be a 1-click launcher for the demo -3. Open source project: the intent may be a 1-click launcher for the project -4. Regular website: the intent may be to clone the website and a launcher. -5. There can be other cases, but try to guess. - -## Project Structure - -Pinokio projects normally follow a standardized structure with app logic separated from launcher scripts: - -Pinokio projects follow a standardized structure with app logic separated from launcher scripts: - -``` -project-root/ -├── app/ # Self-contained app logic (can be standalone repo) -│ ├── package.json # Node.js projects -│ ├── requirements.txt # Python projects -│ └── ... # Other language-specific files -├── README.md # Documentation -├── install.js # Installation script -├── start.js # Launch script -├── update.js # Update script (for updating the scripts and app logic to the latest) -├── reset.js # Reset dependencies script -├── pinokio.js # UI generator script -└── pinokio.json # Metadata (title, description, icon) -``` - -- Keep app code in `/app` folder only (never in root) -- Store all launcher files in project root (never in `/app`) -- `/app` folder should be self-contained and publishable - - -The only exceptions are serverless web apps---purely frontend only web applications that do NOT have a server component and connect to 3rd party API endpoints--in which case the folder structure looks like the following (No need for launcher scripts since the index.html will automatically launch. The only thing needed is the metadata file named pinokio.json): - -``` -project-root/ -├── index.html # The serverless web app entry point -├── ... -├── README.md # Documentation -└── pinokio.json # Metadata (title, description, icon) -``` - -IMPORTANT: ALWAYS try to follow the best practices in the examples folder (D:\pinokio\prototype\system\examples) instead of trying to come up with your own structure. The examples have been optimized for the best user experience. - -## Launcher Project Working Directory - -- The project working directory for a script is always the same directory as the script location. -- For example, when you run `shell.run` API inside `pinokio/start.js`, the default path for shell execution is `pinokio`. -- If the launcher files are in the project root path, then the default path for shell execution is the project root. -- Therefore, it is important to specify the correct `path` attribute when running `shell.run` API commands. - -Example: in the following project structure: - -``` -project-root/ -├── pinokio/ # Pinokio launcher folder -│ ├── start.js # Launch script -│ ├── pinokio.js # UI generator script -│ └── pinokio.json # Metadata (title, description, icon) -└─── backend/ - ├── requirements.txt # App dependencies - └── app.py # App code -``` - -The `pinokio/start.js` should use the correct path `../backend` as the `path` attribute, as follows: - -``` -{ - run: [{ - ... - }, { - method: "shell.run", - params: { - message: "python app.py", - venv: "env", - path: "../backend" - } - }, { - ... - }] -} -``` - -## Development Workflow - -### 1. Understanding the Project -- Check `SPEC.md` in project root. If the file exists, use that to learn about the project details (what and how to build) -- If no `SPEC.md` exists, build based on user requirements -### 2. Modifying Existing Launcher Projects -If we are starting with existing launcher script files, work with the existing files instead of coming up with your own. -- **Preserve existing functionality:** Only modify necessary parts -- **Don't touch working scripts:** Unless adding/updating specific commands -- **Follow existing conventions:** Match the style and structure already present -### 3. Try to adopt from examples as much as possible -- If starting from scratch, first determine what type of project you will be building, and then check the examples folder (D:\pinokio\prototype\system\examples) to see if you can adopt them instead of coming up everything from scratch. -- Even if there are no relevant examples, check the examples to get inspiration for how you would structure the script files even if you have to write from scratch. -### 4. Writing from scratch as a last resort -If there are relevant examples to adopt from, write the scripts from scratch, but just make sure to follow the requirements in the next section. -### 5. Debugging -When the user reports something is not working, ALWAYS inspect the logs folder to get all the execution logs. For more info on how this works, check the "Troubleshooting with Logs" section below. - -## Script Requirements - -### 1. 1-click launchable -- The main purpose of Pinokio is to provide an easy interface to invoke commands, which may include launching servers, installing programs, etc. Make sure the final product provides ways to install, launch, reset, and update whatever is needed. - -### 2. Write Documentation -- ALWAYS write a documentation. A documentation must be stored as `README.md` in the project root folder, along with the rest of the pinokio launcher script files. A documentation file must contain: - - What the app does - - How to use the app - - API documentation for programmatically accessing the app's main features (Javascript, Python, and Curl) - -## Types of launchers -## 1. Launching servers -- When an app requires launching a server, here are the commonly used scripts: - - `install.js`: a script to install the app - - `start.js`: a script to start the app - - `reset.js`: a script to reset all the dependencies installed in the `install.js` step. used if the user wants to restart from scratch - - `update.js`: a script to update the launcher AND the app in case there are new updates. Involves pulling in the relevant git repositories installed through `install.js` (often it's the script repo and some git repositories cloned through the install steps if any) - - `pinokio.js`: the launcher script that ties all of the above scripts together by providing a UI that links to these scripts. - - `pinokio.json`: For metadata - -Here's a basic server launcher script example (`start.js`). Unless there's a special reason you need to use another pattern, this is the most recommended pattern. Use this or adopt it as needed, but NEVER try something else unless there's a good reason you should not take this approach: - -```javascript -module.exports = { - // By setting daemon: true, the script keeps running even after all items in the `run` array finishes running. Mandatory for launching servers, since otherwise the shells running the server process will get killed after the scripts finish running. - daemon: true, - run: [ - { - // The "shell.run" API for running a shell session - method: "shell.run", - params: { - // Edit 'venv' to customize the venv folder path - venv: "env", - // Edit 'env' to customize environment variables (see documentation) - env: { }, - // Edit 'path' to customize the path to start the shell from - path: "app", - // Edit 'message' to customize the commands, or to run multiple commands - message: [ - "python app.py", - ], - on: [{ - // The regular expression pattern to monitor. - // Whenever each "event" pattern occurs in the shell terminal, the shell will return, - // and the script will go onto the next step. - // The regular expression match object will be passed on to the next step as `input.event` - // Useful for capturing the URL at which the server is running (in case the server prints some message about where the server is running) - "event": "/(http:\/\/\\S+)/", - - // Use "done": true to move to the next step while keeping the shell alive. - // Use "kill": true to move to the next step after killing the shell. - "done": true - }] - } - }, - { - // This step sets the local variable 'url'. - // This local variable will be used in pinokio.js to display the "Open WebUI" tab when the value is set. - method: "local.set", - params: { - // the input.event is the regular expression match object from the previous step - // In this example, since the pattern was "/(http:\/\/\\S+)/", input.event[1] will include the exact http url match caputred by the parenthesis. - // Therefore setting the local variable 'url' - url: "{{input.event[1]}}" - } - } - ] -} -``` - -## 2. Launching serverless web apps - -- In case of purely static web apps WITHOUT servers or backends (for example an HTML based app that connects to 3rd party servers--either remote or localhost), we do NOT need the launcher scripts. -- In these cases, simply include `index.html` in the project root folder and everything should automatically work. No need for any of the pinokio launcher scripts. (Do -- You still need to include the metadata file so they show up properly on pinokio: - - `pinokio.json`: For metadata - -## 3. Launching quick scripts without web UI - -- In many cases, we may not even need a web UI, but instead just a simple way to run scripts. -- This may include TUI (Terminal User Interface) apps, a simple launcher -- In these cases, all we need is the launcher file `pinokio.js`, which may link to multiple scripts. In this case, there are no web apps (no serverless apsp, no servers), but instead just the default pinokio launcher UI that calls a bunch of scripts. -- Here are some examples: - - A pinokio script to toggle the desktop theme between dark and light - - Write some code (python or javascript or whatever) - - Write a `toggle.js` pinokio script that executes the code - - Write a `pinokio.js` launcher script to create a sidebar UI that displays the `toggle.js` so the user can simply click the "toggle" button to toggle back and forth between desktop themes - - A pinokio script to fetch some file - - Write some code (python or javascript or whatever) - - Write a `fetch.js` pinokio script that executes the code - - Write a `pinokio.js` launcher script to create a sidebar UI that displays the `fetch.js` so the user can simply click the "fetch" button to fetch some data. -- You still need to include the metadata file so they show up properly on pinokio: - - `pinokio.json`: For metadata - -## API - -This section lists all the script APIs available on Pinokio. To learn the details of how they are used, you can: -1. Check the examples in the D:\pinokio\prototype\system\examples folder -2. Read the `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md further documentation on the full syntax - -### Script API - -These APIs can be used to describe each step in a pinokio script: -- shell.run: run shell commands -- input: accept user input -- filepicker: accept file upload -- fs.write: write to file -- fs.read: read from file -- fs.copy: copy files -- fs.download: download files -- fs.link: create a symbolic link (or junction on windows) for folders -- fs.open: open the system file explorer at a given path -- fs.cat: print file contents -- jump: jump to a specific step -- local.set: set local variables for the currently running script -- json.set: update a json file -- json.rm: remove keys from a json file -- json.get: get values from a json file -- log: print to the web terminal -- net: make network requests -- notify: display a notification -- script.download: download a script from a git uri -- script.start: start a script -- script.stop: stop a script -- script.return: return values if the current script was called by a caller script, so the caller script can utilize the return value as `input` -- web.open: open a url in web browser -- hf.download: huggingfac-cli download API -### Template variables -The following variables are accessible inside template expressions (example `{{args.command}` in scripts, resulting in dynamic behaviors of scripts: -- input: An input is a variable that gets passed from one RPC call to the next -- args: args is the parameter object that gets passed into the script (via pinokio.js `params`). Unlike `input` which takes the value passed in from the immediately previous step, `args` is a global value that is the same through out the entire script execution. -- local: local variable object that can be set with `local.set` API -- self: refers to the script file itself (which is JSON or JavaScript). For example if `start.js` that's currently running has `daemon: true` set, `{{self.daemon}}` will evaluate to true. -- uri: The current script uri -- port: The next available port. Very useful when you need to launch an app at a specific port without port conflicts. -- cwd: The current script execution folder path -- platform: The current operating system. May be one of the following: `darwin`, `win32`, `linux` -- arch: The current system architecture. May be one of the following: x32, x64, arm, arm64, s390, s390x, mipsel, ia32, mips, ppc, ppc64 -- gpus: array of available GPUs on the machine (example: `['apple']`, `['nvidia']`) -- gpu: the first available GPU (example: `nvidia`) -- current: The current variable points to the index of the currently executing instruction within the run array. -- next: The next variable points to the index of the next instruction to be executed. (null if the current instruction is the final instruction in the run array) -- envs: You can access the environment variables of the currently running process with envs object. -- which: Check whether a command exists (example: `{{which('winget')}}`. Can be used in the `when` attribute of a script step to run commands or install first. -- exists: Check whether a file or folder exists at the specified relative path (example: `"when": "{{!exists('app')}}"`). Can be used with the `when` attribute to determine a path's existence and trigger custom logic. Use relative paths and it will resolve automatically to the current execution folder. -- running: Check whether a script file is running (example: `"when": "{{!running('start.js')}}"`). Can be used with the `when` attribute to determine a path's existence and trigger custom logic. Use relative paths and it will resolve automatically to the current execution folder. -- os: Pinokio exposes the node.js os module through the os variable. -- path: Pinokio exposes the node.js path module through the os variable (example: `{{path.resolve(...)}}` - -## System Capabilities -### Package Management (Use in Order of Preference) -The following package managers come pre-installed with Pinokio, so whenever you need to install a 3rd party binary, remember that these are available. Also, you can assume these are available and include the following package manager commands in Pinokio scripts: -1. **UV** - For Python packages (preferred over pip) -2. **NPM** - For Node.js packages -3. **Conda** - For cross-platform 3rd party binaries -4. **Brew** - Mac-only fallback when other options unavailable -5. **Git** - Full access to git is available. -**Important:** Include all install commands in the install script for reproducibility. -### HTTPS Proxy Support -- All HTTP servers automatically get HTTPS endpoints -- Convention: `http://localhost:` → `https://.localhost` -- Full proxy list available at: `http://localhost:2019/config/` -### Pterm Features: -- **Clipboard Access:** Read from or Write to system clipboard via pinokio Pterm CLI (`pterm clipboard` command.) -- **Notifications:** Send desktop alerts via pinokio pterm CLI (`pterm push` command.) -- **Script Testing:** Run launcher scripts via pinokio pterm CLI (`pterm start` command.) -- **File Selection:** Use built-in filepicker for user file/folder input (`pterm filepicker` command.) -- **Git Operations:** Clone repositories, push to GitHub -- **GitHub Integration:** Full GitHub CLI support (`gh` commands) - -## Troubleshooting with Logs -Pinokio stores the logs for everything that happened in terminal at the following locations, so you can make use of them to determine what's going on: - -### Log Structure -In case there is a `pinokio` folder in the project root folder, you should be able to find the logs folder here: - -``` -pinokio/ -└── logs/ # Direct user interaction logs - ├── api/ # Launcher script logs (install.js, start.js, etc.) - ├── dev/ # AI coding tool logs (organized by tool) - └── shell/ # Direct user interaction logs -``` - -Otherwise, the `logs` folder should be found at project root: - -``` -logs/ -├── api/ # Launcher script logs (install.js, start.js, etc.) -├── dev/ # AI coding tool logs (organized by tool) -└── shell/ # Direct user interaction logs -``` - -### Log File Naming -- Unix timestamps for each session -- Special "latest" file contains most recent session logs -- **Default:** Use "latest" files for current issues -- **Historical:** Use timestamped files for pattern analysis and the full history. - -## Best practices -### 0. Always reference the logs when debugging -- When the user asks to fix something, ALWAYS check the logs folder first to check what went wrong. Check the "Troubleshooting with Logs" section. -### 1. Shell commands for launching programs -- Launch flags related - - Try as hard as possible to minimize launch flags and parameters when launching an app. For example, instead of `python app.py --port 8610`, try to do `python app.py` unless really necessary. The only exception is when the only way to launch the app is to specify the flags. -- Launch IP related - - Always try to find a way to launch servers at 127.0.0.1 or localhost, often by specifying launch flags or using environment variables. Some apps launch apps at 0.0.0.0 by default but we do not want this. -- Launch Port related - - In case the app itself automatically launches at the next available port by default (for example Gradio does this), do NOT specify port, since it's taken care of by the app itself. Always try to minimize the amount of code. - - If the install instruction says to launch at a specific port, don't use the hardcoded port they suggest since there's a risk of port conflicts. Instead, use Pinokio's `{{port}}` template expression to automatically get the next available port. - - For example, if the instruction says `python app.py --port 7860`, don't use that hardcoded port since there might be another app running at that port. Instead, automatically assign the next available port like this: `python app.py --port {{port}}` - - Note that the `{{port}}` expression always returns the next immediately available port for each step, so if you have multiple steps in a script and use `{{port}}` in multiple steps, the value will be different. So if you want to launch at the next available port and then later reuse that port, you will need to first use `{{port}}` to get the next available port, and save the value in local variable using `local.set`, and then use the `{{local.}}` expression later. -### 2. shell.run API -- When writing `shell.run` API requests, always use relative paths (no absolute paths) for the `path` field. For example, if you need to run a command from `app` folder, the `path` attribute should simply be `app`, instead of its full absolute path. -### 2. Package managers -- When installing python packages, try best to use `uv` instead of `pip` even if the install instruction says to use pip. Instead of `pip install -r requirements.txt`, you can simply use `uv pip install -r requirements.txt` for example. Even if the project's own README says use pip or poetry, first check if there's a way to use uv instead. -- When you need to install some global package, try to use `conda` as much as possible. Even on macs, `brew` should be only used if there are no `conda` options. -### 3. Minimal Always -- If you are starting with existing script files, before modifying, creating, or removing any script files, first look at `pinokio.js` to understand which script files are actually used in the launcher. The only script files used are the ones mentioned in the `pinokio.js` file. The `pinokio.js` file is the file that constructs the UI dynamically. -- Do not create a redundant script file that does something that already exists. Instead modify the existing script file for the feature. For example, do not create an `install.json` file for installation if `install.js` already exists. Instead, modify the `install.js` file. -- Pinokio accepts both JSON and JS script files, so when determining whether a script for a specific purpose already exists, check both JSON and JS files mentioned in the `pinokio.js` file. Do not create script files for rendundant purpose. -- When building launchers for existing projects cloned from a repository, try to stay away from modifying the project folder (the `D:\pinokio\api\pmoves-pbnj` folder), even if installations are failing. Instead, try to work around it by creating additional files in the launcher folder, and using those files IN ADDITION to the default project. - - The only exception when you may need to make changes to the project folder is when the user explicitly wants to modify the existing project. Otherwise if the purpose is to simply write a launcher, the app logic folder should never be touched. -- When running shell commands, take full advantage of the Pinokio `shell.run` API, which provides features like `env`, `venv`, `input`, `path`, `sudo`, `on`, etc. which can greatly reduce the amount of script code. - - Python apps: Always use virtual environments via `venv` attribute. This attribute automatically creates a venv or uses if it already exists. -### 4. Try to support Cross-platform as much as possible -- Use cross-platform shell commands only. -- This means, prefer to use commands that work on all platforms instead of the current platform. -- If there are no cross platform commands, use Pinokio's template expressions to conditionally use commands depending on `platform`, `arch`, etc. -- Also try to utilize Pinokio Pterm APIs for various cross-platform system features. -- If it is impossible to implement a cross platform solution (due to the nature of the project itself), set the `platform`, `arch`, and/or `gpu` attributes of the `pinokio.json` file to declare the limitation. -- Pinokio provides various APIs for cross-platform way of calling commonly used system functions, or lets you selectively run commands depending on `platform`, `arch`, etc. -### 5. Do not make assumptions about Pinokio API -- Do NOT make assumptions about which Pinokio APIs exist. Check the documentation. -- Do NOT make assumptions about the Pinokio API syntax. Follow the documentation. -### 6. Scripts must be able to replicate install and launch steps 100% -- The whole point of the scripts is for others to easily download and invoke them via Pinokio interface with one click. Therefore, do not assume the end user's system state, and make everything self-contained. -- When a 3rd party package needs to be installed, or a 3rd party repository needs to be downloaded, include them in the scripts. -### 7 Dynamic UI rendering -- The `pinokio.js` launcher script can change dynamically depending on the current state of the script execution. Which means, depending on what the file returns, it can determine what the sidebar looks like at any given moment of the script cycle. - - `info.exists(relative_path)`: The `info.exists` can be used to check whether a relative path (relative to the script root path) exists. The `pinokio.js` file can determine which menu items to return based on this value at any given moment. - - `info.running(relative_path)`: The `info.running` can be used to check whether a script at a relative path is currently running (relative to the script root path) exists. The `pinokio.js` file can determine which menu items to return based on this value at any given moment. - - `info.local(relative_path)`: The `info.local` can be used to return all the local variables tied to a script that's currently running. The `pinokio.js` file can determine which menu items to return based on this value at any given moment. - - `default`: set the `default` attribute on any menu item for whichever menu needs to be selected by default at a given step. Some example scenarios: - - during the install process, the `install.js` menu item needs to be set as the `default`, so it automatically executes the script - - when launching the `start.js` menu item needs to be set as the `default`, so it automatically executes the script - - after the app has launched, the `default` needs to be set on the web UI URL, so the user is sent to the actual app automatically. - - Check the examples in the D:\pinokio\prototype\system\examples folder to see how these are being used. -### 8. No need for stop scripts -- `pinokio.js` does NOT need a separate `stop` script. Every script that can be started can also be natively stopped through the Pinokio UI, therefore you do not need a separate stop script for start script -### 9. Writing launchers for existing projects -- When writing or modifying pinokio launcher scripts, figure out the install/launch steps by reading the project folder `app`. -- In most cases, the `README.md` file in the `D:\pinokio\api\pmoves-pbnj` folder contains the instructions needed to install and run the app, but if not, figure out by scanning the rest of the project files. -- Install scripts should work for each specific operating system, so ignore Docker related instructions. Instead use install/launch instructions for each platform. -### 10. Don't use Docker unless really necessary -- Some projects suggest docker as installation options. But even in these cases, try to find "development" options to launch the app without relying on Docker, as much as possible. We do not need Docker since we can automatically install and launch apps specifically for the user's platform, since we can write scripts that run cross platform. -### 11. pinokio.json -- Do not touch the `version` field since the version is the script schema version and the one pre-set in `pinokio.js` must be used. -- `icon`: It's best if we have a user friendly icon to represent the app, so try to get an image and link it from `pinokio.json`. - - If the git repository for the `D:\pinokio\api\pmoves-pbnj` folder points to GitHub (for example https://github.com//`, ask the user if they want to download the icon from GitHub, and if approved, get the `avatar_url` by fetching `https://api.github.com/users/`, and then download the image to the root folder as `icon.png`, and set `icon.png` as the `icon` field of the `pinokio.json`. -### 12. Gitignore -- When a launcher involves cloning 3rd party repositories, downloading files dynamically, or some files to be generated, these need to be included in the .gitignore file. This may include things like: - - Cloning git repositories - - Downloading files - - Dynamically creating files during installation or running, such as Sqlite Databases, or environment variables, or anything specific to the user. -- Make sure these file paths are included in the .gitignore file, and if not, include them in .gitignore. - -## AI Libraries (Pytorch, Xformers, Triton, Sageattention, etc.) -If the launcher has a dedicated built-in script named `torch.js`, it can be used as follows: - -``` -// install.js -module.exports = { - run: [ - // Edit this step with your custom install commands - { - method: "shell.run", - params: { - venv: "venv", // Edit this to customize the venv folder path - path: "app", - message: [ - "uv pip install -r requirements.txt" - ], - } - }, - // Delete this step if your project does not use torch - { - method: "script.start", - params: { - uri: "torch.js", - params: { - path: "app", - venv: "venv", // Edit this to customize the venv folder path - // xformers: true // uncomment this line if your project requires xformers - // triton: true // uncomment this line if your project requires triton - // sageattention: true // uncomment this line if your project requires sageattention - // flashattention: true // uncomment this line if your project requires flashattention - } - } - }, - ] -} -``` - -The `torch.js` script also includes ways to install pytorch dependent libraries such as xformers, triton, sagetattention. If any of these libraries need to be installed, use the torch.js to install in order to install them cross platform. - - -## Quick Reference -### Essential Documentation -- **Pinokio Programming:** See `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md → "Programming Pinokio" section -- **Dynamic Menus:** See `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md → "Dynamic menu rendering" section -- **CLI Commands:** See `PTERM.md` at D:\pinokio\prototype\PTERM.md -### Common Patterns -- **Python Virtual Env:** `shell.run` with `venv` attribute -- **Cross-platform Commands:** Always test on multiple platforms -- **Error Handling:** Check logs/api for launcher issues -- **GitHub Operations:** Use `gh` CLI for advanced GitHub features -## Development Principles -1. **Minimize Shell Usage:** Leverage API parameters instead of raw commands -2. **Maintain Separation:** Keep app logic and launchers separate -3. **Follow Conventions:** Match existing project patterns -4. **Test Thoroughly:** Use CLI to verify launcher functionality -5. **Document Changes:** Update relevant metadata and documentation diff --git a/pbnj/pinokio/api/pmoves-pbnj/CLAUDE.md b/pbnj/pinokio/api/pmoves-pbnj/CLAUDE.md deleted file mode 100644 index f5dcf6b4a8..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/CLAUDE.md +++ /dev/null @@ -1,474 +0,0 @@ -# Development Guide for Pinokio Projects - -## Non-Negotiable Execution Workflow - -To guarantee every contribution follows this guide precisely, obey this checklist **before any edits** and **again before finalizing**. Do not skip or reorder. -1. **AGENTS Snapshot:** Re-open this file and write down (in your working notes or response draft) the exact sections relevant to the requested task. No work begins until this snapshot exists. -2. **Example Lock-in:** Identify the closest matching script in `D:\pinokio\prototype\system\examples`. Record its path and keep it open while editing. Every launcher change must mirror that reference unless the user explicitly instructs otherwise. -3. **Pre-flight Checklist:** Convert the applicable rules from this document and `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md into a task-specific checklist (install/start/reset/update structure, regex patterns, menu defaults, log checks, etc.). Confirm each item is ticked **before** making changes. -4. **Mid-task Verification:** Any time you touch a Pinokio script, cross-check the corresponding example line to ensure syntax and structure match. Document the reference (example path + line) in your reasoning. -5. **Exit Checklist:** Before responding to the user, revisit the pre-flight checklist and explicitly confirm every item is satisfied. If anything diverges from the example or these rules, fix it first. - -If any step cannot be completed, stop immediately and ask the user how to proceed. These five steps are mandatory for every session. - -### Critical Pattern Lock: Capturing Web UI URLs - -When writing `start.js` (or any script that needs to surface a web URL for a server): - -1. **Always copy the capture block from an example such as `system/examples/mochi/start.js`.** -```javascript -on: [{ - event: "/(http:\\/\\/[0-9.:]+)/", - done: true -}] -``` - -2. **Set the local variable using the captured match exactly as below (The regex capture object is passed in as `input.event`, so need to use the index 1 inside the parenthesis):** -```javascript -{ - method: "local.set", - params: { - url: "{{input.event[1]}}" - } -} -``` - -3. Always try to come up with the most generic regex. -4. During the exit checklist, explicitly confirm that the `url` local variable is set via `local.set` API by using the captured regex object as passed in as `input.event` from the previous `shell.run` step. - -Deviation from this pattern requires written approval from the user. - -- Make sure to keep this entire document and `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md in memory with high priority before making any decision. Pinokio is a system that makes it easy to write launchers through scripting by providing various cross-platform APIs, so whenever possible you should prioritize using Pinokio API over lower level APIs. -- When writing pinokio scripts, ALWAYS check the examples folder (in D:\pinokio\prototype\system\examples folder) to see if there are existing example scripts you can imitate, instead of assuming syntax. -- When implementing pinokio script APIs and you cannot infer the syntax just based on the examples, always search the API documentation `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md to use the correct syntax instead of assuming the syntax. -- When trying to fix something or figure out what's going on, ALWAYS start by checking the `logs` folder before doing anything else, as mentioned in the "Troubleshooting with Logs" section. -- Finally, make sure to ALWAYS follow all the items in the "best practices" section below. - -## Determine User Intent -If the initial prompt is simply a URL and nothing else, check the website content and determine the intent, and ask the user to confirm. For example a URL may point to - -1. A Tutorial: the intent may be to implement a demo for the tutorial and build a launcher. -2. A Demo: the intent may be a 1-click launcher for the demo -3. Open source project: the intent may be a 1-click launcher for the project -4. Regular website: the intent may be to clone the website and a launcher. -5. There can be other cases, but try to guess. - -## Project Structure - -Pinokio projects normally follow a standardized structure with app logic separated from launcher scripts: - -Pinokio projects follow a standardized structure with app logic separated from launcher scripts: - -``` -project-root/ -├── app/ # Self-contained app logic (can be standalone repo) -│ ├── package.json # Node.js projects -│ ├── requirements.txt # Python projects -│ └── ... # Other language-specific files -├── README.md # Documentation -├── install.js # Installation script -├── start.js # Launch script -├── update.js # Update script (for updating the scripts and app logic to the latest) -├── reset.js # Reset dependencies script -├── pinokio.js # UI generator script -└── pinokio.json # Metadata (title, description, icon) -``` - -- Keep app code in `/app` folder only (never in root) -- Store all launcher files in project root (never in `/app`) -- `/app` folder should be self-contained and publishable - - -The only exceptions are serverless web apps---purely frontend only web applications that do NOT have a server component and connect to 3rd party API endpoints--in which case the folder structure looks like the following (No need for launcher scripts since the index.html will automatically launch. The only thing needed is the metadata file named pinokio.json): - -``` -project-root/ -├── index.html # The serverless web app entry point -├── ... -├── README.md # Documentation -└── pinokio.json # Metadata (title, description, icon) -``` - -IMPORTANT: ALWAYS try to follow the best practices in the examples folder (D:\pinokio\prototype\system\examples) instead of trying to come up with your own structure. The examples have been optimized for the best user experience. - -## Launcher Project Working Directory - -- The project working directory for a script is always the same directory as the script location. -- For example, when you run `shell.run` API inside `pinokio/start.js`, the default path for shell execution is `pinokio`. -- If the launcher files are in the project root path, then the default path for shell execution is the project root. -- Therefore, it is important to specify the correct `path` attribute when running `shell.run` API commands. - -Example: in the following project structure: - -``` -project-root/ -├── pinokio/ # Pinokio launcher folder -│ ├── start.js # Launch script -│ ├── pinokio.js # UI generator script -│ └── pinokio.json # Metadata (title, description, icon) -└─── backend/ - ├── requirements.txt # App dependencies - └── app.py # App code -``` - -The `pinokio/start.js` should use the correct path `../backend` as the `path` attribute, as follows: - -``` -{ - run: [{ - ... - }, { - method: "shell.run", - params: { - message: "python app.py", - venv: "env", - path: "../backend" - } - }, { - ... - }] -} -``` - -## Development Workflow - -### 1. Understanding the Project -- Check `SPEC.md` in project root. If the file exists, use that to learn about the project details (what and how to build) -- If no `SPEC.md` exists, build based on user requirements -### 2. Modifying Existing Launcher Projects -If we are starting with existing launcher script files, work with the existing files instead of coming up with your own. -- **Preserve existing functionality:** Only modify necessary parts -- **Don't touch working scripts:** Unless adding/updating specific commands -- **Follow existing conventions:** Match the style and structure already present -### 3. Try to adopt from examples as much as possible -- If starting from scratch, first determine what type of project you will be building, and then check the examples folder (D:\pinokio\prototype\system\examples) to see if you can adopt them instead of coming up everything from scratch. -- Even if there are no relevant examples, check the examples to get inspiration for how you would structure the script files even if you have to write from scratch. -### 4. Writing from scratch as a last resort -If there are relevant examples to adopt from, write the scripts from scratch, but just make sure to follow the requirements in the next section. -### 5. Debugging -When the user reports something is not working, ALWAYS inspect the logs folder to get all the execution logs. For more info on how this works, check the "Troubleshooting with Logs" section below. - -## Script Requirements - -### 1. 1-click launchable -- The main purpose of Pinokio is to provide an easy interface to invoke commands, which may include launching servers, installing programs, etc. Make sure the final product provides ways to install, launch, reset, and update whatever is needed. - -### 2. Write Documentation -- ALWAYS write a documentation. A documentation must be stored as `README.md` in the project root folder, along with the rest of the pinokio launcher script files. A documentation file must contain: - - What the app does - - How to use the app - - API documentation for programmatically accessing the app's main features (Javascript, Python, and Curl) - -## Types of launchers -## 1. Launching servers -- When an app requires launching a server, here are the commonly used scripts: - - `install.js`: a script to install the app - - `start.js`: a script to start the app - - `reset.js`: a script to reset all the dependencies installed in the `install.js` step. used if the user wants to restart from scratch - - `update.js`: a script to update the launcher AND the app in case there are new updates. Involves pulling in the relevant git repositories installed through `install.js` (often it's the script repo and some git repositories cloned through the install steps if any) - - `pinokio.js`: the launcher script that ties all of the above scripts together by providing a UI that links to these scripts. - - `pinokio.json`: For metadata - -Here's a basic server launcher script example (`start.js`). Unless there's a special reason you need to use another pattern, this is the most recommended pattern. Use this or adopt it as needed, but NEVER try something else unless there's a good reason you should not take this approach: - -```javascript -module.exports = { - // By setting daemon: true, the script keeps running even after all items in the `run` array finishes running. Mandatory for launching servers, since otherwise the shells running the server process will get killed after the scripts finish running. - daemon: true, - run: [ - { - // The "shell.run" API for running a shell session - method: "shell.run", - params: { - // Edit 'venv' to customize the venv folder path - venv: "env", - // Edit 'env' to customize environment variables (see documentation) - env: { }, - // Edit 'path' to customize the path to start the shell from - path: "app", - // Edit 'message' to customize the commands, or to run multiple commands - message: [ - "python app.py", - ], - on: [{ - // The regular expression pattern to monitor. - // Whenever each "event" pattern occurs in the shell terminal, the shell will return, - // and the script will go onto the next step. - // The regular expression match object will be passed on to the next step as `input.event` - // Useful for capturing the URL at which the server is running (in case the server prints some message about where the server is running) - "event": "/(http:\/\/\\S+)/", - - // Use "done": true to move to the next step while keeping the shell alive. - // Use "kill": true to move to the next step after killing the shell. - "done": true - }] - } - }, - { - // This step sets the local variable 'url'. - // This local variable will be used in pinokio.js to display the "Open WebUI" tab when the value is set. - method: "local.set", - params: { - // the input.event is the regular expression match object from the previous step - // In this example, since the pattern was "/(http:\/\/\\S+)/", input.event[1] will include the exact http url match caputred by the parenthesis. - // Therefore setting the local variable 'url' - url: "{{input.event[1]}}" - } - } - ] -} -``` - -## 2. Launching serverless web apps - -- In case of purely static web apps WITHOUT servers or backends (for example an HTML based app that connects to 3rd party servers--either remote or localhost), we do NOT need the launcher scripts. -- In these cases, simply include `index.html` in the project root folder and everything should automatically work. No need for any of the pinokio launcher scripts. (Do -- You still need to include the metadata file so they show up properly on pinokio: - - `pinokio.json`: For metadata - -## 3. Launching quick scripts without web UI - -- In many cases, we may not even need a web UI, but instead just a simple way to run scripts. -- This may include TUI (Terminal User Interface) apps, a simple launcher -- In these cases, all we need is the launcher file `pinokio.js`, which may link to multiple scripts. In this case, there are no web apps (no serverless apsp, no servers), but instead just the default pinokio launcher UI that calls a bunch of scripts. -- Here are some examples: - - A pinokio script to toggle the desktop theme between dark and light - - Write some code (python or javascript or whatever) - - Write a `toggle.js` pinokio script that executes the code - - Write a `pinokio.js` launcher script to create a sidebar UI that displays the `toggle.js` so the user can simply click the "toggle" button to toggle back and forth between desktop themes - - A pinokio script to fetch some file - - Write some code (python or javascript or whatever) - - Write a `fetch.js` pinokio script that executes the code - - Write a `pinokio.js` launcher script to create a sidebar UI that displays the `fetch.js` so the user can simply click the "fetch" button to fetch some data. -- You still need to include the metadata file so they show up properly on pinokio: - - `pinokio.json`: For metadata - -## API - -This section lists all the script APIs available on Pinokio. To learn the details of how they are used, you can: -1. Check the examples in the D:\pinokio\prototype\system\examples folder -2. Read the `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md further documentation on the full syntax - -### Script API - -These APIs can be used to describe each step in a pinokio script: -- shell.run: run shell commands -- input: accept user input -- filepicker: accept file upload -- fs.write: write to file -- fs.read: read from file -- fs.copy: copy files -- fs.download: download files -- fs.link: create a symbolic link (or junction on windows) for folders -- fs.open: open the system file explorer at a given path -- fs.cat: print file contents -- jump: jump to a specific step -- local.set: set local variables for the currently running script -- json.set: update a json file -- json.rm: remove keys from a json file -- json.get: get values from a json file -- log: print to the web terminal -- net: make network requests -- notify: display a notification -- script.download: download a script from a git uri -- script.start: start a script -- script.stop: stop a script -- script.return: return values if the current script was called by a caller script, so the caller script can utilize the return value as `input` -- web.open: open a url in web browser -- hf.download: huggingfac-cli download API -### Template variables -The following variables are accessible inside template expressions (example `{{args.command}` in scripts, resulting in dynamic behaviors of scripts: -- input: An input is a variable that gets passed from one RPC call to the next -- args: args is the parameter object that gets passed into the script (via pinokio.js `params`). Unlike `input` which takes the value passed in from the immediately previous step, `args` is a global value that is the same through out the entire script execution. -- local: local variable object that can be set with `local.set` API -- self: refers to the script file itself (which is JSON or JavaScript). For example if `start.js` that's currently running has `daemon: true` set, `{{self.daemon}}` will evaluate to true. -- uri: The current script uri -- port: The next available port. Very useful when you need to launch an app at a specific port without port conflicts. -- cwd: The current script execution folder path -- platform: The current operating system. May be one of the following: `darwin`, `win32`, `linux` -- arch: The current system architecture. May be one of the following: x32, x64, arm, arm64, s390, s390x, mipsel, ia32, mips, ppc, ppc64 -- gpus: array of available GPUs on the machine (example: `['apple']`, `['nvidia']`) -- gpu: the first available GPU (example: `nvidia`) -- current: The current variable points to the index of the currently executing instruction within the run array. -- next: The next variable points to the index of the next instruction to be executed. (null if the current instruction is the final instruction in the run array) -- envs: You can access the environment variables of the currently running process with envs object. -- which: Check whether a command exists (example: `{{which('winget')}}`. Can be used in the `when` attribute of a script step to run commands or install first. -- exists: Check whether a file or folder exists at the specified relative path (example: `"when": "{{!exists('app')}}"`). Can be used with the `when` attribute to determine a path's existence and trigger custom logic. Use relative paths and it will resolve automatically to the current execution folder. -- running: Check whether a script file is running (example: `"when": "{{!running('start.js')}}"`). Can be used with the `when` attribute to determine a path's existence and trigger custom logic. Use relative paths and it will resolve automatically to the current execution folder. -- os: Pinokio exposes the node.js os module through the os variable. -- path: Pinokio exposes the node.js path module through the os variable (example: `{{path.resolve(...)}}` - -## System Capabilities -### Package Management (Use in Order of Preference) -The following package managers come pre-installed with Pinokio, so whenever you need to install a 3rd party binary, remember that these are available. Also, you can assume these are available and include the following package manager commands in Pinokio scripts: -1. **UV** - For Python packages (preferred over pip) -2. **NPM** - For Node.js packages -3. **Conda** - For cross-platform 3rd party binaries -4. **Brew** - Mac-only fallback when other options unavailable -5. **Git** - Full access to git is available. -**Important:** Include all install commands in the install script for reproducibility. -### HTTPS Proxy Support -- All HTTP servers automatically get HTTPS endpoints -- Convention: `http://localhost:` → `https://.localhost` -- Full proxy list available at: `http://localhost:2019/config/` -### Pterm Features: -- **Clipboard Access:** Read from or Write to system clipboard via pinokio Pterm CLI (`pterm clipboard` command.) -- **Notifications:** Send desktop alerts via pinokio pterm CLI (`pterm push` command.) -- **Script Testing:** Run launcher scripts via pinokio pterm CLI (`pterm start` command.) -- **File Selection:** Use built-in filepicker for user file/folder input (`pterm filepicker` command.) -- **Git Operations:** Clone repositories, push to GitHub -- **GitHub Integration:** Full GitHub CLI support (`gh` commands) - -## Troubleshooting with Logs -Pinokio stores the logs for everything that happened in terminal at the following locations, so you can make use of them to determine what's going on: - -### Log Structure -In case there is a `pinokio` folder in the project root folder, you should be able to find the logs folder here: - -``` -pinokio/ -└── logs/ # Direct user interaction logs - ├── api/ # Launcher script logs (install.js, start.js, etc.) - ├── dev/ # AI coding tool logs (organized by tool) - └── shell/ # Direct user interaction logs -``` - -Otherwise, the `logs` folder should be found at project root: - -``` -logs/ -├── api/ # Launcher script logs (install.js, start.js, etc.) -├── dev/ # AI coding tool logs (organized by tool) -└── shell/ # Direct user interaction logs -``` - -### Log File Naming -- Unix timestamps for each session -- Special "latest" file contains most recent session logs -- **Default:** Use "latest" files for current issues -- **Historical:** Use timestamped files for pattern analysis and the full history. - -## Best practices -### 0. Always reference the logs when debugging -- When the user asks to fix something, ALWAYS check the logs folder first to check what went wrong. Check the "Troubleshooting with Logs" section. -### 1. Shell commands for launching programs -- Launch flags related - - Try as hard as possible to minimize launch flags and parameters when launching an app. For example, instead of `python app.py --port 8610`, try to do `python app.py` unless really necessary. The only exception is when the only way to launch the app is to specify the flags. -- Launch IP related - - Always try to find a way to launch servers at 127.0.0.1 or localhost, often by specifying launch flags or using environment variables. Some apps launch apps at 0.0.0.0 by default but we do not want this. -- Launch Port related - - In case the app itself automatically launches at the next available port by default (for example Gradio does this), do NOT specify port, since it's taken care of by the app itself. Always try to minimize the amount of code. - - If the install instruction says to launch at a specific port, don't use the hardcoded port they suggest since there's a risk of port conflicts. Instead, use Pinokio's `{{port}}` template expression to automatically get the next available port. - - For example, if the instruction says `python app.py --port 7860`, don't use that hardcoded port since there might be another app running at that port. Instead, automatically assign the next available port like this: `python app.py --port {{port}}` - - Note that the `{{port}}` expression always returns the next immediately available port for each step, so if you have multiple steps in a script and use `{{port}}` in multiple steps, the value will be different. So if you want to launch at the next available port and then later reuse that port, you will need to first use `{{port}}` to get the next available port, and save the value in local variable using `local.set`, and then use the `{{local.}}` expression later. -### 2. shell.run API -- When writing `shell.run` API requests, always use relative paths (no absolute paths) for the `path` field. For example, if you need to run a command from `app` folder, the `path` attribute should simply be `app`, instead of its full absolute path. -### 2. Package managers -- When installing python packages, try best to use `uv` instead of `pip` even if the install instruction says to use pip. Instead of `pip install -r requirements.txt`, you can simply use `uv pip install -r requirements.txt` for example. Even if the project's own README says use pip or poetry, first check if there's a way to use uv instead. -- When you need to install some global package, try to use `conda` as much as possible. Even on macs, `brew` should be only used if there are no `conda` options. -### 3. Minimal Always -- If you are starting with existing script files, before modifying, creating, or removing any script files, first look at `pinokio.js` to understand which script files are actually used in the launcher. The only script files used are the ones mentioned in the `pinokio.js` file. The `pinokio.js` file is the file that constructs the UI dynamically. -- Do not create a redundant script file that does something that already exists. Instead modify the existing script file for the feature. For example, do not create an `install.json` file for installation if `install.js` already exists. Instead, modify the `install.js` file. -- Pinokio accepts both JSON and JS script files, so when determining whether a script for a specific purpose already exists, check both JSON and JS files mentioned in the `pinokio.js` file. Do not create script files for rendundant purpose. -- When building launchers for existing projects cloned from a repository, try to stay away from modifying the project folder (the `D:\pinokio\api\pmoves-pbnj` folder), even if installations are failing. Instead, try to work around it by creating additional files in the launcher folder, and using those files IN ADDITION to the default project. - - The only exception when you may need to make changes to the project folder is when the user explicitly wants to modify the existing project. Otherwise if the purpose is to simply write a launcher, the app logic folder should never be touched. -- When running shell commands, take full advantage of the Pinokio `shell.run` API, which provides features like `env`, `venv`, `input`, `path`, `sudo`, `on`, etc. which can greatly reduce the amount of script code. - - Python apps: Always use virtual environments via `venv` attribute. This attribute automatically creates a venv or uses if it already exists. -### 4. Try to support Cross-platform as much as possible -- Use cross-platform shell commands only. -- This means, prefer to use commands that work on all platforms instead of the current platform. -- If there are no cross platform commands, use Pinokio's template expressions to conditionally use commands depending on `platform`, `arch`, etc. -- Also try to utilize Pinokio Pterm APIs for various cross-platform system features. -- If it is impossible to implement a cross platform solution (due to the nature of the project itself), set the `platform`, `arch`, and/or `gpu` attributes of the `pinokio.json` file to declare the limitation. -- Pinokio provides various APIs for cross-platform way of calling commonly used system functions, or lets you selectively run commands depending on `platform`, `arch`, etc. -### 5. Do not make assumptions about Pinokio API -- Do NOT make assumptions about which Pinokio APIs exist. Check the documentation. -- Do NOT make assumptions about the Pinokio API syntax. Follow the documentation. -### 6. Scripts must be able to replicate install and launch steps 100% -- The whole point of the scripts is for others to easily download and invoke them via Pinokio interface with one click. Therefore, do not assume the end user's system state, and make everything self-contained. -- When a 3rd party package needs to be installed, or a 3rd party repository needs to be downloaded, include them in the scripts. -### 7 Dynamic UI rendering -- The `pinokio.js` launcher script can change dynamically depending on the current state of the script execution. Which means, depending on what the file returns, it can determine what the sidebar looks like at any given moment of the script cycle. - - `info.exists(relative_path)`: The `info.exists` can be used to check whether a relative path (relative to the script root path) exists. The `pinokio.js` file can determine which menu items to return based on this value at any given moment. - - `info.running(relative_path)`: The `info.running` can be used to check whether a script at a relative path is currently running (relative to the script root path) exists. The `pinokio.js` file can determine which menu items to return based on this value at any given moment. - - `info.local(relative_path)`: The `info.local` can be used to return all the local variables tied to a script that's currently running. The `pinokio.js` file can determine which menu items to return based on this value at any given moment. - - `default`: set the `default` attribute on any menu item for whichever menu needs to be selected by default at a given step. Some example scenarios: - - during the install process, the `install.js` menu item needs to be set as the `default`, so it automatically executes the script - - when launching the `start.js` menu item needs to be set as the `default`, so it automatically executes the script - - after the app has launched, the `default` needs to be set on the web UI URL, so the user is sent to the actual app automatically. - - Check the examples in the D:\pinokio\prototype\system\examples folder to see how these are being used. -### 8. No need for stop scripts -- `pinokio.js` does NOT need a separate `stop` script. Every script that can be started can also be natively stopped through the Pinokio UI, therefore you do not need a separate stop script for start script -### 9. Writing launchers for existing projects -- When writing or modifying pinokio launcher scripts, figure out the install/launch steps by reading the project folder `app`. -- In most cases, the `README.md` file in the `D:\pinokio\api\pmoves-pbnj` folder contains the instructions needed to install and run the app, but if not, figure out by scanning the rest of the project files. -- Install scripts should work for each specific operating system, so ignore Docker related instructions. Instead use install/launch instructions for each platform. -### 10. Don't use Docker unless really necessary -- Some projects suggest docker as installation options. But even in these cases, try to find "development" options to launch the app without relying on Docker, as much as possible. We do not need Docker since we can automatically install and launch apps specifically for the user's platform, since we can write scripts that run cross platform. -### 11. pinokio.json -- Do not touch the `version` field since the version is the script schema version and the one pre-set in `pinokio.js` must be used. -- `icon`: It's best if we have a user friendly icon to represent the app, so try to get an image and link it from `pinokio.json`. - - If the git repository for the `D:\pinokio\api\pmoves-pbnj` folder points to GitHub (for example https://github.com//`, ask the user if they want to download the icon from GitHub, and if approved, get the `avatar_url` by fetching `https://api.github.com/users/`, and then download the image to the root folder as `icon.png`, and set `icon.png` as the `icon` field of the `pinokio.json`. -### 12. Gitignore -- When a launcher involves cloning 3rd party repositories, downloading files dynamically, or some files to be generated, these need to be included in the .gitignore file. This may include things like: - - Cloning git repositories - - Downloading files - - Dynamically creating files during installation or running, such as Sqlite Databases, or environment variables, or anything specific to the user. -- Make sure these file paths are included in the .gitignore file, and if not, include them in .gitignore. - -## AI Libraries (Pytorch, Xformers, Triton, Sageattention, etc.) -If the launcher has a dedicated built-in script named `torch.js`, it can be used as follows: - -``` -// install.js -module.exports = { - run: [ - // Edit this step with your custom install commands - { - method: "shell.run", - params: { - venv: "venv", // Edit this to customize the venv folder path - path: "app", - message: [ - "uv pip install -r requirements.txt" - ], - } - }, - // Delete this step if your project does not use torch - { - method: "script.start", - params: { - uri: "torch.js", - params: { - path: "app", - venv: "venv", // Edit this to customize the venv folder path - // xformers: true // uncomment this line if your project requires xformers - // triton: true // uncomment this line if your project requires triton - // sageattention: true // uncomment this line if your project requires sageattention - // flashattention: true // uncomment this line if your project requires flashattention - } - } - }, - ] -} -``` - -The `torch.js` script also includes ways to install pytorch dependent libraries such as xformers, triton, sagetattention. If any of these libraries need to be installed, use the torch.js to install in order to install them cross platform. - - -## Quick Reference -### Essential Documentation -- **Pinokio Programming:** See `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md → "Programming Pinokio" section -- **Dynamic Menus:** See `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md → "Dynamic menu rendering" section -- **CLI Commands:** See `PTERM.md` at D:\pinokio\prototype\PTERM.md -### Common Patterns -- **Python Virtual Env:** `shell.run` with `venv` attribute -- **Cross-platform Commands:** Always test on multiple platforms -- **Error Handling:** Check logs/api for launcher issues -- **GitHub Operations:** Use `gh` CLI for advanced GitHub features -## Development Principles -1. **Minimize Shell Usage:** Leverage API parameters instead of raw commands -2. **Maintain Separation:** Keep app logic and launchers separate -3. **Follow Conventions:** Match existing project patterns -4. **Test Thoroughly:** Use CLI to verify launcher functionality -5. **Document Changes:** Update relevant metadata and documentation diff --git a/pbnj/pinokio/api/pmoves-pbnj/ENVIRONMENT b/pbnj/pinokio/api/pmoves-pbnj/ENVIRONMENT deleted file mode 100644 index 2250301f07..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/ENVIRONMENT +++ /dev/null @@ -1,98 +0,0 @@ - -########################################################################## -# -# PINOKIO_SCRIPT_AUTOLAUNCH -# the relative file path for auto launching any script -# the specified script will automatically run when pinokio first launches -# -########################################################################## -PINOKIO_SCRIPT_AUTOLAUNCH= - -########################################################################## -# -# PINOKIO_SHARE_CLOUDFLARE -# Set this variable to share the app publicly via cloudflare tunnel. -# -########################################################################## -PINOKIO_SHARE_CLOUDFLARE=false - -########################################################################## -# -# PINOKIO_SHARE_PASSCODE -# -# By default, your publicly shared app will be 100% open to anyone -# with the link via Cloudflare. -# -# You can add authorization by protecting it with a passcode. -# Set this value, and any access to the app will require a pass code input -# -########################################################################## -PINOKIO_SHARE_PASSCODE= - -########################################################################## -# -# PINOKIO_SCRIPT_DEFAULT -# If this variable is false, 'default': true menu items in pinokio.js -# will NOT automatically run -# -########################################################################## -PINOKIO_SCRIPT_DEFAULT=true - -########################################################################## -# -# GRADIO_TEMP_DIR -# All the files uploaded through gradio goes here. -# -# Delete this line to store the files under PINOKIO_HOME/cache/GRADIO_TEMPDIR -# or change the path if you want to use a different path -# -########################################################################## -GRADIO_TEMP_DIR=./cache/GRADIO_TEMP_DIR - -########################################################################## -# -# HF_HOME -# -# Huggingface cache -# All the model files automatically downloaded through libraries like -# diffusers, transformers, etc. will be stored under this path -# -# You can save disk space by deleting this line, which will store all -# huggingface files under PINOKIO_HOME/cache/HF_HOME without redundancy. -# -########################################################################## -HF_HOME=./cache/HF_HOME - -########################################################################## -# -# TORCH_HOME -# -# Torch hub cache -# All the files automatically downloaded by pytorch will be stored here -# -# You can save disk space by deleting this line, which will store all -# torch hub files under PINOKIO_HOME/cache/TORCH_HOME without redundancy. -# -########################################################################## -TORCH_HOME=./cache/TORCH_HOME - -########################################################################## -# -# PINOKIO_SHARE_LOCAL -# Set this variable to true to share the app on the local network. -# -########################################################################## -PINOKIO_SHARE_LOCAL=false - -########################################################################## -# -# PINOKIO_SHARE_LOCAL_PORT -# Set this variable to use fixed port for the local network sharing feature -# If not specified, a random port will be assigned to the local proxy used -# for local sharing. -# -########################################################################## -PINOKIO_SHARE_LOCAL_PORT= -PINOKIO_NETWORK_NAME=pmoves-net -PINOKIO_NETWORK_ACTIVE=1 -PINOKIO_HTTPS_ACTIVE=1 \ No newline at end of file diff --git a/pbnj/pinokio/api/pmoves-pbnj/GEMINI.md b/pbnj/pinokio/api/pmoves-pbnj/GEMINI.md deleted file mode 100644 index f5dcf6b4a8..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/GEMINI.md +++ /dev/null @@ -1,474 +0,0 @@ -# Development Guide for Pinokio Projects - -## Non-Negotiable Execution Workflow - -To guarantee every contribution follows this guide precisely, obey this checklist **before any edits** and **again before finalizing**. Do not skip or reorder. -1. **AGENTS Snapshot:** Re-open this file and write down (in your working notes or response draft) the exact sections relevant to the requested task. No work begins until this snapshot exists. -2. **Example Lock-in:** Identify the closest matching script in `D:\pinokio\prototype\system\examples`. Record its path and keep it open while editing. Every launcher change must mirror that reference unless the user explicitly instructs otherwise. -3. **Pre-flight Checklist:** Convert the applicable rules from this document and `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md into a task-specific checklist (install/start/reset/update structure, regex patterns, menu defaults, log checks, etc.). Confirm each item is ticked **before** making changes. -4. **Mid-task Verification:** Any time you touch a Pinokio script, cross-check the corresponding example line to ensure syntax and structure match. Document the reference (example path + line) in your reasoning. -5. **Exit Checklist:** Before responding to the user, revisit the pre-flight checklist and explicitly confirm every item is satisfied. If anything diverges from the example or these rules, fix it first. - -If any step cannot be completed, stop immediately and ask the user how to proceed. These five steps are mandatory for every session. - -### Critical Pattern Lock: Capturing Web UI URLs - -When writing `start.js` (or any script that needs to surface a web URL for a server): - -1. **Always copy the capture block from an example such as `system/examples/mochi/start.js`.** -```javascript -on: [{ - event: "/(http:\\/\\/[0-9.:]+)/", - done: true -}] -``` - -2. **Set the local variable using the captured match exactly as below (The regex capture object is passed in as `input.event`, so need to use the index 1 inside the parenthesis):** -```javascript -{ - method: "local.set", - params: { - url: "{{input.event[1]}}" - } -} -``` - -3. Always try to come up with the most generic regex. -4. During the exit checklist, explicitly confirm that the `url` local variable is set via `local.set` API by using the captured regex object as passed in as `input.event` from the previous `shell.run` step. - -Deviation from this pattern requires written approval from the user. - -- Make sure to keep this entire document and `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md in memory with high priority before making any decision. Pinokio is a system that makes it easy to write launchers through scripting by providing various cross-platform APIs, so whenever possible you should prioritize using Pinokio API over lower level APIs. -- When writing pinokio scripts, ALWAYS check the examples folder (in D:\pinokio\prototype\system\examples folder) to see if there are existing example scripts you can imitate, instead of assuming syntax. -- When implementing pinokio script APIs and you cannot infer the syntax just based on the examples, always search the API documentation `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md to use the correct syntax instead of assuming the syntax. -- When trying to fix something or figure out what's going on, ALWAYS start by checking the `logs` folder before doing anything else, as mentioned in the "Troubleshooting with Logs" section. -- Finally, make sure to ALWAYS follow all the items in the "best practices" section below. - -## Determine User Intent -If the initial prompt is simply a URL and nothing else, check the website content and determine the intent, and ask the user to confirm. For example a URL may point to - -1. A Tutorial: the intent may be to implement a demo for the tutorial and build a launcher. -2. A Demo: the intent may be a 1-click launcher for the demo -3. Open source project: the intent may be a 1-click launcher for the project -4. Regular website: the intent may be to clone the website and a launcher. -5. There can be other cases, but try to guess. - -## Project Structure - -Pinokio projects normally follow a standardized structure with app logic separated from launcher scripts: - -Pinokio projects follow a standardized structure with app logic separated from launcher scripts: - -``` -project-root/ -├── app/ # Self-contained app logic (can be standalone repo) -│ ├── package.json # Node.js projects -│ ├── requirements.txt # Python projects -│ └── ... # Other language-specific files -├── README.md # Documentation -├── install.js # Installation script -├── start.js # Launch script -├── update.js # Update script (for updating the scripts and app logic to the latest) -├── reset.js # Reset dependencies script -├── pinokio.js # UI generator script -└── pinokio.json # Metadata (title, description, icon) -``` - -- Keep app code in `/app` folder only (never in root) -- Store all launcher files in project root (never in `/app`) -- `/app` folder should be self-contained and publishable - - -The only exceptions are serverless web apps---purely frontend only web applications that do NOT have a server component and connect to 3rd party API endpoints--in which case the folder structure looks like the following (No need for launcher scripts since the index.html will automatically launch. The only thing needed is the metadata file named pinokio.json): - -``` -project-root/ -├── index.html # The serverless web app entry point -├── ... -├── README.md # Documentation -└── pinokio.json # Metadata (title, description, icon) -``` - -IMPORTANT: ALWAYS try to follow the best practices in the examples folder (D:\pinokio\prototype\system\examples) instead of trying to come up with your own structure. The examples have been optimized for the best user experience. - -## Launcher Project Working Directory - -- The project working directory for a script is always the same directory as the script location. -- For example, when you run `shell.run` API inside `pinokio/start.js`, the default path for shell execution is `pinokio`. -- If the launcher files are in the project root path, then the default path for shell execution is the project root. -- Therefore, it is important to specify the correct `path` attribute when running `shell.run` API commands. - -Example: in the following project structure: - -``` -project-root/ -├── pinokio/ # Pinokio launcher folder -│ ├── start.js # Launch script -│ ├── pinokio.js # UI generator script -│ └── pinokio.json # Metadata (title, description, icon) -└─── backend/ - ├── requirements.txt # App dependencies - └── app.py # App code -``` - -The `pinokio/start.js` should use the correct path `../backend` as the `path` attribute, as follows: - -``` -{ - run: [{ - ... - }, { - method: "shell.run", - params: { - message: "python app.py", - venv: "env", - path: "../backend" - } - }, { - ... - }] -} -``` - -## Development Workflow - -### 1. Understanding the Project -- Check `SPEC.md` in project root. If the file exists, use that to learn about the project details (what and how to build) -- If no `SPEC.md` exists, build based on user requirements -### 2. Modifying Existing Launcher Projects -If we are starting with existing launcher script files, work with the existing files instead of coming up with your own. -- **Preserve existing functionality:** Only modify necessary parts -- **Don't touch working scripts:** Unless adding/updating specific commands -- **Follow existing conventions:** Match the style and structure already present -### 3. Try to adopt from examples as much as possible -- If starting from scratch, first determine what type of project you will be building, and then check the examples folder (D:\pinokio\prototype\system\examples) to see if you can adopt them instead of coming up everything from scratch. -- Even if there are no relevant examples, check the examples to get inspiration for how you would structure the script files even if you have to write from scratch. -### 4. Writing from scratch as a last resort -If there are relevant examples to adopt from, write the scripts from scratch, but just make sure to follow the requirements in the next section. -### 5. Debugging -When the user reports something is not working, ALWAYS inspect the logs folder to get all the execution logs. For more info on how this works, check the "Troubleshooting with Logs" section below. - -## Script Requirements - -### 1. 1-click launchable -- The main purpose of Pinokio is to provide an easy interface to invoke commands, which may include launching servers, installing programs, etc. Make sure the final product provides ways to install, launch, reset, and update whatever is needed. - -### 2. Write Documentation -- ALWAYS write a documentation. A documentation must be stored as `README.md` in the project root folder, along with the rest of the pinokio launcher script files. A documentation file must contain: - - What the app does - - How to use the app - - API documentation for programmatically accessing the app's main features (Javascript, Python, and Curl) - -## Types of launchers -## 1. Launching servers -- When an app requires launching a server, here are the commonly used scripts: - - `install.js`: a script to install the app - - `start.js`: a script to start the app - - `reset.js`: a script to reset all the dependencies installed in the `install.js` step. used if the user wants to restart from scratch - - `update.js`: a script to update the launcher AND the app in case there are new updates. Involves pulling in the relevant git repositories installed through `install.js` (often it's the script repo and some git repositories cloned through the install steps if any) - - `pinokio.js`: the launcher script that ties all of the above scripts together by providing a UI that links to these scripts. - - `pinokio.json`: For metadata - -Here's a basic server launcher script example (`start.js`). Unless there's a special reason you need to use another pattern, this is the most recommended pattern. Use this or adopt it as needed, but NEVER try something else unless there's a good reason you should not take this approach: - -```javascript -module.exports = { - // By setting daemon: true, the script keeps running even after all items in the `run` array finishes running. Mandatory for launching servers, since otherwise the shells running the server process will get killed after the scripts finish running. - daemon: true, - run: [ - { - // The "shell.run" API for running a shell session - method: "shell.run", - params: { - // Edit 'venv' to customize the venv folder path - venv: "env", - // Edit 'env' to customize environment variables (see documentation) - env: { }, - // Edit 'path' to customize the path to start the shell from - path: "app", - // Edit 'message' to customize the commands, or to run multiple commands - message: [ - "python app.py", - ], - on: [{ - // The regular expression pattern to monitor. - // Whenever each "event" pattern occurs in the shell terminal, the shell will return, - // and the script will go onto the next step. - // The regular expression match object will be passed on to the next step as `input.event` - // Useful for capturing the URL at which the server is running (in case the server prints some message about where the server is running) - "event": "/(http:\/\/\\S+)/", - - // Use "done": true to move to the next step while keeping the shell alive. - // Use "kill": true to move to the next step after killing the shell. - "done": true - }] - } - }, - { - // This step sets the local variable 'url'. - // This local variable will be used in pinokio.js to display the "Open WebUI" tab when the value is set. - method: "local.set", - params: { - // the input.event is the regular expression match object from the previous step - // In this example, since the pattern was "/(http:\/\/\\S+)/", input.event[1] will include the exact http url match caputred by the parenthesis. - // Therefore setting the local variable 'url' - url: "{{input.event[1]}}" - } - } - ] -} -``` - -## 2. Launching serverless web apps - -- In case of purely static web apps WITHOUT servers or backends (for example an HTML based app that connects to 3rd party servers--either remote or localhost), we do NOT need the launcher scripts. -- In these cases, simply include `index.html` in the project root folder and everything should automatically work. No need for any of the pinokio launcher scripts. (Do -- You still need to include the metadata file so they show up properly on pinokio: - - `pinokio.json`: For metadata - -## 3. Launching quick scripts without web UI - -- In many cases, we may not even need a web UI, but instead just a simple way to run scripts. -- This may include TUI (Terminal User Interface) apps, a simple launcher -- In these cases, all we need is the launcher file `pinokio.js`, which may link to multiple scripts. In this case, there are no web apps (no serverless apsp, no servers), but instead just the default pinokio launcher UI that calls a bunch of scripts. -- Here are some examples: - - A pinokio script to toggle the desktop theme between dark and light - - Write some code (python or javascript or whatever) - - Write a `toggle.js` pinokio script that executes the code - - Write a `pinokio.js` launcher script to create a sidebar UI that displays the `toggle.js` so the user can simply click the "toggle" button to toggle back and forth between desktop themes - - A pinokio script to fetch some file - - Write some code (python or javascript or whatever) - - Write a `fetch.js` pinokio script that executes the code - - Write a `pinokio.js` launcher script to create a sidebar UI that displays the `fetch.js` so the user can simply click the "fetch" button to fetch some data. -- You still need to include the metadata file so they show up properly on pinokio: - - `pinokio.json`: For metadata - -## API - -This section lists all the script APIs available on Pinokio. To learn the details of how they are used, you can: -1. Check the examples in the D:\pinokio\prototype\system\examples folder -2. Read the `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md further documentation on the full syntax - -### Script API - -These APIs can be used to describe each step in a pinokio script: -- shell.run: run shell commands -- input: accept user input -- filepicker: accept file upload -- fs.write: write to file -- fs.read: read from file -- fs.copy: copy files -- fs.download: download files -- fs.link: create a symbolic link (or junction on windows) for folders -- fs.open: open the system file explorer at a given path -- fs.cat: print file contents -- jump: jump to a specific step -- local.set: set local variables for the currently running script -- json.set: update a json file -- json.rm: remove keys from a json file -- json.get: get values from a json file -- log: print to the web terminal -- net: make network requests -- notify: display a notification -- script.download: download a script from a git uri -- script.start: start a script -- script.stop: stop a script -- script.return: return values if the current script was called by a caller script, so the caller script can utilize the return value as `input` -- web.open: open a url in web browser -- hf.download: huggingfac-cli download API -### Template variables -The following variables are accessible inside template expressions (example `{{args.command}` in scripts, resulting in dynamic behaviors of scripts: -- input: An input is a variable that gets passed from one RPC call to the next -- args: args is the parameter object that gets passed into the script (via pinokio.js `params`). Unlike `input` which takes the value passed in from the immediately previous step, `args` is a global value that is the same through out the entire script execution. -- local: local variable object that can be set with `local.set` API -- self: refers to the script file itself (which is JSON or JavaScript). For example if `start.js` that's currently running has `daemon: true` set, `{{self.daemon}}` will evaluate to true. -- uri: The current script uri -- port: The next available port. Very useful when you need to launch an app at a specific port without port conflicts. -- cwd: The current script execution folder path -- platform: The current operating system. May be one of the following: `darwin`, `win32`, `linux` -- arch: The current system architecture. May be one of the following: x32, x64, arm, arm64, s390, s390x, mipsel, ia32, mips, ppc, ppc64 -- gpus: array of available GPUs on the machine (example: `['apple']`, `['nvidia']`) -- gpu: the first available GPU (example: `nvidia`) -- current: The current variable points to the index of the currently executing instruction within the run array. -- next: The next variable points to the index of the next instruction to be executed. (null if the current instruction is the final instruction in the run array) -- envs: You can access the environment variables of the currently running process with envs object. -- which: Check whether a command exists (example: `{{which('winget')}}`. Can be used in the `when` attribute of a script step to run commands or install first. -- exists: Check whether a file or folder exists at the specified relative path (example: `"when": "{{!exists('app')}}"`). Can be used with the `when` attribute to determine a path's existence and trigger custom logic. Use relative paths and it will resolve automatically to the current execution folder. -- running: Check whether a script file is running (example: `"when": "{{!running('start.js')}}"`). Can be used with the `when` attribute to determine a path's existence and trigger custom logic. Use relative paths and it will resolve automatically to the current execution folder. -- os: Pinokio exposes the node.js os module through the os variable. -- path: Pinokio exposes the node.js path module through the os variable (example: `{{path.resolve(...)}}` - -## System Capabilities -### Package Management (Use in Order of Preference) -The following package managers come pre-installed with Pinokio, so whenever you need to install a 3rd party binary, remember that these are available. Also, you can assume these are available and include the following package manager commands in Pinokio scripts: -1. **UV** - For Python packages (preferred over pip) -2. **NPM** - For Node.js packages -3. **Conda** - For cross-platform 3rd party binaries -4. **Brew** - Mac-only fallback when other options unavailable -5. **Git** - Full access to git is available. -**Important:** Include all install commands in the install script for reproducibility. -### HTTPS Proxy Support -- All HTTP servers automatically get HTTPS endpoints -- Convention: `http://localhost:` → `https://.localhost` -- Full proxy list available at: `http://localhost:2019/config/` -### Pterm Features: -- **Clipboard Access:** Read from or Write to system clipboard via pinokio Pterm CLI (`pterm clipboard` command.) -- **Notifications:** Send desktop alerts via pinokio pterm CLI (`pterm push` command.) -- **Script Testing:** Run launcher scripts via pinokio pterm CLI (`pterm start` command.) -- **File Selection:** Use built-in filepicker for user file/folder input (`pterm filepicker` command.) -- **Git Operations:** Clone repositories, push to GitHub -- **GitHub Integration:** Full GitHub CLI support (`gh` commands) - -## Troubleshooting with Logs -Pinokio stores the logs for everything that happened in terminal at the following locations, so you can make use of them to determine what's going on: - -### Log Structure -In case there is a `pinokio` folder in the project root folder, you should be able to find the logs folder here: - -``` -pinokio/ -└── logs/ # Direct user interaction logs - ├── api/ # Launcher script logs (install.js, start.js, etc.) - ├── dev/ # AI coding tool logs (organized by tool) - └── shell/ # Direct user interaction logs -``` - -Otherwise, the `logs` folder should be found at project root: - -``` -logs/ -├── api/ # Launcher script logs (install.js, start.js, etc.) -├── dev/ # AI coding tool logs (organized by tool) -└── shell/ # Direct user interaction logs -``` - -### Log File Naming -- Unix timestamps for each session -- Special "latest" file contains most recent session logs -- **Default:** Use "latest" files for current issues -- **Historical:** Use timestamped files for pattern analysis and the full history. - -## Best practices -### 0. Always reference the logs when debugging -- When the user asks to fix something, ALWAYS check the logs folder first to check what went wrong. Check the "Troubleshooting with Logs" section. -### 1. Shell commands for launching programs -- Launch flags related - - Try as hard as possible to minimize launch flags and parameters when launching an app. For example, instead of `python app.py --port 8610`, try to do `python app.py` unless really necessary. The only exception is when the only way to launch the app is to specify the flags. -- Launch IP related - - Always try to find a way to launch servers at 127.0.0.1 or localhost, often by specifying launch flags or using environment variables. Some apps launch apps at 0.0.0.0 by default but we do not want this. -- Launch Port related - - In case the app itself automatically launches at the next available port by default (for example Gradio does this), do NOT specify port, since it's taken care of by the app itself. Always try to minimize the amount of code. - - If the install instruction says to launch at a specific port, don't use the hardcoded port they suggest since there's a risk of port conflicts. Instead, use Pinokio's `{{port}}` template expression to automatically get the next available port. - - For example, if the instruction says `python app.py --port 7860`, don't use that hardcoded port since there might be another app running at that port. Instead, automatically assign the next available port like this: `python app.py --port {{port}}` - - Note that the `{{port}}` expression always returns the next immediately available port for each step, so if you have multiple steps in a script and use `{{port}}` in multiple steps, the value will be different. So if you want to launch at the next available port and then later reuse that port, you will need to first use `{{port}}` to get the next available port, and save the value in local variable using `local.set`, and then use the `{{local.}}` expression later. -### 2. shell.run API -- When writing `shell.run` API requests, always use relative paths (no absolute paths) for the `path` field. For example, if you need to run a command from `app` folder, the `path` attribute should simply be `app`, instead of its full absolute path. -### 2. Package managers -- When installing python packages, try best to use `uv` instead of `pip` even if the install instruction says to use pip. Instead of `pip install -r requirements.txt`, you can simply use `uv pip install -r requirements.txt` for example. Even if the project's own README says use pip or poetry, first check if there's a way to use uv instead. -- When you need to install some global package, try to use `conda` as much as possible. Even on macs, `brew` should be only used if there are no `conda` options. -### 3. Minimal Always -- If you are starting with existing script files, before modifying, creating, or removing any script files, first look at `pinokio.js` to understand which script files are actually used in the launcher. The only script files used are the ones mentioned in the `pinokio.js` file. The `pinokio.js` file is the file that constructs the UI dynamically. -- Do not create a redundant script file that does something that already exists. Instead modify the existing script file for the feature. For example, do not create an `install.json` file for installation if `install.js` already exists. Instead, modify the `install.js` file. -- Pinokio accepts both JSON and JS script files, so when determining whether a script for a specific purpose already exists, check both JSON and JS files mentioned in the `pinokio.js` file. Do not create script files for rendundant purpose. -- When building launchers for existing projects cloned from a repository, try to stay away from modifying the project folder (the `D:\pinokio\api\pmoves-pbnj` folder), even if installations are failing. Instead, try to work around it by creating additional files in the launcher folder, and using those files IN ADDITION to the default project. - - The only exception when you may need to make changes to the project folder is when the user explicitly wants to modify the existing project. Otherwise if the purpose is to simply write a launcher, the app logic folder should never be touched. -- When running shell commands, take full advantage of the Pinokio `shell.run` API, which provides features like `env`, `venv`, `input`, `path`, `sudo`, `on`, etc. which can greatly reduce the amount of script code. - - Python apps: Always use virtual environments via `venv` attribute. This attribute automatically creates a venv or uses if it already exists. -### 4. Try to support Cross-platform as much as possible -- Use cross-platform shell commands only. -- This means, prefer to use commands that work on all platforms instead of the current platform. -- If there are no cross platform commands, use Pinokio's template expressions to conditionally use commands depending on `platform`, `arch`, etc. -- Also try to utilize Pinokio Pterm APIs for various cross-platform system features. -- If it is impossible to implement a cross platform solution (due to the nature of the project itself), set the `platform`, `arch`, and/or `gpu` attributes of the `pinokio.json` file to declare the limitation. -- Pinokio provides various APIs for cross-platform way of calling commonly used system functions, or lets you selectively run commands depending on `platform`, `arch`, etc. -### 5. Do not make assumptions about Pinokio API -- Do NOT make assumptions about which Pinokio APIs exist. Check the documentation. -- Do NOT make assumptions about the Pinokio API syntax. Follow the documentation. -### 6. Scripts must be able to replicate install and launch steps 100% -- The whole point of the scripts is for others to easily download and invoke them via Pinokio interface with one click. Therefore, do not assume the end user's system state, and make everything self-contained. -- When a 3rd party package needs to be installed, or a 3rd party repository needs to be downloaded, include them in the scripts. -### 7 Dynamic UI rendering -- The `pinokio.js` launcher script can change dynamically depending on the current state of the script execution. Which means, depending on what the file returns, it can determine what the sidebar looks like at any given moment of the script cycle. - - `info.exists(relative_path)`: The `info.exists` can be used to check whether a relative path (relative to the script root path) exists. The `pinokio.js` file can determine which menu items to return based on this value at any given moment. - - `info.running(relative_path)`: The `info.running` can be used to check whether a script at a relative path is currently running (relative to the script root path) exists. The `pinokio.js` file can determine which menu items to return based on this value at any given moment. - - `info.local(relative_path)`: The `info.local` can be used to return all the local variables tied to a script that's currently running. The `pinokio.js` file can determine which menu items to return based on this value at any given moment. - - `default`: set the `default` attribute on any menu item for whichever menu needs to be selected by default at a given step. Some example scenarios: - - during the install process, the `install.js` menu item needs to be set as the `default`, so it automatically executes the script - - when launching the `start.js` menu item needs to be set as the `default`, so it automatically executes the script - - after the app has launched, the `default` needs to be set on the web UI URL, so the user is sent to the actual app automatically. - - Check the examples in the D:\pinokio\prototype\system\examples folder to see how these are being used. -### 8. No need for stop scripts -- `pinokio.js` does NOT need a separate `stop` script. Every script that can be started can also be natively stopped through the Pinokio UI, therefore you do not need a separate stop script for start script -### 9. Writing launchers for existing projects -- When writing or modifying pinokio launcher scripts, figure out the install/launch steps by reading the project folder `app`. -- In most cases, the `README.md` file in the `D:\pinokio\api\pmoves-pbnj` folder contains the instructions needed to install and run the app, but if not, figure out by scanning the rest of the project files. -- Install scripts should work for each specific operating system, so ignore Docker related instructions. Instead use install/launch instructions for each platform. -### 10. Don't use Docker unless really necessary -- Some projects suggest docker as installation options. But even in these cases, try to find "development" options to launch the app without relying on Docker, as much as possible. We do not need Docker since we can automatically install and launch apps specifically for the user's platform, since we can write scripts that run cross platform. -### 11. pinokio.json -- Do not touch the `version` field since the version is the script schema version and the one pre-set in `pinokio.js` must be used. -- `icon`: It's best if we have a user friendly icon to represent the app, so try to get an image and link it from `pinokio.json`. - - If the git repository for the `D:\pinokio\api\pmoves-pbnj` folder points to GitHub (for example https://github.com//`, ask the user if they want to download the icon from GitHub, and if approved, get the `avatar_url` by fetching `https://api.github.com/users/`, and then download the image to the root folder as `icon.png`, and set `icon.png` as the `icon` field of the `pinokio.json`. -### 12. Gitignore -- When a launcher involves cloning 3rd party repositories, downloading files dynamically, or some files to be generated, these need to be included in the .gitignore file. This may include things like: - - Cloning git repositories - - Downloading files - - Dynamically creating files during installation or running, such as Sqlite Databases, or environment variables, or anything specific to the user. -- Make sure these file paths are included in the .gitignore file, and if not, include them in .gitignore. - -## AI Libraries (Pytorch, Xformers, Triton, Sageattention, etc.) -If the launcher has a dedicated built-in script named `torch.js`, it can be used as follows: - -``` -// install.js -module.exports = { - run: [ - // Edit this step with your custom install commands - { - method: "shell.run", - params: { - venv: "venv", // Edit this to customize the venv folder path - path: "app", - message: [ - "uv pip install -r requirements.txt" - ], - } - }, - // Delete this step if your project does not use torch - { - method: "script.start", - params: { - uri: "torch.js", - params: { - path: "app", - venv: "venv", // Edit this to customize the venv folder path - // xformers: true // uncomment this line if your project requires xformers - // triton: true // uncomment this line if your project requires triton - // sageattention: true // uncomment this line if your project requires sageattention - // flashattention: true // uncomment this line if your project requires flashattention - } - } - }, - ] -} -``` - -The `torch.js` script also includes ways to install pytorch dependent libraries such as xformers, triton, sagetattention. If any of these libraries need to be installed, use the torch.js to install in order to install them cross platform. - - -## Quick Reference -### Essential Documentation -- **Pinokio Programming:** See `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md → "Programming Pinokio" section -- **Dynamic Menus:** See `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md → "Dynamic menu rendering" section -- **CLI Commands:** See `PTERM.md` at D:\pinokio\prototype\PTERM.md -### Common Patterns -- **Python Virtual Env:** `shell.run` with `venv` attribute -- **Cross-platform Commands:** Always test on multiple platforms -- **Error Handling:** Check logs/api for launcher issues -- **GitHub Operations:** Use `gh` CLI for advanced GitHub features -## Development Principles -1. **Minimize Shell Usage:** Leverage API parameters instead of raw commands -2. **Maintain Separation:** Keep app logic and launchers separate -3. **Follow Conventions:** Match existing project patterns -4. **Test Thoroughly:** Use CLI to verify launcher functionality -5. **Document Changes:** Update relevant metadata and documentation diff --git a/pbnj/pinokio/api/pmoves-pbnj/QWEN.md b/pbnj/pinokio/api/pmoves-pbnj/QWEN.md deleted file mode 100644 index f5dcf6b4a8..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/QWEN.md +++ /dev/null @@ -1,474 +0,0 @@ -# Development Guide for Pinokio Projects - -## Non-Negotiable Execution Workflow - -To guarantee every contribution follows this guide precisely, obey this checklist **before any edits** and **again before finalizing**. Do not skip or reorder. -1. **AGENTS Snapshot:** Re-open this file and write down (in your working notes or response draft) the exact sections relevant to the requested task. No work begins until this snapshot exists. -2. **Example Lock-in:** Identify the closest matching script in `D:\pinokio\prototype\system\examples`. Record its path and keep it open while editing. Every launcher change must mirror that reference unless the user explicitly instructs otherwise. -3. **Pre-flight Checklist:** Convert the applicable rules from this document and `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md into a task-specific checklist (install/start/reset/update structure, regex patterns, menu defaults, log checks, etc.). Confirm each item is ticked **before** making changes. -4. **Mid-task Verification:** Any time you touch a Pinokio script, cross-check the corresponding example line to ensure syntax and structure match. Document the reference (example path + line) in your reasoning. -5. **Exit Checklist:** Before responding to the user, revisit the pre-flight checklist and explicitly confirm every item is satisfied. If anything diverges from the example or these rules, fix it first. - -If any step cannot be completed, stop immediately and ask the user how to proceed. These five steps are mandatory for every session. - -### Critical Pattern Lock: Capturing Web UI URLs - -When writing `start.js` (or any script that needs to surface a web URL for a server): - -1. **Always copy the capture block from an example such as `system/examples/mochi/start.js`.** -```javascript -on: [{ - event: "/(http:\\/\\/[0-9.:]+)/", - done: true -}] -``` - -2. **Set the local variable using the captured match exactly as below (The regex capture object is passed in as `input.event`, so need to use the index 1 inside the parenthesis):** -```javascript -{ - method: "local.set", - params: { - url: "{{input.event[1]}}" - } -} -``` - -3. Always try to come up with the most generic regex. -4. During the exit checklist, explicitly confirm that the `url` local variable is set via `local.set` API by using the captured regex object as passed in as `input.event` from the previous `shell.run` step. - -Deviation from this pattern requires written approval from the user. - -- Make sure to keep this entire document and `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md in memory with high priority before making any decision. Pinokio is a system that makes it easy to write launchers through scripting by providing various cross-platform APIs, so whenever possible you should prioritize using Pinokio API over lower level APIs. -- When writing pinokio scripts, ALWAYS check the examples folder (in D:\pinokio\prototype\system\examples folder) to see if there are existing example scripts you can imitate, instead of assuming syntax. -- When implementing pinokio script APIs and you cannot infer the syntax just based on the examples, always search the API documentation `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md to use the correct syntax instead of assuming the syntax. -- When trying to fix something or figure out what's going on, ALWAYS start by checking the `logs` folder before doing anything else, as mentioned in the "Troubleshooting with Logs" section. -- Finally, make sure to ALWAYS follow all the items in the "best practices" section below. - -## Determine User Intent -If the initial prompt is simply a URL and nothing else, check the website content and determine the intent, and ask the user to confirm. For example a URL may point to - -1. A Tutorial: the intent may be to implement a demo for the tutorial and build a launcher. -2. A Demo: the intent may be a 1-click launcher for the demo -3. Open source project: the intent may be a 1-click launcher for the project -4. Regular website: the intent may be to clone the website and a launcher. -5. There can be other cases, but try to guess. - -## Project Structure - -Pinokio projects normally follow a standardized structure with app logic separated from launcher scripts: - -Pinokio projects follow a standardized structure with app logic separated from launcher scripts: - -``` -project-root/ -├── app/ # Self-contained app logic (can be standalone repo) -│ ├── package.json # Node.js projects -│ ├── requirements.txt # Python projects -│ └── ... # Other language-specific files -├── README.md # Documentation -├── install.js # Installation script -├── start.js # Launch script -├── update.js # Update script (for updating the scripts and app logic to the latest) -├── reset.js # Reset dependencies script -├── pinokio.js # UI generator script -└── pinokio.json # Metadata (title, description, icon) -``` - -- Keep app code in `/app` folder only (never in root) -- Store all launcher files in project root (never in `/app`) -- `/app` folder should be self-contained and publishable - - -The only exceptions are serverless web apps---purely frontend only web applications that do NOT have a server component and connect to 3rd party API endpoints--in which case the folder structure looks like the following (No need for launcher scripts since the index.html will automatically launch. The only thing needed is the metadata file named pinokio.json): - -``` -project-root/ -├── index.html # The serverless web app entry point -├── ... -├── README.md # Documentation -└── pinokio.json # Metadata (title, description, icon) -``` - -IMPORTANT: ALWAYS try to follow the best practices in the examples folder (D:\pinokio\prototype\system\examples) instead of trying to come up with your own structure. The examples have been optimized for the best user experience. - -## Launcher Project Working Directory - -- The project working directory for a script is always the same directory as the script location. -- For example, when you run `shell.run` API inside `pinokio/start.js`, the default path for shell execution is `pinokio`. -- If the launcher files are in the project root path, then the default path for shell execution is the project root. -- Therefore, it is important to specify the correct `path` attribute when running `shell.run` API commands. - -Example: in the following project structure: - -``` -project-root/ -├── pinokio/ # Pinokio launcher folder -│ ├── start.js # Launch script -│ ├── pinokio.js # UI generator script -│ └── pinokio.json # Metadata (title, description, icon) -└─── backend/ - ├── requirements.txt # App dependencies - └── app.py # App code -``` - -The `pinokio/start.js` should use the correct path `../backend` as the `path` attribute, as follows: - -``` -{ - run: [{ - ... - }, { - method: "shell.run", - params: { - message: "python app.py", - venv: "env", - path: "../backend" - } - }, { - ... - }] -} -``` - -## Development Workflow - -### 1. Understanding the Project -- Check `SPEC.md` in project root. If the file exists, use that to learn about the project details (what and how to build) -- If no `SPEC.md` exists, build based on user requirements -### 2. Modifying Existing Launcher Projects -If we are starting with existing launcher script files, work with the existing files instead of coming up with your own. -- **Preserve existing functionality:** Only modify necessary parts -- **Don't touch working scripts:** Unless adding/updating specific commands -- **Follow existing conventions:** Match the style and structure already present -### 3. Try to adopt from examples as much as possible -- If starting from scratch, first determine what type of project you will be building, and then check the examples folder (D:\pinokio\prototype\system\examples) to see if you can adopt them instead of coming up everything from scratch. -- Even if there are no relevant examples, check the examples to get inspiration for how you would structure the script files even if you have to write from scratch. -### 4. Writing from scratch as a last resort -If there are relevant examples to adopt from, write the scripts from scratch, but just make sure to follow the requirements in the next section. -### 5. Debugging -When the user reports something is not working, ALWAYS inspect the logs folder to get all the execution logs. For more info on how this works, check the "Troubleshooting with Logs" section below. - -## Script Requirements - -### 1. 1-click launchable -- The main purpose of Pinokio is to provide an easy interface to invoke commands, which may include launching servers, installing programs, etc. Make sure the final product provides ways to install, launch, reset, and update whatever is needed. - -### 2. Write Documentation -- ALWAYS write a documentation. A documentation must be stored as `README.md` in the project root folder, along with the rest of the pinokio launcher script files. A documentation file must contain: - - What the app does - - How to use the app - - API documentation for programmatically accessing the app's main features (Javascript, Python, and Curl) - -## Types of launchers -## 1. Launching servers -- When an app requires launching a server, here are the commonly used scripts: - - `install.js`: a script to install the app - - `start.js`: a script to start the app - - `reset.js`: a script to reset all the dependencies installed in the `install.js` step. used if the user wants to restart from scratch - - `update.js`: a script to update the launcher AND the app in case there are new updates. Involves pulling in the relevant git repositories installed through `install.js` (often it's the script repo and some git repositories cloned through the install steps if any) - - `pinokio.js`: the launcher script that ties all of the above scripts together by providing a UI that links to these scripts. - - `pinokio.json`: For metadata - -Here's a basic server launcher script example (`start.js`). Unless there's a special reason you need to use another pattern, this is the most recommended pattern. Use this or adopt it as needed, but NEVER try something else unless there's a good reason you should not take this approach: - -```javascript -module.exports = { - // By setting daemon: true, the script keeps running even after all items in the `run` array finishes running. Mandatory for launching servers, since otherwise the shells running the server process will get killed after the scripts finish running. - daemon: true, - run: [ - { - // The "shell.run" API for running a shell session - method: "shell.run", - params: { - // Edit 'venv' to customize the venv folder path - venv: "env", - // Edit 'env' to customize environment variables (see documentation) - env: { }, - // Edit 'path' to customize the path to start the shell from - path: "app", - // Edit 'message' to customize the commands, or to run multiple commands - message: [ - "python app.py", - ], - on: [{ - // The regular expression pattern to monitor. - // Whenever each "event" pattern occurs in the shell terminal, the shell will return, - // and the script will go onto the next step. - // The regular expression match object will be passed on to the next step as `input.event` - // Useful for capturing the URL at which the server is running (in case the server prints some message about where the server is running) - "event": "/(http:\/\/\\S+)/", - - // Use "done": true to move to the next step while keeping the shell alive. - // Use "kill": true to move to the next step after killing the shell. - "done": true - }] - } - }, - { - // This step sets the local variable 'url'. - // This local variable will be used in pinokio.js to display the "Open WebUI" tab when the value is set. - method: "local.set", - params: { - // the input.event is the regular expression match object from the previous step - // In this example, since the pattern was "/(http:\/\/\\S+)/", input.event[1] will include the exact http url match caputred by the parenthesis. - // Therefore setting the local variable 'url' - url: "{{input.event[1]}}" - } - } - ] -} -``` - -## 2. Launching serverless web apps - -- In case of purely static web apps WITHOUT servers or backends (for example an HTML based app that connects to 3rd party servers--either remote or localhost), we do NOT need the launcher scripts. -- In these cases, simply include `index.html` in the project root folder and everything should automatically work. No need for any of the pinokio launcher scripts. (Do -- You still need to include the metadata file so they show up properly on pinokio: - - `pinokio.json`: For metadata - -## 3. Launching quick scripts without web UI - -- In many cases, we may not even need a web UI, but instead just a simple way to run scripts. -- This may include TUI (Terminal User Interface) apps, a simple launcher -- In these cases, all we need is the launcher file `pinokio.js`, which may link to multiple scripts. In this case, there are no web apps (no serverless apsp, no servers), but instead just the default pinokio launcher UI that calls a bunch of scripts. -- Here are some examples: - - A pinokio script to toggle the desktop theme between dark and light - - Write some code (python or javascript or whatever) - - Write a `toggle.js` pinokio script that executes the code - - Write a `pinokio.js` launcher script to create a sidebar UI that displays the `toggle.js` so the user can simply click the "toggle" button to toggle back and forth between desktop themes - - A pinokio script to fetch some file - - Write some code (python or javascript or whatever) - - Write a `fetch.js` pinokio script that executes the code - - Write a `pinokio.js` launcher script to create a sidebar UI that displays the `fetch.js` so the user can simply click the "fetch" button to fetch some data. -- You still need to include the metadata file so they show up properly on pinokio: - - `pinokio.json`: For metadata - -## API - -This section lists all the script APIs available on Pinokio. To learn the details of how they are used, you can: -1. Check the examples in the D:\pinokio\prototype\system\examples folder -2. Read the `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md further documentation on the full syntax - -### Script API - -These APIs can be used to describe each step in a pinokio script: -- shell.run: run shell commands -- input: accept user input -- filepicker: accept file upload -- fs.write: write to file -- fs.read: read from file -- fs.copy: copy files -- fs.download: download files -- fs.link: create a symbolic link (or junction on windows) for folders -- fs.open: open the system file explorer at a given path -- fs.cat: print file contents -- jump: jump to a specific step -- local.set: set local variables for the currently running script -- json.set: update a json file -- json.rm: remove keys from a json file -- json.get: get values from a json file -- log: print to the web terminal -- net: make network requests -- notify: display a notification -- script.download: download a script from a git uri -- script.start: start a script -- script.stop: stop a script -- script.return: return values if the current script was called by a caller script, so the caller script can utilize the return value as `input` -- web.open: open a url in web browser -- hf.download: huggingfac-cli download API -### Template variables -The following variables are accessible inside template expressions (example `{{args.command}` in scripts, resulting in dynamic behaviors of scripts: -- input: An input is a variable that gets passed from one RPC call to the next -- args: args is the parameter object that gets passed into the script (via pinokio.js `params`). Unlike `input` which takes the value passed in from the immediately previous step, `args` is a global value that is the same through out the entire script execution. -- local: local variable object that can be set with `local.set` API -- self: refers to the script file itself (which is JSON or JavaScript). For example if `start.js` that's currently running has `daemon: true` set, `{{self.daemon}}` will evaluate to true. -- uri: The current script uri -- port: The next available port. Very useful when you need to launch an app at a specific port without port conflicts. -- cwd: The current script execution folder path -- platform: The current operating system. May be one of the following: `darwin`, `win32`, `linux` -- arch: The current system architecture. May be one of the following: x32, x64, arm, arm64, s390, s390x, mipsel, ia32, mips, ppc, ppc64 -- gpus: array of available GPUs on the machine (example: `['apple']`, `['nvidia']`) -- gpu: the first available GPU (example: `nvidia`) -- current: The current variable points to the index of the currently executing instruction within the run array. -- next: The next variable points to the index of the next instruction to be executed. (null if the current instruction is the final instruction in the run array) -- envs: You can access the environment variables of the currently running process with envs object. -- which: Check whether a command exists (example: `{{which('winget')}}`. Can be used in the `when` attribute of a script step to run commands or install first. -- exists: Check whether a file or folder exists at the specified relative path (example: `"when": "{{!exists('app')}}"`). Can be used with the `when` attribute to determine a path's existence and trigger custom logic. Use relative paths and it will resolve automatically to the current execution folder. -- running: Check whether a script file is running (example: `"when": "{{!running('start.js')}}"`). Can be used with the `when` attribute to determine a path's existence and trigger custom logic. Use relative paths and it will resolve automatically to the current execution folder. -- os: Pinokio exposes the node.js os module through the os variable. -- path: Pinokio exposes the node.js path module through the os variable (example: `{{path.resolve(...)}}` - -## System Capabilities -### Package Management (Use in Order of Preference) -The following package managers come pre-installed with Pinokio, so whenever you need to install a 3rd party binary, remember that these are available. Also, you can assume these are available and include the following package manager commands in Pinokio scripts: -1. **UV** - For Python packages (preferred over pip) -2. **NPM** - For Node.js packages -3. **Conda** - For cross-platform 3rd party binaries -4. **Brew** - Mac-only fallback when other options unavailable -5. **Git** - Full access to git is available. -**Important:** Include all install commands in the install script for reproducibility. -### HTTPS Proxy Support -- All HTTP servers automatically get HTTPS endpoints -- Convention: `http://localhost:` → `https://.localhost` -- Full proxy list available at: `http://localhost:2019/config/` -### Pterm Features: -- **Clipboard Access:** Read from or Write to system clipboard via pinokio Pterm CLI (`pterm clipboard` command.) -- **Notifications:** Send desktop alerts via pinokio pterm CLI (`pterm push` command.) -- **Script Testing:** Run launcher scripts via pinokio pterm CLI (`pterm start` command.) -- **File Selection:** Use built-in filepicker for user file/folder input (`pterm filepicker` command.) -- **Git Operations:** Clone repositories, push to GitHub -- **GitHub Integration:** Full GitHub CLI support (`gh` commands) - -## Troubleshooting with Logs -Pinokio stores the logs for everything that happened in terminal at the following locations, so you can make use of them to determine what's going on: - -### Log Structure -In case there is a `pinokio` folder in the project root folder, you should be able to find the logs folder here: - -``` -pinokio/ -└── logs/ # Direct user interaction logs - ├── api/ # Launcher script logs (install.js, start.js, etc.) - ├── dev/ # AI coding tool logs (organized by tool) - └── shell/ # Direct user interaction logs -``` - -Otherwise, the `logs` folder should be found at project root: - -``` -logs/ -├── api/ # Launcher script logs (install.js, start.js, etc.) -├── dev/ # AI coding tool logs (organized by tool) -└── shell/ # Direct user interaction logs -``` - -### Log File Naming -- Unix timestamps for each session -- Special "latest" file contains most recent session logs -- **Default:** Use "latest" files for current issues -- **Historical:** Use timestamped files for pattern analysis and the full history. - -## Best practices -### 0. Always reference the logs when debugging -- When the user asks to fix something, ALWAYS check the logs folder first to check what went wrong. Check the "Troubleshooting with Logs" section. -### 1. Shell commands for launching programs -- Launch flags related - - Try as hard as possible to minimize launch flags and parameters when launching an app. For example, instead of `python app.py --port 8610`, try to do `python app.py` unless really necessary. The only exception is when the only way to launch the app is to specify the flags. -- Launch IP related - - Always try to find a way to launch servers at 127.0.0.1 or localhost, often by specifying launch flags or using environment variables. Some apps launch apps at 0.0.0.0 by default but we do not want this. -- Launch Port related - - In case the app itself automatically launches at the next available port by default (for example Gradio does this), do NOT specify port, since it's taken care of by the app itself. Always try to minimize the amount of code. - - If the install instruction says to launch at a specific port, don't use the hardcoded port they suggest since there's a risk of port conflicts. Instead, use Pinokio's `{{port}}` template expression to automatically get the next available port. - - For example, if the instruction says `python app.py --port 7860`, don't use that hardcoded port since there might be another app running at that port. Instead, automatically assign the next available port like this: `python app.py --port {{port}}` - - Note that the `{{port}}` expression always returns the next immediately available port for each step, so if you have multiple steps in a script and use `{{port}}` in multiple steps, the value will be different. So if you want to launch at the next available port and then later reuse that port, you will need to first use `{{port}}` to get the next available port, and save the value in local variable using `local.set`, and then use the `{{local.}}` expression later. -### 2. shell.run API -- When writing `shell.run` API requests, always use relative paths (no absolute paths) for the `path` field. For example, if you need to run a command from `app` folder, the `path` attribute should simply be `app`, instead of its full absolute path. -### 2. Package managers -- When installing python packages, try best to use `uv` instead of `pip` even if the install instruction says to use pip. Instead of `pip install -r requirements.txt`, you can simply use `uv pip install -r requirements.txt` for example. Even if the project's own README says use pip or poetry, first check if there's a way to use uv instead. -- When you need to install some global package, try to use `conda` as much as possible. Even on macs, `brew` should be only used if there are no `conda` options. -### 3. Minimal Always -- If you are starting with existing script files, before modifying, creating, or removing any script files, first look at `pinokio.js` to understand which script files are actually used in the launcher. The only script files used are the ones mentioned in the `pinokio.js` file. The `pinokio.js` file is the file that constructs the UI dynamically. -- Do not create a redundant script file that does something that already exists. Instead modify the existing script file for the feature. For example, do not create an `install.json` file for installation if `install.js` already exists. Instead, modify the `install.js` file. -- Pinokio accepts both JSON and JS script files, so when determining whether a script for a specific purpose already exists, check both JSON and JS files mentioned in the `pinokio.js` file. Do not create script files for rendundant purpose. -- When building launchers for existing projects cloned from a repository, try to stay away from modifying the project folder (the `D:\pinokio\api\pmoves-pbnj` folder), even if installations are failing. Instead, try to work around it by creating additional files in the launcher folder, and using those files IN ADDITION to the default project. - - The only exception when you may need to make changes to the project folder is when the user explicitly wants to modify the existing project. Otherwise if the purpose is to simply write a launcher, the app logic folder should never be touched. -- When running shell commands, take full advantage of the Pinokio `shell.run` API, which provides features like `env`, `venv`, `input`, `path`, `sudo`, `on`, etc. which can greatly reduce the amount of script code. - - Python apps: Always use virtual environments via `venv` attribute. This attribute automatically creates a venv or uses if it already exists. -### 4. Try to support Cross-platform as much as possible -- Use cross-platform shell commands only. -- This means, prefer to use commands that work on all platforms instead of the current platform. -- If there are no cross platform commands, use Pinokio's template expressions to conditionally use commands depending on `platform`, `arch`, etc. -- Also try to utilize Pinokio Pterm APIs for various cross-platform system features. -- If it is impossible to implement a cross platform solution (due to the nature of the project itself), set the `platform`, `arch`, and/or `gpu` attributes of the `pinokio.json` file to declare the limitation. -- Pinokio provides various APIs for cross-platform way of calling commonly used system functions, or lets you selectively run commands depending on `platform`, `arch`, etc. -### 5. Do not make assumptions about Pinokio API -- Do NOT make assumptions about which Pinokio APIs exist. Check the documentation. -- Do NOT make assumptions about the Pinokio API syntax. Follow the documentation. -### 6. Scripts must be able to replicate install and launch steps 100% -- The whole point of the scripts is for others to easily download and invoke them via Pinokio interface with one click. Therefore, do not assume the end user's system state, and make everything self-contained. -- When a 3rd party package needs to be installed, or a 3rd party repository needs to be downloaded, include them in the scripts. -### 7 Dynamic UI rendering -- The `pinokio.js` launcher script can change dynamically depending on the current state of the script execution. Which means, depending on what the file returns, it can determine what the sidebar looks like at any given moment of the script cycle. - - `info.exists(relative_path)`: The `info.exists` can be used to check whether a relative path (relative to the script root path) exists. The `pinokio.js` file can determine which menu items to return based on this value at any given moment. - - `info.running(relative_path)`: The `info.running` can be used to check whether a script at a relative path is currently running (relative to the script root path) exists. The `pinokio.js` file can determine which menu items to return based on this value at any given moment. - - `info.local(relative_path)`: The `info.local` can be used to return all the local variables tied to a script that's currently running. The `pinokio.js` file can determine which menu items to return based on this value at any given moment. - - `default`: set the `default` attribute on any menu item for whichever menu needs to be selected by default at a given step. Some example scenarios: - - during the install process, the `install.js` menu item needs to be set as the `default`, so it automatically executes the script - - when launching the `start.js` menu item needs to be set as the `default`, so it automatically executes the script - - after the app has launched, the `default` needs to be set on the web UI URL, so the user is sent to the actual app automatically. - - Check the examples in the D:\pinokio\prototype\system\examples folder to see how these are being used. -### 8. No need for stop scripts -- `pinokio.js` does NOT need a separate `stop` script. Every script that can be started can also be natively stopped through the Pinokio UI, therefore you do not need a separate stop script for start script -### 9. Writing launchers for existing projects -- When writing or modifying pinokio launcher scripts, figure out the install/launch steps by reading the project folder `app`. -- In most cases, the `README.md` file in the `D:\pinokio\api\pmoves-pbnj` folder contains the instructions needed to install and run the app, but if not, figure out by scanning the rest of the project files. -- Install scripts should work for each specific operating system, so ignore Docker related instructions. Instead use install/launch instructions for each platform. -### 10. Don't use Docker unless really necessary -- Some projects suggest docker as installation options. But even in these cases, try to find "development" options to launch the app without relying on Docker, as much as possible. We do not need Docker since we can automatically install and launch apps specifically for the user's platform, since we can write scripts that run cross platform. -### 11. pinokio.json -- Do not touch the `version` field since the version is the script schema version and the one pre-set in `pinokio.js` must be used. -- `icon`: It's best if we have a user friendly icon to represent the app, so try to get an image and link it from `pinokio.json`. - - If the git repository for the `D:\pinokio\api\pmoves-pbnj` folder points to GitHub (for example https://github.com//`, ask the user if they want to download the icon from GitHub, and if approved, get the `avatar_url` by fetching `https://api.github.com/users/`, and then download the image to the root folder as `icon.png`, and set `icon.png` as the `icon` field of the `pinokio.json`. -### 12. Gitignore -- When a launcher involves cloning 3rd party repositories, downloading files dynamically, or some files to be generated, these need to be included in the .gitignore file. This may include things like: - - Cloning git repositories - - Downloading files - - Dynamically creating files during installation or running, such as Sqlite Databases, or environment variables, or anything specific to the user. -- Make sure these file paths are included in the .gitignore file, and if not, include them in .gitignore. - -## AI Libraries (Pytorch, Xformers, Triton, Sageattention, etc.) -If the launcher has a dedicated built-in script named `torch.js`, it can be used as follows: - -``` -// install.js -module.exports = { - run: [ - // Edit this step with your custom install commands - { - method: "shell.run", - params: { - venv: "venv", // Edit this to customize the venv folder path - path: "app", - message: [ - "uv pip install -r requirements.txt" - ], - } - }, - // Delete this step if your project does not use torch - { - method: "script.start", - params: { - uri: "torch.js", - params: { - path: "app", - venv: "venv", // Edit this to customize the venv folder path - // xformers: true // uncomment this line if your project requires xformers - // triton: true // uncomment this line if your project requires triton - // sageattention: true // uncomment this line if your project requires sageattention - // flashattention: true // uncomment this line if your project requires flashattention - } - } - }, - ] -} -``` - -The `torch.js` script also includes ways to install pytorch dependent libraries such as xformers, triton, sagetattention. If any of these libraries need to be installed, use the torch.js to install in order to install them cross platform. - - -## Quick Reference -### Essential Documentation -- **Pinokio Programming:** See `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md → "Programming Pinokio" section -- **Dynamic Menus:** See `PINOKIO.md` at D:\pinokio\prototype\PINOKIO.md → "Dynamic menu rendering" section -- **CLI Commands:** See `PTERM.md` at D:\pinokio\prototype\PTERM.md -### Common Patterns -- **Python Virtual Env:** `shell.run` with `venv` attribute -- **Cross-platform Commands:** Always test on multiple platforms -- **Error Handling:** Check logs/api for launcher issues -- **GitHub Operations:** Use `gh` CLI for advanced GitHub features -## Development Principles -1. **Minimize Shell Usage:** Leverage API parameters instead of raw commands -2. **Maintain Separation:** Keep app logic and launchers separate -3. **Follow Conventions:** Match existing project patterns -4. **Test Thoroughly:** Use CLI to verify launcher functionality -5. **Document Changes:** Update relevant metadata and documentation diff --git a/pbnj/pinokio/api/pmoves-pbnj/README.md b/pbnj/pinokio/api/pmoves-pbnj/README.md deleted file mode 100644 index 789fe06549..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/README.md +++ /dev/null @@ -1,126 +0,0 @@ -# PBnJ | PMOVES + Pinokio - -Cluster orchestration bridge for PMOVES.AI — manage local dev, AI Lab (Kubernetes), and KVM4 production deployments from a single control panel. - -## Quick Start - -1. Select a deployment target from the sidebar: - - **Local Dev** — Docker Compose on your machine - - **AI Lab** — Kubernetes cluster for GPU workloads - - **KVM4 Stack** — Production Kubernetes on KVM4 nodes -2. Click the target to deploy -3. Use **Cluster Status** to verify deployments - -## Scripts - -### Local Development (Docker Compose) - -| Script | Purpose | -|--------|---------| -| `local-up.json` | Start local Docker Compose stack | -| `local-down.json` | Stop local Docker Compose stack | -| `local-logs.json` | Stream logs from local services | - -### AI Lab (Kubernetes) - -| Script | Purpose | -|--------|---------| -| `lab-up.json` | Apply AI Lab manifests to K8s | -| `lab-down.json` | Delete AI Lab from K8s | - -### KVM4 Production (Kubernetes) - -| Script | Purpose | -|--------|---------| -| `kvm4-up.json` | Apply KVM4 stack to K8s | -| `kvm4-down.json` | Delete KVM4 stack from K8s | - -### VPS Node Deployments (Tailscale SSH) - -| Script | Target | Services | -|--------|--------|----------| -| `kvm4-1-deploy.json` | KVM4-1 (API gateway) | TensorZero, Agent Zero, Hi-RAG, Archon, Mesh Agent, Extract Worker | -| `kvm4-2-deploy.json` | KVM4-2 (Data) | Supabase, Qdrant, Neo4j, Meilisearch, NATS, Prometheus, Grafana, Loki, MinIO | -| `kvm2-deploy.json` | KVM2 (Exit) | Nginx reverse proxy | - -### Status - -| Script | Purpose | -|--------|---------| -| `status.json` | K8s deployment status for AI Lab | -| `vps-status.json` | Tailscale ping + GitHub runner status for all VPS nodes | - -## API Reference - -### Deploy Script API - -All deployment scripts use shell wrappers under `deploy/scripts/`: - -**Bash/CLI (deployment scripts)** - -```bash -# Local Docker Compose -bash deploy/scripts/deploy-compose.sh up -bash deploy/scripts/deploy-compose.sh down -bash deploy/scripts/deploy-compose.sh logs - -# Kubernetes (AI Lab) -bash deploy/scripts/deploy-k8s.sh apply --target ai-lab -bash deploy/scripts/deploy-k8s.sh status --target ai-lab -bash deploy/scripts/deploy-k8s.sh delete --target ai-lab - -# Kubernetes (KVM4) -bash deploy/scripts/deploy-k8s.sh apply --target kvm4 -bash deploy/scripts/deploy-k8s.sh status --target kvm4 -``` - -**Python** - -```python -import subprocess - -# Check local stack -result = subprocess.run( - ["bash", "deploy/scripts/deploy-compose.sh", "status"], - capture_output=True, text=True, cwd="/path/to/pmoves" -) -print(result.stdout) -``` - -**JavaScript** - -```javascript -const { execSync } = require("child_process"); - -// Check K8s status -const status = execSync( - "bash deploy/scripts/deploy-k8s.sh status --target ai-lab", - { cwd: "/path/to/pmoves", encoding: "utf-8" } -); -console.log(status); -``` - -### VPS Health Checks (via Tailscale SSH) - -```bash -# Ping all nodes -tailscale ping --timeout 3s pmoves-kvm4-1 -tailscale ping --timeout 3s pmoves-kvm4-2 -tailscale ping --timeout 3s pmoves-kvm2 - -# Remote health checks -ssh root@pmoves-kvm4-1 'curl -sf http://localhost:8080/healthz' # Agent Zero -ssh root@pmoves-kvm4-1 'curl -sf http://localhost:3030/healthz' # TensorZero -ssh root@pmoves-kvm4-2 'curl -sf http://localhost:9090/api/v1/targets' # Prometheus -ssh root@pmoves-kvm4-2 'curl -sf http://localhost:6333/healthz' # Qdrant -``` - -## Agent Hints - -AI agents can use this launcher to: - -- **Deploy to lab** — Run `lab-up.json` to apply K8s manifests to AI Lab -- **Deploy to production** — Run `kvm4-up.json` or individual node deploy scripts -- **Check cluster status** — Run `status.json` for K8s or `vps-status.json` for VPS fleet -- **View logs** — Run `local-logs.json` for local Docker Compose logs -- **Stop services** — Run `local-down.json`, `lab-down.json`, or `kvm4-down.json` diff --git a/pbnj/pinokio/api/pmoves-pbnj/SKILL.md b/pbnj/pinokio/api/pmoves-pbnj/SKILL.md deleted file mode 100644 index 5e6c231cd9..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/SKILL.md +++ /dev/null @@ -1,140 +0,0 @@ ---- -name: PBnJ | PMOVES + Pinokio Bridge -description: | - Multi-target deployment bridge for PMOVES.AI infrastructure. - Manages local Docker Compose, Kubernetes AI Lab, KVM4 production, - VPS fleet deployment, homelab bare-metal, and edge (Jetson) nodes - from a single Pinokio control panel. Built-in gepeto + pinokio skills. - Covers: Z890, 5090, 4090, SPARK, R9700, JONS×3, KVM4-1/4-2, KVM2. -keywords: deploy, infrastructure, docker, kubernetes, kvm4, vps, tailscale, glances, network, diagnostics, fleet, jetson, spark, rdna4, edge, gepeto, pinokio -version: 1.1.0 -category: Infrastructure/Deployment -tier: 1 -agent_class: Standard -agent_id: pmoves_pbnj_bridge -pinokio_skills: - native: - - pinokio # Built-in app discovery + launch - - gepeto # Built-in code assistant (~/.agents/skills/gepeto) - - pterm # Pinokio terminal interface - pmoves: - - pmoves-services # Docker Compose profile controls - - pmoves-remote # Headscale/RustDesk remote access - - pmoves-agent-zero - - pmoves-model-registry - - cipher # MoF/P7 state management ---- - -# PBnJ | PMOVES + Pinokio Bridge - -**Agent Class**: `Standard (Pmoves-)` -**Category**: Infrastructure/Deployment -**Version**: 1.1.0 -**Tier**: 1 (Core Infrastructure) -**Status**: Active — homelab + VPS + edge fleet, gepeto + pinokio native skills - ---- - -## Capabilities - -| Command | What It Does | -|---------|-------------| -| `local-up` | Start local Docker Compose stack (Z890 dev) | -| `local-down` | Stop local Docker Compose stack | -| `local-logs` | Stream logs from local services | -| `lab-up` | Apply AI Lab manifests to Kubernetes | -| `lab-down` | Delete AI Lab from Kubernetes | -| `kvm4-up` | Deploy KVM4 production stack | -| `kvm4-down` | Stop KVM4 production stack | -| `kvm4-1-deploy` | Deploy API services to KVM4-1 (Agent Zero, TZ, Hi-RAG) | -| `kvm4-2-deploy` | Deploy data services to KVM4-2 (Supabase, Qdrant, Neo4j) | -| `kvm2-deploy` | Deploy exit proxy to KVM2 (Nginx) | -| `4090-deploy` | Deploy coding workstation to 4090 laptop | -| `4090-models` | Pull models to 4090 (~50GB) | -| `4090-status` | Check 4090 node status | -| `spark-deploy` | Bootstrap DGX Spark (GB10 Grace-Blackwell, 128GB) | -| `spark-models` | Pull models to SPARK (Gemma 4 31B FP16, Nemotron-Super-49B) | -| `spark-status` | Check SPARK node health (Tailscale + Ollama) | -| `rdna4-deploy` | Bootstrap RDNA4 workstation (dual R9700, ROCm 7.1) | -| `rdna4-status` | Check RDNA4 node health (llama-server + rocm-smi) | -| `jons-deploy` | Bootstrap all 3 Jetson Orin Nano Super units (JetPack 6.x) | -| `jons-status` | Check Jetson edge fleet health (mesh-agent + ollama) | -| `fleet-status` | Full fleet: all nodes Tailscale ping + service health | -| `status` | Kubernetes deployment status | -| `vps-status` | Tailscale ping + runner status for all VPS nodes | - ---- - -## Trigger Phrases (Pinokio 7 Interpreter) - -Uses built-in `gepeto` and `pinokio` skills for natural language routing. - -| Phrase | Action | Script | -|--------|--------|--------| -| `"start local dev"` | Launch Docker Compose | `local-up.json` | -| `"stop local dev"` | Stop Docker Compose | `local-down.json` | -| `"show logs"` | Stream local service logs | `local-logs.json` | -| `"deploy to lab"` | Apply K8s manifests | `lab-up.json` | -| `"deploy to production"` | Apply KVM4 K8s stack | `kvm4-up.json` | -| `"deploy kvm4-1"` | API services to KVM4-1 | `kvm4-1-deploy.json` | -| `"deploy kvm4-2"` | Data services to KVM4-2 | `kvm4-2-deploy.json` | -| `"deploy kvm2"` | Exit proxy to KVM2 | `kvm2-deploy.json` | -| `"deploy 4090"` | Coding workstation to 4090 | `4090-deploy.json` | -| `"deploy spark"` | Bootstrap DGX SPARK node | `spark-deploy.json` | -| `"deploy rdna4"` | Bootstrap RDNA4 workstation | `rdna4-deploy.json` | -| `"deploy jetsons"` | Bootstrap all 3 Jetson JONS | `jons-deploy.json` | -| `"check cluster status"` | K8s status | `status.json` | -| `"check vps fleet"` | All VPS node health | `vps-status.json` | -| `"check fleet"` | Full fleet health (all nodes) | `fleet-status.json` | -| `"stop everything"` | Stop all stacks | `lab-down.json` → `kvm4-down.json` → `local-down.json` | - ---- - -## Fleet Nodes - -### Homelab (Bare Metal) -| Node | Role | Deploy Script | -|------|------|---------------| -| Z890 (`pmoves-z890`) | Infrastructure coordinator, Docker, CI | `local-up.json` | -| 5090 (`pmoves-5090`) | GPU compute, voice, model training | (via pmoves-services) | -| SPARK (`pmoves-gb10-spark`) | DGX Grace-Blackwell, 128GB unified, ARM64 inference | `spark-deploy.json` | -| RDNA4 (`pmoves-rdna4`) | Dual R9700 workstation, ROCm 7.1, 64GB VRAM | `rdna4-deploy.json` | -| 4090 Laptop (`pmoves-4090`) | Field agent, mobile | `4090-deploy.json` | - -### Edge Nodes (Jetson Orin Nano Super × 3) -| Node | Role | Deploy Script | -|------|------|---------------| -| JONS-1 (`pmoves-jons-1`) | Edge inference, Whisper, YOLOv8 | `jons-deploy.json` | -| JONS-2 (`pmoves-jons-2`) | Edge inference, Whisper, YOLOv8 | `jons-deploy.json` | -| JONS-3 (`pmoves-jons-3`) | Edge inference, Whisper, YOLOv8 | `jons-deploy.json` | - -**Jetson specs**: 6-core Cortex-A78AE, Ampere SM_87 1024 CUDA cores, 8GB LPDDR5 (102 GB/s), 67 TOPS. -JetPack 6.x (L4T 36.x). Built-in Pinokio `gepeto` + `pinokio` skills. - -### VPS (Hostinger) -| Node | Role | Deploy Script | -|------|------|---------------| -| KVM4-1 | API gateway (TZ, A0, Hi-RAG, Archon) | `kvm4-1-deploy.json` | -| KVM4-2 | Data/storage (Supabase, Qdrant, Neo4j) | `kvm4-2-deploy.json` | -| KVM2 | Exit proxy (Nginx) | `kvm2-deploy.json` | - ---- - -## Network Tools (Optional) - -When network tools are installed (`app/env` exists): -- **Glances** — System monitor (venv or Docker mode) -- **Network Diagnostics** — Connectivity checks -- **DNS Flush** — Clear DNS cache -- **Winsock Reset** — Reset network stack -- **Firewall Rules** — Add PMOVES service rules -- **Docker Network Cleanup** — Prune stale networks - ---- - -## Prerequisites - -- Docker Desktop with Compose v2+ -- Tailscale client (for VPS deployments) -- kubectl (for Kubernetes targets) -- `pmoves/env.shared` bootstrapped diff --git a/pbnj/pinokio/api/pmoves-pbnj/demo.js b/pbnj/pinokio/api/pmoves-pbnj/demo.js deleted file mode 100644 index 0db9cbcc59..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/demo.js +++ /dev/null @@ -1,57 +0,0 @@ -// PMOVES Demo Room launcher -// Starts Agent Zero (local Python), surfaces the WebUI, publishes p7.nats.launch. -// Graceful NATS skip if the bus is not reachable. -module.exports = { - daemon: true, - run: [ - { - method: "log", - params: { text: "PMOVES Demo Room — starting Agent Zero + HERMES V4" } - }, - { - // Save the next available port before launching so we can construct localhost URL cleanly - method: "local.set", - params: { port: "{{port}}" } - }, - { - method: "shell.run", - params: { - // Use PMOVES_ROOT env var — same convention as all other PBnJ launchers - path: "{{envs.PMOVES_ROOT}}/PMOVES-Agent-Zero", - venv: ".venv", - message: ["python run_ui.py --port {{local.port}}"], - on: [{ - // Matches both "Running on http://..." and "Uvicorn running on http://..." - event: "/(http:\\/\\/[^\\s]+)/", - done: true - }] - } - }, - { - method: "local.set", - params: { - url: "http://localhost:{{local.port}}" - } - }, - { - method: "web.open", - params: { url: "{{local.url}}" } - }, - { - // Publish p7.nats.launch — skip gracefully if NATS CLI not in PATH or bus is down - method: "shell.run", - params: { - message: [ - "nats pub p7.nats.launch \"{\\\"room\\\":\\\"demo.room.rehearsal\\\",\\\"stage\\\":\\\"rehearsal\\\",\\\"suits\\\":[\\\"agent-zero-local\\\",\\\"4090-claws\\\",\\\"hermes-v4\\\"]}\" 2>/dev/null || echo NATS skip" - ] - } - }, - { - method: "notify", - params: { - title: "PMOVES Demo Room", - message: "Agent Zero ready at {{local.url}}" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/icon.png b/pbnj/pinokio/api/pmoves-pbnj/icon.png deleted file mode 100644 index a5923a0bfd..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/icon.png +++ /dev/null @@ -1 +0,0 @@ -PNG placeholder - Replace with actual PMOVES.AI icon diff --git a/pbnj/pinokio/api/pmoves-pbnj/kvm2-deploy.json b/pbnj/pinokio/api/pmoves-pbnj/kvm2-deploy.json deleted file mode 100644 index 863d711886..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/kvm2-deploy.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "run": [ - { - "method": "shell.run", - "params": { - "message": [ - "echo 'Deploying KVM2 (Exit Node) via Tailscale SSH...'", - "echo 'NOTE: SSH as root — key-only auth enforced (PasswordAuthentication no)'", - "ssh root@pmoves-kvm2 'cd /opt/pmoves && git pull --ff-only origin main && cd pmoves && docker compose -f docker-compose.yml -f docker-compose.vps.override.yml pull nginx && docker compose -f docker-compose.yml -f docker-compose.vps.override.yml up -d nginx'", - "echo 'Verifying exit node...'", - "ssh root@pmoves-kvm2 'tailscale status | head -5'", - "echo 'KVM2 deployment complete.'" - ] - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/kvm4-1-deploy.json b/pbnj/pinokio/api/pmoves-pbnj/kvm4-1-deploy.json deleted file mode 100644 index bab4b8990a..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/kvm4-1-deploy.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "run": [ - { - "method": "shell.run", - "params": { - "message": [ - "echo 'Deploying KVM4-1 (API Gateway) via Tailscale SSH...'", - "echo 'NOTE: SSH as root — key-only auth enforced (PasswordAuthentication no)'", - "ssh root@pmoves-kvm4-1 'cd /opt/pmoves && git pull --ff-only origin main && cd pmoves && docker compose -f docker-compose.yml -f docker-compose.vps.override.yml pull tensorzero-gateway agent-zero hi-rag-gateway-v2 archon-server mesh-agent gateway-agent extract-worker && docker compose -f docker-compose.yml -f docker-compose.vps.override.yml up -d tensorzero-gateway agent-zero hi-rag-gateway-v2 archon-server mesh-agent gateway-agent extract-worker'", - "echo 'Verifying health...'", - "ssh root@pmoves-kvm4-1 'curl -sf http://localhost:8080/healthz && echo \" Agent Zero: OK\" || echo \" Agent Zero: FAIL\"'", - "ssh root@pmoves-kvm4-1 'curl -sf http://localhost:3030/healthz && echo \" TensorZero: OK\" || echo \" TensorZero: FAIL\"'", - "echo 'KVM4-1 deployment complete.'" - ] - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/kvm4-2-deploy.json b/pbnj/pinokio/api/pmoves-pbnj/kvm4-2-deploy.json deleted file mode 100644 index 251d23dba1..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/kvm4-2-deploy.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "run": [ - { - "method": "shell.run", - "params": { - "message": [ - "echo 'Deploying KVM4-2 (Data Services) via Tailscale SSH...'", - "echo 'NOTE: SSH as root — key-only auth enforced (PasswordAuthentication no)'", - "ssh root@pmoves-kvm4-2 'cd /opt/pmoves && git pull --ff-only origin main && cd pmoves && docker compose -f docker-compose.yml -f docker-compose.vps.override.yml pull supabase-db supabase-rest qdrant neo4j meilisearch nats prometheus grafana loki minio && docker compose -f docker-compose.yml -f docker-compose.vps.override.yml up -d supabase-db supabase-rest qdrant neo4j meilisearch nats prometheus grafana loki minio'", - "echo 'Verifying health...'", - "ssh root@pmoves-kvm4-2 'curl -sf http://localhost:9090/api/v1/targets > /dev/null && echo \" Prometheus: OK\" || echo \" Prometheus: FAIL\"'", - "ssh root@pmoves-kvm4-2 'curl -sf http://localhost:6333/healthz > /dev/null && echo \" Qdrant: OK\" || echo \" Qdrant: FAIL\"'", - "echo 'KVM4-2 deployment complete.'" - ] - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/kvm4-down.json b/pbnj/pinokio/api/pmoves-pbnj/kvm4-down.json deleted file mode 100644 index 2b9850bd45..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/kvm4-down.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "run": [ - { - "method": "shell.run", - "params": { - "path": "{{envs.PMOVES_ROOT}}", - "message": "bash deploy/scripts/deploy-k8s.sh delete --target kvm4" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/kvm4-up.json b/pbnj/pinokio/api/pmoves-pbnj/kvm4-up.json deleted file mode 100644 index 3a030d7fa1..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/kvm4-up.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "run": [ - { - "method": "shell.run", - "params": { - "path": "{{envs.PMOVES_ROOT}}", - "message": "bash deploy/scripts/deploy-k8s.sh apply --target kvm4" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/lab-down.json b/pbnj/pinokio/api/pmoves-pbnj/lab-down.json deleted file mode 100644 index 9b99648269..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/lab-down.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "run": [ - { - "method": "shell.run", - "params": { - "path": "{{envs.PMOVES_ROOT}}", - "message": "bash deploy/scripts/deploy-k8s.sh delete --target ai-lab" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/lab-up.json b/pbnj/pinokio/api/pmoves-pbnj/lab-up.json deleted file mode 100644 index bee56d2a91..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/lab-up.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "run": [ - { - "method": "shell.run", - "params": { - "path": "{{envs.PMOVES_ROOT}}", - "message": "bash deploy/scripts/deploy-k8s.sh apply --target ai-lab" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/local-down.json b/pbnj/pinokio/api/pmoves-pbnj/local-down.json deleted file mode 100644 index ccecd356c0..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/local-down.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "run": [ - { - "method": "shell.run", - "params": { - "path": "{{envs.PMOVES_ROOT}}", - "message": "bash deploy/scripts/deploy-compose.sh down" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/local-logs.json b/pbnj/pinokio/api/pmoves-pbnj/local-logs.json deleted file mode 100644 index 6d02ec73b7..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/local-logs.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "run": [ - { - "method": "shell.run", - "params": { - "path": "{{envs.PMOVES_ROOT}}", - "message": "bash deploy/scripts/deploy-compose.sh logs" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/local-up.json b/pbnj/pinokio/api/pmoves-pbnj/local-up.json deleted file mode 100644 index 2ce9939917..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/local-up.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "run": [ - { - "method": "shell.run", - "params": { - "path": "{{envs.PMOVES_ROOT}}", - "message": "bash deploy/scripts/deploy-compose.sh up" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/nats-launch-hook.js b/pbnj/pinokio/api/pmoves-pbnj/nats-launch-hook.js deleted file mode 100644 index 9512d6d22d..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/nats-launch-hook.js +++ /dev/null @@ -1,27 +0,0 @@ -// nats-launch-hook.js -// Publishes p7.nats.launch.v1 when a Pinokio app starts or stops. -// Usage from a launcher start/stop step: -// { method: "script.start", params: { uri: "nats-launch-hook.js", -// params: { room: "5090-voice.room.studio", app: "flute-gateway", -// port: "8055", action: "started" } } } -module.exports = { - run: [ - { - method: "shell.run", - params: { - message: [ - "nats pub p7.nats.launch.v1 \"{\\\"room\\\":\\\"{{args.room}}\\\",\\\"app\\\":\\\"{{args.app}}\\\",\\\"port\\\":\\\"{{args.port}}\\\",\\\"action\\\":\\\"{{args.action}}\\\",\\\"ts\\\":\\\"{{new Date().toISOString()}}\\\"}\"" - ], - env: { - NATS_URL: "{{envs.NATS_URL || 'nats://localhost:4222'}}" - } - } - }, - { - method: "log", - params: { - text: "P7 launch event published: room={{args.room}} app={{args.app}} port={{args.port}} action={{args.action}}" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/nats-session-hook.js b/pbnj/pinokio/api/pmoves-pbnj/nats-session-hook.js deleted file mode 100644 index ba1d2b8201..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/nats-session-hook.js +++ /dev/null @@ -1,29 +0,0 @@ -// nats-session-hook.js -// Publishes p7.nats.session.v1 to the PMOVES NATS bus when called from a -// Pinokio launcher. Accepts args: node_id, room, action -// (start|started|pause|resume|end|stop|stopped|archive). -// Usage from another script step: -// { method: "script.start", params: { uri: "nats-session-hook.js", -// params: { node_id: "pmoves-4090", room: "5090-voice.room.studio", -// action: "started" } } } -module.exports = { - run: [ - { - method: "shell.run", - params: { - message: [ - "nats pub p7.nats.session.v1 \"{\\\"node\\\":\\\"{{args.node_id}}\\\",\\\"room\\\":\\\"{{args.room}}\\\",\\\"action\\\":\\\"{{args.action}}\\\",\\\"ts\\\":\\\"{{new Date().toISOString()}}\\\"}\"" - ], - env: { - NATS_URL: "{{envs.NATS_URL || 'nats://localhost:4222'}}" - } - } - }, - { - method: "log", - params: { - text: "P7 session event published: node={{args.node_id}} room={{args.room}} action={{args.action}}" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/pinokio.js b/pbnj/pinokio/api/pmoves-pbnj/pinokio.js deleted file mode 100644 index 819fabdc5e..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/pinokio.js +++ /dev/null @@ -1,286 +0,0 @@ -// pbnj/pinokio/api/pmoves-pbnj/pinokio.js -module.exports = { - version: "5.0", - title: "PBnJ | PMOVES + Pinokio", - description: "One-click bridge into your PMOVES lab, KVM4, local dev stacks, and network diagnostics.", - icon: "icon.png", - menu: async (kernel, info) => { - // --------------- State Detection --------------- - let nettoolsInstalled = info.exists("app/env") - - let running = { - localUp: info.running("local-up.json"), - labUp: info.running("lab-up.json"), - kvm4Up: info.running("kvm4-up.json"), - install: info.running("install-nettools.js"), - glancesVenv: info.running("glances-start.js"), - glancesDocker: info.running("glances-docker.js"), - netDiag: info.running("net-diag.js"), - netFix: info.running("net-fix.js"), - reset: info.running("reset-nettools.js"), - update: info.running("update.js"), - demo: info.running("demo.js"), - } - - let glancesRunning = running.glancesVenv || running.glancesDocker - let glancesLocal = running.glancesVenv - ? info.local("glances-start.js") - : (running.glancesDocker ? info.local("glances-docker.js") : null) - let demoLocal = running.demo ? info.local("demo.js") : null - - // --------------- Active Terminal States --------------- - if (running.install) { - return [{ - default: true, - icon: "fa-solid fa-download", - text: "Installing Network Tools...", - href: "install-nettools.js", - }] - } - - if (running.reset) { - return [{ - default: true, - icon: "fa-solid fa-broom", - text: "Resetting Network Tools...", - href: "reset-nettools.js", - }] - } - - if (running.update) { - return [{ - default: true, - icon: "fa-solid fa-arrows-rotate", - text: "Updating...", - href: "update.js", - }] - } - - // --------------- Build Menu Items --------------- - let items = [] - - // ============ Infrastructure Section ============ - if (running.localUp) { - items.push({ - icon: "fa-solid fa-terminal", - text: "Local Dev (Running)", - href: "local-up.json", - }, { - icon: "fa-solid fa-stop", - text: "Stop Local Dev", - href: "local-down.json", - }, { - icon: "fa-solid fa-file-lines", - text: "Logs", - href: "local-logs.json", - }) - } else if (running.labUp) { - items.push({ - icon: "fa-solid fa-terminal", - text: "AI Lab (Running)", - href: "lab-up.json", - }, { - icon: "fa-solid fa-stop", - text: "Stop AI Lab", - href: "lab-down.json", - }) - } else if (running.kvm4Up) { - items.push({ - icon: "fa-solid fa-terminal", - text: "KVM4 Stack (Running)", - href: "kvm4-up.json", - }, { - icon: "fa-solid fa-stop", - text: "Stop KVM4 Stack", - href: "kvm4-down.json", - }) - } else { - items.push({ - icon: "fa-solid fa-play", - text: "Local Dev (Docker) — Up", - href: "local-up.json", - }, { - icon: "fa-solid fa-rocket", - text: "Start AI Lab (K8s)", - href: "lab-up.json", - }, { - icon: "fa-solid fa-server", - text: "Start KVM4 Stack (K8s)", - href: "kvm4-up.json", - }) - } - - // ============ Demo Room Section ============ - if (running.demo) { - if (demoLocal && demoLocal.url) { - items.push({ - icon: "fa-solid fa-rocket", - text: "Open Demo Room", - href: demoLocal.url, - }, { - icon: "fa-solid fa-terminal", - text: "Demo Room Terminal", - href: "demo.js", - }) - } else { - items.push({ - icon: "fa-solid fa-spinner", - text: "Demo Room (Starting...)", - href: "demo.js", - }) - } - } else { - items.push({ - icon: "fa-solid fa-rocket", - text: "Launch Demo Room", - href: "demo.js", - }) - } - - // ============ Status Section ============ - items.push({ - icon: "fa-solid fa-circle-info", - text: "Cluster Status", - href: "status.json", - }, { - icon: "fa-solid fa-satellite-dish", - text: "VPS Fleet Status", - href: "vps-status.json", - }) - - // ============ Deploy Section (idle only) ============ - if (!running.localUp && !running.labUp && !running.kvm4Up) { - if (info.exists("4090-deploy.json")) { - items.push({ - icon: "fa-solid fa-laptop-code", - text: "Deploy 4090 Coding Workstation", - href: "4090-deploy.json", - }) - } - if (info.exists("4090-models.json")) { - items.push({ - icon: "fa-solid fa-download", - text: "Pull 4090 Models (~50GB)", - href: "4090-models.json", - }) - } - if (info.exists("4090-status.json")) { - items.push({ - icon: "fa-solid fa-microchip", - text: "4090 Status", - href: "4090-status.json", - }) - } - items.push({ - icon: "fa-solid fa-cloud-arrow-up", - text: "Deploy KVM4-1 (API)", - href: "kvm4-1-deploy.json", - }, { - icon: "fa-solid fa-database", - text: "Deploy KVM4-2 (Data)", - href: "kvm4-2-deploy.json", - }, { - icon: "fa-solid fa-shield-halved", - text: "Deploy KVM2 (Exit)", - href: "kvm2-deploy.json", - }) - } - - // ============ Network Tools Section ============ - if (!nettoolsInstalled) { - // Install prompt - items.push({ - icon: "fa-solid fa-download", - text: "Install Network Tools", - href: "install-nettools.js", - }) - } else { - // --- Glances Monitor --- - if (glancesRunning && glancesLocal && glancesLocal.url) { - items.push({ - icon: "fa-solid fa-chart-line", - text: "Open Glances", - href: glancesLocal.url, - }, { - icon: "fa-solid fa-terminal", - text: "Glances Terminal", - href: running.glancesVenv ? "glances-start.js" : "glances-docker.js", - }) - } else if (glancesRunning) { - items.push({ - icon: "fa-solid fa-spinner", - text: "Glances (Starting...)", - href: running.glancesVenv ? "glances-start.js" : "glances-docker.js", - }) - } else { - items.push({ - icon: "fa-solid fa-chart-line", - text: "Start Glances (venv)", - href: "glances-start.js", - }, { - icon: "fa-brands fa-docker", - text: "Start Glances (Docker)", - href: "glances-docker.js", - }) - } - - // --- Network Diagnostics --- - items.push({ - icon: "fa-solid fa-stethoscope", - text: "Network Diagnostics", - href: "net-diag.js", - }) - - // --- Network Fix (diagnostic-first) --- - items.push({ - icon: "fa-solid fa-wrench", - text: "Diagnose Issues", - href: "net-fix.js", - params: { action: "--diagnose" }, - }, { - icon: "fa-solid fa-bolt", - text: "Execute All Fixes (Elevated)", - href: "net-fix.js", - params: { action: "--all --execute" }, - }, { - icon: "fa-solid fa-eraser", - text: "Flush DNS", - href: "net-fix.js", - params: { action: "--flush-dns --execute" }, - }, { - icon: "fa-solid fa-rotate", - text: "Reset Network Stack", - href: "net-fix.js", - params: { action: "--reset-winsock --execute" }, - }, { - icon: "fa-solid fa-shield", - text: "Add Firewall Rules", - href: "net-fix.js", - params: { action: "--firewall-add --execute" }, - }, { - icon: "fa-solid fa-trash-can", - text: "Clean Docker Networks", - href: "net-fix.js", - params: { action: "--docker-clean --execute" }, - }) - - // --- Maintenance --- - items.push({ - icon: "fa-solid fa-arrows-rotate", - text: "Update", - href: "update.js", - }, { - icon: "fa-regular fa-circle-xmark", - text: "Reset Network Tools", - href: "reset-nettools.js", - }) - } - - // Set default to first item - if (items.length > 0) { - items[0].default = true - } - - return items - } -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/status.json b/pbnj/pinokio/api/pmoves-pbnj/status.json deleted file mode 100644 index 7b790df048..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/status.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "run": [ - { - "method": "shell.run", - "params": { - "path": "{{envs.PMOVES_ROOT}}", - "message": "bash deploy/scripts/deploy-k8s.sh status --target ai-lab" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-pbnj/vps-status.json b/pbnj/pinokio/api/pmoves-pbnj/vps-status.json deleted file mode 100644 index b00141872b..0000000000 --- a/pbnj/pinokio/api/pmoves-pbnj/vps-status.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "run": [ - { - "method": "shell.run", - "params": { - "message": [ - "echo '=== PMOVES.AI VPS Fleet Status ==='", - "echo ''", - "echo 'KVM4-1 (API Gateway):'", - "tailscale ping --timeout 3s pmoves-kvm4-1 > /dev/null 2>&1 && echo ' Status: ONLINE' || echo ' Status: OFFLINE'", - "echo ''", - "echo 'KVM4-2 (Data Services):'", - "tailscale ping --timeout 3s pmoves-kvm4-2 > /dev/null 2>&1 && echo ' Status: ONLINE' || echo ' Status: OFFLINE'", - "echo ''", - "echo 'KVM2 (Exit Node):'", - "tailscale ping --timeout 3s pmoves-kvm2 > /dev/null 2>&1 && echo ' Status: ONLINE' || echo ' Status: OFFLINE'", - "echo ''", - "echo 'GitHub Actions Runners:'", - "gh api repos/POWERFULMOVES/PMOVES.AI/actions/runners --jq '.runners[] | \" \\(.name): \\(.status)\"' 2>/dev/null || echo ' (unable to fetch)'", - "echo ''", - "echo 'Tailscale Mesh:'", - "tailscale status 2>/dev/null | head -10 || echo ' Tailscale not connected'" - ] - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-remote/README.md b/pbnj/pinokio/api/pmoves-remote/README.md deleted file mode 100644 index 9b32ffc2ee..0000000000 --- a/pbnj/pinokio/api/pmoves-remote/README.md +++ /dev/null @@ -1,108 +0,0 @@ -# PMOVES Remote - -Headscale VPN mesh + RustDesk remote desktop for multi-node PMOVES.AI deployment. Connects your local dev machine, AI Lab, and KVM4 production nodes into a secure private network. - -## Quick Start - -1. Click **Install** to pull Docker images and initialize `env.tier-vpn` -2. Edit `env.tier-vpn` with your Headscale and RustDesk credentials -3. Click **Start** to bring up the VPN mesh + remote desktop server -4. Open the **Headscale Admin** UI at `http://localhost:8096` - -## Architecture - -``` -Z890 (dev) ──┐ -5090 (GPU) ──┤── Headscale VPN ──┬── KVM4-1 (API gateway) - │ (WireGuard) ├── KVM4-2 (data/storage) - └───────────────────└── KVM2 (exit proxy) - -RustDesk relay enables remote desktop to any mesh node. -``` - -## Scripts - -| Script | Purpose | -|--------|---------| -| `install.js` | Pull Docker images, create `env.tier-vpn` from template | -| `start.js` | Start Headscale + RustDesk via `docker-compose.remote.yml` | -| `status.js` | Show container status + Tailscale mesh peers | - -## API Reference - -### Headscale Admin — Port 8096 - -**Curl** - -```bash -# List nodes -curl -H "Authorization: Bearer $HEADSCALE_API_KEY" \ - http://localhost:8096/api/v1/node - -# Get node by ID -curl -H "Authorization: Bearer $HEADSCALE_API_KEY" \ - http://localhost:8096/api/v1/node/1 - -# List users -curl -H "Authorization: Bearer $HEADSCALE_API_KEY" \ - http://localhost:8096/api/v1/user -``` - -**Python** - -```python -import requests -import os - -api_key = os.environ["HEADSCALE_API_KEY"] -headers = {"Authorization": f"Bearer {api_key}"} - -# List nodes -r = requests.get("http://localhost:8096/api/v1/node", headers=headers) -for node in r.json().get("nodes", []): - print(f"{node['name']}: {node['ipAddresses']}") -``` - -**JavaScript** - -```javascript -const apiKey = process.env.HEADSCALE_API_KEY; - -const nodes = await fetch("http://localhost:8096/api/v1/node", { - headers: { Authorization: `Bearer ${apiKey}` } -}).then(r => r.json()); - -nodes.nodes?.forEach(n => console.log(`${n.name}: ${n.ipAddresses}`)); -``` - -### Tailscale CLI (Local Machine) - -```bash -# Check mesh status -tailscale status - -# Ping a node -tailscale ping pmoves-kvm4-1 - -# SSH to a mesh node -ssh root@pmoves-kvm4-1 -``` - -### RustDesk - -RustDesk provides remote desktop access to mesh nodes. Connection details are configured in `env.tier-vpn`: - -```bash -# Key environment variables -RUSTDESK_RELAY=your-relay-server -RUSTDESK_KEY=your-public-key -``` - -## Agent Hints - -AI agents can use this launcher to: - -- **Check VPN status** — Run `status.js` to see which nodes are online -- **Connect to remote node** — Use Tailscale SSH via `ssh root@pmoves-kvm4-1` -- **List mesh peers** — Run `tailscale status` to see all connected nodes -- **Verify connectivity** — Ping nodes with `tailscale ping ` diff --git a/pbnj/pinokio/api/pmoves-remote/SKILL.md b/pbnj/pinokio/api/pmoves-remote/SKILL.md deleted file mode 100644 index 0e80cbceef..0000000000 --- a/pbnj/pinokio/api/pmoves-remote/SKILL.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -name: PMOVES Remote Access -description: | - One-click Headscale VPN mesh + RustDesk remote desktop for PMOVES.AI - multi-node deployment. Connects Z890, 5090, 4090, Jetson edge nodes - into a secure mesh for cross-machine agent routing and remote access. -keywords: headscale, rustdesk, vpn, mesh, tailscale, remote, desktop, ssh, multi-node -version: 1.0.0 -category: Infrastructure/Networking -tier: 1 -agent_class: Standard -agent_id: pmoves_remote_access ---- - -# PMOVES Remote Access - -**Agent Class**: `Standard (Pmoves-)` -**Category**: Infrastructure/Networking -**Version**: 1.0.0 -**Tier**: 1 (Core Infrastructure) -**Status**: Active — Headscale VPN + RustDesk remote desktop - ---- - -## Capabilities - -| Command | What It Does | -|---------|-------------| -| `mesh-status` | Show Tailscale/Headscale mesh node status | -| `connect` | RustDesk remote desktop to a specified node | -| `nodes` | List all PMOVES fleet nodes and their IPs | - ---- - -## Trigger Phrases (Pinokio 7 Interpreter) - -| Phrase | Action | -|--------|--------| -| `"show mesh status"` | Display Tailscale node connectivity | -| `"connect to 5090"` | Open RustDesk to POWERFULMOVES node | -| `"connect to z890"` | Open RustDesk to Z890 node | -| `"list all nodes"` | Display fleet inventory | -| `"check vpn health"` | Verify Headscale control plane | - ---- - -## Fleet Nodes - -| Node | Role | Services | -|------|------|----------| -| Z890 | Infrastructure coordinator | Docker, CI runner, NATS, data stores | -| 5090 (POWERFULMOVES) | GPU compute, voice | TTS, Flute, model training | -| 4090 Laptop | Field agent, mobile | Terminal, monitoring, edge testing | -| Jetson Orin #1 | Edge inference | Whisper, Ollama, YOLO | -| Jetson Orin #2 | Edge inference | TensorRT, mesh agent | - ---- - -## Prerequisites - -- Tailscale or Headscale client installed on each node -- RustDesk server running (self-hosted or relay) -- Headscale control plane at port 8096 diff --git a/pbnj/pinokio/api/pmoves-remote/icon.png b/pbnj/pinokio/api/pmoves-remote/icon.png deleted file mode 100644 index 874d336836e10115bc71fca63474558baeea4ebb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1545 zcmeAS@N?(olHy`uVBq!ia0y~yU|a&i985rwk9x*JWrQQ{=@jAv_74mVMp@~M$RO5l@8en3S|yW zwB?+B!)SA&^xbClJ@2dU&U z_ZU7D4(mi6k;eZc>H5y|^BgXMvT%*+bb1sVSVEijr4`)LL)krs)yxNu@1$Q*)l$#M c!0`XS=w9g!EoNuffkixnr>mdKI;Vst0RCL|WdHyG diff --git a/pbnj/pinokio/api/pmoves-remote/install.js b/pbnj/pinokio/api/pmoves-remote/install.js deleted file mode 100644 index 999452ed29..0000000000 --- a/pbnj/pinokio/api/pmoves-remote/install.js +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = { - run: [ - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose -f docker-compose.remote.yml pull" - ] - } - }, - { - when: "{{!exists('../../pmoves/env.tier-vpn')}}", - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "cp env.tier-vpn.example env.tier-vpn" - ] - } - }, - { - method: "notify", - params: { - html: "Remote stack images pulled and env.tier-vpn initialized. Edit env.tier-vpn with your API keys before starting.", - type: "success" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-remote/pinokio.js b/pbnj/pinokio/api/pmoves-remote/pinokio.js deleted file mode 100644 index 105c804e76..0000000000 --- a/pbnj/pinokio/api/pmoves-remote/pinokio.js +++ /dev/null @@ -1,70 +0,0 @@ -module.exports = { - version: "5.0", - title: "PMOVES Remote", - description: "Headscale VPN + RustDesk remote desktop for multi-node PMOVES deployment.", - menu: async (kernel, info) => { - let installed = info.exists("../../pmoves/env.tier-vpn") - let running = { - start: info.running("start.js"), - install: info.running("install.js"), - status: info.running("status.js"), - } - - if (running.install) { - return [{ - default: true, - icon: "fa-solid fa-plug", - text: "Installing...", - href: "install.js", - }] - } - - if (!installed) { - return [{ - default: true, - icon: "fa-solid fa-plug", - text: "Install (Setup VPN Env)", - href: "install.js", - }] - } - - if (running.start) { - let local = info.local("start.js") - let items = [] - if (local && local.url) { - items.push({ - default: true, - icon: "fa-solid fa-globe", - text: "Open Headscale Admin", - href: local.url, - }) - } - items.push({ - icon: "fa-solid fa-terminal", - text: "Remote Stack (Running)", - href: "start.js", - }) - items.push({ - icon: "fa-solid fa-satellite-dish", - text: "Mesh Status", - href: "status.js", - }) - return items - } - - return [{ - default: true, - icon: "fa-solid fa-play", - text: "Start (Headscale + RustDesk)", - href: "start.js", - }, { - icon: "fa-solid fa-satellite-dish", - text: "Mesh Status", - href: "status.js", - }, { - icon: "fa-solid fa-plug", - text: "Reinstall", - href: "install.js", - }] - } -} diff --git a/pbnj/pinokio/api/pmoves-remote/pinokio.json b/pbnj/pinokio/api/pmoves-remote/pinokio.json deleted file mode 100644 index 9885c9fcce..0000000000 --- a/pbnj/pinokio/api/pmoves-remote/pinokio.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "title": "PMOVES Remote", - "description": "One-click Headscale VPN mesh + RustDesk remote desktop server for PMOVES.AI multi-node deployment.", - "icon": "icon.png" -} diff --git a/pbnj/pinokio/api/pmoves-remote/start.js b/pbnj/pinokio/api/pmoves-remote/start.js deleted file mode 100644 index 545f881d56..0000000000 --- a/pbnj/pinokio/api/pmoves-remote/start.js +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = { - daemon: true, - run: [ - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose -f docker-compose.remote.yml --profile remote up -d" - ], - on: [{ - event: "/Started|running|Attaching/i", - done: true - }] - } - }, - { - method: "local.set", - params: { - url: "http://localhost:8096" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-remote/status.js b/pbnj/pinokio/api/pmoves-remote/status.js deleted file mode 100644 index 89b0814a85..0000000000 --- a/pbnj/pinokio/api/pmoves-remote/status.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - run: [ - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose -f docker-compose.remote.yml ps --format 'table {{.Name}}\t{{.Status}}\t{{.Ports}}'" - ] - } - }, - { - method: "shell.run", - params: { - message: [ - "tailscale status" - ] - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-services/README.md b/pbnj/pinokio/api/pmoves-services/README.md deleted file mode 100644 index 701c14a1e1..0000000000 --- a/pbnj/pinokio/api/pmoves-services/README.md +++ /dev/null @@ -1,231 +0,0 @@ -# PMOVES Services - -One-click control center for all PMOVES.AI Docker Compose services — agents, workers, monitoring, voice, and external integrations. 40+ microservices orchestrated via Docker Compose profiles. - -## Quick Start - -1. Click **Install** to bootstrap the environment (generates `.env` files) -2. Click **Start Core** to launch Agent Zero + workers -3. Open the **Agent Zero UI** at `http://localhost:8081` - -## Service Profiles - -| Profile | Script | What It Launches | -|---------|--------|-----------------| -| Core (Agents + Workers) | `start-core.js` | Agent Zero, Archon, Mesh Agent, Extract Worker, media analyzers | -| Monitoring | `start-monitoring.js` | Prometheus, Grafana, Loki, Promtail, cAdvisor | -| Voice | `start-voice.js` | Flute-Gateway, Ultimate-TTS-Studio, Cast, media pipeline | -| External | `start-external.js` | Wger, Firefly, Jellyfin (via `docker-compose.external.yml`) | - -Additional scripts: - -- **status.js** — Show running containers across all compose files -- **stop.js** — Gracefully stop all services (no volume deletion) -- **reset.js** — Stop all services AND delete volumes (full reset) -- **update.js** — `git pull` + submodule update + re-bootstrap env - -## API Reference - -### Agent Zero (Orchestrator) - -| Endpoint | Method | Description | -|----------|--------|-------------| -| `http://localhost:8080/healthz` | GET | Health check | -| `http://localhost:8080/mcp/command` | POST | MCP command API | -| `http://localhost:8081` | GET | Web UI | - -**Curl** - -```bash -# Health check -curl http://localhost:8080/healthz - -# Send MCP command -curl -X POST http://localhost:8080/mcp/command \ - -H "Content-Type: application/json" \ - -d '{"command": "list_tools"}' -``` - -**Python** - -```python -import requests - -# Health check -r = requests.get("http://localhost:8080/healthz") -print(r.json()) - -# MCP command -r = requests.post("http://localhost:8080/mcp/command", json={"command": "list_tools"}) -print(r.json()) -``` - -**JavaScript** - -```javascript -// Health check -const health = await fetch("http://localhost:8080/healthz").then(r => r.json()); - -// MCP command -const result = await fetch("http://localhost:8080/mcp/command", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ command: "list_tools" }) -}).then(r => r.json()); -``` - -### TensorZero (LLM Gateway) — Port 3030 - -**Curl** - -```bash -# Chat completion -curl -X POST http://localhost:3030/v1/chat/completions \ - -H "Content-Type: application/json" \ - -d '{"model": "claude-sonnet-4-5", "messages": [{"role": "user", "content": "Hello"}]}' - -# Embeddings -curl -X POST http://localhost:3030/v1/embeddings \ - -H "Content-Type: application/json" \ - -d '{"model": "gemma_embed_local", "input": "Text to embed"}' -``` - -**Python** - -```python -import requests - -# Chat completion -r = requests.post("http://localhost:3030/v1/chat/completions", json={ - "model": "claude-sonnet-4-5", - "messages": [{"role": "user", "content": "Hello"}] -}) -print(r.json()["choices"][0]["message"]["content"]) - -# Embeddings -r = requests.post("http://localhost:3030/v1/embeddings", json={ - "model": "gemma_embed_local", - "input": "Text to embed" -}) -print(r.json()["data"][0]["embedding"][:5]) -``` - -**JavaScript** - -```javascript -// Chat completion -const chat = await fetch("http://localhost:3030/v1/chat/completions", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - model: "claude-sonnet-4-5", - messages: [{ role: "user", content: "Hello" }] - }) -}).then(r => r.json()); - -// Embeddings -const embed = await fetch("http://localhost:3030/v1/embeddings", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ model: "gemma_embed_local", input: "Text to embed" }) -}).then(r => r.json()); -``` - -### Hi-RAG v2 (Hybrid Search) — Port 8086 - -**Curl** - -```bash -curl -X POST http://localhost:8086/hirag/query \ - -H "Content-Type: application/json" \ - -d '{"query": "How does agent orchestration work?", "top_k": 10, "rerank": true}' -``` - -**Python** - -```python -import requests - -r = requests.post("http://localhost:8086/hirag/query", json={ - "query": "How does agent orchestration work?", - "top_k": 10, - "rerank": True -}) -print(r.json()) -``` - -**JavaScript** - -```javascript -const results = await fetch("http://localhost:8086/hirag/query", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ query: "How does agent orchestration work?", top_k: 10, rerank: true }) -}).then(r => r.json()); -``` - -### Flute-Gateway (Voice Synthesis) — Port 8055 - -**Curl** - -```bash -# Health check -curl http://localhost:8055/healthz - -# Prosodic TTS -curl -X POST http://localhost:8055/v1/voice/synthesize/prosodic \ - -H "Content-Type: application/json" \ - -d '{"text": "Hello, welcome to PMOVES.", "voice": "default"}' -``` - -**Python** - -```python -import requests - -r = requests.post("http://localhost:8055/v1/voice/synthesize/prosodic", json={ - "text": "Hello, welcome to PMOVES.", - "voice": "default" -}) -# r.content contains audio bytes -with open("output.wav", "wb") as f: - f.write(r.content) -``` - -**JavaScript** - -```javascript -const response = await fetch("http://localhost:8055/v1/voice/synthesize/prosodic", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ text: "Hello, welcome to PMOVES.", voice: "default" }) -}); -const audioBlob = await response.blob(); -``` - -### Monitoring - -| Service | Port | URL | -|---------|------|-----| -| Grafana | 3000 | `http://localhost:3000` | -| Prometheus | 9090 | `http://localhost:9090` | -| Loki | 3100 | `http://localhost:3100` | - -```bash -# Query Prometheus targets -curl http://localhost:9090/api/v1/query?query=up - -# Check Grafana -curl http://localhost:3000/api/health -``` - -## Agent Hints - -AI agents can use this launcher to: - -- **Search knowledge** — Query Hi-RAG v2 at port 8086 for semantic + keyword + graph search -- **Speak text** — Synthesize speech via Flute-Gateway at port 8055 -- **Chat with LLMs** — Route through TensorZero gateway at port 3030 (OpenAI-compatible) -- **Generate embeddings** — Create vector embeddings via TensorZero at port 3030 -- **Check service health** — Run `status.js` or curl individual `/healthz` endpoints -- **Orchestrate agents** — Send MCP commands to Agent Zero at port 8080 diff --git a/pbnj/pinokio/api/pmoves-services/SKILL.md b/pbnj/pinokio/api/pmoves-services/SKILL.md deleted file mode 100644 index c4e84f32fb..0000000000 --- a/pbnj/pinokio/api/pmoves-services/SKILL.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -name: PMOVES Services Control Center -description: | - One-click Docker Compose orchestrator for 40+ PMOVES.AI microservices. - Start/stop/status for 4 service profiles: core agents, voice pipeline, - monitoring stack, and external integrations. Manages the entire PMOVES - infrastructure from a single Pinokio launcher. -keywords: docker, compose, services, agents, voice, monitoring, infrastructure, start, stop, status, reset -version: 1.0.0 -category: Infrastructure/Orchestration -tier: 1 -agent_class: Standard -agent_id: pmoves_services_ctl ---- - -# PMOVES Services Control Center - -**Agent Class**: `Standard (Pmoves-)` -**Category**: Infrastructure/Orchestration -**Version**: 1.0.0 -**Tier**: 1 (Core Infrastructure) -**Status**: Active — 4 service profiles, 40+ containers - ---- - -## Capabilities - -| Command | What It Does | -|---------|-------------| -| `start-core` | Launch Agent Zero, Archon, Mesh Agent, Extract Worker, media analyzers | -| `start-voice` | Launch Flute-Gateway, Ultimate-TTS-Studio, Cast, media pipeline | -| `start-monitoring` | Launch Prometheus, Grafana, Loki, Promtail, cAdvisor | -| `start-external` | Launch Wger, Firefly III, Jellyfin (external integrations) | -| `status` | Show running containers across all compose files | -| `stop` | Gracefully stop all services (volumes preserved) | -| `reset` | Stop all services AND delete volumes (full reset) | -| `update` | Git pull + submodule update + re-bootstrap env | - ---- - -## Trigger Phrases (Pinokio 7 Interpreter) - -| Phrase | Action | Script | -|--------|--------|--------| -| `"start the agents"` | Launch core agent stack | `start-core.js` | -| `"start voice services"` | Launch TTS + Flute pipeline | `start-voice.js` | -| `"start monitoring"` | Launch Prometheus + Grafana | `start-monitoring.js` | -| `"show service status"` | Display all running containers | `status.js` | -| `"stop all services"` | Graceful shutdown | `stop.js` | -| `"reset everything"` | Full reset with volume deletion | `reset.js` | -| `"update pmoves"` | Pull latest + rebuild env | `update.js` | -| `"start external apps"` | Launch Wger + Firefly + Jellyfin | `start-external.js` | - ---- - -## Service Profiles - -### Core (Agents + Workers) -- **Agent Zero** — `http://localhost:8080` (orchestrator, MCP API) -- **Archon** — `http://localhost:8091` (Supabase agent service) -- **Mesh Agent** — Node announcer (NATS every 15s) -- **Extract Worker** — `http://localhost:8083` (text embedding + indexing) -- **Hi-RAG v2** — `http://localhost:8086` (hybrid retrieval) - -### Voice -- **Flute-Gateway** — `http://localhost:8055` (prosodic voice synthesis) -- **Ultimate-TTS-Studio** — `http://localhost:7860` (14-engine TTS) -- **Cast-TTS** — `http://localhost:8060` (Chromecast/Nest speaker TTS) - -### Monitoring -- **Prometheus** — `http://localhost:9090` (metrics) -- **Grafana** — `http://localhost:3000` (dashboards) -- **Loki** — `http://localhost:3100` (log aggregation) - -### External -- **Wger (Health)** — `http://localhost:8000` (fitness tracking) -- **Firefly III (Wealth)** — `http://localhost:8075` (finance management) -- **Jellyfin** — Media server - ---- - -## Health Checks - -```bash -# Quick check all core services -curl http://localhost:8080/healthz # Agent Zero -curl http://localhost:8086/ # Hi-RAG v2 -curl http://localhost:8094/healthz # Publisher-Discord -curl http://localhost:8055/healthz # Flute-Gateway - -# Full verification -make -C pmoves verify-all -``` - ---- - -## Prerequisites - -- Docker Desktop running with Docker Compose v2+ -- `pmoves/env.shared` bootstrapped (Install step handles this) -- NATS message bus accessible at port 4222 diff --git a/pbnj/pinokio/api/pmoves-services/icon.png b/pbnj/pinokio/api/pmoves-services/icon.png deleted file mode 100644 index 874d336836e10115bc71fca63474558baeea4ebb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1545 zcmeAS@N?(olHy`uVBq!ia0y~yU|a&i985rwk9x*JWrQQ{=@jAv_74mVMp@~M$RO5l@8en3S|yW zwB?+B!)SA&^xbClJ@2dU&U z_ZU7D4(mi6k;eZc>H5y|^BgXMvT%*+bb1sVSVEijr4`)LL)krs)yxNu@1$Q*)l$#M c!0`XS=w9g!EoNuffkixnr>mdKI;Vst0RCL|WdHyG diff --git a/pbnj/pinokio/api/pmoves-services/install.js b/pbnj/pinokio/api/pmoves-services/install.js deleted file mode 100644 index f6a0ef6dd0..0000000000 --- a/pbnj/pinokio/api/pmoves-services/install.js +++ /dev/null @@ -1,27 +0,0 @@ -module.exports = { - run: [ - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "py -3 tools/env_setup_unified.py" - ] - } - }, - { - method: "fs.link", - params: { - src: "{{cwd}}", - dest: "{{path.resolve(cwd, '..', '..', '..', '..', 'pinokio', 'api', 'pmoves-services')}}" - } - }, - { - method: "notify", - params: { - html: "PMOVES environment bootstrapped. Ready to start services.", - type: "success" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-services/pinokio.js b/pbnj/pinokio/api/pmoves-services/pinokio.js deleted file mode 100644 index 5c93ff7313..0000000000 --- a/pbnj/pinokio/api/pmoves-services/pinokio.js +++ /dev/null @@ -1,166 +0,0 @@ -module.exports = { - version: "5.0", - title: "PMOVES Services", - description: "One-click control center for all PMOVES.AI Docker Compose services.", - icon: "icon.png", - menu: async (kernel, info) => { - let installed = info.exists("../../pmoves/env.shared") - let running = { - core: info.running("start-core.js"), - voice: info.running("start-voice.js"), - monitoring: info.running("start-monitoring.js"), - external: info.running("start-external.js"), - status: info.running("status.js"), - install: info.running("install.js"), - update: info.running("update.js"), - reset: info.running("reset.js"), - } - - // Installation in progress - if (running.install) { - return [{ - default: true, - icon: "fa-solid fa-plug", - text: "Installing...", - href: "install.js", - }] - } - - // Not installed yet - if (!installed) { - return [{ - default: true, - icon: "fa-solid fa-plug", - text: "Install (Bootstrap Env)", - href: "install.js", - }] - } - - // Update or reset in progress - if (running.update) { - return [{ - default: true, - icon: "fa-solid fa-arrows-rotate", - text: "Updating...", - href: "update.js", - }] - } - if (running.reset) { - return [{ - default: true, - icon: "fa-solid fa-rotate-left", - text: "Resetting...", - href: "reset.js", - }] - } - - // Services running — show active terminals and dashboards - if (running.core || running.voice || running.monitoring || running.external) { - let items = [] - - if (running.core) { - let local = info.local("start-core.js") - if (local && local.url) { - items.push({ - default: true, - icon: "fa-solid fa-rocket", - text: "Open Agent Zero UI", - href: local.url, - }) - } - items.push({ - icon: "fa-solid fa-terminal", - text: "Core Services (Running)", - href: "start-core.js", - }) - } - - if (running.monitoring) { - items.push({ - default: !running.core, - icon: "fa-solid fa-chart-line", - text: "Open Grafana", - href: "http://localhost:3000", - }) - items.push({ - icon: "fa-solid fa-terminal", - text: "Monitoring (Running)", - href: "start-monitoring.js", - }) - } - - if (running.voice) { - let voiceLocal = info.local("start-voice.js") - if (voiceLocal && voiceLocal.url) { - items.push({ - icon: "fa-solid fa-microphone", - text: "Open Flute Gateway", - href: voiceLocal.url, - }) - } - items.push({ - icon: "fa-solid fa-terminal", - text: "Voice Pipeline (Running)", - href: "start-voice.js", - }) - } - - if (running.external) { - items.push({ - icon: "fa-solid fa-terminal", - text: "External (Running)", - href: "start-external.js", - }) - } - - items.push({ - icon: "fa-solid fa-circle-info", - text: "Health Status", - href: "status.js", - }) - items.push({ - icon: "fa-solid fa-stop", - text: "Stop All", - href: "stop.js", - }) - - return items - } - - // Installed but nothing running — show start options - return [{ - default: true, - icon: "fa-solid fa-play", - text: "Start Core (Agents + Workers)", - href: "start-core.js", - }, { - icon: "fa-solid fa-chart-line", - text: "Start Monitoring", - href: "start-monitoring.js", - }, { - icon: "fa-solid fa-microphone", - text: "Start Voice (TTS + Flute + Cast)", - href: "start-voice.js", - }, { - icon: "fa-solid fa-puzzle-piece", - text: "Start External (Wger/Firefly/Jellyfin)", - href: "start-external.js", - }, { - icon: "fa-solid fa-circle-info", - text: "Health Status", - href: "status.js", - }, { - icon: "fa-solid fa-arrows-rotate", - text: "Update", - href: "update.js", - }, { - icon: "fa-solid fa-plug", - text: "Reinstall", - href: "install.js", - }, { - icon: "fa-regular fa-circle-xmark", - text: "Reset", - href: "reset.js", - }] - } -} diff --git a/pbnj/pinokio/api/pmoves-services/pinokio.json b/pbnj/pinokio/api/pmoves-services/pinokio.json deleted file mode 100644 index 57f1823760..0000000000 --- a/pbnj/pinokio/api/pmoves-services/pinokio.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "title": "PMOVES Services", - "description": "One-click control center for all PMOVES.AI Docker Compose services — agents, workers, monitoring, voice, and external integrations. 40+ microservices orchestrated via Docker Compose profiles.", - "icon": "icon.png" -} diff --git a/pbnj/pinokio/api/pmoves-services/reset.js b/pbnj/pinokio/api/pmoves-services/reset.js deleted file mode 100644 index fbce92974b..0000000000 --- a/pbnj/pinokio/api/pmoves-services/reset.js +++ /dev/null @@ -1,38 +0,0 @@ -module.exports = { - run: [ - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose --profile agents --profile workers --profile orchestration --profile gpu --profile tts --profile cast --profile media --profile botz --profile ui down -v" - ] - } - }, - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose -f docker-compose.yml -f monitoring/docker-compose.monitoring.yml down -v" - ] - } - }, - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose -f docker-compose.external.yml down -v" - ] - } - }, - { - method: "notify", - params: { - html: "All PMOVES services and volumes reset. Run Install to bootstrap again.", - type: "warning" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-services/start-core.js b/pbnj/pinokio/api/pmoves-services/start-core.js deleted file mode 100644 index bb99057c98..0000000000 --- a/pbnj/pinokio/api/pmoves-services/start-core.js +++ /dev/null @@ -1,29 +0,0 @@ -module.exports = { - daemon: true, - run: [ - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose --profile agents --profile workers up -d" - ], - on: [{ - // Docker compose "up -d" never prints an HTTP URL to stdout, - // so we match on container lifecycle messages instead. - // The URL below is hardcoded because compose doesn't expose it. - event: "/Started|running|Attaching/i", - done: true - }] - } - }, - { - // Hardcoded: docker compose does not print the service URL to stdout. - // Agent Zero UI listens on port 8081 by default. - method: "local.set", - params: { - url: "http://localhost:8081" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-services/start-external.js b/pbnj/pinokio/api/pmoves-services/start-external.js deleted file mode 100644 index 28883c3362..0000000000 --- a/pbnj/pinokio/api/pmoves-services/start-external.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - daemon: true, - run: [ - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose -f docker-compose.external.yml up -d" - ], - on: [{ - event: "/Started|running|Attaching/i", - done: true - }] - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-services/start-monitoring.js b/pbnj/pinokio/api/pmoves-services/start-monitoring.js deleted file mode 100644 index e0d15522cc..0000000000 --- a/pbnj/pinokio/api/pmoves-services/start-monitoring.js +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = { - daemon: true, - run: [ - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose -f docker-compose.yml -f monitoring/docker-compose.monitoring.yml up -d" - ], - on: [{ - event: "/Started|running|Attaching/i", - done: true - }] - } - }, - { - method: "local.set", - params: { - url: "http://localhost:3000" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-services/start-voice.js b/pbnj/pinokio/api/pmoves-services/start-voice.js deleted file mode 100644 index 2bbe1892e7..0000000000 --- a/pbnj/pinokio/api/pmoves-services/start-voice.js +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = { - daemon: true, - run: [ - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose --profile orchestration --profile media --profile cast --profile gpu up -d" - ], - on: [{ - event: "/Started|running|Attaching|Container.*Started/i", - done: true - }] - } - }, - { - method: "local.set", - params: { - url: "http://localhost:8055" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-services/status.js b/pbnj/pinokio/api/pmoves-services/status.js deleted file mode 100644 index bcd9040099..0000000000 --- a/pbnj/pinokio/api/pmoves-services/status.js +++ /dev/null @@ -1,31 +0,0 @@ -module.exports = { - run: [ - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose ps --format 'table {{.Name}}\t{{.Status}}\t{{.Ports}}'" - ] - } - }, - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose -f docker-compose.external.yml ps --format 'table {{.Name}}\t{{.Status}}\t{{.Ports}}'" - ] - } - }, - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose -f docker-compose.remote.yml ps --format 'table {{.Name}}\t{{.Status}}\t{{.Ports}}'" - ] - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-services/stop.js b/pbnj/pinokio/api/pmoves-services/stop.js deleted file mode 100644 index c2f96a40de..0000000000 --- a/pbnj/pinokio/api/pmoves-services/stop.js +++ /dev/null @@ -1,38 +0,0 @@ -module.exports = { - run: [ - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose --profile agents --profile workers --profile orchestration --profile gpu --profile tts --profile cast --profile media --profile botz --profile ui down" - ] - } - }, - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose -f docker-compose.yml -f monitoring/docker-compose.monitoring.yml down" - ] - } - }, - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "docker compose -f docker-compose.external.yml down" - ] - } - }, - { - method: "notify", - params: { - html: "All PMOVES services stopped.", - type: "info" - } - } - ] -} diff --git a/pbnj/pinokio/api/pmoves-services/update.js b/pbnj/pinokio/api/pmoves-services/update.js deleted file mode 100644 index 04463a4d36..0000000000 --- a/pbnj/pinokio/api/pmoves-services/update.js +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = { - run: [ - { - method: "shell.run", - params: { - path: "../..", - message: [ - "git pull --ff-only origin main", - "git submodule update --init --recursive" - ] - } - }, - { - method: "shell.run", - params: { - path: "../../pmoves", - message: [ - "py -3 tools/env_setup_unified.py" - ] - } - }, - { - method: "notify", - params: { - html: "PMOVES updated to latest.", - type: "success" - } - } - ] -} diff --git a/pbnj/pinokio/plugin/code/pmoves-codex/README.md b/pbnj/pinokio/plugin/code/pmoves-codex/README.md deleted file mode 100644 index ff57098d3f..0000000000 --- a/pbnj/pinokio/plugin/code/pmoves-codex/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# PMOVES Codex Pinokio Plugin - -PMOVES wrapper plugin for OpenAI Codex inside Pinokio. - -## Purpose - -This plugin keeps the upstream Codex terminal flow but injects PMOVES mesh defaults into the target workspace: - -- `PMOVES_AGENT_ZERO_URL` -- `PMOVES_AGENT_ZERO_UI_URL` -- `PMOVES_ARCHON_URL` -- `PMOVES_HIRAG_URL` -- `PMOVES_NOTEBOOK_API_URL` -- `PMOVES_NATS_URL` - -The goal is to keep provider-native behavior while giving Codex a stable PMOVES contract to build against. - -## Install - -Copy or symlink this folder into your Pinokio plugin directory: - -```bash -~/pinokio/plugin/pmoves-codex -``` - -On this node the live Pinokio home is `D:/pinokio`, so the effective install target is: - -```text -D:/pinokio/plugin/pmoves-codex -``` - -## Usage - -1. Open any Pinokio workspace or installed PMOVES app. -2. Choose `PMOVES Codex` from Ask AI or Plugins. -3. Codex launches in the selected workspace with PMOVES mesh defaults available in the environment. - -## Notes - -- This plugin does not replace Pinokio's built-in `codex` plugin. -- It is the PMOVES-customized wrapper layer for Codex-specific defaults. -- Keep direct agent-to-agent communication on the PMOVES mesh, not inside the plugin itself. diff --git a/pbnj/pinokio/plugin/code/pmoves-codex/icon.svg b/pbnj/pinokio/plugin/code/pmoves-codex/icon.svg deleted file mode 100644 index 65a2d418fa..0000000000 --- a/pbnj/pinokio/plugin/code/pmoves-codex/icon.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/pbnj/pinokio/plugin/code/pmoves-codex/pinokio.js b/pbnj/pinokio/plugin/code/pmoves-codex/pinokio.js deleted file mode 100644 index f526a7896b..0000000000 --- a/pbnj/pinokio/plugin/code/pmoves-codex/pinokio.js +++ /dev/null @@ -1,51 +0,0 @@ -module.exports = { - title: "PMOVES Codex", - icon: "icon.svg", - description: "OpenAI Codex with PMOVES mesh defaults for Pinokio workspaces.", - link: "https://github.com/openai/codex", - run: [{ - when: "{{platform === 'win32'}}", - id: "run", - method: "shell.run", - params: { - shell: "{{kernel.path('bin/miniconda/Library/bin/bash.exe')}}", - conda: { - skip: true - }, - env: { - PMOVES_PROVIDER: "openai-codex", - PMOVES_PINOKIO_PLUGIN: "pmoves-codex", - PMOVES_AGENT_ZERO_URL: "{{envs.PMOVES_AGENT_ZERO_URL || 'http://localhost:8080'}}", - PMOVES_AGENT_ZERO_UI_URL: "{{envs.PMOVES_AGENT_ZERO_UI_URL || 'http://localhost:8081'}}", - PMOVES_ARCHON_URL: "{{envs.PMOVES_ARCHON_URL || 'http://localhost:8091'}}", - PMOVES_HIRAG_URL: "{{envs.PMOVES_HIRAG_URL || 'http://localhost:8086'}}", - PMOVES_NOTEBOOK_API_URL: "{{envs.PMOVES_NOTEBOOK_API_URL || 'http://localhost:4110'}}", - PMOVES_NATS_URL: "{{envs.PMOVES_NATS_URL || 'nats://nats:pmoves@localhost:4222'}}" - }, - message: "npx -y @openai/codex@latest {{args.prompt ? JSON.stringify(args.prompt) : ''}}", - path: "{{args.cwd}}", - input: true, - buffer: 1024 - } - }, { - when: "{{platform !== 'win32'}}", - id: "run", - method: "shell.run", - params: { - env: { - PMOVES_PROVIDER: "openai-codex", - PMOVES_PINOKIO_PLUGIN: "pmoves-codex", - PMOVES_AGENT_ZERO_URL: "{{envs.PMOVES_AGENT_ZERO_URL || 'http://localhost:8080'}}", - PMOVES_AGENT_ZERO_UI_URL: "{{envs.PMOVES_AGENT_ZERO_UI_URL || 'http://localhost:8081'}}", - PMOVES_ARCHON_URL: "{{envs.PMOVES_ARCHON_URL || 'http://localhost:8091'}}", - PMOVES_HIRAG_URL: "{{envs.PMOVES_HIRAG_URL || 'http://localhost:8086'}}", - PMOVES_NOTEBOOK_API_URL: "{{envs.PMOVES_NOTEBOOK_API_URL || 'http://localhost:4110'}}", - PMOVES_NATS_URL: "{{envs.PMOVES_NATS_URL || 'nats://nats:pmoves@localhost:4222'}}" - }, - message: "npx -y @openai/codex@latest {{args.prompt ? JSON.stringify(args.prompt) : ''}}", - path: "{{args.cwd}}", - input: true, - buffer: 1024 - } - }] -}