add zeroclaw dual-repo orchestration toolkit
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
name: ZeroClaw Dual Orchestrator
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "tools/ai/zeroclaw_dual_*.sh"
|
||||
- "specs/zeroclaw_dual_hw_*.md"
|
||||
- ".github/workflows/zeroclaw_dual_orchestrator.yml"
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "tools/ai/zeroclaw_dual_*.sh"
|
||||
- "specs/zeroclaw_dual_hw_*.md"
|
||||
- ".github/workflows/zeroclaw_dual_orchestrator.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: zeroclaw-dual-orchestrator-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint-and-contract:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install shellcheck
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y shellcheck
|
||||
|
||||
- name: Shellcheck orchestrator scripts
|
||||
run: |
|
||||
shellcheck tools/ai/zeroclaw_dual_bootstrap.sh
|
||||
shellcheck tools/ai/zeroclaw_dual_chat.sh
|
||||
|
||||
- name: Verify spec files
|
||||
run: |
|
||||
test -s specs/zeroclaw_dual_hw_orchestration_spec.md
|
||||
test -s specs/zeroclaw_dual_hw_todo.md
|
||||
@@ -1,5 +1,6 @@
|
||||
.venv
|
||||
# Fichiers et dossiers à ignorer pour Kill_LIFE
|
||||
zeroclaw/
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
|
||||
@@ -9,3 +9,8 @@ Flux conseillé (itératif) :
|
||||
6) Implémentation (firmware/hardware) + tests + doc
|
||||
|
||||
Le fichier `constraints.yaml` est la **source de vérité** des contraintes non-fonctionnelles et règles repo.
|
||||
|
||||
Specs complémentaires:
|
||||
|
||||
- `zeroclaw_dual_hw_orchestration_spec.md`: architecture d'orchestration ZeroClaw multi-repo + double matériel.
|
||||
- `zeroclaw_dual_hw_todo.md`: backlog opérationnel court terme pour autonomie contrôlée.
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
# Spec: ZeroClaw Dual-Repo + Dual-Hardware Orchestration
|
||||
|
||||
Last updated: 2026-02-21
|
||||
|
||||
## 1) Goal
|
||||
|
||||
Run one orchestration layer that can:
|
||||
|
||||
- converse against `RTC_BL_PHONE` and `le-mystere-professeur-zacus` independently,
|
||||
- keep workspace boundaries strict per repo,
|
||||
- run low-cost autonomous loops with guarded command allowlists,
|
||||
- stay ready for connected hardware checks before any upload/flash action.
|
||||
|
||||
## 2) Scope
|
||||
|
||||
In scope:
|
||||
|
||||
- local ZeroClaw profile bootstrap for both repos,
|
||||
- deterministic workspace switch (`rtc` vs `zacus`) from one CLI entrypoint,
|
||||
- hardware discovery/introspection preflight,
|
||||
- lightweight CI validation for orchestration scripts/spec.
|
||||
|
||||
Out of scope:
|
||||
|
||||
- storing provider secrets in git,
|
||||
- hard-coding serial ports in committed config,
|
||||
- forcing hardware jobs on GitHub-hosted runners.
|
||||
|
||||
## 3) Current Hardware Snapshot (local)
|
||||
|
||||
Detected at bootstrap time:
|
||||
|
||||
- `CP2102 USB to UART Bridge Controller` (`10c4:ea60`)
|
||||
- `USB Single Serial` (`1a86:55d3`)
|
||||
|
||||
Known candidate ports:
|
||||
|
||||
- `/dev/tty.SLAB_USBtoUART`
|
||||
- `/dev/tty.usbserial-0001`
|
||||
- `/dev/tty.usbmodem5AB90753301`
|
||||
|
||||
## 4) Architecture
|
||||
|
||||
### 4.1 Repo-local ZeroClaw profile
|
||||
|
||||
Each repo gets:
|
||||
|
||||
- `<repo>/.zeroclaw/config.toml`
|
||||
|
||||
Runtime workspace selection is done via:
|
||||
|
||||
- `ZEROCLAW_WORKSPACE=<repo>`
|
||||
|
||||
This keeps `autonomy.workspace_only = true` effective on a per-repo boundary.
|
||||
|
||||
### 4.2 Orchestrator scripts
|
||||
|
||||
- `tools/ai/zeroclaw_dual_bootstrap.sh`
|
||||
- writes/refreshes both repo profiles,
|
||||
- archives legacy root `config.toml` + `workspace/` if they match old ZeroClaw layout,
|
||||
- validates ZeroClaw binary availability,
|
||||
- runs `zeroclaw status` for both workspaces,
|
||||
- runs `zeroclaw hardware discover`.
|
||||
- `tools/ai/zeroclaw_dual_chat.sh`
|
||||
- target switch by alias (`rtc`, `zacus`) or absolute path,
|
||||
- message mode (`-m`) or interactive mode,
|
||||
- provider auto-fallback (`copilot` -> `openai-codex` -> `openrouter`),
|
||||
- token sourcing from `gh auth token` at runtime only when `copilot` is selected.
|
||||
|
||||
### 4.3 Provider/cost strategy
|
||||
|
||||
Auto provider selection order in `zeroclaw_dual_chat.sh`:
|
||||
|
||||
1. explicit `ZEROCLAW_PROVIDER` override,
|
||||
2. `copilot` when `gh` auth is valid and Copilot billing endpoint is accessible,
|
||||
3. `openai-codex` when a ZeroClaw auth profile exists,
|
||||
4. `openrouter` when `OPENROUTER_API_KEY` is present.
|
||||
|
||||
Observed on current machine:
|
||||
|
||||
- GitHub API returned `404` for Copilot billing endpoint (no active Copilot subscription on this token), so fallback path is required for autonomous chat.
|
||||
|
||||
## 5) Operations Loop
|
||||
|
||||
1. Bootstrap configs and hardware probe.
|
||||
2. Run one focused prompt in `rtc`.
|
||||
3. Run one focused prompt in `zacus`.
|
||||
4. Apply patches/tests per repo.
|
||||
5. Open small PRs + issue links (one concern per PR).
|
||||
6. Repeat.
|
||||
|
||||
## 6) CI Workflow
|
||||
|
||||
Workflow:
|
||||
|
||||
- `.github/workflows/zeroclaw_dual_orchestrator.yml`
|
||||
|
||||
Behavior:
|
||||
|
||||
- path-filtered on orchestration scripts/spec files,
|
||||
- shellcheck scripts,
|
||||
- verify spec/todo files exist,
|
||||
- concurrency enabled to cancel stale runs on same ref.
|
||||
|
||||
## 7) External References (optimization decisions)
|
||||
|
||||
- GitHub Actions path filters and trigger controls:
|
||||
https://docs.github.com/actions/reference/workflows-and-actions/workflow-syntax
|
||||
- GitHub Actions concurrency control (cancel stale runs):
|
||||
https://docs.github.com/actions/using-jobs/using-concurrency
|
||||
- PlatformIO remote unit test runner and local/remote split strategy:
|
||||
https://docs.platformio.org/en/latest/plus/remote/unit-testing.html
|
||||
- PySerial port metadata usage (`serial.tools.list_ports`) for stable device targeting:
|
||||
https://pyserial.readthedocs.io/en/latest/tools.html
|
||||
@@ -0,0 +1,36 @@
|
||||
# TODO: Dual Hardware Autonomy (RTC + Zacus)
|
||||
|
||||
Last updated: 2026-02-21
|
||||
|
||||
## Phase A: Local Baseline
|
||||
|
||||
- [ ] Run `tools/ai/zeroclaw_dual_bootstrap.sh` and capture hardware snapshot.
|
||||
- [ ] Validate `tools/ai/zeroclaw_dual_chat.sh rtc -m "<diagnostic prompt>"`.
|
||||
- [ ] Validate `tools/ai/zeroclaw_dual_chat.sh zacus -m "<diagnostic prompt>"`.
|
||||
- [ ] Record detected ports and map preferred role per board.
|
||||
|
||||
## Phase B: Repo Specs and PR Cadence
|
||||
|
||||
- [ ] Create/refresh one issue in `RTC_BL_PHONE` for ZeroClaw-assisted hardware loop.
|
||||
- [ ] Create/refresh one issue in `le-mystere-professeur-zacus` for ZeroClaw-assisted hardware loop.
|
||||
- [ ] Open one small PR per repo focused on one gate (build, tests, hardware smoke, docs).
|
||||
- [ ] Require code review pass before merge (`gh pr review --approve` only after checks).
|
||||
|
||||
## Phase C: Autonomy + Cost Optimization
|
||||
|
||||
- [ ] Keep prompts short, target one repo at a time.
|
||||
- [ ] Use provider auto-fallback (`copilot` -> `openai-codex` -> `openrouter`) to avoid dead sessions.
|
||||
- [ ] Add repo-level path filters in workflows to avoid expensive irrelevant runs.
|
||||
- [ ] Use `workflow_dispatch` for hardware-required jobs to avoid noisy CI failures.
|
||||
|
||||
## Phase D: Hardware Robustness
|
||||
|
||||
- [ ] Add serial-port resolver step before every upload/flash action.
|
||||
- [ ] Fail fast if no expected USB device is detected.
|
||||
- [ ] Archive logs per run for replayability (`artifacts/<timestamp>/...`).
|
||||
|
||||
## Exit Criteria
|
||||
|
||||
- [ ] Both repos can be targeted with one command (`rtc` or `zacus`) without workspace leakage.
|
||||
- [ ] Hardware discovery passes before action on connected boards.
|
||||
- [ ] At least one successful PR cycle completed per repo with this orchestration path.
|
||||
Executable
+98
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ZEROCLAW_BIN="${ZEROCLAW_BIN:-/Users/cils/Documents/Lelectron_rare/Kill_LIFE/zeroclaw/target/release/zeroclaw}"
|
||||
RTC_REPO="/Users/cils/Documents/Lelectron_rare/RTC_BL_PHONE"
|
||||
ZACUS_REPO="/Users/cils/Documents/Lelectron_rare/le-mystere-professeur-zacus"
|
||||
HARDWARE_ONLY=0
|
||||
|
||||
usage() {
|
||||
cat <<USAGE
|
||||
Usage: $(basename "$0") [--rtc <path>] [--zacus <path>] [--zeroclaw-bin <path>] [--hardware-only]
|
||||
|
||||
Bootstrap local ZeroClaw workspace profiles for both repos and run hardware discovery.
|
||||
USAGE
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--rtc)
|
||||
RTC_REPO="${2:-}"; shift 2 ;;
|
||||
--zacus)
|
||||
ZACUS_REPO="${2:-}"; shift 2 ;;
|
||||
--zeroclaw-bin)
|
||||
ZEROCLAW_BIN="${2:-}"; shift 2 ;;
|
||||
--hardware-only)
|
||||
HARDWARE_ONLY=1; shift ;;
|
||||
-h|--help)
|
||||
usage; exit 0 ;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
usage
|
||||
exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ ! -x "$ZEROCLAW_BIN" ]]; then
|
||||
if command -v zeroclaw >/dev/null 2>&1; then
|
||||
ZEROCLAW_BIN="$(command -v zeroclaw)"
|
||||
else
|
||||
echo "zeroclaw binary not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$HARDWARE_ONLY" == "1" ]]; then
|
||||
"$ZEROCLAW_BIN" hardware discover
|
||||
exit 0
|
||||
fi
|
||||
|
||||
write_repo_config() {
|
||||
local repo="$1"
|
||||
mkdir -p "$repo/.zeroclaw"
|
||||
mkdir -p "$repo/.zeroclaw/legacy"
|
||||
|
||||
# If a previous run created a root ZeroClaw profile, archive it so
|
||||
# ZEROCLAW_WORKSPACE resolves to repo-local .zeroclaw/config.toml.
|
||||
if [[ -f "$repo/config.toml" ]] && rg -q '^default_provider =|^\[autonomy\]' "$repo/config.toml"; then
|
||||
mv "$repo/config.toml" "$repo/.zeroclaw/legacy/config.root.auto.toml"
|
||||
fi
|
||||
if [[ -d "$repo/workspace" && -d "$repo/workspace/memory" && -d "$repo/workspace/state" ]]; then
|
||||
mv "$repo/workspace" "$repo/.zeroclaw/legacy/workspace.root.auto"
|
||||
fi
|
||||
|
||||
cat > "$repo/.zeroclaw/config.toml" <<'TOML'
|
||||
default_provider = "openai-codex"
|
||||
default_temperature = 0.2
|
||||
|
||||
[memory]
|
||||
backend = "sqlite"
|
||||
auto_save = true
|
||||
embedding_provider = "none"
|
||||
|
||||
[autonomy]
|
||||
level = "supervised"
|
||||
workspace_only = true
|
||||
allowed_commands = ["git", "gh", "ls", "cat", "rg", "sed", "awk", "find", "make", "python3", "bash", "sh", "pio"]
|
||||
forbidden_paths = ["/etc", "/root", "/home", "/usr", "/bin", "/sbin", "/lib", "/opt", "/boot", "/dev", "/proc", "/sys", "/var", "/tmp", "~/.ssh", "~/.gnupg", "~/.aws", "~/.config"]
|
||||
max_actions_per_hour = 40
|
||||
max_cost_per_day_cents = 150
|
||||
require_approval_for_medium_risk = true
|
||||
block_high_risk_commands = true
|
||||
TOML
|
||||
}
|
||||
|
||||
write_repo_config "$RTC_REPO"
|
||||
write_repo_config "$ZACUS_REPO"
|
||||
|
||||
ZEROCLAW_WORKSPACE="$RTC_REPO" "$ZEROCLAW_BIN" status >/dev/null
|
||||
ZEROCLAW_WORKSPACE="$ZACUS_REPO" "$ZEROCLAW_BIN" status >/dev/null
|
||||
|
||||
"$ZEROCLAW_BIN" hardware discover
|
||||
echo "Bootstrap complete."
|
||||
echo "- RTC workspace: $RTC_REPO"
|
||||
echo "- Zacus workspace: $ZACUS_REPO"
|
||||
echo "Provider strategy:"
|
||||
echo "1) export ZEROCLAW_PROVIDER=copilot (requires GitHub Copilot subscription)"
|
||||
echo "2) zeroclaw auth login --provider openai-codex --device-code"
|
||||
echo "3) export OPENROUTER_API_KEY=... and use ZEROCLAW_PROVIDER=openrouter"
|
||||
Executable
+99
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ZEROCLAW_BIN="${ZEROCLAW_BIN:-/Users/cils/Documents/Lelectron_rare/Kill_LIFE/zeroclaw/target/release/zeroclaw}"
|
||||
RTC_REPO="/Users/cils/Documents/Lelectron_rare/RTC_BL_PHONE"
|
||||
ZACUS_REPO="/Users/cils/Documents/Lelectron_rare/le-mystere-professeur-zacus"
|
||||
|
||||
usage() {
|
||||
cat <<USAGE
|
||||
Usage:
|
||||
$(basename "$0") <rtc|zacus|path> -m "message"
|
||||
$(basename "$0") <rtc|zacus|path> --interactive
|
||||
$(basename "$0") <rtc|zacus|path> --hardware
|
||||
USAGE
|
||||
}
|
||||
|
||||
if [[ $# -lt 2 ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
target="$1"
|
||||
shift
|
||||
|
||||
case "$target" in
|
||||
rtc) workspace="$RTC_REPO" ;;
|
||||
zacus) workspace="$ZACUS_REPO" ;;
|
||||
*) workspace="$target" ;;
|
||||
esac
|
||||
|
||||
if [[ ! -d "$workspace" ]]; then
|
||||
echo "Workspace not found: $workspace" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -x "$ZEROCLAW_BIN" ]]; then
|
||||
if command -v zeroclaw >/dev/null 2>&1; then
|
||||
ZEROCLAW_BIN="$(command -v zeroclaw)"
|
||||
else
|
||||
echo "zeroclaw binary not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${1:-}" == "--hardware" ]]; then
|
||||
ZEROCLAW_WORKSPACE="$workspace" "$ZEROCLAW_BIN" hardware discover
|
||||
exit 0
|
||||
fi
|
||||
|
||||
resolve_provider() {
|
||||
if [[ -n "${ZEROCLAW_PROVIDER:-}" ]]; then
|
||||
echo "$ZEROCLAW_PROVIDER"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if command -v gh >/dev/null 2>&1 && gh auth status >/dev/null 2>&1; then
|
||||
if gh api /user/copilot/billing --silent >/dev/null 2>&1; then
|
||||
local gh_token
|
||||
gh_token="$(gh auth token)"
|
||||
export API_KEY="$gh_token"
|
||||
echo "copilot"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if "$ZEROCLAW_BIN" auth list 2>/dev/null | rg -q "openai-codex:"; then
|
||||
echo "openai-codex"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -n "${OPENROUTER_API_KEY:-}" ]]; then
|
||||
export API_KEY="$OPENROUTER_API_KEY"
|
||||
echo "openrouter"
|
||||
return 0
|
||||
fi
|
||||
|
||||
cat <<'ERR' >&2
|
||||
No provider credentials detected.
|
||||
- Option 1: ZEROCLAW_PROVIDER=copilot with GitHub Copilot subscription + gh auth login
|
||||
- Option 2: zeroclaw auth login --provider openai-codex --device-code
|
||||
- Option 3: export OPENROUTER_API_KEY=... and ZEROCLAW_PROVIDER=openrouter
|
||||
ERR
|
||||
return 1
|
||||
}
|
||||
|
||||
export ZEROCLAW_WORKSPACE="$workspace"
|
||||
provider="$(resolve_provider)"
|
||||
echo "[zeroclaw-dual-chat] workspace=$workspace provider=$provider"
|
||||
|
||||
if [[ "${1:-}" == "--interactive" ]]; then
|
||||
exec "$ZEROCLAW_BIN" agent -p "$provider"
|
||||
fi
|
||||
|
||||
if [[ "${1:-}" != "-m" || -z "${2:-}" ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$ZEROCLAW_BIN" agent -p "$provider" -m "$2"
|
||||
Reference in New Issue
Block a user