/welcome
First-touch experience for new Ouroboros users
$ npx -y skills add Q00/ouroboros --skill welcome --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/welcome
Context preview
The summary Claude sees to decide when to auto-load this skill.
First-touch experience for new Ouroboros users
SKILL.md
welcome.SKILL.mdname: welcome
description: "First-touch experience for new Ouroboros users"
/ouroboros:welcome
Interactive onboarding for new Ouroboros users.
Usage
/ouroboros:welcome # First-time or update onboarding
/ouroboros:welcome --skip # Skip welcome, mark as shown
/ouroboros:welcome --force # Force re-run welcome even if shown
Instructions
When this skill is invoked, follow this flow:
Before running any shell snippets below, choose a Python command without assuming a system `python3` binary. Marketplace installs require `uvx`, not a global Python executable:
if [ -z "${OUROBOROS_WELCOME_PYTHON:-}" ]; then
if command -v python3 >/dev/null 2>&1; then
OUROBOROS_WELCOME_PYTHON="python3"
elif command -v python >/dev/null 2>&1; then
OUROBOROS_WELCOME_PYTHON="python"
elif command -v uv >/dev/null 2>&1; then
OUROBOROS_WELCOME_PYTHON="uv run --no-project --quiet python"
else
echo "Ouroboros welcome requires python3, python, or uv to inspect local setup."
exit 1
fi
fi---
Pre-Check: Already Completed?
First, check `~/.ouroboros/prefs.json` for `welcomeCompleted`. For upgrades from older releases, also treat legacy `welcomeShown: true` as completed so the welcome prompt does not reappear forever:
PREFFILE="$HOME/.ouroboros/prefs.json"
if [ -f "$PREFFILE" ]; then
WELCOME_COMPLETED=$($OUROBOROS_WELCOME_PYTHON - <<'PY'
import json, os
path = os.path.expanduser('~/.ouroboros/prefs.json')
try:
prefs = json.load(open(path, encoding='utf-8'))
except Exception:
prefs = {}
if not isinstance(prefs, dict):
prefs = {}
print(prefs.get('welcomeCompleted') or ('legacy-welcomeShown' if prefs.get('welcomeShown') else ''))
PY
)
WELCOME_VERSION=$($OUROBOROS_WELCOME_PYTHON - <<'PY'
import json, os
path = os.path.expanduser('~/.ouroboros/prefs.json')
try:
prefs = json.load(open(path, encoding='utf-8'))
except Exception:
prefs = {}
if not isinstance(prefs, dict):
prefs = {}
print(prefs.get('welcomeVersion') or '')
PY
)
if [ -n "$WELCOME_COMPLETED" ] && [ "$WELCOME_COMPLETED" != "null" ]; then
ALREADY_COMPLETED="true"
fi
fiBefore honoring that completion marker, determine whether the Codex setup is ready. A previously completed welcome must never hide the setup gate from a user who chose **나중에** or whose setup was later removed:
CODEX_HOME_DIR="${CODEX_HOME:-$HOME/.codex}"
case "$CODEX_HOME_DIR" in
"~") CODEX_HOME_DIR="$HOME" ;;
"~/"*) CODEX_HOME_DIR="$HOME/${CODEX_HOME_DIR#"~/"}" ;;
esac
if $OUROBOROS_WELCOME_PYTHON - "$HOME/.ouroboros/config.yaml" "$CODEX_HOME_DIR/config.toml" <<'PY'
from __future__ import annotations
import re
import os
import shutil
import sys
from pathlib import Path
try:
import tomllib
except ModuleNotFoundError: # Python 3.10 and earlier hosts
tomllib = None
try:
import yaml
except ModuleNotFoundError:
yaml = None
config_path, codex_config_path = map(Path, sys.argv[1:])
def yaml_mapping(source: str) -> dict[str, dict[str, str]]:
"""Read only the top-level mapping scalars owned by this readiness gate."""
if yaml is not None:
loaded = yaml.safe_load(source) or {}
return loaded if isinstance(loaded, dict) else {}
parsed: dict[str, dict[str, str]] = {}
section: str | None = None
def scalar_value(raw: str) -> str:
return raw.strip().split(" #", 1)[0].strip().rstrip(",}").strip().strip("'\"")
def flow_mapping(raw: str) -> dict[str, str]:
value = raw.strip().split(" #", 1)[0].strip()
if not (value.startswith("{") and value.endswith("}")):
return {}
fields: dict[str, str] = {}
for part in value[1:-1].split(","):
key, separator, field_value = part.partition(":")
if separator:
fields[key.strip().strip("'\"")] = scalar_value(field_value)
return fields
for raw_line in source.splitlines():
if not raw_line.strip() or raw_line.lstrip().startswith("#"):
continue
indent = len(raw_line) - len(raw_line.lstrip())
key, separator, raw_value = raw_line.strip().partition(":")
if not separator:
continue
if indent == 0:
section = key.strip("'\"")
parsed[section] = flow_mapping(raw_value)
elif section is not None:
parsed[section][key.strip("'\"")] = scalar_value(raw_value)
return parsed
def toml_mcp_servers(source: str) -> dict[str, dict[str, object]]:
"""Read MCP server table membership when the host lacks ``tomllib``."""
servers: dict[str, dict[str, object]] = {}
table: list[str] = []
def scalar_value(raw: str) -> str:
value = raw.strip().split(" #", 1)[0].strip().rstrip(",}").strip()
return value.strip("'\"").strip()
def inline_value(raw: str, key: str) -> str | None:
match = re.search(rf"\b{re.escape(key)}\s*=\s*(\"[^\"]*\"|'[^']*'|[^,}}]+)", raw)
if match is None:
return None
return scalar_value(match.group(1))
for raw_line in source.splitlines():
line = raw_line.strip()
if not line or line.startswith("#"):
continue
if line.startswith("[") and line.endswith("]"):
table = [part.strip().strip("'\"") for part in line[1:-1].split(".")]
if len(table) >= 2 and table[0] == "mcp_servers":
servers.setdefault(table[1], {})
continue
if table == ["mcp_servers"] and "=" in line:
key, raw_value = line.split("=", 1)
server = servers.setdefault(key.strip().strip("'\""), {})
for field in ("command", "url"):
value = inline_value(raw_value, field)
if value is not None:
server[field] = value
continue
if len(table) >= 2 and table[0] == "mcp_servers" and "=" in line:
key, raw_value = line.split("=", 1)Read more
name: welcome description: "First-touch experience for new Ouroboros users"
/ouroboros:welcome
Interactive onboarding for new Ouroboros users.
Usage
/ouroboros:welcome # First-time or update onboarding /ouroboros:welcome --skip # Skip welcome, mark as shown /ouroboros:welcome --force # Force re-run welcome even if shown
Instructions
When this skill is invoked, follow this flow:
Before running any shell snippets below, choose a Python command without assuming a system `python3` binary. Marketplace installs require `uvx`, not a global Python executable:
if [ -z "${OUROBOROS_WELCOME_PYTHON:-}" ]; then
if command -v python3 >/dev/null 2>&1; then
OUROBOROS_WELCOME_PYTHON="python3"
elif command -v python >/dev/null 2>&1; then
OUROBOROS_WELCOME_PYTHON="python"
elif command -v uv >/dev/null 2>&1; then
OUROBOROS_WELCOME_PYTHON="uv run --no-project --quiet python"
else
echo "Ouroboros welcome requires python3, python, or uv to inspect local setup."
exit 1
fi
fi---
Pre-Check: Already Completed?
First, check `~/.ouroboros/prefs.json` for `welcomeCompleted`. For upgrades from older releases, also treat legacy `welcomeShown: true` as completed so the welcome prompt does not reappear forever:
PREFFILE="$HOME/.ouroboros/prefs.json"
if [ -f "$PREFFILE" ]; then
WELCOME_COMPLETED=$($OUROBOROS_WELCOME_PYTHON - <<'PY'
import json, os
path = os.path.expanduser('~/.ouroboros/prefs.json')
try:
prefs = json.load(open(path, encoding='utf-8'))
except Exception:
prefs = {}
if not isinstance(prefs, dict):
prefs = {}
print(prefs.get('welcomeCompleted') or ('legacy-welcomeShown' if prefs.get('welcomeShown') else ''))
PY
)
WELCOME_VERSION=$($OUROBOROS_WELCOME_PYTHON - <<'PY'
import json, os
path = os.path.expanduser('~/.ouroboros/prefs.json')
try:
prefs = json.load(open(path, encoding='utf-8'))
except Exception:
prefs = {}
if not isinstance(prefs, dict):
prefs = {}
print(prefs.get('welcomeVersion') or '')
PY
)
if [ -n "$WELCOME_COMPLETED" ] && [ "$WELCOME_COMPLETED" != "null" ]; then
ALREADY_COMPLETED="true"
fi
fiBefore honoring that completion marker, determine whether the Codex setup is ready. A previously completed welcome must never hide the setup gate from a user who chose **나중에** or whose setup was later removed:
CODEX_HOME_DIR="${CODEX_HOME:-$HOME/.codex}"
case "$CODEX_HOME_DIR" in
"~") CODEX_HOME_DIR="$HOME" ;;
"~/"*) CODEX_HOME_DIR="$HOME/${CODEX_HOME_DIR#"~/"}" ;;
esac
if $OUROBOROS_WELCOME_PYTHON - "$HOME/.ouroboros/config.yaml" "$CODEX_HOME_DIR/config.toml" <<'PY'
from __future__ import annotations
import re
import os
import shutil
import sys
from pathlib import Path
try:
import tomllib
except ModuleNotFoundError: # Python 3.10 and earlier hosts
tomllib = None
try:
import yaml
except ModuleNotFoundError:
yaml = None
config_path, codex_config_path = map(Path, sys.argv[1:])
def yaml_mapping(source: str) -> dict[str, dict[str, str]]:
"""Read only the top-level mapping scalars owned by this readiness gate."""
if yaml is not None:
loaded = yaml.safe_load(source) or {}
return loaded if isinstance(loaded, dict) else {}
parsed: dict[str, dict[str, str]] = {}
section: str | None = None
def scalar_value(raw: str) -> str:
return raw.strip().split(" #", 1)[0].strip().rstrip(",}").strip().strip("'\"")
def flow_mapping(raw: str) -> dict[str, str]:
value = raw.strip().split(" #", 1)[0].strip()
if not (value.startswith("{") and value.endswith("}")):
return {}
fields: dict[str, str] = {}
for part in value[1:-1].split(","):
key, separator, field_value = part.partition(":")
if separator:
fields[key.strip().strip("'\"")] = scalar_value(field_value)
return fields
for raw_line in source.splitlines():
if not raw_line.strip() or raw_line.lstrip().startswith("#"):
continue
indent = len(raw_line) - len(raw_line.lstrip())
key, separator, raw_value = raw_line.strip().partition(":")
if not separator:
continue
if indent == 0:
section = key.strip("'\"")
parsed[section] = flow_mapping(raw_value)
elif section is not None:
parsed[section][key.strip("'\"")] = scalar_value(raw_value)
return parsed
def toml_mcp_servers(source: str) -> dict[str, dict[str, object]]:
"""Read MCP server table membership when the host lacks ``tomllib``."""
servers: dict[str, dict[str, object]] = {}
table: list[str] = []
def scalar_value(raw: str) -> str:
value = raw.strip().split(" #", 1)[0].strip().rstrip(",}").strip()
return value.strip("'\"").strip()
def inline_value(raw: str, key: str) -> str | None:
match = re.search(rf"\b{re.escape(key)}\s*=\s*(\"[^\"]*\"|'[^']*'|[^,}}]+)", raw)
if match is None:
return None
return scalar_value(match.group(1))
for raw_line in source.splitlines():
line = raw_line.strip()
if not line or line.startswith("#"):
continue
if line.startswith("[") and line.endswith("]"):
table = [part.strip().strip("'\"") for part in line[1:-1].split(".")]
if len(table) >= 2 and table[0] == "mcp_servers":
servers.setdefault(table[1], {})
continue
if table == ["mcp_servers"] and "=" in line:
key, raw_value = line.split("=", 1)
server = servers.setdefault(key.strip().strip("'\""), {})
for field in ("command", "url"):
value = inline_value(raw_value, field)
if value is not None:
server[field] = value
continue
if len(table) >= 2 and table[0] == "mcp_servers" and "=" in line:
key, raw_value = line.split("=", 1)Other skills on ouroboros.
- /auto
Automatically converge from goal to A-grade Seed and execute it
Open skill - /brownfield
Scan and manage brownfield repository/worktree defaults for interviews
Open skill - /cancel
Cancel stuck or orphaned executions
Open skill - /config
Open or drive the Ouroboros settings GUI (browser, TUI, or conversational fallback)
Open skill - /evaluate
Evaluate execution with three-stage verification pipeline
Open skill - /evolve
Start or monitor an evolutionary development loop
Open skill

