Signals

For instructions on how to authenticate to use this endpoint, see API overview.

Endpoints

GET
GET
POST
GET
GET
GET
GET
POST
DELETE
GET
GET
POST
GET
GET
POST
POST
GET
GET
POST

Retrieve signals scout config trial

Read a trial's existing run status and its privately captured reports and memory changes.

Required API key scopes

signal_scout:writellm_skill:write

Path parameters

  • id
    string

Query parameters

  • launch_id
    string

Response


Example request

GET /api/projects/:project_id/signals/scout/configs/:id/trial_result
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/configs/:id/trial_result/

Example response

Status 200
RESPONSE
{
"launch_id": "e84bcd27-699d-48e8-b842-1ce01401cf1f",
"context_id": "f31d7249-b7b1-4729-b3a4-ec0ba07b4686",
"model": "string",
"reasoning_effort": "string",
"skill_body_sha256": "string",
"result_key": "string",
"export_error": "string",
"started_at": "2019-08-24T14:15:22Z",
"completed_at": "2019-08-24T14:15:22Z",
"run_id": "dded282c-8ebd-44cf-8ba5-9a234973d1ec",
"task_id": "736fde4d-9029-4915-8189-01353d6982cb",
"task_run_id": "7f0ef9d7-e7b5-4d52-8247-ce8351652f8b",
"status": "string",
"task_status": "string",
"error": "string",
"summary": "string",
"invalid_reason": "string",
"reports": [
{
"id": "string",
"source_report_id": null,
"document": {
"property1": null,
"property2": null
},
"payload": {
"property1": null,
"property2": null
},
"edits": [
{
"property1": null,
"property2": null
}
],
"operator_metadata": {
"property1": null,
"property2": null
},
"evidence": [
{
"property1": null,
"property2": null
}
],
"artefacts": [
{
"property1": null,
"property2": null
}
],
"content_revision_count": 0,
"corroboration_count": 0
}
],
"memory": {
"property1": {
"key": "string",
"content": "string",
"created_at": "string",
"updated_at": "string",
"expires_at": "string",
"created_by_run_id": "string",
"created_by_skill": "string",
"created_by_run_url": "string"
},
"property2": {
"key": "string",
"content": "string",
"created_at": "string",
"updated_at": "string",
"expires_at": "string",
"created_by_run_id": "string",
"created_by_skill": "string",
"created_by_run_url": "string"
}
},
"cost_usd": 0,
"input_tokens": 0,
"output_tokens": 0
}

Retrieve signals scout config trial

Read comparison readiness and source settings for the internal comparison editor.

Required API key scopes

signal_scout:writellm_skill:write

Path parameters

  • id
    string

Query parameters

  • context_id
    string

Response


Example request

GET /api/projects/:project_id/signals/scout/configs/:id/trial_setup
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/configs/:id/trial_setup/

Example response

Status 200
RESPONSE
{
"config_id": "d1d31429-d888-4f1c-b9c1-4e842f9bce5b",
"skill_name": "string",
"skill_version": 0,
"skill_body": "string",
"ready": true,
"blocked_reason": "string",
"model": "string",
"reasoning_effort": "string",
"models": [
{
"model": "string",
"reasoning_efforts": [
"string"
]
}
]
}

Create signals scout config

