exploring-signals-scouts

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Exploring 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 (
signals-scout-general
) 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
signals-scout-*
skill a team authored (e.g.
-brand-mentions
,
-mcp-feedback
) shows up here too, so don't assume a fixed roster:
signals-scout-config-list
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
signals-scout-config-create
— so a brand-new scout may briefly be missing from the list.)
This 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
authoring-signals-scouts
skill (which teaches writing and tuning) and to the
inbox-exploration
skill (which covers the inbox reports scouts feed into).
There are five things you can observe about the fleet, each with its own tool:
What you want to knowToolWhat it tells you
Which scouts run, how often, in what posture
signals-scout-config-list
One row per scout: schedule,
enabled
,
emit
,
last_run_at
,
description
What the scouts actually did, run by run
signals-scout-runs-list
/
-retrieve
Per-run status, timing, end-of-run summary,
emitted_count
, deep-link
What the fleet has learned across runs
signals-scout-scratchpad-search
Durable per-team memory (baselines, noise, allowlists)
What the scouts actually emitted
execute-sql
over
document_embeddings
The authoritative per-finding record (weight, severity, confidence) — see below
What the scouts surfaced to the user
inbox-reports-list
Findings that cleared the bar and became inbox reports
The orienting sixth is
signals-scout-project-profile-get
— 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.
scout是一种定时运行的Agent,会按照自身间隔周期启动,查看单个PostHog项目,判断哪些内容真正值得呈现,并将其作为finding发送至Signals收件箱,或者无结果结束运行(这是真实且有效的结果)。PostHog提供一系列标准scout舰队——包括跨产品通用型scout(
signals-scout-general
)以及各领域专用型scout(覆盖错误追踪、日志、AI可观测性、实验、功能标志、会话重放、Web分析、调研等)。除标准舰队外,项目还可能拥有自定义scout——团队编写的任何
signals-scout-*
技能(例如
-brand-mentions
-mcp-feedback
)都会在此显示,因此不要假设scout列表是固定的:
signals-scout-config-list
是项目scout的权威清单。(注意:刚编写完成的scout在协调器下次自动注册前,或通过写入端工具
signals-scout-config-create
手动注册前,不会有配置条目——因此全新scout可能会短暂不在清单中。)
本技能可帮助你理解并探索项目中scout的运行情况与性能表现——完全通过只读MCP工具实现。它是
authoring-signals-scouts
技能(用于编写和调整scout)和
inbox-exploration
技能(用于探索scout推送的收件箱报告)的可观测性配套工具。
你可以通过五种工具观测scout舰队的不同维度:
你想了解的内容工具名称工具说明
哪些scout在运行、运行频率、运行状态
signals-scout-config-list
每个scout对应一行:调度计划、
enabled
状态、
emit
状态、
last_run_at
、描述信息
scout每次运行的实际操作内容
signals-scout-runs-list
/
-retrieve
单条运行记录的状态、时间、运行结束总结、
emitted_count
、深度链接
舰队在多次运行中积累的知识
signals-scout-scratchpad-search
团队级持久化内存(基准线、噪音、白名单)
scout实际发送的内容基于
document_embeddings
execute-sql
权威的单条finding记录(权重、严重程度、置信度)——详见下文
scout向用户呈现的内容
inbox-reports-list
达标并成为收件箱报告的findings
第六个定位工具是
signals-scout-project-profile-get
——它是每个scout启动时都会加载的“项目真实状态”确定性快照。当scout无结果时,通常可以通过它找到原因。

Output handling: expect to offload to a file

输出处理:准备将结果导出至文件

Two of these tools —
signals-scout-runs-list
and especially
tasks-runs-session-logs-retrieve
— 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:
  • Keep
    limit
    small
    on
    signals-scout-runs-list
    (~10–15). Each row carries a long prose
    summary
    , and runs come back newest-first across the whole fleet, so even a modest page is large.
  • Session logs are large by nature. A single run's log is hundreds of KB to a few MB. Fetch it with
    call --json
    (so the saved file is real JSON, not the pretty text format —
    jq
    -able) and read the saved file with
    jq
    / a script rather than inline.
  • Don't hand-parse the session log. The bundled
    scripts/
    do the reconstruction for you — see below.
