Direct integration with ActiveCampaign's v3 API, built to operate the way an experienced marketer and sales lead actually thinks. Calibration scans your account once at install (taxonomy + 90-day campaign baselines); 50+ scripts then answer questions against your live data in plain English.
Performance analysis — campaign postmortems, subject-line analysis, send-time optimization, send-frequency / fatigue, domain breakdown (Gmail vs. Outlook vs. corporate), engagement decay, from-name performance, monthly trend, baseline-drift detection.
List & contact health — list audits, duplicate finder, role-address detector, field completeness, stale contacts, new-subscriber quality, list-growth forecast, pre-import CSV validator.
Lead scoring & sales — hot leads ranked by composite signals, slipping deals, MQL→SQL handoff, win/loss by source, pipeline audit. (Deals-dependent reports require an AC plan that includes Deals; they exit cleanly otherwise.)
Automation hygiene — orphaned-automation audit, per-step funnel dropoff, multi-automation overlap, stalled enrollments, dependency map, broken-reference detector.
Tag / field / list / segment hygiene — tag audit (typos, dead tags, co-occurrence consolidation), custom-field audit, per-list audit, list-overlap matrix, segment audit, form audit.
Compliance & ops — unsubscribe / opt-in audit, suppression export, Per-contact data export, webhook audit, account snapshot, schema diff between snapshots.
Sales / CRM — overdue tasks audit, per-rep performance scoreboard (deals + tasks + notes), notes content analysis (action-item extraction, stale-note detection), saved-responses audit, B2B accounts audit (orphaned / no-pipeline / owner rollup). (Plus+ for Tasks, Saved Responses, B2B Accounts.)
Marketing-content hygiene — campaign template audit (unused / stale / per-template open rate), per-form lead quality.
Strategic advice (no API calls) — "should this be a tag, custom field, or list?", "why is my open rate dropping?", welcome / re-engagement / drip campaign specs you implement in the AC UI.
> Scope: This skill operates against the AC account whose token you provide. It reads and (with explicit user confirmation) modifies records inside that account only. There is no cross-account access, no third-party data transmission, and no telemetry. All data — reports, exports, snapshots, history — is written to local files on your own machine.
The skill is analysis-first. Most of the 60+ scripts in scripts/ are read-only: they pull data, produce a report, and exit.
Write capabilities — explicitly declared: A small number of scripts can modify records in the AC account when you ask for them. These include contact updates, contact tagging, list subscription changes, automation enrollment, deal updates, custom-field value updates, and tag-merge operations. Every modification flows through one auditable code path with the following guarantees:
INSTALL.md). Admin is not required and not recommended; the token's blast radius should match what you intend to run.ACClient.post / put / delete all route through one write() helper that enforces the rules below and records every modification.AC_READ_ONLY=1 env var. When set, every write is refused at the client layer before any HTTPS request goes out. Lets you run the entire script suite in pure-analysis mode without risk.AC_MAX_WRITES= if intended. A runaway script can't perform more than the budget allows in one invocation.~/.activecampaign-skill/writes.jsonl (file mode 0600). Every write records timestamp, endpoint, method, payload SHA-256 (NOT payload), invoking script, and sequence number.tag_merge.py) are dry-run by default; --confirm is required to execute, and they refuse to operate on anything still referenced by an active automation or segment.scripts/_ac_client.py), which sanitizes API-sourced values before any subprocess call to prevent shell injection.When asked, the skill can act on contacts, deals, custom-field values, and tags — but only behind those gates, scoped to the records you specify, and previewed first.
Calibration, history, and any reports written via --output produce local files only. The skill never transmits data to a third party. Files live under ~/.activecampaign-skill/ with mode 0600 and are owned by the running user:
| File | Purpose | Created by | Retention |
|---|---|---|---|
| --- | --- | --- | --- |
state.json | Calibrated taxonomy + 90-day baselines | calibrate.py | Until you recalibrate or delete it |
history.jsonl | Append-only log of recipe/script runs (no contact PII; just operation metrics) | Most scripts via log_outcome() | Manual — see below |
insights.md | Persistent findings from prior runs | Scripts via write_insight() | Manual |
writes.jsonl | Audit log of POST/PUT/DELETE operations (payload hash, not payload) | _ac_client.write() | Manual |
snapshots/*.json | Versioned account snapshots | snapshot.py, account_archive.py | Manual |
All files can be inspected with normal text tools and deleted by removing the directory. Recommended retention: prune history.jsonl and snapshots every 90 days unless you need longer-term trend analysis. No data is sent off your machine.
To wipe everything the skill has stored locally:
rm -rf ~/.activecampaign-skill/
"Find my hottest leads" — ranks contacts by a composite of AC lead score, recent engagement velocity, deal-stage progression, and content depth. Output includes a "top signal" column explaining why each lead is hot, so you walk into the call already knowing what they care about.
"Merge my duplicate tags" — catches behavioral duplicates that string-similarity tools miss. Surfaces case-mismatch (customer + Customer), separator typos (webinar-attendee + webinar_attendee), and semantic duplicates (vip + high-value-customer) by co-occurrence on the same contacts. Then resolves them in-conversation: applies the survivor tag, removes the dupe, patches automation references, and deletes the dead tag — with explicit confirmation before each destructive step.
"Run my morning briefing" — pulls a daily digest off your account: yesterday's campaign metrics vs. baseline, hot-lead changes since last check, slipping deals that crossed the staleness threshold overnight, automations with new stalled enrollments, and any baseline-drift alerts.
For more examples (subject-line lift analysis, list health audits, stalled-automation detection, re-engagement campaigns), see the workflow recipes in recipes/.
scripts/calibrate.py scans your AC account and writes a state file (taxonomy, baselines, patterns). Every conversation starts with context, not a cold start.recipes/ contains parameterized workflows (welcome series, list audit, deal hygiene, daily digest) instead of bare endpoints.frameworks/ contains what a senior marketer or sales leader knows: email best practices, segmentation theory, deliverability patterns.scripts/ contains tools that run analyses and return markdown reports (list health, hot leads, slipping deals).~/.activecampaign-skill/history.jsonl so future runs can compare to past performance.Get credentials from Settings → Developer in your AC account:
export AC_API_URL=https://youraccount.api-us1.com
export AC_API_TOKEN=your-api-token
On first install, run calibration:
python3 {baseDir}/scripts/calibrate.py
This builds ~/.activecampaign-skill/state.json with your account's lists, tags, custom fields, pipelines, automations, and 90-day performance baselines. Re-run monthly.
Two gotchas:
Api-Token, not Bearer. The #1 reason custom integrations fail.When the user invokes this skill and ~/.activecampaign-skill/state.json does not exist, this is a first-run. Follow this flow:
Greet the user and explain what calibration does in one sentence: "Let me scan your ActiveCampaign account so I can give you advice grounded in your actual data." Then run:
python3 {baseDir}/scripts/calibrate.py
After calibration completes, read the script's output and state.json. Present a conversational account briefing — not a data dump. Narrate what you found as if you're a new team member who just studied their account:
Keep it to 8-12 lines. Conversational, not clinical.
After the briefing, ask: "Are you primarily focused on marketing or sales?" Then show the matching capability menu below.
"Here's what I can do for you right now:"
> Note: items marked (spec) produce a written blueprint — subject lines, timing, segmentation, copy — that you assemble in the AC UI. The v3 API does not allow creating automations or sending campaigns.
"Here's what I can do for you right now:"
If state.json exists and is fresh, skip the welcome flow. Jump straight to answering the user's question. If state.json is >30 days old, suggest recalibration before proceeding but don't block.
These are sub-second single-call scripts. Use them whenever the user is asking about one specific thing — don't reach for the audit scripts.
| If the user wants to... | Run | ||
|---|---|---|---|
| --- | --- | ||
| Look up a contact by email | scripts/contact_lookup.py --email | ||
| Look up a contact by ID | scripts/contact_by_id.py | ||
| Get the most recent N contacts | scripts/contact_recent.py [--limit N] | ||
| Most engaged / top scoring contacts (fast) | `scripts/contact_most_engaged.py [--limit N] [--by score\ | recent]` | |
| Contacts with the most clicks / opens (real engagement events) | `scripts/contact_engagement_leaders.py [--by clicks\ | opens\ | both] [--window-days N] [--limit M]` |
| Full profile on one contact (compound) | `scripts/contact_full_profile.py --email\ | --id` | |
| Look up a deal by ID | scripts/deal_by_id.py | ||
| Full context on one deal (compound) | scripts/deal_full_context.py | ||
| Deep-dive on an automation | scripts/automation_deep_dive.py | ||
| Find a tag id by name | scripts/tag_lookup.py --name (checks state.json first; no API call if cached) | ||
| Find an automation id by name | scripts/automation_lookup.py --name (state.json first) | ||
| See the most recent campaign send | scripts/last_campaign.py |
When the user asks "find / look up / what's the id / what's the most recent" — prefer these over the audit scripts. The audits paginate thousands of records; these single-call scripts return in <1s.
| If the user wants to... | Load | Or use endpoint |
|---|---|---|
| --- | --- | --- |
| Audit list quality | recipes/list-health-audit.md + scripts/audit_list_health.py | — |
| Find hot leads | scripts/find_hot_leads.py | — |
| Surface slipping deals | scripts/find_slipping_deals.py | — |
| Get a morning briefing | recipes/daily-digest.md | — |
| Spec a welcome series (user builds in AC UI) | recipes/welcome-series.md + frameworks/email-best-practices.md | — |
| Clean up the pipeline | recipes/deal-hygiene.md + scripts/find_slipping_deals.py | — |
| If the user wants to... | Load | Or use endpoint |
|---|---|---|
| --- | --- | --- |
| Sync a contact | references/contacts.md | POST /contact/sync |
| Create/update a deal | references/deals.md | POST /deals |
| Read/write custom fields | references/custom-fields.md | fieldValues, dealCustomFieldData |
| Tag a contact | references/contacts.md | POST /contactTags |
| Enroll in automation | references/contacts.md | POST /contactAutomations |
| Understand segmentation | frameworks/segmentation-theory.md | — |
| Email copy/design advice | frameworks/email-best-practices.md | — |
| If the user wants to... | Run |
|---|---|
| --- | --- |
| Postmortem on one campaign | scripts/campaign_postmortem.py |
| Compare two campaigns | scripts/campaign_compare.py |
| Per-link performance for a campaign | scripts/link_performance.py |
| Bounce decomposition (global or per-campaign) | scripts/bounce_breakdown.py [--campaign |
| Monthly performance trend | scripts/monthly_performance.py [--months N] |
| Detect baseline drift vs. calibration | scripts/baseline_drift.py [--window-days N] |
| Send velocity per list | scripts/campaign_velocity.py [--window-days N] |
| Subject line pattern analysis | scripts/subject_line_report.py [--days N] |
| Content length / CTA correlation | scripts/content_length_report.py [--days N] |
| Performance by from-name / from-email | scripts/from_name_report.py [--days N] |
| Best send window | scripts/send_time_optimizer.py |
| Sends-per-contact distribution | scripts/send_frequency_report.py [--window-days N] |
| Engagement by recipient domain | scripts/domain_engagement_report.py |
| Cohort retention | scripts/engagement_decay.py [--months N] |
| Stale contacts | scripts/stale_contact_report.py [--window-days N] |
| New subscriber engagement | scripts/new_subscriber_quality.py [--days N] |
| Audience-cut performance | scripts/segment_performance.py --list/--tag/--segment |
| MQL→SQL handoff diagnostics | scripts/mql_to_sql_handoff.py [--threshold N --days N] (needs Deals) |
| Win/loss by source | scripts/win_loss_report.py [--days N] (needs Deals) |
| Predict outcomes for planned send | scripts/send_simulator.py --list/--tag/--segment |
| Project list growth | scripts/list_growth_forecast.py [--project-days N] |
| If the user wants to... | Run |
|---|---|
| --- | --- |
| Tag hygiene audit | scripts/tag_audit.py |
| Custom field audit | scripts/custom_field_audit.py |
| Per-list audit | scripts/list_audit.py |
| List overlap matrix | scripts/list_overlap.py |
| Saved-segment audit | scripts/segment_audit.py [--skip-counts] |
| Pipeline / stage audit | scripts/pipeline_audit.py (needs Deals) |
| Automation audit | scripts/automation_audit.py [--window-days N] |
| Per-automation funnel | scripts/automation_funnel.py |
| Cross-automation overlap | scripts/automation_overlap.py |
| Stalled enrollments | scripts/stalled_automations.py [--min-days N] |
| Form audit | scripts/form_audit.py |
| Find duplicate contacts | scripts/dedupe_contacts.py |
| Contact field completeness | scripts/contact_completeness_report.py |
| Find role addresses | scripts/role_address_finder.py |
| Free-mail vs. corporate split | scripts/free_vs_corporate_report.py |
| Validate a CSV pre-import | scripts/import_validator.py |
| Snapshot the account | scripts/snapshot.py [--scope taxonomy/contacts/deals/all] |
| Local account archive | scripts/account_archive.py [--scope ...] |
| Diff two snapshots | scripts/schema_diff.py |
| Webhook inventory + reachability | scripts/webhook_audit.py [--skip-probe] |
| Unsubscribe / opt-in compliance | scripts/unsubscribe_audit.py |
| Export suppressed contacts | scripts/suppression_export.py |
| Raw per-contact data export | scripts/contact_data_export.py |
| If the user wants to... | Run |
|---|---|
| --- | --- |
| Audit overdue tasks + per-user workload | scripts/tasks_audit.py (needs Plus+) |
| Analyze contact + deal notes (action items, stale notes) | scripts/notes_analysis.py [--stale-days N] |
| Per-rep performance scoreboard (deals + tasks + notes) | scripts/sales_rep_performance.py |
| Audit campaign email templates (unused, stale, performance) | scripts/template_audit.py [--stale-days N] |
| Audit saved-response library (sales reply templates) | scripts/saved_responses_audit.py (needs Plus+) |
| B2B accounts audit (orphaned, no-pipeline, owner rollup) | scripts/accounts_audit.py (needs Plus+) |
| Per-form lead quality (subscribelist proxy) | scripts/forms_lead_quality.py [--window-days N] |
In recipes/. Each is a parameterized workflow. The agent reads the recipe + invokes any associated script.
In frameworks/. Loaded when the conversation needs strategic thinking:
frameworks/segmentation-theory.mdframeworks/email-best-practices.mdIn references/. Standard API reference for when the agent needs to make a specific call.
~/.activecampaign-skill/state.json (built by scripts/calibrate.py) contains:
{
"schema_version": 1,
"account": {"url": "...", "regional_host": "api-us1"},
"taxonomy": {
"lists": [...], "tags": [...], "custom_fields": {...},
"pipelines": [...], "automations": [...]
},
"baselines": {
"open_rate_p50": 0.28, "click_rate_p50": 0.04,
"best_send_window_utc": ["14:00", "15:00"],
"best_send_dow": ["Tue", "Wed", "Thu"]
},
"last_calibrated": "2026-04-24T12:00:00Z"
}
No PII is stored in the state file. All taxonomy values are sanitized on write.
Always read this before answering account-specific questions. If the file doesn't exist or is >30 days old, prompt the user to run calibration.
~/.activecampaign-skill/history.jsonl — append-only log of recipes executed and decisions made. Read it to ground responses in actual past performance.
~/.activecampaign-skill/insights.md — persistent markdown file of significant findings. Written by scripts when they detect notable patterns (3+ consecutive metric declines, new risks, milestones). Unlike history.jsonl (structured data), insights.md captures human-readable analysis that grounds the agent's recommendations across sessions and survives conversation compaction.
Upsert a contact:
curl -s -X POST -H "Api-Token: $AC_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"contact":{"email":"jane@example.com","firstName":"Jane","lastName":"Doe"}}' \
"$AC_API_URL/api/3/contact/sync" | jq
Tag a contact (look up tag ID from state.json):
curl -s -X POST -H "Api-Token: $AC_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"contactTag":{"contact":"123","tag":"42"}}' \
"$AC_API_URL/api/3/contactTags" | jq
Enroll in automation:
curl -s -X POST -H "Api-Token: $AC_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"contactAutomation":{"contact":"123","automation":"7"}}' \
"$AC_API_URL/api/3/contactAutomations" | jq
Use this skill when:
scripts/ (e.g. calibrate.py, audit_list_health.py, find_hot_leads.py, find_slipping_deals.py, tag_audit.py, campaign_postmortem.py, automation_funnel.py, dedupe_contacts.py, account_archive.py, …) or state.jsonDo NOT use this skill when:
_ac_client.py with built-in backoff._ac_client.py) for all write operations. Do not construct curl commands with user-provided or API-sourced values — shell metacharacters in names, titles, or field values can cause command injection.~/.activecampaign-skill/insights.md for accumulated findings from previous analyses. These insights survive conversation compaction and provide longitudinal context.Wrote /path lines and a __SKILL_FILES__:[...] JSON trailer. Reproduce every path in your response. Don't write a label like Files:, Output:, or Saved to: and trail off without content — either fill it in or drop the label.scripts/.python3 - <<'PY' heredocs, python3 -c "...", and any other ad-hoc Python construction is forbidden. The Telegram / web delivery shows the heredoc body verbatim in the tool-use breadcrumb, which is ugly and exposes raw queries to the user.find_hot_leads.py beats a clean answer from ad-hoc Python every time, because the named script's name lands in the Telegram breadcrumb instead of 12 lines of code.scripts/ first, then run it.scripts/contact_recent.pyscripts/contact_most_engaged.py (fast) or scripts/find_hot_leads.py (deeper composite scoring)scripts/contact_engagement_leaders.py (real engagement-event aggregation)scripts/contact_lookup.pyscripts/deal_by_id.pyscripts/tag_lookup.pyscripts/automation_lookup.pyscripts/last_campaign.pyscripts/contact_full_profile.py/activities endpoint can be incomplete. Use directionally, not as absolute truth./messageActivities is not exposed on every plan. When AC returns 404, the engagement scripts (send_time_optimizer, send_frequency_report, domain_engagement_report, engagement_decay, stale_contact_report, new_subscriber_quality, segment_performance) automatically fall back to /linkData — that means clicks-only analysis with no open events. The client.fetch_engagement_events() helper in _ac_client.py handles the fallback transparently. If a report shows zero opens but non-zero clicks, this is why.pipeline_audit.py reports current state and 90-day-recent-creation only; it cannot compute time-in-stage./deals*, /dealTasks, /savedResponses, /accounts, /notes), it prints a friendly "Not available on your ActiveCampaign plan" markdown report and exits cleanly — this is a tier limitation, not a bug. Affected scripts include pipeline_audit.py, mql_to_sql_handoff.py, win_loss_report.py, tasks_audit.py, notes_analysis.py, sales_rep_performance.py, saved_responses_audit.py, and accounts_audit.py.Retry-After.?limit=100&offset=0. Cursor-based: ?orders[id]=ASC&id_greater=N.100000 = $1,000.|| delimiter.fieldValues resource.共 3 个版本