Back to skills
SkillHub ClubRun DevOpsFull StackDevOpsIntegration

openclaw-manager

Deploy, harden, and operate OpenClaw across local and hosted environments (Fly.io, Render, Railway, Hetzner, GCP) with secure defaults, channel setup guidance, integration onboarding, and troubleshooting workflows grounded in official OpenClaw documentation. Use when users need install/deploy help, migration support, runtime hardening, memory/agent operations tuning, or incident response.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
3,115
Hot score
99
Updated
March 20, 2026
Overall rating
C4.0
Composite score
4.0
Best-practice grade
B75.6

Install command

npx @skill-hub/cli install openclaw-skills-openclaw-manager

Repository

openclaw/skills

Skill path: skills/hollaugo/openclaw-manager

Deploy, harden, and operate OpenClaw across local and hosted environments (Fly.io, Render, Railway, Hetzner, GCP) with secure defaults, channel setup guidance, integration onboarding, and troubleshooting workflows grounded in official OpenClaw documentation. Use when users need install/deploy help, migration support, runtime hardening, memory/agent operations tuning, or incident response.

Open repository

Best for

Primary workflow: Run DevOps.

Technical facets: Full Stack, DevOps, Integration.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: openclaw.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install openclaw-manager into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/openclaw/skills before adding openclaw-manager to shared team environments
  • Use openclaw-manager for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: openclaw-manager
description: Deploy, harden, and operate OpenClaw across local and hosted environments (Fly.io, Render, Railway, Hetzner, GCP) with secure defaults, channel setup guidance, integration onboarding, and troubleshooting workflows grounded in official OpenClaw documentation. Use when users need install/deploy help, migration support, runtime hardening, memory/agent operations tuning, or incident response.
runtime_metadata:
  deployment_modes:
    - local
    - hosted
  supported_providers:
    - local
    - fly
    - render
    - railway
    - hetzner
    - gcp
  supported_operating_systems:
    - macos
    - linux
    - windows-wsl2
  supported_channels:
    - telegram
    - discord
    - slack
  supported_integrations:
    - email
    - calendar
  security_gates:
    - env_validation_passed
    - security_checklist_passed
    - rollback_plan_documented
    - ledger_updated
  privileged_operations:
    - provider_secret_writes
    - public_network_exposure
    - persistent_state_changes
  required_env_vars:
    - OPENCLAW_GATEWAY_TOKEN
---

# OpenClaw Manager

## Overview
Build and operate OpenClaw with production-safe defaults across both local and hosted environments. This skill is optimized for operators with limited platform expertise and enforces hard security gates before rollout completion.

Primary references:
- Docs map: `references/openclaw-doc-map.md`
- Security gates checklist: `references/openclaw-security-checklist.md`
- Mode matrix: `references/openclaw-mode-matrix.md`
- OS matrix: `references/openclaw-os-matrix.md`
- Integrations playbook: `references/openclaw-integrations-playbook.md`
- Ops ledger schema: `references/openclaw-ops-ledger-schema.md`

Automation helpers:
- `scripts/plan_openclaw_rollout.py`
- `scripts/validate_openclaw_env.py`
- `scripts/update_openclaw_ops_ledger.py`

Default ops ledger path:
- `./openclaw-manager-operations-ledger.md` (or operator specified)

## Hard-Stop Rules (Never Bypass)
Stop and block deployment/install progression if any condition is true:
1. Required secrets profile fails validation.
2. Security checklist mandatory gates are not all passing.
3. Rollback path is not documented and owned.
4. Ops ledger was not updated for the current phase.
5. Public exposure requested without auth boundary and token controls.

## Workflow

### 1) Intake and Scope Lock
Collect and confirm:
- `mode`: `local` or `hosted`
- `provider`: `local`, `fly`, `render`, `railway`, `hetzner`, `gcp`
- `os`: `macos`, `linux`, `windows-wsl2`
- `channels`: subset of `telegram`, `discord`, `slack`
- `integrations`: subset of `email`, `calendar`
- `environment`: `dev`, `staging`, `prod`
- `exposure`: `private` or `public`

Before proceeding, write a `scope_lock` ledger entry:

```bash
python3 scripts/update_openclaw_ops_ledger.py \
  --ledger-file ./openclaw-manager-operations-ledger.md \
  --event scope_lock \
  --operator codex \
  --mode hosted \
  --provider fly \
  --os linux \
  --environment prod \
  --secrets-profile hosted-fly \
  --channels telegram,slack \
  --integrations email,calendar \
  --security-status pending \
  --rollback-tested no \
  --blocking-issues "none" \
  --next-owner operator \
  --next-action-date 2026-02-20
```

### 2) Generate a Decision-Complete Plan
Always generate a plan first:

```bash
python3 scripts/plan_openclaw_rollout.py \
  --mode hosted \
  --provider fly \
  --os linux \
  --channels telegram,slack \
  --integrations email,calendar \
  --environment prod \
  --exposure public \
  --ledger-file ./openclaw-manager-operations-ledger.md \
  --output /tmp/openclaw-rollout.md
```

The plan output is the execution contract. Do not skip sections.

### 3) Validate Secrets and Config Profile Before Any Infra Change
Validate environment using profile-aware gates:

```bash
python3 scripts/validate_openclaw_env.py \
  --env-file .env \
  --profile hosted-fly \
  --json
```

Validation enforces:
- required keys by profile
- required provider/model alternatives
- malformed and duplicate env keys
- placeholder values
- weak gateway/setup tokens
- legacy alias warnings

Write a `predeploy_validation` ledger entry immediately after validation.

### 4) Execute Mode Branch

#### Branch A: Local install (`mode=local`)
1. Use official install/onboarding docs for local setup.
2. Apply OS-specific commands from `references/openclaw-os-matrix.md`.
3. Validate startup, persistence path, and local auth boundaries.
4. If local public exposure is requested, apply gateway hardening gates from security checklist first.

#### Branch B: Hosted clone + deploy (`mode=hosted`)
1. Clone the selected OpenClaw source repo.
2. Follow provider playbook from `references/openclaw-doc-map.md`.
3. Configure persistent storage before production traffic.
4. Configure ingress/auth, secrets, and health checks.
5. Verify runtime logs for startup/auth errors and secret leakage.

Write a `deploy_complete` ledger entry once deployment/install is complete.

### 5) Configure Channels and Integrations Safely
For each selected channel/integration:
- inject credentials via secret manager/env only
- run a minimal smoke test
- verify auth boundaries and error logging safety

Track each item as:
- `configured`
- `pending_credentials`
- `blocked`

Use `references/openclaw-integrations-playbook.md` for email/calendar specifics.

### 6) Agent + Memory Baseline
Document and validate:
- memory persistence strategy
- retention expectations
- restart and recovery behavior
- agent behavior boundaries

Update ledger with operational baseline decisions.

### 7) Mandatory Security Gate
Run `references/openclaw-security-checklist.md` and produce pass/fail per gate.

No go-live if any mandatory gate fails.

Write a `security_gate` ledger entry with explicit blockers (if any).

### 8) Handover and Incident Readiness
Produce:
- provider status summary
- channel + integration matrix
- security gate table
- rollback and escalation ownership
- follow-up actions by risk order

Write `handover` ledger entry. For incidents/troubleshooting, append `incident` entries as events happen.

## Output Contract
Always return:
1. Mode/provider/OS/environment status summary
2. Security gate results (hard pass/fail)
3. Channel + integration matrix
4. Agent + memory configuration summary
5. Ops ledger update confirmation (event names written)
6. Follow-up actions ordered by risk


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### scripts/update_openclaw_ops_ledger.py

```python
#!/usr/bin/env python3
"""Append structured events to the OpenClaw operations ledger."""

from __future__ import annotations

import argparse
import datetime as dt
import re
from pathlib import Path

EVENT_CHOICES = {
    "scope_lock",
    "predeploy_validation",
    "deploy_complete",
    "security_gate",
    "handover",
    "incident",
}

DATE_RE = re.compile(r"^\d{4}-\d{2}-\d{2}$")


def parse_csv(value: str) -> str:
    parts = [part.strip() for part in value.split(",") if part.strip()]
    return ",".join(parts) if parts else "none"


def ensure_ledger_exists(path: Path) -> None:
    if path.exists():
        return

    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(
        "# OpenClaw Manager Operations Ledger\n\n"
        "This file records operational metadata for OpenClaw management workflows.\n\n"
        "Required schema: `docs/product/skills/openclaw-manager/references/openclaw-ops-ledger-schema.md`\n"
    )


def main() -> int:
    parser = argparse.ArgumentParser(description="Append an OpenClaw ops ledger event")
    parser.add_argument("--ledger-file", required=True, help="Path to ledger markdown file")
    parser.add_argument("--event", required=True, choices=sorted(EVENT_CHOICES))
    parser.add_argument("--operator", required=True)
    parser.add_argument("--mode", required=True)
    parser.add_argument("--provider", required=True)
    parser.add_argument("--os", required=True)
    parser.add_argument("--environment", required=True)
    parser.add_argument("--secrets-profile", required=True)
    parser.add_argument("--channels", default="")
    parser.add_argument("--integrations", default="")
    parser.add_argument("--security-status", required=True, choices=["pending", "passed", "failed"])
    parser.add_argument("--blocking-issues", default="none")
    parser.add_argument("--rollback-tested", required=True, choices=["yes", "no"])
    parser.add_argument("--next-owner", required=True)
    parser.add_argument("--next-action-date", required=True, help="YYYY-MM-DD")

    args = parser.parse_args()

    if not DATE_RE.match(args.next_action_date):
        print("[ERROR] --next-action-date must be in YYYY-MM-DD format")
        return 1

    # Also validate logical date formatting.
    try:
        dt.date.fromisoformat(args.next_action_date)
    except ValueError:
        print("[ERROR] --next-action-date is not a valid date")
        return 1

    ledger_path = Path(args.ledger_file)
    ensure_ledger_exists(ledger_path)

    timestamp = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
    channels = parse_csv(args.channels)
    integrations = parse_csv(args.integrations)

    entry = (
        f"\n## {timestamp} | {args.event}\n"
        f"- operator: {args.operator}\n"
        f"- mode: {args.mode}\n"
        f"- provider: {args.provider}\n"
        f"- os: {args.os}\n"
        f"- environment: {args.environment}\n"
        f"- secrets_profile: {args.secrets_profile}\n"
        f"- channels: {channels}\n"
        f"- integrations: {integrations}\n"
        f"- security_status: {args.security_status}\n"
        f"- blocking_issues: {args.blocking_issues}\n"
        f"- rollback_tested: {args.rollback_tested}\n"
        f"- next_owner: {args.next_owner}\n"
        f"- next_action_date: {args.next_action_date}\n"
    )

    with ledger_path.open("a", encoding="utf-8") as handle:
        handle.write(entry)

    print(f"[OK] Appended ledger event: {args.event}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

```

