## Summary
- stabilize the local Mac MCP bootstrap and companion repo resolution
- prefer host KiCad, FreeCAD, and stable OpenSCAD runtimes for local CAD/MCP flows
- add an autonomous next-lots runner that refreshes plan/todo docs from real validations
## Validation
- bash tools/run_autonomous_next_lots.sh run
- bash tools/hw/cad_stack.sh doctor
- .venv/bin/python tools/freecad_mcp_smoke.py --quick --json
- .venv/bin/python tools/openscad_mcp_smoke.py --quick --json
copilot-pull-request-reviewer[bot]
(Migrated from github.com)
reviewed 2026-03-09 05:13:56 +00:00
copilot-pull-request-reviewer[bot]
(Migrated from github.com)
left a comment
Copy Link
Copy Source
Pull request overview
This PR improves local macOS MCP/CAD bootstrap by introducing more robust companion-repo resolution, preferring host CAD runtimes when available, and adding an “autonomous next lots” runner that updates plan/todo docs based on local validations.
Changes:
Switch validate-specs MCP launch to a bash wrapper that auto-selects a suitable Python runtime.
Centralize/standardize mascarade companion repo resolution across multiple MCP/CAD launchers.
Add an autonomous runner that detects “lots” from git status, runs validations, and regenerates plan/todo docs.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 8 comments.
Show a summary per file
File
Description
tools/validate_specs_mcp_smoke.py
Launch validate-specs MCP via new bash wrapper.
tools/run_validate_specs_mcp.sh
New runtime-detecting launcher for validate-specs MCP.
tools/run_knowledge_base_mcp.sh
Resolve companion repo via shared resolver; export MASCARADE_DIR.
tools/run_github_dispatch_mcp.sh
Resolve companion repo via shared resolver; export MASCARADE_DIR.
tools/run_autonomous_next_lots.sh
New wrapper to run the autonomous lots runner.
tools/mcp_smoke_common.py
Improve default mascarade dir resolution logic.
tools/lib/runtime_home.sh
Add kill_life_resolve_mascarade_dir helper for companion repo discovery.
New autogenerated todo document with validation summaries.
docs/MCP_SETUP.md
Update docs to reflect new validate-specs launcher and host-first CAD detection.
You can also share your feedback on Copilot code review. Take the survey.
## Pull request overview
This PR improves local macOS MCP/CAD bootstrap by introducing more robust companion-repo resolution, preferring host CAD runtimes when available, and adding an “autonomous next lots” runner that updates plan/todo docs based on local validations.
**Changes:**
- Switch `validate-specs` MCP launch to a bash wrapper that auto-selects a suitable Python runtime.
- Centralize/standardize `mascarade` companion repo resolution across multiple MCP/CAD launchers.
- Add an autonomous runner that detects “lots” from `git status`, runs validations, and regenerates plan/todo docs.
### Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 8 comments.
<details>
<summary>Show a summary per file</summary>
| File | Description |
| ---- | ----------- |
| tools/validate_specs_mcp_smoke.py | Launch validate-specs MCP via new bash wrapper. |
| tools/run_validate_specs_mcp.sh | New runtime-detecting launcher for validate-specs MCP. |
| tools/run_knowledge_base_mcp.sh | Resolve companion repo via shared resolver; export `MASCARADE_DIR`. |
| tools/run_github_dispatch_mcp.sh | Resolve companion repo via shared resolver; export `MASCARADE_DIR`. |
| tools/run_autonomous_next_lots.sh | New wrapper to run the autonomous lots runner. |
| tools/mcp_smoke_common.py | Improve default `mascarade` dir resolution logic. |
| tools/lib/runtime_home.sh | Add `kill_life_resolve_mascarade_dir` helper for companion repo discovery. |
| tools/hw/run_kicad_mcp.sh | Prefer host KiCad Python bits; resolve companion repo via shared resolver. |
| tools/hw/cad_stack.sh | Prefer host KiCad/FreeCAD/OpenSCAD when available; container fallback remains. |
| tools/bootstrap_mac_mcp.sh | Use shared companion repo resolver; validate-specs now launched via bash wrapper. |
| tools/autonomous_next_lots.py | New autonomous planner/validator that can rewrite plan/todo docs. |
| mcp.json | Update validate-specs MCP command to use bash wrapper. |
| docs/plans/README.md | Add plan 18 entry. |
| docs/plans/18_plan_enchainement_autonome_des_lots_utiles.md | New autogenerated plan document with current run state. |
| docs/plans/18_todo_enchainement_autonome_des_lots_utiles.md | New autogenerated todo document with validation summaries. |
| docs/MCP_SETUP.md | Update docs to reflect new validate-specs launcher and host-first CAD detection. |
</details>
---
You can also share your feedback on Copilot code review. [Take the survey](https://www.surveymonkey.com/r/XP6L3XJ).
This generated plan includes ephemeral local Git state (branch header, dirty path count/list, timestamps). As a tracked doc, this will churn frequently and may not be meaningful to other contributors. Consider keeping the runbook content versioned, but moving per-run state into untracked artifacts (or only writing it when explicitly requested).
This generated plan includes ephemeral local Git state (branch header, dirty path count/list, timestamps). As a tracked doc, this will churn frequently and may not be meaningful to other contributors. Consider keeping the runbook content versioned, but moving per-run state into untracked artifacts (or only writing it when explicitly requested).
This generated TODO file includes user-specific absolute paths in the validation summaries (e.g., /Users/.../Kill_LIFE/...). Committing machine-local paths makes the doc noisy and can leak local environment details. Regenerate with sanitized/relative paths (or avoid embedding raw command output in tracked docs).
output_tail (and the subsequent embedding of command outputs into the generated docs) can capture machine-specific absolute paths and other environment details. This is already visible in the committed docs/plans/18_* artifacts (e.g., /Users/... paths in command summaries), which creates noisy diffs and can unintentionally leak local filesystem layout into the repo. Consider redacting absolute paths (e.g., replace ROOT with . / $REPO), truncating/normalizing outputs more aggressively, and/or not persisting raw validation output into tracked markdown.
def _sanitize_summary_line(line: str) -> str:
"""Redact machine-specific details from a single summary line."""
# Normalize common absolute paths to stable tokens to avoid leaking local layout.
repo_root = str(ROOT)
if repo_root and repo_root in line:
line = line.replace(repo_root, "$REPO")
# Also hide the current user's home directory if present.
home_dir = str(Path.home())
if home_dir and home_dir in line:
line = line.replace(home_dir, "$HOME")
# Truncate very long lines to keep summaries compact and diffs manageable.
max_len = 200
if len(line) > max_len:
line = line[: max_len - 3] + "..."
return line
def output_tail(text: str) -> str:
lines = [line.rstrip() for line in text.splitlines() if line.strip()]
if not lines:
return ""
tail = lines[-3:]
sanitized = [_sanitize_summary_line(line) for line in tail]
return " | ".join(sanitized)
`output_tail` (and the subsequent embedding of command outputs into the generated docs) can capture machine-specific absolute paths and other environment details. This is already visible in the committed `docs/plans/18_*` artifacts (e.g., `/Users/...` paths in command summaries), which creates noisy diffs and can unintentionally leak local filesystem layout into the repo. Consider redacting absolute paths (e.g., replace `ROOT` with `.` / `$REPO`), truncating/normalizing outputs more aggressively, and/or not persisting raw validation output into tracked markdown.
```suggestion
def _sanitize_summary_line(line: str) -> str:
"""Redact machine-specific details from a single summary line."""
# Normalize common absolute paths to stable tokens to avoid leaking local layout.
repo_root = str(ROOT)
if repo_root and repo_root in line:
line = line.replace(repo_root, "$REPO")
# Also hide the current user's home directory if present.
home_dir = str(Path.home())
if home_dir and home_dir in line:
line = line.replace(home_dir, "$HOME")
# Truncate very long lines to keep summaries compact and diffs manageable.
max_len = 200
if len(line) > max_len:
line = line[: max_len - 3] + "..."
return line
def output_tail(text: str) -> str:
lines = [line.rstrip() for line in text.splitlines() if line.strip()]
if not lines:
return ""
tail = lines[-3:]
sanitized = [_sanitize_summary_line(line) for line in tail]
return " | ".join(sanitized)
```
The default status mode rewrites the plan/todo markdown files because should_write is true for any mode except json. This makes simply checking status dirty the working tree (and causes constant timestamp churn). Consider only writing docs in run mode, or gating writes behind an explicit --write flag (keeping status read-only by default).
should_write = not args.no_write and args.mode == "run"
The default `status` mode rewrites the plan/todo markdown files because `should_write` is true for any mode except `json`. This makes simply checking status dirty the working tree (and causes constant timestamp churn). Consider only writing docs in `run` mode, or gating writes behind an explicit `--write` flag (keeping `status` read-only by default).
```suggestion
should_write = not args.no_write and args.mode == "run"
```
kill_life_resolve_mascarade_dir is used in a command-substitution assignment while set -e is active. If resolution fails (e.g., companion repo not present), the script will exit immediately with a non-obvious error and will not reach the explicit Unable to resolve mascarade companion path message. Capture the failure (|| true) and handle it with a clear error message (or wrap the call in ... || { echo ...; exit 1; }).
"finetune/kicad_mcp_server" \
|| true
`kill_life_resolve_mascarade_dir` is used in a command-substitution assignment while `set -e` is active. If resolution fails (e.g., companion repo not present), the script will exit immediately with a non-obvious error and will not reach the explicit `Unable to resolve mascarade companion path` message. Capture the failure (`|| true`) and handle it with a clear error message (or wrap the call in `... || { echo ...; exit 1; }`).
```suggestion
"finetune/kicad_mcp_server" \
|| true
```
MASCARADE_DIR is resolved with kill_life_resolve_mascarade_dir using command substitution while set -e is enabled. If the companion repo isn't present, the launcher will exit at this assignment with a hard-to-diagnose error. Consider making the resolution non-fatal (|| true) and then die with a clear message describing expected ../mascarade / ../mascarade-main layout or MASCARADE_DIR override.
if [ -z "${MASCARADE_DIR:-}" ]; then
RESOLVED_MASCARADE_DIR="$(
kill_life_resolve_mascarade_dir \
"$ROOT_DIR" \
"finetune/kicad_mcp_server" || true
)"
if [ -z "$RESOLVED_MASCARADE_DIR" ]; then
die "Unable to locate mascarade companion repository.
Expected one of:
- \$ROOT_DIR/../mascarade
- \$ROOT_DIR/../mascarade-main
You can also override the location explicitly by setting MASCARADE_DIR."
fi
MASCARADE_DIR="$RESOLVED_MASCARADE_DIR"
fi
`MASCARADE_DIR` is resolved with `kill_life_resolve_mascarade_dir` using command substitution while `set -e` is enabled. If the companion repo isn't present, the launcher will exit at this assignment with a hard-to-diagnose error. Consider making the resolution non-fatal (`|| true`) and then `die` with a clear message describing expected `../mascarade` / `../mascarade-main` layout or `MASCARADE_DIR` override.
```suggestion
if [ -z "${MASCARADE_DIR:-}" ]; then
RESOLVED_MASCARADE_DIR="$(
kill_life_resolve_mascarade_dir \
"$ROOT_DIR" \
"finetune/kicad_mcp_server" || true
)"
if [ -z "$RESOLVED_MASCARADE_DIR" ]; then
die "Unable to locate mascarade companion repository.
Expected one of:
- \$ROOT_DIR/../mascarade
- \$ROOT_DIR/../mascarade-main
You can also override the location explicitly by setting MASCARADE_DIR."
fi
MASCARADE_DIR="$RESOLVED_MASCARADE_DIR"
fi
```
MASCARADE_DIR is resolved via command substitution under set -euo pipefail. If kill_life_resolve_mascarade_dir fails, the script will exit at the assignment without printing a helpful error. Handle the failure explicitly and emit an actionable message (expected repo locations, how to override via MASCARADE_DIR).
if [[ -z "${MASCARADE_DIR:-}" ]]; then
if ! MASCARADE_DIR="$(
kill_life_resolve_mascarade_dir \
"$ROOT_DIR" \
"core/mascarade/integrations/github_dispatch.py"
)"; then
cat >&2 <<EOF
ERROR: Unable to resolve the Mascarade repository directory (MASCARADE_DIR).
The helper 'kill_life_resolve_mascarade_dir' failed while looking for:
core/mascarade/integrations/github_dispatch.py
relative to:
$ROOT_DIR
Make sure the Mascarade repository is checked out in an expected location
(for example as a sibling or subdirectory of this project), or override
autodetection by setting the MASCARADE_DIR environment variable explicitly,
e.g.:
MASCARADE_DIR=/path/to/mascarade \\
"$0" "$@"
EOF
exit 1
fi
fi
`MASCARADE_DIR` is resolved via command substitution under `set -euo pipefail`. If `kill_life_resolve_mascarade_dir` fails, the script will exit at the assignment without printing a helpful error. Handle the failure explicitly and emit an actionable message (expected repo locations, how to override via `MASCARADE_DIR`).
```suggestion
if [[ -z "${MASCARADE_DIR:-}" ]]; then
if ! MASCARADE_DIR="$(
kill_life_resolve_mascarade_dir \
"$ROOT_DIR" \
"core/mascarade/integrations/github_dispatch.py"
)"; then
cat >&2 <<EOF
ERROR: Unable to resolve the Mascarade repository directory (MASCARADE_DIR).
The helper 'kill_life_resolve_mascarade_dir' failed while looking for:
core/mascarade/integrations/github_dispatch.py
relative to:
$ROOT_DIR
Make sure the Mascarade repository is checked out in an expected location
(for example as a sibling or subdirectory of this project), or override
autodetection by setting the MASCARADE_DIR environment variable explicitly,
e.g.:
MASCARADE_DIR=/path/to/mascarade \\
"$0" "$@"
EOF
exit 1
fi
fi
```
MASCARADE_DIR is resolved via command substitution under set -euo pipefail. If kill_life_resolve_mascarade_dir fails, the script will exit at the assignment with no actionable error. Consider handling the failure explicitly (e.g., MASCARADE_DIR="$(... || true)" followed by a check that prints guidance about expected locations / MASCARADE_DIR).
"core/mascarade/integrations/knowledge_base.py" \
|| true
)"
if [[ -z "$MASCARADE_DIR" || ! -d "$MASCARADE_DIR" ]]; then
echo "Failed to resolve MASCARADE_DIR via kill_life_resolve_mascarade_dir." >&2
echo "ROOT_DIR=$ROOT_DIR" >&2
echo "Ensure Mascarade core is available (e.g., at \$ROOT_DIR/core/mascarade) and retry." >&2
exit 1
fi
`MASCARADE_DIR` is resolved via command substitution under `set -euo pipefail`. If `kill_life_resolve_mascarade_dir` fails, the script will exit at the assignment with no actionable error. Consider handling the failure explicitly (e.g., `MASCARADE_DIR="$(... || true)"` followed by a check that prints guidance about expected locations / `MASCARADE_DIR`).
```suggestion
"core/mascarade/integrations/knowledge_base.py" \
|| true
)"
if [[ -z "$MASCARADE_DIR" || ! -d "$MASCARADE_DIR" ]]; then
echo "Failed to resolve MASCARADE_DIR via kill_life_resolve_mascarade_dir." >&2
echo "ROOT_DIR=$ROOT_DIR" >&2
echo "Ensure Mascarade core is available (e.g., at \$ROOT_DIR/core/mascarade) and retry." >&2
exit 1
fi
```
chatgpt-codex-connector[bot]
(Migrated from github.com)
reviewed 2026-03-09 05:14:14 +00:00
chatgpt-codex-connector[bot]
(Migrated from github.com)
left a comment
Copy Link
Copy Source
💡 Codex Review
Here are some automated review suggestions for this pull request.
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".
### 💡 Codex Review
Here are some automated review suggestions for this pull request.
**Reviewed commit:** `caea73e0f8`
<details> <summary>ℹ️ About Codex in GitHub</summary>
<br/>
[Your team has set up Codex to review pull requests in this repo](http://chatgpt.com/codex/settings/general). 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".
</details>
Preserve bootstrap error reporting on missing companion
Because this resolver call is also unguarded under set -e, bootstrap aborts before the explicit fallback check/reporting below can run. When no companion repo is present, bash tools/bootstrap_mac_mcp.sh codex exits silently instead of emitting the expected Unable to resolve mascarade companion path message, making setup failures much harder to triage.
Useful? React with 👍 / 👎.
**<sub><sub></sub></sub> Preserve bootstrap error reporting on missing companion**
Because this resolver call is also unguarded under `set -e`, bootstrap aborts before the explicit fallback check/reporting below can run. When no companion repo is present, `bash tools/bootstrap_mac_mcp.sh codex` exits silently instead of emitting the expected `Unable to resolve mascarade companion path` message, making setup failures much harder to triage.
Useful? React with 👍 / 👎.
This command substitution is executed under set -e, so if no valid mascarade candidate is found the script exits immediately before it can reach the --doctor output path. In environments where the companion repo is absent or renamed, tools/hw/run_kicad_mcp.sh --doctor now fails with exit code 1 and no diagnostics, which breaks the intended troubleshooting flow.
Useful? React with 👍 / 👎.
**<sub><sub></sub></sub> Guard companion resolution before doctor mode**
This command substitution is executed under `set -e`, so if no valid `mascarade` candidate is found the script exits immediately before it can reach the `--doctor` output path. In environments where the companion repo is absent or renamed, `tools/hw/run_kicad_mcp.sh --doctor` now fails with exit code 1 and no diagnostics, which breaks the intended troubleshooting flow.
Useful? React with 👍 / 👎.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Validation
Pull request overview
This PR improves local macOS MCP/CAD bootstrap by introducing more robust companion-repo resolution, preferring host CAD runtimes when available, and adding an “autonomous next lots” runner that updates plan/todo docs based on local validations.
Changes:
validate-specsMCP launch to a bash wrapper that auto-selects a suitable Python runtime.mascaradecompanion repo resolution across multiple MCP/CAD launchers.git status, runs validations, and regenerates plan/todo docs.Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 8 comments.
Show a summary per file
MASCARADE_DIR.MASCARADE_DIR.mascaradedir resolution logic.kill_life_resolve_mascarade_dirhelper for companion repo discovery.You can also share your feedback on Copilot code review. Take the survey.
@@ -0,0 +41,4 @@- `tools/autonomous_next_lots.py`- `tools/run_autonomous_next_lots.sh`- `tools/run_validate_specs_mcp.sh`This generated plan includes ephemeral local Git state (branch header, dirty path count/list, timestamps). As a tracked doc, this will churn frequently and may not be meaningful to other contributors. Consider keeping the runbook content versioned, but moving per-run state into untracked artifacts (or only writing it when explicitly requested).
@@ -0,0 +8,4 @@- done: lot detecte (Stabiliser les launchers MCP, le bootstrap Mac, la resolution du repo compagnon et la doc operateur associee.)- done: `bash tools/bootstrap_mac_mcp.sh codex`resume: codex mcp add openscad --env MASCARADE_DIR=/Users/electron/mascarade-main -- bash /Users/electron/Kill_LIFE/tools/run_openscad_mcp.sh | codex mcp add huggingface --url https://huggingface.co/mcp --bearer-token-env-var HUGGINGFACE_API_KEY | codex mcp add playwright -- npx -y @playwright/mcp@latestThis generated TODO file includes user-specific absolute paths in the validation summaries (e.g.,
/Users/.../Kill_LIFE/...). Committing machine-local paths makes the doc noisy and can leak local environment details. Regenerate with sanitized/relative paths (or avoid embedding raw command output in tracked docs).@@ -0,0 +215,4 @@lines = [line.rstrip() for line in text.splitlines() if line.strip()]if not lines:return ""return " | ".join(lines[-3:])output_tail(and the subsequent embedding of command outputs into the generated docs) can capture machine-specific absolute paths and other environment details. This is already visible in the committeddocs/plans/18_*artifacts (e.g.,/Users/...paths in command summaries), which creates noisy diffs and can unintentionally leak local filesystem layout into the repo. Consider redacting absolute paths (e.g., replaceROOTwith./$REPO), truncating/normalizing outputs more aggressively, and/or not persisting raw validation output into tracked markdown.@@ -0,0 +410,4 @@plan_text = render_plan(branch, dirty_paths, ahead, behind, lots, results)todo_text = render_todo(lots, results)should_write = not args.no_write and args.mode != "json"The default
statusmode rewrites the plan/todo markdown files becauseshould_writeis true for any mode exceptjson. This makes simply checking status dirty the working tree (and causes constant timestamp churn). Consider only writing docs inrunmode, or gating writes behind an explicit--writeflag (keepingstatusread-only by default).kill_life_resolve_mascarade_diris used in a command-substitution assignment whileset -eis active. If resolution fails (e.g., companion repo not present), the script will exit immediately with a non-obvious error and will not reach the explicitUnable to resolve mascarade companion pathmessage. Capture the failure (|| true) and handle it with a clear error message (or wrap the call in... || { echo ...; exit 1; }).MASCARADE_DIRis resolved withkill_life_resolve_mascarade_dirusing command substitution whileset -eis enabled. If the companion repo isn't present, the launcher will exit at this assignment with a hard-to-diagnose error. Consider making the resolution non-fatal (|| true) and thendiewith a clear message describing expected../mascarade/../mascarade-mainlayout orMASCARADE_DIRoverride.@@ -10,1 +11,4 @@"core/mascarade/integrations/github_dispatch.py")"MASCARADE_ENV_FILE="${MASCARADE_ENV_FILE:-$MASCARADE_DIR/.env}"MASCARADE_DIRis resolved via command substitution underset -euo pipefail. Ifkill_life_resolve_mascarade_dirfails, the script will exit at the assignment without printing a helpful error. Handle the failure explicitly and emit an actionable message (expected repo locations, how to override viaMASCARADE_DIR).@@ -10,1 +11,4 @@"core/mascarade/integrations/knowledge_base.py")"MASCARADE_ENV_FILE="${MASCARADE_ENV_FILE:-$MASCARADE_DIR/.env}"MASCARADE_DIRis resolved via command substitution underset -euo pipefail. Ifkill_life_resolve_mascarade_dirfails, the script will exit at the assignment with no actionable error. Consider handling the failure explicitly (e.g.,MASCARADE_DIR="$(... || true)"followed by a check that prints guidance about expected locations /MASCARADE_DIR).💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
caea73e0f8ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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".
Because this resolver call is also unguarded under
set -e, bootstrap aborts before the explicit fallback check/reporting below can run. When no companion repo is present,bash tools/bootstrap_mac_mcp.sh codexexits silently instead of emitting the expectedUnable to resolve mascarade companion pathmessage, making setup failures much harder to triage.Useful? React with 👍 / 👎.
This command substitution is executed under
set -e, so if no validmascaradecandidate is found the script exits immediately before it can reach the--doctoroutput path. In environments where the companion repo is absent or renamed,tools/hw/run_kicad_mcp.sh --doctornow fails with exit code 1 and no diagnostics, which breaks the intended troubleshooting flow.Useful? React with 👍 / 👎.