Materialize the scout fleet for this project on demand (idempotent): seed the canonical signals-scout-* skills, create a default-schedule config for any scout lacking one, retire the skills whose canonical scout no longer ships, and return all scout configs. Normally the Temporal coordinator does this on its next tick; this action exists so the scout UIs and setup flows (e.g. the wizard's self-driving program) can hand the user a tunable fleet immediately.

Required API key scopes

signal_scout:write

Query parameters

  • surface
    string
    One of: "roster""desktop""wizard"

Example request

POST /api/projects/:project_id/signals/scout/configs/sync
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/configs/sync/

Example response

Status 200 The team's full scout fleet after the sync, ordered by skill name.
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"skill_name": "string",
"description": "string",
"display_name": "string",
"scout_origin": "canonical",
"scout_role": "specialist",
"deprecation": {
"phase": "announced",
"reason": "string",
"superseded_by": "string",
"sunset_at": "2019-08-24T14:15:22Z"
},
"owners": [
{
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
}
],
"enabled": true,
"status": "active",
"pause_reason": "no_output",
"managed_by": "team",
"emit": true,
"run_interval_minutes": 30,
"run_cron_schedule": "string",
"output_destinations": {
"slack": {
"integration_id": 1,
"channel": "string",
"users": [
"string"
],
"thread_reports": true
},
"webhook": {
"hog_function_id": "string"
}
},
"structured_output_schema": {},
"network_access": "trusted",
"model": "string",
"mcp_gateway_server_ids": [
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
],
"repositories": [
"string"
],
"write_scopes": [
"string"
],
"last_run_at": "2019-08-24T14:15:22Z",
"consecutive_failure_count": 0,
"status_changed_at": "2019-08-24T14:15:22Z",
"status_changed_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"auto_pause_exempt": true,
"tags": [
"string"
],
"source_product": "string",
"source_id": "string",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
}

Retrieve signals scout config tool

List every MCP tool a scout could be configured with. Each entry carries the tool's name, label, one-line summary, category, and required scopes, plus holdable: whether a scout run can hold every scope the tool needs, and missing_scopes: what it would have to be granted on top of the baseline preset. The response also returns the scout scope presets and the write scopes a person can grant to one scout, so a caller can show why a tool is out of reach. Tools a successor has replaced are left out. A tool can carry a feature_flag, which resolves per project: evaluate it for the project you are configuring before you offer the tool. Read-only, and the same for every project.

Required API key scopes

signal_scout:read

Response


Example request

GET /api/projects/:project_id/signals/scout/configs/tool_catalogue
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/configs/tool_catalogue/

Example response

Status 200 Every catalogued MCP tool, with the scout scope postures to read it against.
RESPONSE
{
"tools": [
{
"name": "string",
"title": "string",
"summary": "string",
"category": "string",
"feature": "string",
"required_scopes": [
"string"
],
"is_read_only": true,
"requires_ai_consent": true,
"holdable": true,
"missing_scopes": [
"string"
],
"feature_flag": "string",
"feature_flag_behavior": "string",
"feature_flag_variant": "string",
"hidden_when_flag_on": "string",
"feature_entitlement": "string"
}
],
"presets": [
{
"name": "string",
"scopes": [
"string"
]
}
],
"grantable_write_scopes": [
"string"
]
}

List all signals scout members

Return the people who can review work on this project — one row per member with access to it, each with their user_uuid, email, first_name/last_name, resolved GitHub login (null when they have no linked GitHub identity), and the teams they're on. The cold-start reviewer-routing path: when a finding's owner can't be read off a fetched entity's created_by and there's no cached reviewer:<area> memory or inbox precedent, list members, match the owner by email/name, then put their resolved github_login in suggested_reviewers on emit-report / edit-report. Pass team to resolve a team slug to the people on it, maintainers first. Pass search to narrow a large roster; the result is capped at 200. Strictly team-scoped.

Required API key scopes

signal_scout_internal:read

Query parameters

  • search
    string
  • team
    string

Example request

GET /api/projects/:project_id/signals/scout/members
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/members/

Example response

Status 200 The project's members, each with their routing identity.
RESPONSE
{
"user_uuid": "string",
"email": "user@example.com",
"first_name": "string",
"last_name": "string",
"github_login": "string",
"teams": [
{
"provider": "string",
"slug": "string",
"name": "string",
"is_maintainer": true
}
]
}

Retrieve signals scout metadata

Return the project's scout metadata: whether it is enrolled, the current announcement banner (e.g. an alpha run-limit notice, or null when unset), and the enforced run limits with current usage. Limits reflect what the coordinator actually applies at dispatch, so a user can see the real throttle rather than what they assume they set. All values come from the signals-scout flag payload, so the banner and caps can change with no deploy.

Required API key scopes

signal_scout:read

Response


Example request