### scripts/plan_openclaw_rollout.py

```python
#!/usr/bin/env python3
"""Generate a mode-aware OpenClaw rollout checklist with hard security gates."""

from __future__ import annotations

import argparse
from datetime import datetime, timezone
from pathlib import Path

PROVIDER_LINKS = {
    "local": "https://docs.openclaw.ai/start/getting-started",
    "fly": "https://docs.openclaw.ai/install/fly",
    "render": "https://docs.openclaw.ai/install/render",
    "railway": "https://docs.openclaw.ai/install/railway",
    "hetzner": "https://docs.openclaw.ai/install/hetzner",
    "gcp": "https://docs.openclaw.ai/install/gcp",
}

MODE_PROVIDER_ALLOWED = {
    "local": {"local"},
    "hosted": {"fly", "render", "railway", "hetzner", "gcp"},
}

CHANNEL_LINKS = {
    "telegram": "https://docs.openclaw.ai/channels/telegram",
    "discord": "https://docs.openclaw.ai/channels/discord",
    "slack": "https://docs.openclaw.ai/channels/slack",
}

INTEGRATION_LINKS = {
    "email": "https://docs.openclaw.ai/integrations/gmail",
    "calendar": "https://docs.openclaw.ai/integrations/google-calendar",
}

OS_NOTES = {
    "macos": "Use Homebrew-first install paths and verify shell PATH exports.",
    "linux": "Use distro package manager/system tooling and verify daemon startup strategy.",
    "windows-wsl2": "Run commands inside WSL2 Linux shell and avoid mixed Windows/WSL paths.",
}

DEFAULT_LEDGER_FILE = "openclaw-manager-operations-ledger.md"


def parse_csv(raw: str, *, allowed: set[str], label: str) -> list[str]:
    values = [value.strip().lower() for value in raw.split(",") if value.strip()]
    invalid = sorted({value for value in values if value not in allowed})
    if invalid:
        raise ValueError(f"Unsupported {label}: {', '.join(invalid)}")
    return values


def build_profile(mode: str, provider: str) -> str:
    if mode == "local":
        return "local"
    return f"hosted-{provider}"


def validate_mode_provider(mode: str, provider: str) -> None:
    allowed = MODE_PROVIDER_ALLOWED[mode]
    if provider not in allowed:
        allowed_list = ", ".join(sorted(allowed))
        raise ValueError(f"Provider '{provider}' is invalid for mode '{mode}'. Allowed: {allowed_list}")


def render(
    *,
    mode: str,
    provider: str,
    os_name: str,
    channels: list[str],
    integrations: list[str],
    environment: str,
    exposure: str,
    ledger_file: str,
) -> str:
    now = datetime.now(timezone.utc).isoformat()
    profile = build_profile(mode, provider)

    lines = [
        "# OpenClaw Rollout Plan",
        "",
        f"- Generated: {now}",
        f"- Mode: {mode}",
        f"- Provider: {provider}",
        f"- OS: {os_name}",
        f"- Environment: {environment}",
        f"- Exposure: {exposure}",
        f"- Secrets profile: {profile}",
        f"- Ops ledger: {ledger_file}",
        "",
        "## 1. Scope Lock",
        "- [ ] Confirm operator intent and rollback owner.",
        "- [ ] Confirm mode/provider/OS matrix is valid for this run.",
        "- [ ] Append `scope_lock` entry to ops ledger.",
        "",
        "## 2. Preflight Validation",
        f"- [ ] Validate `.env` with `scripts/validate_openclaw_env.py --env-file .env --profile {profile}`.",
        "- [ ] Block progression on any validation failure.",
        "- [ ] Append `predeploy_validation` entry to ops ledger.",
        "",
        "## 3. Deployment or Install",
    ]

    if mode == "local":
        lines.extend(
            [
                f"- [ ] Follow local install/onboarding guide: {PROVIDER_LINKS['local']}",
                f"- [ ] Apply OS notes: {OS_NOTES[os_name]}",
                "- [ ] Verify local startup, state path permissions, and auth boundaries.",
                "- [ ] If exposure is public, complete security gates before enabling ingress.",
            ]
        )
    else:
        lines.extend(
            [
                f"- [ ] Clone OpenClaw source and follow provider guide: {PROVIDER_LINKS[provider]}",
                "- [ ] Configure persistent state before first traffic.",
                "- [ ] Deploy and capture URL + health endpoint evidence.",
                "- [ ] Verify runtime logs for startup/auth issues and token leakage.",
            ]
        )

    lines.extend(
        [
            "- [ ] Append `deploy_complete` entry to ops ledger.",
            "",
            "## 4. Channels",
        ]
    )

    if channels:
        for channel in channels:
            lines.append(f"- [ ] Configure {channel}: {CHANNEL_LINKS[channel]}")
            lines.append(f"- [ ] Smoke-test {channel} and mark status (`configured`/`pending_credentials`/`blocked`).")
    else:
        lines.append("- [ ] No channels selected for this rollout.")

    lines.extend(["", "## 5. Integrations"])

    if integrations:
        for integration in integrations:
            lines.append(f"- [ ] Configure {integration}: {INTEGRATION_LINKS[integration]}")
            lines.append(f"- [ ] Smoke-test {integration} and record status in ops ledger.")
    else:
        lines.append("- [ ] No integrations selected for this rollout.")

    lines.extend(
        [
            "",
            "## 6. Agent + Memory",
            "- [ ] Document memory persistence strategy and retention expectations.",
            "- [ ] Verify restart/recovery behavior.",
            "- [ ] Confirm agent behavior boundaries for selected environment.",
            "",
            "## 7. Hard Security Gates (Go/No-Go)",
            "- [ ] Gate 1: Secrets profile validation passed.",
            "- [ ] Gate 2: Network/exposure boundaries validated.",
            "- [ ] Gate 3: Channel/integration auth boundaries validated.",
            "- [ ] Gate 4: Runtime/persistence safety validated.",
            "- [ ] Gate 5: Incident readiness and rollback ownership documented.",
            "- [ ] Gate 6: Supply chain patch posture documented.",
            "- [ ] Gate 7: Ops ledger completeness validated.",
            "- [ ] Append `security_gate` entry to ops ledger.",
            "",
            "## 8. Handover",
            "- [ ] Produce provider status summary.",
            "- [ ] Produce channel/integration matrix.",
            "- [ ] Produce security pass/fail table with blockers.",
            "- [ ] Produce next actions ordered by risk.",
            "- [ ] Append `handover` entry to ops ledger.",
            "",
            "## 9. Explicit Blockers",
            "Stop rollout immediately if any are true:",
            "- [ ] Missing required secrets profile key(s).",
            "- [ ] Security gate has any failed mandatory item.",
            "- [ ] Rollback plan or owner missing.",
            "- [ ] Ops ledger missing required phase entries.",
        ]
    )

    return "\n".join(lines)


def main() -> int:
    parser = argparse.ArgumentParser(description="Generate OpenClaw rollout checklist")
    parser.add_argument("--mode", required=True, choices=sorted(MODE_PROVIDER_ALLOWED))
    parser.add_argument("--provider", required=True, choices=sorted(PROVIDER_LINKS))
    parser.add_argument("--os", required=True, choices=sorted(OS_NOTES), dest="os_name")
    parser.add_argument("--channels", default="", help="Comma-separated channels: telegram,discord,slack")
    parser.add_argument("--integrations", default="", help="Comma-separated integrations: email,calendar")
    parser.add_argument("--environment", default="prod", help="Environment label (dev/staging/prod)")
    parser.add_argument("--exposure", required=True, choices=["private", "public"])
    parser.add_argument("--ledger-file", default=DEFAULT_LEDGER_FILE, help="Path to ops ledger markdown file")
    parser.add_argument("--output", required=True, help="Output markdown file")
    args = parser.parse_args()

    try:
        validate_mode_provider(args.mode, args.provider)
        channels = parse_csv(args.channels, allowed=set(CHANNEL_LINKS), label="channels") if args.channels else []
        integrations = (
            parse_csv(args.integrations, allowed=set(INTEGRATION_LINKS), label="integrations")
            if args.integrations
            else []
        )
    except ValueError as err:
        print(f"[ERROR] {err}")
        return 1

    content = render(
        mode=args.mode,
        provider=args.provider,
        os_name=args.os_name,
        channels=channels,
        integrations=integrations,
        environment=args.environment,
        exposure=args.exposure,
        ledger_file=args.ledger_file,
    )

    output = Path(args.output)
    output.parent.mkdir(parents=True, exist_ok=True)
    output.write_text(content)

    print(f"[OK] Wrote rollout plan: {output}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

```