其中两个工具——
signals-scout-runs-list
,尤其是
tasks-runs-session-logs-retrieve
——返回的负载通常会超出MCP客户端的令牌限制,从而自动导出至文件。这是正常流程,并非错误。请提前做好准备,避免调用失败后才发现问题:
  • signals-scout-runs-list
    中设置较小的
    limit
    (约10–15)。每行都包含较长的文本
    summary
    ,且运行记录按时间倒序返回(覆盖整个舰队),因此即使是少量结果也会占用较大空间。
  • 会话日志本身体积较大。单次运行的日志大小从数百KB到几MB不等。请使用**
    call --json
    **获取日志(这样保存的文件是标准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
signals-scout
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.
json
signals-scout-config-list
Read the result against three cases:
The config list is unpaginated — it comes back as
{ results: [...] }
(a bare array), with no
count
field. Read the result against three cases:
  • Empty (
    results: []
    )
    — 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.
  • Configs exist but all
    enabled: false
    — the fleet is registered but paused. Nothing is running. Tell the user which scouts exist and that they're all off.
  • At least one
    enabled: true
    — the fleet is registered and that scout is allowed to run. For each enabled scout note its
    run_interval_minutes
    (cadence),
    emit
    (false = dry-run, runs but writes nothing to the inbox), and
    last_run_at
    . One caveat before reporting "it's live": runs are gated by the
    signals-scout
    feature flag, not by
    enabled
    . A project that was enrolled and later drained from the flag keeps its
    enabled: true
    rows, but the coordinator no longer plans runs for it — so a stale or
    null
    last_run_at
    on an enabled scout usually means the project is no longer enrolled, not that the scout is idle.
    last_run_at
    is 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, yet
    last_run_at
    keeps marching forward each tick. So a recent
    last_run_at
    means "dispatched this tick," not "a run is genuinely happening." The authoritative liveness signal is the newest actual run row in
    signals-scout-runs-list
    , not the config stamp. Cross-check them: if
    last_run_at
    is fresh (minutes ago) but no run row has appeared for that scout in well over its
    run_interval_minutes
    , 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" off
    last_run_at
    alone.
A scout that is
enabled: true
but
emit: false
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
emit
posture when reporting on a scout.
See
references/scout-data-model.md
for every field on a config, run, and scratchpad entry, the run status values, and how the pieces link together.
不要默认项目已部署scout。只有通过
signals-scout
功能标志加入的团队才会运行scout舰队,项目可能没有配置、所有scout都处于禁用状态,或者scout处于试运行模式。当用户首次询问scout相关问题时,请先运行以下命令:
json
signals-scout-config-list
根据以下三种情况解读结果:
配置列表无需分页——返回格式为
{ results: [...] }
(纯数组),无
count
字段。请对照以下三种情况解读:
  • 空数组(
    results: []
    ——未注册任何scout。项目未加入scout舰队(或尚未完成首次调度)。请直接告知用户,无需继续查找运行记录。引导用户查看Signals scout设置或PostHog代码入门文档,而非假设存在运行活动。
  • 存在配置但所有scout的
    enabled: false
    ——舰队已注册但处于暂停状态。没有scout在运行。告知用户存在哪些scout,且所有scout均已关闭。
  • 至少有一个scout的
    enabled: true
    ——舰队已注册且该scout允许运行。对于每个启用的scout,请注意其
    run_interval_minutes
    (运行频率)、
    emit
    状态(false = 试运行模式,正常运行但不会向收件箱写入内容)和
    last_run_at
    。在报告“scout已启动”前需注意一点:运行受
    signals-scout
    功能标志控制,而非
    enabled
    状态。如果项目曾加入舰队但后来被移除功能标志,scout的
    enabled: true
    状态会保留,但协调器不再为其规划运行——因此启用的scout若
    last_run_at
    过期或为
    null
    ,通常意味着项目已不再属于舰队,而非scout闲置。
    last_run_at
    是调度时间戳,而非运行执行的证明
    。协调器在将子工作流加入队列的瞬间就会更新该时间戳——早于任何工作进程启动运行。子工作流是“即发即弃”模式,因此如果工作进程饱和或宕机,子工作流只会停留在队列中,不会实际运行,但
    last_run_at
    仍会在每次调度时更新。因此近期的
    last_run_at
    仅表示“本次调度已加入队列”,不代表“scout正在实际运行”。权威的活跃状态信号是
    signals-scout-runs-list
    中最新的实际运行记录,而非配置中的时间戳。请交叉验证:如果
    last_run_at
    是近期(几分钟前),但该scout的最新运行记录已远超其
    run_interval_minutes
    ,则舰队处于已调度但未运行状态——工作进程积压/宕机,或运行任务滞留——这是真实的可靠性问题,而非scout正常运行。不要仅通过
    last_run_at
    就报告“scout正在运行”。
enabled: true
emit: false
的scout是导致“我的scout什么都没做”困惑的最常见原因:它确实在每次调度时运行并进行推理,只是不被允许发送findings。在报告scout状态时,务必说明
emit
状态。
关于配置、运行记录和暂存内存条目的所有字段、运行状态值以及各模块的关联方式,请参阅
references/scout-data-model.md

Workflow: survey the fleet

工作流:查看舰队整体情况

"What scouts do I have / what are they doing?" — lead with
config-list
, then enrich with the most recent run per scout so the user sees liveness, not just configuration.
  1. signals-scout-config-list
    — the roster.
  2. For each enabled scout,
    signals-scout-runs-list
    and pick the newest run with a matching
    skill_name
    (runs come back newest-first across the whole fleet, so a single call usually covers everyone). Report
    status
    and how long ago it ran.
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?它们在做什么?”——先使用
config-list
获取清单,再为每个启用的scout补充最新运行记录,让用户了解活跃状态,而非仅查看配置。
  1. signals-scout-config-list
    ——获取scout清单。
  2. 对于每个启用的scout,调用
    signals-scout-runs-list
    并选择匹配
    skill_name
    的最新运行记录(运行记录按时间倒序返回,覆盖整个舰队,因此单次调用通常可获取所有scout的最新记录)。报告运行
    status
    和运行时间。
将结果整理为用户易于扫描的表格——包含scout名称、运行频率、状态、上次运行时间、上次运行结果——并标注异常情况(从未运行、上次运行出错、长期处于试运行模式等)。

Workflow: understand one scout end to end

工作流:深入了解单个scout的完整流程

"How does my error-tracking scout work / how is it doing?"
  1. Read its config — find the row in
    config-list
    for
    signals-scout-error-tracking
    : schedule, posture, last run.
  2. Read its body
    posthog:llma-skill-get {"skill_name": "signals-scout-error-tracking"}
    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.
  3. Read its recent runs
    runs-list
    with
    text
    set to the skill's domain, or just scan the newest runs and filter to its
    skill_name
    . The end-of-run
    summary
    on each run is the scout's own account of what it looked at and decided.
  4. Read what it remembered
    scratchpad-search
    (see below). The memory entries a scout wrote reveal the baselines and noise it has internalized about this project.
“我的错误追踪scout是如何工作的?性能如何?”
  1. 查看配置——在
    config-list
    中找到
    signals-scout-error-tracking
    的条目:调度计划、状态、上次运行时间。
  2. 查看技能内容——调用
    posthog:llma-skill-get {"skill_name": "signals-scout-error-tracking"}
    返回团队实际使用的指令集(可能是标准默认内容,也可能是经过手动编辑的自定义内容)。这是scout每次运行时遵循的规则——包括信噪比判别逻辑、探索模式和排除条件。要理解scout的行为原因,请阅读其技能内容。
  3. 查看近期运行记录——调用
    runs-list
    并设置
    text
    为该技能的领域关键词,或直接扫描最新运行记录并筛选其
    skill_name
    。每条运行记录的结束
    summary
    是scout对自身操作和决策的描述。
  4. 查看记忆内容——调用
    scratchpad-search
    (详见下文)。scout写入的内存条目揭示了它对该项目的基准线和噪音的认知。

Workflow: read recent runs

工作流:读取近期运行记录

signals-scout-runs-list
returns the most recent runs across the whole fleet, newest first (capped at 100). Use it to answer "what happened lately?"
  • Scope to a window with
    date_from
    /
    date_to
    (ISO-8601; inclusive lower, exclusive upper on
    created_at
    ). Walk backwards by passing an earlier
    date_to
    .
  • Search summaries with
    text
    — a case-insensitive substring match on each run's end-of-run
    summary
    . This is how the headless scout dedupes, and it's how you find "did any run already look at the checkout error spike?"
  • Filter by emit outcome with
    emitted
    emitted=true
    returns only runs that surfaced at least one finding,
    emitted=false
    only the quiet runs. This is the direct way to answer "which runs actually emitted something?" without parsing prose.
Each summary row carries
run_id
,
skill_name
,
skill_version
,
status
,
started_at
,
completed_at
,
emitted_count
(how many findings the run emitted),
emitted_finding_ids
(their ids),
task_url
(a deep-link into the Tasks UI for the full transcript), and the
summary
prose. Lead with the
summary
when narrating to the user — it's the scout's own plain-language close-out — and always offer the
task_url
for the full reasoning.
signals-scout-runs-list
返回整个舰队的最新运行记录,按时间倒序排列(最多100条)。可用于回答“最近发生了什么?”
  • 按时间范围筛选:使用
    date_from
    /
    date_to
    (ISO-8601格式;
    created_at
    包含下限,排除上限)。通过设置更早的
    date_to
    可回溯历史记录。
  • 搜索总结内容:使用
    text
    ——对每条运行记录的结束
    summary
    进行不区分大小写的子串匹配。这是无界面scout进行去重的方式,也可用于查找“是否有运行记录已检查过结账错误激增问题?”
  • 按发送结果筛选:使用
    emitted
    ——
    emitted=true
    仅返回至少发送一个finding的运行记录,
    emitted=false
    仅返回无结果的运行记录。这是直接回答“哪些运行记录实际发送了内容?”的可靠方式,无需解析文本。
每条总结记录包含
run_id
skill_name
skill_version
status
started_at
completed_at
emitted_count
(运行发送的finding数量)、
emitted_finding_ids
(finding的ID)、
task_url
(指向Tasks UI的深度链接,可查看完整记录)和
summary
文本。向用户汇报时,优先展示
summary
——这是scout用自然语言撰写的运行总结——并始终提供
task_url
供用户查看完整推理过程。

Workflow: 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:
runs-list
returns each run's id as
run_id
, but
runs-retrieve
takes it as
id
. Pass the
run_id
value through as
id
.
Returns the full run:
status
,
started_at
/
completed_at
(compute duration from these),
skill_name
/
skill_version
(what ran, at what body version), the end-of-run
summary
,
emitted_count
/
emitted_finding_ids
, and
task_url
. The transcript — the actual tool calls and reasoning — lives in the Tasks UI behind
task_url
, not in this payload; hand the user that link when they want to see every step. A failed run returns an empty
summary
and no error field — the payload looks the same as the list row, so to learn why it failed you need the transcript.
You don't have to open the UI for that:
tasks-runs-session-logs-retrieve
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
task_run_id
as
id
and its
task_id
(both are on the run row).
The raw stream is large (hundreds of KB to a few MB) and will overflow inline, so fetch it with
call --json
and let it spill to a file
, then run it through
scripts/render_run_report.py
rather than parsing it by hand.
⚠️ Do not reach for
exclude_types: "tool_call_update,…"
to slim it down.
It is tempting — the stream is dominated by incremental
tool_call_update
chunks — but each tool's actual input lives only in those chunks: the base
tool_call
event carries an empty
rawInput
, and the streamed updates build the input (and the final
rawOutput
) 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
toolCallId
, keeps the richest
rawInput
, and attaches the completion's
rawOutput
/
status
).
Whether a run emitted is a first-class field:
emitted_count
.
emitted_count > 0
means the run surfaced that many findings;
emitted_count: 0
means it closed out empty. Don't parse the prose
summary
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
emitted_count
is the authoritative tally.
emitted_finding_ids
lists the
finding_id
s behind that count, in emit order; each maps to a
Signal
with
source_id = run:<run_id>:finding:<finding_id>
, giving a reliable run → finding link. See
references/scout-data-model.md
for the run-to-finding link and how an emitted finding rides through grouping into the
source_product: "signals_scout"
inbox filter.
A run with
status
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.
当用户想要了解某次运行的完整详情(或提供了运行ID/Tasks URL):
json
signals-scout-runs-retrieve
{ "id": "<uuid>" }
注意字段名称变化:
runs-list
返回的运行ID字段为
run_id
,但
runs-retrieve
接收的参数名为
id
。请将
run_id
的值作为
id
传入。
返回完整运行记录:
status
started_at
/
completed_at
(可通过这两个时间计算运行时长)、
skill_name
/
skill_version
(运行的技能名称和版本)、结束
summary
emitted_count
/
emitted_finding_ids
task_url
。完整的对话记录——包括实际工具调用和推理过程——位于
task_url
指向的Tasks UI中,而非返回的负载中;当用户想要查看每一步操作时,请提供该链接。失败的运行记录会返回空的
summary
,且无错误字段——负载格式与列表条目相同,因此要了解失败原因,需要查看对话记录。
无需打开UI即可查看对话记录:
tasks-runs-session-logs-retrieve
会以数据形式返回运行的会话日志(包括所有工具调用、消息和推理步骤)
——在诊断失败或无需离开对话即可追踪运行详情时非常有用。传入运行记录的
task_run_id
作为
id
,以及
task_id
(两者均在运行记录中)。
原始日志流体积较大(数百KB到几MB),无法在终端内完整显示,因此请使用
call --json
获取日志并让其自动导出至文件
,然后通过
scripts/render_run_report.py
处理,而非手动解析。
⚠️ 不要使用
exclude_types: "tool_call_update,…"
来缩小日志体积
。虽然日志流主要由增量
tool_call_update
块组成,但每个工具的实际输入仅存在于这些块中:基础
tool_call
事件的
rawInput
为空,流式更新会逐步构建输入(以及最终的
rawOutput
)。排除这些块后,你只能看到工具名称,无法了解scout实际查询的内容。请获取完整日志,然后让脚本重新组装每个调用(按
toolCallId
分组,保留最完整的
rawInput
,并附上完成后的
rawOutput
/
status
)。
运行是否发送内容是一级字段:
emitted_count
emitted_count > 0
表示运行发送了对应数量的finding;
emitted_count: 0
表示运行无结果结束。无需再通过解析
summary
文本判断——类似“已发送P1…未重复发送”的描述指的是之前的运行,因此通过
summary
子串匹配“emitted”不可靠,而
emitted_count
是权威统计。
emitted_finding_ids
按发送顺序列出对应的
finding_id
;每个
finding_id
对应一个
Signal
,其
source_id = run:<run_id>:finding:<finding_id>
,提供了可靠的运行→finding关联。关于运行与finding的关联方式,以及发送的finding如何分组进入
source_product: "signals_scout"
收件箱筛选器,请参阅
references/scout-data-model.md
status
为complete且总结为空(“处于基准状态,无内容可发送”)的运行是健康结果,而非失败——大多数运行应无结果结束。将连续的无结果运行视为舰队正常工作,而非故障。

Workflow: 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);
text
matches
content
and
key
case-insensitively. Omit
text
to browse everything. Each entry's
key
carries a category prefix that tells you what kind of learning it is:
PrefixMeaning
pattern:
A baseline — how this team's data normally shapes
watch:
A live issue being tracked but still below the emit bar
noise:
A pattern the fleet has decided to ignore (dev-only, single-user…)
addressed:
Something the team fixed or moved on from
dedupe:
A gate on re-emitting a specific issue / fingerprint / finding
allowlist:
Vetted entities never to re-surface
not-in-use:
A product/surface this team doesn't use (close-out memo)
mcp-gap:
A tooling gap a scout noticed worth raising later
This is the common vocabulary, not a closed set — scouts coin their own prefixes and
<domain>
labels as needed (the live fleet uses
watch:
heavily, for example), so treat an unfamiliar prefix as just another category. Entries cross-reference each other with
[[key]]
wikilinks. Keys follow
<prefix>:<domain>:<entity>
(e.g.
dedupe:error_tracking:019e8375-…
).
When a user asks "why isn't my scout flagging X anymore?", search the scratchpad for
noise:
,
addressed:
,
dedupe:
, and
allowlist:
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
authoring-signals-scouts
skill (
references/dedupe-and-memory.md
).
scratchpad是舰队的团队级持久化内存——scout写入的文本条目,用于让后续运行更智能、更安静。查看scratchpad可了解舰队对该项目的认知。
json
signals-scout-scratchpad-search
{ "text": "error_tracking" }
返回结果按时间倒序排列(最多100条);
text
会对
content
key
进行不区分大小写的匹配。省略
text
可浏览所有条目。每条条目的
key
包含类别前缀,用于说明知识类型:
前缀含义
pattern:
基准线——团队数据的正常模式
watch:
正在跟踪但未达发送阈值的实时问题
noise:
舰队决定忽略的模式(仅开发环境、单用户等)
addressed:
团队已修复或不再关注的内容
dedupe:
阻止重复发送特定问题/指纹/finding的规则
allowlist:
无需再次呈现的已验证实体
not-in-use:
团队未使用的产品/领域(无结果备忘录)
mcp-gap:
scout发现的工具缺口,值得后续关注
这是通用词汇,并非封闭集合——scout会根据需要创建自定义前缀和
<domain>
标签(例如当前舰队大量使用
watch:
前缀),因此遇到不熟悉的前缀时,将其视为新类别即可。条目之间通过
[[key]]
维基链接相互引用。
key
遵循
<prefix>:<domain>:<entity>
格式(例如
dedupe:error_tracking:019e8375-…
)。
当用户询问“为什么我的scout不再标记X了?”时,请搜索scratchpad中的
noise:
addressed:
dedupe:
allowlist:
条目——舰队可能已主动学习并抑制该内容。标准前缀词汇和舰队使用的四态去重分类器在
authoring-signals-scouts
技能的
references/dedupe-and-memory.md
中有详细说明。

Workflow: 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
summary
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
document_embeddings
table — queryable for any team via
execute-sql
(the general path). When a scout emits,
emit_signal
writes a signal with
source_product="signals_scout"
; the scout's attribution (
skill_name
,
finding_id
,
severity
,
confidence
) lands in
metadata.extra
, with
weight
and
source_id
at the top level.
Fetch with
execute-sql
and format with
scripts/emitted_signals.py
— the exact query lives in the script's header. One row per finding, filterable by any set of scouts:
bash
undefined
“舰队最近发送了什么?展示我的scout产生的所有finding。”运行记录中没有发送标志和finding计数,
summary
文本是启发式描述,收件箱筛选器(下文)会因为分组将scout的finding合并到混合源集群中,导致信息丢失。权威的单条finding记录是
document_embeddings
表中的发送信号——可通过
execute-sql
为任何团队查询(通用方式)。当scout发送内容时,
emit_signal
会写入一个
source_product="signals_scout"
的信号;scout的属性(
skill_name
finding_id
severity
confidence
)存储在
metadata.extra
中,
weight
source_id
位于顶层。
使用
execute-sql
获取数据,并通过
scripts/emitted_signals.py
格式化——完整查询语句位于脚本头部。每条finding对应一行,可按任意scout集合筛选:
bash
undefined

