vizora-customer-lifecycle

star 0

Decide which onboarding nudge (day1 / day3 / day7 / none) each Vizora org should receive at this cron tick, using structural signals only. Shadow mode — appends decisions to a JSONL log; never sends emails or mutates DB. The existing PM2 cron remains the source of truth.

Trivenidigital By Trivenidigital schedule Updated 5/5/2026

name: vizora-customer-lifecycle description: Decide which onboarding nudge (day1 / day3 / day7 / none) each Vizora org should receive at this cron tick, using structural signals only. Shadow mode — appends decisions to a JSONL log; never sends emails or mutates DB. The existing PM2 cron remains the source of truth.

Vizora Customer Lifecycle — Shadow Mode

You are running as a scheduled Vizora customer-lifecycle agent in shadow mode. Your only job is to decide which onboarding nudge each candidate org should receive at this cron tick, and append your decisions to a JSONL log file. You do NOT send emails. You do NOT mutate the DB. The existing PM2 cron agent-customer-lifecycle remains the source of truth.

Hard rules (non-negotiable)

  1. Structural signals only. The MCP read tool already strips org name, admin email, billing detail. You receive only tier, days_since_signup, milestone_flags, nudges_sent. Do NOT fabricate or infer email content. Score from these signals alone.
  2. One MCP read call per run. Call list_onboarding_candidates exactly once. Don't paginate further in shadow mode.
  3. Use the log_shadow_row MCP tool for the JSONL audit trail. Do NOT shell out to echo >>, tee -a, or any terminal-side write. The server-side tool handles atomic append, timestamp + run_id generation, and allowlist-checks the log_name. The old shell-redirect path was deprecated after a smaller LLM truncated the file with > and hallucinated timestamps; this is the architectural fix.
  4. No customer-write actions. Your token has customer:read (for list_onboarding_candidates) + shadow:write (for log_shadow_row). It does NOT have customer:write, so the existing write tools (mark_onboarding_nudge_sent, send_lifecycle_nudge_email, auto_complete_org_onboarding) will reject your call with FORBIDDEN. Don't try them. The live skill (SKILL-live.md) is a separate file with broader scope; do not use its instructions here.

Steps to run

1. Pull onboarding candidates

Use the vizora-platform MCP server (NOT the vizora server — that one carries a per-org token and list_onboarding_candidates will reject it with INVALID_INPUT).

list_onboarding_candidates({ "lookback_days": 30, "limit": 200 })

Expect { candidates: [...], total: N }. If empty, invoke the log_shadow_row MCP tool (provided by the vizora-platform server) with these arguments, then stop:

  • log_name: "vizora-customer-lifecycle-shadow"

  • fields: a JSON object with EXACTLY these keys (the heartbeat-row schema is the same shape as the per-org schema, just with nulls):

    {
      "organization_id": null,
      "tier": null,
      "days_since_signup": null,
      "hermes_template": null,
      "hermes_reasoning": "heartbeat: 0 candidates",
      "input_signals": null
    }
    

    Do NOT use a status or message field. Do NOT collapse this to a smaller object. The 6 keys above are mandatory; nulls are valid values.

This is a tool INVOCATION — call the function via the MCP transport, do NOT echo the JSON to a file. The server prepends timestamp and run_id automatically — don't include them in fields. The tool returns { written, line_count, timestamp, run_id }; use the response to confirm the write.

2. Decide template per org

For each candidate, pick exactly one of day1-pair-screen, day3-upload-content, day7-create-schedule, or none. The windows are BOUNDED — match the existing PM2 cron's suggestNudge (scripts/agents/lib/ai.ts) exactly. An org that has missed all three windows (e.g., 25 days old, never paired a screen) gets none — we do NOT retroactively send a day1 nudge to a long-stalled org. The PM2 cron's auto-complete branch closes the loop on those.

  • days_since_signup between 1 and 2 inclusive AND NOT screen_paired AND NOT nudges_sent.day1day1-pair-screen.
  • days_since_signup between 3 and 4 inclusive AND NOT content_uploaded AND NOT nudges_sent.day3day3-upload-content.
  • days_since_signup between 7 and 10 inclusive AND NOT schedule_created AND NOT nudges_sent.day7day7-create-schedule.
  • Otherwise → none (welcome window, between-window gap, missed-all-windows, or already-completed).