### scripts/validate_openclaw_env.py

```python
#!/usr/bin/env python3
"""Validate OpenClaw env files for profile-aware deployment readiness."""

from __future__ import annotations

import argparse
import json
import re
import sys
from pathlib import Path

PLACEHOLDER_PATTERNS = (
    "changeme",
    "todo",
    "your-key",
    "your_token",
    "example",
    "replace-me",
    "placeholder",
)

KEY_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
HEX_RE = re.compile(r"^[0-9a-fA-F]+$")

PROFILE_CONFIG = {
    "local": {
        "required": ["OPENCLAW_GATEWAY_TOKEN"],
        "require_any": [["OPENAI_API_KEY", "ANTHROPIC_API_KEY"]],
        "recommended": [],
    },
    "hosted-fly": {
        "required": ["OPENCLAW_GATEWAY_TOKEN"],
        "require_any": [["OPENAI_API_KEY", "ANTHROPIC_API_KEY"]],
        "recommended": ["FLY_API_TOKEN"],
    },
    "hosted-render": {
        "required": ["OPENCLAW_GATEWAY_TOKEN"],
        "require_any": [["OPENAI_API_KEY", "ANTHROPIC_API_KEY"]],
        "recommended": ["RENDER_API_KEY"],
    },
    "hosted-railway": {
        "required": ["OPENCLAW_GATEWAY_TOKEN"],
        "require_any": [["OPENAI_API_KEY", "ANTHROPIC_API_KEY"]],
        "recommended": ["RAILWAY_TOKEN"],
    },
    "hosted-hetzner": {
        "required": ["OPENCLAW_GATEWAY_TOKEN"],
        "require_any": [["OPENAI_API_KEY", "ANTHROPIC_API_KEY"]],
        "recommended": ["HCLOUD_TOKEN"],
    },
    "hosted-gcp": {
        "required": ["OPENCLAW_GATEWAY_TOKEN"],
        "require_any": [["OPENAI_API_KEY", "ANTHROPIC_API_KEY"]],
        "recommended": ["GCP_SERVICE_ACCOUNT_JSON", "GOOGLE_APPLICATION_CREDENTIALS"],
    },
}


def parse_env(env_path: Path):
    values: dict[str, str] = {}
    duplicates: list[str] = []
    malformed: list[tuple[int, str]] = []

    for idx, raw_line in enumerate(env_path.read_text().splitlines(), start=1):
        line = raw_line.strip()
        if not line or line.startswith("#"):
            continue

        if "=" not in line:
            malformed.append((idx, raw_line))
            continue

        key, value = line.split("=", 1)
        key = key.strip()
        value = value.strip()

        if not KEY_RE.match(key):
            malformed.append((idx, raw_line))
            continue

        if key in values:
            duplicates.append(key)

        values[key] = value

    return values, duplicates, malformed


def is_placeholder(value: str) -> bool:
    lowered = value.lower()
    return any(pattern in lowered for pattern in PLACEHOLDER_PATTERNS)


def parse_require_any(values: list[str]) -> list[list[str]]:
    groups: list[list[str]] = []
    for raw in values:
        parts = [part.strip() for part in raw.split(",") if part.strip()]
        if len(parts) < 2:
            raise ValueError("--require-any must include at least two comma-separated keys")
        groups.append(parts)
    return groups


def check_secret_strength(values: dict[str, str]):
    weak: list[str] = []

    gateway = values.get("OPENCLAW_GATEWAY_TOKEN", "")
    if gateway:
        if len(gateway) < 32:
            weak.append("OPENCLAW_GATEWAY_TOKEN (too short; expected >=32 chars)")
        elif HEX_RE.match(gateway) and len(gateway) < 64:
            weak.append("OPENCLAW_GATEWAY_TOKEN (hex token shorter than 64 chars)")

    for key, value in values.items():
        if not value:
            continue

        lowered = key.lower()
        sensitive = any(token in lowered for token in ["token", "secret", "password", "api_key"])
        if sensitive and len(value) < 16:
            weak.append(f"{key} (too short for sensitive credential)")

    return sorted(set(weak))


def main() -> int:
    parser = argparse.ArgumentParser(description="Validate .env file for OpenClaw deployments")
    parser.add_argument("--env-file", required=True, help="Path to .env file")
    parser.add_argument(
        "--profile",
        required=True,
        choices=sorted(PROFILE_CONFIG),
        help="Validation profile (local or hosted provider profile)",
    )
    parser.add_argument(
        "--require",
        action="append",
        default=[],
        help="Additional required key (can be passed multiple times)",
    )
    parser.add_argument(
        "--require-any",
        action="append",
        default=[],
        help="Additional key group requirement; pass as comma-separated list (e.g. A,B)",
    )
    parser.add_argument("--json", action="store_true", help="Emit machine-readable JSON output")
    args = parser.parse_args()

    env_path = Path(args.env_file)
    if not env_path.exists():
        payload = {"ok": False, "errors": [f"Env file not found: {env_path}"]}
        if args.json:
            print(json.dumps(payload, indent=2))
        else:
            print(f"[ERROR] Env file not found: {env_path}")
        return 1

    values, duplicates, malformed = parse_env(env_path)
    normalized = values

    profile = PROFILE_CONFIG[args.profile]
    required_keys = sorted(set(profile["required"] + args.require))

    try:
        dynamic_require_any = parse_require_any(args.require_any)
    except ValueError as err:
        if args.json:
            print(json.dumps({"ok": False, "errors": [str(err)]}, indent=2))
        else:
            print(f"[ERROR] {err}")
        return 1

    require_any_groups = profile["require_any"] + dynamic_require_any

    missing_required = [key for key in required_keys if key not in normalized or not normalized[key]]
    missing_any_groups: list[list[str]] = []
    for group in require_any_groups:
        if not any(normalized.get(key) for key in group):
            missing_any_groups.append(group)

    placeholders = [key for key, value in normalized.items() if value and is_placeholder(value)]
    weak_secrets = check_secret_strength(normalized)

    recommended_missing = [
        key for key in profile.get("recommended", []) if key not in normalized or not normalized[key]
    ]

    errors = []
    warnings = []

    if malformed:
        errors.append("malformed env lines detected")
    if duplicates:
        errors.append("duplicate env keys detected")
    if missing_required:
        errors.append("required keys missing")
    if missing_any_groups:
        errors.append("required alternative key groups unsatisfied")
    if placeholders:
        errors.append("placeholder values detected")
    if weak_secrets:
        errors.append("weak secrets detected")

    if recommended_missing:
        warnings.append(
            "recommended keys missing for profile: " + ", ".join(recommended_missing)
        )

    payload = {
        "ok": len(errors) == 0,
        "profile": args.profile,
        "parsed_keys": len(normalized),
        "required_keys": required_keys,
        "missing_required": missing_required,
        "require_any_groups": require_any_groups,
        "missing_require_any_groups": missing_any_groups,
        "malformed_lines": [{"line": line_no, "content": line} for line_no, line in malformed],
        "duplicate_keys": sorted(set(duplicates)),
        "placeholder_keys": sorted(placeholders),
        "weak_secrets": weak_secrets,
        "warnings": warnings,
        "errors": errors,
    }

    if args.json:
        print(json.dumps(payload, indent=2))
    else:
        print(f"Parsed keys (normalized): {payload['parsed_keys']}")

        if malformed:
            print("\nMalformed lines:")
            for line_no, line in malformed:
                print(f"  - line {line_no}: {line}")

        if duplicates:
            print("\nDuplicate keys:")
            for key in sorted(set(duplicates)):
                print(f"  - {key}")

        if missing_required:
            print("\nMissing required keys:")
            for key in missing_required:
                print(f"  - {key}")

        if missing_any_groups:
            print("\nUnsatisfied required key groups (need at least one key from each):")
            for group in missing_any_groups:
                print(f"  - {', '.join(group)}")

        if placeholders:
            print("\nPotential placeholder values:")
            for key in sorted(placeholders):
                print(f"  - {key}")

        if weak_secrets:
            print("\nWeak secret checks:")
            for issue in weak_secrets:
                print(f"  - {issue}")

        if warnings:
            print("\nWarnings:")
            for warning in warnings:
                print(f"  - {warning}")

        if payload["ok"]:
            print("\n[OK] Env validation passed.")
        else:
            print("\n[FAIL] Env validation failed.")

    return 0 if payload["ok"] else 1


if __name__ == "__main__":
    sys.exit(main())

```