GET /api/projects/:project_id/signals/scout/metadata/current
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/metadata/current/

Example response

Status 200 This project's scout enrollment, announcement banner, and enforced run limits.
RESPONSE
{
"enrolled": true,
"banner_message": "string",
"limits": {
"max_runs_per_tick": 0,
"max_runs_per_day": 0,
"runs_today": 0,
"runs_remaining_today": 0,
"max_enabled_scouts": 0
}
}

List all signals scout notes

Return the steering notes left for this project's scouts, newest first. Pass skill_name to get the notes addressed to one scout (or one pipeline audience, e.g. pipeline:report-research) plus the general (blank-target) fleet-wide notes — the shape a scout run reads at cold start. Omit skill_name to browse every note. Expired notes are excluded unless include_expired=true. date_from / date_to are a half-open window on created_at (>= date_from, < date_to); pass date_to (the created_at of the oldest note seen) to walk past the cap. Pass text to keep only the notes whose content contains it, case-insensitively. Results capped at 500.

Required API key scopes

signal_scout:read

Query parameters

  • content_max_chars
    integer
  • date_from
    string
  • date_to
    string
  • include_expired
    boolean
    Default: false
  • include_general
    boolean
    Default: true
  • limit
    integer
  • skill_name
    string
  • text
    string

Example request

GET /api/projects/:project_id/signals/scout/notes
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/notes/

Example response

Status 200 Matching notes newest-first.
RESPONSE
{
"id": "string",
"skill_name": "string",
"content": "string",
"created_at": "string",
"expires_at": "string",
"created_by_name": "string",
"origin": "string"
}

Create signals scout notes

Leave a steering note the scout fleet reads on its next runs. Address it to one scout via skill_name (a configured scout), to one stage of the report pipeline via a reserved audience (pipeline:report-research), or omit it for a general note every scout sees. Each call creates a new note (no upsert); delete retires one. Attributed to the authenticated user.

Required API key scopes

signal_scout:writellm_skill:write

Request parameters

  • content
    string
  • skill_name
    string
  • expires_at
    string | null

Response


Example request

POST /api/projects/:project_id/signals/scout/notes
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/notes/\
-d content="string"

Example response

Status 201 The note as created.
RESPONSE
{
"id": "string",
"skill_name": "string",
"content": "string",
"created_at": "string",
"expires_at": "string",
"created_by_name": "string",
"origin": "string"
}
Status 400 Invalid note (empty content, oversized, bad skill_name target).

Delete signals scout notes

Delete one note by its id, retiring it from every scout's view. Use this when a note has been acted on or no longer applies; time-boxed notes can instead carry an expires_at and retire themselves.

Required API key scopes

signal_scout:writellm_skill:write

Path parameters

  • id
    string

Example request

DELETE /api/projects/:project_id/signals/scout/notes/:id
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl -X DELETE \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/notes/:id/

Example response

Status 204 Note deleted.
Status 404 Note not found for this project.

Retrieve signals scout project profile

Return the team's deterministic project profile. The response opens with a compact summary envelope carrying the emit gate and the inbox report counts, then the full payload. The inventory runs to tens of kilobytes, so a client that truncates a long tool result still keeps the gate. Pass summary_only=true to omit payload entirely. For the internal scout token the response reflects the newest non-expired cached row or a freshly-built one (lazy compute on cache miss); force_refresh=true skips the cache and rebuilds from authoritative sources. Public read callers (session auth or a signal_scout:read PAK) get the newest cached profile, or 404 if none has been built yet — they never trigger a rebuild. Read this at the start of a run to orient on the team's product mix, integrations, warehouse sources, signal coverage, and existing inbox surface.

Required API key scopes

signal_scout:read

Query parameters

  • force_refresh
    boolean
    Default: false
  • run_id
    string | null
  • summary_only
    boolean
    Default: false

Response


Example request

GET /api/projects/:project_id/signals/scout/project_profile/current
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/project_profile/current/

Example response

