posthog-customer-deep-dive
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePostHog customer deep dive
PostHog客户深度分析
Research an account, then produce an email (first touch, follow-up, or reply), a call-prep brief with its notebook prompt, or for any other ask whatever shape the ask needs on the same research. Output goes to chat. Customer and account systems are read-only: never send, never post, never write to Vitally or PostHog. The only writes are local: during Setup, and a per-run scratchpad ( under the session scratchpad, or ) holding the docs cache, the context file and the gatherer digests. The deliverable is generated once, into chat, and never also written to a file.
config.mddeep-dive-<account>-<HHMM>/tmpInput: , usually an email address; also a domain, an account name, or a Vitally account id (either UUID kind).
$ARGUMENTSVerify every claim before writing it. Every number comes from a query you ran this run; every product fact and link from a docs search you ran this run. Show a derived figure's arithmetic inline () so a slipped digit is visible. Nothing from memory, nothing inferred from a number you did not pull. Where a claim cannot be verified, write the question instead: an unanswered question costs a follow-up, a confident wrong fact costs the relationship. Every table in this skill tells you what to check; none is a citation.
1.72M polls/day / 2,880 per instance = ~600 instancesA claim about the customer's code or SDK config must quote that code from the site scan's fetched page or bundle. Data shows the effect; only code shows the cause, so an identity or billing mechanism is never named from event and billing data alone. Events the SDK emits (, , an explicit event) are assertable from those events; init options and config values need the quoted code.
$identify$create_alias$setRead first: every per-user value and tool binding. A required value reading means ask before the step that needs it, or run Setup. A source set to is skipped silently; that is configuration, not a skip, and a run with every optional source at is complete.
config.md<SET THIS>nonenone| Reference | Read when |
|---|---|
| Before Step 1, every run |
| First, before Round 1a. It carries main's own reading-map row, so it decides what else main opens, plus the conventions block, the per-role map, the context file spec and the return rules |
| Steps 1 and 2, by main, only the sections main's map row names. Gatherers never open it; they get its conventions inline |
| Steps 1 and 2, by main (Round 1 slugs) and by the gatherers assigned to it |
| Step 2, by the gatherer whose map row names the section. Each file's headings are its index |
| Round 0 (Round 2 on a public-provider admin email) |
| Before drafting any recommendation, and by |
| Before drafting anything a customer will see |
| Step 5, the one file for the detected artifact. Any other ask runs the same research and takes the shape the ask needs |
Batch main's reference reads into one block. Opening whole is the largest read in the critical path and most of it belongs to gatherers, who get it inline.
data-rules.mdTwo bundled scripts, each a floor and never a ceiling: run them, then keep going wherever the account points somewhere they do not reach, and name what you ran beyond them. A run that stops exactly where the scripts stop answered the script's questions instead of the customer's.
- sends any HogQL query over the HTTP API on four targets (
scripts/phq.pyproject 2,usEU project 1,eu/ch-usthe direct ClickHouse connection).ch-eufires many at once, one JSON object per line with the keys--batch <file.jsonl>,name,targetand optionalsql; any other key set is aconnectionbefore the first query runs. The MCP stays primary; this is the fallback when the gateway is down and the only path for EU.KeyError - runs the common shape of the Round 0 scan.
scripts/site-scan.sh <domain>
Every other HTTP call, Vitally REST included: build the JSON in Python inside a single-quoted heredoc (), write it to a file, send with . Bash expands , inside inline strings and this skill is full of -prefixed names; Python's hits , so curl sends and Python only builds and parses.
python3 << 'PYEOF'curl --data @file$1$group_0$urllibCERTIFICATE_VERIFY_FAILED调研账户,然后生成邮件(首次联系、跟进或回复)、带笔记本提示的通话准备简报,或根据其他需求生成基于同一调研内容的对应格式输出。输出内容会发送至聊天窗口。客户和账户系统为只读模式:绝不发送、发布或写入Vitally或PostHog。仅允许本地写入:设置期间写入,以及每次运行时的临时文件(会话临时目录下的,或目录),用于存储文档缓存、上下文文件和收集器摘要。交付内容仅生成一次并发送至聊天窗口,绝不会同时写入文件。
config.mddeep-dive-<account>-<HHMM>/tmp输入:,通常为邮箱地址;也可以是域名、账户名称或Vitally账户ID(任意UUID类型)。
$ARGUMENTS撰写前验证所有声明。每个数字都来自本次运行的查询结果;每个产品事实和链接都来自本次运行的文档搜索结果。将推导数据的计算过程内联展示(如),以便清晰查看是否有数字错误。绝不依赖记忆,绝不从未获取的数字中推断信息。对于无法验证的声明,改为提出问题:未解答的问题仅需跟进,而自信的错误事实会损害客户关系。本技能中的所有表格仅告知需检查的内容,而非引用依据。
1.72M polls/day / 2,880 per instance = ~600 instances关于客户代码或SDK配置的声明必须引用代码,来自站点扫描获取的页面或包。数据仅能展示效果;只有代码能说明原因,因此绝不能仅通过事件和账单数据来命名身份或计费机制。SDK发送的事件(如、、显式事件)可通过这些事件进行断言;初始化选项和配置值则需要引用代码。
$identify$create_alias$set首先读取:包含每个用户的专属值和工具绑定。若所需值显示,则在需要该值的步骤前询问用户,或运行设置流程。若源设置为则自动跳过;这属于配置项,而非跳过操作,即使所有可选源都设为,运行仍视为完成。
config.md<SET THIS>nonenone| 参考文档 | 读取时机 |
|---|---|
| 每次运行的步骤1之前 |
| 首先,在第1a轮之前。它包含主程序自身的读取映射行,决定主程序还需打开哪些内容,同时包含约定块、角色映射表、上下文文件规范和返回规则 |
| 步骤1和步骤2,由主程序读取仅主程序映射行指定的章节。收集器绝不打开此文件;相关约定会内联传递给收集器 |
| 步骤1和步骤2,由主程序(第1轮标识)和分配到该任务的收集器读取 |
| 步骤2,由映射行指定对应章节的收集器读取。每个文件的标题即为索引 |
| 第0轮(若为公共提供商管理员邮箱则在第2轮) |
| 起草任何建议之前,以及由 |
| 起草任何客户可见内容之前 |
| 步骤5,根据检测到的输出类型选择对应文件。其他类型的请求会执行相同调研,并生成符合需求格式的内容 |
将主程序的参考文档读取操作批量处理为一个块。完整打开是关键路径中最大的读取操作,且大部分内容属于收集器,收集器会通过内联方式获取这些内容。
data-rules.md附带两个脚本,仅作为基础而非上限:运行脚本后,需继续根据账户指向的内容进行拓展,并记录超出脚本范围的操作。若运行仅在脚本结束时停止,则回答的是脚本的问题而非客户的问题。
- 通过HTTP API向四个目标(
scripts/phq.py项目2、us欧盟项目1、eu/ch-us直接ClickHouse连接)发送任意HogQL查询。ch-eu可批量发送多个查询,每行一个JSON对象,包含**--batch <file.jsonl>、name、target**键,可选sql键;若设置其他键,会在首个查询运行前触发connection。MCP为主要方式;当网关故障时,此为备用方式,也是欧盟区域的唯一路径。KeyError - 运行第0轮扫描的通用流程。
scripts/site-scan.sh <domain>
所有其他HTTP调用(包括Vitally REST):在单引号heredoc()内用Python构建JSON,写入文件后,使用发送。Bash会展开内联字符串中的、,而本技能中包含大量前缀的名称;Python的会触发,因此使用curl发送请求,仅用Python构建和解析数据。
python3 << 'PYEOF'curl --data @file$1$group_0$urllibCERTIFICATE_VERIFY_FAILEDSetup (first run, or when config.md
is not yours)
config.md设置(首次运行,或config.md
非本人所有时)
config.mdProbe before asking, confirm before writing. In one pass: check the tool list for the PostHog exec gateway and the Vitally MCP; check the env for , , ; check the tool list for each optional category in , recording exact tool names; detect the timezone. Show one message with what was found, what is missing and the defaults you keep, ask only what cannot be probed (calendar id, booking link), and write back. A missing optional tool is ; a missing required tool stops the run.
POSTHOG_PERSONAL_API_KEYPOSTHOG_PERSONAL_API_KEY_EUVITALLY_API_KEYconfig.mdconfig.mdnoneWhen something is missing, hand the person the fix, not a diagnosis. carries the whole install, one numbered section per tool, each ending in a check that proves it worked, and it is never loaded at runtime, so read the section for whatever is missing and give them the commands from it inline: the shell and key setup (section 0), the MCP registration, the command for a shared credential, or the mint URL for a personal one. Say which credentials are shared and which are theirs, since reusing someone else's PostHog personal key is the common mistake. Then re-probe and confirm before running. A first run that ends in "the Vitally MCP is missing" and nothing else is how a shared skill loses the person who was trying it.
README.mdop item get先探测再询问,确认后再写入。一次性完成以下操作:检查工具列表中是否有PostHog执行网关和Vitally MCP;检查环境变量中是否存在、、;检查工具列表中的每个可选类别,记录确切工具名称;检测时区。展示一条消息说明已找到的内容、缺失的内容以及保留的默认值,仅询问无法探测的信息(日历ID、预约链接),然后写回。缺失的可选工具设为;缺失的必填工具会终止运行。
POSTHOG_PERSONAL_API_KEYPOSTHOG_PERSONAL_API_KEY_EUVITALLY_API_KEYconfig.mdconfig.mdnone当缺少内容时,直接提供解决方案,而非仅诊断问题。包含完整的安装步骤,每个工具对应一个编号章节,每个章节结尾都有验证步骤证明安装成功,且该文件不会在运行时加载,因此读取缺失工具对应的章节,并内联提供其中的命令:Shell和密钥设置(第0节)、MCP注册、共享凭证的命令,或个人凭证的生成URL。说明哪些凭证是共享的,哪些是个人专属的,因为重复使用他人的PostHog个人密钥是常见错误。然后重新探测并确认后再运行。若首次运行仅提示“缺少Vitally MCP”而无其他内容,会导致尝试使用该共享技能的用户放弃。
README.mdop item getStep 1. Resolve to a Vitally account
步骤1:解析为Vitally账户
| Input | Path |
|---|---|
| |
| Domain | the |
| Account name | |
| Account ID | use directly |
If all fail, ask for the account name. An id handed in can be either UUID kind: the Vitally MCP resolves both, the warehouse matches org ids on only.
vitally.accounts.external_idOne customer carries a different name in each system, so check what the name you were handed refers to. Vitally's account name, (often a legal entity), , and the per-project names in are five independent fields that sometimes disagree, and the name you were given can turn out to be a near-empty second project rather than the account. State in the header which name maps to what whenever they diverge, and report on the project carrying the volume.
stripe.namezendesk.namesfdc.Websiteresolve-teamsget_user_detailsvitally.custom.| Read from | Fields |
|---|---|
| |
| |
Always run the domain sibling sweep, both halves. A sibling org is a duplicate paying twice, a consolidation question, or an account a teammate owns. The two queries see different populations ( and ) and neither alone is complete; skipping one is how a duplicate-billing sibling stays hidden. Flag any sibling in the header: one org with multiple projects usually beats parallel orgs.
vitally.usersbilling_customerThen probe usage across every org the sweep returned and build the context on the one carrying the volume. returns , whichever account Vitally lists first, and on a multi-org customer that is routinely not the live one, so every downstream figure would describe a dead org. This gates the Round 2 launch: no gatherer starts until it has resolved, because a gatherer given the wrong org id does perfect work on the wrong company.
get_user_detailsaccounts[0]sql
SELECT organization_id, count() AS days, sum(event_count_in_period) AS events,
sum(recording_count_in_period) AS recordings, sum(mobile_recording_count_in_period) AS mobile_recordings,
sum(billable_feature_flag_requests_count_in_period) AS flag_requests
FROM billing_usage_by_org_date
WHERE organization_id IN (<every org id the sweep returned>) AND date >= today() - 30
GROUP BY organization_id ORDER BY events DESC LIMIT 20An org missing from the result has no Cloud usage in the window, which is an answer. Where the resolved org and the live org differ, say so in the header, report on the live one, and treat the resolved one as a sibling finding: a paid subscription on a dead org is money leaving for nothing.
| 输入 | 路径 |
|---|---|
| 邮箱 | |
| 域名 | |
| 账户名称 | |
| 账户ID | 直接使用 |
若所有方法都失败,询问用户账户名称。输入的ID可以是任意UUID类型:Vitally MCP可解析两种类型,数据仓库仅在上匹配组织ID。
vitally.accounts.external_id同一客户在不同系统中可能使用不同名称,因此需确认输入的名称对应的对象。Vitally的账户名称、(通常为法律实体名称)、、以及中的每个项目名称是五个独立字段,有时会不一致,输入的名称可能指向一个几乎为空的次要项目而非主账户。当名称不一致时,在标题中说明每个名称对应的系统,并报告承载主要业务量的项目。
stripe.namezendesk.namesfdc.Websiteresolve-teamsget_user_detailsvitally.custom.| 读取来源 | 字段 |
|---|---|
数据仓库中的** | |
| |
务必完整运行域名关联扫描的两部分。关联组织可能是重复付费的账户、合并候选账户,或同事负责的账户。两个查询覆盖不同的群体(和),单独使用任何一个都不完整;跳过其中一个会导致重复计费的关联账户被隐藏。在标题中标记任何关联组织:一个拥有多个项目的组织通常优于并行组织。
vitally.usersbilling_customer然后探测扫描返回的所有组织的使用情况,并基于承载主要业务量的组织构建上下文。返回,即Vitally列出的第一个账户,但对于多组织客户,这通常不是活跃组织,因此后续所有数据都会描述一个已停用的组织。这是第2轮启动的前置条件:收集器必须在解析完成后才能启动,因为若收集器使用错误的组织ID,会针对错误的公司完成完美的工作。
get_user_detailsaccounts[0]sql
SELECT organization_id, count() AS days, sum(event_count_in_period) AS events,
sum(recording_count_in_period) AS recordings, sum(mobile_recording_count_in_period) AS mobile_recordings,
sum(billable_feature_flag_requests_count_in_period) AS flag_requests
FROM billing_usage_by_org_date
WHERE organization_id IN (<every org id the sweep returned>) AND date >= today() - 30
GROUP BY organization_id ORDER BY events DESC LIMIT 20若结果中缺少某个组织,则表示该组织在指定窗口内无Cloud使用量,这也是一种有效结果。若解析出的组织与活跃组织不同,在标题中说明这一点,报告活跃组织的情况,并将解析出的组织视为关联发现:已停用组织上的付费订阅会造成不必要的资金流失。
Step 2. Parallel pull
步骤2:并行拉取数据
Put the PostHog MCP on project 2 (check its active-environment block; to if not). It often defaults to a dev project where every query returns zero rows.
switch-project2Detect the region from (an array, e.g. ), populated far more widely than ; fall back to , then , where means EU. Project 2 answers almost everything for both regions; the exceptions are EU experiment definitions and the EU direct connection, both on the EU key and EU project 1.
vitally.custom.usEuInstance["US"]cloudRegioncloudRegiontraits.site_urleu.posthog.com将PostHog MCP切换到项目2(检查其活跃环境块;若未在项目2则使用切换)。它通常默认指向开发项目,该项目中所有查询都返回零行。
switch-project从(数组类型,例如)检测区域,该字段的覆盖范围远大于;若该字段不存在,回退到,再回退到,其中表示欧盟区域。项目2几乎能回答两个区域的所有问题;例外情况是欧盟实验定义和欧盟直接连接,这两者需使用欧盟密钥和欧盟项目1。
vitally.custom.usEuInstance["US"]cloudRegioncloudRegiontraits.site_urleu.posthog.comHow to fan out
如何分散任务
Fan the gathering out, reconcile in one head, then fan the verification out separately. The two fan-outs are not interchangeable: gathering happens before there are claims, verification after.
A round costs what its deepest agent costs, and an agent costs its longest chain of dependent calls. So batch first (every read depending only on the context goes out in one block; on the HTTP path one ), widen second (one grouped query per org and region rather than one per team, per ), split last and only along a true dependency. No brief carries a serial chain longer than 8 to 10 reads: count the chain, not the calls.
phq.py --batchdata-rules.md- Budget in tool calls, never seconds. Cap each gatherer at 12 to 15, and split the brief BEFORE launching if the list runs past 15. Nobody can estimate an agent's seconds; everyone can count reads in a brief.
- The budget caps shape, never scope. Never drop, defer or narrow a read to fit it. The move when a brief is too big is to split it, and a read that still will not fit runs over budget and is named in the closing note.
- Split by call count; never merge briefs by topic. Concurrent agents are near-free in wall clock; calls inside one agent serialize into one chain. Merging trades a cheap resource for an expensive one, so the instinct to reduce agent count is backwards.
- 8 to 10 concurrent agents, each batching 4 wide. Past that ClickHouse returns 202 and the HTTP path returns 429, and the forced serial retries are slower than not splitting. The cap is machine-wide, so expect an occasional refusal and retry rather than shipping without the refused brief.
- Splitting stops paying below about 12 calls, because every agent carries a fixed startup cost whatever you give it. Split down to 12 to 15, then stop.
- A full call-prep set exceeds the concurrency cap, so it runs in waves. Wave one: ,
change-point,money-quotas. The first two frame every other finding (what moved, and what a limit actually cut off); the third is slowest.claygoes last and never takes a required gatherer's slot.docs-prewarm
| Round | Who | Does what |
|---|---|---|
| 0. Pre-resolve | 1 subagent, the moment the domain is known | |
| 1a. Unblock | Main, three ordered batches | Everything deciding who to research and which batch to run, because both are wrong to guess. Batch 1: the Vitally resolve, |
| 1b. Resolve | Main, one block, concurrent with Round 2 | |
| 2. Gather | The roles below, in waves | Every role the mode requires, |
| 2. (concurrently) | Main | Reading the conversation bodies, Step 4 roster, refining mode detection as |
| 3. Reconcile | Main, in ONE parallel block | The roll call, the hedge sweep, the named pairs, then re-run the header figures and the number driving the top recommendation. List every claim the output will make. Surface any disagreement between two sources with both figures, never resolve it |
| 4. Verify | Main where the cache covers the claim, one subagent per uncovered cluster | A live docs search per claim, returning the URL and the verbatim line that proves it |
| 5. Write | Main | The output |
Give every subagent the path to the context file, the conventions block, its reading-map row, and the return rules, all from . The context is resolved once by main and no gatherer re-resolves any of it; a gatherer missing a value reports the gap rather than querying for it. The Round 0 agent is the exception: it gets only the domain.
agent-briefs.mdProbe an optional source once. Gong, Slack and Clay share a shape: emptiness is knowable in one call, and a zero ends that source. Report "searched X, zero results", which is a finding and not a skip.
The role roster, what each owns and which sections each opens, is one table in . It lives there because that is the file main reads to write the briefs, and two tables listing the same roles in two always-loaded files is how they drift apart.
agent-briefs.mdagent-briefs.mdProbe an unfamiliar property in the block you are already firing, never in its own round: add for that event.
JSONExtractKeys(assumeNotNull(properties))先分散收集任务,在一个主程序中协调,再单独分散验证任务。这两个分散操作不可互换:收集在声明生成前进行,验证在声明生成后进行。
一轮任务的耗时取决于最深层代理的耗时,而代理的耗时取决于其最长的依赖调用链。因此先批量处理(所有仅依赖上下文的读取操作一次性发出;HTTP路径使用一个命令),再拓宽范围(根据,每个组织和区域使用一个分组查询,而非每个团队一个查询),最后拆分且仅在存在真实依赖关系时拆分。任何简报的串行调用链长度不得超过8至10次:统计调用链长度,而非调用次数。
phq.py --batchdata-rules.md- 按工具调用次数预算,而非时间。每个收集器的调用次数上限为12至15次,若列表超过15次,在启动前拆分简报。无人能准确估算代理的耗时;但所有人都能统计简报中的读取次数。
- 预算限制的是任务形式,而非范围。绝不能为了适应预算而删除、延迟或缩小读取范围。当简报过大时,应拆分简报;若某个读取操作仍无法适应预算,则超出预算执行,并在结束说明中提及。
- 按调用次数拆分;绝不要按主题合并简报。并发代理的耗时几乎可以忽略;单个代理内的调用会串行化为一条链。合并简报会浪费廉价资源(并发)而消耗昂贵资源(串行时间),因此减少代理数量的想法是错误的。
- 8至10个并发代理,每个代理批量处理4个操作。超过此数量,ClickHouse会返回202错误,HTTP路径会返回429错误,强制串行重试的速度比不拆分更慢。此上限为机器全局限制,因此偶尔会遇到拒绝请求,需重试,而非跳过该简报。
- 当调用次数低于约12次时,拆分不再有意义,因为每个代理都有固定的启动成本,无论任务多少。拆分到12至15次即可停止。
- 完整的通话准备任务集超出并发上限,因此分波次运行。第一波:、
change-point、money-quotas。前两个任务为其他所有发现奠定基础(哪些数据发生了变化,哪些限制实际影响了业务);第三个任务耗时最长。clay最后运行,绝不占用必填收集器的资源槽。docs-prewarm
| 轮次 | 执行者 | 任务内容 |
|---|---|---|
| 0. 预解析 | 1个子代理,域名确定后立即执行 | 对管理员邮箱域名执行 |
| 1a. 解除阻塞 | 主程序,三个有序批次 | 完成所有决定调研对象和运行批次的操作,因为这两者不能猜测。批次1:Vitally解析、 |
| 1b. 解析 | 主程序,一个块,与第2轮并发执行 | |
| 2. 收集 | 以下角色,分波次执行 | 模式所需的所有角色, |
| 2.(并发) | 主程序 | 读取对话内容、步骤4的人员名单,随着 |
| 3. 协调 | 主程序,一个并行块 | 角色点名、不确定性扫描、成对验证,然后重新运行标题数据和驱动核心建议的关键数字。列出输出将包含的所有声明。若两个来源存在分歧,需展示两个数据,绝不自行解决 |
| 4. 验证 | 缓存覆盖的声明由主程序验证,未覆盖的集群每个分配一个子代理 | 每个声明对应一次实时文档搜索,返回URL和证明该声明的原文内容 |
| 5. 写入 | 主程序 | 生成输出内容 |
为每个子代理提供上下文文件路径、约定块、其读取映射行以及返回规则,所有内容均来自。上下文由主程序一次性解析,收集器绝不重新解析任何上下文内容;若收集器缺少某个值,需报告缺口而非自行查询。第0轮代理是例外:仅提供域名。
agent-briefs.md仅探测一次可选源。Gong、Slack和Clay的逻辑相同:一次调用即可确定是否为空,若返回零结果则终止该源。报告“已搜索X,无结果”,这是一个有效发现而非跳过操作。
角色名单、每个角色的职责以及每个角色需打开的章节,在中以表格形式呈现。该表格放在此处是因为主程序读取此文件来撰写简报,若两个始终加载的文件中存在相同角色的表格,会导致内容不一致。
agent-briefs.mdagent-briefs.md在当前正在执行的块中探测不熟悉的属性,绝不单独开启一轮任务:为该事件添加。
JSONExtractKeys(assumeNotNull(properties))The scope probe, and its three guards
范围探测及其三个防护措施
The Round 1a scope probe (one aggregate) knows which products carry volume. Pass it into each product brief as known state, each line carrying its own proof (, never a bare "flags are zero"). It changes what a brief says, never whether it runs. Three guards, and it is unsafe without all three:
per-product-usagebillable_feature_flag_requests_count_in_period = 0 in billing_usage_by_org_date over the window- Write for every product the probe has no column for. Experiment volume and web analytics volume have no source anywhere; heatmap volume lives only on the usage report's
unmeasurable, no sourcemap;teamslives on the org usage report.ff_count - Check on
realmbefore trusting a flat zero: the table is Cloud only, so a self-hosted org reads zero everywhere while emitting usage daily, and it carries no row for a day with no usage.org-snapshot - Each brief says "verify against the product's own source and report what you found", never "confirm and move on".
Never use the probe to skip a role the mode requires. Skipping is where a zero and an unmeasurable become the same thing, which is the failure this skill exists to prevent. An agent that ran and confirmed a zero is not a skip.
第1a轮的范围探测(一个聚合查询)可了解哪些产品承载业务量。将探测结果作为已知状态传递给每个产品简报,每行都附带证明(例如窗口内,绝不能仅写“标志数量为零”)。它会改变简报的内容,而非决定是否运行简报。需同时启用三个防护措施,否则探测结果不可靠:
per-product-usagebilling_usage_by_org_datebillable_feature_flag_requests_count_in_period = 0- 对于探测中无对应列的产品,写入。实验业务量和Web分析业务量无任何数据源;热图业务量仅存在于使用报告的
无法测量,无数据源映射中;teams存在于组织使用报告中。ff_count - 在信任零值之前,检查的
org-snapshot字段:该表格仅适用于Cloud环境,因此自托管组织的所有字段都会读取为零,但实际每天都会产生使用量,且无使用量的日期不会有对应行。realm - 每个简报需说明“对照产品自身数据源验证并报告结果”,绝不能写“确认后继续”。
绝不能使用探测结果跳过模式所需的角色。跳过操作会导致零值和无法测量的情况被视为同一回事,而这正是本技能要避免的失败。运行并确认零值的代理不属于跳过操作。
Round 3: roll call, hedge sweep, named pairs
第3轮:角色点名、不确定性扫描、成对验证
Three checks before any re-run, because each catches a whole missing input rather than a wrong digit.
The roll call. List the roles the mode requires against the roles launched, and the Round 1 slugs required against the ones that returned. Every gatherer justifies its own skipped reads, but nothing checks the level above it, so a role dropped under time pressure disappears silently while the output reads complete. Launch the gap, or name it in the closing note. "Short of time" is a reason to state, never a reason to omit. This matters most on an ask that is neither an email nor a brief, where there is no expected section for the reader to notice missing.
The hedge sweep, and it produces a list, not an intention. Read every digest for the gatherers' own uncertainty ("probable not proven", "unmeasurable", "needs confirming", "worth reconciling", "the biggest skip is", "ask on the call") and write every hit into a numbered list before closing any of them. Each line gets a disposition: closed with the number, or carried into the output as a named open question. A hedging gatherer has almost always named the read that would close it, so each is cheap and pre-scoped.
Doing this in your head is what fails. A sweep held as an intention closes the easy hedges, and the one it drops is reliably the one sitting under the top recommendation, because that is the hedge whose answer takes work. An unresolved hedge is how a finding dies: the agent did its job, the signal sits in the digest, and it never becomes a sentence. Two specific shapes to catch, both of which have shipped as assertions: a hedge that would have SIZED a lever you are already recommending (you keep the recommendation and lose the number that makes it land), and a hedge naming a cause that another gatherer was holding the data to confirm.
The named pairs, sources that must agree:
- A site-scan absence against the customer's own event stream. The scan is authoritative for what it found, never for what it did not. If their team receives events carrying that host in , the tool is installed there whatever the scan said. One query, before any absence claim reaches the output.
$current_url - The header's money figures against the invoice.
- Two gatherers against each other, wherever they touched the same object. Reachability claims are the ones that collide: one role probes a table, gets and reports unmeasurable, while another reads a near-identical name successfully and publishes a finding from it. Both digests are then true and the output carries a contradiction. Before writing, list every object more than one role touched and confirm they agree on whether it exists and what it holds.
Unknown table
在重新运行任何操作前进行三项检查,因为每项检查都能发现整个缺失的输入,而非单个错误数字。
角色点名。列出模式所需的角色与已启动的角色,以及所需的第1轮标识与已返回的标识。每个收集器会自行说明跳过的读取操作,但无人检查更高层级的内容,因此若因时间压力放弃某个角色,它会静默消失,而输出看起来仍然完整。启动缺失的角色,或在结束说明中提及。“时间不足”是需说明的原因,而非省略的理由。这在既非邮件也非简报的请求中尤为重要,因为读者无法通过预期的章节发现缺失内容。
不确定性扫描,需生成列表而非仅记录意图。读取每个收集器摘要中的不确定性表述(如“可能但未证实”、“无法测量”、“需确认”、“值得协调”、“最大的跳过项是”、“通话时询问”),在关闭任何收集器前将所有命中项写入编号列表。每行需标注处理结果:已用数字确认,或作为未解决问题带入输出。提出不确定性的收集器通常已指出可解决该问题的读取操作,因此每个问题的解决成本低且范围明确。
仅在脑中进行扫描会导致失败。若仅将扫描作为意图,会解决容易的不确定性问题,而被遗漏的往往是核心建议背后的不确定性,因为解决该问题需要付出努力。未解决的不确定性会导致发现失效:代理已完成任务,信号存在于摘要中,但从未转化为句子。需特别注意两种情况,这两种情况曾被作为断言输出:一种是会影响已推荐方案效果的不确定性(保留建议但失去使其有说服力的数字),另一种是指出另一个收集器已掌握数据可确认原因的不确定性。
成对验证,必须一致的数据源:
- 站点扫描未发现的内容与客户自身事件流的对比。扫描仅对已发现的内容具有权威性,对未发现的内容不具有权威性。若客户团队接收的事件中包含该主机,则无论扫描结果如何,该工具已安装在该主机上。在输出任何“未发现”声明前,执行一次查询。
$current_url - 标题中的资金数据与发票的对比。
- 两个收集器对同一对象的分析结果对比。可达性声明最容易冲突:一个角色探测某张表,得到并报告无法测量,而另一个角色读取名称几乎相同的表成功并发布发现。两个摘要都是真实的,但输出会存在矛盾。在撰写输出前,列出所有被多个角色处理的对象,确认它们对对象是否存在以及内容的判断一致。
Unknown table
Round 4 verification, and the docs cache
第4轮验证与文档缓存
Verification runs against the finished claim list; Round 2 pre-warming is additive and may never shrink it. Where the cache covers a claim, verify in main; fan out only for the claims it missed. The invariant holds either way: every claim gets its own live search, and the count of searches against claims is what proves it happened. Searching from before the findings exist verifies levers you predicted and misses the ones the data produced, so build the claim list first (the pre-draft check in ), then verify every lever and product fact it states.
paidProductsvoice.mdThree lines govern the cache, and every Round 4 brief states them verbatim: a cached page is evidence only for a claim whose OWN live search returned that URL; the cache supplies a page body, never a verdict and never a citation; the cache is per run, never a page a previous run fetched. A verifier returns the verdict, the canonical URL and the verbatim sentence. is permitted, and a claim that comes back that way is cut or rewritten as a question, never shipped with the nearest-looking link. Cite first, a PostHog-authored page when no docs page covers it, never Community Questions or GitHub issues. If is unreachable, verify each URL with a plain HTTPS fetch.
not foundposthog.com/docsposthog.com/tutorialsdocs-search验证针对已完成的声明列表;第2轮预加载是补充操作,可能不会缩小声明列表。若缓存覆盖了声明,在主程序中验证;仅对缓存未覆盖的声明分散验证。无论哪种情况,都需遵守不变原则:每个声明都需进行实时搜索,搜索次数与声明数量一致可证明验证已执行。在发现结果生成前从进行搜索,会验证预测的方案而遗漏数据产生的方案,因此需先构建声明列表(中的预草稿检查),然后验证声明中提及的所有方案和产品事实。
paidProductsvoice.md缓存需遵守三条规则,每个第4轮简报需逐字说明:缓存页面仅能作为对应声明的实时搜索返回该URL时的证据;缓存仅提供页面内容,绝不提供结论或引用;缓存为每次运行专属,绝不使用之前运行获取的页面。验证器需返回结论、规范URL和原文句子。允许返回,若声明返回此结果,需删除该声明或改写为问题,绝不附带看似相关的链接。优先引用,若无对应文档页面,引用PostHog官方的页面,绝不引用社区问题或GitHub议题。若不可用,通过普通HTTPS请求验证每个URL。
未找到posthog.com/docsposthog.com/tutorialsdocs-searchThe closing note
结束说明
Nothing accumulates across runs, so this note is the only record. At Step 5, after the output, add a short note in chat: which agents ran long, any brief that overran its cap, and any fix this run revealed that belongs in the skill. Suggestion only. Two figures belong in it because both are correctness checks, not telemetry:
- Claims whose own citation URL you fetched, against total claims. Count it from a list you append to as each verification happens, never from memory at the end of the run: a number reconstructed at the end is a number you will inflate, and an inflated count is worse than none, because the ratio is the only thing standing between a real Round 4 and a warm cache. Count fetched citations rather than searches run, because a search that returned a confident, adjacent page is exactly the failure this is watching for and it looks identical to a search that answered the question.
- Roles launched against roles required, and Round 1 slugs returned against Round 1 slugs required. Print both halves. A dropped role is the loud half and gets noticed anyway; a Round 1 slug that quietly never ran is the silent half, and it is the one that reaches the output as an absence nobody questioned.
- Hedges found, closed, and carried, as three numbers from the Round 3 list.
运行间无数据累积,因此本说明是唯一记录。在步骤5完成输出后,在聊天窗口添加简短说明:哪些代理运行时间过长、哪些简报超出调用上限、本次运行发现的需修复的技能问题。仅作为建议。以下两个数据需包含在说明中,因为它们是正确性检查而非遥测数据:
- 已获取引用URL的声明数量与总声明数量的对比。在每次验证时将声明添加到列表中进行统计,绝不依赖记忆在运行结束时统计:运行结束时重构的数字会被夸大,而夸大的计数比无计数更糟,因为该比例是区分真实第4轮验证与缓存复用的唯一依据。统计已获取的引用URL数量而非运行的搜索次数,因为返回看似相关页面的搜索正是本检查要防范的失败,且与正确回答问题的搜索无法区分。
- 已启动的角色与所需角色的对比,以及已返回的第1轮标识与所需第1轮标识的对比。打印两部分内容。缺失的角色是明显的部分,容易被注意到;而静默未运行的第1轮标识是隐藏的部分,会导致输出中出现无人质疑的缺失内容。
- 发现的不确定性问题数量、已解决数量和带入输出的数量,来自第3轮列表的三个数字。
What main covers beyond the roles
主程序超出角色职责的处理内容
Round 2 subagents own the reads in the table; main does not re-run them. Beyond it: Vitally's (limit 20; metadata only, is Gmail or calendar, is support), , . Conversation bodies, notes and tasks come from the warehouse (, , ), avoiding the MCP calls that overflow on large accounts. Every email with the account syncs to Vitally, so that pair of reads is the whole comms record and a mailbox search adds nothing. Do not reach for one: a on a contact's first name matched a different customer's personal address at another domain and nearly put that account's failed payment into this brief. If you search a mailbox anyway, read the recipient domain before treating a message as this account's. Keep both the Vitally traits and the postgres reads where they overlap and cross-check them. The calendar runs every run with an explicit start/end window (unbounded text searches return nothing), by attendee name from the subject, else by account name and admin emails.
get_account_conversationssource: "google"zendeskget_account_feature_requestsget_account_healthvitally.messagesvitally.notesvitally.tasksgog gmail searchAccepted:Four names main needs by hand, because main verifies numbers without opening a query file. The event saying a limit actually cut a product off is ; who changed a limit is ; the live forecast is joined to on ; current limits are . A guessed column here returns an empty result that reads exactly like "nothing was limited", the inverse of the truth. These are pointers, not recipes: open and in before writing either query, because both carry filters and aliases that decide whether the result means anything, and writing SQL from this paragraph alone has produced a column of nulls and a hard 400.
org_quota_limited_untilbilling limits updatedbilling_customerbilling_upcominginvoicecustomer_idcustom_limits_mapquota-limitsin-flight-periodqueries-money.mdCall prep runs every role. An email run drops the roles whose product the account does not implicate, and names each one dropped. In every mode, skip an individual read only when it cannot apply, and name each skip. Lookback 30 days; re-run a single query at 14 days (follow-up) or 7 (same-week call prep) only where the shorter window changes the conclusion.
第2轮子代理负责表格中的读取操作;主程序绝不重新运行这些操作。除此之外,主程序还需处理:Vitally的(限制20条;仅获取元数据,表示Gmail或日历,表示支持)、、。对话内容、备注和任务来自数据仓库(、、),避免在大型账户上使用会溢出的MCP调用。与该账户相关的所有邮件都会同步到Vitally,因此这两次读取操作即可获取完整的通信记录,邮箱搜索不会增加任何内容。不要进行邮箱搜索:曾有案例,通过联系人名字进行匹配到了另一个客户在其他域名的个人邮箱,差点将该账户的失败付款信息写入本次简报。若仍需搜索邮箱,需先读取收件人域名,再将消息视为该账户的通信记录。在Vitally属性和Postgres读取内容重叠的部分,需同时保留并交叉验证。每次运行都需使用明确的开始/结束窗口运行日历查询(无边界文本搜索返回空结果),优先按主题中的参会者姓名查询,否则按账户名称和管理员邮箱查询。
get_account_conversationssource: "google"zendeskget_account_feature_requestsget_account_healthvitally.messagesvitally.notesvitally.tasksgog gmail searchAccepted:主程序需手动记住四个名称,因为主程序无需打开查询文件即可验证数字。表示限制实际影响产品的事件是**;修改限制的执行者是;实时预测是与通过关联**;当前限制是****。此处猜测列名会返回空结果,而该结果会被解读为“无限制”,与事实完全相反。这些是指向而非方案:在撰写任一查询前,打开中的和,因为两者都包含决定结果是否有意义的过滤器和别名,仅根据本段内容编写SQL会生成全空列和400错误。
org_quota_limited_untilbilling limits updatedbilling_customerbilling_upcominginvoicecustomer_idcustom_limits_mapqueries-money.mdquota-limitsin-flight-period通话准备需运行所有角色。邮件运行可跳过账户未涉及的产品对应的角色,并列出每个被跳过的角色。在任何模式下,仅当读取操作不适用时才跳过,并列出每个跳过的操作。回溯30天的数据;仅当更短的窗口会改变结论时,才重新运行单个查询(跟进邮件回溯14天,当周通话准备回溯7天)。
Step 3. Mode detection
步骤3:模式检测
This step flags, it never blocks; any mode or request runs on any account. The skill only drafts, so a human weighs every output; raise contradictions loudly, never withhold work.
Flag at the top when the account looks already-handled: false, a terminal stage (, , ), or a teammate's recent message on the same topic. An assignment is never a flag; only an active thread is.
onboardingMinimumEligibility3. Onboarding Completed6c. Sales Handoff7. Paid Call PurchasedThe user's explicit ask always wins: "draft outreach for X" produces the draft whatever the account state, flag leading, never a refusal. The signals below decide only when the ask is open. A pasted inbound is a reply; a named call is call prep.
| Signal | Read from | Watch for | |
|---|---|---|---|
| stage | Pipeline stage | | The only field carrying the stage, and every live value carries a numeric prefix: |
| outreach | Initial outreach sent | | Fall back to |
| threads | Onboarding-team conversations | | AE and support threads do not count |
| meeting | Booked FUTURE meeting | conversation | A hint only. Confirm the date on the calendar and fall through if the meeting is past, declined or not found, or a stale acceptance routes to call prep forever |
| inbound | Inbound after outbound | | Counts AE, CSM and support threads and fires on system messages, so it is often true off a calendar acceptance. A prompt to read the actual latest inbound body, never a reason to route alone. If the latest inbound is a calendar or system message, or is addressed to another owner, the signal is not satisfied |
Read the stage from the trait, not from / Vitally . Those are a different field with a different vocabulary (, , , , , ), carry no and no , and no value matches the trait's exactly. Segments corroborate the stage and hold the durable sales-referral record; they never define the stage.
crm_segmentssegmentsOnboarding LeadOnboarding referralCSM ManagedTAMTop 20Annual PlanNew AccountSales HandoffRouting, for an open ask only:
- Terminal stage, or a live thread on the same topic held by a teammate OR by the sender: the flag leads, the research is still full, and the recommendation is a note or a loop-in rather than cold outreach. This sets the framing and never the mode, so carry on down the list; a run that stops here has a flag and no output. The sender's own recent thread is a collision exactly like a teammate's: not a reason to withhold a draft, but the thing the draft must not repeat.
- inbound true and the latest inbound is a real customer question: email, reply state
- else meeting present: call prep
- else stage is , or absent with
1. New Accounttrue and no AE or CSM, outreach null, threads 0: email, first-touch state. An absent stage beside an assigned AE or CSM falls through to 4onboardingMinimumEligibility - else email, follow-up state
Read the conversation history before finalizing; thread context outranks any single signal. Flag and keep going on: outreach exists but stage still ; stage with no outreach trace; terminal timestamps on a non-terminal stage, the signature of a sales-disqualification reset.
1. New Account2. Onboarding Initiated此步骤仅标记,绝不阻塞;任何模式或请求都可在任何账户上运行。本技能仅负责起草内容,因此所有输出都需由人工审核;需大声指出矛盾之处,绝不停止工作。
当账户看起来已被处理时,在顶部标记:为false、处于终端阶段(、、),或队友近期就同一主题发送过消息。分配任务不属于标记;仅活跃线程属于标记。
onboardingMinimumEligibility3. Onboarding Completed6c. Sales Handoff7. Paid Call Purchased用户的明确请求始终优先:“为X起草外展邮件”会生成草稿,无论账户状态如何,标记放在开头,绝不拒绝。仅当请求不明确时,以下信号才会起作用。粘贴的入站消息属于回复;指定的通话属于通话准备。
| 信号 | 读取来源 | 注意事项 | |
|---|---|---|---|
| 阶段 | 管道阶段 | | 这是唯一携带阶段信息的字段,所有有效值都带有数字前缀: |
| 外展 | 首次外展已发送 | | 回退到 |
| 线程 | 入职团队对话 | | AE和支持线程不计入 |
| 会议 | 已预订的未来会议 | 来源为 | 仅作为提示。需在日历上确认日期,若会议已过去、被拒绝或未找到,或接受信息已过期,则不路由到通话准备 |
| 入站 | 外展后的入站消息 | | 计入AE、CSM和支持线程,且会因系统消息触发,因此常因日历接受消息而返回true。这仅提示需读取最新的入站消息内容,绝不能单独作为路由依据。若最新入站消息是日历或系统消息,或发送给其他负责人,则该信号不满足 |
从属性读取阶段,而非从/Vitally 读取。这些是不同的字段,使用不同的词汇(、、、、、),不包含和,且无值与属性中的值完全匹配。Segments可佐证阶段,并保留持久的销售推荐记录;但绝不定义阶段。
crm_segmentssegmentsOnboarding LeadOnboarding referralCSM ManagedTAMTop 20Annual PlanNew AccountSales Handoff仅当请求不明确时进行路由:
0. 处于终端阶段,或队友/发送者就同一主题存在活跃线程:标记放在开头,调研内容仍完整,建议为备注或抄送而非冷外展。这仅设置框架而非模式,因此继续执行后续步骤;若运行在此处停止,仅会有标记而无输出。发送者自身的近期线程与队友的线程冲突情况完全相同:不是拒绝起草的理由,但草稿必须避免重复内容。
- 入站信号为true且最新入站消息是客户的真实问题:邮件,回复状态
- 否则存在会议:通话准备
- 否则阶段为,或阶段缺失且
1. New Account为true、无AE或CSM、外展为空、线程数为0:邮件,首次联系状态。若阶段缺失且已分配AE或CSM,则进入步骤4onboardingMinimumEligibility - 否则邮件,跟进状态
在最终确定前读取对话历史;线程上下文优先级高于任何单个信号。标记并继续执行以下情况:外展已发送但阶段仍为;阶段为但无外展痕迹;非终端阶段存在终端时间戳(销售取消资格重置的特征)。
1. New Account2. Onboarding InitiatedStep 4. People on the account (report it, do not route on it)
步骤4:账户相关人员(仅报告,不用于路由)
Report the roster in the header every run, assigned or not: . Middle dots, never pipes, which break the table cell.
OS <name or NONE> · CSM <name or NONE> · AE <name or NONE>An assignment is roster data, never a warning; an active thread earns the flag. An OS stays assigned after onboarding completes and an AE or CSM is often simply unassigned, so is common and correct. Never turn either into "this belongs to X, check first": it reads as a blocker, is usually wrong, and buries the research. A teammate who recently messaged the account on the topic at hand IS a collision: read the conversation history for that, not the ownership fields.
NONESources in order: the Vitally array (the rows in ) carries role label, email and name together; / and Vitally / corroborate; and are the fallback. is an account tier, not a person. A set with no AE or CSM means sales passed and onboarding has the account again: note the date.
key_roleskeyroleaccount-contextaccounts_replacement_v2.csm_nameae_namecsmIdaccountExecutiveIdbilling_customer.sales_info.owner_*crm_segmentsTop 20sfdc.last_task_disqualified__cTo answer "was this account ever referred to sales", read the segment, not the stage. Adding that segment fires the handoff playbook and it persists after the stage moves on, so a referred account routinely shows another stage. Read it with : segment present and disqualified means it came back and is yours; segment present and not disqualified means sales still has it.
Onboarding referralsfdc.last_task_disqualified__cOn annual plans read , , , , . Credits projected to run out before the plan ends go in the header, since they change the conversation rather than the draft.
purchasedCreditAmountstripe.accountBalancecreditRunwayDaysprojectedCreditExpiryDatecreditExpiryVsAnnualPlanExpiry每次运行都需在标题中报告人员名单,无论是否已分配:。使用中间点分隔,绝不使用竖线,否则会破坏表格单元格。
OS <姓名或NONE> · CSM <姓名或NONE> · AE <姓名或NONE>分配信息是名单数据,绝非警告;活跃线程才需要标记。OS在入职完成后仍会保留分配状态,AE或CSM常未分配,因此是常见且正确的。绝不要将其改为“此账户属于X,请先确认”:这会被视为阻塞,通常是错误的,且会掩盖调研内容。若队友近期就该主题与账户有过通信,则属于冲突:需读取对话历史,而非依赖所有权字段。
NONE来源优先级:Vitally的数组(中的行)同时包含角色标签、邮箱和姓名;/和Vitally的/用于佐证;和作为备用。是账户层级,而非人员。若已设置且无AE或CSM,表示销售团队已转交,入职团队重新负责该账户:需注明日期。
key_rolesaccount-contextkeyroleaccounts_replacement_v2.csm_nameae_namecsmIdaccountExecutiveIdbilling_customer.sales_info.owner_*crm_segmentsTop 20sfdc.last_task_disqualified__c若要回答“该账户是否曾推荐给销售团队”,需读取 segment,而非阶段。添加该segment会触发转交流程,且阶段变更后仍会保留,因此已推荐的账户通常会显示其他阶段。结合读取:存在segment且已取消资格,表示账户已返回并由你负责;存在segment且未取消资格,表示销售团队仍负责该账户。
Onboarding referralsfdc.last_task_disqualified__c对于年度计划,需读取、、、、。若预计信用额度在计划到期前耗尽,需在标题中说明,因为这会改变对话内容而非草稿内容。
purchasedCreditAmountstripe.accountBalancecreditRunwayDaysprojectedCreditExpiryDatecreditExpiryVsAnnualPlanExpiryStep 5. Output
步骤5:输出
No em dashes, en dashes or double hyphens in any output, the internal brief included.
Read before drafting anything a customer will see, before stating any recommendation, and the one mode file for the artifact.
references/voice.mdreferences/levers.mdCommon header for every email and every call-prep brief, and for any other ask whose artifact is an account brief. Render it as a real markdown table, never inside a code fence (the fence below is only the template's source). Drop a row that does not apply rather than writing .
n/aundefined任何输出(包括内部简报)中不得使用破折号、短破折号或双连字符。
在起草任何客户可见内容前,读取;在提出任何建议前,读取;并读取对应模式的文件。
references/voice.mdreferences/levers.md所有邮件和通话准备简报,以及任何其他生成账户简报的请求,都需使用通用标题。将其渲染为真实的Markdown表格,绝不放在代码块中(以下代码块仅为模板来源)。若某行不适用则删除,绝不写。
n/aundefined<Account> | <Artifact: first touch / follow-up / reply / call prep>
<账户名称> | <输出类型:首次联系 / 跟进 / 回复 / 通话准备>
Flag: <only when one applies: a teammate's live thread on this topic, a stage mismatch, a sibling org. Never a roster name.>
| Pipeline | <stage> |
| Health | <X>/10 |
| Renewal | <date> (<n> days, monthly cycle or contract) |
| MRR | $<actual> booked to $<forecast> forecast (<±delta>) |
| Paid | <products> |
| Limits set | <product $each>. Mark any at or near its forecast; say NONE where the largest line has no limit |
| Limits biting | Which products a limit has ACTUALLY cut off, from |
| People | OS <name or NONE> · CSM <name or NONE> · AE <name or NONE> |
| Users | <total> listed, <n> with seats, <n> with real activity |
| Org | <link> |
Header field rules, since several traits collide:
| Field | Rule |
|---|---|
| Renewal | On an annual plan `nextRenewalDate` is the monthly billing-cycle end, not the contract renewal: use `contractRenewalDate` (or `numberOfDaysUntilEndOfContract`). On a monthly account they are the same |
| MRR | `usage_mrr` is actual, `forecasted_mrr` is forecast, both net of any credit discount (`forecasted_usage_mrr` is the gross figure, do not mix them). Delta is `forecasted_mrr - usage_mrr`; a negative delta on an annual account is usually the annual-vs-usage artifact, not churn. `diff_dollars` is a different comparison |
| Health | `healthScore` from `get_user_details`. Two warehouse columns share the name and neither belongs here: `vitally.accounts.health_score` is a stale copy, `account_health_scores.health_score` is PostHog's own engagement model |
| Users total | `usersCount` from `get_user_details`; per-query counts can differ |
| Org link | `https://us.posthog.com/project/2/groups/0/<ORG_ID>` (organization is group type 0) |
Before handing the output over, confirm all eight and send anything unchecked back to the round that owns it: every claim traces to this run's queries or live searches; every skip is named per subagent with its reason; every trap hit is reported, and a run reporting none was interrogated; every source disagreement shows both figures unresolved; the header is a real table with the People row present; **no section shipped as settled while an agent owning its subject was still running**; the Round 3 roll call ran and any shortfall is named; the closing note states both figures.
**The write gate is the one traded away under time pressure, so it is explicit: a still-running agent owns its subject until it returns.** Wait for it, or write the section and mark it provisional in the output. Marked provisional satisfies the checklist; shipped as settled does not. A confident section a pending agent then contradicts costs the user a correction on work they have already read, and may have already acted on.标记: <仅在适用时填写:队友就该主题的活跃线程、阶段不匹配、关联组织。绝不填写名单姓名。>
| 管道阶段 | <阶段内容> |
| 健康评分 | <X>/10 |
| 续约日期 | <日期>(剩余<n>天,月度周期或合同) |
| MRR | 已入账$<实际值>,预测$<预测值>(<±差值>) |
| 已购产品 | <产品列表> |
| 已设置限制 | <产品 $每个>。标记任何接近预测值的限制;若最大项目无限制则写NONE |
| 生效限制 | 哪些产品实际被限制影响,来自 |
| 相关人员 | OS <姓名或NONE> · CSM <姓名或NONE> · AE <姓名或NONE> |
| 用户数量 | 共<总数量>,<n>个拥有席位,<n>个有真实活动 |
| 组织链接 | <链接> |
标题字段规则,因多个属性存在冲突:
| 字段 | 规则 |
|---|---|
| 续约日期 | 对于年度计划,`nextRenewalDate`是月度计费周期结束日期,而非合同续约日期:需使用`contractRenewalDate`(或`numberOfDaysUntilEndOfContract`)。对于月度账户,两者相同 |
| MRR | `usage_mrr`是实际值,`forecasted_mrr`是预测值,均扣除信用折扣(`forecasted_usage_mrr`是总值,请勿混淆)。差值为`forecasted_mrr - usage_mrr`;年度账户的负差值通常是年度计费与使用量的差异,而非流失。`diff_dollars`是另一种比较方式 |
| 健康评分 | 来自`get_user_details`的`healthScore`。数据仓库中有两个同名列均不适用:`vitally.accounts.health_score`是过时副本,`account_health_scores.health_score`是PostHog自身的参与度模型 |
| 总用户数 | 来自`get_user_details`的`usersCount`;各查询的计数可能不同 |
| 组织链接 | `https://us.posthog.com/project/2/groups/0/<ORG_ID>`(组织为组类型0) |
在交付输出前,确认以下八项内容,将未检查的内容返回给负责的轮次:所有声明都可追溯到本次运行的查询或实时搜索;每个跳过操作都由子代理注明原因;每个陷阱触发情况都已报告,未报告任何陷阱的运行需重新检查;所有来源分歧都展示了两个未解决的数据;标题为真实表格且包含相关人员行;**无任何部分在负责该内容的代理仍在运行时被标记为已完成**;第3轮角色点名已执行,任何缺口都已注明;结束说明包含两个统计数字。
**写入闸门是时间压力下最容易被忽略的部分,因此需明确:仍在运行的代理对其负责的内容拥有所有权,直到返回结果**。等待代理返回,或撰写该部分并在输出中标记为临时内容。标记为临时内容符合检查清单要求;标记为已完成则不符合。若已完成的部分被后续返回的代理结果矛盾,会导致用户需要更正已阅读甚至已执行的工作。Pipeline reminder
管道提醒
A reminder to raise with the user, never a write to perform unless they ask for that write in so many words. Once they say they acted: outreach sent means moves to ; passed to sales means . Suggest a Vitally note only when the research concluded "do not reach out", recording why. A draft-only run needs no write.
Onboarding Pipeline2. Onboarding Initiated6c. Sales Handoff此提醒需告知用户,绝不自行执行写入操作,除非用户明确要求。当用户表示已执行操作时:外展邮件已发送表示需改为;转交销售团队表示。仅当调研结论为“请勿联系”时,才建议在Vitally中添加备注,记录原因。仅起草内容的运行无需执行写入操作。
Onboarding Pipeline2. Onboarding Initiated6c. Sales HandoffImproving the skill
技能改进
When a run reveals a fix, ask whether to fold it in. Write the rule into the file that owns it, in the fewest words, and fix the rule that failed rather than adding an exception. Two rules keep these files honest. Every line changes what the model does; provenance, measurements and orientation go to , which is never loaded at runtime, or get cut. The shape of the data is durable and gets written down (a join key, a column that does not exist, an id that collides across regions); the state of the product is perishable and belongs nowhere (which SDKs support a feature, what a tier costs, where a setting lives), so search for it every time and never record the answer.
README.md当运行发现需修复的问题时,询问用户是否将修复整合到技能中。将规则写入负责该内容的文件,用最少的文字表述,修复失败的规则而非添加例外。两条规则可保持文件的准确性。每一行内容都需改变模型的行为;来源、测量和说明性内容需放入(该文件不会在运行时加载)或删除。数据的结构是持久的,需记录下来(关联键、不存在的列、跨区域冲突的ID);产品的状态是易变的,绝不记录(哪些SDK支持某功能、某层级的价格、设置位置),因此每次都需搜索,绝不记录答案。
README.md