exploring-signals-scouts
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseExploring Signals scouts
探索Signals scouts
A scout is a scheduled agent that wakes on its own interval, looks at one PostHog project,
decides what's genuinely worth surfacing, and either emits it as a finding into the Signals
inbox or closes out empty (a real, valid outcome). PostHog ships a fleet of canonical scouts — a
cross-product generalist () plus per-surface specialists (error tracking,
logs, AI observability, experiments, feature flags, session replay, web analytics, surveys, and
more). A project may also have custom scouts beyond the canonical fleet — any
skill a team authored (e.g. , ) shows up here
too, so don't assume a fixed roster: is the authoritative roster for
a project. (One caveat: a just-authored scout has no config row until the coordinator's next
tick auto-registers one — or until someone registers it via the write-side
— so a brand-new scout may briefly be missing from the list.)
signals-scout-generalsignals-scout-*-brand-mentions-mcp-feedbacksignals-scout-config-listsignals-scout-config-createThis skill helps you understand and explore what a project's scouts are doing and how they're
performing — entirely through read-only MCP tools. It is the observability counterpart to
the skill (which teaches writing and tuning) and to the
skill (which covers the inbox reports scouts feed into).
authoring-signals-scoutsinbox-explorationThere are five things you can observe about the fleet, each with its own tool:
| What you want to know | Tool | What it tells you |
|---|---|---|
| Which scouts run, how often, in what posture | | One row per scout: schedule, |
| What the scouts actually did, run by run | | Per-run status, timing, end-of-run summary, |
| What the fleet has learned across runs | | Durable per-team memory (baselines, noise, allowlists) |
| What the scouts actually emitted | | The authoritative per-finding record (weight, severity, confidence) — see below |
| What the scouts surfaced to the user | | Findings that cleared the bar and became inbox reports |
The orienting sixth is — the deterministic snapshot of "what's
true about this project" that every scout cold-starts from. When a scout found nothing, this is
usually why.
signals-scout-project-profile-getscout是一种定时运行的Agent,会按照自身间隔周期启动,查看单个PostHog项目,判断哪些内容真正值得呈现,并将其作为finding发送至Signals收件箱,或者无结果结束运行(这是真实且有效的结果)。PostHog提供一系列标准scout舰队——包括跨产品通用型scout()以及各领域专用型scout(覆盖错误追踪、日志、AI可观测性、实验、功能标志、会话重放、Web分析、调研等)。除标准舰队外,项目还可能拥有自定义scout——团队编写的任何技能(例如、)都会在此显示,因此不要假设scout列表是固定的:是项目scout的权威清单。(注意:刚编写完成的scout在协调器下次自动注册前,或通过写入端工具手动注册前,不会有配置条目——因此全新scout可能会短暂不在清单中。)
signals-scout-generalsignals-scout-*-brand-mentions-mcp-feedbacksignals-scout-config-listsignals-scout-config-create本技能可帮助你理解并探索项目中scout的运行情况与性能表现——完全通过只读MCP工具实现。它是技能(用于编写和调整scout)和技能(用于探索scout推送的收件箱报告)的可观测性配套工具。
authoring-signals-scoutsinbox-exploration你可以通过五种工具观测scout舰队的不同维度:
| 你想了解的内容 | 工具名称 | 工具说明 |
|---|---|---|
| 哪些scout在运行、运行频率、运行状态 | | 每个scout对应一行:调度计划、 |
| scout每次运行的实际操作内容 | | 单条运行记录的状态、时间、运行结束总结、 |
| 舰队在多次运行中积累的知识 | | 团队级持久化内存(基准线、噪音、白名单) |
| scout实际发送的内容 | 基于 | 权威的单条finding记录(权重、严重程度、置信度)——详见下文 |
| scout向用户呈现的内容 | | 达标并成为收件箱报告的findings |
第六个定位工具是——它是每个scout启动时都会加载的“项目真实状态”确定性快照。当scout无结果时,通常可以通过它找到原因。
signals-scout-project-profile-getOutput handling: expect to offload to a file
输出处理:准备将结果导出至文件
Two of these tools — and especially
— routinely return payloads that overflow an MCP client's
token budget and get spilled to a file. This is the normal path, not an error. Plan for it up
front rather than discovering it after a failed call:
signals-scout-runs-listtasks-runs-session-logs-retrieve- Keep small on
limit(~10–15). Each row carries a long prosesignals-scout-runs-list, and runs come back newest-first across the whole fleet, so even a modest page is large.summary - Session logs are large by nature. A single run's log is hundreds of KB to a few MB. Fetch it
with (so the saved file is real JSON, not the pretty text format —
call --json-able) and read the saved file withjq/ a script rather than inline.jq - Don't hand-parse the session log. The bundled do the reconstruction for you — see below.
scripts/
其中两个工具——,尤其是——返回的负载通常会超出MCP客户端的令牌限制,从而自动导出至文件。这是正常流程,并非错误。请提前做好准备,避免调用失败后才发现问题:
signals-scout-runs-listtasks-runs-session-logs-retrieve- 在中设置较小的
signals-scout-runs-list值(约10–15)。每行都包含较长的文本limit,且运行记录按时间倒序返回(覆盖整个舰队),因此即使是少量结果也会占用较大空间。summary - 会话日志本身体积较大。单次运行的日志大小从数百KB到几MB不等。请使用****获取日志(这样保存的文件是标准JSON格式,而非格式化文本——可通过
call --json工具解析),并使用jq或脚本读取保存的文件,而非直接在终端查看。jq - 不要手动解析会话日志。配套的会帮你重构内容——详见下文。
scripts/
Start here: is the fleet even set up?
第一步:舰队是否已配置?
Don't assume the project has scouts. The fleet only runs on teams enrolled via the
feature flag, and a project may have no configs, all-disabled scouts, or scouts stuck in dry-run.
Run this first whenever a user asks about their scouts for the first time in a session.
signals-scoutjson
signals-scout-config-listRead the result against three cases:
The config list is unpaginated — it comes back as (a bare array), with no
field. Read the result against three cases:
{ results: [...] }count-
Empty () — no scouts are registered. The project isn't enrolled in the scout fleet (or hasn't ticked yet). Say so plainly; don't go fishing for runs. Point the user at the Signals scout settings / PostHog Code onboarding rather than inventing activity.
results: [] -
Configs exist but all— the fleet is registered but paused. Nothing is running. Tell the user which scouts exist and that they're all off.
enabled: false -
At least one— the fleet is registered and that scout is allowed to run. For each enabled scout note its
enabled: true(cadence),run_interval_minutes(false = dry-run, runs but writes nothing to the inbox), andemit. One caveat before reporting "it's live": runs are gated by thelast_run_atfeature flag, not bysignals-scout. A project that was enrolled and later drained from the flag keeps itsenabledrows, but the coordinator no longer plans runs for it — so a stale orenabled: truenullon an enabled scout usually means the project is no longer enrolled, not that the scout is idle.last_run_atis a dispatch stamp, not proof a run executed. The coordinator advances it the moment it enqueues a child workflow for a due scout — before any worker picks the run up. Child dispatch is fire-and-forget, so if workers are saturated or down the children just queue and no run ever materializes, yetlast_run_atkeeps marching forward each tick. So a recentlast_run_atmeans "dispatched this tick," not "a run is genuinely happening." The authoritative liveness signal is the newest actual run row inlast_run_at, not the config stamp. Cross-check them: ifsignals-scout-runs-listis fresh (minutes ago) but no run row has appeared for that scout in well over itslast_run_at, the fleet is dispatching but not running — workers backed up / down, or runs stranded — a real reliability problem, not a live scout. Don't report "it's running" offrun_interval_minutesalone.last_run_at
A scout that is but is the most common source of "my scout isn't
doing anything" confusion: it is running and reasoning every tick, it just isn't allowed to post
findings yet. Always surface the posture when reporting on a scout.
enabled: trueemit: falseemitSee for every field on a config,
run, and scratchpad entry, the run status values, and how the pieces link together.
references/scout-data-model.md不要默认项目已部署scout。只有通过功能标志加入的团队才会运行scout舰队,项目可能没有配置、所有scout都处于禁用状态,或者scout处于试运行模式。当用户首次询问scout相关问题时,请先运行以下命令:
signals-scoutjson
signals-scout-config-list根据以下三种情况解读结果:
配置列表无需分页——返回格式为(纯数组),无字段。请对照以下三种情况解读:
{ results: [...] }count-
空数组()——未注册任何scout。项目未加入scout舰队(或尚未完成首次调度)。请直接告知用户,无需继续查找运行记录。引导用户查看Signals scout设置或PostHog代码入门文档,而非假设存在运行活动。
results: [] -
存在配置但所有scout的——舰队已注册但处于暂停状态。没有scout在运行。告知用户存在哪些scout,且所有scout均已关闭。
enabled: false -
至少有一个scout的——舰队已注册且该scout允许运行。对于每个启用的scout,请注意其
enabled: true(运行频率)、run_interval_minutes状态(false = 试运行模式,正常运行但不会向收件箱写入内容)和emit。在报告“scout已启动”前需注意一点:运行受last_run_at功能标志控制,而非signals-scout状态。如果项目曾加入舰队但后来被移除功能标志,scout的enabled状态会保留,但协调器不再为其规划运行——因此启用的scout若enabled: true过期或为last_run_at,通常意味着项目已不再属于舰队,而非scout闲置。null是调度时间戳,而非运行执行的证明。协调器在将子工作流加入队列的瞬间就会更新该时间戳——早于任何工作进程启动运行。子工作流是“即发即弃”模式,因此如果工作进程饱和或宕机,子工作流只会停留在队列中,不会实际运行,但last_run_at仍会在每次调度时更新。因此近期的last_run_at仅表示“本次调度已加入队列”,不代表“scout正在实际运行”。权威的活跃状态信号是last_run_at中最新的实际运行记录,而非配置中的时间戳。请交叉验证:如果signals-scout-runs-list是近期(几分钟前),但该scout的最新运行记录已远超其last_run_at,则舰队处于已调度但未运行状态——工作进程积压/宕机,或运行任务滞留——这是真实的可靠性问题,而非scout正常运行。不要仅通过run_interval_minutes就报告“scout正在运行”。last_run_at
enabled: trueemit: falseemit关于配置、运行记录和暂存内存条目的所有字段、运行状态值以及各模块的关联方式,请参阅。
references/scout-data-model.mdWorkflow: survey the fleet
工作流:查看舰队整体情况
"What scouts do I have / what are they doing?" — lead with , then enrich with the
most recent run per scout so the user sees liveness, not just configuration.
config-list- — the roster.
signals-scout-config-list - For each enabled scout, and pick the newest run with a matching
signals-scout-runs-list(runs come back newest-first across the whole fleet, so a single call usually covers everyone). Reportskill_nameand how long ago it ran.status
Present it as a table the user can scan — scout, cadence, posture, last run, last outcome — and
call out anything anomalous (never run, last run errored, stuck in dry-run for a long time).
“我有哪些scout?它们在做什么?”——先使用获取清单,再为每个启用的scout补充最新运行记录,让用户了解活跃状态,而非仅查看配置。
config-list- ——获取scout清单。
signals-scout-config-list - 对于每个启用的scout,调用并选择匹配
signals-scout-runs-list的最新运行记录(运行记录按时间倒序返回,覆盖整个舰队,因此单次调用通常可获取所有scout的最新记录)。报告运行skill_name和运行时间。status
将结果整理为用户易于扫描的表格——包含scout名称、运行频率、状态、上次运行时间、上次运行结果——并标注异常情况(从未运行、上次运行出错、长期处于试运行模式等)。
Workflow: understand one scout end to end
工作流:深入了解单个scout的完整流程
"How does my error-tracking scout work / how is it doing?"
- Read its config — find the row in for
config-list: schedule, posture, last run.signals-scout-error-tracking - Read its body — returns the team's actual instruction set (which may be a canonical default or a diverged, hand-edited row). This is what the agent is told to do every run — its signal-vs-noise discriminator, explore patterns, and disqualifiers. To understand why a scout behaves the way it does, read its body.
posthog:llma-skill-get {"skill_name": "signals-scout-error-tracking"} - Read its recent runs — with
runs-listset to the skill's domain, or just scan the newest runs and filter to itstext. The end-of-runskill_nameon each run is the scout's own account of what it looked at and decided.summary - Read what it remembered — (see below). The memory entries a scout wrote reveal the baselines and noise it has internalized about this project.
scratchpad-search
“我的错误追踪scout是如何工作的?性能如何?”
- 查看配置——在中找到
config-list的条目:调度计划、状态、上次运行时间。signals-scout-error-tracking - 查看技能内容——调用返回团队实际使用的指令集(可能是标准默认内容,也可能是经过手动编辑的自定义内容)。这是scout每次运行时遵循的规则——包括信噪比判别逻辑、探索模式和排除条件。要理解scout的行为原因,请阅读其技能内容。
posthog:llma-skill-get {"skill_name": "signals-scout-error-tracking"} - 查看近期运行记录——调用并设置
runs-list为该技能的领域关键词,或直接扫描最新运行记录并筛选其text。每条运行记录的结束skill_name是scout对自身操作和决策的描述。summary - 查看记忆内容——调用(详见下文)。scout写入的内存条目揭示了它对该项目的基准线和噪音的认知。
scratchpad-search
Workflow: read recent runs
工作流:读取近期运行记录
signals-scout-runs-list- Scope to a window with /
date_from(ISO-8601; inclusive lower, exclusive upper ondate_to). Walk backwards by passing an earliercreated_at.date_to - Search summaries with — a case-insensitive substring match on each run's end-of-run
text. This is how the headless scout dedupes, and it's how you find "did any run already look at the checkout error spike?"summary - Filter by emit outcome with —
emittedreturns only runs that surfaced at least one finding,emitted=trueonly the quiet runs. This is the direct way to answer "which runs actually emitted something?" without parsing prose.emitted=false
Each summary row carries , , , , ,
, (how many findings the run emitted), (their
ids), (a deep-link into the Tasks UI for the full transcript), and the prose.
Lead with the when narrating to the user — it's the scout's own plain-language close-out —
and always offer the for the full reasoning.
run_idskill_nameskill_versionstatusstarted_atcompleted_atemitted_countemitted_finding_idstask_urlsummarysummarytask_urlsignals-scout-runs-list- 按时间范围筛选:使用/
date_from(ISO-8601格式;date_to包含下限,排除上限)。通过设置更早的created_at可回溯历史记录。date_to - 搜索总结内容:使用——对每条运行记录的结束
text进行不区分大小写的子串匹配。这是无界面scout进行去重的方式,也可用于查找“是否有运行记录已检查过结账错误激增问题?”summary - 按发送结果筛选:使用——
emitted仅返回至少发送一个finding的运行记录,emitted=true仅返回无结果的运行记录。这是直接回答“哪些运行记录实际发送了内容?”的可靠方式,无需解析文本。emitted=false
每条总结记录包含、、、、、、(运行发送的finding数量)、(finding的ID)、(指向Tasks UI的深度链接,可查看完整记录)和文本。向用户汇报时,优先展示——这是scout用自然语言撰写的运行总结——并始终提供供用户查看完整推理过程。
run_idskill_nameskill_versionstatusstarted_atcompleted_atemitted_countemitted_finding_idstask_urlsummarysummarytask_urlWorkflow: drill into a single run
工作流:深入分析单次运行记录
When the user wants the full story of one run (or pastes a run id / Tasks URL):
json
signals-scout-runs-retrieve
{ "id": "<uuid>" }Note the field name flip: returns each run's id as , but
takes it as . Pass the value through as .
runs-listrun_idruns-retrieveidrun_ididReturns the full run: , / (compute duration from these),
/ (what ran, at what body version), the end-of-run ,
/ , and . The transcript — the actual tool calls and
reasoning — lives in the Tasks UI behind , not in this payload; hand the user that link
when they want to see every step. A failed run returns an empty and no error
field — the payload looks the same as the list row, so to learn why it failed you need the
transcript.
statusstarted_atcompleted_atskill_nameskill_versionsummaryemitted_countemitted_finding_idstask_urltask_urlsummaryYou don't have to open the UI for that: returns the run's
session log (every tool call, message, and reasoning step) as data — handy when you're
diagnosing a failure or want to trace exactly what a run did without leaving the conversation. Pass
the run's as and its (both are on the run row).
tasks-runs-session-logs-retrievetask_run_ididtask_idThe raw stream is large (hundreds of KB to a few MB) and will overflow inline, so fetch it with
and let it spill to a file, then run it through
rather than parsing it by hand.
call --jsonscripts/render_run_report.py⚠️ Do not reach for to slim it down. It is tempting —
the stream is dominated by incremental chunks — but each tool's actual input
lives only in those chunks: the base event carries an empty , and the
streamed updates build the input (and the final ) token by token. Excluding them leaves
you with tool names but no idea what the scout actually queried. Fetch the full log and let
the script reassemble each call (it groups by , keeps the richest , and
attaches the completion's /).
exclude_types: "tool_call_update,…"tool_call_updatetool_callrawInputrawOutputtoolCallIdrawInputrawOutputstatusWhether a run emitted is a first-class field: . means the
run surfaced that many findings; means it closed out empty. Don't parse the prose
for this any more — a phrase like "already emitted P1 … did not re-emit" describes a
prior run, so substring-matching the summary for "emitted" is unreliable, whereas
is the authoritative tally. lists the s behind that count, in emit
order; each maps to a with , giving a
reliable run → finding link. See
for the run-to-finding link and how an emitted finding rides through grouping into the
inbox filter.
emitted_countemitted_count > 0emitted_count: 0summaryemitted_countemitted_finding_idsfinding_idSignalsource_id = run:<run_id>:finding:<finding_id>references/scout-data-model.mdsource_product: "signals_scout"A run with complete and an empty-handed summary ("surface at baseline, nothing to
emit") is a healthy outcome, not a failure — most runs should close out empty. Treat a stream
of empty close-outs as the fleet doing its job, not as the fleet being broken.
status当用户想要了解某次运行的完整详情(或提供了运行ID/Tasks URL):
json
signals-scout-runs-retrieve
{ "id": "<uuid>" }注意字段名称变化:返回的运行ID字段为,但接收的参数名为。请将的值作为传入。
runs-listrun_idruns-retrieveidrun_idid返回完整运行记录:、 / (可通过这两个时间计算运行时长)、 / (运行的技能名称和版本)、结束、 / 和。完整的对话记录——包括实际工具调用和推理过程——位于指向的Tasks UI中,而非返回的负载中;当用户想要查看每一步操作时,请提供该链接。失败的运行记录会返回空的,且无错误字段——负载格式与列表条目相同,因此要了解失败原因,需要查看对话记录。
statusstarted_atcompleted_atskill_nameskill_versionsummaryemitted_countemitted_finding_idstask_urltask_urlsummary无需打开UI即可查看对话记录:会以数据形式返回运行的会话日志(包括所有工具调用、消息和推理步骤)——在诊断失败或无需离开对话即可追踪运行详情时非常有用。传入运行记录的作为,以及(两者均在运行记录中)。
tasks-runs-session-logs-retrievetask_run_ididtask_id原始日志流体积较大(数百KB到几MB),无法在终端内完整显示,因此请使用获取日志并让其自动导出至文件,然后通过处理,而非手动解析。
call --jsonscripts/render_run_report.py⚠️ 不要使用来缩小日志体积。虽然日志流主要由增量块组成,但每个工具的实际输入仅存在于这些块中:基础事件的为空,流式更新会逐步构建输入(以及最终的)。排除这些块后,你只能看到工具名称,无法了解scout实际查询的内容。请获取完整日志,然后让脚本重新组装每个调用(按分组,保留最完整的,并附上完成后的/)。
exclude_types: "tool_call_update,…"tool_call_updatetool_callrawInputrawOutputtoolCallIdrawInputrawOutputstatus运行是否发送内容是一级字段:。表示运行发送了对应数量的finding;表示运行无结果结束。无需再通过解析文本判断——类似“已发送P1…未重复发送”的描述指的是之前的运行,因此通过子串匹配“emitted”不可靠,而是权威统计。按发送顺序列出对应的;每个对应一个,其,提供了可靠的运行→finding关联。关于运行与finding的关联方式,以及发送的finding如何分组进入收件箱筛选器,请参阅。
emitted_countemitted_count > 0emitted_count: 0summarysummaryemitted_countemitted_finding_idsfinding_idfinding_idSignalsource_id = run:<run_id>:finding:<finding_id>source_product: "signals_scout"references/scout-data-model.mdstatusWorkflow: inspect what the fleet has learned
工作流:查看舰队积累的知识
The scratchpad is the fleet's durable, per-team memory — prose entries scouts write so future
runs get smarter and quieter. Reading it tells you what the fleet believes about this project.
json
signals-scout-scratchpad-search
{ "text": "error_tracking" }Returns entries newest-first (capped at 100); matches and
case-insensitively. Omit to browse everything. Each entry's carries a category
prefix that tells you what kind of learning it is:
textcontentkeytextkey| Prefix | Meaning |
|---|---|
| A baseline — how this team's data normally shapes |
| A live issue being tracked but still below the emit bar |
| A pattern the fleet has decided to ignore (dev-only, single-user…) |
| Something the team fixed or moved on from |
| A gate on re-emitting a specific issue / fingerprint / finding |
| Vetted entities never to re-surface |
| A product/surface this team doesn't use (close-out memo) |
| A tooling gap a scout noticed worth raising later |
This is the common vocabulary, not a closed set — scouts coin their own prefixes and
labels as needed (the live fleet uses heavily, for example), so treat an unfamiliar
prefix as just another category. Entries cross-reference each other with wikilinks. Keys
follow (e.g. ).
<domain>watch:[[key]]<prefix>:<domain>:<entity>dedupe:error_tracking:019e8375-…When a user asks "why isn't my scout flagging X anymore?", search the scratchpad for ,
, , and entries — the fleet may have deliberately learned to
suppress it. The canonical prefix vocabulary and the four-state dedupe classifier the fleet
reasons in terms of are documented in the skill
().
noise:addressed:dedupe:allowlist:authoring-signals-scoutsreferences/dedupe-and-memory.mdscratchpad是舰队的团队级持久化内存——scout写入的文本条目,用于让后续运行更智能、更安静。查看scratchpad可了解舰队对该项目的认知。
json
signals-scout-scratchpad-search
{ "text": "error_tracking" }返回结果按时间倒序排列(最多100条);会对和进行不区分大小写的匹配。省略可浏览所有条目。每条条目的包含类别前缀,用于说明知识类型:
textcontentkeytextkey| 前缀 | 含义 |
|---|---|
| 基准线——团队数据的正常模式 |
| 正在跟踪但未达发送阈值的实时问题 |
| 舰队决定忽略的模式(仅开发环境、单用户等) |
| 团队已修复或不再关注的内容 |
| 阻止重复发送特定问题/指纹/finding的规则 |
| 无需再次呈现的已验证实体 |
| 团队未使用的产品/领域(无结果备忘录) |
| scout发现的工具缺口,值得后续关注 |
这是通用词汇,并非封闭集合——scout会根据需要创建自定义前缀和标签(例如当前舰队大量使用前缀),因此遇到不熟悉的前缀时,将其视为新类别即可。条目之间通过维基链接相互引用。遵循格式(例如)。
<domain>watch:[[key]]key<prefix>:<domain>:<entity>dedupe:error_tracking:019e8375-…当用户询问“为什么我的scout不再标记X了?”时,请搜索scratchpad中的、、和条目——舰队可能已主动学习并抑制该内容。标准前缀词汇和舰队使用的四态去重分类器在技能的中有详细说明。
noise:addressed:dedupe:allowlist:authoring-signals-scoutsreferences/dedupe-and-memory.mdWorkflow: list what scouts have actually emitted
工作流:列出scout实际发送的内容
"What has the fleet emitted lately / show me every finding my scouts produced." The run row
carries no emit flag and no finding count, the prose is heuristic, and the inbox
filter (below) is lossy because grouping merges scout findings into mixed-source clusters. The
authoritative per-finding record is the emitted signal itself, in the
table — queryable for any team via (the general path). When a scout emits,
writes a signal with ; the scout's attribution
(, , , ) lands in , with
and at the top level.
summarydocument_embeddingsexecute-sqlemit_signalsource_product="signals_scout"skill_namefinding_idseverityconfidencemetadata.extraweightsource_idFetch with and format with — the
exact query lives in the script's header. One row per finding, filterable by any set of scouts:
execute-sqlscripts/emitted_signals.pybash
undefined“舰队最近发送了什么?展示我的scout产生的所有finding。”运行记录中没有发送标志和finding计数,文本是启发式描述,收件箱筛选器(下文)会因为分组将scout的finding合并到混合源集群中,导致信息丢失。权威的单条finding记录是表中的发送信号——可通过为任何团队查询(通用方式)。当scout发送内容时,会写入一个的信号;scout的属性(、、、)存储在中,和位于顶层。
summarydocument_embeddingsexecute-sqlemit_signalsource_product="signals_scout"skill_namefinding_idseverityconfidencemetadata.extraweightsource_id使用获取数据,并通过格式化——完整查询语句位于脚本头部。每条finding对应一行,可按任意scout集合筛选:
execute-sqlscripts/emitted_signals.pybash
undefinedcall --json execute-sql { "truncate": false, "query": "<the emitted-signals query>" } -> emitted.txt
call --json execute-sql { "truncate": false, "query": "<发送信号查询语句>" } -> emitted.txt
python scripts/emitted_signals.py --signals emitted.txt --now <ISO> [--skill mcp-feedback,general]
A row here is **ground truth that a finding persisted** — it cleared every emit gate. The flip
side matters when explaining a gap: a scout can narrate "EMITTED ..." in its `summary` yet have
the emit **silently dropped** by a preflight gate (dry-run at the time, the org hasn't approved
AI processing, or the `signals_scout` source is disabled), or the emit failed. Those never reach
this table, so a claimed-but-absent finding is itself a diagnostic, not a script bug. The emit
contract behind each row (weight vs. confidence rubrics, severity, dedupe) is documented in the
`authoring-signals-scouts` skill (`references/emit-contract.md`); the run → finding link and its
limits are in [`references/scout-data-model.md`](references/scout-data-model.md).python scripts/emitted_signals.py --signals emitted.txt --now <ISO> [--skill mcp-feedback,general]
这里的每一行都是**finding已持久化的事实**——它通过了所有发送校验。反之,当解释缺失内容时也很重要:scout可能在`summary`中描述“已发送…”,但发送可能被预检规则静默拦截(当时处于试运行模式、组织未批准AI处理、或`signals_scout`源被禁用),或发送失败。这些内容不会出现在此表中,因此声称已发送但实际不存在的finding本身就是诊断信息,而非脚本错误。每条记录背后的发送规则(权重与置信度标准、严重程度、去重逻辑)在`authoring-signals-scouts`技能的[`references/emit-contract.md`](references/emit-contract.md)中有详细说明;运行与finding的关联方式及其限制在[`references/scout-data-model.md`](references/scout-data-model.md)中。Workflow: see what scouts have surfaced
工作流:查看scout向用户呈现的内容
Scout findings reach the user as inbox reports. Filter the inbox to the scout source:
json
inbox-reports-list
{ "source_product": "signals_scout", "limit": 20 }This is the direct way to find scout-backed reports. Each finding is emitted with
, that tag rides through grouping into the report's signal metadata,
and the inbox filter keeps any report whose contributing signals include — so the
result is the set of reports the fleet has surfaced.
source_product="signals_scout"signals_scoutAn empty result means the fleet hasn't emitted (yet), not that the filter is broken. Scouts hold
a high bar — most runs close out without emitting — so on a quiet or newly enrolled project zero
scout-backed reports is the normal, expected state. For the per-run view of what emitted, work from
the runs instead: lists every emitting run, and each run's
/ tell you how many and which findings it produced (each
maps to a with ). To browse the
inbox more broadly, use the skill (statuses, suggested reviewers, drilling
into a report's underlying signals). The emit contract behind each finding — weight, confidence,
severity, the description prose — is documented in the skill
().
signals-scout-runs-list?emitted=trueemitted_countemitted_finding_idsfinding_idSignalsource_id = run:<run_id>:finding:<finding_id>inbox-explorationauthoring-signals-scoutsreferences/emit-contract.mdscout的finding会以收件箱报告的形式呈现给用户。将收件箱筛选为scout源:
json
inbox-reports-list
{ "source_product": "signals_scout", "limit": 20 }这是查找scout生成的报告的直接方式。每个finding发送时都会标记,该标签会随分组进入报告的信号元数据,收件箱筛选器会保留所有包含信号的报告——因此结果就是舰队呈现的报告集合。
source_product="signals_scout"signals_scout空结果表示舰队尚未发送内容(或尚未完成发送),不代表筛选器故障。scout的发送阈值很高——大多数运行无结果结束——因此在安静或刚加入的项目中,没有scout生成的报告是正常预期状态。要查看单次运行的发送情况,请从运行记录入手:列出所有发送过内容的运行记录,每条记录的 / 会告诉你发送的数量和对应的finding(每个对应一个,其)。要更广泛地浏览收件箱,请使用技能(状态、建议审阅人、深入分析报告的底层信号)。每个finding背后的发送规则——权重、置信度、严重程度、描述文本——在技能的中有详细说明。
signals-scout-runs-list?emitted=trueemitted_countemitted_finding_idsfinding_idSignalsource_id = run:<run_id>:finding:<finding_id>inbox-explorationauthoring-signals-scoutsreferences/emit-contract.mdWorkflow: assess health and performance
工作流:评估健康状况与性能
"Is my scout actually working / earning its cost?" There's no single metric — judge a scout over a
window of runs. Pull the runs ( with a ), then reason across the dimensions
below. The full playbook, including how to read each signal and the common failure modes, is in
.
runs-listdate_fromreferences/assessing-performance.md- Cadence adherence — are runs landing roughly every ? Large gaps mean the coordinator is skipping it (disabled, drained from the flag, or capped out on busy ticks) — or it's dispatching but the runs aren't materializing. Tell the two apart with
run_interval_minutes: if the config'slast_run_atis also stale, the coordinator stopped planning it; iflast_run_atis fresh but the newest run row is hours old, it's the dispatch-vs-execution divergence above (workers backed up / down, or runs stranded), whichlast_run_atalone hides.runs-list - Success rate — how many runs reach a clean vs. error out? A run of errors is a broken scout, not a quiet one.
status - Emit rate — what fraction of runs emitted vs. closed out empty. Read it straight off
per run (or split the window with
emitted_count/runs-list?emitted=true). Near-zero over a long window on a live surface can mean the discriminator is too strict (or the surface really is quiet); near-100% usually means it's too noisy. Most healthy scouts emit rarely.?emitted=false - Signal-to-noise — of what it emitted, how much became actionable inbox reports vs. got
suppressed? Use each emitting run's to tie runs to their
emitted_finding_idsrows, and cross-check againstSignalreport states.inbox-reports-list - Memory growth — a healthy scout accumulates /
pattern:/noise:entries over time. A scout with an empty scratchpad after many runs isn't learning.dedupe:
“我的scout是否真的在工作?是否物有所值?”没有单一指标——需要在一段时间的运行记录中评估scout。获取运行记录(使用调用),然后从以下维度分析。完整指南包括如何解读每个信号和常见故障模式,请参阅。
date_fromruns-listreferences/assessing-performance.md- 运行频率一致性——运行是否大致按照的间隔进行?较大的间隔意味着协调器跳过了该scout(已禁用、被移除功能标志、或在繁忙调度时达到上限)——或者已调度但运行未实际执行。通过
run_interval_minutes区分两种情况:如果配置中的last_run_at也过期,说明协调器已停止规划运行;如果last_run_at是近期,但最新运行记录已过时数小时,则属于上述调度与执行的差异(工作进程积压/宕机,或运行任务滞留),而last_run_at本身无法揭示这一点。runs-list - 成功率——有多少运行记录成功完成,多少运行出错?连续出错的scout是故障状态,而非安静状态。
- 发送率——发送内容的运行记录占比。直接读取每条运行记录的(或通过
emitted_count/runs-list?emitted=true拆分时间范围)。在活跃领域中长时间接近零的发送率可能意味着判别逻辑过于严格(或该领域确实很安静);接近100%通常意味着噪音过多。健康的scout发送频率通常较低。?emitted=false - 信噪比——发送的内容中,有多少成为可操作的收件箱报告,多少被抑制?使用每条发送运行记录的将运行记录与对应的
emitted_finding_ids条目关联,并与Signal的报告状态交叉验证。inbox-reports-list - 内存增长——健康的scout会随着时间积累/
pattern:/noise:条目。经过多次运行后scratchpad仍为空的scout没有学习能力。dedupe:
Helper scripts
辅助脚本
The skill bundles four pure formatters under for the most common asks.
They do no network I/O — they are the back half of an "agent fetches, script formats" split.
The pattern is always the same:
scripts/- Fetch each payload with the MCP using (raw JSON, not the pretty text format) and save it to a file. For the big ones (
call --json,runs-list) this is mandatory anyway — they overflow inline and spill to a file you can point the script at.tasks-runs-session-logs-retrieve - Run the script over those files.
All four are stdlib-only Python 3.11+ and print plain text to stdout (or ) — designed
to read well in a terminal, so save them as .
--out.txt本技能在下提供了四个纯格式化工具,用于处理最常见的需求。它们不进行网络I/O——是“Agent获取数据,脚本格式化”流程的后半部分。使用模式始终相同:
scripts/- 使用MCP的****获取每个负载(原始JSON格式,而非格式化文本)并保存至文件。对于体积较大的负载(
call --json、runs-list),这是必须的——它们会超出终端显示限制并自动导出至文件,你可以将文件路径提供给脚本。tasks-runs-session-logs-retrieve - 使用脚本处理这些文件。
所有脚本均为仅依赖标准库的Python 3.11+脚本,会向stdout(或通过指定文件)输出纯文本——专为终端阅读设计,因此建议保存为文件。
--out.txtscripts/render_run_report.py
— drill into one run
scripts/render_run_report.pyscripts/render_run_report.py
——深入分析单次运行记录
scripts/render_run_report.pyProduces the kind of detailed write-up you'd want when inspecting a single run: header
(status, duration, posture), a narrated timeline that interleaves the agent's narration with
each tool call and its real input, the end-of-run summary, and any scratchpad memory.
bash
undefined生成检查单次运行记录所需的详细报告:头部信息(状态、时长、运行状态)、将Agent的叙述与每个工具调用及其实际输入交织的叙述时间线、运行结束总结、以及所有暂存内存内容。
bash
undefinedfetch (note --json), saving each to a file:
获取数据(注意使用--json),保存至文件:
call --json signals-scout-runs-retrieve { "id": "<run_id>" } -> run.json
call --json signals-scout-runs-retrieve { "id": "<run_id>" } -> run.json
call --json tasks-runs-session-logs-retrieve { "id": "<task_run_id>", "task_id": "<task_id>", "offset": 0 } -> log.json (FULL — no exclude_types)
call --json tasks-runs-session-logs-retrieve { "id": "<task_run_id>", "task_id": "<task_id>", "offset": 0 } -> log.json (完整日志——不要使用exclude_types)
(optional) call --json signals-scout-scratchpad-search { ... } -> mem.json
(可选)call --json signals-scout-scratchpad-search { ... } -> mem.json
(optional) call --json signals-scout-config-list {} -> cfg.json
(可选)call --json signals-scout-config-list {} -> cfg.json
python scripts/render_run_report.py --run run.json --log log.json
--scratchpad mem.json --config cfg.json --out report.txt
--scratchpad mem.json --config cfg.json --out report.txt
Modes (`--mode`, default `detailed`):
| Mode | Contains | `--log` needed? |
| ---------- | ------------------------------------------------------------------ | --------------- |
| `summary` | header + posture + close-out prose | no |
| `detailed` | + narrated timeline with tool **inputs** + tool tally + scratchpad | yes |
| `full` | + each tool call's (truncated) **output** inline | yes |
Other flags: `--show-output` (outputs in detailed mode), `--input-width` / `--output-width`
(truncation), `--no-art` (skip the hedgehog banner), `--base-url` (defaults to `us.posthog.com`).python scripts/render_run_report.py --run run.json --log log.json
--scratchpad mem.json --config cfg.json --out report.txt
--scratchpad mem.json --config cfg.json --out report.txt
模式(`--mode`,默认`detailed`):
| 模式 | 包含内容 | 是否需要`--log`? |
| ---------- | ------------------------------------------------------------------ | --------------- |
| `summary` | 头部信息 + 运行状态 + 结束文本 | 否 |
| `detailed` | + 包含工具输入的叙述时间线 + 工具统计 + 暂存内存 | 是 |
| `full` | + 每个工具调用的(截断)输出内容 | 是 |
其他参数:`--show-output`(在detailed模式下显示输出)、`--input-width` / `--output-width`(截断长度)、`--no-art`(跳过刺猬横幅)、`--base-url`(默认`us.posthog.com`)。scripts/fleet_survey.py
— survey the whole fleet
scripts/fleet_survey.pyscripts/fleet_survey.py
——查看整个舰队情况
scripts/fleet_survey.pyOne scannable table — scout, enabled, posture, cadence, last run, last outcome — with a "worth a
look" section that flags never-run, stuck-in-dry-run, and last-run-failed scouts.
bash
undefined生成一个易于扫描的表格——包含scout名称、启用状态、运行状态、运行频率、上次运行时间、上次运行结果——并附带“值得关注”部分,标记从未运行、长期处于试运行模式、上次运行失败的scout。
bash
undefinedcall --json signals-scout-config-list {} -> cfg.json
call --json signals-scout-config-list {} -> cfg.json
(optional) call --json signals-scout-runs-list { "limit": 30 } -> runs.json (small limit!)
(可选)call --json signals-scout-runs-list { "limit": 30 } -> runs.json (设置较小的limit值!)
python scripts/fleet_survey.py --config cfg.json --runs runs.json --now <current-ISO-time>
Pass `--now` (the current time, ISO-8601) to get relative "ago" columns; the emit/quiet column is
a **heuristic** on each run's summary prose — confirm against the summary before trusting it.python scripts/fleet_survey.py --config cfg.json --runs runs.json --now <当前ISO时间>
传入`--now`(当前时间,ISO-8601格式)可获取相对时间列;发送/无结果列是基于每条运行记录的`summary`文本的**启发式判断**——在信任该结果前,请与`summary`交叉验证。scripts/assess_health.py
— health over a window of runs
scripts/assess_health.pyscripts/assess_health.py
——一段时间内的健康状况评估
scripts/assess_health.pyImplements the "assess health and performance" workflow above: a per-scout table (runs, success
%, emit %, cadence gap vs interval, adherence, median duration, memory growth) plus a "worth a
look" section flagging all-failed scouts, timeout-shaped failures, cadence stalls, staleness, and
empty scratchpads.
bash
undefined实现上述“评估健康状况与性能”工作流:每个scout的表格(运行次数、成功率、发送率、运行频率与间隔的差距、一致性、中位时长、内存增长),并附带“值得关注”部分,标记全失败scout、超时类故障、运行频率停滞、过期、scratchpad为空的scout。
bash
undefinedcall --json signals-scout-runs-list { "limit": 100, "date_from": "<ISO>" } -> runs.json
call --json signals-scout-runs-list { "limit": 100, "date_from": "<ISO>" } -> runs.json
(optional) call --json signals-scout-config-list {} -> cfg.json
(可选)call --json signals-scout-config-list {} -> cfg.json
(optional) call --json signals-scout-scratchpad-search {} -> mem.json
(可选)call --json signals-scout-scratchpad-search {} -> mem.json
python scripts/assess_health.py --runs runs.json --config cfg.json
--scratchpad mem.json --now <current-ISO-time> [--skill signals-scout-general]
--scratchpad mem.json --now <current-ISO-time> [--skill signals-scout-general]
`--config` is what lets it score cadence adherence (the expected interval) and staleness (the
authoritative `last_run_at`, which the windowed runs can miss when the 100-row cap truncates the
newest runs). Without `--scratchpad` the memory column shows `n/a` and no memory flags fire. The
emit % is the same summary-prose heuristic — cross-check signal-to-noise against
`inbox-reports-list`.python scripts/assess_health.py --runs runs.json --config cfg.json
--scratchpad mem.json --now <当前ISO时间> [--skill signals-scout-general]
--scratchpad mem.json --now <当前ISO时间> [--skill signals-scout-general]
`--config`用于评估运行频率一致性(预期间隔)和过期状态(权威的`last_run_at`,当100条记录的上限截断最新运行记录时,时间范围内的运行记录可能无法获取该信息)。如果没有`--scratchpad`,内存列会显示`n/a`,且不会触发内存相关的标记。发送率是基于`summary`文本的启发式判断——请与`inbox-reports-list`交叉验证信噪比。scripts/emitted_signals.py
— every finding the fleet actually emitted
scripts/emitted_signals.pyscripts/emitted_signals.py
——舰队实际发送的所有finding
scripts/emitted_signals.pyImplements the "list what scouts have actually emitted" workflow: the authoritative per-finding
table (when, scout, severity, weight, confidence, , one-line hypothesis) plus a
per-scout rollup (emit count, severity mix, weight range, latest emit). Unlike 's
emit % — a prose heuristic — this reads the emitted signals directly, so it's exact.
finding_idassess_healthIts input is not a tool; it's an result over
(the general, any-team path). The full query lives in the script's header —
copy it verbatim. returns a pipe-delimited text table (even under it's
that text wrapped in a JSON string), so the script parses that text; the query deliberately selects
only pipe-safe scalar columns (the multi-line is excluded, is sanitized).
signals-scout-*execute-sqldocument_embeddingsexecute-sqlcall --jsondescriptionhypothesisbash
undefined实现上述“列出scout实际发送的内容”工作流:权威的单条finding表格(发送时间、scout名称、严重程度、权重、置信度、、单行假设),以及每个scout的汇总统计(发送数量、严重程度分布、权重范围、最新发送时间)。与中的发送率(基于文本的启发式判断)不同,该脚本直接读取发送信号,因此结果是精确的。
finding_idassess_health其输入并非工具,而是基于的结果(通用的跨团队方式)。完整查询语句位于脚本头部——请直接复制使用。返回竖线分隔的文本表格(即使使用,也是文本包裹在JSON字符串中),因此脚本会解析该文本;查询语句特意仅选择竖线安全的标量列(排除多行,会被清理)。
signals-scout-*document_embeddingsexecute-sqlexecute-sqlcall --jsondescriptionhypothesisbash
undefinedcall --json execute-sql { "truncate": false, "query": "<emitted-signals query from the header>" } -> emitted.txt
call --json execute-sql { "truncate": false, "query": "<脚本头部的发送信号查询语句>" } -> emitted.txt
python scripts/emitted_signals.py --signals emitted.txt --now <current-ISO-time>
[--skill mcp-feedback,general] [--severity P0,P1,P2] [--since <ISO>] [--sort weight] [--wide]
[--skill mcp-feedback,general] [--severity P0,P1,P2] [--since <ISO>] [--sort weight] [--wide]
`--skill` takes a comma-separated set (the `signals-scout-` prefix is optional). `--wide` adds the
`scout_run_id` so you can chain straight into `render_run_report.py` for the run that emitted a
finding. Remember the coverage caveat: this lists signals that **persisted** — a finding a run
summary claims but that's absent here was gated (dry-run / AI processing not approved / source
disabled) or failed.python scripts/emitted_signals.py --signals emitted.txt --now <当前ISO时间>
[--skill mcp-feedback,general] [--severity P0,P1,P2] [--since <ISO>] [--sort weight] [--wide]
[--skill mcp-feedback,general] [--severity P0,P1,P2] [--since <ISO>] [--sort weight] [--wide]
`--skill`接收逗号分隔的集合(可选`signals-scout-`前缀)。`--wide`会添加`scout_run_id`,以便直接链接到`render_run_report.py`分析发送该finding的运行记录。请记住覆盖范围的注意事项:该脚本列出的是**已持久化**的信号——运行记录`summary`中声称发送但未出现在此处的finding是被拦截(试运行模式/未批准AI处理/源被禁用)或发送失败。Tips
提示
- Always surface the posture. "Running but in dry-run" is the single most common reason a user thinks a scout is broken when it isn't.
emit - An empty close-out is success. Most runs should find nothing. Don't report a wall of clean, empty runs as a problem.
- Emit-vs-quiet is a first-class run field. Filter runs directly with (or read
runs-list?emitted=trueper run) to find what emitted, without parsing the proseemitted_count. Thesummaryinbox filter lists the reports the fleet surfaced; an empty result there means it hasn't emitted yet (scouts hold a high bar), not that the filter is broken.source_product: "signals_scout" - A ~30-min run that is usually a timeout, not a broken scout. Completed runs finish in a couple of minutes. Most often the scout over-investigated and ran the full budget (the fleet self-corrects by writing "tight-run recipe" scratchpad entries) — but some are false timeouts where the scout actually finished in a few minutes and the run then hung on a dropped close-out. The session log (above) tells them apart: real over-investigation shows tool calls right up to the wall; a false timeout goes silent long before it. Don't assume over-investigation from duration alone.
failed - Lead with the run , then offer
summaryfor the full transcript — don't dump raw run rows at the user.task_url - means a scout has never fired — check it's enabled and the project is enrolled before digging further.
last_run_at: null - To explain a quiet scout, read the project profile. shows whether the surface it watches is even in use — a logs scout on a project with no logs has nothing to do.
signals-scout-project-profile-get - This skill is read-only. To change a scout's schedule, posture, or body, hand off to
the skill — it covers
authoring-signals-scoutsand the skills-store edit path.signals-scout-config-update
- 务必说明状态。“正在运行但处于试运行模式”是用户认为scout故障但实际正常的最常见原因。
emit - 无结果结束是成功状态。大多数运行应无结果。不要将连续的无结果运行报告为问题。
- 发送/无结果是运行记录的一级字段。直接使用筛选运行记录(或读取每条记录的
runs-list?emitted=true)查找发送过内容的记录,无需解析emitted_count文本。summary收件箱筛选器列出舰队呈现的报告;空结果表示舰队尚未发送内容(scout阈值很高),而非筛选器故障。source_product: "signals_scout" - 运行时长约30分钟且的记录通常是超时,而非scout故障。成功完成的运行通常在几分钟内结束。大多数情况下,scout过度调查并耗尽了预算(舰队会通过写入“精简运行规则”的scratchpad条目进行自我修正)——但有些是假超时,scout实际在几分钟内完成,但运行记录因结束信号丢失而挂起。会话日志(上文)可区分两者:真实的过度调查会显示工具调用持续到时间上限;假超时会提前长时间静默。不要仅通过时长就假设是过度调查。
failed - 优先展示运行记录的,然后提供
summary查看完整对话记录——不要向用户直接输出原始运行记录。task_url - ****表示scout从未运行——在深入排查前,请检查它是否已启用以及项目是否已加入舰队。
last_run_at: null - 要解释安静的scout,请查看项目配置文件。会显示它监控的领域是否被使用——例如,没有日志的项目上的日志scout没有可处理的内容。
signals-scout-project-profile-get - 本技能仅用于只读操作。若需更改scout的调度计划、状态或技能内容,请切换至技能——它涵盖
authoring-signals-scouts和技能商店编辑流程。signals-scout-config-update