About overwatcher
overwatcher is a skill for deploying Docker Compose services to a VM through Overwatcher and owctl. It guides agents through project setup, agent binding or installation, GitHub App checks, and deployment verification.
Key features
- 01Install and use owctl
- 02Inspect projects and agents
- 03Configure Compose services
- 04Bind or install VM agents
- 05Verify GitHub App access
Use cases
- 01Set up a project for VM deployment
- 02Reuse or install a deployment agent
- 03Check service triggers and configuration
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ lwlee2608/ overwatcher --skill overwatcherAfter installing, type/overwatcherin Claude Code to confirm it loaded.
Details
From the project READMEManaging Overwatcher Projects
Overwatcher deploys Docker Compose services on a VM when a GitHub repo is pushed or its CI workflow succeeds. Use owctl for every API operation; do not hand-roll API calls or handle agent tokens.
Rules
-
Install owctl if missing. If the installer fails, stop and report it; do not build from source unless asked.
curl -fsSL "${OVERWATCHER_URL:-https://overwatcher-web-production.up.railway.app}/cli.sh" | sh export PATH="$HOME/.local/bin:$PATH" -
Use existing credentials. owctl reads
OVERWATCHER_API_KEYor a savedowctl login. If it reports no API key, ask the user to runowctl loginin their terminal or setOVERWATCHER_API_KEY(create one under user menu → API keys). Never echo the key or pass it as an argument. -
Inspect the coordinator. Use
--json; stop on errors. Reuse a project with the same name instead of creating a duplicate.owctl project list --json owctl agent list --json owctl project get <project> --json -
Inspect the VM before asking anything else. Ask only for the SSH target, resolve aliases with
ssh -G <target>, then probe (read-only;sh -savoids zsh glob errors on the VM):ssh -T -o BatchMode=yes <target> sh -s <<'EOF' echo "user: $(id -un)" sudo -n true 2>/dev/null && echo "sudo: passwordless" || echo "sudo: needs password" command -v systemctl >/dev/null && echo "systemd: ok" || echo "systemd: missing" command -v curl >/dev/null && echo "curl: ok" || echo "curl: missing" systemctl show -p LoadState -p ActiveState overwatcher-agent 2>/dev/null docker compose version 2>/dev/null || echo "compose v2: missing" docker compose ls --all 2>/dev/null || echo "docker: no access for $(id -un)" EOFDo not read
/etc/overwatcher-agent.env; it holds the agent token. Then ask only what is still unknown, stating findings:LoadState=loaded: an agent exists. If it is inagent list(matchnameorremote_ip), offer to bind it instead of reinstalling; otherwise ask the user.- Offer
docker compose lsconfig files as the compose path. Without docker access, ask for the path; the installer adds the user to thedockergroup. - Missing sudo, systemd, curl, or Compose v2: stop until fixed.
-
Create the project with a confirmed compose path. The file must already exist on the VM (
ssh <target> test -r <path>).owctl project create <project> --compose-file <path> --environment production --json -
Derive services from the app repo. Take each field from the source, not defaults:
imagefrom the composeimage:line,workflowfrom the CI file that pushes it,tagfrom the tags it pushes,root_directoryfrom its buildcontext(never/in a monorepo). Use existing projects as a pattern.namemust equal the compose service key.service setreplaces the whole list, so keep existing services.owctl service set <project> -f - --json <<'EOF' services: - name: web repo: acme/my-app image: ghcr.io/acme/my-app-web tag: main branch: main root_directory: services/web workflow: build.yml EOFWithout
workflow, deploys fire on push and may pull a stale image. If one workflow builds several images, every run redeploys all of them; tell the user. -
Bind or install the agent. Binding moves an agent off its old project and replaces the project's current agent; ask before either.
owctl agent bind <agent-id> <project> --json owctl agent install --ssh <target> --project <project> --jsonInstall sets up a root-managed systemd service; get explicit approval before adding
--yes. On failure owctl revokes the agent but VM files may remain; report and do not retry blindly. The agent runs as the SSH user, which needs registry login for private images. -
Check GitHub App access. Without it, CI passes but nothing deploys. owctl cannot check this; use
gh(needs theread:userscope; if missing, ask the user to rungh auth refresh -h github.com -s read:user):gh api user/installations --jq '.installations[] | select(.app_slug=="overwatcher-app") | {id, account: .account.login, repository_selection, events}' gh api user/installations/<id>/repositories --paginate --jq '.repositories[].full_name'The repo owner needs an installation whose
eventsincludepush(andworkflow_runwhen used). Ifrepository_selectionisselected, the repo must be listed. Otherwise send the user to the installation's Configure → Repository access and do not report setup as complete. GitHub does not resend earlier events; re-run the latest CI run after access is granted.
Verification
owctl project get <project> --json: checkcompose_file,enabled, and each service's fields.owctl agent list --json: the agent'sproject_idmatches andstatusisconnected.- The GitHub App check in rule 8 passes for every repo.
- Report project ID, agent name, and trigger per service. This does not prove a deploy succeeded.