### references/openclaw-doc-map.md

```markdown
# OpenClaw Doc Map

Use official OpenClaw docs as the source of truth.

## Core
- Features: https://docs.openclaw.ai/concepts/features
- Getting started: https://docs.openclaw.ai/start/getting-started
- Setup guide: https://docs.openclaw.ai/setup-guide
- Onboarding CLI: https://docs.openclaw.ai/start/onboarding-cli
- Skills overview: https://docs.openclaw.ai/skills

## Deployment
- Install overview: https://docs.openclaw.ai/install
- Fly.io install: https://docs.openclaw.ai/install/fly
- Render install: https://docs.openclaw.ai/install/render
- Railway install: https://docs.openclaw.ai/install/railway
- Hetzner install: https://docs.openclaw.ai/install/hetzner
- GCP install: https://docs.openclaw.ai/install/gcp

## Platforms and OS
- Platforms: https://docs.openclaw.ai/platforms
- Linux support: https://docs.openclaw.ai/platforms/linux
- Windows support: https://docs.openclaw.ai/platforms/windows

## Agent and Memory
- Agent concepts: https://docs.openclaw.ai/concepts/agent
- Memory concepts: https://docs.openclaw.ai/concepts/memory

## Channels
- Telegram: https://docs.openclaw.ai/channels/telegram
- Discord: https://docs.openclaw.ai/channels/discord
- Slack: https://docs.openclaw.ai/channels/slack

## Integrations
- Gmail: https://docs.openclaw.ai/integrations/gmail
- Google Calendar: https://docs.openclaw.ai/integrations/google-calendar

## Security
- Security overview: https://docs.openclaw.ai/security
- Remote access hardening: https://docs.openclaw.ai/remote-access
- VPN/Tailscale: https://docs.openclaw.ai/vpn/tailscale

## Legacy/Open Source Compatibility
- Open source repo: https://github.com/openclaw/openclaw
- Moltbot Fly baseline (legacy reference): https://github.com/hollaugo/moltbot-fly-deployer

```