call --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
source_product="signals_scout"
, that tag rides through grouping into the report's signal metadata, and the inbox filter keeps any report whose contributing signals include
signals_scout
— so the result is the set of reports the fleet has surfaced.
An 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:
signals-scout-runs-list?emitted=true
lists every emitting run, and each run's
emitted_count
/
emitted_finding_ids
tell you how many and which findings it produced (each
finding_id
maps to a
Signal
with
source_id = run:<run_id>:finding:<finding_id>
). To browse the inbox more broadly, use the
inbox-exploration
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
authoring-signals-scouts
skill (
references/emit-contract.md
).
scout的finding会以收件箱报告的形式呈现给用户。将收件箱筛选为scout源:
json
inbox-reports-list
{ "source_product": "signals_scout", "limit": 20 }
这是查找scout生成的报告的直接方式。每个finding发送时都会标记
source_product="signals_scout"
,该标签会随分组进入报告的信号元数据,收件箱筛选器会保留所有包含
signals_scout
信号的报告——因此结果就是舰队呈现的报告集合。
空结果表示舰队尚未发送内容(或尚未完成发送),不代表筛选器故障。scout的发送阈值很高——大多数运行无结果结束——因此在安静或刚加入的项目中,没有scout生成的报告是正常预期状态。要查看单次运行的发送情况,请从运行记录入手:
signals-scout-runs-list?emitted=true
列出所有发送过内容的运行记录,每条记录的
emitted_count
/
emitted_finding_ids
会告诉你发送的数量和对应的finding(每个
finding_id
对应一个
Signal
,其
source_id = run:<run_id>:finding:<finding_id>
)。要更广泛地浏览收件箱,请使用
inbox-exploration
技能(状态、建议审阅人、深入分析报告的底层信号)。每个finding背后的发送规则——权重、置信度、严重程度、描述文本——在
authoring-signals-scouts
技能的
references/emit-contract.md
中有详细说明。

