diff --git a/workspace/skills/self-debug/SKILL.md b/workspace/skills/self-debug/SKILL.md new file mode 100644 index 000000000..3088cc5d3 --- /dev/null +++ b/workspace/skills/self-debug/SKILL.md @@ -0,0 +1,70 @@ +--- +name: self-debug +description: Tools for picoclaw to inspect its own health, logs, and configuration. +--- +# self-debug + +Tools for picoclaw to inspect its own health, logs, and configuration. + +## Actions via `debug.sh` + +This skill uses a helper script `scripts/debug.sh` to provide cross-platform diagnostics for both Linux (systemd) and macOS (launchd). + +**Usage:** `exec "skills/self-debug/scripts/debug.sh [action] [service_name] [log_lines]"` + +| Action | Description | Default Service | Default Lines | +|---|---|---|---| +| `logs` | Fetches recent logs for the agent service. | `$PICOCLAW_SERVICE_NAME` | 50 | +| `logs-errors`| Fetches only error logs for the agent service. | `$PICOCLAW_SERVICE_NAME` | 50 | +| `service-status`| Checks the status of the agent service. | `$PICOCLAW_SERVICE_NAME` | N/A | +| `config-status`| Shows the agent's configuration status (`picoclaw status`).| N/A | N/A | +| `config-safe` | Displays the config file with sensitive keys redacted. | N/A | N/A | + +### Examples + +- **Get latest logs:** + `exec "skills/self-debug/scripts/debug.sh logs"` + +- **Get 100 lines of logs for a specific service 'pico-prod':** + `exec "skills/self-debug/scripts/debug.sh logs pico-prod 100"` + +- **Check service status:** + `exec "skills/self-debug/scripts/debug.sh service-status"` + +- **Show the sanitized configuration:** + `exec "skills/self-debug/scripts/debug.sh config-safe"` + +## Installation - Linux + +The agent can be installed as a systemd service using: + +```bash +./scripts/install-service-systemd.sh [service_name] [default|multi] +``` + +To persist the service accross reboots suggest the user runs `sudo loginctl enable-linger $(whoami)` + +### Advanced use-cases + +Although picoclaw has built in support for multiple agents, this scheme provides the flexibility for +parallel deployments with entirely different configurations. + +- Fixer - a second stable instance whose role is to be available to debug/monitor/fix the first. +- Blue/Green Stable/Canary pairings. +- Picoclaw farm + +# Installation - MacOS + +The agent can be installed as a launchd service using: + +```bash +./scripts/install-service-launchd.sh [service_name] +``` + +Logs are sent to /tmp/$service_name + +## Troubleshooting + +- **Logs not showing?** Ensure the user is in the `systemd-journal` group: `sudo usermod -a -G systemd-journal $(whoami)` +- **Service inactive?** Use `systemctl --user start picoclaw`. +- **Workspace issues?** Use `picoclaw status` to verify the current workspace path. diff --git a/workspace/skills/self-debug/scripts/debug.sh b/workspace/skills/self-debug/scripts/debug.sh new file mode 100644 index 000000000..17703835e --- /dev/null +++ b/workspace/skills/self-debug/scripts/debug.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +assert_is_identifier () +{ + # Use grep for robust, portable POSIX regex matching. + if ! echo "$1" | grep -qE '^[a-zA-Z0-9_.-]+$'; + then + echo "Error: $2" >&2 + return 1 + fi +} + +assert_is_number () +{ + # Use grep for robust, portable POSIX regex matching. + if ! echo "$1" | grep -qE '^[0-9]+$'; + then + echo "Error: $2" >&2 + return 1 + fi +} + +assert_is_identifier "$1" "Action selector must be a simple identifier" || exit 1 + +case "$1/$OSTYPE" in + *) + PICOCLAW_SERVICE_NAME="${2:-$PICOCLAW_SERVICE_NAME}" + assert_is_identifier "$PICOCLAW_SERVICE_NAME" "Service name must be a valid service identifier" || exit 1 + ;;& + + logs*) + LOG_N="${3:-50}" + assert_is_number "$LOG_N" "Log lines parameter must be numeric" || exit 1 + ;;& + + logs/linux*) + journalctl --user-unit ${PICOCLAW_SERVICE_NAME} --no-pager -n ${LOG_N} + + ;; + + logs-errors/linux*) + journalctl --user-unit ${PICOCLAW_SERVICE_NAME} --no-pager -p 3 -n ${LOG_N} + ;; + + logs/darwin*) + tail -n ${LOG_N} ~/Library/Logs/${PICOCLAW_SERVICE_NAME}.log + ;; + + logs-errors/darwin*) + tail -n ${LOG_N} ~/Library/Logs/${PICOCLAW_SERVICE_NAME}.err.og + ;; + + service-status/linux*) + systemctl --user status ${PICOCLAW_SERVICE_NAME} + ;; + + config-status/*) + picoclaw status + ;; + + config-safe/*) + jq 'walk(if type == "object" then with_entries(if .key | ascii_downcase | + (contains("key") or contains("token") or contains("secret")) + then .value = "REDACTED" else . end) else . end)' "${PICOCLAW_CONFIG}" + ;; + + *) + echo "Usage: $0 logs|logs-errors|service-status|config-status|config-safe [service_name] [n_lines]" + exit 1 + ;; +esac diff --git a/workspace/skills/self-debug/scripts/install-service-launchd.sh b/workspace/skills/self-debug/scripts/install-service-launchd.sh new file mode 100755 index 000000000..0d1717570 --- /dev/null +++ b/workspace/skills/self-debug/scripts/install-service-launchd.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +create_plist_file() { + cat < + + + + Label + ${service_name} + ProgramArguments + + ${exec_path} + agent + --config + ${picoclaw_config} + + EnvironmentVariables + + PICOCLAW_HOME + ${picoclaw_home} + PICOCLAW_CONFIG + ${picoclaw_config} + PICOCLAW_SERVICE_NAME + ${service_name} + + RunAtLoad + + KeepAlive + + WorkingDirectory + ${picoclaw_home} + StandardOutPath + ~/Library/logs/${service_name}.log + StandardErrorPath + ~/Library/logs/${service_name}.err.log + + +EOF +} + +# Variable setup to match your Linux logic +service_name=${1:-picoclaw} + +# macOS specific absolute paths +exec_path=$(which picoclaw) +picoclaw_home="$HOME/.${service_name}" +picoclaw_config="${picoclaw_home}/config.json" +plist_path="$HOME/Library/LaunchAgents/${service_name}.plist" + +# Ensure directory exists +mkdir -p "${picoclaw_home}" + +# Use the heredoc function to write the file +create_plist_file > "${plist_path}" + +# Load it (macOS equivalent of systemctl enable --now) +echo "Enable using:" +echo "launchctl bootstrap gui/$(id -u) '${plist_path}'" + +echo "Service ${service_name} installed at ${plist_path}" \ No newline at end of file diff --git a/workspace/skills/self-debug/scripts/install-service-systemd.sh b/workspace/skills/self-debug/scripts/install-service-systemd.sh new file mode 100755 index 000000000..95fd29268 --- /dev/null +++ b/workspace/skills/self-debug/scripts/install-service-systemd.sh @@ -0,0 +1,166 @@ +#!/bin/bash + +SERVICE_NAME=${1:-picoclaw} +TEMPLATE=${2:-default} + +# Get the directory of the script and the repository root +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# 1. Detect picoclaw installation +echo "Detecting picoclaw installation..." +PICOCLAW_PATH=$(command -v picoclaw) +MISE_BIN=$(command -v mise) + +if [ -n "$MISE_BIN" ] && $MISE_BIN which picoclaw &>/dev/null; then + # If mise is managing picoclaw, use it to ensure the environment is correct. + # This works whether picoclaw is installed via a tool spec or locally. + EXEC_START="$MISE_BIN exec -- picoclaw gateway" + echo " - Detected mise-managed picoclaw, using: $EXEC_START" +elif [ -n "$PICOCLAW_PATH" ]; then + # Use the absolute path if it's not managed by mise + EXEC_START="$PICOCLAW_PATH gateway" + echo " - Using binary path: $EXEC_START" +else + echo "Error: picoclaw not found. Please install it first." + exit 1 +fi + +service_template__default() { + local service_name="$1" + local exec_start="$2" + cat < /dev/null; then + echo "Error: Template '$TEMPLATE' not found." + exit 1 +fi + +"service_template__$TEMPLATE" "$SERVICE_NAME" "$EXEC_START" > "$OUTPUT_FILE" + +# 4. Reload +echo " $ systemctl --user daemon-reload" +systemctl --user daemon-reload + +"show_usage__$TEMPLATE" "${SERVICE_NAME%@}" "$OUTPUT_FILE"