### references/openclaw-security-checklist.md

```markdown
# OpenClaw Security Checklist

Use this checklist before considering deployment complete.

## Gate 1: Secrets Profile Validation (Mandatory)
Fail conditions:
- missing required keys for active profile
- placeholder values
- duplicate/malformed env keys
- weak gateway/setup tokens

Pass criteria:
- `scripts/validate_openclaw_env.py` exits 0 for active profile
- required model/provider alternatives are satisfied

## Gate 2: Network and Exposure Boundaries (Mandatory)
Fail conditions:
- public exposure without gateway auth token
- unnecessary open ports/routes
- debug/admin endpoints accessible from public internet

Pass criteria:
- TLS enforced for public exposure
- ingress routes scoped to required surfaces
- private mode uses restricted network boundaries

## Gate 3: Channel and Integration Auth Boundaries (Mandatory)
Fail conditions:
- channel/integration credentials stored in plaintext config committed to git
- missing signature/token checks where supported
- auth failure logs leak sensitive payloads

Pass criteria:
- channel + integration credentials sourced from secret manager/env
- smoke tests confirm authenticated message/event path

## Gate 4: Runtime and Persistence Safety (Mandatory)
Fail conditions:
- no persistent state configuration where required
- restart corrupts state/memory
- backups unencrypted or broadly accessible

Pass criteria:
- persistent path and permissions validated
- restart behavior tested and documented
- backup controls documented

## Gate 5: Incident Readiness (Mandatory)
Fail conditions:
- rollback path missing or owner undefined
- token revocation flow undefined
- no operator runbook for common outages

Pass criteria:
- rollback, revocation, and escalation path documented
- on-call owner/date captured in ops ledger

## Gate 6: Supply Chain and Patch Posture (Mandatory)
Fail conditions:
- untracked runtime image/dependency versions
- no policy for critical vulnerability updates

Pass criteria:
- deployment artifact version tracked
- critical vulnerability patch/redeploy process documented

## Gate 7: Ops Ledger Completeness (Mandatory)
Fail conditions:
- missing required ledger events (`scope_lock`, `predeploy_validation`, `deploy_complete`, `security_gate`, `handover`)
- missing required metadata fields for latest run

Pass criteria:
- ledger entries exist for all mandatory events
- blockers and next actions are recorded with owner/date

## Go/No-Go Rule
Production go-live is blocked unless **all mandatory gates pass**.

```

