mirror of
https://github.com/domfelipe/hermes-client-onboarding.git
synced 2026-08-07 09:16:39 +00:00
Initial release: Hermes client onboarding bootstrap + skill
One-liner install.sh, conversational skill for OpenRouter/DeepSeek V4 Flash + Telegram gateway, and DomHubs client demo flow.
This commit is contained in:
commit
4c33662ead
6 changed files with 807 additions and 0 deletions
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
.DS_Store
|
||||||
|
*.swp
|
||||||
|
*~
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
128
README.md
Normal file
128
README.md
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
# Hermes Client Onboarding (DomHubs)
|
||||||
|
|
||||||
|
One-liner + skill conversacional para deixar o **Hermes Agent** pronto no cliente em minutos:
|
||||||
|
|
||||||
|
- OpenRouter + `deepseek/deepseek-v4-flash`
|
||||||
|
- Telegram (gateway como serviço)
|
||||||
|
- Personalidade em `SOUL.md`
|
||||||
|
- Setup guiado por LLM (Codex ou Hermes)
|
||||||
|
|
||||||
|
## One-liner (produção)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://setup.domhubs.com.br/hermes | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
Variantes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# só instalar skill + Hermes, sem abrir agente
|
||||||
|
curl -fsSL https://setup.domhubs.com.br/hermes | bash -s -- --no-launch
|
||||||
|
|
||||||
|
# forçar condutor
|
||||||
|
curl -fsSL https://setup.domhubs.com.br/hermes | bash -s -- --conductor hermes
|
||||||
|
curl -fsSL https://setup.domhubs.com.br/hermes | bash -s -- --conductor codex
|
||||||
|
```
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
install.sh # bootstrap
|
||||||
|
skill/hermes-client-onboarding/
|
||||||
|
SKILL.md
|
||||||
|
references/troubleshooting.md
|
||||||
|
scripts/apply-core-config.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
O bootstrap:
|
||||||
|
|
||||||
|
1. Instala Hermes se faltar (`--skip-browser`)
|
||||||
|
2. Copia a skill para `~/.hermes/skills/hermes-client-onboarding/`
|
||||||
|
3. Copia também para `~/.codex/skills/` e `~/.agents/skills/` se existirem
|
||||||
|
4. Pergunta o condutor (Codex / Hermes / skip) e abre o chat com a skill
|
||||||
|
|
||||||
|
## Uso local (dev)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd hermes-client-onboarding
|
||||||
|
chmod +x install.sh skill/hermes-client-onboarding/scripts/apply-core-config.sh
|
||||||
|
./install.sh --no-launch # instala skill local sem abrir TUI
|
||||||
|
./install.sh --conductor hermes # abre Hermes com skill
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hospedagem do one-liner
|
||||||
|
|
||||||
|
O `install.sh` baixa a skill de `HERMES_ONBOARD_BASE` (default `https://setup.domhubs.com.br/hermes`) quando **não** está rodando a partir de um checkout com `skill/`.
|
||||||
|
|
||||||
|
### Opção A — Domínio próprio (recomendado)
|
||||||
|
|
||||||
|
Publique arquivos estáticos:
|
||||||
|
|
||||||
|
| URL | Arquivo |
|
||||||
|
|-----|---------|
|
||||||
|
| `https://setup.domhubs.com.br/hermes` | `install.sh` (Content-Type: text/plain) |
|
||||||
|
| `https://setup.domhubs.com.br/hermes/skill/hermes-client-onboarding/SKILL.md` | skill |
|
||||||
|
| `.../references/troubleshooting.md` | ref |
|
||||||
|
| `.../scripts/apply-core-config.sh` | script |
|
||||||
|
|
||||||
|
Nginx/Caddy exemplo (path prefix `/hermes` → root do repo, com rewrite de `/hermes` → `install.sh`).
|
||||||
|
|
||||||
|
### Opção B — GitHub raw
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export HERMES_ONBOARD_BASE="https://raw.githubusercontent.com/<org>/hermes-client-onboarding/main"
|
||||||
|
curl -fsSL "$HERMES_ONBOARD_BASE/install.sh" | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
Ou grave esse `BASE` no topo do `install.sh` antes de publicar.
|
||||||
|
|
||||||
|
### Opção C — Gist
|
||||||
|
|
||||||
|
Gist single-file só serve se a skill for embutida. Prefira repo/GitHub raw.
|
||||||
|
|
||||||
|
## Stack padrão (decisões)
|
||||||
|
|
||||||
|
| Item | Valor |
|
||||||
|
|------|--------|
|
||||||
|
| Modelo | `deepseek/deepseek-v4-flash` via OpenRouter |
|
||||||
|
| Canal | Telegram |
|
||||||
|
| Gateway | `hermes gateway install` (systemd/launchd) |
|
||||||
|
| Soul | `~/.hermes/SOUL.md` |
|
||||||
|
| Alvo | Ubuntu/Debian VM limpa |
|
||||||
|
|
||||||
|
## Validação manual (VM limpa)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. bootstrap
|
||||||
|
./install.sh --no-launch
|
||||||
|
|
||||||
|
# 2. skill presente
|
||||||
|
test -f ~/.hermes/skills/hermes-client-onboarding/SKILL.md && echo skill_ok
|
||||||
|
|
||||||
|
# 3. hermes ok
|
||||||
|
hermes --version
|
||||||
|
hermes doctor
|
||||||
|
|
||||||
|
# 4. onboarding interativo
|
||||||
|
hermes chat -s hermes-client-onboarding
|
||||||
|
# completar fases 1–6 com chaves reais de teste
|
||||||
|
|
||||||
|
# 5. smoke telegram
|
||||||
|
hermes gateway status
|
||||||
|
# enviar "oi" no bot
|
||||||
|
```
|
||||||
|
|
||||||
|
## Helper de config
|
||||||
|
|
||||||
|
```bash
|
||||||
|
~/.hermes/skills/hermes-client-onboarding/scripts/apply-core-config.sh \
|
||||||
|
--openrouter-key "$OPENROUTER_API_KEY" \
|
||||||
|
--telegram-token "$TELEGRAM_BOT_TOKEN" \
|
||||||
|
--allowed-users "123456789"
|
||||||
|
```
|
||||||
|
|
||||||
|
Não imprime secrets.
|
||||||
|
|
||||||
|
## Licença
|
||||||
|
|
||||||
|
MIT (skill + bootstrap DomHubs). Hermes Agent em si: licença do projeto Nous Research.
|
||||||
257
install.sh
Executable file
257
install.sh
Executable file
|
|
@ -0,0 +1,257 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# DomHubs — Hermes Client Onboarding bootstrap
|
||||||
|
# One-liner: curl -fsSL https://setup.domhubs.com.br/hermes | bash
|
||||||
|
# Local: ./install.sh [--conductor codex|hermes|skip] [--no-launch]
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SKILL_NAME="hermes-client-onboarding"
|
||||||
|
DEFAULT_BASE="${HERMES_ONBOARD_BASE:-https://setup.domhubs.com.br/hermes}"
|
||||||
|
HERMES_INSTALL_URL="${HERMES_INSTALL_URL:-https://hermes-agent.nousresearch.com/install.sh}"
|
||||||
|
KICKOFF_MSG="${HERMES_ONBOARD_KICKOFF:-Inicie agora o onboarding de cliente Hermes. Siga a skill hermes-client-onboarding fase a fase (Phase 1 primeiro). Fale em português brasileiro.}"
|
||||||
|
|
||||||
|
CONDUCTOR="${HERMES_ONBOARD_CONDUCTOR:-}"
|
||||||
|
NO_LAUNCH=0
|
||||||
|
NONINTERACTIVE=0
|
||||||
|
|
||||||
|
log() { printf '==> %s\n' "$*"; }
|
||||||
|
warn() { printf 'warn: %s\n' "$*" >&2; }
|
||||||
|
die() { printf 'error: %s\n' "$*" >&2; exit 1; }
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: install.sh [options]
|
||||||
|
|
||||||
|
--conductor codex|hermes|skip Who runs the guided onboarding (default: prompt)
|
||||||
|
--no-launch Install only; do not start the conductor
|
||||||
|
--base URL Asset base for skill files (or HERMES_ONBOARD_BASE)
|
||||||
|
--non-interactive No prompts; default conductor=hermes if unset
|
||||||
|
-h, --help Show help
|
||||||
|
|
||||||
|
Env:
|
||||||
|
HERMES_ONBOARD_BASE, HERMES_ONBOARD_CONDUCTOR, HERMES_ONBOARD_KICKOFF
|
||||||
|
HERMES_INSTALL_URL, HERMES_ONBOARD_NO_LAUNCH=1
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--conductor) CONDUCTOR="${2:-}"; shift 2 ;;
|
||||||
|
--no-launch) NO_LAUNCH=1; shift ;;
|
||||||
|
--base) DEFAULT_BASE="${2:-}"; shift 2 ;;
|
||||||
|
--non-interactive) NONINTERACTIVE=1; shift ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) die "unknown arg: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ "${HERMES_ONBOARD_NO_LAUNCH:-0}" == "1" ]] && NO_LAUNCH=1
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Resolve skill source: local checkout vs remote base URL
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
SCRIPT_PATH="${BASH_SOURCE[0]:-}"
|
||||||
|
SCRIPT_DIR=""
|
||||||
|
if [[ -n "$SCRIPT_PATH" && -f "$SCRIPT_PATH" ]]; then
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_PATH")" && pwd)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
LOCAL_SKILL=""
|
||||||
|
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/skill/${SKILL_NAME}/SKILL.md" ]]; then
|
||||||
|
LOCAL_SKILL="$SCRIPT_DIR/skill/${SKILL_NAME}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
need_cmd() { command -v "$1" >/dev/null 2>&1; }
|
||||||
|
|
||||||
|
os_name="$(uname -s 2>/dev/null || echo unknown)"
|
||||||
|
case "$os_name" in
|
||||||
|
Linux|Darwin) ;;
|
||||||
|
*) warn "untested OS: $os_name (expected Linux Ubuntu/Debian for production demos)" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ "$os_name" == "Darwin" ]]; then
|
||||||
|
warn "macOS detected — gateway uses launchd; production clients should be Ubuntu/Debian VMs"
|
||||||
|
fi
|
||||||
|
|
||||||
|
export PATH="${HOME}/.local/bin:${PATH}"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Ensure Hermes
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
ensure_hermes() {
|
||||||
|
if need_cmd hermes; then
|
||||||
|
log "Hermes already installed: $(hermes --version 2>/dev/null | head -1 || echo ok)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
log "Installing Hermes (--skip-browser)..."
|
||||||
|
need_cmd curl || die "curl is required"
|
||||||
|
curl -fsSL "$HERMES_INSTALL_URL" | bash -s -- --skip-browser
|
||||||
|
export PATH="${HOME}/.local/bin:${PATH}"
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
source "${HOME}/.bashrc" 2>/dev/null || true
|
||||||
|
need_cmd hermes || die "Hermes install finished but 'hermes' not on PATH. Open a new shell or: export PATH=\"\$HOME/.local/bin:\$PATH\""
|
||||||
|
log "Hermes installed: $(hermes --version 2>/dev/null | head -1 || echo ok)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Install skill into Hermes (+ Codex/agents if present)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
copy_tree() {
|
||||||
|
local src="$1" dest="$2"
|
||||||
|
mkdir -p "$dest"
|
||||||
|
# portable: prefer cp -R then fix modes
|
||||||
|
rm -rf "${dest:?}/"*
|
||||||
|
cp -R "$src"/. "$dest"/
|
||||||
|
if [[ -f "$dest/scripts/apply-core-config.sh" ]]; then
|
||||||
|
chmod +x "$dest/scripts/apply-core-config.sh"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch_skill_to() {
|
||||||
|
local dest="$1"
|
||||||
|
local base="$DEFAULT_BASE"
|
||||||
|
need_cmd curl || die "curl is required to download skill assets"
|
||||||
|
mkdir -p "$dest/references" "$dest/scripts"
|
||||||
|
log "Downloading skill from ${base}/skill/${SKILL_NAME}/ ..."
|
||||||
|
curl -fsSL "${base}/skill/${SKILL_NAME}/SKILL.md" -o "$dest/SKILL.md"
|
||||||
|
curl -fsSL "${base}/skill/${SKILL_NAME}/references/troubleshooting.md" -o "$dest/references/troubleshooting.md"
|
||||||
|
curl -fsSL "${base}/skill/${SKILL_NAME}/scripts/apply-core-config.sh" -o "$dest/scripts/apply-core-config.sh"
|
||||||
|
chmod +x "$dest/scripts/apply-core-config.sh"
|
||||||
|
[[ -s "$dest/SKILL.md" ]] || die "failed to download SKILL.md from $base"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_skill() {
|
||||||
|
local staging
|
||||||
|
staging="$(mktemp -d)"
|
||||||
|
# shellcheck disable=SC2064
|
||||||
|
trap "rm -rf '$staging'" RETURN
|
||||||
|
|
||||||
|
if [[ -n "$LOCAL_SKILL" ]]; then
|
||||||
|
log "Using local skill: $LOCAL_SKILL"
|
||||||
|
copy_tree "$LOCAL_SKILL" "$staging"
|
||||||
|
else
|
||||||
|
fetch_skill_to "$staging"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local hermes_dest="${HOME}/.hermes/skills/${SKILL_NAME}"
|
||||||
|
mkdir -p "${HOME}/.hermes/skills"
|
||||||
|
copy_tree "$staging" "$hermes_dest"
|
||||||
|
log "Skill installed for Hermes → $hermes_dest"
|
||||||
|
|
||||||
|
# Codex / agents (optional)
|
||||||
|
if [[ -d "${HOME}/.codex" ]] || need_cmd codex; then
|
||||||
|
mkdir -p "${HOME}/.codex/skills"
|
||||||
|
copy_tree "$staging" "${HOME}/.codex/skills/${SKILL_NAME}"
|
||||||
|
log "Skill installed for Codex → ~/.codex/skills/${SKILL_NAME}"
|
||||||
|
fi
|
||||||
|
if [[ -d "${HOME}/.agents/skills" ]]; then
|
||||||
|
copy_tree "$staging" "${HOME}/.agents/skills/${SKILL_NAME}"
|
||||||
|
log "Skill installed for agents → ~/.agents/skills/${SKILL_NAME}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Conductor selection + launch
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
pick_conductor() {
|
||||||
|
if [[ -n "$CONDUCTOR" ]]; then
|
||||||
|
echo "$CONDUCTOR"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [[ "$NONINTERACTIVE" -eq 1 ]]; then
|
||||||
|
if need_cmd codex; then echo codex; else echo hermes; fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
# curl|bash: stdin is the script pipe — read prompts from the real TTY when possible
|
||||||
|
local tty_in="/dev/tty"
|
||||||
|
if [[ ! -r "$tty_in" ]]; then
|
||||||
|
if need_cmd codex; then echo codex; else echo hermes; fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local has_codex=0
|
||||||
|
need_cmd codex && has_codex=1
|
||||||
|
|
||||||
|
echo "" >&2
|
||||||
|
echo "Quem deve conduzir o onboarding conversacional?" >&2
|
||||||
|
if [[ "$has_codex" -eq 1 ]]; then
|
||||||
|
echo " 1) Codex (recomendado se disponível)" >&2
|
||||||
|
echo " 2) Hermes (modelos baratos / já instalado)" >&2
|
||||||
|
echo " 3) Só instalar skill — não abrir agente" >&2
|
||||||
|
printf "Escolha [1]: " >&2
|
||||||
|
read -r ans <"$tty_in" || ans=1
|
||||||
|
case "${ans:-1}" in
|
||||||
|
2|hermes|h) echo hermes ;;
|
||||||
|
3|skip|s) echo skip ;;
|
||||||
|
*) echo codex ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
echo " 1) Hermes" >&2
|
||||||
|
echo " 2) Só instalar skill — não abrir agente" >&2
|
||||||
|
printf "Escolha [1]: " >&2
|
||||||
|
read -r ans <"$tty_in" || ans=1
|
||||||
|
case "${ans:-1}" in
|
||||||
|
2|skip|s) echo skip ;;
|
||||||
|
*) echo hermes ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
launch_conductor() {
|
||||||
|
local c="$1"
|
||||||
|
case "$c" in
|
||||||
|
skip)
|
||||||
|
log "Skill pronta. Rode depois:"
|
||||||
|
echo " hermes chat -s ${SKILL_NAME}"
|
||||||
|
need_cmd codex && echo " codex \"${KICKOFF_MSG}\""
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
hermes)
|
||||||
|
need_cmd hermes || die "hermes missing"
|
||||||
|
log "Abrindo Hermes com skill ${SKILL_NAME}..."
|
||||||
|
echo ""
|
||||||
|
echo "────────────────────────────────────────"
|
||||||
|
echo "Quando o chat abrir, envie (ou já use):"
|
||||||
|
echo " ${KICKOFF_MSG}"
|
||||||
|
echo "────────────────────────────────────────"
|
||||||
|
echo ""
|
||||||
|
# Reattach stdin to TTY after curl|bash so the chat is interactive
|
||||||
|
if [[ -r /dev/tty ]]; then
|
||||||
|
exec hermes chat -s "$SKILL_NAME" </dev/tty
|
||||||
|
else
|
||||||
|
exec hermes chat -s "$SKILL_NAME"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
codex)
|
||||||
|
need_cmd codex || die "codex not found — install Codex or use --conductor hermes"
|
||||||
|
log "Abrindo Codex com kickoff de onboarding..."
|
||||||
|
if [[ -r /dev/tty ]]; then
|
||||||
|
exec codex --sandbox danger-full-access "$KICKOFF_MSG" </dev/tty
|
||||||
|
else
|
||||||
|
exec codex --sandbox danger-full-access "$KICKOFF_MSG"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "unknown conductor: $c"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
main() {
|
||||||
|
log "DomHubs Hermes Client Onboarding"
|
||||||
|
ensure_hermes
|
||||||
|
install_skill
|
||||||
|
|
||||||
|
if [[ "$NO_LAUNCH" -eq 1 ]]; then
|
||||||
|
log "Done (--no-launch). Start with:"
|
||||||
|
echo " hermes chat -s ${SKILL_NAME}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local c
|
||||||
|
c="$(pick_conductor)"
|
||||||
|
log "Conductor: $c"
|
||||||
|
launch_conductor "$c"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
249
skill/hermes-client-onboarding/SKILL.md
Normal file
249
skill/hermes-client-onboarding/SKILL.md
Normal file
|
|
@ -0,0 +1,249 @@
|
||||||
|
---
|
||||||
|
name: hermes-client-onboarding
|
||||||
|
description: Use when setting up Hermes for a client, install Hermes + Telegram + OpenRouter, run a demo setup, or launch client onboarding. Conducts guided conversational onboarding on a clean Linux VM (deepseek/deepseek-v4-flash, Telegram gateway, systemd, SOUL.md).
|
||||||
|
version: 1.0.0
|
||||||
|
author: DomHubs
|
||||||
|
license: MIT
|
||||||
|
platforms: [linux, macos]
|
||||||
|
metadata:
|
||||||
|
hermes:
|
||||||
|
tags: [onboarding, client, telegram, openrouter, deepseek, gateway, demo]
|
||||||
|
related_skills: []
|
||||||
|
---
|
||||||
|
|
||||||
|
# Hermes Client Onboarding
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
You are conducting a professional, step-by-step onboarding of Hermes Agent on a clean Ubuntu/Debian VM so a client can start using it immediately (primarily via Telegram). The goal is a working agent in minutes, with OpenRouter + DeepSeek V4 Flash as the default model, Telegram as the primary channel, and the gateway running as a persistent service.
|
||||||
|
|
||||||
|
This skill is designed for live demos in front of the client and for commercial handoff. Be clear, structured, and efficient. Always confirm critical values before applying them.
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
- User asks to set up Hermes for a client
|
||||||
|
- Demo setup of Hermes + Telegram + OpenRouter
|
||||||
|
- Launch of the DomHubs client onboarding flow
|
||||||
|
- Fresh VM that needs Hermes ready end-to-end
|
||||||
|
|
||||||
|
Don't use for: day-to-day Hermes coding tasks after onboarding is done; multi-tenant fleet orchestration; non-Hermes agent installs.
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
The onboarding is complete only when all of the following are true:
|
||||||
|
|
||||||
|
- Hermes is installed and `hermes` command works
|
||||||
|
- Model is set to `deepseek/deepseek-v4-flash` via OpenRouter
|
||||||
|
- `OPENROUTER_API_KEY` is configured
|
||||||
|
- Telegram bot token and at least one allowed user ID are set
|
||||||
|
- Gateway is installed as a systemd service and is running
|
||||||
|
- A test message sent to the Telegram bot receives a coherent reply
|
||||||
|
- `hermes doctor` reports no critical errors
|
||||||
|
- SOUL.md has been personalized (or the user explicitly skipped it)
|
||||||
|
|
||||||
|
## Pre-flight Checks (do these first)
|
||||||
|
|
||||||
|
Run these checks silently or with minimal output before starting the dialogue:
|
||||||
|
|
||||||
|
1. Confirm you are on Linux (preferably Ubuntu 22.04/24.04 or Debian). On macOS, warn that gateway persistence differs (launchd) and demos still work.
|
||||||
|
2. Check if `hermes` is already in PATH. If yes, note the version with `hermes --version`.
|
||||||
|
3. Check available disk space and RAM (`df -h /` and `free -h`). Warn if RAM < 2 GB or free disk < 5 GB.
|
||||||
|
4. Verify internet connectivity (can reach `https://hermes-agent.nousresearch.com` and `https://openrouter.ai`).
|
||||||
|
|
||||||
|
If Hermes is missing, install it with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash -s -- --skip-browser
|
||||||
|
source ~/.bashrc 2>/dev/null || true
|
||||||
|
export PATH="$HOME/.local/bin:$PATH"
|
||||||
|
```
|
||||||
|
|
||||||
|
After install, confirm with `hermes --version` and `hermes doctor`.
|
||||||
|
|
||||||
|
**Done when:** OS/resources known, Hermes on PATH, version recorded.
|
||||||
|
|
||||||
|
## Conversational Flow
|
||||||
|
|
||||||
|
Conduct the onboarding as a structured dialogue. Move phase by phase. Never skip confirmation of secrets or user IDs.
|
||||||
|
|
||||||
|
### Phase 1 — Context & Goals
|
||||||
|
|
||||||
|
Ask:
|
||||||
|
|
||||||
|
- Is this a live demo in front of the client or a setup you will hand over later?
|
||||||
|
- What is the client/company name? (used later in SOUL.md)
|
||||||
|
- Preferred language for the agent (default: Portuguese Brazilian)
|
||||||
|
- Will the client interact mainly via Telegram? (yes/no — we still set Telegram as primary)
|
||||||
|
|
||||||
|
**Done when:** demo vs handoff, company name, language, and channel intent confirmed.
|
||||||
|
|
||||||
|
### Phase 2 — OpenRouter Credentials
|
||||||
|
|
||||||
|
1. Ask for the OpenRouter API key (format usually starts with `sk-or-v1-`).
|
||||||
|
2. Confirm the key is present and looks valid (do not echo the full key back).
|
||||||
|
3. Apply it (prefer `scripts/apply-core-config.sh` when you already have Telegram values too; otherwise set now):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hermes config set OPENROUTER_API_KEY "THE_KEY"
|
||||||
|
hermes config set model.provider openrouter
|
||||||
|
hermes config set model.default deepseek/deepseek-v4-flash
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Verify with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hermes config get model.default
|
||||||
|
hermes config get model.provider
|
||||||
|
```
|
||||||
|
|
||||||
|
Optional: Offer to set a fallback model (e.g. another cheap OpenRouter model) if the user wants resilience.
|
||||||
|
|
||||||
|
**Done when:** provider=openrouter, model=deepseek/deepseek-v4-flash, key set without printing it.
|
||||||
|
|
||||||
|
### Phase 3 — Telegram Bot
|
||||||
|
|
||||||
|
1. Guide the user (or do it yourself if they give you the token) to create a bot with @BotFather if they do not have one yet.
|
||||||
|
2. Collect:
|
||||||
|
- `TELEGRAM_BOT_TOKEN`
|
||||||
|
- At least one numeric User ID (from @userinfobot or @get_id_bot). Multiple IDs can be comma-separated.
|
||||||
|
3. Apply:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hermes config set TELEGRAM_BOT_TOKEN "TOKEN"
|
||||||
|
hermes config set TELEGRAM_ALLOWED_USERS "ID1,ID2"
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Optional advanced settings (only if requested):
|
||||||
|
- Home channel for proactive messages
|
||||||
|
- Group chat IDs
|
||||||
|
|
||||||
|
**Done when:** token set, at least one allowed user ID set, values repeated back (IDs only, never full token).
|
||||||
|
|
||||||
|
### Phase 4 — Agent Personality (SOUL.md)
|
||||||
|
|
||||||
|
Ask how the agent should present itself. Offer a default template and let the user customize.
|
||||||
|
|
||||||
|
Default template (adapt with company name and language):
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
Você é o assistente oficial da [Nome da Empresa].
|
||||||
|
Responda sempre em português brasileiro de forma clara, profissional, objetiva e prestativa.
|
||||||
|
Você tem memória persistente e pode usar ferramentas para ajudar o usuário em tarefas reais.
|
||||||
|
```
|
||||||
|
|
||||||
|
Write the final content to `~/.hermes/SOUL.md`. Confirm before overwriting if the file already exists.
|
||||||
|
|
||||||
|
**Done when:** SOUL.md written or user explicitly skipped personalization.
|
||||||
|
|
||||||
|
### Phase 5 — Gateway & Persistence
|
||||||
|
|
||||||
|
1. Install the gateway as a system service:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hermes gateway install
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Start / restart it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hermes gateway start
|
||||||
|
# or
|
||||||
|
hermes gateway restart
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Check status:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hermes gateway status
|
||||||
|
```
|
||||||
|
|
||||||
|
4. If the service fails, inspect logs (`hermes gateway logs` or `journalctl -u hermes* -n 50` / `launchctl` on macOS) and fix common issues (PATH, missing env, permissions). See `references/troubleshooting.md`.
|
||||||
|
|
||||||
|
**Done when:** gateway status shows running and service is installed for reboot persistence.
|
||||||
|
|
||||||
|
### Phase 6 — Validation & Handover
|
||||||
|
|
||||||
|
Run the full validation sequence:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hermes doctor
|
||||||
|
hermes gateway status
|
||||||
|
```
|
||||||
|
|
||||||
|
Then instruct the user to send a test message to the Telegram bot (“oi” ou “teste”). Confirm that a coherent reply arrives.
|
||||||
|
|
||||||
|
Final checklist to present to the user:
|
||||||
|
|
||||||
|
- [ ] Hermes installed and in PATH
|
||||||
|
- [ ] Model = deepseek/deepseek-v4-flash via OpenRouter
|
||||||
|
- [ ] Telegram bot responding
|
||||||
|
- [ ] Gateway running as service (survives reboot)
|
||||||
|
- [ ] SOUL.md personalized
|
||||||
|
- [ ] `hermes doctor` clean
|
||||||
|
|
||||||
|
Give the user the useful commands for later:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hermes gateway status
|
||||||
|
hermes gateway logs
|
||||||
|
hermes doctor
|
||||||
|
hermes config get model.default
|
||||||
|
hermes update
|
||||||
|
```
|
||||||
|
|
||||||
|
**Done when:** checklist walked, test Telegram reply confirmed, useful commands delivered.
|
||||||
|
|
||||||
|
## Error Handling Guidelines
|
||||||
|
|
||||||
|
- If `hermes config set` fails, check file permissions on `~/.hermes/.env` and `~/.hermes/config.yaml`.
|
||||||
|
- If Telegram does not respond: verify token with a direct `getMe` call, confirm Allowed Users, restart gateway, check logs for connection errors.
|
||||||
|
- If OpenRouter returns auth errors: re-validate the key and model name (`deepseek/deepseek-v4-flash`).
|
||||||
|
- Prefer fixing issues yourself when possible, then explain what was wrong in plain language.
|
||||||
|
- Never leave the system in a half-configured state. Either finish a phase or clearly roll back.
|
||||||
|
|
||||||
|
## Style & Tone While Onboarding
|
||||||
|
|
||||||
|
- Professional and calm (you are in front of a client or preparing a commercial handoff).
|
||||||
|
- Short confirmations after each successful step.
|
||||||
|
- Always repeat back critical non-secret values (model name, allowed user IDs, company name).
|
||||||
|
- Never print full API keys or bot tokens in the conversation.
|
||||||
|
- Prefer Portuguese when the user is speaking Portuguese.
|
||||||
|
|
||||||
|
## Optional Extensions (only if requested)
|
||||||
|
|
||||||
|
- Add Discord or WhatsApp after Telegram is working.
|
||||||
|
- Switch to native DeepSeek provider later (`DEEPSEEK_API_KEY` + provider `deepseek`).
|
||||||
|
- Enable extra tools or change terminal backend.
|
||||||
|
- Create additional allowlisted users.
|
||||||
|
- Set up a simple cron job or home channel for proactive messages.
|
||||||
|
|
||||||
|
## Supporting Resources
|
||||||
|
|
||||||
|
- `references/troubleshooting.md` — detailed fixes for the most common failures (Telegram not replying, auth errors, service problems, PATH issues).
|
||||||
|
- `scripts/apply-core-config.sh` — safe helper to apply OpenRouter key + model + Telegram token + allowed users in one go. Prefer using it when you already have all three values confirmed.
|
||||||
|
|
||||||
|
## Reference Commands (quick lookup)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install
|
||||||
|
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash -s -- --skip-browser
|
||||||
|
|
||||||
|
# Core config (or use the helper script)
|
||||||
|
hermes config set OPENROUTER_API_KEY "sk-or-..."
|
||||||
|
hermes config set model.provider openrouter
|
||||||
|
hermes config set model.default deepseek/deepseek-v4-flash
|
||||||
|
hermes config set TELEGRAM_BOT_TOKEN "..."
|
||||||
|
hermes config set TELEGRAM_ALLOWED_USERS "123456789"
|
||||||
|
|
||||||
|
# Gateway
|
||||||
|
hermes gateway install
|
||||||
|
hermes gateway start
|
||||||
|
hermes gateway status
|
||||||
|
hermes gateway logs
|
||||||
|
|
||||||
|
# Validation
|
||||||
|
hermes doctor
|
||||||
|
hermes --version
|
||||||
|
```
|
||||||
|
|
||||||
|
When the user says the onboarding is finished or the bot is responding correctly, summarize what was configured and congratulate them. Offer to make any final adjustments.
|
||||||
99
skill/hermes-client-onboarding/references/troubleshooting.md
Normal file
99
skill/hermes-client-onboarding/references/troubleshooting.md
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
# Troubleshooting — Hermes Client Onboarding
|
||||||
|
|
||||||
|
## PATH / `hermes: command not found`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export PATH="$HOME/.local/bin:$PATH"
|
||||||
|
# persist
|
||||||
|
grep -q '.local/bin' ~/.bashrc 2>/dev/null || echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
|
||||||
|
hash -r
|
||||||
|
hermes --version
|
||||||
|
```
|
||||||
|
|
||||||
|
Re-run install if still missing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash -s -- --skip-browser
|
||||||
|
```
|
||||||
|
|
||||||
|
## OpenRouter auth errors
|
||||||
|
|
||||||
|
1. Confirm key format (`sk-or-v1-...`) without pasting full key into chat.
|
||||||
|
2. Re-set:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hermes config set OPENROUTER_API_KEY "THE_KEY"
|
||||||
|
hermes config set model.provider openrouter
|
||||||
|
hermes config set model.default deepseek/deepseek-v4-flash
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Check:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hermes config get model.default
|
||||||
|
hermes config get model.provider
|
||||||
|
# key lives in ~/.hermes/.env — never cat full file in front of client
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Test connectivity: `curl -sI https://openrouter.ai | head -1`
|
||||||
|
|
||||||
|
## Telegram bot does not reply
|
||||||
|
|
||||||
|
1. Token validity:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# TOKEN from env; do not log it
|
||||||
|
source ~/.hermes/.env 2>/dev/null || true
|
||||||
|
curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getMe" | head -c 200
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Allowed users: numeric IDs only (from @userinfobot). Restart after change:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hermes config set TELEGRAM_ALLOWED_USERS "ID1,ID2"
|
||||||
|
hermes gateway restart
|
||||||
|
hermes gateway status
|
||||||
|
hermes gateway logs
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Common mistakes:
|
||||||
|
- User ID is username string instead of numeric ID
|
||||||
|
- Gateway not running
|
||||||
|
- Bot blocked by user / wrong bot
|
||||||
|
|
||||||
|
## Gateway service won't start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hermes gateway status
|
||||||
|
hermes gateway logs
|
||||||
|
# Linux
|
||||||
|
journalctl -u 'hermes*' -n 80 --no-pager
|
||||||
|
# macOS
|
||||||
|
# check launchd labels from hermes gateway status
|
||||||
|
```
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
- Ensure `~/.hermes/.env` readable by the service user
|
||||||
|
- Ensure `hermes` on PATH for the service unit (re-run `hermes gateway install`)
|
||||||
|
- Free port conflicts if any webhook mode is misconfigured
|
||||||
|
|
||||||
|
## `hermes config set` fails
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls -la ~/.hermes/.env ~/.hermes/config.yaml
|
||||||
|
# fix ownership if needed
|
||||||
|
chown "$USER" ~/.hermes/.env ~/.hermes/config.yaml
|
||||||
|
chmod 600 ~/.hermes/.env
|
||||||
|
```
|
||||||
|
|
||||||
|
## `hermes doctor` critical errors
|
||||||
|
|
||||||
|
Run `hermes doctor` and fix top critical items first (keys, model, gateway). Warnings about optional tools (browser, extra MCP) can wait until after Telegram works.
|
||||||
|
|
||||||
|
## Half-configured state recovery
|
||||||
|
|
||||||
|
If onboarding aborted mid-way:
|
||||||
|
|
||||||
|
1. `hermes config show` — see what's set
|
||||||
|
2. Finish remaining phases from the skill (do not reinstall unless broken)
|
||||||
|
3. `hermes gateway restart && hermes doctor`
|
||||||
68
skill/hermes-client-onboarding/scripts/apply-core-config.sh
Executable file
68
skill/hermes-client-onboarding/scripts/apply-core-config.sh
Executable file
|
|
@ -0,0 +1,68 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Apply OpenRouter + model + Telegram core config for Hermes client onboarding.
|
||||||
|
# Does not print secrets. Requires: hermes on PATH.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage:
|
||||||
|
apply-core-config.sh \
|
||||||
|
--openrouter-key KEY \
|
||||||
|
--telegram-token TOKEN \
|
||||||
|
--allowed-users ID1,ID2 \
|
||||||
|
[--model deepseek/deepseek-v4-flash] \
|
||||||
|
[--provider openrouter]
|
||||||
|
|
||||||
|
Env fallbacks (if flags omitted):
|
||||||
|
OPENROUTER_API_KEY, TELEGRAM_BOT_TOKEN, TELEGRAM_ALLOWED_USERS
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
MODEL="deepseek/deepseek-v4-flash"
|
||||||
|
PROVIDER="openrouter"
|
||||||
|
OR_KEY="${OPENROUTER_API_KEY:-}"
|
||||||
|
TG_TOKEN="${TELEGRAM_BOT_TOKEN:-}"
|
||||||
|
TG_USERS="${TELEGRAM_ALLOWED_USERS:-}"
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--openrouter-key) OR_KEY="${2:-}"; shift 2 ;;
|
||||||
|
--telegram-token) TG_TOKEN="${2:-}"; shift 2 ;;
|
||||||
|
--allowed-users) TG_USERS="${2:-}"; shift 2 ;;
|
||||||
|
--model) MODEL="${2:-}"; shift 2 ;;
|
||||||
|
--provider) PROVIDER="${2:-}"; shift 2 ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) echo "Unknown arg: $1" >&2; usage; exit 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! command -v hermes >/dev/null 2>&1; then
|
||||||
|
echo "error: hermes not found on PATH" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
missing=0
|
||||||
|
[[ -z "$OR_KEY" ]] && { echo "error: missing OpenRouter key" >&2; missing=1; }
|
||||||
|
[[ -z "$TG_TOKEN" ]] && { echo "error: missing Telegram bot token" >&2; missing=1; }
|
||||||
|
[[ -z "$TG_USERS" ]] && { echo "error: missing TELEGRAM_ALLOWED_USERS" >&2; missing=1; }
|
||||||
|
[[ "$missing" -eq 1 ]] && exit 1
|
||||||
|
|
||||||
|
# light validation (no secret echo)
|
||||||
|
if [[ ! "$OR_KEY" =~ ^sk-or- ]]; then
|
||||||
|
echo "warn: OpenRouter key does not start with sk-or- (continuing)" >&2
|
||||||
|
fi
|
||||||
|
if [[ ! "$TG_USERS" =~ ^[0-9]+(,[0-9]+)*$ ]]; then
|
||||||
|
echo "error: allowed users must be numeric IDs, comma-separated" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
hermes config set OPENROUTER_API_KEY "$OR_KEY"
|
||||||
|
hermes config set model.provider "$PROVIDER"
|
||||||
|
hermes config set model.default "$MODEL"
|
||||||
|
hermes config set TELEGRAM_BOT_TOKEN "$TG_TOKEN"
|
||||||
|
hermes config set TELEGRAM_ALLOWED_USERS "$TG_USERS"
|
||||||
|
|
||||||
|
echo "ok: provider=$(hermes config get model.provider 2>/dev/null || echo "$PROVIDER")"
|
||||||
|
echo "ok: model=$(hermes config get model.default 2>/dev/null || echo "$MODEL")"
|
||||||
|
echo "ok: allowed_users=$TG_USERS"
|
||||||
|
echo "ok: secrets written (not displayed)"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue