agentleFS
engine9-aiengine9-ai/skills/e9-global-message/SKILL.md

e9-global-message

Skill1 starsChanged 48 days agoApache-2.0View on GitHub

Read and consume engine9 global message warehouse views, including message identity, plugin context in legacy bot_* columns, platform engagement, native conversions, last-click attributed_* metrics, and primary-source-code dictionary fields. Use when querying message performance, attributed revenue, spend or impressions, building message grids and reports, interpreting inventory message statistics, or choosing publish_date versus by-date date. Email always uses global_message_summary on publish_date. Ads and other long-running types use global_message_summary_by_date.date (the day the statistic occurred). Do not use it to build messaging plugins or the attribution pipeline.

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Treat columns as separate categories.

    line 37
  2. Very specific:

    Use message_activity when the question is “on which days did this ad or long-running message report stats?” Do not use …

    line 175

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

engine9 global message tables

Global message warehouse views put a message’s identity, platform engagement, last-click attribution, and primary-source-code dictionary or legacy origin fields on a single row. Most message performance reports and data grids read these views instead of joining the underlying tables by hand. Use this skill to select a view, choose the correct metric family, and avoid double counting or incorrect attribution.

Quick reference

ViewGrainDate columnUse for
global_message_summaryOne row per message_idpublish_date — when the message went outEmail always. Also other one-shot sends whose platform totals are lifetime stats on the message (SMS blasts).
global_message_summary_by_dateOne row per message_id + datedate — the day the platform reported the statistic (not publish_date)Ads and other long-running types, where impressions, clicks, and spend are reported on the day they occurred.

Both sit under the account global_table_prefix (often empty). They are views over global_message, global_message_stats / _by_date, plugin metadata, and source_code_summary / _by_date; they are not base tables you write to.

Rules

Rule: Say transaction, never donation.

Rule: Email sends, opens, and clicks always come from global_message_summary on publish_date. Do not use global_message_summary_by_date or its date column for email.

Rule: global_message_summary_by_date.date is the day a statistic occurred. Use it for ads and other long-running message types. It is not a substitute for email publish_date.

Rule: Prefer attributed_* for cross-platform fundraising truth; platform revenue and transactions are native conversions only.

Rule: Do not add platform revenue to attributed_revenue; the metric families overlap and would double count.

Rule: Do not sum origin_* across messages that share a primary source code; those values are code-level totals repeated on each message.

Concepts

Column categories

Treat columns as separate categories. Mixing them (e.g. adding revenue + attributed_revenue, or treating origin_* as message-level last click) double-counts or misattributes.

1. Message identity — from global_message

Typical columnsMeaning
message_id, idFrakture message key (int); optional UUID id
label, subject, preview_urlPlatform-facing copy / preview
channel, channel_label, type, statusChannel and lifecycle
publish_dateWhen the message published
campaign_id / campaign_name, adset_*, message_set_idHierarchy on the platform
from_address, from_nameSender (email) / from phone (SMS), etc.
bot_id, submodule, remote_idWhich plugin/submodule loaded it; remote key (bot_id is legacy naming — see below)
primary_source_code, primary_source_code_override, final_primary_source_codePrimary code used for dictionary join and reporting buckets
do_not_attributeMessage excluded from attribution when set

2. Plugin context — legacy bot_* columns

These come from plugin / deployment metadata. Column names still use the older bot vocabulary; treat them as plugin fields.

ColumnsMeaning
bot_id, bot_path, bot_label, bot_nicknamePlugin that owns the message (reports often break down by bot_nickname)

Filter or group by bot_nickname / bot_path the same way you would by plugin. Do not invent a separate “bot” concept when explaining results to users — say plugin.

3. Platform engagement and native conversions — from global_message_stats / _by_date

Platform-reported metrics from the messaging or ad system — not engine9 last-click attribution.

Typical columnsMeaning
sent, deliveredSends / deliveries (email-style)
impressions, machine_impressionsOpens / impressions (email opens often land in impressions)
clicks, engagements, actions, leads, total_actions, unique_actionsEngagement
unsubscribes, complaints, soft_bounces, hard_bounces, blockedList hygiene / deliverability
spend, spend_overrideAd spend from the platform; optional override
revenue, transactionsNative platform conversion counts/amounts. Prefer attributed_* for fundraising truth

On _by_date, these numbers are for activity on that date as reported by the platform. That is the right grain for ads and other long-running types. Email platforms store lifetime sends, opens, and clicks on the message; report those from global_message_summary by publish_date, even if a by-date row also exists.

4. Last-click attribution — also on global_message_stats / _by_date

Rollups of transactions whose final message id is this message. Pipeline details: e9-source-code (last-click A–F).

ColumnsMeaning
attributed_revenue, attributed_transactionsSum/count of attributed transaction amounts (amount > 0)
attributed_revenue_day_1 / _day_6, attributed_transactions_day_*Windows relative to publish_date (+1 / +6 days). On the lifetime summary; not the main by-date rollup
attributed_recurring_*, attributed_initial_recurring_*, attributed_subsequent_recurring_*Recurring vs first installment vs later installments
attributed_refund_* (and recurring refund variants)Refund counts/amounts (not netted out of attributed_revenue unless a report does so)
attributed_soft_credit_*Soft credits when present
attributed_min_amount / max / avgAmount distribution
attributed_transaction_unique_personDistinct people (legacy person_id_int) on attributed txs
attributed_actionsAttributed non-monetary actions when populated