### references/openclaw-mode-matrix.md

```markdown
# OpenClaw Mode Matrix

Use this matrix to choose the correct setup branch.

| Dimension | Local Mode | Hosted Mode |
|---|---|---|
| Primary path | Install + onboard on operator machine | Clone repo + provider deploy |
| Best for | Single operator, private workflows, rapid trial | Team/shared access, durable operations |
| Infra ownership | Local machine/WSL resources | Cloud account + provider runtime |
| Exposure defaults | Private-first | Provider ingress with explicit auth controls |
| Required profile | `local` | `hosted-fly`, `hosted-render`, `hosted-railway`, `hosted-hetzner`, `hosted-gcp` |
| Rollback model | Restore local config/state snapshot | Redeploy prior revision + restore persisted state |

## Decision Rules
1. If user wants minimal setup and no cloud account, prefer `local`.
2. If user needs always-on access, team usage, or managed ingress, prefer `hosted`.
3. If user has no rollback owner/runbook, block `prod` in either mode.

## Mode-Specific Hard Stops

### Local
- No profile validation pass for `local`
- Public exposure requested without gateway protections

### Hosted
- Provider-specific profile validation fails
- Persistent volume/state not configured before traffic
- Public ingress configured without token/auth boundaries

```

### references/openclaw-os-matrix.md