Status 200 The team's current project profile (cached, or freshly built for the internal scout token).
RESPONSE
{
"summary": {
"emit_eligibility": {
"ai_processing_approved": true,
"source_enabled": true,
"scout_emit_enabled": true,
"can_emit": true,
"blocking_reason": "string",
"remediation": "string"
},
"existing_inbox_reports": {
"total": 0,
"by_status": [
{
"status": "string",
"count": 0
}
]
}
},
"profile_id": "string",
"computed_at": "string",
"expires_at": "string",
"source_version": "string",
"payload": {
"inventory": {
"project_context": {
"product_description": "string",
"app_urls": [
"string"
]
},
"products_in_use": [
"string"
],
"product_intents": [
{
"product_type": "string",
"activated_at": "string",
"created_at": "string"
}
],
"integrations": [
{
"kind": "string",
"created_at": "string"
}
],
"external_data_sources": [
{
"source_type": "string",
"status": "string",
"prefix": "string",
"created_at": "string",
"last_run_at": "string",
"latest_error": "string"
}
],
"signal_source_configs": {
"enabled": [
{
"source_product": "string",
"source_type": "string"
}
],
"disabled": [
{
"source_product": "string",
"source_type": "string"
}
]
},
"emit_eligibility": {
"ai_processing_approved": true,
"source_enabled": true,
"scout_emit_enabled": true,
"can_emit": true,
"blocking_reason": "string",
"remediation": "string"
},
"scout_fleet": {
"enabled": [
{
"skill_name": "string",
"run_interval_minutes": 0,
"run_cron_schedule": "string",
"emit": true,
"last_run_at": "string",
"last_emitted_at": "string",
"not_running_reason": "string",
"pause_reason": "string"
}
],
"disabled": [
{
"skill_name": "string",
"run_interval_minutes": 0,
"run_cron_schedule": "string",
"emit": true,
"last_run_at": "string",
"last_emitted_at": "string",
"not_running_reason": "string",
"pause_reason": "string"
}
],
"emitted_lookback_days": 0
},
"existing_inbox_reports": {
"total": 0,
"by_status": [
{
"status": "string",
"count": 0
}
]
},
"recent_activity": {
"window_days": 0,
"by_scope": [
{
"scope": "string",
"edits": 0,
"users": 0,
"last_edit": "string"
}
]
},
"recent_reviewer_corrections": {
"window_days": 0,
"corrections": [
{
"report_id": "string",
"report_title": "string",
"before": [
"string"
],
"after": [
"string"
],
"at": "string"
}
]
},
"recent_dashboards": [
{
"id": 0,
"name": "string",
"last_accessed_at": "string",
"last_refresh": "string",
"created_at": "string"
}
],
"recent_surveys": {
"total_count": 0,
"active_count": 0,
"recent": [
{
"id": "string",
"name": "string",
"type": "string",
"status": "string",
"updated_at": "string"
}
]
},
"recent_feature_flags": {
"total_count": 0,
"active_count": 0,
"recent": [
{
"id": 0,
"key": "string",
"name": "string",
"active": true,
"updated_at": "string"
}
]
},
"recent_experiments": {
"total_count": 0,
"running_count": 0,
"recent": [
{
"id": 0,
"name": "string",
"status": "string",
"feature_flag_key": "string",
"updated_at": "string"
}
]
},
"recent_alerts": {
"total_count": 0,
"enabled_count": 0,
"recent": [
{
"id": "string",
"name": "string",
"enabled": true,
"state": "string",
"calculation_interval": "string",
"insight_id": 0,
"created_at": "string"
}
]
},
"recent_hog_functions": {
"total_count": 0,
"enabled_count": 0,
"recent": [
{
"id": "string",
"name": "string",
"type": "string",
"kind": "string",
"enabled": true,
"updated_at": "string"
}
]
},
"recent_hog_flows": {
"total_count": 0,
"active_count": 0,
"recent": [
{
"id": "string",
"name": "string",
"status": "string",
"updated_at": "string"
}
]
},
"recent_notebooks": {
"total_count": 0,
"recent": [
{
"short_id": "string",
"title": "string",
"last_modified_at": "string"
}
]
},
"recent_cohorts": {
"total_count": 0,
"recent": [
{
"id": 0,
"name": "string",
"is_static": true,
"count": 0,
"created_at": "string"
}
]
},
"recent_actions": {
"total_count": 0,
"recent": [
{
"id": 0,
"name": "string",
"updated_at": "string"
}
]
},
"top_events": [
{
"window_days": 0,
"event": "string",
"count": 0,
"distinct_users": 0,
"recent_24h_count": 0,
"recent_24h_users": 0,
"first_seen_in_window": "string",
"last_seen_in_window": "string"
}
]
}
}
}
Status 404 No profile has been built for this team yet, and the caller is not the internal scout token (which builds on cache miss). Public read callers never trigger a build.