On _by_date, attributed_* are grouped by transaction calendar day (ts), not by publish_date. A day can have attributed revenue with zero impressions (or the reverse): engagement days and conversion days are independent.

5. Source-code elements and legacy origin — from source_code_summary / _by_date

Joined on message.final_primary_source_code = summary.source_code (and matching date for the by-date view).

ColumnsMeaning
Parsed elements (source_code_channel, goal, geo, …) and *_labelDictionary parse + labels for the primary source code
source_code_date_parsed / source_code_parsed_dateDate embedded in the code string (often ≠ publish_date)
origin_person_count, origin_transaction_*, origin_initial_*, origin_subsequent_*, origin_refund_*Legacy origin-model rollups for that source code. Not message-scoped last click. Prefer current {prefix}_* model tables (e9-model)

origin_* and element fields on a message row are properties of the primary source code, not of the message alone. If several messages share one primary code, they each show the same code-level origin totals.

Workflow

Choose a view and metrics

QuestionUse
How did this email perform (sends, opens, clicks, or last-click on that send)?global_message_summary only. channel='email'. Filter and group by publish_date.
How did this one-shot send perform (SMS blast, same lifetime totals)?global_message_summary on publish_date, same as email.
How did this ad or long-running message perform on the days stats were reported?global_message_summary_by_date, filter on date (not publish_date). Sum engagement and spend.
Last-click revenue by the day the transaction happened?global_message_summary_by_date, sum attributed_revenue on date (transaction day). Email fundraising tied to the send still uses the lifetime summary and publish_date.
Cross-channel fundraising truth?attributed_*, not revenue / transactions
Acquisition / LTV by first touch or CRM origin?Current model tables ({prefix}_*), not origin_* on these views
ROI for ads?sum(attributed_revenue) / sum(spend) on the by-date view (reports usually do this)

Trace related objects

ObjectRole
global_messageMessage dimension only
global_message_stats / _by_dateMeasures behind categories 3–4
source_code_summary / _by_datePer–source-code rollups; join key for category 5
transaction_summaryRow-level last-click debug (recommended_message_id, transaction_source_code)
union_global_message_summary*Account-union variants (multi-warehouse setups)

Stale attributed_* with good transaction_summary.recommended_message_id usually means attribution stats have not run for that publish window — diagnose with e9-source-code pipeline A–F, not by rewriting these views.

Examples

Query lifetime and daily metrics

-- Email (and other one-shot sends): lifetime totals by publish month.
-- Do not switch this query to global_message_summary_by_date.
SELECT
  date_trunc('month', publish_date) AS month,
  sum(sent) AS sent,
  sum(impressions) AS impressions,
  sum(clicks) AS clicks,
  sum(attributed_revenue) AS attributed_revenue
FROM global_message_summary
WHERE channel = 'email'
  AND publish_date >= DATE '2026-01-01'
GROUP BY 1
ORDER BY 1;

-- Ads and long-running types: stats on the day they occurred (`date`),
-- not on publish_date. Also the axis for last-click revenue by transaction day.
SELECT date, sum(spend) AS spend, sum(attributed_revenue) AS attributed_revenue
FROM global_message_summary_by_date
WHERE date >= DATE '2026-01-01'
GROUP BY date
ORDER BY date;

Interpret inventory statistics

e9-inventory warehouse statistics read these views. Grain is month (YYYY-MM). impressions is platform opens.

These blocks are aggregate message stats (kind: aggregate) — the usual inventory audit. They are not per-person timeline entries. Per-person send/open/click rows live under Timeline → Messages (statistics.inputs, subcategory: messages). Audit this aggregate work more often than timeline entries.

Inventory keySourceBucket
statistics.messagesglobal_message_summaryPlugin (bot_*) / submodule / channel / month of publish_date. records = message count; sums sent, impressions, clicks, spend, attributed_* when columns exist. Also by_channel_month. Inventory UI: Messages. Home email (sends, opens, clicks) uses this block only.
statistics.message_summary_by_dateglobal_message_summary_by_dateActive ads (spend > 0) by plugin / submodule / channel / month of date (count(distinct message_id)). Coverage only — no engagement sums.
statistics.message_activityglobal_message_summary_by_dateCalendar-day engagement on date, no spend filter. Same metric sums as messages. For ads and other long-running types only. Do not use it for email.

Rule: Home email and any other email sends/opens/clicks read statistics.messages (publish_date). A by-date series that only has recent date rows must not replace a year of publish-month email history.

Use message_activity when the question is “on which days did this ad or long-running message report stats?” Do not use message_summary_by_date for email — it drops rows without spend. Do not use inputs.by_plugin_entry_type_month as a substitute for these views.

Troubleshooting

SymptomCheck
attributed_* is stale but recommended_message_id is correctAttribution statistics may not have run for the publish window
Revenue appears duplicatedConfirm native revenue was not added to attributed_revenue
origin_* totals repeat across rowsCheck whether messages share final_primary_source_code
Email chart covers one recent month while Inventory Messages spans a year of publishesEmail was read from message_activity / date. Use statistics.messages on publish_date.
Email activity is missing from inventoryRead statistics.messages (global_message_summary, publish_date), not message_activity and not spend-filtered message_summary_by_date

Related documentation

  • Source codes and last-click attribution
  • Acquisition and LTV models
  • Inventory statistics and Home mapping
  • Timeline per-person message entries

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.