Workflow: 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 (
runs-list
with a
date_from
), then reason across the dimensions below. The full playbook, including how to read each signal and the common failure modes, is in
references/assessing-performance.md
.
  • Cadence adherence — are runs landing roughly every
    run_interval_minutes
    ? 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
    last_run_at
    : if the config's
    last_run_at
    is also stale, the coordinator stopped planning it; if
    last_run_at
    is fresh but the newest run row is hours old, it's the dispatch-vs-execution divergence above (workers backed up / down, or runs stranded), which
    runs-list
    alone hides.
  • Success rate — how many runs reach a clean
    status
    vs. error out? A run of errors is a broken scout, not a quiet one.
  • Emit rate — what fraction of runs emitted vs. closed out empty. Read it straight off
    emitted_count
    per run (or split the window with
    runs-list?emitted=true
    /
    ?emitted=false
    ). 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.
  • Signal-to-noise — of what it emitted, how much became actionable inbox reports vs. got suppressed? Use each emitting run's
    emitted_finding_ids
    to tie runs to their
    Signal
    rows, and cross-check against
    inbox-reports-list
    report states.
  • Memory growth — a healthy scout accumulates
    pattern:
    /
    noise:
    /
    dedupe:
    entries over time. A scout with an empty scratchpad after many runs isn't learning.