Retrieve signals scout rubrics

Required API key scopes

signal_scout:read

Path parameters

  • id
    string

Response


Example request

GET /api/projects/:project_id/signals/scout/rubrics/:id
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/rubrics/:id/

Example response

Status 200
RESPONSE
{
"config_id": "d1d31429-d888-4f1c-b9c1-4e842f9bce5b",
"skill_name": "string",
"revision": 0,
"criteria": [
{
"id": "string",
"title": "string",
"description": "string",
"pass_condition": "string",
"applicability": "string",
"enabled": true,
"source": "default"
}
],
"generation": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"status": "queued",
"requested_at": "2019-08-24T14:15:22Z",
"context": "string",
"completed_at": "2019-08-24T14:15:22Z",
"task_id": "736fde4d-9029-4915-8189-01353d6982cb",
"task_run_id": "7f0ef9d7-e7b5-4d52-8247-ce8351652f8b",
"error": "string",
"suggestions": [
{
"id": "string",
"title": "string",
"description": "string",
"pass_condition": "string",
"applicability": "string",
"enabled": true,
"source": "default"
}
],
"summary": "string",
"reference_context": {
"schema_version": 0,
"skill_id": "string",
"skill_name": "string",
"skill_version": 0,
"description": "string",
"instructions": "string",
"instructions_truncated": true,
"report_channel": "none",
"report_disposition_instructions": "string",
"reference_files": [
"string"
],
"reference_files_truncated": true,
"reference_texts": [
{
"path": "string",
"content_type": "string",
"content": "string"
}
],
"reference_limits": {
"omitted_files": 0,
"truncated_files": [
"string"
]
}
}
},
"reference_context": {
"schema_version": 0,
"skill_id": "string",
"skill_name": "string",
"skill_version": 0,
"description": "string",
"instructions": "string",
"instructions_truncated": true,
"report_channel": "none",
"report_disposition_instructions": "string",
"reference_files": [
"string"
],
"reference_files_truncated": true,
"reference_texts": [
{
"path": "string",
"content_type": "string",
"content": "string"
}
],
"reference_limits": {
"omitted_files": 0,
"truncated_files": [
"string"
]
}
},
"reference_generation_id": "11e5f8e6-0022-4fc6-aae5-6cfd0717dc91"
}

Create signals scout rubrics

Required API key scopes

signal_scout:write

Path parameters

  • id
    string

Request parameters

  • context
    string
    Default:

Response


Example request

POST /api/projects/:project_id/signals/scout/rubrics/:id/generate
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/rubrics/:id/generate/\
-d context="string"

Example response

