vip
GitHub管理VIP客户列表与优先级,确保高价值用户在客服流程中获得优先处理、完整上下文及专属草稿审核,支持基于信号自动建议新增VIP。
Trigger Scenarios
Install
npx skills add Lifecycle-Innovations-Limited/claude-ops --skill vip -g -y
SKILL.md
Frontmatter
{
"name": "vip",
"description": "OPS on-demand: This skill should be used when the user asks to \"vip list\", \"who is a VIP\", \"add someone…",
"allowed-tools": [
"Bash",
"Read",
"Grep",
"Skill",
"AskUserQuestion"
],
"argument-hint": "[list|show <person>|set <person> --tier N|suggest|why <person>]"
}
/ops:vip — VIP List
Load ops-rules before acting. Public repo (no personal data). Outbound: one draft → one approval → one send. If AskUserQuestion / Workflow are missing, follow Rule 10 in ops-rules (Hermes: numbered options / two-turn Telegram card; delegate_task).
The priority layer over every inbox. VIPs are checked FIRST in any sweep, answered first, drafted with extra care, and never buried in a bulk digest.
Scope (deliberately narrow)
This skill does four things and nothing else:
- Enforce the list — VIP senders rank ahead of everything else in every sweep.
- Require FULL context before answering or drafting for a VIP: the whole thread, every account on that channel, both directions, plus the ledger brief.
- Order triage output by tier.
- Suggest additions when the signals below appear.
It does not read histories for their own sake, does not draft unasked, and does not open a second channel just because one record is open. A tier edit is metadata only. Tagging someone is never an instruction to sweep their history.
Configuration
Nothing here is machine-specific. Every value resolves from userConfig, an env
var, or $HOME.
| userConfig key | Env override | Default | Meaning |
|---|---|---|---|
vip_list_path |
VIP_LIST_PATH |
$HOME/.claude-ops/state/vip-list.json |
Tier data + why/register notes |
vip_max_tier |
VIP_MAX_TIER |
2 |
Highest tier treated as VIP |
vip_suggest_enabled |
— | true |
Emit VIP candidate suggestions |
vip_volume_days |
— | 30 |
Window for the volume signal |
vip_volume_min |
— | 12 |
Two-way messages that trip volume |
relations_cli |
RELATIONS_CLI |
$HOME/.claude-ops/relations/bin/relations-cli |
Shared ledger CLI (see relations) |
PREFS_PATH="${PREFS_PATH:-${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}/preferences.json}"
read_pref() { [ -f "$PREFS_PATH" ] && python3 -c 'import json,sys;print(json.load(open(sys.argv[1])).get(sys.argv[2],"") or "")' "$PREFS_PATH" "$1" 2>/dev/null; }
VIP_LIST_PATH="${VIP_LIST_PATH:-$(read_pref vip_list_path)}"
VIP_LIST_PATH="${VIP_LIST_PATH:-$HOME/.claude-ops/state/vip-list.json}"
VIP_MAX_TIER="${VIP_MAX_TIER:-$(read_pref vip_max_tier)}"
VIP_MAX_TIER="${VIP_MAX_TIER:-2}"
# "No VIPs" and "the VIP list was never set up" are DIFFERENT answers and must
# never look the same. An unconfigured install that silently reports an empty
# list turns this skill into a no-op: every inbox sweep then treats the most
# important people as ordinary traffic and nobody finds out. Fail loud.
if [ ! -f "$VIP_LIST_PATH" ]; then
echo "vip: no list at $VIP_LIST_PATH — set userConfig vip_list_path or VIP_LIST_PATH." >&2
echo "vip: copy templates/vip-list.example.json there to start one." >&2
exit 3
fi
The list file lives OUTSIDE the repo tree — it is the operator's identity and
must never be committed (ops-rules Rule 0). Shape:
templates/vip-list.example.json.
Tiers
| Tier | Meaning | Handling |
|---|---|---|
| 1 | Inner circle | Never let it sit. Checked first, answered first, never batched |
| 2 | Key business | Same day. Ranked above general triage |
| 3-5 | Reserved | Not VIP by default (vip_max_tier = 2) |
The ledger's importance_tier column is the source of truth for the tier value;
the JSON file carries the why and the register notes (language, tone, dates to
avoid). Both are read; the DB wins on conflict.
Operations
| Subcommand | What it does |
|---|---|
list (default) |
Every person at or above vip_max_tier, grouped by tier |
show <person> |
Tier, type, why, channel, register notes |
set <person> --tier N |
Audited tier write via the ledger CLI, reason required |
suggest |
Read-only candidate scan (see signals below); never writes |
why <person> |
Which signal put a suggested candidate on the list |
"$RELATIONS_CLI" vip-list --max-tier "$VIP_MAX_TIER"
"$RELATIONS_CLI" vip <person_id> --tier 1 --type personal --reason "<why>"
Tier writes go through the CLI, never raw SQL. The CLI owns
source_reference, the audit log, and the rollback path. A direct
UPDATE on the ledger DB — inline or wrapped in a script — leaves an
unauditable row and is forbidden even where no guard happens to fire.
Sweep order
Any inbox, chat, email, or ticket sweep runs in this order:
- Resolve the VIP set once (
vip list), cache it for the sweep. - Tier 1 senders, every channel, both directions, every account.
- Tier 2 senders, same.
- Everything else, normal triage.
A VIP with an unanswered inbound is always surfaced individually, with the thread context, never as a line in a digest.
Suggesting additions
Suggest, never add silently. A tier change needs the owner's word, then the audited CLI write. Three signals:
| Signal | Trigger |
|---|---|
| volume | vip_volume_min+ two-way messages in vip_volume_days with someone off the list |
| frustration | They say they are being ignored or chased ("still waiting", "any update") |
| chain-break | Their last message is inbound and still unanswered |
Two filters keep this honest, both learned from real false positives:
- Anchor every keyword on both sides. A bare stem matches inside longer
words (
pinginside "tapping") and produces phantom frustration hits. - A thread ending on a sign-off is CLOSED, not broken. "Thanks!", "sounds good", an emoji, or any short ack with no question mark is not an open ask. Without this filter most chain-breaks are noise that buries the real ones.
Present at most 5 a week: who, which signal, the evidence line, and the exact CLI command to apply it. Then ask plainly. On "no", do not raise that person again.
Related skills
relations— the ledger, decision queue and draft path this list ranksops-inbox— the sweep that consumes the tier orderops-comms— the send path, still gated by Rule 6 for every VIPpeople— contact directory / identity resolutionops-rules— Rule 0 (the list is operator data, never committed)
Version History
- 9d2d383 Current 2026-09-02 21:50