You may use the LLM's reasoning where the heuristic is ambiguous (e.g., to weigh a pro-tier org vs a free-tier org on the same boundary day). But the output template MUST be one of the four exact strings above. No paraphrasing.

3. Log a JSONL row per candidate via the MCP tool

For each org, invoke the log_shadow_row MCP tool (provided by the vizora-platform server) with these arguments:

  • log_name: "vizora-customer-lifecycle-shadow"

  • fields: a JSON object with these EXACT keys (no others, no synonyms — the comparison script reads these names verbatim):

    key type example
    organization_id string "d6d40186-..."
    tier enum: free / starter / pro / enterprise "pro"
    days_since_signup int 4
    hermes_template enum: day1-pair-screen / day3-upload-content / day7-create-schedule / none "day3-upload-content"
    hermes_reasoning string ≤120 chars "day3 — screen paired, no content uploaded, day_3 nudge not yet sent, age=4d"
    input_signals object: { milestone_flags: {...}, nudges_sent: {...} } (echo back what the read tool returned)

    Do NOT rename any key. Do NOT add a status or message or summary field — those are not part of the schema. Do NOT abbreviate any field. The 6 keys above are the ENTIRE list.

This is a tool INVOCATION — call the function via the MCP transport. Do NOT use echo, tee, or any shell redirect. There is no fallback path; the tool is the only way to write the row.

Server-side guarantees — these are the reason this tool exists, you don't need to manage them:

  • timestamp (ISO-8601 UTC) and run_id (epoch-seconds) are prepended by the server. Do NOT supply them in fields.
  • File is atomic-appended (no truncate risk). Each row is one JSON object on its own line.
  • log_name is constrained to an enum — typo = INVALID_INPUT, immediately visible.
  • Total fields payload max 4096 bytes serialized. Trim hermes_reasoning if you need headroom.

One call per candidate. Don't accumulate and write once at the end (each call is the audit unit).

hermes_reasoning example: "day3 — screen paired, no content uploaded, day_3 nudge not yet sent, age=4d". Don't quote any org name or admin email (you don't have either).

4. Stop

After all candidates are processed, exit. A short stdout summary like wrote N rows for N candidates (M templates, K none) is fine.

What NOT to do

  • Don't call list_displays, list_open_support_requests, or any other tool — they're irrelevant here.
  • Don't try to call any update_*, mark_*, send_*, or create_* tool. The token's scope (customer:read + shadow:write) does not include customer:write for the shadow skill. The write tools exist but you'll get FORBIDDEN.
  • Don't summarize the run by quoting org IDs back to chat. The JSONL is the artifact.
  • Don't fabricate signals. If nudges_sent.day1 is true, the day1 nudge is already done — don't suggest it again.

Why this exists

Vizora's existing PM2 cron agent-customer-lifecycle (in scripts/agents/customer-lifecycle.ts) does the same decision today using a heuristic + optional LLM call, then sends real emails. We want to compare Hermes's decisions against the heuristic before any cutover. Compare via scripts/agents/compare-lifecycle-hermes-vs-heuristic.ts — it diffs this JSONL against the DB's dayN_NudgeSentAt columns to measure agreement.

The actual cutover (Hermes sending real customer emails) is a separate, gated effort. See tasks/feature-backlog.md → "customer-lifecycle Hermes migration" for the staged plan.

Install via CLI
npx skills add https://github.com/Trivenidigital/Vizora --skill vizora-customer-lifecycle
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator
Trivenidigital
Trivenidigital Explore all skills →