“我的scout是否真的在工作?是否物有所值?”没有单一指标——需要在一段时间的运行记录中评估scout。获取运行记录(使用
date_from
调用
runs-list
),然后从以下维度分析。完整指南包括如何解读每个信号和常见故障模式,请参阅
references/assessing-performance.md
  • 运行频率一致性——运行是否大致按照
    run_interval_minutes
    的间隔进行?较大的间隔意味着协调器跳过了该scout(已禁用、被移除功能标志、或在繁忙调度时达到上限)——或者已调度但运行未实际执行。通过
    last_run_at
    区分两种情况:如果配置中的
    last_run_at
    也过期,说明协调器已停止规划运行;如果
    last_run_at
    是近期,但最新运行记录已过时数小时,则属于上述调度与执行的差异(工作进程积压/宕机,或运行任务滞留),而
    runs-list
    本身无法揭示这一点。
  • 成功率——有多少运行记录成功完成,多少运行出错?连续出错的scout是故障状态,而非安静状态。
  • 发送率——发送内容的运行记录占比。直接读取每条运行记录的
    emitted_count
    (或通过
    runs-list?emitted=true
    /
    ?emitted=false
    拆分时间范围)。在活跃领域中长时间接近零的发送率可能意味着判别逻辑过于严格(或该领域确实很安静);接近100%通常意味着噪音过多。健康的scout发送频率通常较低。
  • 信噪比——发送的内容中,有多少成为可操作的收件箱报告,多少被抑制?使用每条发送运行记录的
    emitted_finding_ids
    将运行记录与对应的
    Signal
    条目关联,并与
    inbox-reports-list
    的报告状态交叉验证。
  • 内存增长——健康的scout会随着时间积累
    pattern:
    /
    noise:
    /
    dedupe:
    条目。经过多次运行后scratchpad仍为空的scout没有学习能力。

Helper scripts

辅助脚本

The skill bundles four pure formatters under
scripts/
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:
  1. Fetch each payload with the MCP using
    call --json
    (raw JSON, not the pretty text format) and save it to a file. For the big ones (
    runs-list
    ,
    tasks-runs-session-logs-retrieve
    ) this is mandatory anyway — they overflow inline and spill to a file you can point the script at.
  2. Run the script over those files.
All four are stdlib-only Python 3.11+ and print plain text to stdout (or
--out
) — designed to read well in a terminal, so save them as
.txt
.
本技能在
scripts/
下提供了四个纯格式化工具,用于处理最常见的需求。它们不进行网络I/O——是“Agent获取数据,脚本格式化”流程的后半部分。使用模式始终相同:
  1. 使用MCP的**
    call --json
    **获取每个负载(原始JSON格式,而非格式化文本)并保存至文件。对于体积较大的负载(
    runs-list
    tasks-runs-session-logs-retrieve
    ),这是必须的——它们会超出终端显示限制并自动导出至文件,你可以将文件路径提供给脚本。
  2. 使用脚本处理这些文件。
所有脚本均为仅依赖标准库的Python 3.11+脚本,会向stdout(或通过
--out
指定文件)输出纯文本——专为终端阅读设计,因此建议保存为
.txt
文件。

scripts/render_run_report.py
— drill into one run

scripts/render_run_report.py
——深入分析单次运行记录

Produces 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
undefined

fetch (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

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

模式(`--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.py
——查看整个舰队情况

One 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
undefined

call --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.py
——一段时间内的健康状况评估

Implements 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
undefined

call --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]

`--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]

`--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.py
——舰队实际发送的所有finding

Implements the "list what scouts have actually emitted" workflow: the authoritative per-finding table (when, scout, severity, weight, confidence,
finding_id
, one-line hypothesis) plus a per-scout rollup (emit count, severity mix, weight range, latest emit). Unlike
assess_health
's emit % — a prose heuristic — this reads the emitted signals directly, so it's exact.
Its input is not a
signals-scout-*
tool; it's an
execute-sql
result over
document_embeddings
(the general, any-team path). The full query lives in the script's header — copy it verbatim.
execute-sql
returns a pipe-delimited text table (even under
call --json
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
description
is excluded,
hypothesis
is sanitized).
bash
undefined
实现上述“列出scout实际发送的内容”工作流:权威的单条finding表格(发送时间、scout名称、严重程度、权重、置信度、
finding_id
、单行假设),以及每个scout的汇总统计(发送数量、严重程度分布、权重范围、最新发送时间)。与
assess_health
中的发送(基于文本的启发式判断)不同,该脚本直接读取发送信号,因此结果是精确的。
其输入并非
signals-scout-*
工具,而是基于
document_embeddings
execute-sql
结果(通用的跨团队方式)。完整查询语句位于脚本头部——请直接复制使用。
execute-sql
返回竖线分隔的文本表格(即使使用
call --json
,也是文本包裹在JSON字符串中),因此脚本会解析该文本;查询语句特意仅选择竖线安全的标量列(排除多行
description
hypothesis
会被清理)。
bash
undefined

call --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` 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`接收逗号分隔的集合(可选`signals-scout-`前缀)。`--wide`会添加`scout_run_id`,以便直接链接到`render_run_report.py`分析发送该finding的运行记录。请记住覆盖范围的注意事项:该脚本列出的是**已持久化**的信号——运行记录`summary`中声称发送但未出现在此处的finding是被拦截(试运行模式/未批准AI处理/源被禁用)或发送失败。

Tips

提示

  • Always surface the
    emit
    posture.
    "Running but in dry-run" is the single most common reason a user thinks a scout is broken when it isn't.
  • 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
    runs-list?emitted=true
    (or read
    emitted_count
    per run) to find what emitted, without parsing the prose
    summary
    . The
    source_product: "signals_scout"
    inbox 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.
  • A ~30-min run that
    failed
    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.
  • Lead with the run
    summary
    , then offer
    task_url
    for the full transcript — don't dump raw run rows at the user.
  • last_run_at: null
    means a scout has never fired — check it's enabled and the project is enrolled before digging further.
  • To explain a quiet scout, read the project profile.
    signals-scout-project-profile-get
    shows whether the surface it watches is even in use — a logs scout on a project with no logs has nothing to do.
  • This skill is read-only. To change a scout's schedule, posture, or body, hand off to the
    authoring-signals-scouts
    skill — it covers
    signals-scout-config-update
    and the skills-store edit path.
  • 务必说明
    emit
    状态
    。“正在运行但处于试运行模式”是用户认为scout故障但实际正常的最常见原因。
  • 无结果结束是成功状态。大多数运行应无结果。不要将连续的无结果运行报告为问题。
  • 发送/无结果是运行记录的一级字段。直接使用
    runs-list?emitted=true
    筛选运行记录(或读取每条记录的
    emitted_count
    )查找发送过内容的记录,无需解析
    summary
    文本。
    source_product: "signals_scout"
    收件箱筛选器列出舰队呈现的报告;空结果表示舰队尚未发送内容(scout阈值很高),而非筛选器故障。
  • 运行时长约30分钟且
    failed
    的记录通常是超时,而非scout故障
    。成功完成的运行通常在几分钟内结束。大多数情况下,scout过度调查并耗尽了预算(舰队会通过写入“精简运行规则”的scratchpad条目进行自我修正)——但有些是假超时,scout实际在几分钟内完成,但运行记录因结束信号丢失而挂起。会话日志(上文)可区分两者:真实的过度调查会显示工具调用持续到时间上限;假超时会提前长时间静默。不要仅通过时长就假设是过度调查。
  • 优先展示运行记录的
    summary
    ,然后提供
    task_url
    查看完整对话记录——不要向用户直接输出原始运行记录。
  • **
    last_run_at: null
    **表示scout从未运行——在深入排查前,请检查它是否已启用以及项目是否已加入舰队。
  • 要解释安静的scout,请查看项目配置文件
    signals-scout-project-profile-get
    会显示它监控的领域是否被使用——例如,没有日志的项目上的日志scout没有可处理的内容。
  • 本技能仅用于只读操作。若需更改scout的调度计划、状态或技能内容,请切换至
    authoring-signals-scouts
    技能——它涵盖
    signals-scout-config-update
    和技能商店编辑流程。