Skip to content

fix(evo-controller): read CHIT_PASSPHRASE via services.common.env helpers - #2124

Closed
POWERFULMOVES wants to merge 6 commits into
mainfrom
fix/evo-controller-chit-secrets
Closed

POWERFULMOVES wants to merge 6 commits into
mainfrom
fix/evo-controller-chit-secrets

Conversation

@POWERFULMOVES

@POWERFULMOVES POWERFULMOVES commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

Replaces direct os.getenv("CHIT_PASSPHRASE") calls in pmoves/services/evo-controller/app.py with services.common.env.get_secret() so Docker *_FILE secrets are supported consistently with the rest of the stack.

Changes

  • _chit_signing_key() now uses get_secret("CHIT_SIGNING_KEY") / get_secret("CHIT_PASSPHRASE", "").
  • Added test_payload_signed_when_passphrase_file_present to verify CHIT_PASSPHRASE_FILE support.

Verification

python3 -m pytest pmoves/services/evo-controller/tests/ -v
# 13 passed

Related

This addresses the evo-controller secrets-audit blocker. A follow-up issue will track the remaining services still using raw os.environ.get / os.getenv for CHIT_PASSPHRASE.

Summary by CodeRabbit

  • New Features

    • Added broader MCP connectivity across agent tools, databases, networking, and Docker services.
    • Added automated MCP configuration generation, bootstrap, validation, and backup support.
    • Added KiloCode GLM agent support, health checks, parity checks, and operational skills.
    • Added configurable local and fleet endpoints across supported profiles.
  • Bug Fixes

    • Added support for file-based signing secrets, improving secure deployment compatibility.
  • Documentation

    • Expanded MCP toolkit, KiloCode, operator, and workflow guidance.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@POWERFULMOVES, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 56 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0dbdc038-52eb-4dc2-9beb-4192629445c2

📥 Commits

Reviewing files that changed from the base of the PR and between 4c473b4 and 4a7c842.

📒 Files selected for processing (45)
  • .claude/mcp.json
  • .gitignore
  • .kimi/mcp.json
  • kilo.json
  • pmoves/Makefile
  • pmoves/config/mcp_inventory.json
  • pmoves/config/profiles/hermes/4090.yaml
  • pmoves/config/profiles/hermes/5090.yaml
  • pmoves/config/profiles/hermes/b850.yaml
  • pmoves/config/profiles/hermes/elder-melchor.yaml
  • pmoves/config/profiles/hermes/kvm4-1.yaml
  • pmoves/config/profiles/hermes/spark.yaml
  • pmoves/config/profiles/hermes/z890.yaml
  • pmoves/configs/claws/opencode-4090.json
  • pmoves/configs/claws/opencode-5090.json
  • pmoves/configs/claws/opencode-kvm2.json
  • pmoves/configs/claws/opencode-kvm4-1.json
  • pmoves/configs/claws/opencode-kvm4-2.json
  • pmoves/configs/claws/opencode-nemoclaw.json
  • pmoves/configs/claws/opencode-nemotron-claw.json
  • pmoves/configs/claws/opencode-spark.json
  • pmoves/configs/claws/scopes/4090.json
  • pmoves/configs/claws/scopes/5090.json
  • pmoves/configs/claws/scopes/kvm2.json
  • pmoves/configs/claws/scopes/kvm4-1.json
  • pmoves/configs/claws/scopes/kvm4-2.json
  • pmoves/configs/claws/scopes/nemoclaw.json
  • pmoves/configs/claws/scopes/nemotron-claw.json
  • pmoves/configs/claws/scopes/spark.json
  • pmoves/configs/claws/scopes/z890.json
  • pmoves/docs/operations/MCP_TOOLKIT.md
  • pmoves/mk/kilo.mk
  • pmoves/mk/mcp-toolkit.mk
  • pmoves/scripts/bootstrap-hermes-crush.sh
  • pmoves/scripts/bootstrap-node.sh
  • pmoves/scripts/mcp-toolkit-bootstrap.sh
  • pmoves/services/evo-controller/app.py
  • pmoves/services/evo-controller/tests/test_chit_signing.py
  • pmoves/tensorzero/config/tensorzero.toml
  • pmoves/tests/test_mcp_config_generator.py
  • pmoves/tools/bootstrap_openclaw_scopes.py
  • pmoves/tools/bootstrap_opencode.py
  • pmoves/tools/crush_configurator.py
  • pmoves/tools/kilo_parity_mcp_check.py
  • pmoves/tools/mcp_config_generator.py
📝 Walkthrough

Walkthrough

The PR establishes a canonical PMOVES MCP inventory, generates client-specific configurations, bootstraps multiple agent stacks, adds KiloCode operational tooling and documentation, updates node configurations, and changes CHIT secret handling and TensorZero KiloCode routing.

Changes

MCP and KiloCode platform