```markdown
# OpenClaw OS Matrix

Use this matrix to adapt commands and caveats for each platform.

| OS | Supported Path | Key Notes |
|---|---|---|
| macOS | local + hosted CLI workflows | Prefer Homebrew package installs where available; verify shell path exports. |
| Linux | local + hosted CLI workflows | Prefer distro package manager + systemd for daemonized local workflows. |
| Windows (WSL2) | local (inside WSL2) + hosted CLI workflows | Run OpenClaw tooling inside WSL2 Linux environment; avoid mixed host/WSL path assumptions. |

## Command Adaptation Guidance
1. Normalize path assumptions before writing state/config files.
2. Keep provider CLIs installed in the same environment where commands run.
3. For Windows users, require explicit confirmation that terminal is WSL2 before local install steps.

## OS-Specific Verification
- Confirm CLI binaries resolve (`which`/`command -v`) in active shell.
- Confirm state directory read/write behavior.
- Confirm restart behavior and local process persistence approach.

## Hard Stops
- Platform mismatch between declared OS and active execution environment.
- State path not writable in selected OS runtime.
- Required CLI missing and no secure install path chosen.

```

### references/openclaw-integrations-playbook.md

```markdown
# OpenClaw Integrations Playbook

This playbook covers integration onboarding for `email` and `calendar`.

## Integration Status Vocabulary
- `configured`
- `pending_credentials`
- `blocked`

## Email (Gmail) Path
Reference: https://docs.openclaw.ai/integrations/gmail

Checklist:
1. Confirm OAuth/API credentials are provisioned for active environment.
2. Store secrets in env/provider secret manager.
3. Validate account authorization and token refresh behavior.
4. Run a smoke test (fetch inbox metadata only).
5. Verify logs avoid sensitive payload/token leakage.

Blockers:
- OAuth/client credentials missing
- refresh token flow failing
- auth errors not observable in logs

## Calendar (Google Calendar) Path
Reference: https://docs.openclaw.ai/integrations/google-calendar

Checklist:
1. Confirm calendar API credentials are provisioned for active environment.
2. Store credentials in env/provider secret manager.
3. Validate authorization scope minimums.
4. Run a smoke test (list upcoming events metadata only).
5. Verify logs avoid sensitive payload/token leakage.

Blockers:
- missing API access/scope
- failed refresh/consent flow
- unbounded privileged scopes

## Recording Requirements
For each selected integration, record in the ops ledger:
- status
- credentials source (name only)
- smoke-test result
- blockers and owner

```

### references/openclaw-ops-ledger-schema.md

```markdown
# OpenClaw Ops Ledger Schema

Use this schema for every ledger entry.

## Required Fields
- `timestamp_utc`
- `event`
- `operator`
- `mode`
- `provider`
- `os`
- `environment`
- `secrets_profile`
- `channels`
- `integrations`
- `security_status`
- `blocking_issues`
- `rollback_tested`
- `next_owner`
- `next_action_date`

## Event Types
- `scope_lock`
- `predeploy_validation`
- `deploy_complete`
- `security_gate`
- `handover`
- `incident`

## Rules
1. Never record secret values.
2. Record profile and key names only.
3. Keep one entry per event occurrence.
4. If `security_status=failed`, include actionable blockers.
5. `next_action_date` must be ISO date (`YYYY-MM-DD`).

## Example Entry
```markdown
## 2026-02-15T21:20:00Z | security_gate
- operator: codex
- mode: hosted
- provider: fly
- os: linux
- environment: prod
- secrets_profile: hosted-fly
- channels: telegram,slack
- integrations: email,calendar
- security_status: failed
- blocking_issues: gateway token rotation policy missing
- rollback_tested: no
- next_owner: platform-oncall
- next_action_date: 2026-02-16
```

```



---

## Skill Companion Files

> Additional files collected from the skill directory layout.

### _meta.json

```json
{
  "owner": "hollaugo",
  "slug": "openclaw-manager",
  "displayName": "Openclaw Manager",
  "latest": {
    "version": "0.1.1",
    "publishedAt": 1772174636860,
    "commit": "https://github.com/openclaw/skills/commit/796870c5d8ce1590ceb964f7ae2a9ee505550edf"
  },
  "history": []
}

```

openclaw-manager | SkillHub