Status 202
RESPONSE
{
"config_id": "d1d31429-d888-4f1c-b9c1-4e842f9bce5b",
"skill_name": "string",
"revision": 0,
"criteria": [
{
"id": "string",
"title": "string",
"description": "string",
"pass_condition": "string",
"applicability": "string",
"enabled": true,
"source": "default"
}
],
"generation": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"status": "queued",
"requested_at": "2019-08-24T14:15:22Z",
"context": "string",
"completed_at": "2019-08-24T14:15:22Z",
"task_id": "736fde4d-9029-4915-8189-01353d6982cb",
"task_run_id": "7f0ef9d7-e7b5-4d52-8247-ce8351652f8b",
"error": "string",
"suggestions": [
{
"id": "string",
"title": "string",
"description": "string",
"pass_condition": "string",
"applicability": "string",
"enabled": true,
"source": "default"
}
],
"summary": "string",
"reference_context": {
"schema_version": 0,
"skill_id": "string",
"skill_name": "string",
"skill_version": 0,
"description": "string",
"instructions": "string",
"instructions_truncated": true,
"report_channel": "none",
"report_disposition_instructions": "string",
"reference_files": [
"string"
],
"reference_files_truncated": true,
"reference_texts": [
{
"path": "string",
"content_type": "string",
"content": "string"
}
],
"reference_limits": {
"omitted_files": 0,
"truncated_files": [
"string"
]
}
}
},
"reference_context": {
"schema_version": 0,
"skill_id": "string",
"skill_name": "string",
"skill_version": 0,
"description": "string",
"instructions": "string",
"instructions_truncated": true,
"report_channel": "none",
"report_disposition_instructions": "string",
"reference_files": [
"string"
],
"reference_files_truncated": true,
"reference_texts": [
{
"path": "string",
"content_type": "string",
"content": "string"
}
],
"reference_limits": {
"omitted_files": 0,
"truncated_files": [
"string"
]
}
},
"reference_generation_id": "11e5f8e6-0022-4fc6-aae5-6cfd0717dc91"
}

List all signals scout runs

Return the most recent SignalScoutRun summaries for this project, newest first. Used by the headless scout to dedupe against work other runs already covered. ILIKE matches on summary. date_from / date_to are a half-open window on created_at (>= date_from, < date_to); pass date_to on subsequent calls to walk past the 100-row cap. Pass emitted=true to see only runs that surfaced at least one finding. Pass skill_name (optionally with skill_version) to scope to a single scout. Results capped at 100.

Required API key scopes

signal_scout:read

Query parameters

  • date_from
    string
  • date_to
    string
  • emitted
    boolean | null
  • limit
    integer
  • skill_name
    string
  • skill_version
    integer
  • text
    string

Example request

GET /api/projects/:project_id/signals/scout/runs
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/runs/

Example response

Status 200 Recent run summaries newest-first.
RESPONSE
{
"run_id": "string",
"skill_name": "string",
"skill_version": 0,
"status": "not_started",
"created_at": "string",
"started_at": "string",
"completed_at": "string",
"task_id": "string",
"task_run_id": "string",
"task_url": "string",
"summary": "string",
"error": "string",
"failure_reason": "string",
"emitted_count": 0,
"emitted_finding_ids": [
"string"
],
"emitted_report_ids": [
"string"
],
"edited_report_ids": [
"string"
],
"metadata": {
"harness_prompt_version": "string",
"report_channel": "string",
"skill_origin": "string",
"github_guidance": true,
"business_knowledge_maintained": true,
"model": "string",
"runtime_adapter": "string",
"reasoning_effort": "string",
"service_tier": "string",
"network_access": "string",
"write_scopes": [
"string"
],
"triggered_by": "string",
"run_note": "string",
"derived": {
"has_emit_report": true,
"has_edit_report": true,
"has_self_improvement": true,
"has_chart": true,
"has_self_validation": true,
"has_structured_output": true
}
}
}

Retrieve signals scout runs

Return the full SignalScoutRun row. Status, timing, and error flow from the linked tasks.TaskRun. Strictly team-scoped — a UUID belonging to another team returns 404.

Required API key scopes

signal_scout:read

Path parameters

  • run_id
    string

Response


Example request

GET /api/projects/:project_id/signals/scout/runs/:run_id
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/runs/:run_id/

Example response

Status 200 Full run detail.
RESPONSE
{
"run_id": "string",
"skill_name": "string",
"skill_version": 0,
"status": "not_started",
"created_at": "string",
"started_at": "string",
"completed_at": "string",
"task_id": "string",
"task_run_id": "string",
"task_url": "string",
"summary": "string",
"error": "string",
"failure_reason": "string",
"emitted_count": 0,
"emitted_finding_ids": [
"string"
],
"emitted_report_ids": [
"string"
],
"edited_report_ids": [
"string"
],
"metadata": {
"harness_prompt_version": "string",
"report_channel": "string",
"skill_origin": "string",
"github_guidance": true,
"business_knowledge_maintained": true,
"model": "string",
"runtime_adapter": "string",
"reasoning_effort": "string",
"service_tier": "string",
"network_access": "string",
"write_scopes": [
"string"
],
"triggered_by": "string",
"run_note": "string",
"derived": {
"has_emit_report": true,
"has_edit_report": true,
"has_self_improvement": true,
"has_chart": true,
"has_self_validation": true,
"has_structured_output": true
}
}
}
Status 404 Run not found or not visible to this project.

Create signals scout record check

Close the follow-up check this run was dispatched to answer. The run note carries the check id and what to establish; this call is the only thing that records the answer, so a run that investigates and says nothing leaves the check unanswered. The verdict lands on the report as a check_result entry people read in the inbox. failed retires the check, passed re-arms a recurring one, and errored retries it. inconclusive with the awaiting_data reason looks again later, and any other reason ends the check. Send the outcome you actually reached rather than the one that closes the loop. A run may close the check it was dispatched for, or a check on its own scout that is due or waiting on a run.

Required API key scopes

signal_scout_internal:write

Path parameters

  • run_id
    string

Request parameters

  • check_id
    string
  • outcome
  • reason
  • explanation
    string
  • observed_value
    number | null

Response


Example request

POST /api/projects/:project_id/signals/scout/runs/:run_id/check-result
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/runs/:run_id/check-result/\
-d check_id="string",\
-d outcome=undefined,\
-d explanation="string"

Example response

Status 200 Verdict recorded on the report, and the check advanced or retired.
RESPONSE
{
"check_id": "051490c8-9abf-480a-9348-72c146208cd5",
"outcome": "string",
"check_status": "string",
"runs_remaining": 0
}
Status 400 The check does not exist for this project, already finished, waits for its report to resolve, is measured by the coordinator rather than a run, runs on another scout, or is neither waiting on a run nor due.
Status 404 Run not found for this project.

Create signals scout edit

Rewrite a report's title/summary, append a note or fresh evidence, set its suggested reviewers, and/or point it at another repository. Can target ANY of the project's inbox reports, not just scout-authored ones — so the edit is attributed to this scout. Reviewers and repository are how you rescue a report that surfaced routed to no one or against the wrong codebase: each replaces what the report holds and re-runs autostart, so a report that was missing a qualifying reviewer or a repository can open a draft PR. The response carries the repository the report holds after the edit, and the call fails when a repository it named did not land. Set actionability and/or priority (each with its explanation) when new evidence changed your judgment: each replaces the report's decision and re-runs autostart, without changing the report's inbox status. Title/summary edits are best-effort: the pipeline may later re-research them. Set supersedes_implementation alongside a rewrite when the fix changed. Verified automated predecessor PRs close only after the replacement completes with verified open PRs.

Required API key scopes

signal_scout_report:write

Path parameters

  • run_id
    string

Request parameters

  • report_id
    string
  • title
    string | null
  • summary
    string | null
  • append_note
    string | null
  • corroboration_only
    boolean
  • append_evidence
    Click to open
    array | null
  • suggested_reviewers
    Click to open
    array
  • repository
    string | null
  • charts
    Click to open
    array | null
  • metrics
    Click to open
    array | null
  • suggested_prompts
    array | null
  • links
    Click to open
    array
  • supersedes_implementation
    boolean
  • actionability
  • actionability_explanation
    string | null
  • already_addressed
    boolean | null
  • priority
  • priority_explanation
    string | null

Response


Example request

POST /api/projects/:project_id/signals/scout/runs/:run_id/edit-report
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/runs/:run_id/edit-report/\
-d report_id="string"

Example response