Layer / File(s) Summary
Canonical inventory and config generation
pmoves/config/mcp_inventory.json, pmoves/tools/mcp_config_generator.py, pmoves/tests/test_mcp_config_generator.py
Defines canonical MCP servers, renders client-native configurations, merges existing settings, expands environment placeholders, and tests client, endpoint, and scope behavior.
Bootstrap and parity workflows
pmoves/tools/bootstrap_*.py, pmoves/tools/crush_configurator.py, pmoves/tools/kilo_parity_mcp_check.py, pmoves/scripts/bootstrap-hermes-crush.sh
Adds OpenClaw/OpenCode/Hermes/Crush bootstrap utilities, environment gating, backups, and KiloCode MCP parity validation.
Client and node MCP configurations
.claude/mcp.json, .kimi/mcp.json, kilo.json, pmoves/config/profiles/**, pmoves/configs/claws/**
Adds or expands MCP servers, transports, credentials placeholders, permissions, gateway settings, and node-specific services across client configurations.
Make and node bootstrap integration
pmoves/Makefile, pmoves/mk/*.mk, pmoves/scripts/bootstrap-node.sh, pmoves/scripts/mcp-toolkit-bootstrap.sh, pmoves/docs/operations/MCP_TOOLKIT.md
Adds MCP and KiloCode Make targets, validation flows, first-run integration, optional node bootstrap execution, and updated operational documentation.
KiloCode skills and registry
.kilocode/skills/*, pmoves/config/agent_registry.yaml, pmoves/docs/AGENTS/*, skills/README.md, .kimi/AGENTS.md
Adds KiloCode agent metadata, skills, persona guidance, operator references, and navigation documentation.

Runtime signing and model routing

Layer / File(s) Summary
CHIT secrets and TensorZero routing
pmoves/services/evo-controller/*, pmoves/tensorzero/config/tensorzero.toml
Adds file-backed CHIT secret support with tests, removes the GLM-5.2 model and legacy KiloCode function block, and adds a GLM-5.1 KiloCode variant.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description covers summary and verification, but misses most required template sections and the required bullet-list summary format. Add the template’s bullet summary, Testing section, Required Checks, Review Coordination, Follow-up Tasks, and Reviewer Notes.
Docstring Coverage ⚠️ Warning Docstring coverage is 27.59% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main evo-controller secrets-helper change and is concise.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/evo-controller-chit-secrets

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

❤️ Share

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4c473b4490

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread pmoves/tools/mcp_config_generator.py Outdated
Comment on lines +107 to +109
val = env.get(var) or os.environ.get(var)
if val:
result.append(val)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Stop expanding secrets into tracked MCP configs

When mcp-config-bootstrap/opencode-bootstrap runs in a shell that has loaded the PMOVES secrets, this fallback reads values such as CIPHER_API_TOKEN and SUPABASE_SERVICE_KEY from os.environ and writes them into tracked outputs like .kimi/mcp.json, kilo.json, and pmoves/configs/claws/*.json instead of preserving ${...} placeholders. I reproduced this with CIPHER_API_TOKEN=SECRET123 SUPABASE_SERVICE_KEY=SUPAKEY python3 -m pmoves.tools.mcp_config_generator --client kimi --output /tmp/mcp.json, which wrote Bearer SECRET123 and SUPAKEY into JSON. For tracked config generation, only explicit --set values should be expanded, or secret placeholders should remain literal.

Useful? React with 👍 / 👎.

# ── Crush ────────────────────────────────────────────────────────────────────

info "Updating Crush config: ${CRUSH_CONFIG}"
python3 -m pmoves.tools.mcp_config_generator --client crush --output "${CRUSH_CONFIG}" || warn "Crush config update failed"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Run the Crush generator with the repo on PYTHONPATH

When this target is invoked through make -C pmoves hermes-crush-bootstrap, the current directory is pmoves/, so python3 -m pmoves.tools.mcp_config_generator cannot resolve the top-level pmoves package; I checked from that directory and it fails with ModuleNotFoundError: No module named 'pmoves.tools'. Because the failure is converted to a warning and the script still exits 0, the Crush config is silently not updated in the advertised bootstrap flow; set PYTHONPATH="$REPO_ROOT" or run the module from the repo root before invoking it.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 15

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.kimi/mcp.json:
- Around line 31-43: Update the --apiKey value in the pmoves-supabase
configuration at .kimi/mcp.json lines 31-43 and kilo.json lines 146-158 to use
${SUPABASE_SERVICE_ROLE_KEY:-${SUPABASE_SERVICE_KEY}}, matching .claude/mcp.json
so either secret name is supported.

In `@kilo.json`:
- Around line 160-169: Change the supabase-db permission configuration from
allow to ask so database operations require explicit approval before execution.
Update the permission.supabase-db_* setting associated with the supabase-db MCP
server, while leaving its command and environment configuration unchanged.

In `@pmoves/config/profiles/hermes/kvm4-1.yaml`:
- Around line 104-109: Align the Hermes gateway configuration with
render_hermes(), which currently emits only enabled, type, url, and optional
headers. Remove the unsupported auth_token and tools fields from
docker_mcp_gateway in pmoves/config/profiles/hermes/kvm4-1.yaml (104-109),
pmoves/config/profiles/hermes/spark.yaml (140-145), and
pmoves/config/profiles/hermes/z890.yaml (121-126), unless the renderer/bootstrap
path is explicitly updated to preserve them.

In `@pmoves/configs/claws/opencode-4090.json`:
- Around line 32-55: Apply least-privilege Supabase configuration to the
pmoves-supabase and supabase-db entries in
pmoves/configs/claws/opencode-4090.json lines 32-55,
pmoves/configs/claws/opencode-5090.json lines 72-95,
pmoves/configs/claws/opencode-kvm2.json lines 32-55, and
pmoves/configs/claws/opencode-kvm4-1.json lines 32-55: replace broad shared
credentials with scoped Supabase credentials and change postgres-mcp from
--access-mode=unrestricted to the appropriate restricted access mode, preserving
each entry’s existing connectivity settings.

In `@pmoves/configs/claws/opencode-nemoclaw.json`:
- Around line 32-44: Remove the Supabase service key from the CLI args for the
pmoves-supabase MCP configuration and use the project’s secret-injection
mechanism instead, while preserving the existing endpoint and schema settings.
Apply the same change in pmoves/configs/claws/opencode-nemoclaw.json#L32-L44,
pmoves/configs/claws/scopes/kvm4-2.json#L73-L85,
pmoves/configs/claws/scopes/nemotron-claw.json#L88-L100,
pmoves/configs/claws/scopes/spark.json#L73-L85, and
pmoves/configs/claws/scopes/z890.json#L114-L126, then regenerate the mirrored
claw configurations.

In `@pmoves/configs/claws/scopes/kvm4-2.json`:
- Around line 109-119: Remove the “tailscale” MCP configuration from the
restricted scope, or replace it with a read-only credential and tool set that
cannot perform network administration. Ensure this tier retains only status-only
Tailscale access and no longer wires the administrative TAILSCALE_API_KEY
through tailscale-mcp.

In `@pmoves/scripts/bootstrap-hermes-crush.sh`:
- Around line 34-35: Update the bootstrap error paths around the Crush config
generation and the referenced missing-PyYAML and client-configuration branches
to return a nonzero status instead of success. Ensure failures from the python3
mcp_config_generator command and unavailable required dependencies propagate out
of the script, preventing the “bootstrap complete” success path from running.

In `@pmoves/tests/test_mcp_config_generator.py`:
- Around line 325-332: Update the test setup around scopes.main([]) to use
pytest’s monkeypatch fixture for both scopes.SCOPES_DIR and
scopes.INVENTORY_PATH, replacing the manual try/finally restoration. Apply the
same change to the corresponding test blocks at the other affected locations so
both module globals are automatically restored after each test.

In `@pmoves/tools/bootstrap_openclaw_scopes.py`:
- Around line 138-150: Update the scope validation logic around SCOPE_CONFIG,
TIER_KEYS, and PMOVES_MCP_KEYS to compare each expected PMOVES MCP entry’s
complete canonical definition, including URLs, headers, commands, and arguments,
rather than only comparing key presence. Render or derive the expected tier
configuration, compare it against data["mcp_servers"], and report mismatched
definitions alongside missing and unexpected entries while preserving the
existing tier-specific validation.

In `@pmoves/tools/crush_configurator.py`:
- Around line 196-318: Replace the duplicate MCP definitions in
pmoves/tools/crush_configurator.py (lines 196-318) with rendering through
mcp_config_generator; in pmoves/tools/bootstrap_openclaw_scopes.py (lines 23-35)
and pmoves/tools/bootstrap_opencode.py (lines 18-30), derive owned PMOVES keys
from the canonical inventory; in pmoves/scripts/bootstrap-hermes-crush.sh (line
76), remove inventory-owned entries before merging the newly rendered Hermes
block.

In `@pmoves/tools/kilo_parity_mcp_check.py`:
- Around line 15-31: The parity check currently compares only MCP keys; update
its main validation flow to generate the canonical KiloCode fragment from the
inventory and structurally compare the owned mcp definitions and permission
entries, including URLs, headers, commands, and permissions. Detect and report
stale values and unexpected obsolete entries, while preserving the existing
client filtering and nonzero failure behavior.

In `@pmoves/tools/mcp_config_generator.py`:
- Around line 452-458: Update the client-output selection logic in the loop over
clients to reject the combination of args.client == "all" and a single
args.output path before generating files. Require args.output_dir for all-client
generation, or otherwise assign a distinct output filename per client; preserve
the existing single-client output behavior.
- Around line 366-375: Update the hermes branch of the MCP configuration
generation flow to avoid writing the rendered fragment over the real Hermes
config.yaml. Use the existing merge behavior to parse and preserve unrelated
YAML settings while updating only the top-level mcp_servers key, or require and
write to a distinct fragment output path; do not ignore merge in this branch.
- Around line 107-114: Update the variable expansion logic around _expand so
process-environment values are not used to resolve placeholders by default,
preventing secrets from being written to generated configuration files. Preserve
unresolved references such as CIPHER_API_TOKEN and Supabase service keys unless
the caller explicitly enables secret materialization, while retaining explicit
env mappings and recursive default expansion.
- Around line 227-229: Update render_kilocode() so it does not automatically
assign wildcard permissions to every rendered MCP server. Require explicit
per-server opt-in or use narrower permissions for sensitive servers such as
tailscale and supabase-db, while preserving rendering of the MCP entries and
existing permissions for non-sensitive servers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8953f37e-c6bf-4b8b-90ca-2f37b3c5b6f0

📥 Commits

Reviewing files that changed from the base of the PR and between d9a077c and 4c473b4.

📒 Files selected for processing (51)
  • .claude/mcp.json
  • .gitignore
  • .kilocode/skills/kilocode-agent-trails/SKILL.md
  • .kilocode/skills/kilocode-bringup-audit/SKILL.md
  • .kimi/AGENTS.md
  • .kimi/mcp.json
  • kilo.json
  • pmoves/Makefile
  • pmoves/config/agent_registry.yaml
  • pmoves/config/mcp_inventory.json
  • pmoves/config/profiles/hermes/4090.yaml
  • pmoves/config/profiles/hermes/5090.yaml
  • pmoves/config/profiles/hermes/b850.yaml
  • pmoves/config/profiles/hermes/elder-melchor.yaml
  • pmoves/config/profiles/hermes/kvm4-1.yaml
  • pmoves/config/profiles/hermes/spark.yaml
  • pmoves/config/profiles/hermes/z890.yaml
  • pmoves/configs/claws/opencode-4090.json
  • pmoves/configs/claws/opencode-5090.json
  • pmoves/configs/claws/opencode-kvm2.json
  • pmoves/configs/claws/opencode-kvm4-1.json
  • pmoves/configs/claws/opencode-kvm4-2.json
  • pmoves/configs/claws/opencode-nemoclaw.json
  • pmoves/configs/claws/opencode-nemotron-claw.json
  • pmoves/configs/claws/opencode-spark.json
  • pmoves/configs/claws/scopes/4090.json
  • pmoves/configs/claws/scopes/5090.json
  • pmoves/configs/claws/scopes/kvm2.json
  • pmoves/configs/claws/scopes/kvm4-1.json
  • pmoves/configs/claws/scopes/kvm4-2.json
  • pmoves/configs/claws/scopes/nemoclaw.json
  • pmoves/configs/claws/scopes/nemotron-claw.json
  • pmoves/configs/claws/scopes/spark.json
  • pmoves/configs/claws/scopes/z890.json
  • pmoves/docs/AGENTS/KILOCODE_PERSONA_STYLE_PLAYBOOK.md
  • pmoves/docs/operations/MCP_TOOLKIT.md
  • pmoves/mk/kilo.mk
  • pmoves/mk/mcp-toolkit.mk
  • pmoves/scripts/bootstrap-hermes-crush.sh
  • pmoves/scripts/bootstrap-node.sh
  • pmoves/scripts/mcp-toolkit-bootstrap.sh
  • pmoves/services/evo-controller/app.py
  • pmoves/services/evo-controller/tests/test_chit_signing.py
  • pmoves/tensorzero/config/tensorzero.toml
  • pmoves/tests/test_mcp_config_generator.py
  • pmoves/tools/bootstrap_openclaw_scopes.py
  • pmoves/tools/bootstrap_opencode.py
  • pmoves/tools/crush_configurator.py
  • pmoves/tools/kilo_parity_mcp_check.py
  • pmoves/tools/mcp_config_generator.py
  • skills/README.md

Comment thread .kimi/mcp.json
Comment thread kilo.json
Comment thread pmoves/config/profiles/hermes/kvm4-1.yaml
Comment on lines +32 to +55
"pmoves-supabase": {
"description": "Supabase PostgREST API",
"command": "npx",
"args": [
"-y",
"@supabase/mcp-server-postgrest@0.1.1",
"--apiUrl",
"http://localhost:8000/rest/v1",
"--apiKey",
"${SUPABASE_SERVICE_KEY}",
"--schema",
"public"
]
},
"supabase-db": {
"description": "Supabase Postgres database",
"command": "uvx",
"args": [
"postgres-mcp@0.3.0",
"--access-mode=unrestricted"
],
"env": {
"DATABASE_URI": "${SUPABASE_DB_URI}"
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' "== file list =="
git ls-files 'pmoves/configs/claws/opencode-4090.json' \
            'pmoves/configs/claws/opencode-5090.json' \
            'pmoves/configs/claws/opencode-kvm2.json' \
            'pmoves/configs/claws/opencode-kvm4-1.json'

printf '\n%s\n' "== targeted excerpts =="
for f in \
  pmoves/configs/claws/opencode-4090.json \
  pmoves/configs/claws/opencode-5090.json \
  pmoves/configs/claws/opencode-kvm2.json \
  pmoves/configs/claws/opencode-kvm4-1.json
do
  echo "--- $f ---"
  nl -ba "$f" | sed -n '1,140p'
done

printf '\n%s\n' "== search for related Supabase / DB config patterns =="
rg -n '"pmoves-supabase"|"supabase-db"|"SUPABASE_SERVICE_KEY"|"SUPABASE_DB_URI"|"access-mode=unrestricted"|mcp-server-postgrest|postgres-mcp' pmoves/configs -S

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 453


🏁 Script executed:

#!/bin/bash
set -euo pipefail

for f in \
  pmoves/configs/claws/opencode-4090.json \
  pmoves/configs/claws/opencode-5090.json \
  pmoves/configs/claws/opencode-kvm2.json \
  pmoves/configs/claws/opencode-kvm4-1.json
do
  echo "--- $f ---"
  awk 'NR>=1 && NR<=140 { printf "%4d  %s\n", NR, $0 }' "$f"
  echo
done

echo '== related patterns in pmoves/configs =='
python3 - <<'PY'
from pathlib import Path
import re

patterns = [
    r'"pmoves-supabase"',
    r'"supabase-db"',
    r'SUPABASE_SERVICE_KEY',
    r'SUPABASE_DB_URI',
    r'access-mode=unrestricted',
    r'mcp-server-postgrest',
    r'postgres-mcp',
]
for path in sorted(Path('pmoves/configs').rglob('*')):
    if not path.is_file():
        continue
    try:
        text = path.read_text()
    except Exception:
        continue
    hits = [p for p in patterns if re.search(p, text)]
    if hits:
        print(path)
        for p in hits:
            print('  ', p)
PY

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 17859


Use scoped Supabase credentials and restrict DB access
The shared pmoves-supabase/supabase-db entries pass ${SUPABASE_SERVICE_KEY} on the command line and start postgres-mcp with --access-mode=unrestricted, giving these nodes broad Supabase authority.

Apply the least-privilege change to the matching claw and scope configs as well.

📍 Affects 4 files
  • pmoves/configs/claws/opencode-4090.json#L32-L55 (this comment)
  • pmoves/configs/claws/opencode-5090.json#L72-L95
  • pmoves/configs/claws/opencode-kvm2.json#L32-L55
  • pmoves/configs/claws/opencode-kvm4-1.json#L32-L55
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pmoves/configs/claws/opencode-4090.json` around lines 32 - 55, Apply
least-privilege Supabase configuration to the pmoves-supabase and supabase-db
entries in pmoves/configs/claws/opencode-4090.json lines 32-55,
pmoves/configs/claws/opencode-5090.json lines 72-95,
pmoves/configs/claws/opencode-kvm2.json lines 32-55, and
pmoves/configs/claws/opencode-kvm4-1.json lines 32-55: replace broad shared
credentials with scoped Supabase credentials and change postgres-mcp from
--access-mode=unrestricted to the appropriate restricted access mode, preserving
each entry’s existing connectivity settings.

Comment on lines +32 to +44
"pmoves-supabase": {
"description": "Supabase PostgREST API",
"command": "npx",
"args": [
"-y",
"@supabase/mcp-server-postgrest@0.1.1",
"--apiUrl",
"http://localhost:8000/rest/v1",
"--apiKey",
"${SUPABASE_SERVICE_KEY}",
"--schema",
"public"
]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## file list\n'
git ls-files 'pmoves/configs/claws/**/*.json' 'pmoves/configs/claws/*.json' | sed -n '1,200p'

printf '\n## search for SUPABASE_SERVICE_KEY and mcp-server-postgrest\n'
rg -n 'SUPABASE_SERVICE_KEY|mcp-server-postgrest|apiKey|apiUrl|schema' pmoves/configs -S

printf '\n## inspect one representative config and any shared templates/docs\n'
for f in \
  pmoves/configs/claws/opencode-nemoclaw.json \
  pmoves/configs/claws/scopes/kvm4-2.json \
  pmoves/configs/claws/scopes/nemotron-claw.json \
  pmoves/configs/claws/scopes/spark.json \
  pmoves/configs/claws/scopes/z890.json
do
  echo "\n### $f"
  sed -n '1,180p' "$f"
done

printf '\n## search repo for Supabase auth guidance\n'
rg -n 'Supabase|service key|service_key|environment.*secret|process listings|command.*args|PostgREST' -S .

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 50382


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '1,180p' pmoves/configs/claws/opencode-nemoclaw.json

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2941


🌐 Web query:

@supabase/mcp-server-postgrest apiKey environment variable command line args secret path

💡 Result:

To configure the @supabase/mcp-server-postgrest, you typically pass the apiKey as a command-line argument when setting up the MCP server in your configuration file (such as the Claude Desktop configuration file) [1][2][3]. The standard way to provide this configuration is within the args array of your mcpServers entry [1][3]. The following structure is used: { "mcpServers": { "your-server-name": { "command": "npx", "args": [ "-y", "@supabase/mcp-server-postgrest@latest", "--apiUrl", "https://your-project-ref.supabase.co/rest/v1", "--apiKey", "your-anon-key", "--schema", "public" ] } } } Key details regarding the configuration: - The --apiKey argument is optional and is used for authentication [1][4]. - The --apiUrl argument is required and specifies the base URL of your PostgREST endpoint [1][4]. - The --schema argument is required and defines the Postgres schema to serve (e.g., public) [1][4]. - If you are using the server programmatically, the createPostgrestMcpServer function accepts these parameters as options in an object (apiUrl, apiKey, and schema) [1][4]. There is no native or explicit mention in the documentation of using a specific secret path or environment variable mapping within the command-line args for this package; the standard practice is to pass the value directly via the --apiKey flag as shown above [1][2]. If you need to manage sensitive keys, it is common practice in MCP environments to handle them via your local shell's environment variables if supported by your MCP client, or by using a secure configuration management approach outside of the MCP server's command-line definition [1][3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '## env-style secret handling in pmoves configs\n'
rg -n '"env"\s*:|SUPABASE_SERVICE_KEY|SERVICE_KEY|SECRET' pmoves/configs -S

printf '\n## any other MCP server configs that keep secrets out of args\n'
rg -n 'mcp-server|command|args|env' pmoves/configs -g '*.json' -S | sed -n '1,220p'

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 23645


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## files containing the Supabase service key in MCP args"
rg -l '"--apiKey",\s*"\$\{SUPABASE_SERVICE_KEY\}"' pmoves/configs/claws -g '*.json' | sort

echo
echo "## exact occurrences count"
rg -n '"--apiKey",\s*"\$\{SUPABASE_SERVICE_KEY\}"' pmoves/configs/claws -g '*.json' | wc -l

echo
echo "## any generator/template references"
rg -n 'opencode-nemoclaw|nemotron-claw|kvm4-2|spark|z890|SUPABASE_SERVICE_KEY' pmoves -g '*.json' -g '*.md' -g '*.yml' -g '*.yaml' | sed -n '1,200p'

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 218


Keep the Supabase service key out of args.
--apiKey ${SUPABASE_SERVICE_KEY} expands into the spawned argv, exposing the credential via process listings and telemetry. Move this MCP launch to a secret-injection path that keeps the key out of CLI args, then regenerate the mirrored claw configs.

  • pmoves/configs/claws/opencode-nemoclaw.json#L32-L44
  • pmoves/configs/claws/scopes/kvm4-2.json#L73-L85
  • pmoves/configs/claws/scopes/nemotron-claw.json#L88-L100
  • pmoves/configs/claws/scopes/spark.json#L73-L85
  • pmoves/configs/claws/scopes/z890.json#L114-L126
📍 Affects 5 files
  • pmoves/configs/claws/opencode-nemoclaw.json#L32-L44 (this comment)
  • pmoves/configs/claws/scopes/kvm4-2.json#L73-L85
  • pmoves/configs/claws/scopes/nemotron-claw.json#L88-L100
  • pmoves/configs/claws/scopes/spark.json#L73-L85
  • pmoves/configs/claws/scopes/z890.json#L114-L126
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pmoves/configs/claws/opencode-nemoclaw.json` around lines 32 - 44, Remove the
Supabase service key from the CLI args for the pmoves-supabase MCP configuration
and use the project’s secret-injection mechanism instead, while preserving the
existing endpoint and schema settings. Apply the same change in
pmoves/configs/claws/opencode-nemoclaw.json#L32-L44,
pmoves/configs/claws/scopes/kvm4-2.json#L73-L85,
pmoves/configs/claws/scopes/nemotron-claw.json#L88-L100,
pmoves/configs/claws/scopes/spark.json#L73-L85, and
pmoves/configs/claws/scopes/z890.json#L114-L126, then regenerate the mirrored
claw configurations.

Comment on lines +15 to +31
inventory = json.loads(inventory_path.read_text(encoding="utf-8"))
kilo = json.loads(kilo_path.read_text(encoding="utf-8"))
kilo_keys = set(kilo.get("mcp", {}).keys())

expected: set[str] = set()
for group in inventory.get("groups", {}).values():
for srv in group.get("servers", []):
clients = srv.get("clients")
if clients is None or "kilocode" in clients:
expected.add(srv["key"])

missing = sorted(expected - kilo_keys)
for key in missing:
print(f" ❌ kilo.json missing MCP: {key}", file=sys.stderr)
if not missing:
print(" ✅ kilo.json contains all canonical MCP servers", file=sys.stderr)
return len(missing)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Compare rendered MCP definitions, not only missing keys.

The check passes stale URLs, headers, commands, permissions, and unexpected obsolete MCP entries. Generate the canonical KiloCode fragment and compare the owned mcp and permission entries structurally.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pmoves/tools/kilo_parity_mcp_check.py` around lines 15 - 31, The parity check
currently compares only MCP keys; update its main validation flow to generate
the canonical KiloCode fragment from the inventory and structurally compare the
owned mcp definitions and permission entries, including URLs, headers, commands,
and permissions. Detect and report stale values and unexpected obsolete entries,
while preserving the existing client filtering and nonzero failure behavior.

Comment thread pmoves/tools/mcp_config_generator.py Outdated
Comment on lines +227 to +229
mcp[spec.key] = entry
permissions[f"{spec.key}_*"] = "allow"
return {"mcp": mcp, "permission": permissions}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## File outline\n'
ast-grep outline pmoves/tools/mcp_config_generator.py --view expanded || true

printf '\n## Relevant slices\n'
sed -n '1,320p' pmoves/tools/mcp_config_generator.py

printf '\n## Search for generated permission usage and privileged specs\n'
rg -n "permission|permissions|mcp_config_generator|spec.key|Tailscale|Supabase|MCP" pmoves -S

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 50381


🏁 Script executed:

#!/bin/bash
set -euo pipefail

nl -ba pmoves/tools/mcp_config_generator.py | sed -n '1,320p'

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 201


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "tailscale|supabase|mcp" pmoves -S --glob '!**/.git/**' | sed -n '1,200p'

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 19023


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '## Outline\n'
ast-grep outline pmoves/tools/mcp_config_generator.py --view expanded || true

printf '\n## File excerpt with line numbers\n'
sed -n '1,280p' pmoves/tools/mcp_config_generator.py | cat -n

printf '\n## Permission and spec references\n'
rg -n "permissions|permission|MCP_SPECS|tailscale|supabase-db|required_env|required_commands|required_envs" pmoves/tools/mcp_config_generator.py -n -S

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 14918


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '## Inventory outline\n'
ast-grep outline pmoves/config/mcp_inventory.json --view expanded || true

printf '\n## Inventory entries mentioning tailscale/supabase/privileged servers\n'
python3 - <<'PY'
import json
from pathlib import Path

path = Path("pmoves/config/mcp_inventory.json")
data = json.loads(path.read_text())
for group_name, group in data.get("groups", {}).items():
    for server in group.get("servers", []):
        key = server.get("key", "")
        text = json.dumps(server, sort_keys=True)
        if any(name in text.lower() for name in ("tailscale", "supabase", "hostinger", "docker", "nats")):
            print(f"[{group_name}] {key}")
            print(json.dumps(server, indent=2, sort_keys=True))
            print()
PY

printf '\n## Client restrictions in inventory\n'
python3 - <<'PY'
import json
from pathlib import Path

data = json.loads(Path("pmoves/config/mcp_inventory.json").read_text())
clients = {}
for group in data.get("groups", {}).values():
    for server in group.get("servers", []):
        if "clients" in server:
            clients[server["key"]] = server["clients"]
for k, v in sorted(clients.items()):
    print(k, "->", v)
PY

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2565


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import json
from pathlib import Path

data = json.loads(Path("pmoves/config/mcp_inventory.json").read_text())
for group_name, group in data.get("groups", {}).items():
    for server in group.get("servers", []):
        key = server.get("key", "")
        blob = json.dumps(server, sort_keys=True).lower()
        if any(name in blob for name in ("tailscale", "supabase", "hostinger", "docker", "nats")):
            print(f"[{group_name}] {key}")
            print(json.dumps(server, indent=2, sort_keys=True))
            print()
PY

python3 - <<'PY'
import json
from pathlib import Path

data = json.loads(Path("pmoves/config/mcp_inventory.json").read_text())
for group in data.get("groups", {}).values():
    for server in group.get("servers", []):
        if "clients" in server:
            print(server["key"], "->", server["clients"])
PY

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2389


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '320,390p' pmoves/tools/mcp_config_generator.py | cat -n

printf '\n## Renderer registration and client generation references\n'
rg -n "render_kilocode|generate_for_client|_collect_servers|clients" pmoves/tools/mcp_config_generator.py -n -S

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 4130


Avoid wildcard-allowing every rendered MCP server. render_kilocode() assigns *_ permissions to every included server, so privileged MCPs like tailscale and supabase-db end up allowed by default. Require explicit per-server opt-in or narrower permissions for sensitive tools.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pmoves/tools/mcp_config_generator.py` around lines 227 - 229, Update
render_kilocode() so it does not automatically assign wildcard permissions to
every rendered MCP server. Require explicit per-server opt-in or use narrower
permissions for sensitive servers such as tailscale and supabase-db, while
preserving rendering of the MCP entries and existing permissions for
non-sensitive servers.

Comment on lines +366 to +375
if client == "hermes":
# Hermes is YAML; return the rendered snippet and let the bootstrap
# script merge it surgically. We do not overwrite the whole YAML file.
output_path.parent.mkdir(parents=True, exist_ok=True)
output_path.write_text(
f"# PMOVES MCP servers (auto-generated by mcp_config_generator.py)\n"
f"# Merge this into your Hermes config.yaml under the top-level `mcp_servers:` key.\n"
+ json.dumps(rendered, indent=2),
encoding="utf-8",
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🔴 Critical | 🏗️ Heavy lift

Do not overwrite the complete Hermes profile with an MCP fragment.

--client hermes targets the real config.yaml, but this branch ignores merge and replaces every unrelated Hermes setting. Merge mcp_servers through a YAML parser or require a separate fragment output path.

🧰 Tools
🪛 ast-grep (0.44.1)

[info] 372-372: use jsonify instead of json.dumps for JSON output
Context: json.dumps(rendered, indent=2)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pmoves/tools/mcp_config_generator.py` around lines 366 - 375, Update the
hermes branch of the MCP configuration generation flow to avoid writing the
rendered fragment over the real Hermes config.yaml. Use the existing merge
behavior to parse and preserve unrelated YAML settings while updating only the
top-level mcp_servers key, or require and write to a distinct fragment output
path; do not ignore merge in this branch.

Comment on lines +452 to +458
for client in clients:
output = args.output
if output is None:
if args.client == "all" and args.output_dir:
output = args.output_dir / f"mcp.{client}.json"
else:
output = DEFAULT_OUTPUTS[client]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject --client all with a single --output path.

All clients currently write to the same file sequentially, leaving only the final client’s incompatible configuration. Require --output-dir for all, or derive distinct filenames.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pmoves/tools/mcp_config_generator.py` around lines 452 - 458, Update the
client-output selection logic in the loop over clients to reject the combination
of args.client == "all" and a single args.output path before generating files.
Require args.output_dir for all-client generation, or otherwise assign a
distinct output filename per client; preserve the existing single-client output
behavior.

Agent Zero and others added 6 commits July 15, 2026 05:37
…tstrap

- Add pmoves/config/mcp_inventory.json as single source of truth
- Add pmoves/tools/mcp_config_generator.py to render client-native configs
- Wire MCP bootstrap into pmoves/scripts/bootstrap-node.sh and Makefile
- Add hermes-crush bootstrap script and make targets
- Update Claude, Kimi, KiloCode, Hermes, Crush, and OpenCode configs
- Add pytest suite for the generator
- Add kilo parity check tooling
- Docs updated in MCP_TOOLKIT.md
- Extend mcp_inventory.json with endpoint_prefix so fleet/local URLs resolve cleanly
- Fix mcp_config_generator.py endpoint lookup to honor caller endpoint preference
- Add pmoves/tools/bootstrap_openclaw_scopes.py with full/edge tier policy
- Update all 8 pmoves/configs/claws/scopes/*.json configs
  - full nodes (4090, 5090, z890, kvm4-1, kvm4-2, nemotron-claw): full PMOVES MCP set
  - edge nodes (nemoclaw, kvm2): cipher + agent-zero + tailscale
  - preserve scope-specific MCPs (gpu-mesh, docker, zai-*, etc.)
- Add openclaw-scope-bootstrap and openclaw-scope-check make targets
- Extend test_mcp_config_generator.py with endpoint + scope tests (17 passing)
KVMs act as Tailscale exit nodes and connect to GPU-bearing nodes, so
every KVM gets the full PMOVES MCP set per operator clarification.

- Move kvm2 from edge to full tier in bootstrap_openclaw_scopes.py
- Regenerate pmoves/configs/claws/scopes/kvm2.json with full PMOVES MCP set
…pers

Replaces direct os.getenv calls with get_secret so Docker *_FILE
secrets are supported. Adds test for CHIT_PASSPHRASE_FILE.
1. mcp_config_generator.py: remove os.environ fallback in _expand() (CR P1)
   — secrets from shell env were leaking into tracked config files
2. bootstrap-hermes-crush.sh: add export PYTHONPATH (CR P2)
   — python3 -m pmoves.tools.* failed without repo root on path
3. .kimi/mcp.json + kilo.json: SUPABASE_SERVICE_KEY -> canonical
   SUPABASE_SERVICE_ROLE_KEY with fallback (Codex P2)
4. kilo.json: supabase-db access-mode unrestricted -> schema + permission
   allow -> ask (CR Major — auto-approving all DDL/DML)
5. mcp_config_generator.py: add extra field to ServerSpec + pass-through
   in render_hermes so auth_token/tools fields survive regeneration (CR Major)
6. All 16 opencode + scope configs: access-mode=unrestricted -> schema
   across fleet (CR Major — restricted DB access everywhere)
@github-actions github-actions Bot added chit-aware Touches a CHIT-aware service — control-body signature gate applies docs Documentation services Service source under pmoves/services/ config pmoves/config(s)/ changes labels Jul 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔏 CHIT-aware change — control-body routing

This PR touches a CHIT-aware service (ports 8086/8087/8103/8106/8113/9224 surface). Before a Control-Body ACK:

  • the diff (or PR body) should reference a CHIT signature trail — chit.signed.v1, a CHIT: trailer, or a make -C pmoves sign-trail entry;
  • the chit-pr-audit-agent (.claude/agents/chit-pr-audit-agent.md) is the gate that grants/refuses ACK eligibility;
  • signing quickstart: pmoves/docs/AGENTS/CHIT_SIGNING_TUTORIAL.md.

Advisory routing only — the blocking contract check is CHIT Contract.

@POWERFULMOVES
POWERFULMOVES force-pushed the fix/evo-controller-chit-secrets branch from 909fcdd to 4a7c842 Compare July 15, 2026 09:38
@POWERFULMOVES
POWERFULMOVES enabled auto-merge (squash) July 15, 2026 09:39
POWERFULMOVES pushed a commit that referenced this pull request Jul 15, 2026
… fallback

1. DEFAULT_OUTPUTS: add opencode entry (was missing — KeyError on --client all)
2. bootstrap-hermes-crush.sh: add export PYTHONPATH for python3 -m pmoves.tools.*
3. .kimi/mcp.json: SUPABASE_SERVICE_KEY -> canonical with fallback
   (same fixes as PR #2124, applied to this branch)
@POWERFULMOVES

Copy link
Copy Markdown
Owner Author

Closing in favor of #2126 — this PR is a strict subset (43 of 46 files are identical, plus #2126 adds 6 more). The evo-controller CHIT_PASSPHRASE fix is present in both branches identically. All 12 review threads apply equally to #2126 and will be addressed there. The test_chit_signing.py file will be cherry-picked if missing.

auto-merge was automatically disabled July 15, 2026 13:15

Pull request was closed

@POWERFULMOVES
POWERFULMOVES deleted the fix/evo-controller-chit-secrets branch July 15, 2026 13:15
POWERFULMOVES pushed a commit that referenced this pull request Jul 15, 2026
… fallback

1. DEFAULT_OUTPUTS: add opencode entry (was missing — KeyError on --client all)
2. bootstrap-hermes-crush.sh: add export PYTHONPATH for python3 -m pmoves.tools.*
3. .kimi/mcp.json: SUPABASE_SERVICE_KEY -> canonical with fallback
   (same fixes as PR #2124, applied to this branch)
POWERFULMOVES added a commit that referenced this pull request Jul 15, 2026
…node matrix (#2126)

* feat(mcp): canonical MCP inventory + generator + full agent-stack bootstrap

- Add pmoves/config/mcp_inventory.json as single source of truth
- Add pmoves/tools/mcp_config_generator.py to render client-native configs
- Wire MCP bootstrap into pmoves/scripts/bootstrap-node.sh and Makefile
- Add hermes-crush bootstrap script and make targets
- Update Claude, Kimi, KiloCode, Hermes, Crush, and OpenCode configs
- Add pytest suite for the generator
- Add kilo parity check tooling
- Docs updated in MCP_TOOLKIT.md

* feat(mcp): bootstrap canonical PMOVES MCPs into OpenClaw scopes

- Extend mcp_inventory.json with endpoint_prefix so fleet/local URLs resolve cleanly
- Fix mcp_config_generator.py endpoint lookup to honor caller endpoint preference
- Add pmoves/tools/bootstrap_openclaw_scopes.py with full/edge tier policy
- Update all 8 pmoves/configs/claws/scopes/*.json configs
  - full nodes (4090, 5090, z890, kvm4-1, kvm4-2, nemotron-claw): full PMOVES MCP set
  - edge nodes (nemoclaw, kvm2): cipher + agent-zero + tailscale
  - preserve scope-specific MCPs (gpu-mesh, docker, zai-*, etc.)
- Add openclaw-scope-bootstrap and openclaw-scope-check make targets
- Extend test_mcp_config_generator.py with endpoint + scope tests (17 passing)

* fix(mcp): promote kvm2 OpenClaw scope to full tier

KVMs act as Tailscale exit nodes and connect to GPU-bearing nodes, so
every KVM gets the full PMOVES MCP set per operator clarification.

- Move kvm2 from edge to full tier in bootstrap_openclaw_scopes.py
- Regenerate pmoves/configs/claws/scopes/kvm2.json with full PMOVES MCP set

* feat(spark): add SPARK node to OpenClaw/OpenCode MCP matrix and fix TensorZero TOML duplicates

* fix(mcp): add opencode to DEFAULT_OUTPUTS + PYTHONPATH + Supabase key fallback

1. DEFAULT_OUTPUTS: add opencode entry (was missing — KeyError on --client all)
2. bootstrap-hermes-crush.sh: add export PYTHONPATH for python3 -m pmoves.tools.*
3. .kimi/mcp.json: SUPABASE_SERVICE_KEY -> canonical with fallback
   (same fixes as PR #2124, applied to this branch)

* fix(mcp): preserve secrets in tracked configs + fix Hermes overwrite

Addresses Codex P1, Codex P2, CodeRabbit Critical + Major findings:

P1 (security): mcp_config_generator._expand() now accepts
allow_os_environ flag. Tracked configs (repo-relative claude/kimi/
kilocode/opencode) generate with allow_os_environ=False, preserving
${VAR} placeholders instead of expanding real secret values from
os.environ. Only --set values and local configs (crush/hermes in
~/.config or ~/.hermes) expand from os.environ.

Critical (hermes): --client hermes now writes to a .mcp_snippet.json
sidecar instead of overwriting the real config.yaml. The bootstrap
script merges the snippet into config.yaml surgically via PyYAML.

Major (--client all): --client all with --output is now rejected
(exit 2) with a message requiring --output-dir.

P2 (PYTHONPATH): bootstrap-hermes-crush.sh already exports
PYTHONPATH at line 33 (was added in a prior commit).

Major (bootstrap fail): script now exits 1 on Crush generator failure
or missing PyYAML, instead of silently succeeding.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2

---------

Co-authored-by: Agent Zero <agent.zero@pmoves.ai>
Co-authored-by: Shaela Bello <slbello@uncg.edu>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chit-aware Touches a CHIT-aware service — control-body signature gate applies config pmoves/config(s)/ changes docs Documentation services Service source under pmoves/services/

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants