8.4 KiB
Agent JSON export
The agent JSON profile is the stable machine-readable research contract for downstream agents, scripts, dashboards, and workflow tools. Ask the slash command for machine-readable JSON:
/last30days AI coding agents — return the versioned agent JSON export
For direct engine use in scripts, cron jobs, or development, use:
python3 skills/last30days/scripts/last30days.py "AI coding agents" --emit=json
python3 skills/last30days/scripts/last30days.py "AI coding agents" --emit=json --output results.json
--emit=json defaults to --json-profile=agent. The full internal report remains available for debugging and power users:
python3 skills/last30days/scripts/last30days.py "AI coding agents" --emit=json --json-profile=raw
The raw profile is intentionally unversioned and may change when pipeline internals change. It preserves the JSON serialization used before the agent profile was introduced.
Local corpus privacy
Evidence from --corpus / LAST30DAYS_CORPUS_DIRS is excluded from the versioned agent profile by default. The exclusion removes corpus results, corpus-only clusters, corpus source outcomes, freshness verdicts, and titles derived from a corpus representative. Set LAST30DAYS_CORPUS_IN_EXPORT=1 only for a run whose JSON is intentionally allowed to contain local file contents. This opt-in does not change the schema shape or version; it permits source: "corpus" entries in the existing result fields. The unversioned raw profile is a complete local debug dump and may contain corpus paths and text.
Discovery export
Discovery mode has a separate versioned contract so its topic results do not change the normal research export:
python3 skills/last30days/scripts/last30days.py --discover "AI agents" --emit=json
Its top level contains schema_version (1.0), kind ("discovery"), domain, generated_at, window_days, source_status, feeds, results, and warnings. Each ranked result contains rank, topic, why_spiking, momentum (new-this-week or building), velocity_score, sources, per-source native engagement, a ready-to-run command, and evidence_urls. The discovery contract follows the same versioning policy below but evolves independently of the normal agent export. --json-profile=raw returns the unversioned internal DiscoveryReport dataclass instead.
When LAST30DAYS_API_KEY and LAST30DAYS_API_BASE route a run through a configured remote API, the server does not return the local Report needed to build this profile. In that mode, --json-profile=agent exits with status 2 instead of emitting a misleading shape; use --json-profile=raw to retain the remote backend's existing server-response JSON contract.
Top-level fields
| Field | Type | Meaning |
|---|---|---|
schema_version |
string | Agent export contract version. The current version is 1.2. |
query |
string | The research topic supplied to the engine. |
generated_at |
string | UTC generation timestamp in RFC 3339 format. |
window_days |
integer | Number of days between the report's start and end dates. |
source_status |
object | Map of source name to the outcome observed during this run. |
freshness_verdicts |
array | Per-claim act-time verdicts produced by --verify-freshness; empty when verification was not requested or no conservative claims were extractable. |
clusters |
array | Ranked groups of related results. |
results |
array | Ranked, flat evidence results for downstream processing. |
All top-level fields are always present. Empty runs contain empty clusters and results arrays. Sources appear in source_status when the run recorded an outcome for them.
freshness_verdicts
Each entry identifies the grounded claim and candidate, its primary source item, the typed verdict (current, stale, contradicted, or unsupported), the original and re-derived values when applicable, and source/evidence URLs and timestamps. stale means a successful point re-fetch returned a moved value; contradicted means a newer item in the report window explicitly disagrees; unsupported means the datum could not be re-checked, including degraded source_status outcomes. Consumers can gate actions on verdict == "current" without treating an unreachable source as evidence that a claim moved.
source_status
Each value distinguishes a clean empty result from incomplete coverage:
| State | Meaning |
|---|---|
ok |
The source completed and returned one or more items. |
no-results |
The source completed successfully but found no matching items. |
partial |
The source returned some items before a later failure. |
rate-limited |
Retrieval was stopped by a provider rate limit. |
auth-failed |
Credentials were missing, rejected, or expired during retrieval. |
unreachable |
The source or network endpoint could not be reached. |
timeout |
Retrieval exceeded its time limit. |
schema-drift |
The provider response no longer matched the expected shape. |
skipped-unconfigured |
The source was intentionally skipped because required configuration was absent. |
error |
Retrieval failed for another reason. |
Consumers must not interpret failure states as evidence that a source had no discussion. Only no-results means the source completed cleanly with zero matches.
Cluster fields
| Field | Type | Meaning |
|---|---|---|
title |
string | Cluster headline. |
summary |
string | Summary from the cluster's representative ranked result. |
sources |
array of strings | Sources represented by the cluster. |
engagement_total |
number | Sum of one headline native engagement counter per result. Known sources use their primary count (for example, Digg uses postCount); otherwise the largest counter-like field is used. Ranking, ratio, rating, and computed-score metadata are excluded. |
Cluster array order is ranking order. A result's cluster value is the zero-based index into this array.
Result fields
| Field | Type | Meaning |
|---|---|---|
candidate_id |
string | Stable identifier joining this result to freshness_verdicts[].candidate_id. Added in 1.2. |
title |
string | Result title. |
source |
string | Primary source name, such as reddit, x, youtube, or grounding. |
url |
string | Canonical result URL. It may be empty when the provider supplies no link. |
published_at |
string | Primary source item's publication date or timestamp. Omitted when unknown. |
summary |
string | Normalized snippet, with the relevance explanation or body used as fallback. |
engagement |
object | Native engagement counters from the primary source item, such as Reddit score and num_comments or X likes and reposts. |
relevance_score |
number | Engine final score normalized to the inclusive 0.0–1.0 range. |
cluster |
integer | Zero-based index into clusters. Omitted when the result is not assigned to a cluster. |
Fields whose value is unknown are omitted rather than emitted as JSON null. Strings and collection fields otherwise remain present, including empty strings, objects, or arrays.
Comparison runs
Comparison queries use an envelope so each entity keeps its own contract:
{
"schema_version": "1.2",
"comparison": true,
"entities": ["OpenAI", "Anthropic"],
"reports": [
{"entity": "OpenAI", "report": {"schema_version": "1.2", "query": "OpenAI"}},
{"entity": "Anthropic", "report": {"schema_version": "1.2", "query": "Anthropic"}}
]
}
The abbreviated reports above only illustrate the envelope; real reports contain every documented top-level field.
Versioning policy
schema_versionusesmajor.minornumbering.- Any breaking field removal, rename, type change, semantic change, or envelope change requires a major-version bump.
- Backward-compatible field additions may use a minor-version bump. Consumers should ignore fields they do not recognize.
- The checked-in golden snapshot test locks the complete current shape. Contract changes must update the version and snapshot deliberately.
1.2addedcandidate_idto eachresultsentry so verdicts can be joined to the result they annotate.--json-profile=rawis outside this compatibility policy because it mirrors internal pipeline dataclasses.
--preflight --emit=json is a different machine contract for permission and configuration inspection. --json-profile does not alter preflight output.