Status 200 Report edited.
RESPONSE
{
"report_id": "string",
"updated_fields": [
"string"
],
"note_appended": true,
"evidence_appended": 0,
"links_appended": 0,
"reviewers_set": true,
"repository_set": true,
"repository": "string",
"charts_set": 0,
"metrics_set": 0,
"suggested_prompts_set": 0,
"is_content_revision": true,
"content_revision_count": 0,
"supersedes_implementation": true,
"decision_fields_set": [
"string"
],
"warnings": [
{
"field": "string",
"message": "string"
}
],
"corroboration_collapsed": true
}
Status 400 Nothing to edit, empty note, or report not found for this project.
Status 404 Run not found for this project.

Retrieve signals scout runs

Return the findings a SignalScoutRun emitted to the inbox, newest first — one row per emit with its description (the finding text as surfaced), severity, and the deterministic source_id that joins back to the underlying signal. Lets a team and its agents see what a run surfaced without parsing emitted_finding_ids or scanning the signal store. Strictly team-scoped — a run UUID belonging to another team returns 404.

Required API key scopes

signal_scout:read

Path parameters

  • run_id
    string

Example request

GET /api/projects/:project_id/signals/scout/runs/:run_id/emissions
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/runs/:run_id/emissions/

Example response

Status 200 Findings this run emitted to the inbox, newest first.
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"run_id": "string",
"finding_id": "string",
"description": "string",
"severity": "P0",
"tags": [
"string"
],
"source_id": "string",
"emitted_at": "2019-08-24T14:15:22Z"
}
Status 404 Run not found or not visible to this project.

Retrieve signals scout runs emission

Best-effort reverse of the report -> signals link. For each finding the run emitted, resolve the inbox SignalReport (if any) its underlying signal grouped into by walking the deterministic source_id back through the signal store. report is null when the finding hasn't grouped into a report yet, was de-duplicated away, or its signal was deleted. Lets the scout UI surface which inbox report a finding contributed to — the reverse of the report's evidence list. Strictly team-scoped — a run UUID belonging to another team returns 404.

Required API key scopes

signal_scout:readtask:read

Path parameters

  • run_id
    string

Example request

GET /api/projects/:project_id/signals/scout/runs/:run_id/emissions/reports
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/runs/:run_id/emissions/reports/

Example response

Status 200 Per-finding inbox report links for this run, newest finding first.
RESPONSE
{
"finding_id": "string",
"source_id": "string",
"report": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"title": "string",
"status": "string"
}
}
Status 404 Run not found or not visible to this project.

Create signals scout emit

The second emit channel: author a complete SignalReport directly instead of emitting a weak signal. The report passes the safety judge, then surfaces at the status the scout's actionability call implies (or is suppressed). Backing evidence is written as bound signals so the report behaves like a pipeline report. Safe to retry: resending an emission returns the report the first call authored (idempotent_replay true) rather than a second one, keyed on idempotency_key or, without one, on the report's content. Use reports to find a report from an earlier run and edit-report to update it instead of authoring a near-duplicate.

Required API key scopes

signal_scout_report:write

Path parameters

  • run_id
    string

Request parameters

  • title
    string
  • summary
    string
  • evidence
    Click to open
    array
  • actionability_explanation
    string
  • actionability
  • already_addressed
    boolean
    Default: false
  • repository
    string | null
  • priority
  • priority_explanation
    string | null
  • suggested_reviewers
    Click to open
    array
  • charts
    Click to open
    array
  • metrics
    Click to open
    array
  • suggested_prompts
    array
  • links
    Click to open
    array
  • idempotency_key
    string | null

Response


Example request

POST /api/projects/:project_id/signals/scout/runs/:run_id/emit-report
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/runs/:run_id/emit-report/\
-d title="string",\
-d summary="string",\
-d evidence="array",\
-d actionability_explanation="string",\
-d actionability=undefined

Example response

Status 200 Report authored (READY/PENDING_INPUT/suppressed), or skipped by a preflight gate.
RESPONSE
{
"report_id": "string",
"report_status": "string",
"emitted": true,
"skipped_reason": "string",
"safety_explanation": "string",
"remediation": "string",
"idempotent_replay": true
}
Status 400 Invalid report shape (empty title/summary/evidence, bad actionability).
Status 404 Run not found for this project.