relations
GitHub关系管理器,用于维护联系人账本和决策队列。回答谁需要回复、承诺了什么、哪些关系冷却,并提供起草邮件所需的上下文。默认处于影子模式,不直接发送内容。
Trigger Scenarios
Install
npx skills add Lifecycle-Innovations-Limited/claude-ops --skill relations -g -y
SKILL.md
Frontmatter
{
"name": "relations",
"description": "OPS on-demand: This skill should be used when the user asks to \"who do I owe a reply\", \"relationship…",
"allowed-tools": [
"Bash",
"Read",
"Grep",
"Glob",
"Skill",
"AskUserQuestion"
],
"argument-hint": "[queue|brief <person>|find <email|phone|name>|draft <person>|close <id>|audit]"
}
/ops:relations — Relationship Manager
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).
Relationship ledger and decision queue. Answers: who is owed a reply, what was promised, what is going cold, and what context a draft needs before it is written. It never sends anything.
Configuration
Every path and toggle comes from plugin userConfig, an env var, or $HOME.
Nothing in this skill is machine-specific.
| userConfig key | Env override | Default | Meaning |
|---|---|---|---|
relations_cli |
RELATIONS_CLI |
$HOME/.claude-ops/relations/bin/relations-cli |
Ledger CLI entry point (JSON out) |
relations_db_path |
RELATIONS_DB |
$HOME/.claude-ops/relations/people.db |
SQLite ledger, the factual source of truth |
relations_shadow_mode |
RELATIONS_SHADOW_MODE |
true |
When true, no external send on any channel |
relations_queue_limit |
RELATIONS_QUEUE_LIMIT |
10 |
Max decision-queue items per report |
relations_followup_limit_personal |
— | 1 |
Unanswered follow-ups allowed, personal |
relations_followup_limit_business |
— | 2 |
Unanswered follow-ups allowed, business |
relations_suppress_days |
— | 30 |
Minimum suppression after a dismissal |
Resolve in this order, first non-empty wins. Never hardcode an absolute path:
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; }
RELATIONS_CLI="${RELATIONS_CLI:-$(read_pref relations_cli)}"
RELATIONS_CLI="${RELATIONS_CLI:-$HOME/.claude-ops/relations/bin/relations-cli}"
RELATIONS_DB="${RELATIONS_DB:-$(read_pref relations_db_path)}"
RELATIONS_DB="${RELATIONS_DB:-$HOME/.claude-ops/relations/people.db}"
if [ ! -x "$RELATIONS_CLI" ]; then
echo "relations: no ledger CLI at $RELATIONS_CLI — set userConfig relations_cli or RELATIONS_CLI" >&2
fi
A missing CLI is reported as a missing CLI. Never fall back to an empty result: "no follow-ups" and "the ledger is not installed" must never look the same.
Hard rules
- Shadow mode is the default. With
relations_shadow_modetrue, this skill drafts and stages only. No email, chat, SMS, or calendar invite leaves the box. - Never merge two records on a name. Hard keys only: contact-provider id, normalized email, E.164 phone, or a previously verified alias. Everything else goes to the review queue.
- Every fact, commitment and follow-up carries a source reference. No source, no row, no draft sentence.
- Facts and inference are separate. An inference never justifies an outbound.
- Silence is the default. Nothing meaningful changed means send nothing.
- Contact history never enters agent memory. Person facts belong in the
ledger DB, not in a memory plane or a committed file. See
ops-rulesRule 0. - Progressive disclosure. Never load the contact list into context. Query the one person you need.
Operations
| Subcommand | What it does |
|---|---|
queue (default) |
Ranked decision queue, max relations_queue_limit, one per person |
brief <person> |
Contact methods, open commitments, sourced facts, recent threads |
find <key> |
Resolve an identity by email / phone / name; ambiguity → review |
draft <person> |
Full-context draft, staged for approval, never sent |
close <id> |
Close a follow-up with a reason |
snooze <id> <ts> |
Defer with a reason |
suppress <id> |
Dismiss for at least relations_suppress_days |
audit |
Duplicates, unsourced rows, stale facts, integrity |
"$RELATIONS_CLI" queue --limit "${RELATIONS_QUEUE_LIMIT:-10}"
"$RELATIONS_CLI" brief <person_id>
"$RELATIONS_CLI" find --email user@example.com
"$RELATIONS_CLI" close <follow_up_id> --reason "they replied on chat"
Draft order (fixed)
- Resolve identity across every channel the person owns — never answer on one channel while the real conversation is on another.
- Read the COMPLETE thread, not the latest message. Check both directions (sent and received) and every account the channel has.
- Read messages from the recipient and anyone relevant on copy.
- Check the calendar and open commitments.
- Check
viptier first (see thevipskill) — a tier-1 person is drafted with more care and never batched into a digest. - Load
humanizer, write ONE draft in the owner's voice, in the language the thread is already in. - Stage it for approval with recipient, channel, thread, and a content hash. If any of those change, ask again. Send only the exact approved content.
Never send. Never produce several near-duplicate drafts.
Follow-up gate
States: i_owe_them, they_owe_me, waiting_date, waiting_document,
waiting_decision, going_cold, no_action, suppressed.
The gate blocks on: do-not-automate, archived person, snoozed, suppressed,
not due yet, they responded elsewhere, upcoming meeting, unanswered limit
(relations_followup_limit_personal / _business), missing source reference,
cross-channel duplicate.
Not every unanswered message is overdue. Was a response actually requested? Was something promised? Has that date arrived? Would silence be more natural?
Report format
Plain text, no decoration, recommendation first, max relations_queue_limit
items, numbered actions per item. If nothing survives the gate, output nothing.
relationship desk — monday
1. <person>
business, a revised proposal was promised friday (email thread, <date>)
recommendation: send the prepared draft, confidence high
1 approve 2 edit 3 snooze 2 days 4 close 5 show context
Source authority
Current complete thread > verified identity > current calendar event > current conversation > signed document > this ledger > recent public primary source > search result > existing summary > draft. A draft is never a source of truth. On conflict: record it, prefer the newest authoritative primary source, surface it, and do not send until it is resolved.
Related skills
vip— who is checked and answered first; always consulted before triageops-inbox— channel sweeps feed this ledgerops-comms— the send path, gated by Rule 6people— contact directory sync (identity layer under this ledger)humanizer— voice pass before any draft is stagedops-rules— Rule 0 (public repo), Rule 6 (per-message approval)
Version History
- 9d2d383 Current 2026-09-02 21:49


