horizOn MCP Server
OfficialThe horizOn MCP Server lets AI assistants read horizOn docs, call live backend player APIs, use workflow prompts, and—with an Account Key—manage dashboard/admin resources.
Read 29 documentation resources without an API key covering overview, auth, marketplace, chat, matches, shared objects, items, groups, friends, achievements, inbox, statistics, player values, leaderboards, cloud save, remote config, localization, news, gift codes, profile, validated actions, feedback, logs, crash reporting, API reference, Godot/Unity/Unreal quickstarts, and email.
Authenticate players with anonymous/email signup and sign-in, and validate sessions.
Use leaderboards: list boards, submit scores, and fetch top, around-user, and user-rank entries with profiles.
Manage cloud saves: save/load player data, with revision conflict handling.
Read configuration/content: remote configs, localizations, languages, and news.
Handle gift codes and profiles: validate/prepare/redeem codes, read/update avatar, frame, badges, unlocks, and cosmetics catalog.
Run Validated Actions: start server-checked runs, submit results with input-log hashes, upload evidence, and read server-owned balances/state.
Use documented social/gameplay features: friends, groups, items, shared objects, asynchronous matches, hosted chat, marketplace, inbox, achievements, statistics, and player values.
Submit operational data: feedback, user logs, crash sessions/reports, and transactional emails; check and cancel emails.
Use 4 workflow prompts: integrate-feature, setup-auth, debug-connection, and explain-feature.
With HORIZON_ACCOUNT_API_KEY, access scoped admin tools for dashboard projects, config, news, email templates, gift codes, users, leaderboards, cloud saves, crash reports, feedback, logs, SMTP, Validated Actions, and related management/statistics.
Respect safety semantics: tools declare read/destructive/idempotent/open-world hints; session tools require accessToken as sessionToken; no automatic retries, background polling, WebSocket, or trading processes.
Provides quickstart documentation and code examples for integrating horizOn Backend-as-a-Service into Unity projects.
Provides quickstart documentation and code examples for integrating horizOn Backend-as-a-Service into Unreal Engine 5.5+ projects using the official horizOn SDK plugin, including C++ and Blueprint examples.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@horizOn MCP ServerCan you show me the Godot quickstart for cloud saves?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
horizOn MCP Server
MCP server for horizOn Backend-as-a-Service
Gives AI coding assistants documentation, live API tools, and workflow prompts for game and app development.
Quick Install
Add to your MCP client configuration (Claude Desktop, Cursor, etc.):
{
"mcpServers": {
"horizOn": {
"command": "npx",
"args": ["-y", "horizon-mcp"],
"env": {
"HORIZON_API_KEY": "your-api-key-here"
}
}
}
}Related MCP server: Godot MCP
Features
The server exposes 29 documentation resources, 120 player tools and 4 workflow prompts. An Account Key enables additional scoped admin tools. These counts come from the registered MCP resources, tools and prompts.
Resources
Documentation resources are served directly from the MCP server. No API key required.
URI | Description |
| Atomic original-item escrow, exact prices, protected Inbox returns and scoped recovery. |
| Direct/group/project text, metadata-only realtime, incremental snapshots, original receipts and scoped moderation. |
| Opaque turn state, exact revisions, immutable reports, bounded deadlines and original ranked-run recovery. |
| Opaque bounded world data, current permissions, exact revisions and trusted ordinary game notices. |
| Unique inventory, bounded item properties and atomic server-owned purchases |
| Guilds, roles, bounded member pages and revision-safe membership actions |
| Atomic social relationships, explicit revisions and exact public friend-code lookup |
| Versioned definitions, permanent completion bits and immediate atomic value rewards |
| Session inbox, protected rewards, immutable broadcasts, server clock and safe publication retries |
| Atomic session counters, safe integer batches, explicit original IDs and cache/UTC recovery. SDK and admin examples |
| Atomic balances and offers, stable operation IDs, all three SDKs, safe retries and support corrections |
| What is horizOn, core concepts (Account vs User), features, tier system, API structure, and SDKs |
| Authentication methods (Anonymous, Email, Google), endpoints, SDK code examples, and common errors |
| Leaderboard score submission, top entries, user rank, entries around user, player profile per entry, validated only boards, with SDK examples |
| Cloud save/load for JSON and binary data, tier size limits, SDK examples |
| Server-side key-value configuration: feature flags, game balance, A/B testing. SDK examples |
| Server-side localized strings across 15 languages: per-key translations, single/all fetch, available languages. SDK examples |
| In-game news and announcements with language filtering. SDK examples |
| Gift code validation and redemption, cosmetic grants, server-owned value rewards, compact V2 original intents and exact counter strings. SDK examples |
| Player avatar, frame and badges from a per-project cosmetics catalog, unlocks via gift code grants, profile in leaderboard entries. SDK examples |
| Server-checked runs: single-use run tickets with a server seed, SHA-256 input log hash, server-only rules, validated only leaderboards, server-owned player state, start context, evidence upload, admin evidence review with sus packages and package export, rejection codes. SDK examples |
| Bug reports, feature requests, and general feedback submission. SDK examples |
| Server-side event and error tracking. Requires BASIC tier or higher. SDK examples |
| Crash report submission, session tracking, fingerprinting, breadcrumbs, and auto-regression detection. SDK examples |
| Complete API reference for all horizOn App API endpoints with request/response schemas |
| Step-by-step guide to integrate horizOn in Godot with GDScript examples |
| Step-by-step guide to integrate horizOn in Unity with C# examples |
| Transactional and event-based email delivery to registered users. Templates, scheduling, status tracking, and SMTP integration. SDK examples |
| Step-by-step guide to integrate horizOn in Unreal Engine 5.5+ with the official horizOn SDK plugin. C++ and Blueprint examples |
Player tools
Live API tools that call the horizOn backend. Requires a valid API key.
horizon_submit_score, horizon_save_cloud_data, horizon_load_cloud_data, horizon_prepare_gift_code, horizon_redeem_gift_code, horizon_get_profile, horizon_set_profile, horizon_start_run, horizon_submit_validated, horizon_get_state and horizon_upload_evidence also need the player's session: sign in first and pass the returned accessToken as sessionToken.
The four player-value tools also require the same player session. Never generate another operation ID automatically after an uncertain result.
Every tool declares MCP annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint), so clients can tell reads from writes. Examples of destructive tools include horizon_save_cloud_data (replaces the save), horizon_set_profile (replaces the whole profile), horizon_submit_validated (consumes the ticket, can spend balances) and horizon_cancel_email, plus horizon_purchase_player_value_offer and horizon_adjust_player_value (debit or credit exactly once per persisted operation ID). Many read tools that return an object also declare an outputSchema and return structuredContent next to the JSON text. Each description names when to use the tool, which sibling to use instead, what it returns and how to recover from its errors.
Tool | Description |
| Test connection to the horizOn API (health check) |
| Create a new anonymous user account |
| Create a new user account with email and password |
| Sign in with email and password |
| Sign in with an anonymous token |
| Check whether a user session is still valid |
| List available leaderboard boards for multi-board calls |
| Submit a score to the leaderboard (403 |
| Get the top leaderboard entries with each player's profile, optionally by board key |
| Get a user's leaderboard rank, optionally by board key |
| Get leaderboard entries around a user's position, optionally by board key |
| Save cloud data for a user, optionally only at an |
| Load cloud save data for a user, with its |
| Get a single remote config value by key |
| Get all remote config values |
| Get a single localized string by key, optionally for a specific language |
| Get all localized strings, optionally for a specific language |
| List the languages that have localizations for the app |
| Get news articles with optional language filtering |
| Validate a gift code without redeeming it |
| Read-only V2 preparation; persist all seven original intent fields before consume |
| Explicit consume/retry of that saved |
| Get a player's profile (avatar, frame, badges), unlocks and the cosmetics catalog |
| Replace a player's whole profile (avatar, frame, up to 3 badges) |
| Read balances and operation window with the active player session |
| Read configured offers for the player |
| Purchase atomically with a caller-persisted operation ID |
| Adjust within explicitly enabled limits with a stable ID and reason |
| Start a server-checked run: single-use ticket with a server seed, optionally bound to a board and with a start context (game, content, simulation and replay format versions, content digest, initial state as base64) |
| Submit a run result with the ticket and the SHA-256 input log hash (given, or computed locally from base64 bytes or text), optionally with |
| Read the player's server-owned values (balance, earned today, daily cap per value key); read only |
| Upload the input log (text or base64, encoded locally) of a run whose submit result asked for evidence; rejections name their |
| Reads a player's statistics snapshot and server operation window. |
| Reads the project's statistics catalog conditionally by version. |
| Applies one explicit atomic session batch with a caller-persisted operation ID. |
| Reads visible achievement definitions and permanent completion bits. |
| Unlocks one configured manual achievement once for the authenticated player. |
| Reads compatibility reward status for up to eight original achievement keys. |
| Reads friends, incoming/outgoing requests, blocks and current limits. |
| Finds one public player by exact UUID or canonical H- friend code in this project. |
| Sends Friend Request using the reviewed player revision. |
| Accepts Friend Request using the reviewed player revision. |
| Declines Friend Request using the reviewed player revision. |
| Cancels Friend Request using the reviewed player revision. |
| Removes Friend using the reviewed player revision. |
| Blocks Player using the reviewed player revision. |
| Unblocks Player using the reviewed player revision. |
| Reads my groups using a matching player session. |
| Reads group using a matching player session. |
| Reads group members using a matching player session. |
| Reads group pending requests using a matching player session. |
| Creates a fresh server-identified group and its leader atomically. |
| Replaces the complete group metadata and private JSON object. |
| Applies the explicit join group action using the reviewed group revision. |
| Applies the explicit request group join action using the reviewed group revision. |
| Applies the explicit invite group player action using the reviewed group revision. |
| Applies the explicit accept group invite action using the reviewed group revision. |
| Applies the explicit decline group invite action using the reviewed group revision. |
| Applies the explicit cancel group invite action using the reviewed group revision. |
| Applies the explicit accept group request action using the reviewed group revision. |
| Applies the explicit decline group request action using the reviewed group revision. |
| Applies the explicit cancel group request action using the reviewed group revision. |
| Applies the explicit leave group action using the reviewed group revision. |
| Applies the explicit remove group member action using the reviewed group revision. |
| Applies the explicit set group member role action using the reviewed group revision. |
| Applies the explicit transfer group leadership action using the reviewed group revision. |
| Applies the explicit delete group action using the reviewed group revision. |
| Reads the player's bounded unique item inventory. |
| Reads one bounded item template page, including archived templates. |
| Adjusts Item Properties using the reviewed inventory revision. |
| Sets Item Equipped State using the reviewed inventory revision. |
| Discards Item using the reviewed inventory revision. |
| Reads one permanent collection catalog page. |
| Reads the current player's count and creation precondition for one collection. |
| Reads one object under current permissions. |
| Reads one bounded metadata-selected object page. |
| Creates one server-ID object using the original owner-usage revision. |
| Replaces one object's opaque bytes and configured search data under its exact revision. |
| Deletes one exact-revision object and refunds its stored charge. |
| Reads the player's bounded active, invited and recent match summaries. |
| Reads the player's five-tier limits and project capabilities. |
| Reads one strength-filtered open-lobby page under current blocks and active-owner checks. |
| Reads one currently authorized match snapshot. |
| Creates one server-ID lobby under the original player-ledger revision. |
| Executes join match under the exact original revision. |
| Executes decline match invitation under the exact original revision. |
| Executes start match under the exact original revision. |
| Executes submit match turn under the exact original revision. |
| Executes advance match timeout under the exact original revision. |
| Executes leave match under the exact original revision. |
| Executes cancel match lobby under the exact original revision. |
| Records this participant's immutable report for the frozen final state. |
| Creates or recovers one original match-bound validated run after complete consensus. |
| Reads five-tier bounds, current moderation and hosted capabilities. |
| Opens deterministic direct, group or project chat under current permissions. |
| Reads an authorized incremental snapshot after subscription resync/event or explicit user action. |
| Sends plain text once or explicitly replays the exact original operation. |
| Reads the current player's retained original send receipt. |
| Reports one currently visible message with the original reason. |
| Reads current own marketplace state or configured limits. |
| Reads current own marketplace state or configured limits. |
| Reads one revision-consistent bounded rule page. |
| Reads one bounded active-listing page by item and price. |
| Reads one authorized listing or original own operation receipt. |
| Reads one authorized listing or original own operation receipt. |
| Lists one original unequipped item at the explicitly approved price and fee configuration. |
| Purchases the exact listing under its original revision, currency and price. |
| Cancels the original listing revision into a protected pending item return. |
| Attempts one explicitly requested pending return delivery for the current return owner. |
| Reads targeted messages and eligible project broadcasts, counters and server polling interval. |
| Marks an inbox entry read for the authenticated player. |
| Claims an inbox reward once for the authenticated player. |
| Removes an eligible inbox entry for the authenticated player. |
| Submit user feedback (bug reports, feature requests) |
| Create a server-side log entry (INFO, WARN, ERROR) |
| Submit a crash report (grouped by fingerprint, with regression detection) |
| Register a game session for the crash-free rate |
| Send a transactional email to a registered user from a template |
| Cancel a pending or scheduled email |
| Get the status of a sent or scheduled email |
Prompts (4 prompts)
Workflow prompts that guide AI assistants through common horizOn tasks.
Prompt | Description |
| Generate integration code for a specific horizOn feature in your game engine |
| Step-by-step guide to set up horizOn authentication in your project |
| Diagnose and fix horizOn connection issues |
| Get a detailed explanation of any horizOn feature |
Configuration
Variable | Required | Description |
| Yes (for tools) | Your horizOn API key. Get one at horizon.pm |
| No | API base URL. Defaults to |
| No | Account Key for additional scoped dashboard admin tools |
Resources (documentation) work without an API key. Only the live API tools require authentication. Session-bound tools also require the matching player session and declare userId and sessionToken in their input schemas.
Feature availability follows the selected backend and project configuration. Realtime, chat, Validated Actions and ranked match validation require hosted horizOn. The self-hosted simpleServer supports a subset of the REST APIs. MCP tools make explicit HTTP calls and do not create a background WebSocket connection, polling loop or automatic trading/retry process.
Admin Tools (v1.2+)
With an Account Key (creatable in your horizOn Dashboard -> API Keys -> Create -> Account Key), the MCP server exposes additional tools that let Claude manage your dashboard -- projects, remote config, news, email templates, gift codes, users, leaderboards, cloud-save data, crash reports, feedback, user logs, SMTP, and Validated Actions (rules, runs, player values and the evidence review).
How to get your Account Key
Log in to your horizOn Dashboard
Navigate to API Keys in the sidebar
Click Create API Key
Select Account Key as the key type
Choose whether the key can access the entire account, a single Project API Key, or selected feature groups
Click Create -- your key will be shown once. Copy it immediately.
Add the key to your MCP configuration (see Setup below)
Setup
Add both keys to your MCP client configuration:
{
"mcpServers": {
"horizOn": {
"command": "npx",
"args": ["-y", "horizon-mcp"],
"env": {
"HORIZON_API_KEY": "your-project-key (for player-facing tools)",
"HORIZON_ACCOUNT_API_KEY": "your-account-key (for dashboard tools)"
}
}
}
}Both can be set together or individually. Admin tools only register when the account key is set -- otherwise the server exposes only the original player-facing tools.
Scope
Account Keys inherit your account's tier (FREE/BASIC/PLUS/PRO/ENTERPRISE) -- they grant no extra privileges. A key can be full-account, limited to a single Project API Key, limited to selected feature groups, or both. Platform-admin-only endpoints (Blog, Banner, System-Config) are automatically unreachable. A handful of ultra-sensitive endpoints (account deletion, credentials change, key management itself, subscription cancel) require a dashboard session and cannot be called via an Account Key.
When a key is project-scoped, the backend enforces that scope on direct HTTP calls too. Account-wide endpoints or ID-only endpoints that cannot prove project context are rejected for project-scoped keys.
Tool Groups
Admin tools carry the same annotations as the player tools: list, get and statistics tools are read only, update and delete tools are marked destructive.
Prefix | Description |
| Configure definitions and inspect owned player progression |
| Inspect scoped relationships, groups and configured limits |
| Manage item catalogs, owned collections and explicit cleanup |
| Inspect asynchronous matches and manage hosted chat/moderation |
| Manage marketplace rules, scoped operations and durable inbox notices |
| Manage scoped localization entries |
| Read/replace catalogue with If-Match, inspect minimal guards and correct balances with an original note/hash |
| Project API key management (create/update/regenerate/revoke/delete) |
| Remote config CRUD |
| Multilingual news (titles/messages as |
| Multilingual email templates with variables |
| Gift code CRUD + revoke |
| User management + statistics (no full-list needed) |
| Leaderboard entries + statistics |
| Cloud save data + statistics |
| Crash groups, reports, statistics |
| Read user feedback |
| Read user logs |
| Account SMTP configuration (password always returned masked) |
| Validated Actions evidence review: list (top N records or, with |
| Validated Actions configuration: rule set per Project API key (get, replace, delete), run capacity of the hour, recent runs with rejection codes (filter |
What is horizOn?
horizOn is a multi-tenant Backend-as-a-Service platform built for game and app developers. It provides a managed backend so developers can focus on building their game or app instead of server infrastructure.
Core features:
Authentication (Anonymous, Email, Google, Apple)
Leaderboards
Cloud Save
Remote Config
Localization
News and Announcements
Gift Codes
Player Profile (avatar, frame, badges)
Player Values (atomic configured purchases, safe adjustments, minimal public replay guards)
Statistics, inbox rewards and achievements
Friends, blocklists and groups
Item catalogs, unique inventory and marketplace escrow/trades
Shared objects with scoped permissions and asynchronous matches
Hosted chat, with realtime managers provided by the native SDKs
Validated Actions (server-checked runs, validated only leaderboards, server-owned currency)
User Feedback
User Logs
Crash Reporting
Email Sending
Learn more at horizon.pm. Install this MCP server via npm.
Supported Engines
Godot 4.5+ -- GDScript SDK
Unity 6 -- C# SDK
Unreal Engine 5.5+ -- C++ and Blueprint SDK
Development
# Clone the repository
git clone https://github.com/ProjectMakersDE/horizOn-mcp.git
cd horizOn-mcp
# Install dependencies
npm install
# Start the server (development mode)
npm run dev
# Build for production
npm run build
# Run tests
npm testLicense
MIT
Statistics tools
horizon_get_statistics, horizon_get_statistics_definitions and horizon_update_statistics expose explicit session counters. Persist the original timestamp:UUID and immutable batch before posting; after a timeout reuse that intent, never generate a replacement ID automatically. Read horizon://docs/statistics or use integrate-feature with feature=statistics for engine guidance. Four Account Key tools inspect/replace definitions with If-Match, inspect one owned player and read tier limits (horizon_admin_statistics_*). Statistics are separate from player values.
Inbox tools
Four player tools read, mark read, claim and remove inbox entries with the active session. Four horizon_admin_inbox_* tools manage immutable broadcasts or inspect an owned player with an INBOX-scoped Account Key. Read horizon://docs/inbox before publishing: persist the exact intent, use serverTime for new timestamps, and retain the original ID after an uncertain response. Protected rewards never silently expire or disappear.
Achievements
horizon_get_achievements, horizon_unlock_achievement and horizon_deliver_achievement_rewards
expose permanent completion and immediate atomic Player Values rewards. The compatibility delivery
tool only reads legacy status. Four horizon_admin_achievements_* tools manage
the versioned catalog and inspect owned players with ACHIEVEMENTS scope. Read
horizon://docs/achievements for hidden-definition caching, original-key replay and verified cold
settlement of legacy originals. New unlocks create no personal Inbox reward/history copy.
Engine prompts accept feature=achievements.
Friends
horizon_get_friends, horizon_find_player and seven explicit social-action tools preserve reviewed
revisions and pending request IDs. Two read-only horizon_admin_friends_* tools inspect owned state
and current limits. Read horizon://docs/friends; both engine prompts accept feature=friends.
After an uncertain response, read and reconcile the snapshot before any new player-confirmed action.
Groups
Twenty player tools cover group snapshots, bounded member pages, pending entries, creation, metadata
and fourteen explicit membership/role actions. Six read-only horizon_admin_groups_* tools inspect
owned projects. All writes preserve reviewed revisions and pending IDs. Read horizon://docs/groups;
both engine prompts accept feature=groups. Uncertain writes are never retried automatically.
Items
Five player tools read inventory/catalog and explicitly adjust, equip or discard an instance. Four
horizon_admin_items_* tools inspect owned state, page the catalog, edit one template using If-Match
and read tier limits. Player-value offers accept bounded itemRewards and grant them atomically with
the debit. Read horizon://docs/items; both engine prompts accept feature=items.
Shared Objects
Seven player tools expose bounded opaque shared objects, typed queries and exact-revision writes.
Ten horizon_admin_shared_* tools manage owned collections and explicit cleanup. A separate
horizon_admin_inbox_send_ordinary tool uses INBOX scope for a trusted backend's durable notice
intent. Read horizon://docs/shared-objects; both engine prompts accept feature=shared-objects.
Native SDK/PHP/deployment readiness must be checked against the installed version.
Configured policies and technical frames
The new feature tools forward higher/lower current System Config policies rather than treating tier defaults as maxima. Groups expose eleven policies; explicit pages may exceed50 and the default page1 remains usable after lowering. PV supports256 lifetime identities, configured offer counts above1000 and up to256 correction keys. Achievement catalogs can exceed the former 500-key default within current active/lifetime policies and their1 MiB frame. Retained responses are passed through completely after reductions; MCP never truncates a result to a current quota.
Technical bounds stay separate: Shared has a1 MiB decoded object/query envelope and1402200-byte write frame; Matches accepts up to14999552 decoded state bytes (14648KiB) within its20003500-byte create/turn frame. Groups use the complete16 MiB BSON envelope and100663296-byte create/update HTTP frame, with configured name/description/data/depth policies. Fixed item property/template/ delta/grant formats, three Shared search fields and current Chat text/window bounds remain. Validation adds no limits fetch, pagination, retry or database request. These are representation bounds, not a throughput, memory-use or cluster-admission guarantee.
Asynchronous Matches
Fourteen player tools and seven scoped admin tools cover bounded lobbies, opaque turns, immutable
result reports and original match-bound ranked-run recovery. Writes keep exact revisions and
make one HTTP attempt. Consensus does not award automatic rewards. simpleServer supports ordinary
REST and explicitly excludes ranked validation/realtime. Read horizon://docs/matches; engine
prompts accept feature=matches.
Hosted Chat (TASK-1014)
Six app tools cover capabilities, deterministic channel open, incremental sync, original send,
receipt reconciliation and reporting. Twelve CHAT-scoped admin tools expose word filters,
metadata/messages, report moderation, mute/ban and bounded cleanup. Read
horizon://docs/chat; engine prompts accept feature=chat. simpleServer explicitly returns
501 NOT_SUPPORTED for chat. These HTTP tools do not create a background WebSocket connection
or polling loop. Use the existing native realtime managers for interactive feeds.
Marketplace
The ten player and fourteen scoped operator tools preserve original-item escrow, atomic
currency settlement, exact original intent and lossless Inbox returns. Read
horizon://docs/marketplace for routes, original revisions, five-tier limits and recovery.
Engine prompts accept feature=marketplace. No automatic trading, price polling or retries.
Available Tools
120 toolshorizon_accept_friend_requestAccept Friend RequestADestructiveIdempotent
Accepts Friend Request using the reviewed player revision. Use when: the player explicitly requests this social action. Not for: automatic retries after timeout, automatic acceptance of crossed requests or changing expectedRevision without reconciling intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. A current snapshot revision and its exact requestId. Side effects: Consumes the exact incoming request and any crossed request, creates the friendship on both sides and sends an ordinary confirmation atomically. No automatic retry. Repeating the same revision cannot create a second effect. Returns: Complete {userId,revision,friendCode,friends,incoming,outgoing,blocked,limits,serverTime} snapshot. Replace the matching host/project/player cache. lastActiveAt is the latest retained login, null when unknown; it is not online presence. Errors: 409 REVISION_CONFLICT or an uncertain response: get a new snapshot and reconcile intent, never silently replace expectedRevision and repeat. 404 FRIEND_REQUEST_NOT_FOUND means this request was removed or replaced; do not act on a newer ID. INBOX_FULL rejects the entire send/accept. Friend/request/block capacity limits reject additions while existing data remains removable. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player UUID matching the session | |
| requestId | Yes | Exact request ID from the reviewed incoming/outgoing snapshot | |
| sessionToken | Yes | Player accessToken sent only as Authorization Bearer | |
| targetUserId | Yes | The other player UUID in the same project | |
| expectedRevision | Yes | Exact revision from the reviewed actor snapshot; never refresh and substitute automatically |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it states exactly what is consumed (the incoming request plus any crossed request), what is created on both sides, that the confirmation is sent atomically, and that repeating the same revision cannot double-apply — which operationalizes idempotentHint=true with real semantics. The error catalogue (REVISION_CONFLICT, FRIEND_REQUEST_NOT_FOUND, INBOX_FULL, capacity limits, 401/403/429) with per-code remediation is rich behavioral context the annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded and cleanly sectioned (Use when / Not for / Requires / Side effects / Returns / Errors), with no filler about the tool's purpose. It is long and slightly redundant — 401 handling is covered twice (expired session vs. wrong HORIZON_API_KEY) — but for a destructive, revision-guarded mutation nearly every clause carries operational weight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With five required parameters, no output schema, and destructive+idempotent semantics, the description supplies everything an agent needs: auth prerequisites, the exact snapshot/revision contract, the full returned snapshot shape and cache-replacement instruction, the lastActiveAt caveat, and a complete error-to-recovery mapping. Nothing material is left to inference.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description earns extra: it explains how to obtain sessionToken (sign in via horizon_signin_email or horizon_signin_anonymous and pass the accessToken) and stresses that expectedRevision/requestId must come from the reviewed snapshot rather than a refreshed one. That is invocation guidance the schema does not provide, though it does not document targetUserId or the userId/403 token-ownership tie in detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb + resource ("Accepts Friend Request") and immediately qualifies the mechanism ("using the reviewed player revision"), which separates it from horizon_decline_friend_request and horizon_cancel_friend_request in the sibling list. An agent can pick this tool without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit "Use when" and "Not for" sections rule out automatic retries, automatic acceptance of crossed requests, and silent expectedRevision substitution — unusually clear exclusions for a social-write tool. It stops short of naming the sibling to use instead (e.g. decline/cancel), so it lands at 4 rather than 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_accept_group_inviteaccept group inviteADestructiveIdempotent
Applies the explicit accept group invite action using the reviewed group revision. Use when: the player explicitly confirms this group action. Not for: replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Current group revision and the exact pending requestId where applicable. Side effects: Consumes your exact invitation, rechecks limits/blocks and notifies the active issuer. No automatic retry. Same-revision replay cannot create a second effect. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| requestId | Yes | Exact pending identity from the reviewed snapshot | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| expectedRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the annotations: discloses that the exact invitation is consumed, limits/blocks are rechecked, the issuer is notified, and that same-revision replay cannot produce a second effect — consistent with idempotentHint=true and destructiveHint=true rather than contradicting them. Adds concrete HTTP-status semantics (409 revision conflict, REQUEST_NOT_FOUND, INBOX_FULL rollback, 429 no retry) that annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose then clearly labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors), making it scannable despite its length. Minor redundancy in the error tail, where 429 and the 401/HORIZON_API_KEY case are restated.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, yet the description specifies the return shape ({groups: MyGroupsView, group: GroupView|null}), the privacy scope of groups, and the cache-invalidation instruction. Auth, side effects, idempotency, and failure reconciliation are all covered for a destructive 5-param mutation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, but the description adds operational meaning: how to obtain sessionToken (sign in via horizon_signin_email/horizon_signin_anonymous and pass the accessToken), and that expectedRevision must be the reviewed revision and requestId the exact pending identity. Slight redundancy with the schema's own hints, hence not a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: applies the accept-group-invite action against a reviewed group revision, and that it consumes the player's exact invitation. It does not explicitly distinguish itself from nearby siblings horizon_accept_group_request or horizon_decline_group_invite, so the agent must infer invite-vs-request semantics from the name alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' and 'Not for' clauses name the triggering condition (player explicitly confirms the action) and three exclusions (replacing reviewed revision/requestId, bypassing a leader's block, automatic retry after uncertainty). It also routes reconciliation to horizon_get_groups and horizon_get_group_pending.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_accept_group_requestaccept group requestADestructiveIdempotent
Applies the explicit accept group request action using the reviewed group revision. Use when: the player explicitly confirms this group action. Not for: replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Current group revision and the exact pending requestId where applicable. Side effects: Leader/officer admits this exact requester and sends their ordinary confirmation atomically. No automatic retry. Same-revision replay cannot create a second effect. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| requestId | Yes | Exact pending identity from the reviewed snapshot | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| targetUserId | Yes | Other player in this project | |
| expectedRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, it discloses atomic admission and confirmation, no automatic retry, same-revision replay safety, return shape, and a detailed error-handling model. These details materially help an agent understand a destructive, idempotent, open-world mutation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is structured and front-loaded with purpose, usage, requirements, side effects, returns, and errors. It is long, especially in the error section, but most content is useful for this complex mutation tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given six required parameters, no output schema, and destructive/idempotent annotations, the description is complete: it explains authentication, side effects, return shape, idempotency behavior, and recovery from conflicts and errors.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents all six parameters well. The description reinforces key constraints around sessionToken, expectedRevision, and requestId, but adds little semantic meaning beyond what the schema descriptions already provide.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly names the action as accepting a group request and ties it to the reviewed group revision. It is specific enough to distinguish from related tools like decline_group_request or accept_group_invite, though it does not explicitly contrast those siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states when to use the tool ('the player explicitly confirms this group action') and when not to use it ('replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty'). It also directs reconciliation to horizon_get_groups and horizon_get_group_pending.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_adjust_itemAdjust Item PropertiesADestructiveIdempotent
Adjusts Item Properties using the reviewed inventory revision. Use when: the player explicitly requests this inventory action. Not for: automatic retries, client grants, changing instance IDs or revisions to force an uncertain action through. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. An exact reviewed inventory revision and instance UUID. Side effects: Applies all configured deltas atomically. Archived templates and properties without a rule cannot be adjusted. One HTTP attempt only. Returns: Complete {userId,revision,instances,limits,serverTime} inventory. Replace only the matching host/project/player cache. Instances carry server-generated UUIDs, properties, equipped and createdAt. Errors: 409 REVISION_CONFLICT or an uncertain response: use horizon_get_items and reconcile intent, never silently substitute a new revision and repeat. 404 ITEM_NOT_FOUND means this instance no longer exists. 422 ITEM_PROPERTY_NOT_ALLOWED/ITEM_PROPERTY_LIMIT_REACHED rejects the entire adjustment. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player UUID matching the session | |
| changes | Yes | Up to eight distinct nonzero deltas; current server rules and final 256-byte size still apply | |
| instanceId | Yes | Exact owned item instance UUID from the reviewed inventory | |
| sessionToken | Yes | Player accessToken sent only as Authorization Bearer | |
| expectedRevision | Yes | Exact reviewed revision; never refresh and substitute automatically |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the annotations: atomic delta application, archived templates and rule-less properties being unadjustable, a single HTTP attempt only, cache replacement scoped to the matching host/project/player, and a full error taxonomy (409/404/422/401/403/429) with required remediation for each. This is exactly the behavioral context a destructive mutation needs on top of destructiveHint/idempotentHint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) make it scannable and the purpose is front-loaded. The error enumeration is long and slightly repetitive (401 and 429 are explained in two places), which is the only real waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, revision-guarded mutation with no output schema, it covers everything an agent needs: auth chain, atomicity, return shape ({userId,revision,instances,limits,serverTime}), cache handling, and failure semantics. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description earns more by explaining what the parameters mean operationally: expectedRevision is the exact reviewed revision that must not be silently substituted, sessionToken is the accessToken from sign-in, and changes are deltas subject to server rules and archived-template restrictions. It does not document the per-key format or the 8-item cap, but the schema already carries those.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Adjusts Item Properties') plus the scoping constraint that it operates against a reviewed inventory revision, which separates it from catalogue/equip/discard siblings by implication. It never names an adjacent sibling (e.g. horizon_equip_item, horizon_discard_item) explicitly, so the differentiation is inferred rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit 'Use when' trigger (player explicitly requests this inventory action), an explicit 'Not for' exclusion list (automatic retries, client grants, forcing IDs/revisions), and names the concrete alternative path on conflict: horizon_get_items plus reconciliation. It also names the prerequisite sign-in tools (horizon_signin_email / horizon_signin_anonymous) and how to feed their accessToken in.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_adjust_player_valueAdjust Player ValueADestructiveIdempotent
Adjusts one player value within explicitly enabled project rules and per-call and daily limits. Use when: the configured game permits a direct value adjustment; use horizon_get_player_values to inspect the result. Not for: trusted rewards or arbitrary grants; client adjustment is disabled by default. Purchases use horizon_purchase_player_value_offer. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. This definition must enable adjustment. Side effects: Applies the signed amount once per operationId. The minimal guard binds the original reason/payload hash without copying the reason. Never creates an ID or retries automatically. Returns: Current state with replayed/alreadyApplied. Fresh success includes its delta; replay has empty applied/items. Errors: ADJUST_NOT_ALLOWED or ADJUST_ABOVE_LIMIT: change the game flow or project rules. 409 STATE_CONFLICT: refresh state and retry the SAME operation ID and payload. OPERATION_CONFLICT: do not reuse an ID for a different action. OPERATION_EXPIRED: reconcile state/history; never silently generate another ID. INSUFFICIENT_BALANCE, MAX_BALANCE_REACHED or DAILY_LIMIT_REACHED leaves the whole operation unapplied. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | Configured value or offer key, 1 to 24 lowercase letters, digits, '.', '_' or '-' | |
| amount | Yes | Nonzero signed safe integer delta; limited by the project rules | |
| reason | Yes | Nonblank audit reason, at most 200 UTF-8 bytes | |
| userId | Yes | Player UUID belonging to the selected project and player session | |
| operationId | Yes | Stable operation ID: server-aligned Unix milliseconds + ':' + UUID. Persist before sending; reuse unchanged on timeout or retry | |
| sessionToken | Yes | Player accessToken from sign-in, sent only in the Authorization Bearer header |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare mutation, open-world, idempotent, and destructive behavior, and the description goes well beyond them by explaining operationId replay semantics, no automatic ID creation or retries, full side effects, auth requirements, return states, and specific error meanings. Nothing contradicts the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well front-loaded and explicitly structured with Use when / Not for / Requires / Side effects / Returns / Errors. The density is justified by the mutation, auth, idempotency, and error-handling complexity, though it is close to overloaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the lack of an output schema and the tool's destructive/idempotent nature, the description supplies the missing operational context: return shape, replay states, error recovery instructions, auth prerequisites, and rate-limit behavior. An agent has enough information to invoke and recover correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the per-field descriptions already carry most parameter semantics. The tool description adds useful operational meaning beyond the schema, particularly around operationId idempotent replay, signed amount application, and reason/payload guard behavior.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Adjusts one player value') plus scope constraints (enabled project rules, per-call and daily limits). It explicitly distinguishes itself from horizon_get_player_values and horizon_purchase_player_value_offer, so an agent can route without inferring from sibling names.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit 'Use when', 'Not for', and alternative-tool guidance, including the purchase alternative and inspection sibling. It also states the prerequisite that adjustment must be enabled and the authentication flow needed before calling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_advance_match_timeoutAdvance Match TimeoutADestructiveIdempotent
Executes advance match timeout under the exact original revision. Use when: explicit asynchronous multiplayer actions after reading horizon://docs/matches. Not for: automatic polling, page traversal, timeout progression, invented winners or automatic rewards. Reconcile with horizon_get_matches and horizon_get_match. Consent and game consensus do not validate honest gameplay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt. Start requires the creator and every joined UUID exactly once. Turn requires the current unexpired actor. Timeout advances only one turn. Active leave forfeits without selecting a winner. Lobby cancel is creator-only. Full Inbox retains a durable notice without undoing a committed move. Returns: {match,pollAfterSeconds,serverTime}; departing lobby actors receive metadata only and lose point-read access. Errors: 404 hides private/missing/expired matches. 409 REVISION_CONFLICT or STATE_CONFLICT: explicitly reread and reconcile the original intent, never replace the revision or automatically resubmit. RESULT_CONFLICT preserves the original report. RUN_EXPIRED/RUN_ALREADY_USED never allow replacement ranked runs. 501 FEATURE_NOT_SUPPORTED is explicit for simpleServer ranked mode. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the session and project | |
| matchId | Yes | Original server match UUID in the selected project | |
| sessionToken | Yes | Player accessToken sent only as Bearer | |
| expectedRevision | Yes | Original reviewed revision; never substitute a newer revision after an uncertain write |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations, it discloses one HTTP attempt, auth/session requirements, revision-conflict handling, side effects, return fields, rate limits, and error semantics. This is exactly the kind of behavioral context an agent needs for a destructive open-world mutation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is well organized with front-loaded Use/Not for/Requires/Side effects/Returns/Errors sections. But it is long and includes start, turn, leave, cancel, and Inbox side effects that do not obviously belong to advancing a match timeout, so not every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive open-world mutation with no output schema, it covers auth, return shape, conflicts, rate limits, and key failure modes. The agent has enough to call correctly, even if scope wording could be tighter.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds useful semantics for sessionToken (pass accessToken as Bearer) and expectedRevision (original reviewed revision, never substitute), though matchId remains schema-only.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence names a specific operation and revision constraint: execute an advance match timeout under the original revision. However, it does not clearly differentiate this tool from siblings like horizon_start_match, horizon_submit_match_turn, or horizon_leave_match, and later sentences mention those sibling behaviors, muddying scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit 'Use when' and 'Not for' conditions and points to horizon_get_matches and horizon_get_match for reconciliation. The exclusion of automatic polling and the auth setup are concrete guidance for selecting and invoking the tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_block_playerBlock PlayerADestructiveIdempotent
Blocks Player using the reviewed player revision. Use when: the player explicitly requests this social action. Not for: automatic retries after timeout, automatic acceptance of crossed requests or changing expectedRevision without reconciling intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. A current snapshot revision. Side effects: Adds your block and removes friendship and both request directions atomically. Does not notify the blocked party. No automatic retry. Repeating the same revision cannot create a second effect. Returns: Complete {userId,revision,friendCode,friends,incoming,outgoing,blocked,limits,serverTime} snapshot. Replace the matching host/project/player cache. lastActiveAt is the latest retained login, null when unknown; it is not online presence. Errors: 409 REVISION_CONFLICT or an uncertain response: get a new snapshot and reconcile intent, never silently replace expectedRevision and repeat. 404 FRIEND_REQUEST_NOT_FOUND means this request was removed or replaced; do not act on a newer ID. INBOX_FULL rejects the entire send/accept. Friend/request/block capacity limits reject additions while existing data remains removable. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player UUID matching the session | |
| sessionToken | Yes | Player accessToken sent only as Authorization Bearer | |
| targetUserId | Yes | The other player UUID in the same project | |
| expectedRevision | Yes | Exact revision from the reviewed actor snapshot; never refresh and substitute automatically |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: atomic removal of friendship and both request directions, no notification to the blocked party, no automatic retry, and idempotency keyed to the revision. It also documents auth requirements, cache replacement, and specific error semantics (409, 404, INBOX_FULL, 401, 403, 429), which is exactly the behavioral detail needed for a destructive mutation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and organized into labeled sections (Use when, Not for, Requires, Side effects, Returns, Errors), so it is easy to scan. It is dense and long, but most sentences carry operational value for a destructive, idempotent mutation; a few error details could be trimmed without losing meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even without an output schema, the description specifies the returned snapshot shape and instructs the caller to replace the matching cache. It also covers auth, side effects, idempotency, and error recovery, leaving nothing critical for an agent to infer before invoking the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: sessionToken must be the accessToken from horizon_signin_email or horizon_signin_anonymous, and expectedRevision must come from a reviewed snapshot and never be silently replaced. The 409 guidance reinforces how expectedRevision is intended to be used.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Blocks Player') and adds scope ('using the reviewed player revision'), so the action is unambiguous. It does not explicitly contrast with the sibling horizon_unblock_player, but the name and description make the distinction clear enough without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names the triggering condition ('the player explicitly requests this social action') and enumerates exclusions: no automatic retries after timeout, no automatic acceptance of crossed requests, and no silent expectedRevision changes. This is a textbook when/when-not section with no inference required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_buy_marketplace_listingBuy Original Marketplace ItemADestructiveIdempotent
Purchases the exact listing under its original revision, currency and price. Use when: explicit marketplace actions after reading horizon://docs/marketplace. Not for: automatic trading, price polling or generated replacement operations. Use horizon_get_marketplace_operation to reconcile the original intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt. Atomic buyer debit, seller net credit, fee and original item transfer. Persist the original intent before sending. Competing buyers cannot both settle. Returns: {receipt,listing,replayed,serverTime} Errors: 409 conflicts require explicit reconciliation, never fresh revisions or operation IDs on an unknown outcome. Missing OPERATION_NOT_FOUND does not prove nonexecution. 422 capacity/balance/daily-limit errors preserve atomicity. 429 schedules no retry. Full Inbox returns pending without losing the original item. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the current session and project | |
| issuedAt | Yes | Original canonical timestamp including .SSSZ; never replace issuedAt on retry | |
| listingId | Yes | Original canonical lowercase UUID | |
| operationId | Yes | Persisted original operation UUID, never replaced after uncertainty | |
| sessionToken | Yes | Current accessToken sent only as Bearer | |
| expectedPrice | Yes | Original positive safe-integer price in the configured currency | |
| expectedCurrencyKey | Yes | Exact currency key from the saved Player Values configuration | |
| expectedListingRevision | Yes | Exact original safe-integer revision; never refresh-and-retry a mutation |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the destructive/idempotent/open-world profile, but the description goes well beyond them: it discloses that settlement is atomic (buyer debit, seller credit, fee, item transfer), that competing buyers cannot both settle, that the original intent must be persisted before sending, and it gives a concrete returns shape plus per-status-code error semantics (409, 422, 429, 401, 403, OPERATION_NOT_FOUND, full Inbox). The 401/403 guidance and the 'never fresh revisions or operation IDs on unknown outcome' rule are exactly the kind of context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded (purpose → when/not-for → requires → side effects → returns → errors) and nearly every line is actionable for a destructive purchase. Minor redundancy remains: 401 and 429 are each explained twice (in the error list and again in the closing failure paragraph), and 'Needs HORIZON_API_KEY' sits awkwardly inside the behavior text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an eight-required-parameter, destructive, no-output-schema tool, this covers the gaps that matter: auth acquisition, atomicity and concurrency guarantees, replay/retry discipline on unknown outcomes, return shape, and per-status error handling. An agent has everything needed to call it safely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline would be 3, but the description adds real meaning: it tells the agent to obtain sessionToken from horizon_signin_email/anonymous and pass it as userId-matched Bearer, and it explains that revision, price and currency must be the *original* values held across retries, which reinforces the schema's 'never replace' notes with a coherent story.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with precision: 'Purchases the exact listing under its original revision, currency and price.' It also draws a boundary against automatic trading and price polling, and names horizon_get_marketplace_operation as the reconciliation sibling, so an agent can distinguish it from the other marketplace tools without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (explicit marketplace actions after reading horizon://docs/marketplace) and 'Not for' (automatic trading, price polling, generated replacement operations), plus a named alternative for the reconciliation case. This is the full when/when-not/alternative triad.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_cancel_emailCancel EmailADestructiveIdempotent
Cancels a queued email that is still pending (sent now or scheduled) so it is never delivered. Use when: a scheduled email is no longer wanted, for example the player already came back. Not for: emails that are already processing or sent (they cannot be recalled); check with horizon_get_email_status first when unsure. Requires: the emailId from horizon_send_email, sent with the same API key. Side effects: the email is never sent and cannot be restored; to send it later, call horizon_send_email again. Returns: {message: 'Email cancelled'}. Errors: An email that is not pending (already processing, sent, failed or cancelled) or belongs to another API key is rejected: read its state with horizon_get_email_status. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| emailId | Yes | Email ID (UUID) returned by horizon_send_email |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, but the description adds substantial value beyond them: irreversibility ('cannot be restored'), the same-API-key constraint, required HORIZON_API_KEY, error semantics (isError with HTTP status/body), and specific 401/429 meanings including rate limiting. This is rich behavioral context layered on top of the structured hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded with a labeled Use when / Not for / Requires / Side effects / Returns / Errors structure that scans cleanly. Slightly verbose: horizon_get_email_status and HORIZON_API_KEY are each referenced twice, and the error paragraph is dense, costing some tightness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description supplies the return value ({message: 'Email cancelled'}), error behavior, prerequisites, and side effects. An agent has everything needed to call it correctly and interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and documents emailId, so the baseline is 3. The description adds useful provenance — the emailId comes from horizon_send_email and must be sent with the same API key — which meaningfully constrains correct invocation beyond the schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb and resource ('cancels a queued email') plus the crucial scope qualifier ('still pending... so it is never delivered'). This clearly distinguishes it from horizon_send_email and horizon_get_email_status among the large sibling set.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (scheduled email no longer wanted), 'Not for' (already processing/sent, cannot be recalled), and a named alternative ('check with horizon_get_email_status first when unsure'). The when/when-not routing is fully spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_cancel_friend_requestCancel Friend RequestADestructiveIdempotent
Cancels Friend Request using the reviewed player revision. Use when: the player explicitly requests this social action. Not for: automatic retries after timeout, automatic acceptance of crossed requests or changing expectedRevision without reconciling intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. A current snapshot revision and its exact requestId. Side effects: Removes only this exact outgoing request and the matching recipient incoming record. No automatic retry. Repeating the same revision cannot create a second effect. Returns: Complete {userId,revision,friendCode,friends,incoming,outgoing,blocked,limits,serverTime} snapshot. Replace the matching host/project/player cache. lastActiveAt is the latest retained login, null when unknown; it is not online presence. Errors: 409 REVISION_CONFLICT or an uncertain response: get a new snapshot and reconcile intent, never silently replace expectedRevision and repeat. 404 FRIEND_REQUEST_NOT_FOUND means this request was removed or replaced; do not act on a newer ID. INBOX_FULL rejects the entire send/accept. Friend/request/block capacity limits reject additions while existing data remains removable. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player UUID matching the session | |
| requestId | Yes | Exact request ID from the reviewed incoming/outgoing snapshot | |
| sessionToken | Yes | Player accessToken sent only as Authorization Bearer | |
| targetUserId | Yes | The other player UUID in the same project | |
| expectedRevision | Yes | Exact revision from the reviewed actor snapshot; never refresh and substitute automatically |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructive=true and idempotent=true, but the description adds the concrete mechanics: exactly which records are removed, that repetition cannot double-effect, that the returned snapshot should replace the cache, and the lastActiveAt semantics. It also documents auth requirements, error taxonomy (409, 404, INBOX_FULL, 401, 403, 429), and rate limiting — far beyond what the annotations supply.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action, then organized into labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors). It is long but largely earns the length for a destructive, revision-guarded mutation; some error prose (e.g. HORIZON_API_KEY, 429 rate-limit explanation) could be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, but the description fully specifies the returned snapshot shape, cache-replacement guidance, and the failure surface. For a five-parameter destructive social action, an agent has everything needed to call it correctly and recover from conflicts.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds relational meaning: sessionToken comes from horizon_signin_email/anonymous, expectedRevision must come from a reviewed snapshot and not be auto-substituted, and requestId must be the exact reviewed ID. It does not explain format details, but it meaningfully clarifies how to source these values.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Cancels Friend Request') and the exact object acted on ('this exact outgoing request'), which distinguishes it from horizon_decline_friend_request (incoming) and horizon_remove_friend (established friendship). The side-effects sentence makes the scope unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit 'Use when' and 'Not for' clauses, including concrete exclusions such as automatic retries after timeout and silently swapping expectedRevision. The alternative behaviors (snapshot + reconcile) are named, so the agent knows what to do instead of calling this tool blindly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_cancel_group_invitecancel group inviteADestructiveIdempotent
Applies the explicit cancel group invite action using the reviewed group revision. Use when: the player explicitly confirms this group action. Not for: replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Current group revision and the exact pending requestId where applicable. Side effects: Leader/officer cancels this exact invitation. No automatic retry. Same-revision replay cannot create a second effect. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| requestId | Yes | Exact pending identity from the reviewed snapshot | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| targetUserId | Yes | Other player in this project | |
| expectedRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial context beyond the annotations: it names the required sign-in flow (horizon_signin_email / horizon_signin_anonymous → sessionToken), the exact side effect (leader/officer cancels this invitation), the no-auto-retry policy, the idempotency mechanism (same-revision replay cannot create a second effect), and cache invalidation scope. Error semantics (409 REVISION_CONFLICT, REQUEST_NOT_FOUND, INBOX_FULL rollback, 403 role/block, 429 rate limit, 401/403 session cases) are all disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the action, then when/when-not, requirements, side effects, returns, and errors in a sensible order. However it bloats: the final sentence re-explains the 401 and 429 meanings already given in the preceding error block, and the returns/cache sentence is compressed past readability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, open-world, six-required-parameter mutation with no output schema, the description covers auth sourcing, side effects, return shape, cache replacement scope, and the full failure/reconciliation protocol. Nothing material needed to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3; the description earns above that by explaining the semantics of expectedRevision and requestId in relation to error codes (revision conflicts, REQUEST_NOT_FOUND meaning the request was removed/replaced) rather than just restating field types.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('cancel group invite action using the reviewed group revision') and clarifies the actor ('Leader/officer cancels this exact invitation'). It does not, however, disambiguate from the closest siblings — horizon_decline_group_invite and horizon_cancel_group_request — so an agent must infer which cancel path applies.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when: the player explicitly confirms this group action' plus a 'Not for' clause excluding revision replacement, block bypass, and automatic retry. It also routes to horizon_get_groups and horizon_get_group_pending for reconciliation, but never explains why to pick this over decline/cancel_request siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_cancel_group_requestcancel group requestADestructiveIdempotent
Applies the explicit cancel group request action using the reviewed group revision. Use when: the player explicitly confirms this group action. Not for: replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Current group revision and the exact pending requestId where applicable. Side effects: Cancels your exact join request. No automatic retry. Same-revision replay cannot create a second effect. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| requestId | Yes | Exact pending identity from the reviewed snapshot | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| expectedRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructive/idempotent, but the description goes well beyond them: it specifies that same-revision replay cannot create a second effect, that there is no automatic retry, that INBOX_FULL rolls back the entire action, and how 409/REQUEST_NOT_FOUND/403/429/401 each behave. Session sourcing (signin tools, accessToken as sessionToken) and the HORIZON_API_KEY dependency are also disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is well front-loaded and sectioned (Use when / Not for / Requires / Side effects / Returns / Errors), but the Errors block is bloated, restating 401 and 403 twice with overlapping explanations of token ownership and API-key failure. Several lines could be merged without losing guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description supplies the return shape ({groups:MyGroupsView, group:GroupView|null}) and its cache implications, so an agent knows what state changes after the call. Combined with the error/reconciliation guidance, nothing needed to invoke this destructive mutation correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description nevertheless adds real meaning by explaining where sessionToken comes from and warning that expectedRevision and requestId must come from the reviewed snapshot and never be refreshed after an uncertain response. It does not elaborate on userId/groupId beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The side-effects line ('Cancels your exact join request') makes the resource and the actor precise: the player withdrawing their own pending join request, not a leader declining someone else's. The opening sentence ('Applies the explicit cancel group request action') is close to a restatement of the name, and no sibling such as horizon_decline_group_request or horizon_cancel_group_invite is named to sharpen the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It uses explicit 'Use when' / 'Not for' framing, and the exclusions (don't replace reviewed revisions or requestIds, don't bypass a leader's block, don't auto-retry) are concrete and actionable. The positive trigger ('the player explicitly confirms this group action') is generic, though, and does not tell the agent when to pick this over declining or cancelling an invite.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_cancel_marketplace_listingCancel Own Marketplace ListingADestructiveIdempotent
Cancels the original listing revision into a protected pending item return. Use when: explicit marketplace actions after reading horizon://docs/marketplace. Not for: automatic trading, price polling or generated replacement operations. Use horizon_get_marketplace_operation to reconcile the original intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt with the persisted original UUID/time/revision. Cancel and receipt replay remain available while trading is disabled. Claim through Inbox, never mint a replacement item. Returns: {receipt,listing,replayed,serverTime} Errors: 409 conflicts require explicit reconciliation, never fresh revisions or operation IDs on an unknown outcome. Missing OPERATION_NOT_FOUND does not prove nonexecution. 422 capacity/balance/daily-limit errors preserve atomicity. 429 schedules no retry. Full Inbox returns pending without losing the original item. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the current session and project | |
| issuedAt | Yes | Original canonical timestamp including .SSSZ; never replace issuedAt on retry | |
| listingId | Yes | Original canonical lowercase UUID | |
| operationId | Yes | Persisted original operation UUID, never replaced after uncertainty | |
| sessionToken | Yes | Current accessToken sent only as Bearer | |
| expectedListingRevision | Yes | Exact original safe-integer revision; never refresh-and-retry a mutation |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructive/open-world/idempotent, but the description adds real value: exactly one HTTP attempt with the persisted UUID/time/revision, cancel and receipt replay remaining available while trading is disabled, claim-through-Inbox rather than minting a replacement, and itemized 409/422/429/401/403 error semantics with atomicity guarantees. Minor deduction because the 401 guidance is ambiguous — it is attributed both to a missing/expired session and to a wrong HORIZON_API_KEY, which could send an agent down the wrong recovery path.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) with the core action front-loaded make a long description scannable. It is somewhat over-stuffed — the error block runs many sentences and repeats the 401 case twice with different causes — so a portion of the text does not fully earn its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive six-required-parameter mutation with no output schema, the description covers authentication path, side effects, return shape, and failure modes. Everything an agent needs to call it safely and interpret failures is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description earns an extra point by explaining where sessionToken comes from (sign in via horizon_signin_email or horizon_signin_anonymous and pass the accessToken) and by framing operationId/issuedAt/listingId/expectedListingRevision as the persisted original values that must never be regenerated on retry.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — cancels the original listing revision into a protected pending item return — which is far more precise than the title alone. It distinguishes itself from adjacent siblings by naming horizon_get_marketplace_operation and by excluding automatic trading, polling, and generated replacement operations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (explicit marketplace actions after reading horizon://docs/marketplace) and 'Not for' (automatic trading, price polling, generated replacements), plus a named alternative for reconciliation. An agent can route correctly without reading any other definition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_cancel_matchCancel Match LobbyADestructiveIdempotent
Executes cancel match lobby under the exact original revision. Use when: explicit asynchronous multiplayer actions after reading horizon://docs/matches. Not for: automatic polling, page traversal, timeout progression, invented winners or automatic rewards. Reconcile with horizon_get_matches and horizon_get_match. Consent and game consensus do not validate honest gameplay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt. Start requires the creator and every joined UUID exactly once. Turn requires the current unexpired actor. Timeout advances only one turn. Active leave forfeits without selecting a winner. Lobby cancel is creator-only. Full Inbox retains a durable notice without undoing a committed move. Returns: {match,pollAfterSeconds,serverTime}; departing lobby actors receive metadata only and lose point-read access. Errors: 404 hides private/missing/expired matches. 409 REVISION_CONFLICT or STATE_CONFLICT: explicitly reread and reconcile the original intent, never replace the revision or automatically resubmit. RESULT_CONFLICT preserves the original report. RUN_EXPIRED/RUN_ALREADY_USED never allow replacement ranked runs. 501 FEATURE_NOT_SUPPORTED is explicit for simpleServer ranked mode. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the session and project | |
| matchId | Yes | Original server match UUID in the selected project | |
| sessionToken | Yes | Player accessToken sent only as Bearer | |
| expectedRevision | Yes | Original reviewed revision; never substitute a newer revision after an uncertain write |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, idempotentHint=true, openWorldHint=true, and readOnlyHint=false. The description adds meaningful behavioral context: sign-in requirements, creator-only lobby cancellation, one HTTP attempt, point-read access loss for departing actors, and detailed error semantics. However, it also includes side-effect rules for unrelated operations (start, turn, timeout, active leave), which muddies the transparency for this specific tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with a clear purpose sentence and uses labeled sections, but it is bloated with rules that apply to other tools, such as 'Start requires the creator and every joined UUID exactly once' and 'Turn requires the current unexpired actor.' Those sentences do not earn their place in a description for canceling a match lobby.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive mutation with no output schema, the description covers authentication, side effects, return shape, and error handling in detail. It is nearly complete for an agent to invoke correctly, with the main weakness being the extra unrelated match-operation rules rather than missing information.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all four parameters. The description nonetheless adds valuable semantics: it explains how sessionToken is obtained from horizon_signin_email or horizon_signin_anonymous, and it stresses that expectedRevision must be the exact original revision and never substituted after an uncertain write.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Executes cancel match lobby under the exact original revision.' It also distinguishes this action from siblings by noting 'Lobby cancel is creator-only' versus 'Active leave forfeits,' so an agent can tell it apart from horizon_leave_match without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides an explicit 'Use when' section and a 'Not for' list, which is more than most definitions offer. It also names horizon_get_matches and horizon_get_match for reconciliation, though it stops short of directly saying when to choose this over horizon_leave_match.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_check_authCheck AuthenticationAIdempotent
Checks whether a player's session token (accessToken) is still valid for the given user. Use when: before a session tool when the token may have expired, or when a game resumes, to decide whether the player must sign in again. Not for: testing the API key or base URL (use horizon_test_connection) or getting a new token (use horizon_signin_email or horizon_signin_anonymous). Requires: userId and the accessToken from horizon_signin_email or horizon_signin_anonymous. Side effects: a valid check refreshes the session's one hour idle timeout; nothing else changes. Returns: {userId, isAuthenticated, authStatus, message}. An invalid or expired token is not an HTTP error: isAuthenticated is false, so sign in again with horizon_signin_*. Errors: 400 for a malformed userId or token: pass the values from the sign-in result. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Player user ID (UUID) from the result of horizon_signup_* or horizon_signin_* | |
| sessionToken | Yes | accessToken from horizon_signin_email or horizon_signin_anonymous (max 256 characters) |
Output Schema
| Name | Required | Description |
|---|---|---|
| userId | No | |
| message | No | |
| authStatus | No | |
| isAuthenticated | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=false and idempotentHint=true; the description supplies the reason — a valid check refreshes the one-hour idle timeout and nothing else changes — which is exactly the non-obvious behavior the hint implies. It further discloses that an invalid token is NOT an HTTP error (isAuthenticated=false), the API-key requirement, the 429 rate-limit meaning, and the isError contract on failures.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but well-labeled (Use when / Not for / Requires / Side effects / Returns / Errors) with the core purpose front-loaded. Slightly over-long: the recover-by-signing-in guidance appears twice (under Returns and implicitly under Not for), and the Returns detail overlaps the output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter authenticated check, the description covers trigger, alternatives, prerequisites, side effects, success shape, and the full error taxonomy — more than enough even though an output schema already exists. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents both parameters, but the description adds real meaning by naming the origin of each value (userId from signup/signin, token from horizon_signin_*) and explaining that a 400 means malformed input. Minor friction: the prose calls the token 'accessToken' while the schema property is 'sessionToken', resolving the synonym is left to the schema's own description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (checks) and resource (a player's session token validity for a userId) up front, and explicitly differentiates itself from siblings like horizon_test_connection and horizon_signin_*. An agent can identify the tool's role without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides an explicit 'Use when' trigger (before session tools when a token may have expired, or on game resume) and an explicit 'Not for' with named alternatives for both excluded cases. Nothing about tool selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_claim_inboxClaim Inbox RewardADestructiveIdempotent
Claims an inbox reward once for the authenticated player. Use when: an explicit player action on an entry returned by horizon_get_inbox. Not for: changing the recipient or inventing attachment amounts. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Atomically marks the entry claimed and grants its configured values or restores its exact escrowed original item once. No automatic retries or new action IDs. Overdue unclaimed rewards remain claimable. Returns: {entryId,replayed,inbox,playerValues,items}. Replace the value cache with playerValues; item references are receipts, never instructions to mint an item. Explicitly refresh inventory after a claim. Never apply a reward delta again. Errors: 409 STATE_CONFLICT: retry the same entry ID. UNCLAIMED_REWARD: claim before removal. MAX_BALANCE_REACHED/DAILY_LIMIT_REACHED/INVENTORY_FULL leaves the reward or original item unclaimed. ENTRY_NOT_FOUND after removal/cleanup never grants again. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Player UUID belonging to the selected project and player session | |
| entryId | Yes | Exact stable entry ID from the inbox snapshot, including message: or broadcast: prefix | |
| sessionToken | Yes | Player accessToken, sent only as Authorization Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Although annotations already declare destructive, idempotent, and open-world behavior, the description adds substantial context: atomic claim marking, one-time grant or exact item restoration, no automatic retries or new action IDs, overdue rewards remaining claimable, required inventory refresh, and detailed error handling. These details do not contradict the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well structured with labels for use cases, exclusions, requirements, side effects, returns, and errors. Given the high-stakes claim operation and broad error surface, every section adds useful information rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, but the description supplies the return shape and meaning of key fields, including replayed and playerValues. It also covers auth prerequisites, side effects, post-claim inventory refresh, and failure modes, making it complete enough for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents the three parameters, but the description adds meaningful auth semantics: sessionToken must be the accessToken from sign-in, userId must match the session token, and entryId should come from the inbox snapshot. It does not add much beyond the schema for entryId format, but the session/user relationship is useful.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource: "Claims an inbox reward once for the authenticated player." It also distinguishes this from related inbox operations by naming horizon_get_inbox as the source of the entry and explicitly excluding recipient changes or invented attachment amounts.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit "Use when" and "Not for" guidance, states the prerequisite auth flow via horizon_signin_email or horizon_signin_anonymous, and ties the call to an explicit player action on an entry returned by horizon_get_inbox. Alternatives and exclusions are clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_create_crash_reportCreate Crash ReportA
Submits one crash (CRASH), caught exception (NON_FATAL) or freeze (ANR) with device data to horizOn Crash Reporting, grouped by fingerprint. Use when: the game crashed (send on next start) or caught an exception worth tracking. Not for: technical events without a crash (use horizon_create_log) and messages written by players (use horizon_submit_feedback). Requires: a sessionId registered with horizon_create_crash_session for this app run; userId is optional. Side effects: adds one report per call (a repeat adds a duplicate) and marks the session as crashed. Reports with the same fingerprint form one group; a group marked resolved becomes REGRESSED when a newer app version crashes again. Returns: {id, groupId, createdAt}; groupId identifies the crash group in the dashboard. Errors: 400 when a required field is missing or too long: fix it and resend. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| os | Yes | OS details (e.g. 'Android 14', 'iOS 17.2') | |
| type | Yes | Crash type: CRASH (fatal), NON_FATAL (exception), or ANR (Application Not Responding) | |
| userId | No | Player user ID (UUID) from horizon_signup_* or horizon_signin_*, if a player is signed in | |
| message | Yes | Error or exception message (1 to 5000 characters) | |
| platform | Yes | Platform (e.g. 'Android', 'iOS', 'Windows') | |
| sessionId | Yes | The sessionId registered with horizon_create_crash_session for this app run (1 to 100 characters) | |
| appVersion | Yes | App version (e.g. '1.2.3') | |
| customKeys | No | String key to string value metadata such as level or build flavor (max 10 entries) | |
| sdkVersion | Yes | horizOn SDK version, for example '1.8.2' (1 to 50 characters) | |
| stackTrace | No | Full stack trace (max 20000 characters) | |
| breadcrumbs | No | Recent events before the crash, oldest first (max 50) | |
| deviceModel | Yes | Device model (e.g. 'Pixel 8', 'iPhone 15') | |
| fingerprint | Yes | Grouping key: reports with the same fingerprint form one crash group, for example a hash of exception type and top stack frame (1 to 128 characters) | |
| deviceMemoryMb | No | Device RAM in MB, for example 8192 |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (readOnlyHint=false, openWorldHint=true, idempotentHint=false): it discloses that each call adds a report and repeats create duplicates, that the session is marked crashed, that same-fingerprint reports form a group, and that resolved groups become REGRESSED on a newer version. It also documents auth (HORIZON_API_KEY), error behavior (400/401/429) and the isError contract.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then cleanly segmented into Use when / Not for / Requires / Side effects / Returns / Errors. Despite its length, every section carries distinct information, so nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 14-parameter, 9-required mutation with a nested breadcrumbs array and no output schema, the description supplies return shape ({id, groupId, createdAt}), grouping semantics, auth requirements, and error handling. An agent has everything needed to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all 14 parameters including fingerprint grouping and sessionId provenance. The description adds only marginal meaning (userId optional, sessionId must come from horizon_create_crash_session), so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Submits) and resource (a CRASH/NON_FATAL/ANR report with device data) plus the grouping model by fingerprint. It explicitly distinguishes itself from horizon_create_log and horizon_submit_feedback, so an agent can route correctly without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when', 'Not for', and 'Requires' sections. It names the two alternatives (horizon_create_log, horizon_submit_feedback) with the conditions that select them, and specifies the sessionId prerequisite from horizon_create_crash_session.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_create_crash_sessionCreate Crash SessionA
Registers one app run (session) so horizOn can calculate the crash-free session rate. Use when: once at every app start, with a new unique sessionId; keep that ID for horizon_create_crash_report. Not for: reporting the crash itself (use horizon_create_crash_report) or player sign-in sessions (those come from horizon_signin_*). Side effects: records one session per call; a later crash report with the same sessionId marks it as crashed. Returns: {status: 'ok'}. Errors: 400 when a field is missing or too long: fix it and resend. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | No | Player user ID (UUID) from horizon_signup_* or horizon_signin_*, if a player is signed in | |
| platform | Yes | Platform (e.g. 'Android', 'iOS', 'Windows') | |
| sessionId | Yes | New unique ID for this app run, for example a UUID generated at start (1 to 100 characters) | |
| appVersion | Yes | App version (e.g. '1.2.3') |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, it discloses the side effect (one session recorded per call; a later crash report with the same sessionId marks it crashed), the return value, and a full error taxonomy: 400 validation, HORIZON_API_KEY requirement, 401 vs horizon_test_connection, and 429 per-minute rate limiting with retry guidance.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Labeled sections (Use when / Not for / Side effects / Returns / Errors) make it skimmable, and the core purpose leads. Every sentence carries operational information; nothing is padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description supplies the return shape, the safety-relevant side effect, cross-tool ID reuse, and the error contract, which is more than enough for a 4-parameter ingest call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds lifecycle meaning the schema lacks: sessionId must be new and unique per run and must be kept for horizon_create_crash_report. It does not add much about userId, platform, or appVersion beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Registers one app run (session)') plus the downstream purpose ('so horizOn can calculate the crash-free session rate'). It distinguishes itself from horizon_create_crash_report and the horizon_signin_* family without the reader needing to open a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (once at every app start, with a new unique sessionId) and 'Not for' clauses that name the correct alternatives (horizon_create_crash_report for the crash itself, horizon_signin_* for player sessions). It even states the caller must retain the sessionId for the later report call.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_create_groupCreate GroupAIdempotent
Creates a fresh server-identified group and its leader atomically. Use when: the player explicitly confirms the group settings. Not for: choosing/reusing a group ID or resending uncertain writes with a new revision. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. The current MyGroupsView revision. Side effects: Creates one group and membership within both limits. The retained player revision prevents duplicate creation on replay. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| data | Yes | Required finite JSON object; current maxDataBytes/maxDataDepth are server policies. Client JSON bytes can differ from stored dataJson after number normalization; the server validates the complete stored representation. No default2048-byte/depth16 clamp. Only members/admins can read it. | |
| name | Yes | Nonblank display name under current maxNameBytes; server enforces the complete BSON envelope | |
| userId | Yes | Signed-in player matching the Bearer session | |
| joinMode | Yes | Whether players join directly, request admission or need an invitation | |
| description | Yes | Public description under current maxDescriptionBytes | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| expectedPlayerRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: requires prior sign-in via horizon_signin_email/anonymous and passing accessToken as sessionToken, explains that the retained player revision prevents duplicate creation on replay (consistent with idempotentHint), specifies that INBOX_FULL rolls back the entire action, that 403 covers bilateral block violations, and that 429 must not be auto-retried. This is exactly the extra context annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded with labelled Use when / Not for / Requires / Side effects / Returns / Errors sections. It is on the long side and repeats the 'never refresh the revision and repeat automatically' instruction twice (in the Not-for line and the Errors block), which is redundant rather than harmful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates by documenting the return shape ({groups, group}), the null-group case after leave/delete, the privacy boundary on private state, and which cache entries to replace. For a mutating, 7-param, nested-object tool, nothing an agent needs to call it safely is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description adds a small amount of genuine value: it names where expectedPlayerRevision comes from (the current MyGroupsView revision) and clarifies that userId must match the signed-in Bearer session. It does not elaborate on joinMode or data, which the schema handles.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Creates a fresh server-identified group and its leader atomically') and the atomicity constraint distinguishes it from horizon_update_group and horizon_join_group. An agent knows exactly what this call produces without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (player confirms group settings) and 'Not for' (choosing/reusing a group ID, resending uncertain writes with a new revision) sections, plus named alternatives (horizon_get_groups, horizon_get_group_pending) for reconciliation. This routing guidance is unusually complete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_create_logCreate LogA
Writes one server-side log entry (INFO, WARN or ERROR) for a player, visible in the horizOn dashboard's user logs. Use when: the game records a technical event or a handled error for later debugging, for example a failed purchase or a slow load. Not for: crashes and exceptions with a stack trace (use horizon_create_crash_report) or messages written by players (use horizon_submit_feedback). Requires: a userId from horizon_signup_* or horizon_signin_* and the BASIC tier or higher; no session token. Side effects: creates one log entry per call; a repeat creates a duplicate. Returns: {id, createdAt} of the new entry. Errors: 403 on the FREE tier: logs need BASIC or higher, so upgrade or skip logging. 400 for an invalid userId: pass the ID from the sign-in result. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| type | Yes | Log level: INFO, WARN or ERROR | |
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* | |
| message | Yes | Log message (max 1000 characters) | |
| errorCode | No | Optional code to group entries in the dashboard, useful with ERROR, for example 'IAP_TIMEOUT' (max 50 characters) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this as a non-idempotent, non-destructive write, and the description adds substantial context beyond that: one entry created per call with duplicates on repeat, the exact return shape ({id, createdAt}), tier-gated 403 behavior, 400 for bad userId, 401 API-key mismatch, and 429 per-minute rate limiting with a retry recommendation. It is fully consistent with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action and uses clear labeled sections (Use when, Not for, Requires, Side effects, Returns, Errors) that make scanning easy. Some content is redundant, such as restating the BASIC-tier requirement in the 403 error note, which slightly dilutes an otherwise tight structure.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a four-parameter write tool with no output schema, the description covers purpose, routing to siblings, auth requirements, side effects, return shape, and the expected error modes. An agent has everything needed to invoke it correctly and interpret failures without opening other resources.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all four parameters already have in-schema documentation (type enum, userId UUID source, message max length, errorCode grouping). The description restates the userId source and INFO/WARN/ERROR levels but adds no syntax or format detail beyond the schema, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Writes one server-side log entry ... for a player') and pins the scope to the horizOn dashboard. It explicitly distinguishes itself from the two nearest siblings by naming horizon_create_crash_report and horizon_submit_feedback as different use cases.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Has explicit 'Use when' and 'Not for' clauses, and the exclusion names the correct alternative tool for each case (crash report with stack trace, player-written feedback). Prerequisites (userId source, BASIC tier, no session token) are also stated, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_create_marketplace_listingEscrow Original Item for SaleADestructiveIdempotent
Lists one original unequipped item at the explicitly approved price and fee configuration. Use when: explicit marketplace actions after reading horizon://docs/marketplace. Not for: automatic trading, price polling or generated replacement operations. Use horizon_get_marketplace_operation to reconcile the original intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt. Persist all original fields before sending under project/player/feature. Atomically removes the exact inventory instance into escrow. Never recalculate revisions after a lost response. Returns: {receipt,listing,replayed,serverTime}; listing can be null on retained replay after terminal audit purge Errors: 409 conflicts require explicit reconciliation, never fresh revisions or operation IDs on an unknown outcome. Missing OPERATION_NOT_FOUND does not prove nonexecution. 422 capacity/balance/daily-limit errors preserve atomicity. 429 schedules no retry. Full Inbox returns pending without losing the original item. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| price | Yes | Original positive safe-integer price in the configured currency | |
| userId | Yes | Active player matching the current session and project | |
| issuedAt | Yes | Original canonical timestamp including .SSSZ; never replace issuedAt on retry | |
| instanceId | Yes | Original canonical lowercase UUID | |
| operationId | Yes | Persisted original operation UUID, never replaced after uncertainty | |
| sessionToken | Yes | Current accessToken sent only as Bearer | |
| durationSeconds | Yes | Original sale lifetime in seconds, from five minutes to seven days | |
| expectedConfigRevision | Yes | Exact original safe-integer revision; never refresh-and-retry a mutation | |
| expectedInventoryRevision | Yes | Exact original safe-integer revision; never refresh-and-retry a mutation |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: one HTTP attempt, atomic removal of the exact inventory instance into escrow, persisted replay fields, and what 'replayed' means in the return. Error semantics are unusually rich — 409 reconciliation, 422 atomicity preservation, 429 no scheduled retry, 401/403 session distinctions, and the HORIZON_API_KEY / horizon_test_connection cross-check.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Long but cleanly front-loaded with labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors), which makes it scannable for a 9-parameter mutation. There is some redundancy and a mild internal tension: '429 schedules no retry' versus the later '429 ... wait a minute, then retry.'
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, open-world, 9-required-parameter mutation with no output schema, the description covers auth, atomicity, replay, return shape, and every documented failure mode. Nothing an agent needs in order to call this safely is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: the original-field persistence contract (operationId, issuedAt, revisions must never be refreshed on retry) and which credential source supplies sessionToken. It does not explain the price/currency or duration semantics beyond the schema, so it stops short of a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with scope: 'Lists one original unequipped item at the explicitly approved price and fee configuration.' It also names what it is not for (automatic trading, polling, generated replacement ops), which separates it from siblings like horizon_buy_marketplace_listing and horizon_cancel_marketplace_listing without needing their schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (explicit marketplace actions after reading the docs) and 'Not for' exclusions, plus a named reconciliation alternative (horizon_get_marketplace_operation). The auth prerequisite is spelled out with concrete sibling calls (horizon_signin_email / horizon_signin_anonymous) to obtain sessionToken.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_create_matchCreate MatchAIdempotent
Creates one server-ID lobby under the original player-ledger revision. Use when: explicit asynchronous multiplayer actions after reading horizon://docs/matches. Not for: automatic polling, page traversal, timeout progression, invented winners or automatic rewards. Reconcile with horizon_get_matches and horizon_get_match. Consent and game consensus do not validate honest gameplay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt. Reserves active and settlement capacity plus bounded invite slots atomically. Completed detail history is separate; FREE defaults to zero. Lost response: reconcile horizon_get_matches with the original intent. Returns: {match,playerRevision,pollAfterSeconds,serverTime} Errors: 404 hides private/missing/expired matches. 409 REVISION_CONFLICT or STATE_CONFLICT: explicitly reread and reconcile the original intent, never replace the revision or automatically resubmit. RESULT_CONFLICT preserves the original report. RUN_EXPIRED/RUN_ALREADY_USED never allow replacement ranked runs. 501 FEATURE_NOT_SUPPORTED is explicit for simpleServer ranked mode. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the session and project | |
| settings | Yes | Complete immutable lobby settings; current tier state cap also applies | |
| sessionToken | Yes | Player accessToken sent only as Bearer | |
| expectedRevision | Yes | Original reviewed revision; never substitute a newer revision after an uncertain write |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations, the description discloses atomic capacity and invite-slot reservation, lost-response reconciliation, revision/state conflict handling, 404 privacy behavior, 401/403 auth distinctions, 429 rate limits, and error-result behavior. These are material operational traits for a create operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose and organized into Use when, Not for, Requires, Side effects, Returns, and Errors sections. It is thorough for a high-stakes mutation, but the error block is long and somewhat repetitive, keeping it from being maximally concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even without an output schema, the description states the return shape and covers prerequisites, side effects, conflict semantics, and error cases. Combined with the annotations and fully described schema, an agent has enough information to invoke and recover from this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is already 100%, so the baseline is 3, but the description adds useful meaning: sign in via horizon_signin_email or horizon_signin_anonymous and pass that accessToken as sessionToken. It also reinforces expectedRevision as the original reviewed revision, though it does not expand nested settings fields.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Creates one server-ID lobby under the original player-ledger revision.' It also scopes the action against reconciliation tools and lists exclusions, so the agent can distinguish this from get/list/start/join siblings without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit 'Use when' and 'Not for' guidance, including exclusions for polling, page traversal, timeout progression, and invented results. It also names horizon_get_matches and horizon_get_match for reconciliation, though it does not explicitly route creation versus start_match or join_match.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_decline_friend_requestDecline Friend RequestADestructiveIdempotent
Declines Friend Request using the reviewed player revision. Use when: the player explicitly requests this social action. Not for: automatic retries after timeout, automatic acceptance of crossed requests or changing expectedRevision without reconciling intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. A current snapshot revision and its exact requestId. Side effects: Removes only this exact incoming request and the matching sender outgoing record. No automatic retry. Repeating the same revision cannot create a second effect. Returns: Complete {userId,revision,friendCode,friends,incoming,outgoing,blocked,limits,serverTime} snapshot. Replace the matching host/project/player cache. lastActiveAt is the latest retained login, null when unknown; it is not online presence. Errors: 409 REVISION_CONFLICT or an uncertain response: get a new snapshot and reconcile intent, never silently replace expectedRevision and repeat. 404 FRIEND_REQUEST_NOT_FOUND means this request was removed or replaced; do not act on a newer ID. INBOX_FULL rejects the entire send/accept. Friend/request/block capacity limits reject additions while existing data remains removable. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player UUID matching the session | |
| requestId | Yes | Exact request ID from the reviewed incoming/outgoing snapshot | |
| sessionToken | Yes | Player accessToken sent only as Authorization Bearer | |
| targetUserId | Yes | The other player UUID in the same project | |
| expectedRevision | Yes | Exact revision from the reviewed actor snapshot; never refresh and substitute automatically |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial context beyond annotations: exactly what gets removed (this incoming request plus the sender's outgoing record), that repeating a revision cannot double-apply, that no automatic retry occurs, and that the full host/project/player cache should be replaced from the returned snapshot. It also documents rate limits (429), auth failure modes (401/403) and the HORIZON_API_KEY dependency with per-status remediation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Labeled sections (Use when, Not for, Requires, Side effects, Returns, Errors) make it easy to scan and front-load the decision-relevant information. Slightly redundant: the no-automatic-retry rule is stated twice, once under "Not for" and again under "Side effects," and the error block is dense.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, revision-guarded mutation with five required parameters and no output schema, the description covers prerequisites, concurrency semantics, side effects, the returned snapshot shape and cache-replacement guidance, plus every meaningful error path. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description earns extra credit by explaining provenance and constraints: sessionToken comes from horizon_signin_email/horizon_signin_anonymous accessToken, expectedRevision must be the current snapshot revision, and requestId must be the exact ID from the reviewed snapshot. It also clarifies that a 403 means the wrong userId was paired with the token.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Declines Friend Request") and immediately scopes it to the exact incoming request via the reviewed revision. The side-effects sentence ("Removes only this exact incoming request and the matching sender outgoing record") implicitly separates it from horizon_cancel_friend_request and horizon_remove_friend without the agent needing the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit "Use when" and "Not for" sections give clear inclusion and exclusion criteria, including the important anti-pattern of auto-retrying after a timeout. It stops short of naming the concrete sibling alternatives (horizon_cancel_friend_request for outgoing, horizon_accept_friend_request for acceptance), so routing is inferred rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_decline_group_invitedecline group inviteADestructiveIdempotent
Applies the explicit decline group invite action using the reviewed group revision. Use when: the player explicitly confirms this group action. Not for: replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Current group revision and the exact pending requestId where applicable. Side effects: Removes your exact pending invitation on both sides. No automatic retry. Same-revision replay cannot create a second effect. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| requestId | Yes | Exact pending identity from the reviewed snapshot | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| expectedRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructive, idempotent, open-world, and non-read-only behavior, and the description adds substantial context: removes the exact pending invitation on both sides, disallows automatic retry, and explains why same-revision replay cannot duplicate the effect. It also documents return shape, cache replacement scope, and error semantics including rollback and status-specific handling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but front-loaded and clearly sectioned into purpose, usage, requirements, side effects, returns, and errors. The detail is largely justified for a destructive, revision-sensitive operation, though it could be tightened in places.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, but the description explicitly documents the return shape and meaning. For a complex authenticated mutation with revision and requestId constraints, it supplies enough behavioral, error, and reconciliation context for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds useful meaning beyond the schema by tying userId and sessionToken to the sign-in flow, emphasizing that expectedRevision is the exact reviewed revision, and clarifying that requestId is the exact pending identity from the reviewed snapshot.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: decline a group invite using the reviewed group revision. It is readily distinguishable from sibling actions such as accept, cancel, decline request, or leave group by the named action and required pending request identity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit use conditions ('player explicitly confirms this group action') and explicit exclusions ('Not for replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically'). It also names reconciliation tools and specifies when to reconcile rather than retry.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_decline_group_requestdecline group requestADestructiveIdempotent
Applies the explicit decline group request action using the reviewed group revision. Use when: the player explicitly confirms this group action. Not for: replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Current group revision and the exact pending requestId where applicable. Side effects: Leader/officer declines this exact request. No automatic retry. Same-revision replay cannot create a second effect. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| requestId | Yes | Exact pending identity from the reviewed snapshot | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| targetUserId | Yes | Other player in this project | |
| expectedRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: declares the leader/officer authority requirement, the no-automatic-retry rule, idempotent same-revision replay, the exact return shape ({groups, group|null}) and its privacy scoping, and specific error semantics (409 REVISION_CONFLICT, REQUEST_NOT_FOUND, INBOX_FULL rollback, 403 role/session/bilateral-block, 429, 401).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with Use when / Not for / Requires / Side effects / Returns / Errors, so an agent can scan it quickly. It is dense and repeats itself in the error section (401 and 403 are each described twice, and HORIZON_API_KEY handling is restated at the end), which costs it a point.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, stateful group mutation with six required parameters and no output schema, it supplies auth prerequisites, authority requirements, the return contract, privacy guarantees, cache-invalidation guidance, and a full error/recovery map. Nothing an agent needs in order to call it safely is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real meaning: sessionToken must be the accessToken from horizon_signin_email/horizon_signin_anonymous, expectedRevision is the reviewed revision that must not be refreshed-and-retried, and requestId is the exact pending identity from a reviewed snapshot. It does not explain targetUserId or groupId beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('decline group request ... using the reviewed group revision') and clarifies the actor: 'Leader/officer declines this exact request'. That distinguishes it from sibling operations like horizon_accept_group_request, horizon_cancel_group_request, and horizon_decline_group_invite without needing the schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when: the player explicitly confirms this group action' and 'Not for: replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty'. It also routes error recovery to horizon_get_groups and horizon_get_group_pending, naming the reconcile tools directly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_decline_match_inviteDecline Match InvitationADestructiveIdempotent
Executes decline match invitation under the exact original revision. Use when: explicit asynchronous multiplayer actions after reading horizon://docs/matches. Not for: automatic polling, page traversal, timeout progression, invented winners or automatic rewards. Reconcile with horizon_get_matches and horizon_get_match. Consent and game consensus do not validate honest gameplay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt. Start requires the creator and every joined UUID exactly once. Turn requires the current unexpired actor. Timeout advances only one turn. Active leave forfeits without selecting a winner. Lobby cancel is creator-only. Full Inbox retains a durable notice without undoing a committed move. Returns: {match,pollAfterSeconds,serverTime}; departing lobby actors receive metadata only and lose point-read access. Errors: 404 hides private/missing/expired matches. 409 REVISION_CONFLICT or STATE_CONFLICT: explicitly reread and reconcile the original intent, never replace the revision or automatically resubmit. RESULT_CONFLICT preserves the original report. RUN_EXPIRED/RUN_ALREADY_USED never allow replacement ranked runs. 501 FEATURE_NOT_SUPPORTED is explicit for simpleServer ranked mode. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the session and project | |
| matchId | Yes | Original server match UUID in the selected project | |
| sessionToken | Yes | Player accessToken sent only as Bearer | |
| expectedRevision | Yes | Original reviewed revision; never substitute a newer revision after an uncertain write |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description discloses auth requirements, one HTTP attempt, revision-conflict behavior, 404/409/401/403/429 handling, and rate-limit semantics. Some listed side effects belong to other match operations, but the tool’s failure and concurrency behavior is unusually well documented.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is structured with Use/Side effects/Returns/Errors headings, but it is far too long for one operation. Large portions describe start, turn, timeout, active leave, lobby cancel, inbox, and ranked-run behavior that is irrelevant to declining a match invitation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The return shape and error/auth behavior are described, which matters because there is no output schema. However, the definition does not clearly explain the core effect of declining an invitation or the resulting match state, and it substitutes broad match-lifecycle material for focused semantics.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3, but the description adds meaningful auth context for sessionToken and userId by explaining the sign-in flow and passing accessToken as sessionToken. It also reinforces the expectedRevision rule, though matchId itself is not elaborated.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb and resource, 'decline match invitation,' and adds the key constraint 'under the exact original revision.' It is clear enough to identify the action, but it does not distinguish this tool from adjacent invitation-decline or match-lifecycle siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives some usage guidance via 'Use when' and 'Not for,' but those apply broadly to asynchronous multiplayer actions rather than specifically to declining a match invitation. It names horizon_get_matches and horizon_get_match for reconciliation, yet does not explicitly say when to decline versus accept, leave, or cancel.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_delete_groupdelete groupADestructiveIdempotent
Applies the explicit delete group action using the reviewed group revision. Use when: the player explicitly confirms this group action. Not for: replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Current group revision and the exact pending requestId where applicable. Side effects: Sole leader deletes the group only when no invitations/requests remain. No automatic retry. Same-revision replay cannot create a second effect. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| expectedRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, yet the description adds real value: sole-leader precondition, the no-invitations/requests-remaining gate, no automatic retry, and same-revision replay producing no second effect. Auth path (sign in, pass accessToken as sessionToken), rate-limit behavior, and full error taxonomy are all disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) front-load the action and make it scannable, which is the right structure for a destructive tool. It is on the verbose side, with 401/403 handling restated in both the Errors and the trailing paragraph, costing some density.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, and the description compensates by specifying the return shape ({groups: MyGroupsView, group: GroupView|null}) plus the rule that groups is the actor's snapshot and never the target's private state. Error reconciliation steps, cache-replacement scope, and API-key failure modes are all covered, leaving nothing an agent needs to call this safely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds operational meaning: sessionToken must come from horizon_signin_email/horizon_signin_anonymous, and expectedRevision must never be refreshed and blindly retried after an uncertain response. That is semantic guidance beyond the field text, though it doesn't explain groupId versus any other identifier beyond what the schema says.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ("delete group action") and pins the mechanism to a reviewed group revision, which an agent can act on unambiguously. It stops short of naming the closest sibling (horizon_leave_group) that a player-vs-leader distinction should route away from, so the differentiation is implied by the side-effects clause rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit "Use when: the player explicitly confirms this group action" and a "Not for:" list covering revision replacement, block bypass, and automatic retry. The exclusions target retry/state misuse rather than naming the sibling alternative (horizon_leave_group, horizon_transfer_group_leadership), so it falls short of full alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_deliver_achievement_rewardsInspect Legacy Achievement Reward StatusARead-onlyIdempotent
Reads compatibility reward status for up to eight original achievement keys. Use when: diagnosing an older unsettled reward without changing its original identity. Not for: delivering or claiming new achievement rewards; new unlocks credit immediately. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Read-only compatibility POST; creates no reward, delivery or grant. Legacy pending status returns MIGRATION_REQUIRED for verified cold settlement. Returns: {achievements,results:[{key,state,inboxEntryId,code}]}. New compact achievements are complete with no Inbox ID; never invent a new action from a legacy pending result. Errors: 409 STATE_CONFLICT: reconcile and retry the same key. ACHIEVEMENT_NOT_MANUAL: report the configured statistic instead. MIGRATION_REQUIRED preserves legacy reward originals for the verified cold operator; it never authorizes a replacement reward or Inbox delivery. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| keys | Yes | One to eight distinct original keys; fixed compatibility request bound | |
| userId | Yes | Signed-in player UUID matching the session | |
| sessionToken | Yes | Player accessToken, sent only as Authorization Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/idempotentHint/destructiveHint=false, but the description goes well beyond them: it discloses that the read is a POST, that no reward, delivery or grant is created, that MIGRATION_REQUIRED preserves legacy originals and never authorizes a replacement, and it maps the 409/401/403/429/ACHIEVEMENT_NOT_MANUAL failure modes to concrete recovery actions. Rate-limit and auth-source behavior are both covered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and then labeled blocks (Use when / Not for / Requires / Side effects / Returns / Errors) that make skimming easy. The errors paragraph is dense and partially redundant with the auth block, so it is slightly longer than it needs to be, but every section carries operational information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, yet the description supplies the return shape ({achievements,results:[{key,state,inboxEntryId,code}]}) and interprets edge cases (compact achievements have no Inbox ID). Combined with error handling, side effects and auth prerequisites, an agent has everything needed to call and interpret this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds genuine meaning on top: it explains where sessionToken comes from (the accessToken of a prior sign-in) and ties userId to the signed-in player ('pass the userId that signed in' on a 403), and it reinforces the fixed one-to-eight key bound and the 'never invent a replacement key' rule for retries.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Reads compatibility reward status for up to eight original achievement keys.' It draws a hard boundary against the achievement siblings with 'Not for: delivering or claiming new achievement rewards; new unlocks credit immediately,' which separates it from horizon_unlock_achievement and horizon_get_achievements. It also implicitly corrects the misleading 'deliver' in the tool name.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (diagnosing an older unsettled reward without changing its original identity) and explicit 'Not for' (delivering or claiming new rewards). Prerequisites are spelled out: sign in via horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken, plus the HORIZON_API_KEY requirement. Nothing about when to reach for this versus a sibling is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_discard_itemDiscard ItemADestructiveIdempotent
Discards Item using the reviewed inventory revision. Use when: the player explicitly requests this inventory action. Not for: automatic retries, client grants, changing instance IDs or revisions to force an uncertain action through. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. An exact reviewed inventory revision and instance UUID. Side effects: Permanently removes this instance. The original source guards consumption; replay cannot recreate a discarded item and no recipient receipt is added. One HTTP attempt only. Returns: Complete {userId,revision,instances,limits,serverTime} inventory. Replace only the matching host/project/player cache. Instances carry server-generated UUIDs, properties, equipped and createdAt. Errors: 409 REVISION_CONFLICT or an uncertain response: use horizon_get_items and reconcile intent, never silently substitute a new revision and repeat. 404 ITEM_NOT_FOUND means this instance no longer exists. 422 ITEM_PROPERTY_NOT_ALLOWED/ITEM_PROPERTY_LIMIT_REACHED rejects the entire adjustment. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player UUID matching the session | |
| instanceId | Yes | Exact owned item instance UUID from the reviewed inventory | |
| sessionToken | Yes | Player accessToken sent only as Authorization Bearer | |
| expectedRevision | Yes | Exact reviewed revision; never refresh and substitute automatically |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it discloses permanence and non-replayability, that no recipient receipt is added, that only one HTTP attempt is made, that the response replaces only the matching host/project/player cache, and it maps 409/404/422/401/403/429 to concrete meanings and remedies. The 'one HTTP attempt only' and rate-limit notes are the kind of operational detail annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded and labeled (purpose, Use when, Not for, Requires, Side effects, Returns, Errors), so an agent can scan to the section it needs. It is long and the error enumeration is dense with mixed concerns (auth, rate limits, validation) that could be trimmed, but almost every sentence carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, revision-guarded mutation with no output schema, the description covers everything an agent needs: the auth prerequisite and token plumbing, exact-revision semantics, permanence, the full return shape, and per-status recovery rules. Nothing essential to calling it correctly or recovering from failure is left unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description still adds real meaning by tying expectedRevision to the reviewed revision ('never refresh and substitute automatically'), pinning instanceId to an exact owned instance from reviewed inventory, and explaining that sessionToken comes from horizon_signin_email/horizon_signin_anonymous and must be sent as a Bearer token. That exceeds what the schema's field descriptions convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Discards Item') and immediately narrows the scope ('Permanently removes this instance'), so the agent knows this is a destructive inventory mutation rather than a read or an adjustment. It never names its nearest siblings (horizon_adjust_item, horizon_equip_item, horizon_get_items as the read counterpart), so differentiation is only inferable from behavior rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'Use when' / 'Not for' pair is explicit and unusually useful, ruling out automatic retries and revision-forcing, which is exactly where an agent would otherwise go wrong. It also names horizon_get_items as the reconciliation path after a 409 or uncertain response. The positive condition ('the player explicitly requests this inventory action') is somewhat generic, but the exclusions carry the guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_equip_itemSet Item Equipped StateADestructiveIdempotent
Sets Item Equipped State using the reviewed inventory revision. Use when: the player explicitly requests this inventory action. Not for: automatic retries, client grants, changing instance IDs or revisions to force an uncertain action through. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. An exact reviewed inventory revision and instance UUID. Side effects: Sets this instance's equipped boolean; it does not enforce game-specific slot rules. One HTTP attempt only. Returns: Complete {userId,revision,instances,limits,serverTime} inventory. Replace only the matching host/project/player cache. Instances carry server-generated UUIDs, properties, equipped and createdAt. Errors: 409 REVISION_CONFLICT or an uncertain response: use horizon_get_items and reconcile intent, never silently substitute a new revision and repeat. 404 ITEM_NOT_FOUND means this instance no longer exists. 422 ITEM_PROPERTY_NOT_ALLOWED/ITEM_PROPERTY_LIMIT_REACHED rejects the entire adjustment. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player UUID matching the session | |
| equipped | Yes | Explicit desired equipped state | |
| instanceId | Yes | Exact owned item instance UUID from the reviewed inventory | |
| sessionToken | Yes | Player accessToken sent only as Authorization Bearer | |
| expectedRevision | Yes | Exact reviewed revision; never refresh and substitute automatically |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare the safety profile (destructive, openWorld, idempotent), and the description adds substantial context beyond them: the write is limited to the equipped boolean and does not enforce slot rules, it makes exactly one HTTP attempt, the returned inventory shape and cache-replacement rule, plus a full error taxonomy (409/404/422/401/403/429) with prescribed recovery rather than silent retry. The idempotentHint and 'one attempt only' detail are complementary rather than contradictory given the expectedRevision guard.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) make a long block scannable and front-load the routing decision. It is dense but nearly every sentence carries actionable information; only the duplicated 401/rate-limit diagnostics edge toward verbosity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutating, open-world, revision-guarded tool with no output schema, it covers prerequisites (API key, session flow), side-effect scope, the returned inventory shape, and every foreseeable failure with recovery guidance. Nothing needed to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description adds real meaning on top by explaining how sessionToken is obtained (horizon_signin_email/horizon_signin_anonymous accessToken), that userId must match the signed-in session, and that expectedRevision must be the exact reviewed revision with no silent refresh. It stops short of documenting the equipped/instanceId semantics beyond what the schema already says.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (set an item instance's equipped boolean) and the precondition that makes it distinct: it operates on an exact reviewed inventory revision and instance UUID, unlike horizon_adjust_item or horizon_discard_item. An agent can distinguish it from its inventory siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (player explicitly requests the inventory action) and 'Not for' (automatic retries, client grants, forcing through by swapping revision/instance IDs). It also routes to the concrete alternative for the uncertain case (horizon_get_items to reconcile intent), satisfying the when/when-not/alternatives bar.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_find_open_matchesFind Open MatchesARead-onlyIdempotent
Reads one strength-filtered open-lobby page under current blocks and active-owner checks. Use when: explicit asynchronous multiplayer actions after reading horizon://docs/matches. Not for: automatic polling, page traversal, timeout progression, invented winners or automatic rewards. Reconcile with horizon_get_matches and horizon_get_match. Consent and game consensus do not validate honest gameplay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Read only, at most256 metadata candidates and50 results. Empty cursor pages are valid. No game state is returned. Returns: {matches,nextCursor,pollAfterSeconds,serverTime} Errors: 404 hides private/missing/expired matches. 409 REVISION_CONFLICT or STATE_CONFLICT: explicitly reread and reconcile the original intent, never replace the revision or automatically resubmit. RESULT_CONFLICT preserves the original report. RUN_EXPIRED/RUN_ALREADY_USED never allow replacement ranked runs. 501 FEATURE_NOT_SUPPORTED is explicit for simpleServer ranked mode. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | One explicit page of at most fifty summaries | |
| cursor | No | Previous consumed-only cursor; an empty page can have a continuation | |
| userId | Yes | Active player matching the session and project | |
| maxStrength | Yes | Exact safe integer strength from the original search range | |
| minStrength | Yes | Exact safe integer strength from the original search range | |
| sessionToken | Yes | Player accessToken sent only as Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as read-only and idempotent, and the description reinforces that with 'Side effects: Read only' and 'No game state is returned.' It adds substantial context beyond annotations: auth requirements, candidate/result limits, cursor semantics, rate limits, and a detailed error taxonomy.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well structured and front-loaded: purpose first, then use/not-for guidance, prerequisites, side effects, return shape, and errors. The error section is dense and somewhat expansive, but it remains relevant to correct invocation and troubleshooting.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, but the description fully documents the return shape as {matches,nextCursor,pollAfterSeconds,serverTime}. It also covers auth, read-only behavior, pagination limits, valid empty pages, and relevant error paths, making it complete for this complex tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds useful meaning by linking sessionToken to the accessToken from sign-in and requiring userId to match the signed-in player. It also frames minStrength and maxStrength as a strength-filtered lobby query, though those parameters are still mostly explained by the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: it reads one strength-filtered open-lobby page under current blocks and active-owner checks. That distinguishes it from broader match retrieval siblings such as horizon_get_matches and horizon_get_match.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly gives a 'Use when' condition tied to asynchronous multiplayer actions after reading the matches docs, and a 'Not for' list covering polling, page traversal, timeout progression, invented winners, and automatic rewards. It also directs reconciliation with horizon_get_matches and horizon_get_match.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_find_playerFind Player by Friend CodeARead-onlyIdempotent
Finds one public player by exact UUID or canonical H- friend code in this project. Use when: a player intentionally shares their ID or friend code. Not for: email/name search, enumerating players or testing online presence. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only). Returns: {userId,friendCode,display:{name,profile}}. Unknown, inactive, deleted, foreign and blocked players share PLAYER_NOT_FOUND. Errors: 409 REVISION_CONFLICT or an uncertain response: get a new snapshot and reconcile intent, never silently replace expectedRevision and repeat. 404 FRIEND_REQUEST_NOT_FOUND means this request was removed or replaced; do not act on a newer ID. INBOX_FULL rejects the entire send/accept. Friend/request/block capacity limits reject additions while existing data remains removable. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Public UUID or H-code; not a credential and never an email/name prefix | |
| userId | Yes | Signed-in player UUID matching the session | |
| sessionToken | Yes | Player accessToken sent only as Authorization Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare a read-only, idempotent, non-destructive, open-world operation, and the description usefully adds 'Side effects: None', the return shape, auth prerequisites, and 401/403/429 handling. However, the long error section is contaminated with unrelated mutation/friend-request/inbox/revision-conflict behavior, which is misleading context for a simple player lookup.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose, usage, auth, side effects, and return shape are front-loaded and clearly labeled, but the description is bloated by a large error block that mostly describes unrelated friend-request, inbox, and revision-conflict flows. Many sentences do not earn their place for this read-only lookup tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter read-only lookup with full schema coverage and rich annotations, the description includes the important missing pieces: auth acquisition, query form, return shape, and relevant 401/403/429 behavior. Its completeness is undermined by irrelevant and potentially confusing error cases such as 409 REVISION_CONFLICT, FRIEND_REQUEST_NOT_FOUND, and INBOX_FULL.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents the three parameters well. The description still adds value by clarifying that query is exact UUID or canonical H-code and by explaining that sessionToken is the accessToken from horizon_signin_email or horizon_signin_anonymous, and that userId must match the signed-in player.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: finds one public player by exact UUID or canonical H- friend code in this project. It also clearly scopes the tool away from email/name search, enumeration, and presence testing, which distinguishes it from nearby player/friend tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use guidance (player intentionally shares ID or friend code) and explicit when-not-to-use cases (email/name search, enumerating players, testing online presence). It also names sign-in alternatives for obtaining the required session token.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_achievementsGet Player AchievementsARead-onlyIdempotent
Reads visible achievement definitions and permanent completion bits. Use when: loading progress or refreshing after newlyUnlocked statistics or realtime invalidation. Not for: changing balances or revealing locked hidden achievements. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only). Does not grant anything. Returns: {userId,revision,definitionVersion,definitions,progress,limits,serverTime}. definitions=null retains matching cached definitions; [] clears them. Scope caches to host/project/player/session. Compact progress has rewardState=complete, nullable unknown unlockedAt and no pendingReward/inboxEntryId copy. Legacy unsettled originals remain visible until verified cold settlement. Errors: 409 STATE_CONFLICT: reconcile and retry the same key. ACHIEVEMENT_NOT_MANUAL: report the configured statistic instead. MIGRATION_REQUIRED preserves legacy reward originals for the verified cold operator; it never authorizes a replacement reward or Inbox delivery. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player UUID matching the session | |
| sessionToken | Yes | Player accessToken, sent only as Authorization Bearer | |
| definitionVersion | No | Opaque version from the matching cached snapshot; omit for full definitions |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes well beyond the annotations by specifying authentication prerequisites, sign-in alternatives, no side effects and no granting behavior, response shape, cache scoping, cache retention semantics, and detailed error handling including 401, 403, 409, 429, ACHIEVEMENT_NOT_MANUAL, and MIGRATION_REQUIRED. The read-only claims are fully consistent with readOnlyHint=true and destructiveHint=false.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded and uses helpful labels such as Use when, Not for, Requires, Side effects, Returns, and Errors. It is information-dense but long, with some highly implementation-specific sentences about compact progress and legacy settlement that are useful but reduce conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex read operation with no output schema, the description supplies the return shape, auth requirements, cache behavior, side-effect guarantees, and detailed failure modes. Nothing critical for correct invocation appears to be missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents userId, sessionToken, and definitionVersion. The description reinforces the userId/sessionToken relationship and names horizon_signin_email and horizon_signin_anonymous as sources for the accessToken, but it does not meaningfully elaborate on definitionVersion beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource: reads visible achievement definitions and permanent completion bits. It also distinguishes the operation from mutations and hidden-achievement revelation with explicit 'Not for' language, so an agent can separate it from related achievement and statistics tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states clear usage contexts: loading progress or refreshing after newlyUnlocked statistics or realtime invalidation, and explicitly excludes changing balances and revealing locked hidden achievements. It does not name the best alternative for those excluded cases, such as horizon_unlock_achievement or horizon_get_statistics, which keeps it below a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_all_localizationsGet All LocalizationsARead-onlyIdempotent
Reads all translated strings of one language as a key to text map (default: the app's default language). Use when: at game start or on a language switch, to load every UI text at once. Not for: a single key (use horizon_get_localization). Side effects: None (read only). Returns: {translations, language, total}; translations is empty (total 0) when the language has no strings. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| lang | No | ISO 639-1 language code (2 lowercase letters). One of: en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id. Omit for the app's default language. |
Output Schema
| Name | Required | Description |
|---|---|---|
| total | No | |
| language | No | |
| translations | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, but the description adds genuinely new behavioral context: the required HORIZON_API_KEY, the isError/HTTP-status error contract, a 401 meaning a bad key, and a 429 per-minute rate limit with retry guidance. This is exactly the auth-needs and rate-limit disclosure that goes beyond structured annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the purpose, then uses labeled sections (Use when / Not for / Side effects / Returns / Errors) that map to the questions an agent asks before calling. Every sentence carries information; the only mild redundancy is the read-only side-effect line, which is negligible.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema exists, return-shape explanation is optional, but the description goes further by covering auth, empty-result behavior (total 0), and error/rate-limit semantics. Nothing an agent needs to invoke this read tool correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%; the lang parameter is fully documented in the schema (ISO 639-1, 2 lowercase letters, enumerated values, omit for default). The description restates 'one language' and the default-language fallback but adds no syntax or format detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Reads all translated strings of one language as a key to text map') and immediately scopes it with the default-language behavior. It explicitly distinguishes itself from the single-key sibling horizon_get_localization, so an agent can select between them without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides an explicit 'Use when' (game start or language switch, load all UI text at once) and an explicit 'Not for' that names the alternative (horizon_get_localization) for single keys. Both the positive trigger and the exclusion are stated, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_all_remote_configsGet All Remote ConfigsARead-onlyIdempotent
Reads every remote config value of the app in one call as a key to string map. Use when: at game start, to cache all flags and balance values at once. Not for: a single value (use horizon_get_remote_config) or checking the API key only (use horizon_test_connection). Side effects: None (read only). Returns: {configs, total}, where configs maps each key to its string value; an app without configs returns an empty map and total 0. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| total | No | |
| configs | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/destructive/openWorld, but the description goes well beyond them by disclosing auth requirements (HORIZON_API_KEY), the error contract (isError with HTTP status/body), and behavioral specifics for 401 (key wrong) and 429 (per-minute rate limit; wait and retry). This is rich operational context the annotations cannot provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the operation, then cleanly labeled sections (Use when, Not for, Side effects, Returns, Errors). Every sentence adds distinct value; nothing is padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description still orients the agent on the {configs, total} shape and the empty-map/zero-total edge case, plus the full error taxonomy. For a read-only config fetch, an agent has everything needed to call and interpret it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is no parameter semantics to document; the description's 'key to string map' phrasing correctly conveys the shape of what is read. Baseline 4 applies for a parameterless tool.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (reads) and resource (every remote config value of the app) with clear scope (all, in one call, as a key-to-string map). It distinguishes itself from siblings by naming horizon_get_remote_config for single values, so an agent can route correctly without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (game start, to cache all flags at once) and 'Not for' clauses that route to two named alternatives: horizon_get_remote_config for a single value and horizon_test_connection for API-key checks. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_chat_limitsGet Chat LimitsARead-onlyIdempotent
Reads five-tier bounds, current moderation and hosted capabilities. Use when: explicit hosted chat actions after reading horizon://docs/chat. Not for: automatic sends, repeated polling, rich-text rendering or exposing moderation credentials. Use horizon_get_chat_operation to reconcile original sends, then horizon_send_chat_message only for the explicit identical replay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Read only, including during FREE/mute/ban. No polling timer. Returns: {limits,capabilities,moderation,serverTime} Errors: 404 hides private/missing/expired channels or source messages. 409 OPERATION_CONFLICT/OPERATION_EXPIRED or STATE_CONFLICT requires explicit original-intent reconciliation. Never replace an unknown send UUID/time/text. 429 does not schedule a retry. CHAT_MUTED/CHAT_BANNED restrict current chat access. 501 NOT_SUPPORTED means simpleServer has no chat or polling fallback. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the current session and project | |
| sessionToken | Yes | Player accessToken sent only as Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/idempotent/non-destructive, and the description still adds real behavioral context: read-only even under FREE/mute/ban, no polling timer, and a full error contract (404 channel hiding, 409 reconciliation requirement, 429 no auto-retry, 501 NOT_SUPPORTED, 401 re-auth, 403 userId mismatch). The rule "Never replace an unknown send UUID/time/text" is a genuine safety constraint not derivable from structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The when/when-not/auth/returns blocks are front-loaded and scannable, but the error paragraph sprawls into one dense run-on covering 404/409/429/501/401/403/API-key/rate-limit cases. Several clauses (the horizon_test_connection cross-reference, the restated 429 meaning) repeat earlier statements and dilute the signal for a read-only introspection tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description carries the return shape itself ({limits,capabilities,moderation,serverTime}), the auth prerequisite chain, and the failure semantics. Nothing an agent needs to call this correctly on the first attempt is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description goes further by explaining provenance — sign in via horizon_signin_email/anonymous and pass the resulting accessToken as sessionToken, with userId matching that signer. That is meaningfully more than the schema's "Player accessToken sent only as Bearer".
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Reads five-tier bounds, current moderation and hosted capabilities" gives a specific verb and a concrete set of resources, and the Returns line enumerates the payload. The phrase "five-tier bounds" is a bit of internal jargon, but combined with the return keys the agent can tell this is a limits/capability introspection call, distinct from horizon_send_chat_message and horizon_get_chat_operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit "Use when" / "Not for" structure with concrete exclusions (automatic sends, repeated polling, rich-text rendering, exposing moderation credentials). It names the alternatives and the ordering: horizon_get_chat_operation to reconcile an original send, then horizon_send_chat_message for the identical replay only.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_chat_operationGet Original Chat ReceiptARead-onlyIdempotent
Reads the current player's retained original send receipt. Use when: explicit hosted chat actions after reading horizon://docs/chat. Not for: automatic sends, repeated polling, rich-text rendering or exposing moderation credentials. Use horizon_get_chat_operation to reconcile original sends, then horizon_send_chat_message only for the explicit identical replay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Read only, with current identity while the original message remains. A missing/expired receipt does not prove a send never committed and cannot authorize a new ID. No historical per-player copy is retained. Returns: {receipt,serverTime}, metadata only Errors: 404 hides private/missing/expired channels or source messages. 409 OPERATION_CONFLICT/OPERATION_EXPIRED or STATE_CONFLICT requires explicit original-intent reconciliation. Never replace an unknown send UUID/time/text. 429 does not schedule a retry. CHAT_MUTED/CHAT_BANNED restrict current chat access. 501 NOT_SUPPORTED means simpleServer has no chat or polling fallback. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the current session and project | |
| operationId | Yes | Original canonical lowercase UUID | |
| sessionToken | Yes | Player accessToken sent only as Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond readOnly/idempotent/openWorld annotations, the description discloses the critical nuance that a missing or expired receipt does not prove a send never committed and cannot authorize a new ID, and that no historical per-player copy is retained. It also documents the error surface (404 masking private/missing/expired, 409 OPERATION_CONFLICT/EXPIRED and STATE_CONFLICT, 429 non-retry, 501 NOT_SUPPORTED, 401 vs 403 session semantics) and the HORIZON_API_KEY requirement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded with labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors), so an agent can scan to the relevant part. It is however quite long for a read tool, and the trailing paragraph re-explains 401/429 already covered in the Errors line, which is mild redundancy rather than a structural flaw.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter read with no output schema, the description supplies auth prerequisites, the return shape ({receipt, serverTime}, metadata only), the side-effect/retention model, and a full error-to-cause mapping. Nothing an agent needs to invoke this correctly, or to interpret a failure without retrying blindly, is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: sessionToken must come from the signin tool's accessToken, and userId must be the identity that signed in ('pass the userId that signed in'). It also frames operationId as the original canonical UUID that must never be replaced when unknown, which the schema alone does not convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence gives a specific verb and resource ('Reads the current player's retained original send receipt'), which is precise enough to separate it from siblings like horizon_get_chat_limits or horizon_get_marketplace_operation. Scope ('current player', 'retained original') is stated up front, so an agent knows exactly what object is being fetched.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (explicit hosted chat actions after reading horizon://docs/chat) and 'Not for' clauses (automatic sends, repeated polling, rich-text rendering, exposing moderation credentials) give both sides of the decision. It also names the follow-up alternative, horizon_send_chat_message, and restricts it to 'explicit identical replay', plus points to horizon_signin_email/horizon_signin_anonymous for prerequisite auth.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_email_statusGet Email StatusARead-onlyIdempotent
Returns the delivery status (pending, processing, sent or failed) and details of one email queued with horizon_send_email. Use when: checking whether a sent or scheduled email was delivered, or why it failed. Not for: sending again (use horizon_send_email only for a new email) or stopping delivery (use horizon_cancel_email). Requires: the emailId from horizon_send_email. Side effects: None (read only). Returns: {id, status, templateSlug, userId, language, scheduledAt, processedAt, errorReason, createdAt}; errorReason explains a failed email (for example SMTP rejected it). Errors: An unknown emailId or one of another API key is rejected: pass the id returned by horizon_send_email. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| emailId | Yes | Email ID (UUID) returned by horizon_send_email |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| status | No | |
| userId | No | |
| language | No | |
| createdAt | No | |
| errorReason | No | |
| processedAt | No | |
| scheduledAt | No | |
| templateSlug | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/idempotent/destructive, but the description adds substantial context beyond them: auth requirement (HORIZON_API_KEY), rate-limit behavior (429 per-minute, wait and retry), 401 meaning, and cross-API-key id rejection. These are genuine behavioral disclosures the annotations do not provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Uses labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) with the purpose front-loaded, so scanning is fast. It is somewhat verbose, and restating the return fields is arguably redundant given an output schema exists, but no sentence is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter read tool this covers everything an agent needs: selection criteria, prerequisites, side-effect profile, error taxonomy with remediation, and return shape. Output schema exists, yet the description's return summary is a harmless supplement rather than a gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already documents emailId as the UUID returned by horizon_send_email, so the baseline is 3. The description adds that an unknown id or one belonging to another API key is rejected, which is a real invocation constraint beyond the schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Returns the delivery status... of one email queued with horizon_send_email') and enumerates the possible status values. It explicitly distinguishes itself from the siblings horizon_send_email and horizon_cancel_email, so an agent can select it without ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use ('checking whether a sent or scheduled email was delivered, or why it failed') and when-not-to-use with named alternatives ('Not for: sending again... or stopping delivery...'). This is the full when/when-not/alternative triple.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_friendsGet FriendsARead-onlyIdempotent
Reads friends, incoming/outgoing requests, blocks and current limits. Use when: opening a social screen or reconciling an uncertain mutation. Not for: polling for online presence or applying old snapshots to a new session. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only). Returns: Complete {userId,revision,friendCode,friends,incoming,outgoing,blocked,limits,serverTime} snapshot. Replace the matching host/project/player cache. lastActiveAt is the latest retained login, null when unknown; it is not online presence. Errors: 409 REVISION_CONFLICT or an uncertain response: get a new snapshot and reconcile intent, never silently replace expectedRevision and repeat. 404 FRIEND_REQUEST_NOT_FOUND means this request was removed or replaced; do not act on a newer ID. INBOX_FULL rejects the entire send/accept. Friend/request/block capacity limits reject additions while existing data remains removable. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player UUID matching the session | |
| sessionToken | Yes | Player accessToken sent only as Authorization Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the read-only/idempotent annotations, the description explains snapshot replacement semantics, the meaning of lastActiveAt, revision-conflict recovery, request-not-found behavior, inbox/capacity limits, auth failures, API-key failures, and rate-limit behavior. This is unusually rich behavior detail for an agent invoking the tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded and sectioned into use cases, exclusions, requirements, side effects, return shape, and errors. Despite its length, the structure makes every part easy to scan and the detail is justified by the missing output schema and numerous failure modes.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by describing the complete returned snapshot fields. It also covers auth acquisition, cache replacement, online-presence semantics, and key error recovery paths, leaving little an agent needs to infer before calling it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the schema documents userId and sessionToken format. The description still adds meaningful operational semantics: userId must match the signed-in player, and sessionToken must come from one of the horizon_signin_* tools as the accessToken.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific read operation and enumerates exactly what is read: friends, incoming/outgoing requests, blocks, and limits. It also distinguishes itself from nearby social mutations and explicitly rules out online-presence polling, so an agent can identify its role among siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit positive triggers (opening a social screen, reconciling an uncertain mutation) and explicit exclusions (polling for online presence, applying old snapshots to a new session). The auth prerequisite also points to the exact sign-in tools whose token should be used.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_groupGet GroupARead-onlyIdempotent
Reads group using a matching player session. Use when: opening a group screen or reconciling an uncertain action. Not for: unbounded group search, automatic pagination or using stale snapshots after a session change. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only). Returns: GroupView: public metadata for nonmembers, with data/myRole only for members. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| sessionToken | Yes | Player accessToken, sent only in Authorization |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond annotations by describing the return shape, auth prerequisites, error/status semantics, rate-limit behavior, and the rule against automatic retry. It also clarifies that failures return isError with HTTP status and body.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is front-loaded and clearly labeled (Use when, Not for, Requires, Returns, Errors), but the error paragraph is very long and partly redundant, especially around 429 and 401 handling. For a single-group read, the description is overstuffed relative to its core purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description supplies the return shape and member/nonmember visibility rules. It also covers auth, side effects, and error reconciliation, making it complete enough for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds useful meaning by explaining how to obtain sessionToken via horizon_signin_email or horizon_signin_anonymous and by tying userId to the signed-in Bearer session.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Reads group') and clarifies scope with 'Not for: unbounded group search', which distinguishes it from horizon_get_groups. The return note ('GroupView: public metadata for nonmembers, with data/myRole only for members') confirms it is a single-group read.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly gives 'Use when' and 'Not for' conditions, including exclusions around unbounded search and stale snapshots. The error section also names horizon_get_groups and horizon_get_group_pending as alternatives for reconciliation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_group_membersGet Group MembersARead-onlyIdempotent
Reads group members using a matching player session. Use when: opening a group screen or reconciling an uncertain action. Not for: unbounded group search, automatic pagination or using stale snapshots after a session change. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Group membership. Side effects: None (read only). Returns: {groupId,revision,members,nextAfterUserId,serverTime}; one requested page under current memberPageSize. A changed revision between pages requires explicit reconciliation. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Explicit page size no larger than current memberPageSize; default1 stays valid after a reduction. Never automatically follow pages | |
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| afterUserId | No | Last user UUID from the preceding member page | |
| sessionToken | Yes | Player accessToken, sent only in Authorization |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive behavior, and the description adds substantial context beyond that: no side effects, page-size constraints, revision-conflict handling, 401/403/429 semantics, and rollback behavior for related pending actions. It does not contradict the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well structured with labels like "Use when", "Not for", "Requires", "Returns", and "Errors", and the core purpose is front-loaded. Some error and auth details are repeated, but most sentences add operational value for a complex authenticated paginated read.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description carries return-value documentation and does so explicitly: groupId, revision, members, nextAfterUserId, and serverTime. It also covers pagination, revision conflicts, auth failures, and rate limits, making it complete enough for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents the parameters. The description adds useful meaning for authentication semantics: userId must match the signed-in player, sessionToken is the accessToken from a sign-in tool, and limit must not exceed current memberPageSize.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: "Reads group members using a matching player session." It also distinguishes scope with explicit exclusions for unbounded group search, automatic pagination, and stale snapshots, so an agent can tell this apart from broader group-reading or reconciliation tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit "Use when" and "Not for" guidance, and names alternatives such as horizon_get_groups and horizon_get_group_pending for reconciliation. It also explains the required sign-in flow and session-token dependency, leaving little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_group_pendingGet Group Pending RequestsARead-onlyIdempotent
Reads group pending requests using a matching player session. Use when: opening a group screen or reconciling an uncertain action. Not for: unbounded group search, automatic pagination or using stale snapshots after a session change. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Leader/officer membership. Side effects: None (read only). Returns: {groupId,revision,invitations,joinRequests,serverTime}; complete retained entries, including after policy reductions. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| sessionToken | Yes | Player accessToken, sent only in Authorization |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond annotations: states side effects are none, requires leader/officer membership, describes the return payload, and maps error codes (409 REVISION_CONFLICT, 403, 429, 401, INBOX_FULL rollback) to required agent behavior. The value is real, but the 'Use horizon_get_groups and horizon_get_group_pending to reconcile state' line is self-referential and slightly misleads about recovery paths.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded and labeled (Use when / Not for / Requires / Side effects / Returns / Errors), which makes the long error catalogue scannable. Slightly overlong and repetitive — the 429 no-automatic-retry rule is stated twice — and the self-referential recovery line costs it a point.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read tool with no output schema it supplies the return shape ({groupId,revision,invitations,joinRequests,serverTime}), the retained-entries guarantee, auth requirements, and error semantics, so an agent could invoke it correctly. Residual gaps are minor: the revision-conflict reconciliation guidance is ambiguous about which sibling actually performs the reconciliation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, and the description earns an extra point by synthesizing the parameters into an auth story: sign in via horizon_signin_email/horizon_signin_anonymous, pass the accessToken as sessionToken, and pass the userId that signed in. It also clarifies 403/token-mismatch failure modes for those parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Reads group pending requests') plus the session precondition, which is enough to place it alongside horizon_get_groups and horizon_get_group. It loses a point because the Errors paragraph confusingly names the tool itself ('horizon_get_groups and horizon_get_group_pending') as the thing to reconcile with, muddying the sibling boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Uses explicit Use when / Not for framing: 'opening a group screen or reconciling an uncertain action' versus 'unbounded group search, automatic pagination or using stale snapshots after a session change.' It also names prerequisites (leader/officer membership, session signin) so the agent knows when it cannot use this tool at all.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_groupsGet My GroupsARead-onlyIdempotent
Reads my groups using a matching player session. Use when: opening a group screen or reconciling an uncertain action. Not for: unbounded group search, automatic pagination or using stale snapshots after a session change. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only). Returns: MyGroupsView with memberships, pending invitations/requests, revision, limits and serverTime. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| sessionToken | Yes | Player accessToken, sent only in Authorization |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the read-only/idempotent annotations, it discloses required auth flow, return contents, rate-limit behavior, session-expiry handling, conflict semantics, and API-key dependency. It also clarifies that failures return isError with HTTP status and body.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded and labeled well, but it is long and the error section repeats 401/403/429 details and includes action-oriented errors like INBOX_FULL and original requestId reconciliation that are not clearly relevant to a read-only groups fetch.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Because there is no output schema, the description usefully explains that MyGroupsView includes memberships, pending invitations/requests, revision, limits, and serverTime. It also covers auth, side effects, and error handling sufficiently for an agent to invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real workflow meaning: sign in first, pass accessToken as sessionToken, and pass the userId that signed in when the session belongs to another user. That goes beyond the schema's field descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: reads 'my groups' using a matching player session. It clearly distinguishes this list-my-groups operation from unbounded search, pagination, and stale-snapshot use, and it routes reconciliation to the pending-groups sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit 'Use when' and 'Not for' conditions, including opening a group screen or reconciling an uncertain action, and warns against unbounded search and stale snapshots. Auth prerequisites are also spelled out with sign-in alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_inboxGet Player InboxARead-onlyIdempotent
Reads targeted messages and eligible project broadcasts, counters and server polling interval. Use when: displaying notifications or refreshing after realtime invalidation. Not for: choosing rewards or writing messages from the player client. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only). Returns: {userId,cursor,revision,broadcastRevision,serverTime,pollAfterSeconds,unchanged,entries,counts,limits}. unchanged=true has empty entries: keep the cached entries. A changed snapshot replaces them completely. Errors: 409 STATE_CONFLICT: retry the same entry ID. UNCLAIMED_REWARD: claim before removal. MAX_BALANCE_REACHED/DAILY_LIMIT_REACHED/INVENTORY_FULL leaves the reward or original item unclaimed. ENTRY_NOT_FOUND after removal/cleanup never grants again. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Opaque cursor from this same player/project; omit for a full snapshot | |
| userId | Yes | Player UUID belonging to the selected project and player session | |
| sessionToken | Yes | Player accessToken, sent only as Authorization Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the read-only annotations, the description discloses authentication requirements, absence of side effects, return-shape semantics, cache behavior for unchanged snapshots, and a detailed error taxonomy. This is unusually thorough behavioral context for an agent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose, usage, requirements, and side effects, which is good. However, it is very long and packs in an extensive error taxonomy, making it denser and less concise than necessary even for a complex read tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by documenting the return fields, unchanged-snapshot behavior, authentication source, and relevant error states. An agent has enough context to call and interpret this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the schema documents all three parameters. The description still adds meaningful provenance for sessionToken by explaining that it is the accessToken from a sign-in call, though it does not further explain the since cursor beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific read operation over targeted messages and project broadcasts, including counters and polling metadata. It also distinguishes the tool from adjacent inbox actions by stating it is not for choosing rewards or writing messages.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit use-when guidance for notifications and realtime invalidation, plus a not-for exclusion. However, it does not explicitly route the agent to the relevant sibling tools for marking, claiming, or removing inbox entries, despite referencing claim/removal behavior in errors.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_item_catalogGet Item Catalog PageARead-onlyIdempotent
Reads one bounded item template page, including archived templates. Use when: showing item details or reviewing a catalog with explicit keyset pagination. Not for: automatically scanning the whole catalog or combining pages from different revisions. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only). Returns: {revision,definitions,nextAfterKey,total,limits,serverTime}. Retain the first revision for later pages; null cursor ends the list. Errors: 409 REVISION_CONFLICT or an uncertain response: use horizon_get_items and reconcile intent, never silently substitute a new revision and repeat. 404 ITEM_NOT_FOUND means this instance no longer exists. 422 ITEM_PROPERTY_NOT_ALLOWED/ITEM_PROPERTY_LIMIT_REACHED rejects the entire adjustment. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Explicit page size, default 50; never automatically fetch all pages | |
| userId | Yes | Signed-in player UUID matching the session | |
| afterKey | No | Previous nextAfterKey, or omit for the first page | |
| sessionToken | Yes | Player accessToken sent only as Authorization Bearer | |
| catalogRevision | No | First page revision, retained unchanged on later pages; conflict requires restarting the catalog read |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/idempotent/non-destructive, yet the description adds real value: the sign-in prerequisite and how to pass the accessToken, the requirement to retain the first revision across pages, and a full error taxonomy including 401/403 session semantics and 429 rate limiting. The only gap is that it does not say whether archived templates are flagged in the payload, which matters for a read that includes them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) which is good structure, but the error block balloons to five status codes plus isError and rate-limit conventions, much of which is boilerplate that could be one line. It is informative but heavier than it needs to be for a single-page read.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a paginated read with no output schema, the description supplies the return shape {revision,definitions,nextAfterKey,total,limits,serverTime}, session/API-key prerequisites, pagination termination, and error recovery. An agent can call this correctly and recover from each documented failure without further information.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds lifecycle meaning the schema does not: catalogRevision must be retained unchanged across pages, a null cursor ends the list, and the limit is an explicit page size rather than a fetch-all. That is useful procedural semantics for both the cursor and revision parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb+resource+scope: read one bounded item template page, including archived templates. The 'Not for' clause separates it from whole-catalog scanning and from mixing revisions, and the error text routes the agent to horizon_get_items, so it is distinguishable from its siblings without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (showing item details, catalog review with keyset pagination) and 'Not for' (auto-scanning the catalog, combining pages across revisions), plus an alternative path via horizon_get_items on 409 or an uncertain response. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_itemsGet Player InventoryARead-onlyIdempotent
Reads the player's bounded unique item inventory. Use when: opening inventory or reconciling an uncertain edit. Not for: polling or minting items; use horizon_get_item_catalog for templates. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only); an absent inventory is returned empty without writing. Returns: Complete {userId,revision,instances,limits,serverTime} inventory. Replace only the matching host/project/player cache. Instances carry server-generated UUIDs, properties, equipped and createdAt. Errors: 409 REVISION_CONFLICT or an uncertain response: use horizon_get_items and reconcile intent, never silently substitute a new revision and repeat. 404 ITEM_NOT_FOUND means this instance no longer exists. 422 ITEM_PROPERTY_NOT_ALLOWED/ITEM_PROPERTY_LIMIT_REACHED rejects the entire adjustment. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player UUID matching the session | |
| sessionToken | Yes | Player accessToken sent only as Authorization Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/idempotent annotations: states side effects (absent inventory returned empty without writing), the full auth flow via horizon_signin_email/anonymous and accessToken-as-sessionToken, the HORIZON_API_KEY requirement, rate-limit behavior (429), and per-status error semantics (401/403/404/409/422).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose/usage/auth/returns/errors in labeled chunks, but the error paragraph is dense and restates the 401 sign-in retry rule twice. It earns most of its length but could be trimmed without losing meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description fully documents the return shape ({userId,revision,instances,limits,serverTime}), what instances contain, and cache-replacement guidance. An agent has everything needed to call and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real value by explaining how sessionToken is obtained (sign in and pass its accessToken) and reinforcing that userId must be the signed-in player's UUID matching the session.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource: 'Reads the player's bounded unique item inventory.' The 'bounded unique item inventory' phrasing distinguishes it from catalog/template reads and from mutation tools like horizon_adjust_item.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (opening inventory, reconciling an uncertain edit) and 'Not for' (polling, minting) sections, plus a named alternative (horizon_get_item_catalog for templates) and a retry rule on conflict. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_leaderboard_aroundGet Leaderboard Around UserARead-onlyIdempotent
Returns the leaderboard entries directly above and below a player's own position, including the player, each with profile. Use when: a game shows 'you and your rivals' instead of the global top. Not for: the global top list (use horizon_get_leaderboard_top) or the position alone (use horizon_get_user_rank). Requires: a userId from horizon_signup_* or horizon_signin_*; no session token. Side effects: None (read only). Returns: {entries: [{position, username, score, profile}]} in board order. profile is {avatarId, frameId, badges} (IDs from the cosmetics catalog; null or [] when not set, set with horizon_set_profile). Errors: 404 for an unknown leaderboardKey: list valid keys with horizon_list_leaderboards. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| range | No | How many entries around the player to return, 1 to 50 (default 10) | |
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* | |
| leaderboardKey | No | Board key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board. |
Output Schema
| Name | Required | Description |
|---|---|---|
| entries | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false and openWorldHint=true, so safety is covered structurally. The description adds useful non-annotation context: no session token required, the userId provenance, error semantics (404/401/429 with the 429 rate-limit wait-and-retry instruction), and the isError behavior. That said, much of the return-shape detail is redundant with the existing output schema, so it does not reach the top of the range.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) make it scannable and front-load the scope before the alternative routing. It is slightly long, and the Returns block partially duplicates the output schema, but no sentence is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a read-only tool with a full schema and an output schema, the definition still covers prerequisites (userId, no session token), auth (HORIZON_API_KEY), error handling and rate-limit recovery, and the sibling routing needed to call it correctly. Nothing an agent needs is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all three parameters (range, userId, leaderboardKey) are already documented, including UUID format and the leaderboardKey pattern/default. The description echoes the userId source and leaderboardKey default rather than adding new semantics beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('returns the leaderboard entries directly above and below a player's own position') and immediately distinguishes itself from horizon_get_leaderboard_top and horizon_get_user_rank. An agent can identify the exact scope without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' gives the triggering scenario ('you and your rivals' UI) and 'Not for' names both alternative siblings with the condition that selects each. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_leaderboard_topGet Leaderboard TopARead-onlyIdempotent
Returns the top entries of a leaderboard from position 1, each with the player's profile, plus the requesting player's own entry when they are outside the list. Use when: a game shows a global top list (top 10, top 100). Not for: one player's position alone (use horizon_get_user_rank) or the players around them (use horizon_get_leaderboard_around). Requires: a userId from horizon_signup_* or horizon_signin_* (used to append the player's own entry); no session token. Side effects: None (read only). Returns: {entries: [{position, username, score, profile}]} in board order. When the userId is not among them, the player's own entry with the real position is added at the end. An empty board returns an empty list. profile is {avatarId, frameId, badges} (IDs from the cosmetics catalog; null or [] when not set, set with horizon_set_profile). Errors: 404 for an unknown leaderboardKey: list valid keys with horizon_list_leaderboards. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Number of top entries to return, 1 to 100 (default 10) | |
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* | |
| leaderboardKey | No | Board key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board. |
Output Schema
| Name | Required | Description |
|---|---|---|
| entries | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond annotations: discloses the self-entry append behavior when the userId is outside the list, empty-board behavior, 404/401/429 error semantics with remediation, the HORIZON_API_KEY requirement, and 'no session token'. The read-only claim aligns with readOnlyHint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with a labeled structure (Use when / Not for / Requires / Side effects / Returns / Errors) that makes scanning trivial. Every sentence carries operational value with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers return shape, edge cases (empty board, self-entry), auth prerequisites, and error taxonomy including cross-tool 401 comparison. Despite an output schema existing, the extra edge-case detail is warranted and complete for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both userId and leaderboardKey carry full descriptions including UUID format, defaults, and the 'omit to use the API key's default board' fallback. The description largely defers to the schema, which is the right call here, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Returns the top entries of a leaderboard from position 1') and explicitly distinguishes from siblings horizon_get_user_rank and horizon_get_leaderboard_around. An agent can pick the right tool without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (global top list, top 10/top 100) and 'Not for' clauses naming the two alternative tools and their selecting conditions. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_localizationGet LocalizationARead-onlyIdempotent
Reads one translated string by key in one language (default: the app's default language). Use when: the game needs a single text, for example a dynamic message. Not for: loading the UI texts at start (use horizon_get_all_localizations) or finding out which languages exist (use horizon_get_localization_languages). Side effects: None (read only). Returns: {localizationKey, value, language, found}. A missing key or translation is not an error: found is false and value null, so show a fallback text. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | Localization key exactly as defined in the dashboard, for example 'ui.play_button' (max 100 characters) | |
| lang | No | ISO 639-1 language code (2 lowercase letters). One of: en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id. Omit for the app's default language. |
Output Schema
| Name | Required | Description |
|---|---|---|
| found | No | |
| value | No | |
| language | No | |
| localizationKey | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (which only cover readOnly/idempotent/destructive/openWorld) by disclosing the return shape, that a missing key is NOT an error (found=false, value=null), the HORIZON_API_KEY requirement, and the 401/429 failure semantics including rate-limit retry guidance.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then clearly labelled Use when / Not for / Side effects / Returns / Errors sections. Dense but every sentence carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite the output schema existing, the description completes the picture by covering the auth prerequisite, non-error missing-key case, and error taxonomy, which the schema and annotations do not convey.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters are already documented in the schema. The description only restates the default-language behavior for 'lang', adding no syntax beyond the structured fields; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Reads one translated string by key in one language') plus the default behavior, which an agent can distinguish immediately from horizon_get_all_localizations and horizon_get_localization_languages.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' with a concrete example (dynamic message) and an explicit 'Not for' clause naming both alternative tools and the conditions that select them.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_localization_languagesGet Localization LanguagesARead-onlyIdempotent
Lists the languages that have at least one translation for the app. Use when: before horizon_get_localization or horizon_get_all_localizations, to pick a valid lang or build a language menu. Not for: the texts themselves (use horizon_get_all_localizations). Side effects: None (read only). Returns: {languages, total}, where languages holds ISO 639-1 codes such as 'en' or 'de'; empty when the app has no translations. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| total | No | |
| languages | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent/non-destructive annotations, the description adds auth requirements (HORIZON_API_KEY), the exact return shape ({languages, total} with ISO 639-1 codes, empty when no translations), and concrete failure semantics including distinguishing 401 from horizon_test_connection and the 429 per-minute rate limit with a retry hint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Organized as labeled, front-loaded sections (Use when / Not for / Side effects / Returns / Errors) with no filler. The only mild overlap is the Returns section against the existing output schema, but it is brief and non-redundant in substance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read tool, the definition covers routing, semantics, side effects, return structure and error behavior, so an agent can select and invoke it without further exploration. Nothing needed is missing given the annotations and output schema already present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the schema baseline applies (baseline 4). There is nothing for the description to clarify about inputs, and it correctly adds no invented parameter detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Lists the languages that have at least one translation for the app') and immediately bounds the scope to translated languages only. It is clearly distinguishable from horizon_get_localization and horizon_get_all_localizations, which return texts rather than the language list.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to use ('before horizon_get_localization or horizon_get_all_localizations, to pick a valid lang or build a language menu') and when not ('the texts themselves - use horizon_get_all_localizations'). Alternatives are named with the condition that selects them.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_marketplaceGet Own MarketplaceBRead-onlyIdempotent
Reads current own marketplace state or configured limits. Use when: explicit marketplace actions after reading horizon://docs/marketplace. Not for: automatic trading, price polling or generated replacement operations. Use horizon_get_marketplace_operation to reconcile the original intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Read only. No automatic refresh or polling. Returns: {state,serverTime} Errors: 409 conflicts require explicit reconciliation, never fresh revisions or operation IDs on an unknown outcome. Missing OPERATION_NOT_FOUND does not prove nonexecution. 422 capacity/balance/daily-limit errors preserve atomicity. 429 schedules no retry. Full Inbox returns pending without losing the original item. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the current session and project | |
| sessionToken | Yes | Current accessToken sent only as Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, but the description adds genuinely non-obvious behavior: no automatic refresh or polling, the required API key, the sign-in-then-token flow, and specific 401/403/429 recovery steps. It loses a point because a large block of mutation-flavored errors (409 reconciliation, 422 atomicity, full-Inbox pending) reads as copy-paste from a write tool and can make a read-only GET look stateful.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose, side effects and returns are reasonably front-loaded, but the Errors block dominates the text with boilerplate irrelevant to a 2-parameter read (conflict reconciliation, operation IDs, 422 atomicity, inbox capacity). On a read-only idempotent tool this padding dilutes the sentences that actually earn their place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the explicit 'Returns: {state, serverTime}' is valuable, and auth, side effects and failure modes are all covered, which is more than enough for a simple read. It falls short of 5 only because the error section is generic rather than tailored, leaving the shape of 'state' still undefined.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters are documented in-schema, so the baseline applies. The description does add one useful cross-field constraint — the sessionToken must be the accessToken returned by a sign-in, and userId must be the user who signed in (reinforced by the 403 guidance) — but it adds nothing else about format or scoping.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The verb ('Reads') and resource ('marketplace') are stated, but the object is left vague: 'current own marketplace state or configured limits' never says what 'state' contains, and the 'or configured limits' clause overlaps confusingly with the sibling horizon_get_marketplace_limits. An agent must open the schema/docs to know whether this returns balance, listings, or limits — and may pick the wrong sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It has explicit 'Use when', 'Not for' and named-alternative structure, and it redirects to horizon_get_marketplace_operation for reconciliation, plus concrete prerequisites (sign in via horizon_signin_email/anonymous, pass accessToken as sessionToken). The 'Use when' clause is weak and mismatched though ('explicit marketplace actions' describes a write, not a read), so the routing value is partly undermined.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_marketplace_limitsGet Marketplace LimitsARead-onlyIdempotent
Reads current own marketplace state or configured limits. Use when: explicit marketplace actions after reading horizon://docs/marketplace. Not for: automatic trading, price polling or generated replacement operations. Use horizon_get_marketplace_operation to reconcile the original intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Read only. No automatic refresh or polling. Returns: {limits,capabilities,config,serverTime} Errors: 409 conflicts require explicit reconciliation, never fresh revisions or operation IDs on an unknown outcome. Missing OPERATION_NOT_FOUND does not prove nonexecution. 422 capacity/balance/daily-limit errors preserve atomicity. 429 schedules no retry. Full Inbox returns pending without losing the original item. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the current session and project | |
| sessionToken | Yes | Current accessToken sent only as Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing the auth chain (sign in via horizon_signin_email/anonymous, pass accessToken as sessionToken), the HORIZON_API_KEY requirement, the exact return shape {limits,capabilities,config,serverTime}, no-refresh behavior, and how 401/403/429 should be handled. It is consistent with readOnlyHint=true and destructiveHint=false.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the when/when-not guidance, which is good. However the Errors block contains a large amount of boilerplate that cannot apply to a read-only limits read (409 conflict reconciliation, 422 capacity/balance/daily-limit atomicity, 'Full Inbox returns pending'), diluting the signal.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter read with full schema coverage and rich annotations, the description supplies everything needed to invoke it correctly: authentication path, return shape, and error handling. The relevance of some error cases is questionable, but nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100% for the two parameters, so the schema carries the basics; the description adds real meaning by explaining that sessionToken is the accessToken from a sign-in call and that the userId must match the signed-in player.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: reads the caller's own marketplace state / configured limits. It is distinguishable from horizon_get_marketplace and horizon_get_marketplace_rules in broad strokes, though 'marketplace state or configured limits' is slightly blurred and does not explicitly contrast with the sibling 'rules' tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when' and 'Not for' clauses plus a named alternative (horizon_get_marketplace_operation). The alternative routing is somewhat mismatched for a read-only limits call (reconciliation applies to operations), but the when/when-not framing is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_marketplace_listingGet Marketplace ListingARead-onlyIdempotent
Reads one authorized listing or original own operation receipt. Use when: explicit marketplace actions after reading horizon://docs/marketplace. Not for: automatic trading, price polling or generated replacement operations. Use horizon_get_marketplace_operation to reconcile the original intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Read only. Missing receipts never authorize replacement IDs; retained receipts do not regrant items or currency. Returns: {listing,serverTime} Errors: 409 conflicts require explicit reconciliation, never fresh revisions or operation IDs on an unknown outcome. Missing OPERATION_NOT_FOUND does not prove nonexecution. 422 capacity/balance/daily-limit errors preserve atomicity. 429 schedules no retry. Full Inbox returns pending without losing the original item. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the current session and project | |
| listingId | Yes | Original canonical lowercase UUID | |
| sessionToken | Yes | Current accessToken sent only as Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes far beyond the annotations. It details unique operational constraints like 'Missing receipts never authorize replacement IDs' and provides comprehensive error semantics for status codes like 422 (preserves atomicity) and 429 (schedules no retry).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely dense and verbose, sacrificing conciseness for extreme detail. However, it maintains excellent structural logic by grouping information logically: purpose, usage, requirements, side effects, and errors.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The definition is exceptionally complete. It addresses authentication requirements, specific side effects of the read operation, detailed error handling, and functional scope, making it an exhaustive resource for the agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
While the schema provides the structure, the description adds vital operational semantics for the parameters, specifically detailing that the `sessionToken` requires prior execution of a specific sign-in method (email or anonymous) and the need for an `HORIZON_API_KEY`.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool 'Reads one authorized listing or original own operation receipt.' This is highly specific, immediately identifying the resource and operation, while the use guidelines provide excellent differentiation from other sibling listing tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides perfect usage guidance by listing 'Use when' and 'Not for' scenarios. It also explicitly points the agent to a specific alternative sibling, `horizon_get_marketplace_operation`, which is crucial for correct workflow selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_marketplace_operationGet Original Marketplace ReceiptARead-onlyIdempotent
Reads one authorized listing or original own operation receipt. Use when: explicit marketplace actions after reading horizon://docs/marketplace. Not for: automatic trading, price polling or generated replacement operations. Use horizon_get_marketplace_operation to reconcile the original intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Read only. Missing receipts never authorize replacement IDs; retained receipts do not regrant items or currency. Returns: {receipt,serverTime} Errors: 409 conflicts require explicit reconciliation, never fresh revisions or operation IDs on an unknown outcome. Missing OPERATION_NOT_FOUND does not prove nonexecution. 422 capacity/balance/daily-limit errors preserve atomicity. 429 schedules no retry. Full Inbox returns pending without losing the original item. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the current session and project | |
| operationId | Yes | Original canonical lowercase UUID | |
| sessionToken | Yes | Current accessToken sent only as Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent annotations, the description discloses important behavioral constraints: missing receipts do not authorize replacement IDs, retained receipts do not regrant items or currency, and 409/422/429/401/403 failure semantics are explained. It also documents authentication requirements and side-effect expectations in substantial detail.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with useful sections (Use when, Not for, Requires, Side effects, Returns, Errors), which helps scanning. However, it is very long and dense with error prose, and the circular instruction to use the same tool for reconciliation is confusing rather than helpful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex authenticated receipt lookup with no output schema, the description supplies the required context: auth flow, return shape, side effects, nuanced failure semantics, and rate-limit behavior. An agent has enough information to call it correctly and interpret common error outcomes.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is already 100%, so the schema carries the base parameter definitions. The description adds useful auth context by explaining that userId must match the signed-in session and that the accessToken from horizon_signin_email or horizon_signin_anonymous is passed as sessionToken. It is slightly less detailed about operationId beyond referencing the original receipt.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Reads one authorized listing or original own operation receipt.' It is clear enough to distinguish this receipt lookup from adjacent marketplace tools, but the self-referential instruction to 'Use horizon_get_marketplace_operation to reconcile the original intent' weakens differentiation from sibling retry/reconciliation tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides explicit 'Use when' and 'Not for' boundaries, including exclusions around automatic trading and price polling. However, it does not name the relevant alternative sibling tools for reconciliation, and the alternative it does name is itself, which reduces practical routing value.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_marketplace_rulesGet Marketplace Price RulesARead-onlyIdempotent
Reads one revision-consistent bounded rule page. Use when: explicit marketplace actions after reading horizon://docs/marketplace. Not for: automatic trading, price polling or generated replacement operations. Use horizon_get_marketplace_operation to reconcile the original intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Read only. Preserve catalogRevision and after for explicit subsequent pages. Returns: {revision,rules,nextCursor,serverTime} Errors: 409 conflicts require explicit reconciliation, never fresh revisions or operation IDs on an unknown outcome. Missing OPERATION_NOT_FOUND does not prove nonexecution. 422 capacity/balance/daily-limit errors preserve atomicity. 429 schedules no retry. Full Inbox returns pending without losing the original item. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| after | No | Original last item key from the preceding rule page | |
| limit | No | One explicit bounded page, never automatic traversal | |
| userId | Yes | Active player matching the current session and project | |
| sessionToken | Yes | Current accessToken sent only as Bearer | |
| catalogRevision | No | Original rule catalog revision across pages |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, it discloses prerequisites (sign-in and accessToken), pagination invariants (`catalogRevision` and `after`), return shape, and detailed error semantics including 401/403 authentication cases, 409 reconciliation behavior, 429 rate limiting, and API-key requirements. These are substantial behavioral details not covered by the read-only/idempotent annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded and uses clear labeled sections, but it is noticeably overlong and includes at least one unrelated error case: 'Full Inbox returns pending without losing the original item' has no apparent relevance to marketplace rule pagination. The useful content is present, but it is diluted by boilerplate and extraneous error details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the read-only annotations, 100% schema coverage, and lack of an output schema, the description supplies the missing operational context: auth flow, pagination rules, return shape, rate-limit behavior, and error conditions. An agent has enough information to call the tool and interpret failures correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents all five parameters. The description adds useful context about how `catalogRevision` and `after` preserve revision-consistent pagination and how `userId`/`sessionToken` tie to the player session, though it does not need to restate every parameter's format.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Reads one revision-consistent bounded rule page.' It also scopes the operation as explicit, bounded pagination and distinguishes it from `horizon_get_marketplace_operation` for reconciliation, so an agent can identify when this tool is the right choice.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit usage guidance: use after reading `horizon://docs/marketplace` for explicit marketplace actions; not for automatic trading, price polling, or generated replacement operations. It names the alternative `horizon_get_marketplace_operation` and the condition under which that alternative should be used.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_matchGet MatchARead-onlyIdempotent
Reads one currently authorized match snapshot. Use when: explicit asynchronous multiplayer actions after reading horizon://docs/matches. Not for: automatic polling, page traversal, timeout progression, invented winners or automatic rewards. Reconcile with horizon_get_matches and horizon_get_match. Consent and game consensus do not validate honest gameplay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Read only. Invited players receive lobby metadata with dataBase64=null, participants receive original bytes and reports. Returns: {match,pollAfterSeconds,serverTime} Errors: 404 hides private/missing/expired matches. 409 REVISION_CONFLICT or STATE_CONFLICT: explicitly reread and reconcile the original intent, never replace the revision or automatically resubmit. RESULT_CONFLICT preserves the original report. RUN_EXPIRED/RUN_ALREADY_USED never allow replacement ranked runs. 501 FEATURE_NOT_SUPPORTED is explicit for simpleServer ranked mode. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the session and project | |
| matchId | Yes | Original server match UUID in the selected project | |
| sessionToken | Yes | Player accessToken sent only as Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Well beyond the annotations: it discloses what invited players versus participants actually receive (dataBase64=null lobby metadata vs original bytes and reports), the exact return shape, and a full error taxonomy — 404 intentional masking, 409 REVISION/STATE_CONFLICT with a do-not-resubmit rule, RESULT_CONFLICT preservation, RUN_EXPIRED, 501 for simpleServer ranked, 401 vs 403 session distinctions, and 429 rate limiting.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors), which makes a long description scannable. It loses a point for redundancy — the 401 and rate-limit guidance is restated in the Requires, Errors and closing failure paragraph.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the explicit "Returns: {match,pollAfterSeconds,serverTime}" is load-bearing, and the auth prerequisite, HORIZON_API_KEY requirement, and every failure mode an agent could hit are covered. Nothing needed to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: sessionToken must come from horizon_signin_email/horizon_signin_anonymous as an accessToken sent as Bearer, and the 403 note explains that userId must be the same user who signed in. That turns three plain UUID/string fields into a coherent auth contract.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Reads one currently authorized match snapshot" gives a specific verb (read) plus resource and cardinality (one match), which cleanly separates it from horizon_get_matches. The only weakness is the self-referential "Reconcile with horizon_get_matches and horizon_get_match", where the singular name is the tool itself, slightly blurring the sibling boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit "Use when" (explicit asynchronous multiplayer actions after reading horizon://docs/matches) plus an explicit "Not for" list covering automatic polling, page traversal, timeout progression, invented winners and automatic rewards. That is a genuine when/when-not statement with named alternatives (horizon_get_matches, and by contrast horizon_advance_match_timeout / horizon_submit_match_turn).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_matchesGet My MatchesARead-onlyIdempotent
Reads the player's bounded active, invited and recent match summaries. Use when: explicit asynchronous multiplayer actions after reading horizon://docs/matches. Not for: automatic polling, page traversal, timeout progression, invented winners or automatic rewards. Reconcile with horizon_get_matches and horizon_get_match. Consent and game consensus do not validate honest gameplay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Read only. Respect pollAfterSeconds on refresh. Retained state is not truncated after System Config reductions. Returns: {userId,revision,active,invites,recent,pendingResults,limits,pollAfterSeconds,serverTime}; minimal pendingResults retain matchId,finalStateRevision,ownRankedRunId and expiresAt independently of completed detail history. Errors: 404 hides private/missing/expired matches. 409 REVISION_CONFLICT or STATE_CONFLICT: explicitly reread and reconcile the original intent, never replace the revision or automatically resubmit. RESULT_CONFLICT preserves the original report. RUN_EXPIRED/RUN_ALREADY_USED never allow replacement ranked runs. 501 FEATURE_NOT_SUPPORTED is explicit for simpleServer ranked mode. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the session and project | |
| sessionToken | Yes | Player accessToken sent only as Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Although annotations already flag readOnly/idempotent, the description adds substantial context: pollAfterSeconds refresh guidance, retention behavior after System Config reductions, 404 privacy masking, 409 conflict reconciliation rules, 401/403 session semantics, 429 rate limiting, and isError return shape. These are behaviors the annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is front-loaded and uses clear labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors), which makes it scannable. It is long and the Errors section is dense, but nearly every sentence carries operational information rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description provides the return shape explicitly ({userId, revision, active, invites, recent, pendingResults, limits, pollAfterSeconds, serverTime}) plus retention caveats on pendingResults. Auth requirements, error taxonomy, and side effects are all covered, so an agent has what it needs to call and handle the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real value by explaining how to obtain sessionToken (sign in via horizon_signin_email or horizon_signin_anonymous and pass its accessToken) and by clarifying that userId must match the session/project. That is authentication semantics the schema hints at but does not fully spell out.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise verb and resource: 'Reads the player's bounded active, invited and recent match summaries.' The scoping words 'bounded,' 'active, invited and recent' distinguish it from horizon_get_match (single match detail) and horizon_find_open_matches (discovery), which are named later in the text.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit 'Use when' clause and an explicit 'Not for' list that rules out automatic polling, page traversal, and timeout progression. It also points to horizon://docs/matches as a prerequisite and names horizon_get_match for reconciliation, leaving no ambiguity about when to call this versus siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_match_limitsGet Match LimitsARead-onlyIdempotent
Reads the player's five-tier limits and project capabilities. Use when: explicit asynchronous multiplayer actions after reading horizon://docs/matches. Not for: automatic polling, page traversal, timeout progression, invented winners or automatic rewards. Reconcile with horizon_get_matches and horizon_get_match. Consent and game consensus do not validate honest gameplay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Read only. Respect pollAfterSeconds on refresh. Retained state is not truncated after System Config reductions. Returns: {limits,config,capabilities,pollAfterSeconds,serverTime}; limits include activeMatches,stateBytes,retainedMatches,pendingInvites,settlementMatches,historyRetentionSeconds,rankedSettlementSeconds. Zero completed history is valid. Errors: 404 hides private/missing/expired matches. 409 REVISION_CONFLICT or STATE_CONFLICT: explicitly reread and reconcile the original intent, never replace the revision or automatically resubmit. RESULT_CONFLICT preserves the original report. RUN_EXPIRED/RUN_ALREADY_USED never allow replacement ranked runs. 501 FEATURE_NOT_SUPPORTED is explicit for simpleServer ranked mode. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the session and project | |
| sessionToken | Yes | Player accessToken sent only as Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive behavior. The description adds meaningful context—session/auth requirements, pollAfterSeconds refresh cadence, retained-state semantics, HORIZON_API_KEY and 429 rate limits—but its error list includes 409 conflict/run-expired cases that seem inapplicable to this read endpoint, so it is strong but slightly muddied.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded and labeled, but at roughly 300 words for a two-parameter read it is over-long. The error catalog includes conditions such as REVISION_CONFLICT and RUN_EXPIRED that appear copied from mutation/result tools and do not obviously apply here, so not every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully enumerates return fields (limits, config, capabilities, pollAfterSeconds, serverTime) and auth requirements. It covers enough for an agent to call correctly, though the over-broad error section slightly reduces precision.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters are documented. The description adds practical auth semantics—sign in via horizon_signin_email or horizon_signin_anonymous and pass accessToken as sessionToken—beyond the schema's field descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening 'Reads the player's five-tier limits and project capabilities' is a specific verb+resource, and the return summary reinforces scope. It references match siblings, but does not explicitly differentiate itself from horizon_get_chat_limits or horizon_get_marketplace_limits, keeping it from a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit 'Not for' exclusions and names horizon_get_matches and horizon_get_match for reconciliation. The positive 'Use when' is vague ('explicit asynchronous multiplayer actions after reading docs'), so an agent must infer the exact trigger.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_newsGet NewsARead-onlyIdempotent
Lists the published in-game news of the app (announcements, patch notes) created in the horizOn dashboard, newest first. Use when: a game shows a news feed or a message of the day, optionally filtered to the player's language. Not for: configuration values (use horizon_get_remote_config) or UI translations (use horizon_get_localization). Side effects: None (read only). Returns: an array of {id, title, message, releaseDate, languageCode} with only published entries whose release date has passed; an empty array means there is no news. Without languageCode, entries of all languages are returned. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of entries to return, 0 to 100 (default 20) | |
| languageCode | No | ISO 639-1 code (2 lowercase letters, for example 'en' or 'de') to return only entries in that language. Omit for all languages |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing auth requirements (HORIZON_API_KEY), filtering behavior (only published entries past release date), empty-array semantics, and detailed error semantics: 401 means a bad key (cross-referenced to horizon_test_connection) and 429 means a per-minute rate limit with a retry instruction. This is exactly the extra context annotations don't carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then cleanly labeled sections (Use when / Not for / Side effects / Returns / Errors). The length is justified because each section carries decision-relevant information for an agent with no output schema to fall back on.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by specifying the return shape ({id, title, message, releaseDate, languageCode}), field semantics, and empty-result meaning. Auth, side effects, and error handling are all covered, so an agent has everything needed to invoke and interpret the call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description reinforces the languageCode filtering meaning ('optionally filtered to the player's language', all languages when omitted), which adds contextual clarity, though it adds no syntax detail for limit beyond what the schema already documents.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Lists the published in-game news... announcements, patch notes'), adds ordering ('newest first'), and explicitly distinguishes itself from siblings horizon_get_remote_config and horizon_get_localization. An agent can identify the tool's scope without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides an explicit 'Use when' condition (a game shows a news feed or message of the day, optionally language-filtered) and an explicit 'Not for' with the correct alternative named for each exclusion. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_player_value_offersGet Player Value OffersARead-onlyIdempotent
Returns configured purchase offers and the player's value definitions for the current project. Use when: preparing a purchase with horizon_purchase_player_value_offer. Not for: buying an offer (use horizon_purchase_player_value_offer). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: May lazily initialize missing configured values once; does not change existing balances. Returns: {definitionVersion, serverTime, definitions, offers: [{key, name, active, costs, rewards, purchasesPerDay}]} Errors: 409 STATE_CONFLICT: refresh state and retry the SAME operation ID and payload. OPERATION_CONFLICT: do not reuse an ID for a different action. OPERATION_EXPIRED: reconcile state/history; never silently generate another ID. INSUFFICIENT_BALANCE, MAX_BALANCE_REACHED or DAILY_LIMIT_REACHED leaves the whole operation unapplied. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Player UUID belonging to the selected project and player session | |
| sessionToken | Yes | Player accessToken from sign-in, sent only in the Authorization Bearer header |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: states the lazy initialization side effect and clarifies it does not alter existing balances, spells out the auth prerequisite (sign-in tool, accessToken as sessionToken, HORIZON_API_KEY), documents the return shape, and enumerates error codes with recovery actions including 401/403/409/429 semantics. The 'may lazily initialize' note is reconciled with readOnlyHint=true rather than contradicting it.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded and well-labeled (Use when / Not for / Requires / Side effects / Returns / Errors), but the error block is inflated with 409 STATE_CONFLICT, OPERATION_CONFLICT and OPERATION_EXPIRED guidance about operation IDs that do not apply to this read-only, operation-ID-free tool. That is template carry-over that dilutes the signal.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, yet the description supplies the exact response shape (definitionVersion, serverTime, definitions, offers with costs/rewards/purchasesPerDay), along with auth flow, side effects and error taxonomy. An agent has everything needed to call it and interpret failures.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description adds real value by explaining where sessionToken comes from (horizon_signin_email / horizon_signin_anonymous) and what a 403 implies about userId/session pairing. It stops short of describing parameter format constraints, which the schema already handles.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: returns configured purchase offers plus the player's value definitions for the current project, and explicitly says it is not the buying tool. It is clear against horizon_purchase_player_value_offer, but it never reconciles itself with the closely named sibling horizon_get_player_values, which also surfaces value definitions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when: preparing a purchase with horizon_purchase_player_value_offer' plus 'Not for: buying an offer' gives both the positive trigger and the exclusion, naming the alternative tool. Nothing about selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_player_valuesGet Player ValuesARead-onlyIdempotent
Returns the player's server-owned balances, UTC daily counters and operation replay window. Use when: displaying balances or recovering a timed-out horizon_adjust_player_value operation. Not for: changing balances (use horizon_adjust_player_value or horizon_purchase_player_value_offer). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: May lazily initialize missing configured values once; does not change existing balances. Returns: {userId, definitionVersion, revision, day, values, operationWindow: {serverTime, oldestAcceptedAt}} Errors: 409 STATE_CONFLICT: refresh state and retry the SAME operation ID and payload. OPERATION_CONFLICT: do not reuse an ID for a different action. OPERATION_EXPIRED: reconcile state/history; never silently generate another ID. INSUFFICIENT_BALANCE, MAX_BALANCE_REACHED or DAILY_LIMIT_REACHED leaves the whole operation unapplied. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Player UUID belonging to the selected project and player session | |
| sessionToken | Yes | Player accessToken from sign-in, sent only in the Authorization Bearer header |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/idempotent/non-destructive annotations by disclosing lazy initialization behavior, auth requirements, error semantics, retry rules for conflict and expired operations, balance failure behavior, rate limits, and API key dependence. Does not contradict the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but well-structured and front-loaded, moving from purpose to usage, auth, side effects, return shape, and errors. Every section provides actionable information for calling and recovering this tool correctly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even without an output schema, the description names the return shape and the relevant operation window fields. It also covers authentication, side effects, error conditions, and retry guidance, which is complete for this read operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already defines both parameters. The description adds useful authentication semantics by explaining that sessionToken must come from sign-in and belongs to the signed-in userId.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: returns the player's server-owned balances, UTC daily counters, and operation replay window. It also distinguishes itself from mutation siblings by naming horizon_adjust_player_value and horizon_purchase_player_value_offer as the tools for changing balances.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly defines when to use it: displaying balances or recovering a timed-out horizon_adjust_player_value operation. It also gives a clear 'Not for' exclusion and names the correct alternatives for balance-changing actions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_profileGet Player ProfileARead-onlyIdempotent
Returns a player's profile (avatar, frame, badges), the player's unlocks and the cosmetics catalog of the API key with an available flag per entry. Use when: before horizon_set_profile, to show the selection screen and learn which IDs the player may pick. Not for: changing the profile (use horizon_set_profile) or showing other players' profiles (leaderboard entries already carry them). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only). Returns: {userId, profile: {avatarId, frameId, badges}, unlocks, cosmetics: [{id, type, locked, available}], limits: {maxBadges, maxUnlocks}}. available true means this player may select the entry. Errors: 401 SESSION_REQUIRED for a missing or expired session: sign in again. 403 SESSION_FORBIDDEN for a session of another user: pass the userId that signed in. 404 PLAYER_NOT_FOUND for an unknown userId. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* | |
| sessionToken | Yes | accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session |
Output Schema
| Name | Required | Description |
|---|---|---|
| limits | No | |
| userId | No | |
| profile | No | |
| unlocks | No | |
| cosmetics | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, yet the description goes further: it names the required session flow (signin tools producing accessToken), the no-side-effects guarantee, the HORIZON_API_KEY dependency, per-minute 429 rate limits, and specific error semantics (401/403/404) with remediation. This is materially richer than the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with labeled sections (Use when/Not for/Requires/Side effects/Returns/Errors) that make it highly scannable. The Errors paragraph is verbose with some redundancy, but nearly every sentence carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Though an output schema exists, the description still enumerates the return shape and the meaning of the 'available' flag, covers auth prerequisites, side-effect profile, and the full error/rate-limit surface. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters (userId UUID, sessionToken) are already documented in the schema. The description restates their provenance (userId from signup/signin, sessionToken as Bearer) but adds little beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Returns a player's profile ... unlocks and the cosmetics catalog') and explicitly distinguishes itself from horizon_set_profile and from leaderboard-embedded profiles. An agent can identify this tool's scope without reading any other tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when' (before horizon_set_profile, to show the selection screen), 'Not for' (changing the profile, showing others' profiles), and names the correct alternatives for each excluded case. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_remote_configGet Remote ConfigARead-onlyIdempotent
Reads one remote config value by key (a feature flag or balance value set in the horizOn dashboard) as a string. Use when: the game needs a single value, for example to check one feature flag. Not for: loading many values at start (use horizon_get_all_remote_configs, one request instead of many). Side effects: None (read only). Returns: {configKey, configValue, found}. Values are always strings: parse numbers and booleans yourself. An unknown key is not an error: found is false and configValue null, so fall back to a default. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | Config key exactly as defined in the dashboard, case-sensitive, for example 'max_lives' (max 256 characters) |
Output Schema
| Name | Required | Description |
|---|---|---|
| found | No | |
| configKey | No | |
| configValue | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, but the description goes well beyond them: unknown keys are not errors (found=false, configValue=null, fall back to a default), all values are strings requiring manual parsing, and error semantics include HORIZON_API_KEY requirement, 401 diagnosis via horizon_test_connection, and 429 per-minute rate limit with a wait-and-retry instruction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but organized under labeled sections (Use when / Not for / Side effects / Returns / Errors), with the core purpose front-loaded in the opening sentence. Every line carries actionable information; none is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read with an output schema, the description supplies everything an agent needs: auth requirement, verbatim error taxonomy, string-typed return caveat, and default-fallback behavior on missing keys. Nothing material is omitted.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single 'key' parameter is fully documented in the schema (case-sensitivity, 256 char max, example). The description adds only 'by key', contributing nothing beyond the structured field, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource ('Reads one remote config value by key') with scope stated as a single value, and it explicitly contrasts with the sibling horizon_get_all_remote_configs. An agent can distinguish these two tools without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (single value / check one feature flag) and 'Not for' (loading many values at start → use horizon_get_all_remote_configs, one request instead of many), naming the exact alternative and the condition that selects it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_stateGet Player StateARead-onlyIdempotent
Returns the player's server-owned values (Validated Actions): balance, today's earnings and daily cap per value key, such as currency or loot counters. Use when: the game shows the wallet or checks whether a spend is possible before starting a run. Not for: changing balances: nothing writes a balance directly, only accepted runs through horizon_submit_validated with earned. Also not for the save game (use horizon_load_cloud_data). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only). Returns: {userId, day, values: [{key, balance, earnedToday, dailyCap}]}: every value key defined in the API key's rules, sorted by key (balance 0 when never earned); values is empty when the rules define no values. day is the current UTC day, earnedToday the positive credit on that day (0 after midnight UTC), dailyCap null without a daily cap; the other value rules stay hidden. Games may mirror the values into cloud save for offline display but must never send them back. Errors: The error result names the stable code: 401 SESSION_REQUIRED (sign in again), 403 SESSION_FORBIDDEN (pass the userId that signed in), 404 PLAYER_NOT_FOUND, 429 without code (account request limit, wait). Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* | |
| sessionToken | Yes | accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session |
Output Schema
| Name | Required | Description |
|---|---|---|
| day | No | |
| userId | No | |
| values | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description still adds substantial context beyond them: required session token sourcing, the UTC-day reset semantics of earnedToday, the 0-when-never-earned default, the empty-values case, and a full error taxonomy (401/403/404/429) with remediation. This is far richer than the annotation baseline.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose and organized under clear labels (Use when / Not for / Requires / Side effects / Returns / Errors), which aids scanning. It is on the long side and the Returns section overlaps the output schema, but for a tool with this many auth and error paths the length is largely earned.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity of session-authenticated reads with specific error codes, the description covers prerequisites, side-effect profile, return shape semantics, and failure handling. Even though an output schema exists, the added day/dailyCap/sorting semantics make it complete for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so userId and sessionToken are already documented in the schema; the description's 'Requires: userId and the player's session' largely restates that. It adds only the constraint that the session must come from a matching sign-in, which is marginal value over the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('Returns the player's server-owned values (Validated Actions)') and enumerates the concrete payload (balance, today's earnings, daily cap). It explicitly names siblings it is not (horizon_submit_validated, horizon_load_cloud_data), so an agent can separate it from the many horizon_* tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides an explicit 'Use when' trigger (wallet display, pre-spend check), an explicit 'Not for' exclusion with the correct alternative named for each case (horizon_submit_validated for writes, horizon_load_cloud_data for saves). Nothing about selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_statisticsGet Player StatisticsARead-onlyIdempotent
Reads a player's statistics snapshot and server operation window. Use when: explicit loading, reconnect recovery or checking an uncertain batch before retrying its original ID. Not for: writing counters; use horizon_update_statistics with the original durable ID. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only). Returns: {userId, definitionVersion, definitions, revision, values, operationWindow, operationId?, replayed?, newlyUnlocked}. definitions null means unchanged since definitionVersion; keep the cached definitions. Errors: 401 SESSION_REQUIRED: sign in again; 403 SESSION_FORBIDDEN: use the matching player. 409 OPERATION_CONFLICT means the ID was already used for a different payload. 410 OPERATION_EXPIRED rejects an expired/evicted unknown ID. Never replace an uncertain ID automatically. 422 UNKNOWN_STATISTIC/UPDATE_ABOVE_LIMIT/VALUE_OVERFLOW rejects the whole batch. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player UUID matching the supplied session token | |
| sessionToken | Yes | Player accessToken from horizon_signin_anonymous or horizon_signin_email; sent as Bearer | |
| definitionVersion | No | Last cached definitionVersion; omit to load the full catalog |
Output Schema
| Name | Required | Description |
|---|---|---|
| userId | Yes | |
| values | Yes | |
| replayed | No | |
| revision | Yes | |
| definitions | Yes | |
| operationId | No | |
| newlyUnlocked | Yes | |
| operationWindow | Yes | |
| definitionVersion | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/openWorld/non-destructive, yet the description goes further: it states how to obtain the sessionToken, documents the replayed?/operationId semantics, and enumerates error codes (401/403/409/410/422/429) with remediation. It also warns against auto-retrying an uncertain operation ID, which is guidance no annotation or schema field carries.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded statement of purpose followed by clearly labeled Use when / Not for / Requires / Side effects / Returns / Errors sections, so an agent can scan to the needed part. The errors section is dense and slightly over-long for a read call, which keeps it from a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even though an output schema exists, the description explains the non-obvious return fields (replayed?, newlyUnlocked, definitions caching) and covers auth, rate limits, and failure modes. Nothing an agent needs to invoke or interpret this call correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds value the schema lacks: it ties definitionVersion to response behavior ('definitions null means unchanged since definitionVersion; keep the cached definitions') and explains where sessionToken comes from. That causal explanation of the version parameter exceeds schema prose.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ('Reads a player's statistics snapshot and server operation window') and explicitly contrasts with the write sibling horizon_update_statistics. An agent can distinguish this from the mutation path without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use when: explicit loading, reconnect recovery or checking an uncertain batch before retrying its original ID' gives concrete triggering conditions, and 'Not for: writing counters; use horizon_update_statistics' names the alternative and the condition that selects it. Both when-to-use and when-not-to-use are present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_statistics_definitionsGet Statistics DefinitionsARead-onlyIdempotent
Reads the project's statistics catalog conditionally by version. Use when: showing counter labels, modes, reset policies and optional report bounds. Not for: loading player counter values; use horizon_get_statistics. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only). Returns: {definitionVersion, definitions}; definitions null means unchanged, an empty array means an empty catalog. Errors: 401 SESSION_REQUIRED: sign in again; 403 SESSION_FORBIDDEN: use the matching player. 409 OPERATION_CONFLICT means the ID was already used for a different payload. 410 OPERATION_EXPIRED rejects an expired/evicted unknown ID. Never replace an uncertain ID automatically. 422 UNKNOWN_STATISTIC/UPDATE_ABOVE_LIMIT/VALUE_OVERFLOW rejects the whole batch. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| sessionToken | Yes | Player accessToken from horizon_signin_anonymous or horizon_signin_email; sent as Bearer | |
| definitionVersion | No | Last cached definitionVersion; omit to load the full catalog |
Output Schema
| Name | Required | Description |
|---|---|---|
| definitions | Yes | |
| definitionVersion | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds real value beyond the annotations: the sign-in prerequisite and accessToken-as-sessionToken flow, the read-only side effect, and the meaningful return semantics (null definitions = unchanged, empty array = empty catalog). However, the long error block includes codes that do not apply to a read operation — 409 OPERATION_CONFLICT about an ID reused for a different payload, 410 OPERATION_EXPIRED about an evicted ID, and 422 UNKNOWN_STATISTIC/UPDATE_ABOVE_LIMIT 'rejects the whole batch' — which read like boilerplate from the statistics-update tool and could mislead an agent debugging a failed read.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The front half is well structured with labeled Use when / Not for / Requires / Returns / Errors sections and the key routing fact is front-loaded. The errors paragraph is disproportionately long and contains several irrelevant codes, undermining the conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Auth flow, read-only nature, and return semantics are all covered, and an output schema exists so return values needn't be spelled out in detail. The gap is the irrelevant update-oriented error codes, which make the error guidance untrustworthy for this specific read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters are already documented, including 'omit to load the full catalog'. The phrase 'conditionally by version' and the null-means-unchanged return note add modest context but no new syntax, format, or constraint beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Reads the project's statistics catalog') plus the version-conditional scope. It is clearly distinguishable from horizon_get_statistics, which the description explicitly names as the counter-values tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Has an explicit 'Use when' clause (counter labels, modes, reset policies, report bounds) and an explicit 'Not for' clause that routes the agent to horizon_get_statistics for player values. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_get_user_rankGet User RankARead-onlyIdempotent
Returns one player's own position, score and profile on a leaderboard. Use when: after horizon_submit_score, or to show 'your rank' in the game. Not for: a list of entries (use horizon_get_leaderboard_top or horizon_get_leaderboard_around). Requires: a userId from horizon_signup_* or horizon_signin_*; no session token. Side effects: None (read only). Returns: {position, username, score, profile}. profile is {avatarId, frameId, badges} (IDs from the cosmetics catalog; null or [] when not set, set with horizon_set_profile). Errors: 404 when the player has no score on this board yet (submit one first) or the leaderboardKey is unknown (check horizon_list_leaderboards). Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* | |
| leaderboardKey | No | Board key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board. |
Output Schema
| Name | Required | Description |
|---|---|---|
| score | No | |
| profile | No | |
| position | No | |
| username | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld), so the description goes beyond them by disclosing required auth (HORIZON_API_KEY), the 404 semantics (no score yet / unknown board) with remedies, and 401/429 failure handling including rate-limit advice. This is substantial behavioral context an agent cannot get from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) make it scannable and front-loaded with the core purpose first. The Errors sentence is dense and long, but each clause is actionable rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Although an output schema exists, the description still summarizes the return shape and profile sub-fields, and it covers auth, error taxonomy, and rate limits. Nothing an agent needs to select or invoke this tool correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both userId and leaderboardKey are fully documented in the schema (origin, format, default-board behavior). The description largely restates those origins rather than adding new syntax or value constraints, so the baseline 3 is correct.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Returns one player's own position, score and profile on a leaderboard') and immediately distinguishes itself from the sibling list tools by scope (single player's own rank vs. a list of entries). An agent can differentiate it from horizon_get_leaderboard_top/around without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit 'Use when' triggers (after horizon_submit_score, to show 'your rank') and an explicit 'Not for' with named alternatives (horizon_get_leaderboard_top, horizon_get_leaderboard_around). Preconditions are also spelled out (needs a userId, no session token).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_invite_group_playerinvite group playerAIdempotent
Applies the explicit invite group player action using the reviewed group revision. Use when: the player explicitly confirms this group action. Not for: replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Current group revision and the exact pending requestId where applicable. Side effects: Leader/officer creates an invitation and ordinary recipient Inbox notice atomically. No automatic retry. Same-revision replay cannot create a second effect. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| targetUserId | Yes | Other player in this project | |
| expectedRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds rich behavioral context beyond annotations: atomic invitation plus inbox notice, no automatic retry, same-revision replay safety, detailed return shape, cache replacement guidance, and extensive error semantics. These traits align with the annotations and significantly reduce uncertainty for a mutating tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded and organized into clear sections: purpose, usage, requirements, side effects, returns, and errors. It is long and somewhat repetitive ('no automatic retry' appears multiple times), but the density is justified by the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given five required parameters, mutation semantics, and no output schema, the description is remarkably complete. It explains the return shape, side effects, cache handling, authentication requirements, and error recovery paths, leaving little an agent would need to infer.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaningful context such as how to obtain the sessionToken via horizon_signin_email or horizon_signin_anonymous and how to treat expectedRevision. The mention of an 'exact pending requestId where applicable' is slightly confusing because no such parameter exists, but overall it adds value beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: it applies an invite action for a group player using a reviewed group revision. It is clear what the tool does, but it does not explicitly distinguish this action from sibling tools like horizon_request_group_join or horizon_accept_group_invite.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides explicit 'Use when' and 'Not for' guidance, including that the player must explicitly confirm the action and that automatic retries or revision replacement are prohibited. However, it does not name a specific sibling alternative for the invite action itself, only reconciliation tools for error handling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_join_groupjoin groupAIdempotent
Applies the explicit join group action using the reviewed group revision. Use when: the player explicitly confirms this group action. Not for: replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Current group revision and the exact pending requestId where applicable. Side effects: Joins an open group; checks member and player limits. No automatic retry. Same-revision replay cannot create a second effect. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| expectedRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: states it joins an open group, checks member and player limit constraints, performs no automatic retry, and that same-revision replay cannot double-effect (consistent with idempotentHint=true). It also documents 409 REVISION_CONFLICT, REQUEST_NOT_FOUND, INBOX_FULL rollback, 403 block violations, 429 rate limits and 401 session recovery — genuinely actionable failure behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The Use when / Not for / Requires / Side effects / Returns / Errors labels front-load well, but the block is very long and mixes tool-local guidance with account-level API key and rate-limit explanation. Several clauses (e.g. the 401/horizon_test_connection cross-check) could be trimmed without loss.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, describing the return shape ({groups: MyGroupsView, group: GroupView|null}) and privacy scoping is valuable and present, as are cache-invalidation and error-reconciliation instructions. The stray requestId reference is the one gap, since this tool takes no requestId.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description does add value by explaining how to obtain sessionToken via horizon_signin_email/anon and that expectedRevision must never be auto-replaced. However, it references 'the exact pending requestId where applicable', which does not exist in this tool's schema, muddying parameter expectations.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Applies the explicit join group action using the reviewed group revision') and the 'explicit' qualifier distinguishes it from horizon_request_group_join and horizon_accept_group_invite. The phrase 'join group action' is slightly jargon-heavy but an agent can select it correctly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (player explicitly confirms) and 'Not for' clauses (replacing revisions, bypassing leader block, automatic retry) give concrete inclusion and exclusion criteria. It never names the specific sibling to use instead for the open-vs-request-join decision, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_join_matchJoin MatchAIdempotent
Executes join match under the exact original revision. Use when: explicit asynchronous multiplayer actions after reading horizon://docs/matches. Not for: automatic polling, page traversal, timeout progression, invented winners or automatic rewards. Reconcile with horizon_get_matches and horizon_get_match. Consent and game consensus do not validate honest gameplay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt. Start requires the creator and every joined UUID exactly once. Turn requires the current unexpired actor. Timeout advances only one turn. Active leave forfeits without selecting a winner. Lobby cancel is creator-only. Full Inbox retains a durable notice without undoing a committed move. Returns: {match,pollAfterSeconds,serverTime}; departing lobby actors receive metadata only and lose point-read access. Errors: 404 hides private/missing/expired matches. 409 REVISION_CONFLICT or STATE_CONFLICT: explicitly reread and reconcile the original intent, never replace the revision or automatically resubmit. RESULT_CONFLICT preserves the original report. RUN_EXPIRED/RUN_ALREADY_USED never allow replacement ranked runs. 501 FEATURE_NOT_SUPPORTED is explicit for simpleServer ranked mode. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the session and project | |
| matchId | Yes | Original server match UUID in the selected project | |
| sessionToken | Yes | Player accessToken sent only as Bearer | |
| expectedRevision | Yes | Original reviewed revision; never substitute a newer revision after an uncertain write |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds substantial behavior beyond the annotations: authentication flow, HTTP attempt count, revision-conflict handling, result conflicts, expired sessions, missing API key, rate limits, and return shape. Although annotations already declare the safety profile, the description provides unusually rich operational context without clearly contradicting readOnlyHint=false, openWorldHint=true, idempotentHint=true, or destructiveHint=false.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but structured and front-loaded, with labeled Use, Not for, Requires, Side effects, Returns, and Errors sections. Most sentences carry relevant operational detail, though the side-effects list includes behavior for other match operations that may not belong to this tool and slightly increases cognitive load.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex authenticated write operation with no output schema, the description covers the missing return shape, error semantics, authentication prerequisites, conflict handling, and side effects. An agent has enough context to invoke it correctly and interpret common failure modes.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline would be 3, but the description adds meaningful semantics by linking sign-in to sessionToken and explaining that expectedRevision must remain the original reviewed revision. It adds less detail for matchId and userId beyond the schema, but the auth and revision guidance is useful.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence names a specific operation and concurrency condition: "Executes join match under the exact original revision." That is clear enough to identify the resource and action, though the side-effects section also describes start, turn, timeout, leave, and cancel behavior, which blurs whether this tool performs those operations or merely relates to them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit "Use when" and "Not for" guidance, including exclusion of polling, traversal, timeout progression, invented winners, and automatic rewards. It also names horizon_get_matches and horizon_get_match for reconciliation, but it does not explicitly distinguish join_match from sibling mutations such as start_match, submit_match_turn, or leave_match.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_leave_groupleave groupADestructiveIdempotent
Applies the explicit leave group action using the reviewed group revision. Use when: the player explicitly confirms this group action. Not for: replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Current group revision and the exact pending requestId where applicable. Side effects: Leaves membership. A leader must transfer first, unless sole member with no pending entries. No automatic retry. Same-revision replay cannot create a second effect. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| expectedRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare a destructive, idempotent, open-world write, but the description adds what they cannot: a leader must transfer ownership first unless they are the sole member, no automatic retry is allowed, and a clean replay of the same revision cannot create a second effect. It also explains error codes, including the 409 conflict and the INBOX_FULL rollback.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well front-loaded with Use when / Not for / Requires / Side effects / Returns / Errors labels, so the agent can scan each section quickly. The Errors paragraph is dense and long, but each sentence still carries operational value for a destructive call.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must carry the return values, and it does: it defines the {groups, group} shape, tells the agent that group is null after leaving, and explains that groups is the actor's full snapshot rather than the target's private state. Since this is a destructive, idempotent write, the description also covers auth setup, key handling and rate limits.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents all four parameters, which sets the baseline at 3. The description still adds useful meaning: sessionToken must come from a horizon_signin_* accessToken, expectedRevision is the exact reviewed revision that must not be silently refreshed, and the pending requestId carries the original decision identity.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Applies the explicit leave group action using the reviewed group revision.' This distinguishes it from siblings like horizon_remove_group_member or horizon_delete_group, though it never names those alternatives directly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit 'Use when' and 'Not for' clauses and names concrete exclusions: it must not replace reviewed revisions or request IDs, bypass a leader's block, or retry automatically. It also routes the agent to horizon_get_groups and horizon_get_group_pending for reconciliation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_leave_matchLeave MatchADestructiveIdempotent
Executes leave match under the exact original revision. Use when: explicit asynchronous multiplayer actions after reading horizon://docs/matches. Not for: automatic polling, page traversal, timeout progression, invented winners or automatic rewards. Reconcile with horizon_get_matches and horizon_get_match. Consent and game consensus do not validate honest gameplay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt. Start requires the creator and every joined UUID exactly once. Turn requires the current unexpired actor. Timeout advances only one turn. Active leave forfeits without selecting a winner. Lobby cancel is creator-only. Full Inbox retains a durable notice without undoing a committed move. Returns: {match,pollAfterSeconds,serverTime}; departing lobby actors receive metadata only and lose point-read access. Errors: 404 hides private/missing/expired matches. 409 REVISION_CONFLICT or STATE_CONFLICT: explicitly reread and reconcile the original intent, never replace the revision or automatically resubmit. RESULT_CONFLICT preserves the original report. RUN_EXPIRED/RUN_ALREADY_USED never allow replacement ranked runs. 501 FEATURE_NOT_SUPPORTED is explicit for simpleServer ranked mode. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the session and project | |
| matchId | Yes | Original server match UUID in the selected project | |
| sessionToken | Yes | Player accessToken sent only as Bearer | |
| expectedRevision | Yes | Original reviewed revision; never substitute a newer revision after an uncertain write |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructive/openWorld/idempotent, and the description adds substantive context beyond them: 'One HTTP attempt', 'Active leave forfeits without selecting a winner', creator-only lobby cancel, the durable Inbox notice that does not undo a committed move, plus the 429 rate-limit and HORIZON_API_KEY/auth failure modes. Nothing here contradicts the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The Use when / Not for / Requires / Side effects / Returns / Errors skeleton is well front-loaded, but the block is long and telegraphed as fragmented clauses. Several segments (Start requires the creator and every joined UUID, Turn requires the current unexpired actor, Timeout advances only one turn) describe actions this tool's schema cannot perform, which dilutes rather than focuses the definition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema, the description covers return shape, auth prerequisites, key error codes and rate limiting, so an agent has enough to call it correctly. The residual gap is resolving how this tool relates to the closely-named match siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description goes beyond the schema by spelling out that sessionToken must be the accessToken from horizon_signin_email/horizon_signin_anonymous and that the 403 case means the userId must match the token owner. It adds interpretation rather than format detail, earning a 4 but not a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening 'Executes leave match under the exact original revision' is close to restating the name, and the body then describes start/turn/timeout/lobby-cancel semantics that the 4-parameter schema cannot express. The verb+resource is identifiable, but an agent cannot cleanly tell what this tool does that horizon_cancel_match or horizon_submit_match_turn do not.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use when: explicit asynchronous multiplayer actions after reading horizon://docs/matches' and an explicit 'Not for: automatic polling, page traversal, timeout progression...' give real when/when-not guidance, and it names horizon_get_matches/horizon_get_match as the reconcile path. It does not address the nearest siblings (horizon_cancel_match, horizon_submit_match_turn, horizon_advance_match_timeout), which is why it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_list_leaderboardsList Leaderboard BoardsARead-onlyIdempotent
Lists the leaderboard boards of this API key with their keys, sort order and whether they accept only validated runs. Use when: first, when a game has several boards (weekly, per level) or before submitting, to learn the leaderboardKey values and whether a board is validatedOnly. Not for: reading entries (use horizon_get_leaderboard_top, horizon_get_user_rank or horizon_get_leaderboard_around). Side effects: None (read only). Returns: {boards: [{key, name, sortOrder, isActive, scoreCount, validatedOnly}], totalElements}. Pass a key as leaderboardKey to the submit, top, rank and around tools; without it they use the default board. validatedOnly true means scores are accepted only through horizon_start_run plus horizon_submit_validated. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| boards | No | |
| totalElements | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the description's 'Side effects: None (read only)' is redundant. It earns credit for the downstream-key contract ('pass a key as leaderboardKey... without it they use the default board') and the validatedOnly semantics, but the errors section partially overlaps with the output schema and general MCP error patterns.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then Use/Not-for/Side effects/Returns/Errors sections. Dense but well-organized. The errors paragraph names a specific 401/429 interplay with horizon_test_connection that is useful, though slightly verbose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema exists, the return values needn't be restated, yet the description does so anyway (helpful for agents that don't parse schemas). The auth/error contract (HORIZON_API_KEY, 401/429 semantics, test_connection cross-reference) fills a real gap for a zero-param read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so baseline is 4. The description adds value by explaining how returned keys are consumed by other tools, which is param-adjacent semantics not present in the (empty) schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource ('Lists the leaderboard boards of this API key') with the returned fields enumerated, and sibling tools for reading entries are named as out-of-scope. An agent can distinguish this discovery/listing tool from horizon_get_leaderboard_top without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' clauses (multiple boards, before submitting to learn leaderboardKey/validatedOnly) plus an explicit 'Not for' clause naming the three alternative tools for reading entries. This is the strongest form of routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_load_cloud_dataLoad Cloud DataARead-onlyIdempotent
Reads a player's save game that was stored with horizon_save_cloud_data. Use when: the game starts or the player switches devices and needs the saved progress. Not for: writing (use horizon_save_cloud_data) or balances of server-owned values (use horizon_get_state). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only). Returns: {found, saveData, revision}. found false with saveData null means the player never saved: this is normal on first start, so initialize default data. revision is the save's server revision (0 = empty slot, 1 after the first save): pass it as expectedRevision to horizon_save_cloud_data. revision null means the server sent none (unknown state, for example a self-hosted simpleServer), not an empty slot. Errors: 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* | |
| sessionToken | Yes | accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session |
Output Schema
| Name | Required | Description |
|---|---|---|
| found | No | |
| revision | No | |
| saveData | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only/idempotent/no-destruction, and the description goes well beyond them: prerequisite auth chain (sign in, pass accessToken as sessionToken), required HORIZON_API_KEY, and a concrete error taxonomy (401 re-sign-in, 403 user mismatch, 429 per-minute rate limit with retry advice). The only minor redundancy is 'Side effects: None (read only)', which restates readOnlyHint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Labeled, front-loaded sections (Use when / Not for / Requires / Side effects / Returns / Errors) make it scannable, and the precondition and routing information precede the detailed return and error semantics. Density is high with essentially no filler sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Although an output schema exists, the description supplies interpretation the schema cannot: found=false with null saveData is a normal first-start case requiring default init, revision 0 vs 1 vs null are distinguished, and revision is linked forward to expectedRevision on save. Auth, error, and state-machine context are all present for a two-parameter read.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real semantic constraints the schema cannot: sessionToken must be the accessToken issued for the same userId, and a 403 indicates the token belongs to a different user. It does not describe token lifetime or refresh beyond the 401 retry path.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Reads a player's save game') and ties it to the sibling that produced the data ('stored with horizon_save_cloud_data'). An agent can distinguish this read path from horizon_save_cloud_data and horizon_get_state without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' triggers (game start, device switch) and explicit 'Not for' exclusions that name the correct alternatives (horizon_save_cloud_data for writes, horizon_get_state for server-owned balances). Both directions of routing are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_mark_inbox_readMark Inbox Entry ReadADestructiveIdempotent
Marks an inbox entry read for the authenticated player. Use when: an explicit player action on an entry returned by horizon_get_inbox. Not for: changing the recipient or inventing attachment amounts. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Marks this entry read without claiming its reward. Returns: Updated complete inbox snapshot. Errors: 409 STATE_CONFLICT: retry the same entry ID. UNCLAIMED_REWARD: claim before removal. MAX_BALANCE_REACHED/DAILY_LIMIT_REACHED/INVENTORY_FULL leaves the reward or original item unclaimed. ENTRY_NOT_FOUND after removal/cleanup never grants again. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Player UUID belonging to the selected project and player session | |
| entryId | Yes | Exact stable entry ID from the inbox snapshot, including message: or broadcast: prefix | |
| sessionToken | Yes | Player accessToken, sent only as Authorization Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare mutation and openness, but the description adds substantial context: the side effect of marking read without claiming the reward, required authentication flow, session-token behavior, rate limits, API-key requirement, error result shape, and detailed HTTP/error semantics. It does not contradict the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded and clearly segmented into purpose, use cases, requirements, side effects, returns, and errors. It is dense but mostly earns its length because the auth and error details are operationally useful, though the error catalog is long and the attachment-amount exclusion is somewhat oddly scoped.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must explain returns and errors; it does both by stating that the tool returns an updated complete inbox snapshot and by cataloging authentication, conflict, reward, balance, inventory, and rate-limit failures. Given the complexity, it is complete enough for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning beyond the schema: sessionToken must be the accessToken from horizon_signin_email or horizon_signin_anonymous, and userId must be the one that signed in. It also reinforces that the same entry ID should be retried after a state conflict.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: marking an inbox entry read for the authenticated player. It also distinguishes the operation from nearby inbox actions by noting that it works on an entry from horizon_get_inbox and marks it read without claiming its reward.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit use criteria and exclusions: use when an explicit player action targets an entry returned by horizon_get_inbox, and not for changing the recipient or inventing attachment amounts. However, it does not directly name horizon_claim_inbox or horizon_remove_inbox as the alternatives for claiming or removing, though the error notes imply those workflows.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_open_chat_channelOpen Chat ChannelAIdempotent
Opens deterministic direct, group or project chat under current permissions. Use when: explicit hosted chat actions after reading horizon://docs/chat. Not for: automatic sends, repeated polling, rich-text rendering or exposing moderation credentials. Use horizon_get_chat_operation to reconcile original sends, then horizon_send_chat_message only for the explicit identical replay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt. Existing live open is a no-op. A new/expired channel allocates a fresh epoch under quota/rate gates. Subscribe before first sync/send. Returns: {channel,serverTime} Errors: 404 hides private/missing/expired channels or source messages. 409 OPERATION_CONFLICT/OPERATION_EXPIRED or STATE_CONFLICT requires explicit original-intent reconciliation. Never replace an unknown send UUID/time/text. 429 does not schedule a retry. CHAT_MUTED/CHAT_BANNED restrict current chat access. 501 NOT_SUPPORTED means simpleServer has no chat or polling fallback. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| kind | Yes | Chat audience under current friend or group permissions | |
| peerId | No | Required only for a direct channel with this other player | |
| userId | Yes | Active player matching the current session and project | |
| groupId | No | Required only for a channel of this current group | |
| sessionToken | Yes | Player accessToken sent only as Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare idempotent, non-destructive, open-world, so the bar is lower, yet the description still adds substantial context: single HTTP attempt, live-open no-op, epoch allocation under quota/rate gates, subscribe-before-sync ordering, and a full error taxonomy including 404/409/429/muted/501 semantics. It also flags the HORIZON_API_KEY dependency and the 401 vs 403 distinction for session tokens.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose and organized into labeled Use when/Not for/Requires/Side effects/Returns/Errors sections, which makes it easy to scan. The Errors paragraph is long and dense, bordering on kitchen-sink, but every clause carries operationally relevant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a state-changing, open-world chat tool with no output schema, the description covers returns ({channel, serverTime}), side effects, ordering requirements, auth provenance, and error recovery paths. An agent has essentially everything needed to call this correctly and handle failures.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents kind, peerId, groupId, userId and sessionToken, including the conditional-required semantics. The description only restates that userId and sessionToken are required and where the token comes from; it adds little on peerId/groupId conditional behavior beyond what the schema says, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence gives a specific verb (opens) and resource (deterministic direct, group or project chat) with a scoping condition (under current permissions). It clearly separates this from related siblings, and the subsequent 'use when/not for' framing makes the boundary unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use (explicit hosted chat actions after reading the docs), when not to use (automatic sends, polling, rendering, credential exposure), and names the exact alternatives: horizon_get_chat_operation for reconciliation and horizon_send_chat_message only for identical replay.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_prepare_gift_codePrepare Gift Code IntentARead-onlyIdempotent
Reads a compact V2 campaign identity and exact current sequence without reserving or consuming a redemption. Use when: starting an explicit new action after prior outcomes are resolved; persist the returned intent before horizon_redeem_gift_code. Not for: recovering an uncertain action; retry its saved original intent with horizon_redeem_gift_code instead. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only); no server intent or reservation is stored. Returns: {valid,intent}; intent is null when invalid, otherwise exactly protocolVersion,projectScope,userId,code,campaignId,expectedCount,configRevision. Counts/revisions are exact Int64 decimal strings; projectScope binds the local host/project without exposing credentials. Persist all seven fields, never the session token. Errors: 409 UPGRADE_REQUIRED closes V1; MIGRATION_REQUIRED needs operator migration; COUNT_AHEAD, CAMPAIGN_CHANGED, COUNTER_EXHAUSTED and STATE_CONFLICT require explicit reconciliation. Keep the original intent on every uncertain outcome, never prepare or advance automatically. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Original visible gift code, retained with the prepared campaign identity | |
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* | |
| sessionToken | Yes | Current accessToken of the intent's original user, sent only as a Bearer header |
Output Schema
| Name | Required | Description |
|---|---|---|
| valid | No | |
| intent | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the read-only annotations, the description clarifies that no server intent or reservation is stored and that all seven returned identity fields must be persisted while the session token must not be. It also documents authentication requirements, token provenance, rate-limit behavior, and specific error meanings, giving the agent unusually rich behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well structured around Use when, Not for, Requires, Side effects, Returns, and Errors, with the core purpose front-loaded. The length is largely justified by the operation's many error and recovery conditions, though the extensive error catalogue is denser than strictly necessary.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has an output schema, but the description still gives a precise return summary: valid plus intent, with intent null when invalid and otherwise containing exactly seven persisted fields. Combined with authentication, side-effect, and error details, the description is complete enough for correct invocation and handling.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Input schema coverage is 100%, so the schema already explains the three parameters. The description adds useful semantics beyond the schema by explaining that sessionToken is the accessToken from horizon_signin_email or horizon_signin_anonymous, that userId must match the signed-in user, and that the token is sent only as a Bearer header.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific operation on a specific resource: preparing a V2 campaign gift-code intent by reading identity and sequence without reserving or consuming a redemption. It clearly distinguishes this from recovery and redemption paths by directing uncertain cases to horizon_redeem_gift_code with the saved intent.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states when to use the tool: starting a new action after prior outcomes are resolved, and persisting the returned intent before redemption. It also states when not to use it: recovering an uncertain action should retry the saved original intent with horizon_redeem_gift_code instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_purchase_player_value_offerPurchase Player Value OfferADestructiveIdempotent
Purchases one configured offer with atomic costs and value/item rewards, retaining only a minimal public duplicate guard. Use when: a player confirms an offer returned by horizon_get_player_value_offers. Not for: choosing arbitrary costs or rewards; only the server's configured offer is accepted. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Persist operationId before the first request. Side effects: Debits and credits together once. Same ID and body replay without another debit; no automatic retries or new IDs. Returns: Current state with operation:{operationId,replayed,alreadyApplied,applied,items}. Fresh success contains committed deltas and new item references; replay has empty applied/items. Never add an old reward delta locally. Errors: 409 STATE_CONFLICT: refresh state and retry the SAME operation ID and payload. OPERATION_CONFLICT: do not reuse an ID for a different action. OPERATION_EXPIRED: reconcile state/history; never silently generate another ID. INSUFFICIENT_BALANCE, MAX_BALANCE_REACHED or DAILY_LIMIT_REACHED leaves the whole operation unapplied. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Player UUID belonging to the selected project and player session | |
| offerKey | Yes | Configured value or offer key, 1 to 24 lowercase letters, digits, '.', '_' or '-' | |
| operationId | Yes | Stable operation ID: server-aligned Unix milliseconds + ':' + UUID. Persist before sending; reuse unchanged on timeout or retry | |
| sessionToken | Yes | Player accessToken from sign-in, sent only in the Authorization Bearer header |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructive=true and idempotent=true, but the description goes well beyond them: atomic debit+credit, replay-by-same-ID semantics with no automatic retry, distinct fresh-vs-replay return shapes, and a specific error taxonomy (409/OPERATION_CONFLICT/OPERATION_EXPIRED/INSUFFICIENT_BALANCE/401/403/429) with recovery instructions. Nothing here contradicts the annotations; the destructive and idempotent hints are actively explained.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded and clearly segmented into Use when / Not for / Requires / Side effects / Returns / Errors. It is long, but for a destructive monetary operation with no output schema most sentences carry operational weight; the only mild redundancy is the repeated warning about not generating a new operation ID ('no automatic retries or new IDs' vs. 'never silently generate another ID').
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With four required parameters, no output schema, and destructive+idempotent semantics, the description covers everything an agent needs: auth acquisition path, API key requirement, idempotency contract, return shape including the operation object, and failure handling for each documented status. Nothing material is left to inference.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description still adds real value by stating where each value comes from (offerKey from horizon_get_player_value_offers, sessionToken from horizon_signin_email/anonymous) and by emphasizing the operationId lifecycle ('persist before the first request', never mint a new ID on conflict/expiry). That is meaningful guidance beyond the schema's field-level text, though the schema already documents operationId formatting and reuse fairly well.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource ('Purchases one configured offer') and immediately scopes it ('atomic costs and value/item rewards, retaining only a minimal public duplicate guard'). It also names the sibling that produces the input (horizon_get_player_value_offers), so the agent can distinguish this from the read-side offer tool without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' and 'Not for' clauses: only after a player confirms an offer returned by horizon_get_player_value_offers, and never for arbitrary cost/reward selection. This is exactly the when/when-not/alternative structure that routes an agent correctly among 100+ siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_query_marketplace_listingsQuery Marketplace ListingsARead-onlyIdempotent
Reads one bounded active-listing page by item and price. Use when: explicit marketplace actions after reading horizon://docs/marketplace. Not for: automatic trading, price polling or generated replacement operations. Use horizon_get_marketplace_operation to reconcile the original intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Read only, up to 256 candidates and 50 returned listings. An empty page can carry a continuation cursor. Returns: {listings,nextCursor,serverTime} Errors: 409 conflicts require explicit reconciliation, never fresh revisions or operation IDs on an unknown outcome. Missing OPERATION_NOT_FOUND does not prove nonexecution. 422 capacity/balance/daily-limit errors preserve atomicity. 429 schedules no retry. Full Inbox returns pending without losing the original item. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | One explicit bounded page, never automatic traversal | |
| cursor | No | Original cursor with identical filters; an empty page may still have continuation | |
| userId | Yes | Active player matching the current session and project | |
| itemKey | No | Optional exact template key | |
| maxPrice | No | Inclusive safe-integer maximum price | |
| minPrice | No | Inclusive safe-integer minimum price, default zero | |
| sessionToken | Yes | Current accessToken sent only as Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive behavior, but the description adds valuable limits (256 candidates/50 returned listings), continuation-cursor semantics, return shape, auth token requirement, and error handling. However, the long error block includes several mutation-oriented cases (409 conflicts, 422 capacity/balance errors, 'Full Inbox returns pending') that appear irrelevant to a read-only listing query and slightly muddy the behavioral picture.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with labeled sections ('Use when', 'Requires', 'Side effects', 'Returns', 'Errors'), which aids scanning. But the Errors paragraph is a dense run-on with several cases unrelated to a read-only listing query, so not every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, but the description supplies the return shape ({listings,nextCursor,serverTime}), auth flow, pagination limits, and cursor behavior. The main completeness issue is that the extraneous error details could distract an agent from the relevant read-only path.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for all 7 parameters, so the schema already defines limit, cursor, userId, itemKey, minPrice/maxPrice, and sessionToken semantics. The description echoes 'by item and price' and bounded-page behavior but adds no new parameter-level meaning beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence gives a specific verb ('Reads'), a precise resource ('one bounded active-listing page'), and filter axes ('by item and price'), which clearly distinguishes it from horizon_get_marketplace_listing (single listing) and horizon_get_marketplace_operation (reconciliation).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It has explicit 'Use when' and 'Not for' clauses excluding automatic trading and price polling, names horizon_get_marketplace_operation as the alternative for reconciliation, and prescribes the sign-in/auth flow via horizon_signin_email or horizon_signin_anonymous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_redeem_gift_codeRedeem Prepared Gift CodeAIdempotent
Consumes the original persisted V2 campaign/player sequence once and returns current authoritative state on replay. Use when: an explicit consume or retry of the exact seven-field intent previously returned by horizon_prepare_gift_code and durably saved. Not for: preparing or advancing a counter after uncertainty; horizon_validate_gift_code alone does not produce an intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Fresh redemption and rewards commit atomically. Identical intent retries share one logical sequence slot. No automatic retry or preparation occurs. Returns: {success,campaignId,count,configRevision,alreadyApplied,replayed,giftData,grantedValues,grantedUnlocks,playerValues}. Fresh count is expectedCount+1 at the original revision. Replay has current count/state, null giftData and empty grants. Replace balances from playerValues; never add rewards locally. Remove only this exact confirmed intent; malformed replies leave it unresolved. Errors: 409 UPGRADE_REQUIRED closes V1; MIGRATION_REQUIRED needs operator migration; COUNT_AHEAD, CAMPAIGN_CHANGED, COUNTER_EXHAUSTED and STATE_CONFLICT require explicit reconciliation. Keep the original intent on every uncertain outcome, never prepare or advance automatically. V1 arguments return local UPGRADE_REQUIRED without HTTP; mixed forms return INVALID_REQUEST. A changed local host/project returns PROJECT_SCOPE_CHANGED. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| code | No | Obsolete V1 argument, rejected with UPGRADE_REQUIRED; use the original saved intent | |
| intent | No | Required V2 recovery object: the exact seven fields durably saved from horizon_prepare_gift_code; never retarget or advance it | |
| userId | No | Obsolete V1 argument, rejected with UPGRADE_REQUIRED; the original owner is inside intent | |
| sessionToken | Yes | Current accessToken of the intent's original user, sent only as a Bearer header | |
| idempotencyId | No | Obsolete arbitrary V1 ID, never translated to a V2 sequence; rejected without HTTP |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Although annotations already establish non-read-only, open-world, idempotent, and non-destructive behavior, the description adds substantial context: atomic reward commit, shared logical sequence slots on identical retries, no automatic retry/preparation, replay semantics, and what to do on uncertain outcomes. It also maps authentication and rate-limit failures to concrete next steps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose, usage, requirements, side effects, returns, and errors, which is appropriate for a complex idempotent recovery tool. It is very dense and repeats the 'never prepare or advance automatically' guidance in both the Returns and Errors sections, so it is not maximally concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, but the description supplies the return shape, replay-specific return behavior, error mapping, authentication requirements, and recovery guidance. Given the complexity of the mutation/idempotency semantics, it is complete enough for an agent to call and interpret results correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already defines all five parameters and nested intent fields. The description still adds useful semantic constraints: the intent must be the exact saved seven-field object, obsolete V1 arguments are rejected locally, and sessionToken must belong to the intent's original user. Slight ambiguity remains because 'Requires: userId' could be confused with the obsolete top-level userId, though the intent context clarifies it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a precise verb and resource: consuming the persisted V2 campaign/player sequence and returning authoritative state on replay. It explicitly distinguishes this tool from `horizon_prepare_gift_code` and `horizon_validate_gift_code`, so an agent can identify its role without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use guidance: only for consuming or retrying the exact seven-field intent previously returned by `horizon_prepare_gift_code` and durably saved. It also gives explicit when-not-to-use guidance, including not preparing or advancing after uncertainty, and clarifies that validate alone does not produce an intent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_remove_friendRemove FriendADestructiveIdempotent
Removes Friend using the reviewed player revision. Use when: the player explicitly requests this social action. Not for: automatic retries after timeout, automatic acceptance of crossed requests or changing expectedRevision without reconciling intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. A current snapshot revision. Side effects: Removes the friendship on both sides. Pending requests and blocks remain unchanged. No automatic retry. Repeating the same revision cannot create a second effect. Returns: Complete {userId,revision,friendCode,friends,incoming,outgoing,blocked,limits,serverTime} snapshot. Replace the matching host/project/player cache. lastActiveAt is the latest retained login, null when unknown; it is not online presence. Errors: 409 REVISION_CONFLICT or an uncertain response: get a new snapshot and reconcile intent, never silently replace expectedRevision and repeat. 404 FRIEND_REQUEST_NOT_FOUND means this request was removed or replaced; do not act on a newer ID. INBOX_FULL rejects the entire send/accept. Friend/request/block capacity limits reject additions while existing data remains removable. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player UUID matching the session | |
| sessionToken | Yes | Player accessToken sent only as Authorization Bearer | |
| targetUserId | Yes | The other player UUID in the same project | |
| expectedRevision | Yes | Exact revision from the reviewed actor snapshot; never refresh and substitute automatically |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already identify this as destructive, idempotent, non-read-only, and open-world, but the description adds substantial context beyond them: it explains that removal affects both sides, that pending requests and blocks are unchanged, that there is no automatic retry, and that repeating the same revision cannot create a second effect. It also covers authentication requirements, error behavior, rate limiting, and conflict handling in detail.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but highly structured and front-loaded: purpose, usage, requirements, side effects, return value, and errors appear in a logical order. Every section provides actionable information for a complex destructive social operation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a four-parameter destructive mutation with no output schema, the description is complete: it explains authentication, revision semantics, exact side effects, returned snapshot contents, cache replacement, and error recovery paths. Nothing critical for correct invocation appears to be missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all four parameters, including userId, sessionToken, targetUserId, and expectedRevision. The description adds some useful context, such as obtaining the session token via sign-in and treating expectedRevision as a reviewed snapshot, but most parameter meaning is already provided by the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ("Removes Friend") and clarifies the revision-scoped nature of the operation. It also distinguishes the effect from related social actions by noting that pending requests and blocks remain unchanged.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use guidance ("the player explicitly requests this social action") and explicit when-not-to-use guidance for automatic retries, crossed requests, and unreconciled revision changes. The error section reinforces the correct alternative path for 409 conflicts.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_remove_group_memberremove group memberADestructiveIdempotent
Applies the explicit remove group member action using the reviewed group revision. Use when: the player explicitly confirms this group action. Not for: replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Current group revision and the exact pending requestId where applicable. Side effects: Leader removes an officer/member; an officer can remove only a member. No automatic retry. Same-revision replay cannot create a second effect. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| targetUserId | Yes | Other player in this project | |
| expectedRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: states the role hierarchy that governs who can be removed, that no automatic retry is performed, that a same-revision replay cannot create a second effect (concrete idempotency semantics), that INBOX_FULL rolls back the whole action, and that returned groups data is the actor's snapshot only. Auth provenance (signin accessToken as sessionToken) and 401/403/429 semantics are all disclosed without contradicting readOnly=false, destructive=true, idempotent=true.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well structured with labeled clauses (Use when / Not for / Requires / Side effects / Returns / Errors) and front-loaded routing information, but roughly 350 words for a five-parameter call. The error block repeats generic account-level guidance (HORIZON_API_KEY wrongness, per-minute rate limiting) that applies to every tool in the family rather than to this one.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, revision-guarded mutation with no output schema, the description covers auth, authorization, rollback, idempotency, return shape and the 409/401/403/429 error paths, which is close to complete. The dangling requestId reference is the one inconsistency an agent could trip over.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: sessionToken comes from horizon_signin_email/anonymous's accessToken, and expectedRevision is the 'reviewed' revision that must never be refreshed and replayed after an uncertain response. One gap: it refers to 'the exact pending requestId where applicable' although no requestId parameter exists in the schema, which could confuse the agent.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The verb+resource ('remove group member') is unambiguous, and the side-effects line distinguishes the two authority cases (leader removes officer/member; officer removes only member), which separates it from horizon_leave_group (self-leave) and horizon_set_group_member_role. The opening sentence, however, largely restates the tool name ('Applies the explicit remove group member action'), so the differentiation arrives later than it should.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (player explicitly confirms this group action) and 'Not for' clauses (replacing reviewed revisions/request IDs, bypassing a leader's block, automatic retry) set hard boundaries. It also names the reconciliation alternatives, horizon_get_groups and horizon_get_group_pending, for the conflict path, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_remove_inboxRemove Inbox EntryADestructiveIdempotent
Removes an eligible inbox entry for the authenticated player. Use when: an explicit player action on an entry returned by horizon_get_inbox. Not for: changing the recipient or inventing attachment amounts. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Removes ordinary or already-claimed entries. Unclaimed valuable attachments are protected. Removal does not create a new claim opportunity. Returns: Updated complete inbox snapshot. Errors: 409 STATE_CONFLICT: retry the same entry ID. UNCLAIMED_REWARD: claim before removal. MAX_BALANCE_REACHED/DAILY_LIMIT_REACHED/INVENTORY_FULL leaves the reward or original item unclaimed. ENTRY_NOT_FOUND after removal/cleanup never grants again. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Player UUID belonging to the selected project and player session | |
| entryId | Yes | Exact stable entry ID from the inbox snapshot, including message: or broadcast: prefix | |
| sessionToken | Yes | Player accessToken, sent only as Authorization Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover destructive/idempotent/openWorld, but the description adds real context: protected unclaimed valuable attachments, no new claim opportunity, 409 retry semantics, and per-error recovery paths (401 re-sign-in, 403 userId mismatch, HORIZON_API_KEY dependency, 429 rate limit).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) keep it front-loaded and scannable, but the error paragraph is dense and the 401 explanation is stated twice, which is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive mutation with no output schema, the description supplies the return value ('updated complete inbox snapshot'), auth prerequisites, failure taxonomy, and side-effect boundaries — nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so the baseline is 3, but the description adds derivation rules beyond the schema: sessionToken must come from horizon_signin_email/horizon_signin_anonymous, and userId must be the one that signed in (403 otherwise); entryId retry only with the same ID.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Removes an eligible inbox entry') scoped to the authenticated player, and the 'eligible' qualifier plus the 'Not for' clause separate it from horizon_claim_inbox, horizon_mark_inbox_read and horizon_get_inbox.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (an explicit player action on an entry returned by horizon_get_inbox) and 'Not for' exclusions (changing recipient, inventing attachment amounts), and the UNCLAIMED_REWARD error routes the agent to horizon_claim_inbox first.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_report_chat_messageReport Chat MessageAIdempotent
Reports one currently visible message with the original reason. Use when: explicit hosted chat actions after reading horizon://docs/chat. Not for: automatic sends, repeated polling, rich-text rendering or exposing moderation credentials. Use horizon_get_chat_operation to reconcile original sends, then horizon_send_chat_message only for the explicit identical replay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt. Retains one immutable shared report snapshot under current project capacity. Same-original replay uses that retained report; after removal, a still-visible original message may be reported only by another explicit action under current permission/rate checks (one new report/player/minute). Missing original messages cannot reopen reports. No per-player receipt history or implicit retry. Returns: {reportId,status,replayed,serverTime} Errors: 404 hides private/missing/expired channels or source messages. 409 OPERATION_CONFLICT/OPERATION_EXPIRED or STATE_CONFLICT requires explicit original-intent reconciliation. Never replace an unknown send UUID/time/text. 429 does not schedule a retry. CHAT_MUTED/CHAT_BANNED restrict current chat access. 501 NOT_SUPPORTED means simpleServer has no chat or polling fallback. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| reason | Yes | Original plain Unicode text, at most 240 scalars and 960 UTF-8 bytes | |
| userId | Yes | Active player matching the current session and project | |
| channelId | Yes | Original canonical lowercase UUID | |
| messageId | Yes | Original canonical lowercase UUID | |
| sessionToken | Yes | Player accessToken sent only as Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (which only say non-read-only, idempotent, non-destructive, open-world): one HTTP attempt, an immutable retained report snapshot, replay reusing that snapshot, the one-new-report-per-player-per-minute rate limit, no receipt history, and no implicit retry. The error semantics (404 masking, 409 conflict handling, 429 not scheduling retries, 501 no fallback) and the auth/key requirements are exactly the operational context an agent needs. No contradiction with idempotentHint=true, since same-original replay is described as reusing the retained report.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and use-when, then requirement/side-effect/return/error blocks in a predictable order. It is dense and long, with minor duplication (HORIZON_API_KEY and 401 handling appear in both the requirements and errors sections), but almost every clause carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a five-required-param mutation with no output schema, the description supplies the return shape ({reportId,status,replayed,serverTime}), auth prerequisites, side effects, idempotency semantics, and a full error-to-action mapping. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds real meaning: userId and sessionToken must come from a signin call's accessToken, and channelId/messageId must be the original canonical UUIDs that must never be replaced with unknown values. It does not add nuance on the 480-char reason cap beyond what the schema already states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with scope: 'Reports one currently visible message with the original reason.' It also names the siblings it is not (horizon_get_chat_operation, horizon_send_chat_message), so an agent can route correctly. It stops short of 5 because the nature of a 'report' (moderation flag creating an immutable snapshot) only becomes clear later in the side-effects section rather than in the opening sentence.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly gives when-to-use ('explicit hosted chat actions after reading horizon://docs/chat') and when-not ('automatic sends, repeated polling, rich-text rendering or exposing moderation credentials'). It then names the alternative tools and the exact ordering: reconcile with horizon_get_chat_operation, then horizon_send_chat_message only for an identical replay.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_report_match_resultReport Match ResultAIdempotent
Records this participant's immutable report for the frozen final state. Use when: explicit asynchronous multiplayer actions after reading horizon://docs/matches. Not for: automatic polling, page traversal, timeout progression, invented winners or automatic rewards. Reconcile with horizon_get_matches and horizon_get_match. Consent and game consensus do not validate honest gameplay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt, original finalStateRevision/result/winnerIds on explicit retry. All accepted players must agree for confirmed. Missing reports become unconfirmed, disagreements disputed. No automatic reward. Returns: {match,replayed,pollAfterSeconds,serverTime} Errors: 404 hides private/missing/expired matches. 409 REVISION_CONFLICT or STATE_CONFLICT: explicitly reread and reconcile the original intent, never replace the revision or automatically resubmit. RESULT_CONFLICT preserves the original report. RUN_EXPIRED/RUN_ALREADY_USED never allow replacement ranked runs. 501 FEATURE_NOT_SUPPORTED is explicit for simpleServer ranked mode. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the session and project | |
| matchId | Yes | Original server match UUID in the selected project | |
| winnerIds | Yes | Sorted accepted winners; empty means draw | |
| resultBase64 | Yes | Original opaque bytes, including empty state. Never interpret or silently replace them | |
| sessionToken | Yes | Player accessToken sent only as Bearer | |
| finalStateRevision | Yes | Original reviewed revision; never substitute a newer revision after an uncertain write |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the mutation profile (readOnlyHint false, idempotentHint true), but the description adds substantial context beyond them: one HTTP attempt, preservation of the original revision/result/winnerIds on explicit retry, consensus semantics (all accepted players must agree for confirmed), unconfirmed/disputed outcomes, and no automatic reward. The detailed error taxonomy (404/409 variants, 501, 401, 403, 429) with prescribed recovery behavior is unusually rich. It stops short of 5 only because the 'Not for' and 'Side effects' sections repeat the no-automatic-reward point.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded and clearly segmented with labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors), so an agent can scan to the part it needs. It is long and contains some redundancy — 'automatic rewards' is excluded in the Not-for list and again as 'No automatic reward' under Side effects — which costs a point.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a six-required-parameter mutation with no output schema, the description covers prerequisites (userId, sessionToken sourcing, HORIZON_API_KEY), side effects, the return shape {match,replayed,pollAfterSeconds,serverTime}, and every documented failure mode with recovery steps. An agent has everything needed to call it correctly and to recover from a 409 without corrupting state.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds two things the schema does not: the cross-parameter relationship that sessionToken must be the accessToken from horizon_signin_email/horizon_signin_anonymous, and the immutability rule that finalStateRevision/result/winnerIds must never be substituted on an uncertain write. Those constraints materially change how an agent fills and re-fills the parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — 'Records this participant's immutable report for the frozen final state' — which is unambiguous and distinct from siblings like horizon_submit_match_turn or horizon_advance_match_timeout. It also implicitly scopes itself to the final-state phase of a match, so an agent can tell it apart from turn submission without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (explicit asynchronous multiplayer actions after reading horizon://docs/matches) and 'Not for' (automatic polling, page traversal, timeout progression, invented winners, automatic rewards), plus a direct routing instruction to reconcile with horizon_get_matches and horizon_get_match. This is the full when/when-not/alternative triad.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_request_group_joinrequest group joinAIdempotent
Applies the explicit request group join action using the reviewed group revision. Use when: the player explicitly confirms this group action. Not for: replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Current group revision and the exact pending requestId where applicable. Side effects: Creates a join request and ordinary leader Inbox notice atomically. No automatic retry. Same-revision replay cannot create a second effect. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| expectedRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds substantial behavior beyond the annotations: it explains the atomic creation of a join request and leader Inbox notice, same-revision replay safety, no automatic retry, auth requirements, rate-limit handling, and detailed error reconciliation paths. These details are useful for a mutating, open-world action and align with idempotentHint=true and readOnlyHint=false.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded and well-structured with Use when, Not for, Requires, Side effects, Returns, and Errors sections. It is somewhat verbose and repeats no-retry and 401 concepts, but most of the length is justified by the mutation/auth/error complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description appropriately explains the returned groups/group shape and null cases, and it covers auth, side effects, retry constraints, and key errors. The only notable gap is the mention of a requestId that is absent from the schema, which weakens completeness for parameter-level guidance.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all four parameters and the baseline is 3. The description adds useful context about obtaining sessionToken via sign-in and never auto-replacing expectedRevision, but it also refers to an 'exact pending requestId' that is not present in the input schema, which may confuse parameter usage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence names the action as an explicit request group join using a reviewed revision, which gives a specific verb/resource combination. It does not explicitly distinguish this from nearby siblings such as horizon_join_group or horizon_accept_group_invite, so an agent still has to infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear 'Use when' condition (player explicitly confirms the action) and explicit exclusions around replacing revisions/request IDs, bypassing leader blocks, and automatic retry. It names horizon_get_groups and horizon_get_group_pending for reconciliation, but it does not directly state when to use this instead of horizon_join_group or accept/decline request siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_retry_marketplace_returnAttempt Original Item Return DeliveryAIdempotent
Attempts one explicitly requested pending return delivery for the current return owner. Use when: explicit marketplace actions after reading horizon://docs/marketplace. Not for: automatic trading, price polling or generated replacement operations. Use horizon_get_marketplace_operation to reconcile the original intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt. Full Inbox leaves durable pending escrow; successful delivery still needs Inbox claim with inventory space. Does not recreate or claim the original item. Returns: {listing,delivery:pending|delivered|returned,serverTime} Errors: 409 conflicts require explicit reconciliation, never fresh revisions or operation IDs on an unknown outcome. Missing OPERATION_NOT_FOUND does not prove nonexecution. 422 capacity/balance/daily-limit errors preserve atomicity. 429 schedules no retry. Full Inbox returns pending without losing the original item. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the current session and project | |
| listingId | Yes | Original canonical lowercase UUID | |
| sessionToken | Yes | Current accessToken sent only as Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it discloses that only one HTTP attempt is made, that a full Inbox leaves durable pending escrow and still requires an inventory-space claim, that the original item is neither recreated nor claimed, and it maps out 401/403/409/422/429 semantics plus the HORIZON_API_KEY prerequisite. This is exactly the mutation-consequence and auth context the readOnlyHint/destructiveHint fields cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The Use when / Not for / Requires / Side effects / Returns / Errors labelling is front-loaded and scannable, which is good. However, it is very dense and repeats itself: 429 and 401 are each covered twice with slightly different framing ('429 schedules no retry' vs 'wait a minute, then retry'), which adds noise to an already long block.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema and only three annotations, the description supplies the auth chain, the return shape ({listing,delivery,serverTime}), the escrow/claim consequence and the full error taxonomy. An agent has everything needed to call it and to interpret a failure.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so userId, listingId and sessionToken are already documented with formats and constraints. The description adds marginal value by tying sessionToken to the accessToken from horizon_signin_email/horizon_signin_anonymous and requiring the userId that signed in (relevant to the 403 case), but it adds no per-parameter syntax beyond that. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Attempts one explicitly requested pending return delivery for the current return owner.' It also explicitly disclaims automatic trading, price polling and generated replacements, and names horizon_get_marketplace_operation for reconciliation, so it is separable from siblings. The domain jargon ('return owner', 'pending return delivery') presumes the marketplace doc, keeping it just below top marks.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Has an explicit 'Use when' clause (explicit marketplace actions after reading horizon://docs/marketplace), an explicit 'Not for' exclusion list (automatic trading, price polling, generated replacements), and a named alternative (horizon_get_marketplace_operation) for the reconcile case. When-to-use, when-not-to-use and alternative routing are all present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_save_cloud_dataSave Cloud DataADestructiveIdempotent
Stores a player's save game as one string (usually JSON) on the server, replacing the player's previous save. Use when: the game saves progress so it survives reinstalls and can be loaded on another device. Pass expectedRevision (the revision from horizon_load_cloud_data or the last save) so a save from another device is never overwritten silently. Not for: reading the save (use horizon_load_cloud_data) or server-owned currency that players must not edit (use Validated Actions: horizon_submit_validated and horizon_get_state). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: overwrites the player's single save slot; the old save is gone. With expectedRevision it only writes while the save is still at that revision. Saving the same data again changes nothing. Returns: {success: true, dataSizeBytes, revision}. revision is the new revision: pass it as expectedRevision to the next save. Errors: 409 (only with expectedRevision) when another device saved first: nothing was written, load the current save and revision, decide, then save again. 403 when the data exceeds the tier limit (defaults FREE 1 KB, BASIC 5 KB, PRO 20 KB, ENTERPRISE 250 KB): shrink the save or upgrade. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| data | Yes | The complete save as a string, usually serialized JSON (max 300,000 characters; the tier limit is usually lower) | |
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* | |
| sessionToken | Yes | accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session | |
| expectedRevision | No | Optional. Revision the save must still have, sent as If-Match: 0 for an empty slot, else the revision from horizon_load_cloud_data or the last save. Omit for an unconditional overwrite. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond annotations (destructiveHint/idempotentHint are already declared) by specifying what is destroyed ('the old save is gone'), the single-slot model, the compare-and-swap behavior of expectedRevision, the no-op on identical data, and the tier size caps. Error handling (409/403/401/429 and what each means for retry) is spelled out, which is exactly the added context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded with labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors), so an agent can scan to the relevant part. It is on the long side and the error paragraph packs several unrelated failures into one run-on block, but nearly every sentence carries actionable information rather than restating the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers a destructive mutation with no output schema by describing the return shape ({success, dataSizeBytes, revision}), the revision chaining requirement, dependency on HORIZON_API_KEY and a session token, size limits per tier, and each failure mode's remedy. Nothing an agent needs to call this safely is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and each parameter is documented, so the schema does most of the work. The description still adds real meaning: it explains the expectedRevision round-trip ('pass the revision from load or last save'), the 0-for-empty-slot case, and how to recover from a 409. It does not add much for userId/sessionToken beyond what the schema says.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb+resource ('Stores a player's save game as one string ... on the server, replacing the player's previous save') and immediately contrasts with the read path via horizon_load_cloud_data. The single-slot replacement semantics are explicit, so an agent can distinguish it from every sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Has explicit 'Use when' and 'Not for' sections that name the alternatives (horizon_load_cloud_data for reading, horizon_submit_validated/horizon_get_state for server-owned currency that players must not edit). It also names the prerequisite sign-in tools, so selection and sequencing are unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_send_chat_messageSend Original Chat MessageADestructiveIdempotent
Sends plain text once or explicitly replays the exact original operation. Use when: explicit hosted chat actions after reading horizon://docs/chat. Not for: automatic sends, repeated polling, rich-text rendering or exposing moderation credentials. Use horizon_get_chat_operation to reconcile original sends, then horizon_send_chat_message only for the explicit identical replay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt. Persist project+player operationId/issuedAt/channel/full text before sending. The original live message provides its receipt; replay never recreates expired/deleted text. Direct/group windows are15 messages/30seconds, project windows20/seven days. A monotone player time fence rejects unknown older sends; no per-player message/receipt copy. Returns: {receipt,replayed,serverTime} Errors: 404 hides private/missing/expired channels or source messages. 409 OPERATION_CONFLICT/OPERATION_EXPIRED or STATE_CONFLICT requires explicit original-intent reconciliation. Never replace an unknown send UUID/time/text. 429 does not schedule a retry. CHAT_MUTED/CHAT_BANNED restrict current chat access. 501 NOT_SUPPORTED means simpleServer has no chat or polling fallback. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | Exact original plain text, never silently rewritten | |
| userId | Yes | Active player matching the current session and project | |
| issuedAt | Yes | Original canonical timestamp including .SSSZ; never replace issuedAt on retry | |
| channelId | Yes | Original canonical lowercase UUID | |
| operationId | Yes | Original canonical lowercase UUID | |
| sessionToken | Yes | Player accessToken sent only as Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond annotations: one HTTP attempt, mandatory persistence of operationId/issuedAt/channel/text before sending, per-window rate limits, monotone player time fence, no per-player message copy, and replay never recreating expired text. Error semantics (404, 409, 429, 501, 401, 403) and the isError result contract are also disclosed. This is consistent with idempotentHint and destructiveHint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded and sectioned (Use when/Not for/Requires/Side effects/Returns/Errors), with little filler. It is very dense and repeats 429 handling in two places ("does not schedule a retry" vs "wait a minute, then retry"), which mildly muddies the otherwise disciplined structure.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, open-world mutation with no output schema, the description supplies return shape ({receipt,replayed,serverTime}), auth prerequisites, side effects, rate limits, and error handling. An agent has enough to call it correctly and interpret failures.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real meaning: sessionToken must be the accessToken from horizon_signin_email/anonymous, userId must match the signed-in player, and operationId/issuedAt/text are the immutable original-send identity never to be replaced. That linkage to auth and replay semantics exceeds the schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Sends plain text once or explicitly replays the exact original operation") and distinguishes the two modes. Naming horizon_get_chat_operation as the reconciliation path separates it from siblings clearly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit "Use when" and "Not for" sections name automatic sends, polling, rich-text rendering, and credential exposure as exclusions. It also names horizon_get_chat_operation and the signin tools as alternatives, leaving little inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_send_emailSend EmailA
Queues a transactional email from a dashboard template to one registered player, sent now or at a scheduled time through the developer's own SMTP server. Use when: the game triggers a message to a player, such as a welcome mail or a reminder. Not for: checking delivery (use horizon_get_email_status) or stopping a queued email (use horizon_cancel_email). Requires: an SMTP configuration and the template in the horizOn dashboard, and a recipient with a verified email address. Side effects: queues one new email per call; repeating the call sends the email again, so never repeat it to retry a status check. Returns: {id, status: 'pending', scheduledAt}; pass id to horizon_get_email_status to follow delivery or to horizon_cancel_email to stop it. Errors: 400 for an unknown templateSlug or a recipient without a verified email address: check the slug in the dashboard or pick another user. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Player user ID (UUID) of the recipient; the player needs a verified email address | |
| language | Yes | ISO 639-1 code (2 lowercase letters) of the template translation to render, for example 'en' or 'de' | |
| variables | Yes | Values for the template's variables as a string map, for example {"username": "John"}; pass {} when the template has none | |
| scheduledAt | No | ISO 8601 timestamp for delayed delivery, at most 30 days ahead, for example 2026-10-01T09:00:00Z. Omit to send immediately | |
| templateSlug | Yes | Slug of an email template defined in the dashboard, for example 'welcome' or 'reminder' |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnlyHint=false, idempotentHint=false, openWorldHint=true), and the description adds substantial context beyond them: it queues one email per call, repeating sends again (so never retry a status check), requires an SMTP config + dashboard template + verified recipient, and documents the return shape and the 400/401/429 error semantics including rate limiting.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded, followed by labeled Use when / Not for / Requires / Side effects / Returns / Errors blocks, so an agent can scan to the relevant section. It is long, but the length is justified by the non-idempotent send and multiple error modes; little of it is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates fully by describing the return object ({id, status, scheduledAt}), how to use the id downstream, the required credentials (HORIZON_API_KEY), and the error envelope behavior. Everything needed to call the tool correctly and interpret failures is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds failure semantics tied to specific parameters: a 400 for an unknown templateSlug or a recipient without a verified email address, plus the instruction to check the slug in the dashboard or pick another user. That is genuine meaning beyond the schema field docs, though most syntax still lives in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource+scope: 'Queues a transactional email from a dashboard template to one registered player, sent now or at a scheduled time through the developer's own SMTP server.' It also distinguishes itself from siblings by name (horizon_get_email_status, horizon_cancel_email), so an agent can route correctly without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (game triggers a message to a player) and 'Not for' clauses that name the two alternative tools for delivery checking and cancellation. When-to-use, when-not-to-use, and alternatives are all stated rather than inferred.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_send_friend_requestSend Friend RequestAIdempotent
Sends Friend Request using the reviewed player revision. Use when: the player explicitly requests this social action. Not for: automatic retries after timeout, automatic acceptance of crossed requests or changing expectedRevision without reconciling intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. A current snapshot revision. Side effects: Creates both pending request records and an ordinary recipient Inbox notice atomically. A crossed request still needs explicit acceptance. No automatic retry. Repeating the same revision cannot create a second effect. Returns: Complete {userId,revision,friendCode,friends,incoming,outgoing,blocked,limits,serverTime} snapshot. Replace the matching host/project/player cache. lastActiveAt is the latest retained login, null when unknown; it is not online presence. Errors: 409 REVISION_CONFLICT or an uncertain response: get a new snapshot and reconcile intent, never silently replace expectedRevision and repeat. 404 FRIEND_REQUEST_NOT_FOUND means this request was removed or replaced; do not act on a newer ID. INBOX_FULL rejects the entire send/accept. Friend/request/block capacity limits reject additions while existing data remains removable. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player UUID matching the session | |
| sessionToken | Yes | Player accessToken sent only as Authorization Bearer | |
| targetUserId | Yes | The other player UUID in the same project | |
| expectedRevision | Yes | Exact revision from the reviewed actor snapshot; never refresh and substitute automatically |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing atomicity ('creates both pending request records and an ordinary recipient Inbox notice atomically'), crossed-request semantics, the no-auto-retry policy, and the idempotency guarantee in concrete terms. It also specifies the exact return payload and cache-replacement duty, plus per-status error handling (409, 404, INBOX_FULL, 401, 403, 429).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and use/not-for guidance, which is good, but the body is a dense, largely unstructured block covering side effects, returns, and an extensive error catalogue. Some content is redundant — the no-automatic-retry rule appears both in 'Not for' and again in 'Side effects' — and the volume makes key constraints harder to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description's explicit enumeration of the returned snapshot fields and the instruction to replace the matching host/project/player cache are necessary and present. Error behavior, auth requirements, capacity rejection, and rate limiting are all covered for a state-mutating social action.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description earns an extra point by explaining where sessionToken comes from (horizon_signin_email / horizon_signin_anonymous accessToken), that userId must be the signed-in player, and that expectedRevision is a reviewed snapshot revision that must never be silently substituted. targetUserId is not discussed in the description beyond what the schema says.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb+resource (sends a friend request) and qualifies it with the required precondition (reviewed player revision). It is clearly separable from horizon_accept_friend_request, horizon_decline_friend_request, horizon_cancel_friend_request and horizon_block_player in the sibling list.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (player explicitly requests the action) and 'Not for' clauses (no automatic retries after timeout, no automatic acceptance of crossed requests, no changing expectedRevision without reconciling intent). It also names the sign-in siblings that must be used to obtain sessionToken, so routing is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_set_group_member_roleset group member roleADestructiveIdempotent
Applies the explicit set group member role action using the reviewed group revision. Use when: the player explicitly confirms this group action. Not for: replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Current group revision and the exact pending requestId where applicable. Side effects: Leader sets another member's role to officer/member. No automatic retry. Same-revision replay cannot create a second effect. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| role | Yes | New nonleader role for the target member | |
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| targetUserId | Yes | Other player in this project | |
| expectedRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations, it discloses the specific destructive effect (changing another member's role), no automatic retry, same-revision replay behavior, return shape, cache replacement guidance, and detailed error reconciliation paths. It is consistent with destructiveHint=true and idempotentHint=true.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is organized with Use when/Not for/Requires/Side effects/Returns/Errors sections and is front-loaded, but it is very dense and run-on. Error and auth guidance is repeated enough that some sentences do not fully earn their place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, and the description compensates by documenting the return shape, null group cases, cache behavior, auth requirements, and failure handling. For a destructive group-mutation tool, this gives an agent enough context to call and recover correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds useful meaning around sessionToken acquisition and expectedRevision caution, but it also mentions 'the exact pending requestId where applicable' even though no requestId parameter exists in the schema, creating potential confusion rather than fully clarifying parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies the resource and operation through 'set group member role' and clarifies the effect as 'Leader sets another member's role to officer/member.' The opening 'Applies the explicit set group member role action' is somewhat abstract, but the side-effects line makes the actual operation clear and distinguishes it from siblings like transfer or remove member.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states when to use the tool: 'the player explicitly confirms this group action.' It also gives clear exclusions: not for replacing reviewed revisions/request IDs, bypassing a leader's block, or automatic retry after uncertainty. This is unusually strong routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_set_profileSet Player ProfileADestructiveIdempotent
Sets a player's avatar, frame and displayed badges. This REPLACES THE WHOLE PROFILE: an omitted, null or empty slot is cleared. Use when: the player confirms a new look. Pass the current values from horizon_get_profile for the slots that should stay. Not for: reading the profile or the catalog (use horizon_get_profile). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Every ID must be in the API key's catalog, have the type of its slot and be free or unlocked for the player; at most 3 distinct badges. Side effects: overwrites all three slots; the same call again changes nothing more. The profile shows up in leaderboard entries. Returns: the same body as horizon_get_profile after the change. Errors: The error result names the stable code. 400 INVALID_BADGES, INVALID_COSMETIC_ID, COSMETIC_NOT_FOUND or COSMETIC_TYPE_MISMATCH: pick IDs of the right type from horizon_get_profile. 403 COSMETIC_LOCKED: the cosmetic is locked and the player has not unlocked it (unlocks come from gift code grants). 401 SESSION_REQUIRED for a missing or expired session: sign in again. 403 SESSION_FORBIDDEN for a session of another user: pass the userId that signed in. 404 PLAYER_NOT_FOUND for an unknown userId. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| badges | No | Badge cosmetic IDs of type badge to display (0 to 3, distinct, order kept, each 1 to 32 characters: a-z, 0-9, ., _ and -). Omit or [] clears all badges. | |
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* | |
| frameId | No | Cosmetic ID of type frame from the catalog (for example "frame.gold"). Omit, null or "" clears the frame slot. | |
| avatarId | No | Cosmetic ID of type avatar from the catalog (for example "avatar.gold"). Omit, null or "" clears the avatar slot. | |
| sessionToken | Yes | accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Although annotations already declare destructive=true and idempotent=true, the description goes well beyond them: it explains that omitted/null/empty clears slots, that the call replaces all three slots at once, the catalog/type/unlock constraints, the 3-badge cap, the leaderboard visibility, and a full error taxonomy (400 INVALID_BADGES, 403 COSMETIC_LOCKED, 401/403 SESSION_*, 404, 429 rate limit with retry advice). This is unusually rich disclosure and does not contradict the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Long but dense and well-sectioned into Use when / Not for / Requires / Side effects / Returns / Errors, with the destructive replace-all semantics front-loaded. Every sentence carries actionable content, though the error-code enumeration makes it heavier than strictly necessary.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
A mutation tool with no output schema needs to explain side effects, auth, and failure modes; it does all three, including what is returned (the get_profile body) and the isError contract. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: pass current values from horizon_get_profile for slots that should stay, every ID must belong to the API key's catalog with the type of its slot and be free or unlocked, and at most 3 distinct badges. These constraints are semantic rules not expressible in the JSON schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource ("Sets a player's avatar, frame and displayed badges") and immediately names the sibling it is not (horizon_get_profile for reading). An agent can distinguish it from the ~30 siblings without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit "Use when: the player confirms a new look" plus a concrete instruction to seed unchanged slots from horizon_get_profile, and a "Not for:" clause naming the alternative. Both the when and the when-not are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_signin_anonymousSign In AnonymouslyA
Signs in an anonymous (guest) account with its stored anonymousToken and starts a player session (accessToken). Use when: a returning guest opens the game, or right after horizon_signup_anonymous, before any tool that needs sessionToken. Not for: email accounts (use horizon_signin_email) or creating a guest (use horizon_signup_anonymous). Requires: the anonymousToken returned by horizon_signup_anonymous for this account. Side effects: creates a new session on every call; older sessions stay valid. Returns: {userId, username, accessToken, authStatus, message}. Pass userId and accessToken (as sessionToken) to the session tools; the token stays valid for one hour after its last use. Errors: 404 for an unknown anonymousToken: the account is lost, create a new one with horizon_signup_anonymous. 429 also comes from the per-token limit (5 attempts per minute) and the per-IP limit (30 per minute): wait a minute. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| anonymousToken | Yes | anonymousToken returned by horizon_signup_anonymous (exactly 32 characters: letters, digits, _ and -) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already mark this as a non-read-only, non-idempotent, non-destructive, open-world operation. The description goes well beyond them by disclosing session side effects, token lifetime, rate limits, required API key, and error semantics, all consistent with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well structured with front-loaded sections for use, exclusions, requirements, side effects, returns, and errors. It is somewhat verbose, however, and the 429 explanation is repeated in the final sentence, slightly diluting conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter authentication tool with no output schema, the description covers prerequisites, returns, session lifetime, side effects, and common failure modes. An agent has enough information to invoke it correctly and handle expected errors.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the input schema already fully documents anonymousToken, including its exact format and origin. The description adds only a light reminder that the token comes from horizon_signup_anonymous for this account, without extra syntax or usage detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: signs in an anonymous guest account and starts a player session. It distinguishes itself from siblings by naming horizon_signin_email and horizon_signup_anonymous as adjacent but different operations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says when to use it ('returning guest opens the game', 'right after horizon_signup_anonymous') and when not to use it, naming both alternative tools. The routing guidance is complete enough that an agent can choose correctly without opening other schemas.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_signin_emailSign In with EmailA
Signs in an existing email account with email and password and starts a player session (accessToken). Use when: a registered, verified player logs in, before any tool that needs sessionToken (submit score, cloud save, gift code redeem, profile, validated runs). Not for: guest accounts (use horizon_signin_anonymous), new players (use horizon_signup_email) or checking an existing token (use horizon_check_auth). Side effects: creates a new session on every call; older sessions stay valid. Returns: {userId, username, email, accessToken, authStatus, message}. Pass userId and accessToken (as sessionToken) to the session tools; the token stays valid for one hour after its last use. Errors: 401 for a wrong password or unknown email: ask the player to check the credentials. 403 (NOT_VERIFIED) for an unverified email: the player must confirm the verification email first. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| Yes | Email address the account was registered with (max 40 characters) | ||
| password | Yes | Account password (max 128 characters); sent to the API only, never returned |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses behavior far beyond the annotations: a new session is created on every call while older sessions stay valid, token lifetime of one hour after last use, HORIZON_API_KEY requirement, 401/403 discrimination, isError semantics on every failure, and the 429 per-minute rate limit. This is a model example of documenting side effects and auth needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then organized into labeled Use when/Not for/Side effects/Returns/Errors blocks. It is long but dense and well-structured; a few clauses (e.g. the dual-401 explanation) could be tightened, keeping it just short of perfect.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a non-idempotent, open-world auth tool with no output schema, the description covers purpose, gating, side effects, returned fields, token lifecycle, error codes, and rate limiting. An agent has everything needed to call it and handle outcomes.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so email and password constraints are already fully documented in the schema. The description only restates that email and password are used and adds post-call guidance (pass userId/accessToken as sessionToken), which is about return usage rather than parameter meaning. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Signs in an existing email account with email and password and starts a player session'), and goes further by naming the return token. It clearly delineates itself from the signup/anonymous/check siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' clause (registered, verified player logs in before any sessionToken-dependent tool) plus a 'Not for' clause that names the exact alternative for each rejected case (horizon_signin_anonymous, horizon_signup_email, horizon_check_auth). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_signup_anonymousSign Up AnonymouslyA
Creates a new anonymous (guest) player account that needs only a display name and returns its anonymousToken. Use when: a player starts without email, for example on first launch of a game with guest play. Not for: players who sign up with email and password (use horizon_signup_email) or returning guests (use horizon_signin_anonymous with the stored anonymousToken). Side effects: creates one new player account per call; calling it again creates another account, it never finds an existing one. Sign-up starts no session. Returns: {userId, username, isAnonymous: true, anonymousToken, createdAt}. Store anonymousToken on the device: it is the only way back into this account. Then call horizon_signin_anonymous to get the accessToken that session tools need. Errors: 400 for an invalid displayName: fix the name and retry. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| displayName | Yes | Display name shown on leaderboards (max 30 characters) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial context beyond the annotations: one account created per call with no lookup semantics, no session started, the anonymousToken being the only way back in, the need for HORIZON_API_KEY, and per-status error handling (400/401/429). The annotations already cover non-idempotence and open-world behavior, and the description reinforces and extends that with the retry and storage guidance.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but well partitioned into Use when / Not for / Side effects / Returns / Errors, with the core purpose front-loaded. Every labeled sentence carries unique operational value (idempotence caveat, token storage, error triage) rather than repeating structured fields.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even without an output schema, the description enumerates the return object fields and the follow-up call (horizon_signin_anonymous) needed for a session. For a low-complexity, 1-param signup tool this leaves no meaningful gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the single displayName parameter (with its 30-char limit) is fully documented by the schema. The description reinforces that only a display name is needed and adds the 400-invalid-name failure mode, but adds no syntax beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Creates a new anonymous (guest) player account') plus the exact return artifact ('returns its anonymousToken'). It explicitly distinguishes itself from the email-signup and returning-guest siblings, so an agent can route correctly without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' and 'Not for' clauses name the alternatives (horizon_signup_email, horizon_signin_anonymous with stored token) and the selecting condition (no email / first guest launch). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_signup_emailSign Up with EmailA
Creates a new player account with email, password and display name; the account starts unverified and without a session. Use when: a new player registers with email so the account can be recovered on other devices. Not for: existing accounts (use horizon_signin_email) and guest play without email (use horizon_signup_anonymous). Side effects: creates one player account and sends the verification email. It does not sign in. Returns: the new user with userId and isVerified: false. After the player verified the email address, call horizon_signin_email to get the accessToken. Errors: 409 when the email already belongs to an account: sign in with horizon_signin_email instead. 400 for an invalid email, a password outside 8 to 128 characters or a common password, or a bad name: fix the value and retry. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| Yes | Player email address (valid format, max 40 characters); must not be registered yet | ||
| password | Yes | Password, 8 to 128 characters; common passwords such as "password1" are rejected. Sent to the API only, never returned | |
| displayName | Yes | Display name shown on leaderboards (max 30 characters) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds rich context beyond annotations: account starts unverified/no session, sends a verification email, does not sign in, and it documents error semantics (409, 400, 401, 429) plus required HORIZON_API_KEY. This is far beyond the minimal readOnly/destructive/idempotent hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded purpose, then structured 'Use when/Not for/Side effects/Returns/Errors' blocks. Well organized, though the error block is dense and could be trimmed slightly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and a mutation tool, the description fully covers return value (userId, isVerified:false), side effects, follow-up workflow, and error handling. Nothing an agent needs to invoke correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents email/password/displayName constraints. The description restates some password length limits but adds little new semantic detail beyond the schema's baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource ('Creates a new player account') with scope details ('starts unverified and without a session'). Explicitly distinguishes from siblings horizon_signin_email and horizon_signup_anonymous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' for new email registrations and 'Not for' naming the two alternatives (signin, anonymous signup). Also gives a follow-up flow when email is already taken.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_start_matchStart MatchADestructiveIdempotent
Executes start match under the exact original revision. Use when: explicit asynchronous multiplayer actions after reading horizon://docs/matches. Not for: automatic polling, page traversal, timeout progression, invented winners or automatic rewards. Reconcile with horizon_get_matches and horizon_get_match. Consent and game consensus do not validate honest gameplay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt. Start requires the creator and every joined UUID exactly once. Turn requires the current unexpired actor. Timeout advances only one turn. Active leave forfeits without selecting a winner. Lobby cancel is creator-only. Full Inbox retains a durable notice without undoing a committed move. Returns: {match,pollAfterSeconds,serverTime}; departing lobby actors receive metadata only and lose point-read access. Errors: 404 hides private/missing/expired matches. 409 REVISION_CONFLICT or STATE_CONFLICT: explicitly reread and reconcile the original intent, never replace the revision or automatically resubmit. RESULT_CONFLICT preserves the original report. RUN_EXPIRED/RUN_ALREADY_USED never allow replacement ranked runs. 501 FEATURE_NOT_SUPPORTED is explicit for simpleServer ranked mode. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the session and project | |
| matchId | Yes | Original server match UUID in the selected project | |
| turnOrder | Yes | Every joined participant in the explicit turn order | |
| sessionToken | Yes | Player accessToken sent only as Bearer | |
| expectedRevision | Yes | Original reviewed revision; never substitute a newer revision after an uncertain write |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Far beyond the annotations, it discloses the sign-in prerequisite, HORIZON_API_KEY requirement, one-HTTP-attempt behavior, revision-conflict handling, rate-limit response, 401/403 session semantics, and return payload. It also states consequential behavior such as non-replacement of ranked runs and preservation of original results on conflict.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is well front-loaded and many sentences carry real operational value, especially the error recovery guidance. But it is very long and the side-effects paragraph describes behaviors belonging to other match tools, so not every sentence earns its place in this tool's definition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex five-required-parameter mutation with no output schema, it covers authentication, side effects, return shape, and detailed error recovery. Nothing an agent needs in order to invoke it correctly appears to be missing, even though the description is broader than necessary.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so parameter basics are already documented. The description still adds useful meaning: sessionToken must be the accessToken from horizon_signin_email or horizon_signin_anonymous, userId must match the signer, and expectedRevision must never be replaced after an uncertain write.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence, 'Executes start match under the exact original revision,' names a specific verb and resource and is distinguishable from list/get siblings. However, the later 'Use when: explicit asynchronous multiplayer actions' and the side-effects paragraph describing turn, timeout, leave, and lobby-cancel semantics blur whether this tool also performs those actions, which are separate siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit 'Use when' and 'Not for' guidance, excluding automatic polling, timeout progression, invented winners, and automatic rewards. It also names concrete alternatives for reconciliation, horizon_get_matches and horizon_get_match, and tells the agent to read horizon://docs/matches first.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_start_match_ranked_runStart or Recover Match Ranked RunAIdempotent
Creates or recovers one original match-bound validated run after complete consensus. Use when: explicit asynchronous multiplayer actions after reading horizon://docs/matches. Not for: automatic polling, page traversal, timeout progression, invented winners or automatic rewards. Reconcile with horizon_get_matches and horizon_get_match. Consent and game consensus do not validate honest gameplay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt. Server rechecks the original configured board and binds match/final revision. Recovery preserves runId, seed and expiry; never replaces consumed/expired tickets. This short post-match validation is not retrospective game simulation. Returns: Existing StartRunResponse with original ticket, runId, seed, expiry and context status; submit through the existing validated-actions endpoint. Errors: 404 hides private/missing/expired matches. 409 REVISION_CONFLICT or STATE_CONFLICT: explicitly reread and reconcile the original intent, never replace the revision or automatically resubmit. RESULT_CONFLICT preserves the original report. RUN_EXPIRED/RUN_ALREADY_USED never allow replacement ranked runs. 501 FEATURE_NOT_SUPPORTED is explicit for simpleServer ranked mode. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Active player matching the session and project | |
| matchId | Yes | Original server match UUID in the selected project | |
| sessionToken | Yes | Player accessToken sent only as Bearer | |
| finalStateRevision | Yes | Original reviewed revision; never substitute a newer revision after an uncertain write |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes far beyond the annotations (idempotent, openWorld, non-destructive) by disclosing that a single HTTP attempt is made, that the server rechecks the original board and binds match/final revision, that recovery preserves runId/seed/expiry and never replaces consumed tickets, and by enumerating auth requirements (HORIZON_API_KEY, sessionToken via signin) and error semantics (404 concealment, 409 conflicts, 401/403 handling, 429). This is unusually rich behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Structured into labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) that are front-loaded and scannable. It is long and dense, with some redundancy across the requirement and error prose, but nearly every sentence carries operational value and the important scoping constraint leads.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex, stateful mutation with recovery semantics, the description covers prerequisites, side effects, return shape, and the full error taxonomy, and no output schema exists so this prose appropriately carries the return-value burden. An agent has everything needed to invoke it correctly and handle failures.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds genuine value beyond the schema: it explains the sessionToken sourcing workflow (sign in and pass the accessToken as sessionToken), states userId must be the signing-in player on 403, and reinforces that finalStateRevision must never be substituted with a newer revision after an uncertain write.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (creates or recovers) and a precisely scoped resource (one original match-bound validated run after complete consensus), which clearly distinguishes it from horizon_start_run and horizon_report_match_result. An agent can tell it apart from siblings without reading the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names the 'Use when' condition (explicit async multiplayer actions after reading match docs) and the 'Not for' exclusions (automatic polling, page traversal, timeout progression, invented winners, automatic rewards), plus names horizon_get_matches and horizon_get_match as reconciliation partners. When-to-use, when-not, and alternatives are all present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_start_runStart Validated RunA
Starts a server-checked run (Validated Actions): issues a single-use ticket with a server seed and starts the server's run timer. Use when: before a round whose score or earned currency must be checked by the server, and always for boards marked validatedOnly in horizon_list_leaderboards. Not for: normal boards where the client may write its own score (use horizon_submit_score) and reading balances (use horizon_get_state). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Pass leaderboardKey to bind the ticket to a board (it must exist; 'default' is created on first use). Optionally declare the start context (gameVersion, contentVersion, simulationVersion, replayFormatVersion, contentDigest, initialStateBase64); the server binds it with its own start values (rule version, balances, seed) into the run, and a sus run keeps it in its review package. The server never reads the cloud save; send the start state a replay needs as initialStateBase64. Side effects: issues a new ticket per call and counts against the run limits per player and per account; unused tickets simply expire. Returns: {runId, ticket, seed, leaderboardKey, issuedAt, expiresAt, expiresInSeconds}. Seed the game's deterministic randomness with seed, record the input log, then send the result with horizon_submit_validated and the unchanged ticket before expiresAt. Errors: Errors carry a stable code in the body and the error result names it: 400 for a bad context field, 400 INITIAL_STATE_INVALID_ENCODING (initialState not standard base64), 413 INITIAL_STATE_TOO_LARGE (decoded initialState above the plan's evidenceMaxBytes), 401 SESSION_REQUIRED, 403 SESSION_FORBIDDEN, 404 PLAYER_NOT_FOUND or LEADERBOARD_NOT_FOUND, 429 RUN_RATE_LIMITED (per player and hour) or RUN_CAPACITY_REACHED (account per UTC hour; do not retry automatically, the wait can be an hour), 503 VALIDATED_ACTIONS_UNAVAILABLE (server has no ticket key). After 401 sign in again; after 403 SESSION_FORBIDDEN pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* | |
| gameVersion | No | Game build version, for example "1.4.2" (1 to 64 printable ASCII characters), stored in the run's start context. Optional | |
| sessionToken | Yes | accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session | |
| contentDigest | No | SHA-256 of the game content the run uses, 64 hex characters (sent in lower case). Optional | |
| contentVersion | No | Version of the game content (levels, balancing data) the run uses (1 to 64 printable ASCII characters), stored in the run's start context. Optional | |
| leaderboardKey | No | Board key to bind the ticket to, from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit for an unbound ticket (currency only runs, or choose the board at submit). | |
| simulationVersion | No | Version of the deterministic simulation that replays the input log (1 to 64 printable ASCII characters), stored in the run's start context. Optional | |
| initialStateBase64 | No | Bytes the simulation starts from as standard base64 (sent as context.initialState); decoded at most the plan's evidenceMaxBytes (32,768 bytes by default). Optional | |
| replayFormatVersion | No | Format version of the recorded input log (1 to 64 printable ASCII characters), stored in the run's start context. Optional |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Rich disclosure beyond the annotations: a new ticket per call, per-player and per-account run limits, unused tickets expire, the server never reads the cloud save (so start state must be sent as initialStateBase64), and a full error-code table with remediation. One flaw: the final sentence says 429 means the account's per-minute limit and 'wait a minute, then retry', which conflicts with the earlier 'do not retry automatically, the wait can be an hour' for RUN_CAPACITY_REACHED.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Long, but front-loaded and segmented into Use when / Not for / Requires / Side effects / Returns / Errors, with nearly every line carrying operational information. It loses a point for some redundancy and for the internally inconsistent 429 guidance in the closing paragraph.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 9 parameters, no output schema, and a mutation tool, the description supplies what is otherwise missing: exact return fields, ticket lifetime and the horizon_submit_validated follow-up, typed error codes with per-code recovery, and capacity caveats. An agent has everything needed to call it correctly and handle failures.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real semantics: leaderboardKey binds the ticket to an existing board ('default' is created on first use) or may be omitted for an unbound ticket, and initialStateBase64 is framed as the channel for start state given the server never reads the cloud save. The optional context fields are otherwise only summarized as 'start context', leaving the schema to carry the detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('starts a server-checked run (Validated Actions)') and immediately names the concrete artifact produced: a single-use ticket with a server seed plus the server run timer. It is clearly separable from horizon_submit_score and horizon_get_state, both of which are named as the wrong tools for adjacent jobs.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (server-checked score/currency rounds, always for validatedOnly boards per horizon_list_leaderboards) and 'Not for' (normal boards → horizon_submit_score; balances → horizon_get_state). Prerequisites are spelled out: sign in via horizon_signin_email/horizon_signin_anonymous and pass the accessToken as sessionToken.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_submit_feedbackSubmit FeedbackA
Sends a message written by a player (bug report, feature request or comment) to the developer's feedback inbox in the horizOn dashboard. Use when: the player fills in a feedback or bug report form in the game. Not for: crashes and caught exceptions (use horizon_create_crash_report) or technical events the game logs by itself (use horizon_create_log). Requires: a userId from horizon_signup_* or horizon_signin_*; no session token. Side effects: creates one feedback entry per call; a repeat creates a duplicate. Returns: the text "ok" when the entry was stored. Errors: An unknown userId, or one of another API key, is rejected: pass the ID from the sign-in result. 403 when the account's feedback limit is reached: delete old feedback in the dashboard. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| No | Contact email address for a reply, if the player wants one | ||
| title | Yes | Short summary shown in the dashboard list (1 to 100 characters) | |
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* | |
| message | Yes | Full feedback text (1 to 2048 characters) | |
| category | No | Free text category (max 50 characters); the horizOn SDKs use BUG, FEATURE and GENERAL. Omit for none | |
| deviceInfo | No | Device and OS details for bug reports, for example 'Pixel 8, Android 14' (max 500 characters) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Although annotations already cover the safety profile (readOnlyHint=false, destructiveHint=false, idempotentHint=false), the description adds substantial context beyond them: one entry per call with duplicates on repeat, the literal 'ok' return, required HORIZON_API_KEY, 403 feedback-limit behavior, and a full error taxonomy including 401 vs 429 diagnosis. This is rich, actionable behavioral disclosure consistent with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) make it highly scannable, and the core purpose is front-loaded. Despite its length, each block carries distinct operational information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a non-idempotent mutation tool with no output schema, the description covers auth requirements, side effects, the return value, and the full failure surface including status-code interpretation. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all six parameters with formats and length limits. The description reinforces userId provenance (from horizon_signup_*/horizon_signin_*) and the session-token-free requirement, but adds little semantic detail the schema lacks. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Sends a message written by a player ... to the developer's feedback inbox') and enumerates the content types (bug report, feature request, comment). It explicitly names the siblings it is not, so an agent can distinguish it from horizon_create_crash_report and horizon_create_log without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides an explicit 'Use when' (player fills in a feedback/bug report form) and an explicit 'Not for' with the two alternative tools named for each excluded case. The condition selecting each sibling is spelled out, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_submit_match_turnSubmit Match TurnADestructiveIdempotent
Executes submit match turn under the exact original revision. Use when: explicit asynchronous multiplayer actions after reading horizon://docs/matches. Not for: automatic polling, page traversal, timeout progression, invented winners or automatic rewards. Reconcile with horizon_get_matches and horizon_get_match. Consent and game consensus do not validate honest gameplay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: One HTTP attempt. Start requires the creator and every joined UUID exactly once. Turn requires the current unexpired actor. Timeout advances only one turn. Active leave forfeits without selecting a winner. Lobby cancel is creator-only. Full Inbox retains a durable notice without undoing a committed move. Returns: {match,pollAfterSeconds,serverTime}; departing lobby actors receive metadata only and lose point-read access. Errors: 404 hides private/missing/expired matches. 409 REVISION_CONFLICT or STATE_CONFLICT: explicitly reread and reconcile the original intent, never replace the revision or automatically resubmit. RESULT_CONFLICT preserves the original report. RUN_EXPIRED/RUN_ALREADY_USED never allow replacement ranked runs. 501 FEATURE_NOT_SUPPORTED is explicit for simpleServer ranked mode. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| finish | Yes | True freezes final bytes and opens reporting without choosing a winner | |
| userId | Yes | Active player matching the session and project | |
| matchId | Yes | Original server match UUID in the selected project | |
| dataBase64 | Yes | Original opaque bytes, including empty state. Never interpret or silently replace them | |
| sessionToken | Yes | Player accessToken sent only as Bearer | |
| expectedRevision | Yes | Original reviewed revision; never substitute a newer revision after an uncertain write |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag a destructive, open-world, non-read-only operation, and the description adds substantial behavior: single HTTP attempt, auth flow, revision-conflict handling, 404 privacy masking, 409/501/401/403/429 semantics, and return shape. This is exactly the kind of extra context the annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The front-loaded Use when / Not for structure is good, but the description is bloated with unrelated match-lifecycle and Inbox side-effect sentences that do not apply to this six-parameter submit-turn call. Those sentences dilute focus and should be removed or moved.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex destructive mutation with six required parameters and no output schema, the description is complete: it explains prerequisites, side effects, return shape, and detailed error handling. Nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so all six parameters are already documented in the schema, establishing a baseline of 3. The description adds meaningful auth semantics for userId/sessionToken and revision-safety guidance for expectedRevision, raising it slightly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description says it executes a match turn under an exact original revision and frames it as an explicit asynchronous multiplayer action. However, the core verb is largely a restatement of the tool name, and the side-effects list mixes in start/timeout/leave/cancel behavior, so the specific operation remains only partly clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit Use when clause, a Not for clause covering polling, page traversal, timeout progression, invented winners, and automatic rewards, and directs reconciliation with horizon_get_matches and horizon_get_match. The main gap is that it does not name the sibling for timeout progression, but the routing guidance is strong.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_submit_scoreSubmit ScoreAIdempotent
Submits a player's score to a leaderboard; the board keeps only each player's best score (higher on DESC boards, lower on ASC boards). Use when: a round ends on a normal board. Then call horizon_get_user_rank to show the new position. Not for: boards marked validatedOnly in horizon_list_leaderboards (use horizon_start_run and horizon_submit_validated) and reading scores (use horizon_get_leaderboard_top). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: replaces the player's entry only when the new score beats it; a worse or equal score, or the same call again, changes nothing. Returns: {success: true} (also when the score did not beat the best one). Errors: 403 VALIDATED_SUBMIT_REQUIRED on a validatedOnly board, nothing written: switch to horizon_start_run and horizon_submit_validated, do not retry. 403 PLAYER_BANNED when a moderator banned the player from the board: final, do not retry. 404 for an unknown leaderboardKey: list valid keys with horizon_list_leaderboards. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| score | Yes | Score to submit, a non-negative integer | |
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* | |
| sessionToken | Yes | accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session | |
| leaderboardKey | No | Board key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing the replace-only-if-better semantics, the auth/session flow, the return value, and a full error taxonomy (403 VALIDATED_SUBMIT_REQUIRED, 403 PLAYER_BANNED, 404, 401, 429) with retry guidance. This is exactly the extra context annotations (idempotentHint=true) cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and organized under labeled clauses (Use when / Not for / Requires / Side effects / Returns / Errors), so it scans well. It is on the long side, but nearly every clause carries actionable content rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, yet the description supplies the return shape and the full error/retry matrix, plus the session prerequisite. An agent has everything needed to invoke correctly and handle failures without consulting anything else.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description adds meaning by explaining how sessionToken is obtained (horizon_signin_email/anonymous) and that leaderboardKey can be omitted to use the API key's default board. It doesn't add format detail beyond the schema, but the auth-flow framing is genuinely useful.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Submits a player's score to a leaderboard') and immediately disambiguates by board type ('higher on DESC boards, lower on ASC boards'). It clearly distinguishes itself from horizon_submit_validated and the read-oriented siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when', 'Not for', and 'Requires' sections, naming the alternative tools (horizon_start_run + horizon_submit_validated for validated boards, horizon_get_leaderboard_top for reads). The trigger condition (round ends on a normal board) is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_submit_validatedSubmit Validated RunADestructive
Submits the result of a run started with horizon_start_run; the server checks ticket and server-only rules before it writes the score and earned values. Use when: a validated run ends: send the ticket, the claimed score (and stage) and the SHA-256 commitment of the input log. Not for: runs without a ticket (use horizon_submit_score on normal boards) and reading balances (use horizon_get_state). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. The ticket from horizon_start_run and exactly one of inputLogHash (a ready SHA-256), inputLogBase64 (raw log bytes, hashed locally) or inputLog (UTF-8 text, hashed locally); the log itself is never sent. score is required when a board is targeted (the ticket's board, or leaderboardKey) and ignored otherwise. Send earned ({key, amount}[]) only when the API key's rules define values: positive amounts earn, negative amounts spend. Side effects: consumes the ticket (single use, also when rejected); an accepted run writes the score (best score kept) and changes the balances of earned values. The same ticket cannot be submitted twice. Returns: {accepted, runId, leaderboardKey, score, bestScore, isNewHighScore, rank, durationSeconds, state, evidence, sus} plus inputLogHash (the hash that was sent). sus is true when the run was accepted but crossed a soft threshold of the rules (the flag names stay on the server); the run counts normally and the server keeps a review package. Rejected runs are never sus; an older server without the field reads as false. state is the player's server-owned values after the run: {day, values: [{key, balance, earnedToday, dailyCap, requested, credited}]}, every value key of the rules sorted by key; requested (amount sent) and credited (amount applied) appear only for the keys in earned. credited < requested on a positive amount means dailyCap or maxBalance clamped it (not an error). For a spend, credited is either requested or 0 (a concurrent run of the same player used the balance first): grant a purchase only when credited == requested. state is null when the rules define no values or the state write failed. evidence is null, or {required: true, runId, uploadBefore, maxBytes} when the server asks for the input log (the run became the player's row and is flagged or lands in the board's evidence top N, or the run is sus): upload exactly the logged bytes with horizon_upload_evidence before uploadBefore (24 hours); a log that was only hashed via inputLogHash must be kept by the caller. Errors: Rejections carry a stable code (never the rule values) and the error result names it: 400 SCORE_REQUIRED (board targeted without score) or PLAYER_NAME_REQUIRED; 401 SESSION_REQUIRED; 403 SESSION_FORBIDDEN, PLAYER_BANNED (banned from the board by a moderator, final; the ticket is not used) or SCORE_LIMIT_REACHED (ticket used up); 404 PLAYER_NOT_FOUND or LEADERBOARD_NOT_FOUND; 422 TICKET_INVALID, TICKET_EXPIRED, TICKET_FOREIGN, TICKET_CONSUMED, LEADERBOARD_MISMATCH; 422 rule codes STAGE_REQUIRED, STAGE_UNKNOWN, SCORE_ABOVE_MAX, SCORE_BELOW_MIN, STAGE_SCORE_ABOVE_MAX, STAGE_SCORE_BELOW_MIN, DURATION_TOO_SHORT, SCORE_RATE_TOO_HIGH and value codes UNKNOWN_VALUE_KEY (key not defined in the rules' values, also when the rules define none), DUPLICATE_VALUE_KEY, EARNED_ABOVE_MAX (above maxPerRun), EARNED_BELOW_MIN (below minPerRun), INSUFFICIENT_BALANCE (spend larger than the balance) (the ticket is consumed, start a new run); 503 VALIDATED_ACTIONS_UNAVAILABLE. After a 422 rule or value code or SCORE_LIMIT_REACHED the ticket is spent; after 401, 404, 429 or 503 the same ticket may be sent again. Local errors (no request sent, ticket kept): INVALID_INPUT_LOG_HASH when the hash input was missing, doubled or malformed, DUPLICATE_VALUE_KEY when earned lists a key twice. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| score | No | Claimed score (0 to 9007199254740991). Required when a board is targeted, ignored for a run without board. | |
| stage | No | Stage key for stage rules (for example "level-3") | |
| earned | No | Earned or spent server-owned values ({key, amount}, at most 64, each key once). Every key must be defined in the values of the API key's rules (else UNKNOWN_VALUE_KEY). Omit when the game uses no server-owned values. | |
| ticket | Yes | ticket from horizon_start_run, sent unchanged (opaque, about 190 characters, max 512) | |
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* | |
| inputLog | No | Input log as UTF-8 text; the tool hashes its UTF-8 bytes locally. Use this or inputLogHash or inputLogBase64. | |
| inputLogHash | No | SHA-256 of the raw input log bytes, 64 hex characters. Use this or inputLogBase64 or inputLog. | |
| sessionToken | Yes | accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session | |
| inputLogBase64 | No | Raw input log bytes as base64; the tool computes the SHA-256 locally. Use this or inputLogHash or inputLog. | |
| leaderboardKey | No | Target board. Omit to use the board the ticket is bound to; required for a leaderboard write with an unbound ticket. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Far exceeds the annotations (destructiveHint/readOnlyHint/idempotentHint/openWorldHint): it discloses single-use ticket consumption even on rejection, which error classes spend vs. preserve the ticket, the soft-threshold 'sus' flag and review package, dailyCap/maxBalance clamping semantics (credited < requested), the concurrent-spend race where credited==0, and the 24h evidence-upload obligation. This is exactly the behavioral context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Very long, but structured with labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) and front-loaded with the purpose before the routing rules. Given 10 parameters, a stateful ticket lifecycle and dozens of error codes, nearly every sentence earns its place, though some error-code enumeration could be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full return-value burden and does so thoroughly: the response object fields, the meaning of sus, the null state/evidence cases, credited-vs-requested clamping, and the retryability of each HTTP status. Nothing an agent needs to call and interpret this tool correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3, but the description adds genuine meaning beyond the schema: the log itself is never sent and a hash-only log must be retained by the caller, exactly one of the three log inputs is required, and earned positive/negative amounts map to earn/spend with clamping implications. Score required only when a board is targeted is reinforced with the ignore case.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Submits the result of a run started with horizon_start_run') and the server-side validation it triggers. It explicitly distinguishes itself from horizon_submit_score (runs without a ticket) and horizon_get_state (reading balances), so an agent can route without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Has explicit 'Use when', 'Not for' and 'Requires' sections that name the alternatives (horizon_submit_score, horizon_get_state, horizon_signin_*, horizon_upload_evidence) and the exact conditions selecting them. The lifecycle is unambiguous: a validated run ends, send ticket + score + log commitment.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_sync_chat_channelSync Chat ChannelARead-onlyIdempotent
Reads an authorized incremental snapshot after subscription resync/event or explicit user action. Use when: explicit hosted chat actions after reading horizon://docs/chat. Not for: automatic sends, repeated polling, rich-text rendering or exposing moderation credentials. Use horizon_get_chat_operation to reconcile original sends, then horizon_send_chat_message only for the explicit identical replay. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Read-only POST, one HTTP attempt. Complete visible ID order plus unknown immutable text. Known IDs are valid only for the exact cached epoch and complete authorized cache. No periodic polling. Returns: {channel,visibleMessageIds,messages,moderation,serverTime}; hide cache on disconnect/permission change and apply only a complete matching snapshot. Errors: 404 hides private/missing/expired channels or source messages. 409 OPERATION_CONFLICT/OPERATION_EXPIRED or STATE_CONFLICT requires explicit original-intent reconciliation. Never replace an unknown send UUID/time/text. 429 does not schedule a retry. CHAT_MUTED/CHAT_BANNED restrict current chat access. 501 NOT_SUPPORTED means simpleServer has no chat or polling fallback. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| epoch | Yes | Exact cached channel epoch, or null for an initial complete sync | |
| userId | Yes | Active player matching the current session and project | |
| channelId | Yes | Original canonical lowercase UUID | |
| sessionToken | Yes | Player accessToken sent only as Bearer | |
| knownMessageIds | Yes | Known cached message IDs for the exact original epoch; fixed current wire bound20 matches the largest channel window |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only supply readOnly/openWorld/idempotent/destructive flags; the description adds substantial context beyond them: read-only POST with exactly one HTTP attempt, no retry scheduling on 429, cache-epoch validity rules, hide-on-disconnect/permission-change behavior, required HORIZON_API_KEY, and a mapping of 401/403/404/409/429/501 outcomes. Nothing contradicts the readOnlyHint=true annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The Use when / Not for / Requires / Side effects / Returns / Errors ordering is genuinely front-loaded and scannable, but the block is heavily over-long: error-code enumeration dominates and partially duplicates the usage section (repeated-polling prohibition appears twice, retry guidance repeats). Much of the density could be compressed without information loss.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 5-required-parameter authenticated read with no output schema, the description covers prerequisites, auth wiring, return shape ({channel,visibleMessageIds,messages,moderation,serverTime}), cache consistency rules, and failure handling. An agent has everything needed to invoke and interpret it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description clarifies the semantics that the schema only hints at: sessionToken must be the accessToken from horizon_signin_email/horizon_signin_anonymous, userId must match the signed-in player, and known IDs are valid only for the exact cached epoch and a complete authorized cache. The epoch null-for-initial-sync case is left to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: reads an authorized incremental snapshot of a chat channel after a resync event or explicit user action. It differentiates from the send/reconcile siblings (horizon_get_chat_operation, horizon_send_chat_message) by name, but never distinguishes itself from the closest sibling, horizon_open_chat_channel, leaving the read-vs-open boundary implicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' and 'Not for' clauses name concrete triggers (after reading horizon://docs/chat, explicit hosted chat actions) and concrete exclusions (automatic sends, repeated polling, rich-text rendering, exposing moderation credentials). It also routes to the correct alternative tools for reconciliation and replay.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_test_connectionTest ConnectionARead-onlyIdempotent
Checks that HORIZON_API_KEY and HORIZON_BASE_URL reach the horizOn API by fetching the app's remote configs; takes no input. Use when: first during setup, and whenever other tools fail, to tell a configuration problem from a problem of the call itself. Not for: checking a player's session (use horizon_check_auth) or reading config values for the game (use horizon_get_all_remote_configs). Side effects: None (read only). Returns: {success: true, data} where data holds the app's remote configs; success means key and URL work. Errors: A network error means HORIZON_BASE_URL is wrong or unreachable: check the URL (default https://horizon.pm). Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | |
| success | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (which already declare readOnly, idempotent, open-world and non-destructive), the description discloses the required env vars, the exact failure semantics (401 means bad key, 429 means per-minute rate limit, network error means bad base URL), and the default URL. This is materially more than the annotations convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured and front-loaded with labelled sections (Use when / Not for / Side effects / Returns / Errors) so the agent can scan quickly. It is slightly verbose in the Errors block and repeats the read-only fact already implied by Side effects, so it falls short of maximum conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even with an output schema present, the description supplies the auth prerequisite, the success/failure interpretation, and the meaning of key error codes. For a first-run diagnostic in a crowded 33-tool namespace, nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. The description reinforces this with 'takes no input', but there is nothing further to document at the parameter level.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Checks that HORIZON_API_KEY and HORIZON_BASE_URL reach the horizOn API by fetching the app's remote configs') and explicitly marks it as a no-input diagnostic. It also distinguishes itself from the two nearest siblings, so the agent can select it without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit timing ('first during setup, and whenever other tools fail'), the diagnostic intent ('tell a configuration problem from a problem of the call itself'), and named alternatives for the cases it is not for (horizon_check_auth, horizon_get_all_remote_configs). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_transfer_group_leadershiptransfer group leadershipADestructiveIdempotent
Applies the explicit transfer group leadership action using the reviewed group revision. Use when: the player explicitly confirms this group action. Not for: replacing reviewed revisions/request IDs, bypassing a leader's block, or retrying automatically after uncertainty. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Current group revision and the exact pending requestId where applicable. Side effects: Leader transfers leadership to an existing member, becoming an ordinary member. No automatic retry. Same-revision replay cannot create a second effect. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| targetUserId | Yes | Other player in this project | |
| expectedRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructive=true and idempotent=true; the description then explains the actual consequence (leader becomes an ordinary member), denies automatic retry, and clarifies that same-revision replay cannot duplicate the effect. It adds auth, rate-limit, and rollback (INBOX_FULL) semantics far beyond the structured hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, use-when, not-for, requires, side effects, returns, then errors — a logical, skimmable order. It is dense and the error section is long, but for a destructive, multi-error-mode operation most sentences carry real decision value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the absence of an output schema, the description supplies the return shape ({groups, group}), privacy guarantees (actor's snapshot, never target's private state), and a full error taxonomy, so an agent has everything needed to call and recover correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents all five parameters, anchoring the baseline at 3. The description adds useful framing (sessionToken is the accessToken; expectedRevision must be the reviewed revision, not auto-refreshed), but also references a pending requestId that does not exist in this schema, creating minor confusion without net semantic gain.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (transfer group leadership) scoped by the reviewed revision, which distinguishes it from sibling mutations like set_group_member_role or leave_group. An agent can identify the exact operation without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (player explicitly confirms) and 'Not for' clauses naming concrete exclusion scenarios (bypassing a block, auto-retry, replacing reviewed revisions). It also points to horizon_get_groups and horizon_get_group_pending for reconciliation, leaving little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_unblock_playerUnblock PlayerADestructiveIdempotent
Unblocks Player using the reviewed player revision. Use when: the player explicitly requests this social action. Not for: automatic retries after timeout, automatic acceptance of crossed requests or changing expectedRevision without reconciling intent. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. A current snapshot revision. Side effects: Removes only your block. Does not restore a friendship or request, and does not remove the other player's block. No automatic retry. Repeating the same revision cannot create a second effect. Returns: Complete {userId,revision,friendCode,friends,incoming,outgoing,blocked,limits,serverTime} snapshot. Replace the matching host/project/player cache. lastActiveAt is the latest retained login, null when unknown; it is not online presence. Errors: 409 REVISION_CONFLICT or an uncertain response: get a new snapshot and reconcile intent, never silently replace expectedRevision and repeat. 404 FRIEND_REQUEST_NOT_FOUND means this request was removed or replaced; do not act on a newer ID. INBOX_FULL rejects the entire send/accept. Friend/request/block capacity limits reject additions while existing data remains removable. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player UUID matching the session | |
| sessionToken | Yes | Player accessToken sent only as Authorization Bearer | |
| targetUserId | Yes | The other player UUID in the same project | |
| expectedRevision | Yes | Exact revision from the reviewed actor snapshot; never refresh and substitute automatically |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it discloses that only your block is removed, the other player's block persists, no friendship is restored, and that replaying the same revision cannot produce a second effect (consistent with idempotentHint=true). It also documents auth prerequisites, rate limiting (429), and a full error taxonomy (409/404/INBOX_FULL/401/403/needs HORIZON_API_KEY).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with a one-line purpose, then clearly labeled Use when / Not for / Requires / Side effects / Returns / Errors sections, so it is scannable despite its length. Some of the error prose is dense and slightly repetitive around the 401/HORIZON_API_KEY distinction, keeping it short of a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, state-mutating call with no output schema, the description supplies everything an agent needs: required credentials, the returned snapshot shape and that it should replace the cache, the meaning of lastActiveAt, and recovery paths for every enumerated failure. Nothing material is left to inference.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description earns extra by explaining how to obtain sessionToken (sign in via horizon_signin_email/horizon_signin_anonymous and pass the accessToken) and by framing expectedRevision as coming from a reviewed snapshot that must be reconciled, not refreshed. It does not add per-parameter detail for targetUserId beyond what the schema already says.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Unblocks Player") and immediately scopes the mechanic: it removes only the caller's block and does not restore a friendship or request. This distinguishes it from the sibling horizon_block_player and from horizon_remove_friend without needing either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit "Use when" (player explicitly requests this social action) and "Not for" (automatic retries after timeout, automatic acceptance of crossed requests, silently changing expectedRevision). The positive trigger and the exclusions are both named, so an agent can route between this and the block/friend tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_unlock_achievementUnlock Manual AchievementAIdempotent
Unlocks one configured manual achievement once for the authenticated player. Use when: an explicit game event meets this manual achievement's rule. Not for: statistic achievements or client-chosen reward amounts. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: Commits the permanent completion bit and configured Player Values rewards in one transaction, immediately. No new Inbox or reward-history copy. Repeating the same key never grants twice, including after archival. This tool does not retry automatically. Returns: {achievements,newlyUnlocked,replayed,deliveryResults:[]}. On success explicitly refresh Player Values to replace the balance cache; do not claim or add a reward locally. Errors: 409 STATE_CONFLICT: reconcile and retry the same key. ACHIEVEMENT_NOT_MANUAL: report the configured statistic instead. MIGRATION_REQUIRED preserves legacy reward originals for the verified cold operator; it never authorizes a replacement reward or Inbox delivery. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | Stable configured achievement key; never replace it to retry an unlock | |
| userId | Yes | Signed-in player UUID matching the session | |
| sessionToken | Yes | Player accessToken, sent only as Authorization Bearer |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (readOnly=false, idempotent=true, destructive=false) by disclosing the transactional commit of the completion bit plus Player Values rewards, absence of an Inbox/reward-history copy, permanent no-double-grant semantics surviving archival, and no automatic retry. Auth requirements (HORIZON_API_KEY, session vs userId), and specific 401/403/409/429 behaviors are spelled out.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core sentence, then uses labeled sections (Use when, Not for, Requires, Side effects, Returns, Errors) that make skimming easy. The Errors paragraph is dense and somewhat sprawling, but nearly every clause carries actionable behavior rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by naming the return shape ({achievements,newlyUnlocked,replayed,deliveryResults}) and the required post-call step of refreshing Player Values. Combined with full side-effect and error coverage for a non-idempotent-looking write tool, an agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: userId must match the signed-in session and sessionToken is the accessToken from a signin call, plus the retry rule that the key must never be replaced. Only the key's pattern/length constraints remain schema-only.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb and resource ('Unlocks one configured manual achievement once for the authenticated player') including the 'once' cardinality and the 'manual' qualifier. The 'Not for: statistic achievements or client-chosen reward amounts' clause cleanly separates it from horizon_update_statistics and horizon_get_achievements.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when: an explicit game event meets this manual achievement's rule' and 'Not for' exclusions, plus a concrete prerequisite path naming horizon_signin_email / horizon_signin_anonymous as the way to obtain sessionToken. Nothing about selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_update_groupUpdate GroupADestructiveIdempotent
Replaces the complete group metadata and private JSON object. Use when: the player explicitly confirms the group settings. Not for: choosing/reusing a group ID or resending uncertain writes with a new revision. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Leader/officer and the current group revision. Side effects: Changes metadata, private data and join mode. Existing pending requests remain. Returns: {groups:MyGroupsView,group:GroupView|null}. groups is the actor's complete snapshot, never the target's private state. group is null after leave/delete; nonmembers never receive private data. Replace only the matching host/project/player cache. Errors: Use horizon_get_groups and horizon_get_group_pending to reconcile state. 409 REVISION_CONFLICT or uncertain response: read and reconcile intent, never refresh the revision and repeat automatically. Pending decisions require the original requestId; REQUEST_NOT_FOUND means it was removed/replaced. INBOX_FULL rolls back the entire action. 403 rejects group role, session or bilateral block violations. 429 is reported without automatic retry. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| data | Yes | Required finite JSON object; current maxDataBytes/maxDataDepth are server policies. Client JSON bytes can differ from stored dataJson after number normalization; the server validates the complete stored representation. No default2048-byte/depth16 clamp. Only members/admins can read it. | |
| name | Yes | Nonblank display name under current maxNameBytes; server enforces the complete BSON envelope | |
| userId | Yes | Signed-in player matching the Bearer session | |
| groupId | Yes | Exact group UUID in the current project; never an authorization credential | |
| joinMode | Yes | Whether players join directly, request admission or need an invitation | |
| description | Yes | Public description under current maxDescriptionBytes | |
| sessionToken | Yes | Player accessToken, sent only in Authorization | |
| expectedRevision | Yes | Exact reviewed revision; never replace automatically after an uncertain response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructive/idempotent/openWorld, but the description adds material context beyond them: it names what changes (metadata, private data, join mode), notes that pending requests survive, documents the return shape and cache-scoping rule, and explains revision/409, INBOX_FULL rollback, 403/429/401 semantics. This is rich behavioral disclosure that a destructive mutation genuinely needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the verb+scope, then labeled Use when / Not for / Requires / Side effects / Returns / Errors sections, which is good structure. It is long and has minor redundancy (429 and 401 are each revisited in the final sentence), so it earns most but not every sentence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 8 required params, a nested JSON object, and no output schema, the description carries the burden and does: it describes return values ({groups, group|null}), private-state leakage rules, side effects, auth flow, and error reconciliation. An agent could call and recover correctly from this text alone.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds acquisition semantics not in the schema: userId plus a sessionToken obtained from horizon_signin_email/anonymous, plus the leader/officer role requirement and the 'never refresh the revision and repeat automatically' rule for expectedRevision. Meaningful beyond the property descriptions, though it doesn't add much per-field detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb+resource+scope: replaces the *complete* group metadata and private JSON object. That full-replacement framing is reinforced by a 'Not for: choosing/reusing a group ID' exclusion, which separates it from horizon_create_group and other group tools without requiring the schema to be opened.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when/when-not: 'Use when: the player explicitly confirms the group settings' and 'Not for: choosing/reusing a group ID or resending uncertain writes with a new revision.' It also routes error recovery to horizon_get_groups and horizon_get_group_pending, giving the agent concrete alternatives rather than leaving inference to it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_update_statisticsUpdate Player Statistics BatchADestructiveIdempotent
Applies one explicit atomic session batch with a caller-persisted operation ID. Use when: reporting completed session counters, or retrying exactly the same durable ID and payload after an uncertain timeout. Not for: automatically generating another ID for a failed/unknown outcome, or one HTTP call per counter. Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Persist the original operationId and unchanged updates before sending. ID is <13-digit Unix milliseconds>:; use the snapshot server operation time for clock alignment. Side effects: Updates all counters atomically. A retained same-ID same-payload receipt replays; changed payload conflicts. Eight receipts and a persistent eviction floor can reject delayed out-of-order unknown IDs even within 24 hours; nothing is rebooked. Returns: The current statistics snapshot with operationId and replayed. Errors: 401 SESSION_REQUIRED: sign in again; 403 SESSION_FORBIDDEN: use the matching player. 409 OPERATION_CONFLICT means the ID was already used for a different payload. 410 OPERATION_EXPIRED rejects an expired/evicted unknown ID. Never replace an uncertain ID automatically. 422 UNKNOWN_STATISTIC/UPDATE_ABOVE_LIMIT/VALUE_OVERFLOW rejects the whole batch. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| userId | Yes | Signed-in player UUID matching the supplied session token | |
| updates | Yes | Original immutable batch of distinct statistic keys with safe integer values; server enforces the current System Config definition limit, which can exceed tier defaults | |
| operationId | Yes | Original durable <13-digit Unix milliseconds>:<UUID> operation ID; reuse unchanged on retry | |
| sessionToken | Yes | Player accessToken from horizon_signin_anonymous or horizon_signin_email; sent as Bearer |
Output Schema
| Name | Required | Description |
|---|---|---|
| userId | Yes | |
| values | Yes | |
| replayed | No | |
| revision | Yes | |
| definitions | Yes | |
| operationId | No | |
| newlyUnlocked | Yes | |
| operationWindow | Yes | |
| definitionVersion | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (destructive/idempotent/openWorld) by explaining the exact replay-vs-conflict semantics, the eight-receipt retention and eviction floor that can reject in-window unknown IDs, and that nothing is rebooked. It also documents auth sourcing (accessToken from signin tools), the HORIZON_API_KEY requirement, 401/403/409/410/422 error meanings, and 429 rate-limit handling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action, then uses labelled sections (Use when / Not for / Requires / Side effects / Returns / Errors) that an agent can scan quickly. It is long and has minor redundancy, e.g. 'Never replace an uncertain ID automatically' repeats the earlier retry rule, but nearly every sentence carries operational weight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, idempotent mutation with an output schema, the description covers prerequisites, idempotency contract, retention edge cases, return shape (snapshot plus operationId and replayed), and the full failure taxonomy. Nothing an agent needs to call this safely and correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description adds real meaning on top by explaining that the operationId must be persisted and reused verbatim on retry, that updates must stay unchanged, that the userId must match the session's player, and where sessionToken comes from. It does not restate the batch-size or value-range constraints beyond what the schema already enforces.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: applying one explicit atomic session batch of statistic counter updates with a caller-persisted operation ID. This clearly separates it from horizon_get_statistics (read) and horizon_adjust_player_value (player-values resource), with the atomic-batch scope making the distinction explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Uses explicit 'Use when' and 'Not for' clauses: use for reporting completed session counters or retrying the same durable ID after an uncertain timeout; not for minting new IDs on unknown outcomes or one HTTP call per counter. The alternatives and exclusions are named rather than implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_upload_evidenceUpload Validated Run EvidenceA
Uploads the input log of a validated run after horizon_submit_validated answered with evidence.required = true (evidence review). Use when: only when a submit result carries evidence.required: true, before evidence.uploadBefore (24 hours). Not for: runs without an evidence request (the server answers 404 EVIDENCE_NOT_REQUESTED) and sending the log with the submit (the submit takes only its hash). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. The runId from the submit result and the raw input log as exactly one of inputLogBase64 (raw bytes as base64) or inputLog (UTF-8 text). Its SHA-256 must equal the inputLogHash sent with the run, so pass the same bytes or text that were hashed at submit; at most evidence.maxBytes (32,768 bytes by default). Side effects: stores the log for the developer's review; one upload per run (a second one gets 409). Returns: {runId, status: "UPLOADED", bytes} plus inputLogHash (the SHA-256 of the uploaded bytes, for comparison with the submit). Errors: Errors carry a stable code in the body and the error result names it: 400 EVIDENCE_INVALID_ENCODING (not standard base64), 401 SESSION_REQUIRED, 403 SESSION_FORBIDDEN, 404 EVIDENCE_NOT_REQUESTED (no request for this run and player; also for a run of another player), 409 EVIDENCE_ALREADY_UPLOADED, 410 EVIDENCE_EXPIRED (window passed, slot freed), 413 EVIDENCE_TOO_LARGE (decoded log above maxBytes), 422 EVIDENCE_HASH_MISMATCH (SHA-256 of the log differs from the run's inputLogHash; the request stays open, retry with the correct bytes until uploadBefore), 429 without code (account request limit). Only 422 and network errors are worth a retry; the others are final. Local error (no request sent): INVALID_INPUT_LOG when the log input was missing, doubled, empty or not base64. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| runId | Yes | runId (UUID) from the horizon_submit_validated result (evidence.runId) | |
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* | |
| inputLog | No | Input log as UTF-8 text; its UTF-8 bytes are uploaded. Use this or inputLogBase64. | |
| sessionToken | Yes | accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session | |
| inputLogBase64 | No | Raw input log bytes as standard base64. Use this or inputLog. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare the safety profile (readOnlyHint=false, idempotentHint=false, destructiveHint=false); the description goes well beyond them, disclosing auth prerequisites (signin + accessToken as sessionToken, HORIZON_API_KEY), the one-upload-per-run limit (409), size cap (maxBytes 32,768), rate limiting (429), and a full enumerated error table with retry-worthiness classification. That is exactly the behavioral context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded and organized with clear Use when / Not for / Requires / Side effects / Returns / Errors sections, so the agent can scan to what it needs. It is dense and the closing paragraph restates the 401 and 429 semantics already implied above, which is minor redundancy rather than bloat.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description supplies the return shape ({runId, status, bytes, inputLogHash}) and its comparison purpose. Combined with prerequisites, limits, side effects, and error handling, an agent has everything needed to invoke this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real semantics: the mutual exclusivity of inputLog/inputLogBase64, the requirement that the uploaded bytes' SHA-256 equal the submit's inputLogHash, where each token originates, and a 32,768-byte effective cap that differs from the schema's maxLength. It does not need to do more since the schema documents each field.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Uploads the input log of a validated run') and ties it directly to the producing sibling (horizon_submit_validated with evidence.required = true). An agent can distinguish it from submit tools and from unrelated uploads without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' (only after a submit result carries evidence.required: true, before evidence.uploadBefore/24h) and 'Not for' clauses that name the failure the server returns (404 EVIDENCE_NOT_REQUESTED) and the alternative pattern (passing the log with the submit, which only takes a hash). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
horizon_validate_gift_codeValidate Gift CodeARead-onlyIdempotent
Checks whether a gift code is currently valid for a player without consuming or preparing it. Use when: showing an early validity message; horizon_prepare_gift_code prepares a consumable V2 identity. Not for: claiming rewards (use horizon_redeem_gift_code with an already persisted intent). Requires: userId from horizon_signup_* or horizon_signin_*; no session token. Side effects: None (read only). Returns: {valid}; a validity check reserves nothing and cannot recover an uncertain redemption. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Original visible gift code, retained with the prepared campaign identity | |
| userId | Yes | Player user ID (UUID) from horizon_signup_* or horizon_signin_* |
Output Schema
| Name | Required | Description |
|---|---|---|
| valid | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive, but the description goes further: reserves nothing, cannot recover an uncertain redemption, requires HORIZON_API_KEY, and no session token. It also maps specific error outcomes (401 vs 429) to causes and remedies, which annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) make it scannable and front-loaded. Slightly heavy on error prose and mildly redundant with 'None (read only)' given readOnlyHint, but every line still carries actionable content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-param read tool with full schema coverage and an output schema, nothing essential is missing: auth prerequisite, side-effect profile, return shape, and error handling are all covered. The description need not re-explain the return object since an output schema exists.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both params are documented in the schema, so the baseline of 3 applies. The 'Requires userId from horizon_signup_*' line reinforces provenance but largely restates the schema's own userId description without adding format or constraint detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (checks validity) and resource (gift code), and explicitly delimits scope: it does not consume or prepare the code. This unmistakably distinguishes it from horizon_prepare_gift_code and horizon_redeem_gift_code, both named in the text.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when' (early validity message) and 'Not for' (claiming rewards) clauses, each routed to the correct sibling. An agent can choose between validate/prepare/redeem without opening any schema.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
90 tool updates
v1.9.1- Added
horizon_accept_friend_request - Added
horizon_accept_group_invite - Added
horizon_accept_group_request - Added
horizon_adjust_item - Added
horizon_adjust_player_value - Added
horizon_advance_match_timeout - Added
horizon_block_player - Added
horizon_buy_marketplace_listing - Added
horizon_cancel_friend_request - Added
horizon_cancel_group_invite - Added
horizon_cancel_group_request - Added
horizon_cancel_marketplace_listing - Added
horizon_cancel_match - Added
horizon_claim_inbox - Added
horizon_create_group - Added
horizon_create_marketplace_listing - Added
horizon_create_match - Added
horizon_create_shared_object - Added
horizon_decline_friend_request - Added
horizon_decline_group_invite - Added
horizon_decline_group_request - Added
horizon_decline_match_invite - Added
horizon_delete_group - Added
horizon_delete_shared_object - Added
horizon_deliver_achievement_rewards - Added
horizon_discard_item - Added
horizon_equip_item - Added
horizon_find_open_matches - Added
horizon_find_player - Added
horizon_get_achievements - Added
horizon_get_chat_limits - Added
horizon_get_chat_operation - Added
horizon_get_friends - Added
horizon_get_group - Added
horizon_get_group_members - Added
horizon_get_group_pending - Added
horizon_get_groups - Added
horizon_get_inbox - Added
horizon_get_item_catalog - Added
horizon_get_items - Added
horizon_get_marketplace - Added
horizon_get_marketplace_limits - Added
horizon_get_marketplace_listing - Added
horizon_get_marketplace_operation - Added
horizon_get_marketplace_rules - Added
horizon_get_match - Added
horizon_get_match_limits - Added
horizon_get_matches - Added
horizon_get_player_value_offers - Added
horizon_get_player_values - Added
horizon_get_shared_collections - Added
horizon_get_shared_object - Added
horizon_get_shared_usage - Added
horizon_get_statistics - Added
horizon_get_statistics_definitions - Added
horizon_invite_group_player - Added
horizon_join_group - Added
horizon_join_match - Added
horizon_leave_group - Added
horizon_leave_match - Changed
horizon_load_cloud_data1 field changed- added
Output schema / properties / revisionAdded value: +{ + "anyOf": [ + { + "description": "Server revision (0 = empty slot), to pass as expectedRevision when saving. Null when unknown", + "type": "number" + }, + { + "type": "null" + } + ] +}
- Added
horizon_mark_inbox_read - Added
horizon_open_chat_channel - Added
horizon_prepare_gift_code - Added
horizon_purchase_player_value_offer - Added
horizon_query_marketplace_listings - Added
horizon_query_shared_objects - Changed
horizon_redeem_gift_code6 fields changed- changed
Input schema / properties / code / descriptionPrevious value: -"Gift code as the player typed it (max 50 characters)"New value: +"Obsolete V1 argument, rejected with UPGRADE_REQUIRED; use the original saved intent" - added
Input schema / properties / idempotencyIdAdded value: +{ + "description": "Obsolete arbitrary V1 ID, never translated to a V2 sequence; rejected without HTTP", + "type": "string" +} - added
Input schema / properties / intentAdded value: +{ + "additionalProperties": false, + "description": "Required V2 recovery object: the exact seven fields durably saved from horizon_prepare_gift_code; never retarget or advance it", + "properties": { + "campaignId": { + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000)$", + "type": "string" + }, + "code": { + "maxLength": 50, + "minLength": 1, + "type": "string" + }, + "configRevision": { + "maxLength": 19, + "pattern": "^(0|[1-9][0-9]*)$", + "type": "string" + }, + "expectedCount": { + "maxLength": 19, + "pattern": "^(0|[1-9][0-9]*)$", + "type": "string" + }, + "projectScope": { + "pattern": "^[a-f0-9]{64}$", + "type": "string" + }, + "protocolVersion": { + "const": 2, + "type": "number" + }, + "userId": { + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000)$", + "type": "string" + } + }, + "required": [ + "protocolVersion", + "projectScope", + "userId", + "code", + "campaignId", + "expectedCount", + "configRevision" + ], + "type": "object" +} - changed
Input schema / properties / sessionToken / descriptionPrevious value: -"accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session"New value: +"Current accessToken of the intent's original user, sent only as a Bearer header" - changed
Input schema / properties / userId / descriptionPrevious value: -"Player user ID (UUID) from horizon_signup_* or horizon_signin_*"New value: +"Obsolete V1 argument, rejected with UPGRADE_REQUIRED; the original owner is inside intent" - changed
Input schema / requiredPrevious value: -[ - "code", - "userId", - "sessionToken" -]New value: +[ + "sessionToken" +]
- Added
horizon_remove_friend - Added
horizon_remove_group_member - Added
horizon_remove_inbox - Added
horizon_report_chat_message - Added
horizon_report_match_result - Added
horizon_request_group_join - Added
horizon_retry_marketplace_return - Changed
horizon_save_cloud_data1 field changed- added
Input schema / properties / expectedRevisionAdded value: +{ + "description": "Optional. Revision the save must still have, sent as If-Match: 0 for an empty slot, else the revision from horizon_load_cloud_data or the last save. Omit for an unconditional overwrite.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" +}
- Added
horizon_send_chat_message - Added
horizon_send_friend_request - Added
horizon_set_group_member_role - Added
horizon_start_match - Added
horizon_start_match_ranked_run - Added
horizon_submit_match_turn - Added
horizon_sync_chat_channel - Added
horizon_transfer_group_leadership - Added
horizon_unblock_player - Added
horizon_unlock_achievement - Added
horizon_update_group - Added
horizon_update_shared_object - Added
horizon_update_statistics - Changed
horizon_validate_gift_code1 field changed- changed
Input schema / properties / code / descriptionPrevious value: -"Gift code as the player typed it (max 50 characters)"New value: +"Original visible gift code, retained with the prepared campaign identity"
1 tool update
v1.7.0- Changed
horizon_start_run6 fields changed- added
Input schema / properties / contentDigestAdded value: +{ + "description": "SHA-256 of the game content the run uses, 64 hex characters (sent in lower case). Optional", + "pattern": "^[0-9a-fA-F]{64}$", + "type": "string" +} - added
Input schema / properties / contentVersionAdded value: +{ + "description": "Version of the game content (levels, balancing data) the run uses (1 to 64 printable ASCII characters), stored in the run's start context. Optional", + "pattern": "^[\\x20-\\x7E]{1,64}$", + "type": "string" +} - added
Input schema / properties / gameVersionAdded value: +{ + "description": "Game build version, for example \"1.4.2\" (1 to 64 printable ASCII characters), stored in the run's start context. Optional", + "pattern": "^[\\x20-\\x7E]{1,64}$", + "type": "string" +} - added
Input schema / properties / initialStateBase64Added value: +{ + "description": "Bytes the simulation starts from as standard base64 (sent as context.initialState); decoded at most the plan's evidenceMaxBytes (32,768 bytes by default). Optional", + "maxLength": 2000000, + "type": "string" +} - added
Input schema / properties / replayFormatVersionAdded value: +{ + "description": "Format version of the recorded input log (1 to 64 printable ASCII characters), stored in the run's start context. Optional", + "pattern": "^[\\x20-\\x7E]{1,64}$", + "type": "string" +} - added
Input schema / properties / simulationVersionAdded value: +{ + "description": "Version of the deterministic simulation that replays the input log (1 to 64 printable ASCII characters), stored in the run's start context. Optional", + "pattern": "^[\\x20-\\x7E]{1,64}$", + "type": "string" +}
34 tool updates
v1.6.0- Changed
horizon_cancel_email1 field changed- changed
Input schema / properties / emailId / descriptionPrevious value: -"ID of the email to cancel (returned by send_email)"New value: +"Email ID (UUID) returned by horizon_send_email"
- Changed
horizon_check_auth4 fields changed- changed
Input schema / properties / sessionToken / descriptionPrevious value: -"accessToken returned by a horizon_signin_* tool (max 256 characters)"New value: +"accessToken from horizon_signin_email or horizon_signin_anonymous (max 256 characters)" - added
Input schema / properties / sessionToken / minLengthAdded value: +1 - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from the result of horizon_signup_* or horizon_signin_*" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "authStatus": { + "anyOf": [ + { + "description": "Server auth status name", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "isAuthenticated": { + "anyOf": [ + { + "description": "true when the session is valid", + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "message": { + "anyOf": [ + { + "description": "Human-readable status message", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "userId": { + "anyOf": [ + { + "description": "User ID the session belongs to", + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" +}
- Changed
horizon_create_crash_report9 fields changed- changed
Input schema / properties / breadcrumbs / descriptionPrevious value: -"Activity trail before the crash (max 50 items)"New value: +"Recent events before the crash, oldest first (max 50)" - changed
Input schema / properties / breadcrumbs / items / properties / timestamp / descriptionPrevious value: -"When the event occurred"New value: +"When the event occurred, ISO 8601 (for example 2026-09-29T14:03:12Z)" - changed
Input schema / properties / customKeys / descriptionPrevious value: -"Key-value metadata (max 10 entries)"New value: +"String key to string value metadata such as level or build flavor (max 10 entries)" - changed
Input schema / properties / deviceMemoryMb / descriptionPrevious value: -"Device RAM in MB"New value: +"Device RAM in MB, for example 8192" - changed
Input schema / properties / fingerprint / descriptionPrevious value: -"Grouping key — crashes with the same fingerprint are grouped together (1-128 characters)"New value: +"Grouping key: reports with the same fingerprint form one crash group, for example a hash of exception type and top stack frame (1 to 128 characters)" - changed
Input schema / properties / message / descriptionPrevious value: -"Error message (1-5000 characters)"New value: +"Error or exception message (1 to 5000 characters)" - changed
Input schema / properties / sdkVersion / descriptionPrevious value: -"horizOn SDK version"New value: +"horizOn SDK version, for example '1.8.2' (1 to 50 characters)" - changed
Input schema / properties / sessionId / descriptionPrevious value: -"Session ID from horizon_create_crash_session"New value: +"The sessionId registered with horizon_create_crash_session for this app run (1 to 100 characters)" - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID) who experienced the crash"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*, if a player is signed in"
- Changed
horizon_create_crash_session2 fields changed- changed
Input schema / properties / sessionId / descriptionPrevious value: -"Unique session identifier (1-100 characters)"New value: +"New unique ID for this app run, for example a UUID generated at start (1 to 100 characters)" - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID) starting the session"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*, if a player is signed in"
- Changed
horizon_create_log3 fields changed- changed
Input schema / properties / errorCode / descriptionPrevious value: -"Error code (max 50 characters)"New value: +"Optional code to group entries in the dashboard, useful with ERROR, for example 'IAP_TIMEOUT' (max 50 characters)" - changed
Input schema / properties / type / descriptionPrevious value: -"Log level: INFO, WARN, or ERROR"New value: +"Log level: INFO, WARN or ERROR" - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*"
- Changed
horizon_get_all_localizations2 fields changed- changed
Input schema / properties / lang / descriptionPrevious value: -"ISO 639-1 language code (2 characters). One of: en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id."New value: +"ISO 639-1 language code (2 lowercase letters). One of: en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id. Omit for the app's default language." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "language": { + "anyOf": [ + { + "description": "ISO 639-1 code of the language used", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "total": { + "anyOf": [ + { + "description": "Number of translations", + "type": "number" + }, + { + "type": "null" + } + ] + }, + "translations": { + "anyOf": [ + { + "additionalProperties": { + "type": "string" + }, + "description": "Map of localization key to translated text", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" +}
- Changed
horizon_get_all_remote_configs1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "configs": { + "anyOf": [ + { + "additionalProperties": { + "type": "string" + }, + "description": "Map of config key to string value", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + { + "type": "null" + } + ] + }, + "total": { + "anyOf": [ + { + "description": "Number of configs", + "type": "number" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" +}
- Changed
horizon_get_email_status2 fields changed- changed
Input schema / properties / emailId / descriptionPrevious value: -"ID of the email to check (returned by send_email)"New value: +"Email ID (UUID) returned by horizon_send_email" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "createdAt": { + "anyOf": [ + { + "description": "When the email was queued", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "errorReason": { + "anyOf": [ + { + "description": "Why sending failed, null unless failed", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "id": { + "anyOf": [ + { + "description": "Email ID", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "language": { + "anyOf": [ + { + "description": "Template language", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "processedAt": { + "anyOf": [ + { + "description": "When the email was processed, null while pending", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "scheduledAt": { + "anyOf": [ + { + "description": "Scheduled send time, null for immediate", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "status": { + "anyOf": [ + { + "description": "pending, processing, sent or failed", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "templateSlug": { + "anyOf": [ + { + "description": "Template used", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "userId": { + "anyOf": [ + { + "description": "Recipient user ID", + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" +}
- Changed
horizon_get_leaderboard_around4 fields changed- changed
Input schema / properties / leaderboardKey / descriptionPrevious value: -"Leaderboard key — selects a named board on the API key. Omit to use the default board."New value: +"Board key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board." - changed
Input schema / properties / range / descriptionPrevious value: -"Number of entries around the user (1-50, default 10)"New value: +"How many entries around the player to return, 1 to 50 (default 10)" - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "entries": { + "anyOf": [ + { + "description": "Leaderboard entries in board order", + "items": { + "additionalProperties": {}, + "properties": { + "position": { + "anyOf": [ + { + "description": "1-based position on the board", + "type": "number" + }, + { + "type": "null" + } + ] + }, + "profile": { + "anyOf": [ + { + "additionalProperties": {}, + "description": "The player's displayed cosmetics", + "properties": { + "avatarId": { + "anyOf": [ + { + "description": "Avatar cosmetic ID, null when not set", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "badges": { + "anyOf": [ + { + "description": "Displayed badge cosmetic IDs (0 to 3)", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ] + }, + "frameId": { + "anyOf": [ + { + "description": "Frame cosmetic ID, null when not set", + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + { + "type": "null" + } + ] + }, + "score": { + "anyOf": [ + { + "description": "Best score of the player on this board", + "type": "number" + }, + { + "type": "null" + } + ] + }, + "username": { + "anyOf": [ + { + "description": "Player display name", + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" +}
- Changed
horizon_get_leaderboard_top4 fields changed- changed
Input schema / properties / leaderboardKey / descriptionPrevious value: -"Leaderboard key — selects a named board on the API key. Omit to use the default board."New value: +"Board key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board." - changed
Input schema / properties / limit / descriptionPrevious value: -"Number of top entries to return (1-100, default 10)"New value: +"Number of top entries to return, 1 to 100 (default 10)" - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "entries": { + "anyOf": [ + { + "description": "Leaderboard entries in board order", + "items": { + "additionalProperties": {}, + "properties": { + "position": { + "anyOf": [ + { + "description": "1-based position on the board", + "type": "number" + }, + { + "type": "null" + } + ] + }, + "profile": { + "anyOf": [ + { + "additionalProperties": {}, + "description": "The player's displayed cosmetics", + "properties": { + "avatarId": { + "anyOf": [ + { + "description": "Avatar cosmetic ID, null when not set", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "badges": { + "anyOf": [ + { + "description": "Displayed badge cosmetic IDs (0 to 3)", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ] + }, + "frameId": { + "anyOf": [ + { + "description": "Frame cosmetic ID, null when not set", + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + { + "type": "null" + } + ] + }, + "score": { + "anyOf": [ + { + "description": "Best score of the player on this board", + "type": "number" + }, + { + "type": "null" + } + ] + }, + "username": { + "anyOf": [ + { + "description": "Player display name", + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" +}
- Changed
horizon_get_localization4 fields changed- changed
Input schema / properties / key / descriptionPrevious value: -"Localization key as defined in the dashboard, e.g. 'ui.play_button' (max 100 characters)"New value: +"Localization key exactly as defined in the dashboard, for example 'ui.play_button' (max 100 characters)" - added
Input schema / properties / key / minLengthAdded value: +1 - changed
Input schema / properties / lang / descriptionPrevious value: -"ISO 639-1 language code (2 characters). One of: en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id."New value: +"ISO 639-1 language code (2 lowercase letters). One of: en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id. Omit for the app's default language." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "found": { + "anyOf": [ + { + "description": "false when the key has no translation", + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "language": { + "anyOf": [ + { + "description": "ISO 639-1 code of the language used", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "localizationKey": { + "anyOf": [ + { + "description": "The requested key", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "value": { + "anyOf": [ + { + "description": "The translated text, null when not found", + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" +}
- Changed
horizon_get_localization_languages1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "languages": { + "anyOf": [ + { + "description": "ISO 639-1 codes with at least one translation", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ] + }, + "total": { + "anyOf": [ + { + "description": "Number of languages", + "type": "number" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" +}
- Changed
horizon_get_news2 fields changed- changed
Input schema / properties / languageCode / descriptionPrevious value: -"ISO 639-1 language code (2 characters, e.g. 'en')"New value: +"ISO 639-1 code (2 lowercase letters, for example 'en' or 'de') to return only entries in that language. Omit for all languages" - changed
Input schema / properties / limit / descriptionPrevious value: -"Number of news items to return (0-100, default 20)"New value: +"Maximum number of entries to return, 0 to 100 (default 20)"
- Added
horizon_get_profile - Changed
horizon_get_remote_config3 fields changed- changed
Input schema / properties / key / descriptionPrevious value: -"Configuration key as defined in the dashboard, case-sensitive (max 256 characters)"New value: +"Config key exactly as defined in the dashboard, case-sensitive, for example 'max_lives' (max 256 characters)" - added
Input schema / properties / key / minLengthAdded value: +1 - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "configKey": { + "anyOf": [ + { + "description": "The requested key", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "configValue": { + "anyOf": [ + { + "description": "The value as a string, null when not found", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "found": { + "anyOf": [ + { + "description": "false when the key does not exist", + "type": "boolean" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" +}
- Added
horizon_get_state - Changed
horizon_get_user_rank3 fields changed- changed
Input schema / properties / leaderboardKey / descriptionPrevious value: -"Leaderboard key — selects a named board on the API key. Omit to use the default board."New value: +"Board key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board." - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "position": { + "anyOf": [ + { + "description": "1-based position on the board", + "type": "number" + }, + { + "type": "null" + } + ] + }, + "profile": { + "anyOf": [ + { + "additionalProperties": {}, + "description": "The player's displayed cosmetics", + "properties": { + "avatarId": { + "anyOf": [ + { + "description": "Avatar cosmetic ID, null when not set", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "badges": { + "anyOf": [ + { + "description": "Displayed badge cosmetic IDs (0 to 3)", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ] + }, + "frameId": { + "anyOf": [ + { + "description": "Frame cosmetic ID, null when not set", + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + { + "type": "null" + } + ] + }, + "score": { + "anyOf": [ + { + "description": "Best score of the player on this board", + "type": "number" + }, + { + "type": "null" + } + ] + }, + "username": { + "anyOf": [ + { + "description": "Player display name", + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" +}
- Changed
horizon_list_leaderboards1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "boards": { + "anyOf": [ + { + "description": "Boards of the API key", + "items": { + "additionalProperties": {}, + "properties": { + "isActive": { + "anyOf": [ + { + "description": "false when the board is disabled", + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "key": { + "anyOf": [ + { + "description": "Board key to pass as leaderboardKey", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "name": { + "anyOf": [ + { + "description": "Display name", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "scoreCount": { + "anyOf": [ + { + "description": "Number of entries", + "type": "number" + }, + { + "type": "null" + } + ] + }, + "sortOrder": { + "anyOf": [ + { + "description": "DESC (higher wins) or ASC (lower wins)", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "validatedOnly": { + "anyOf": [ + { + "description": "true when only horizon_submit_validated may write scores", + "type": "boolean" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } + ] + }, + "totalElements": { + "anyOf": [ + { + "description": "Number of boards", + "type": "number" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" +}
- Changed
horizon_load_cloud_data3 fields changed- changed
Input schema / properties / sessionToken / descriptionPrevious value: -"accessToken returned by horizon_signin_email or horizon_signin_anonymous for this user; sent as a Bearer session"New value: +"accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session" - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "found": { + "anyOf": [ + { + "description": "false when the player never saved", + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "saveData": { + "anyOf": [ + { + "description": "The stored save string, null when found is false", + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" +}
- Changed
horizon_redeem_gift_code5 fields changed- changed
Input schema / properties / code / descriptionPrevious value: -"Gift code to redeem (max 50 characters)"New value: +"Gift code as the player typed it (max 50 characters)" - added
Input schema / properties / code / minLengthAdded value: +1 - added
Input schema / properties / sessionTokenAdded value: +{ + "description": "accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session", + "maxLength": 256, + "minLength": 1, + "type": "string" +} - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*" - changed
Input schema / requiredPrevious value: -[ - "code", - "userId" -]New value: +[ + "code", + "userId", + "sessionToken" +]
- Changed
horizon_save_cloud_data3 fields changed- changed
Input schema / properties / data / descriptionPrevious value: -"Save data string, usually serialized JSON (max 300,000 characters; the tier limit is usually lower)"New value: +"The complete save as a string, usually serialized JSON (max 300,000 characters; the tier limit is usually lower)" - changed
Input schema / properties / sessionToken / descriptionPrevious value: -"accessToken returned by horizon_signin_email or horizon_signin_anonymous for this user; sent as a Bearer session"New value: +"accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session" - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*"
- Changed
horizon_send_email5 fields changed- changed
Input schema / properties / language / descriptionPrevious value: -"ISO 639-1 language code for template rendering (e.g. 'en', 'de')"New value: +"ISO 639-1 code (2 lowercase letters) of the template translation to render, for example 'en' or 'de'" - changed
Input schema / properties / scheduledAt / descriptionPrevious value: -"ISO 8601 timestamp for scheduled delivery. Omit to send immediately."New value: +"ISO 8601 timestamp for delayed delivery, at most 30 days ahead, for example 2026-10-01T09:00:00Z. Omit to send immediately" - changed
Input schema / properties / templateSlug / descriptionPrevious value: -"Slug of the email template (e.g. 'welcome', 'reminder')"New value: +"Slug of an email template defined in the dashboard, for example 'welcome' or 'reminder'" - changed
Input schema / properties / userId / descriptionPrevious value: -"horizOn user ID of the recipient"New value: +"Player user ID (UUID) of the recipient; the player needs a verified email address" - changed
Input schema / properties / variables / descriptionPrevious value: -"Template variable values as key-value pairs (e.g. {\"username\": \"John\"})"New value: +"Values for the template's variables as a string map, for example {\"username\": \"John\"}; pass {} when the template has none"
- Added
horizon_set_profile - Changed
horizon_signin_anonymous3 fields changed- changed
Input schema / properties / anonymousToken / descriptionPrevious value: -"anonymousToken returned by horizon_signup_anonymous (max 32 characters)"New value: +"anonymousToken returned by horizon_signup_anonymous (exactly 32 characters: letters, digits, _ and -)" - added
Input schema / properties / anonymousToken / minLengthAdded value: +32 - added
Input schema / properties / anonymousToken / patternAdded value: +"^[A-Za-z0-9_-]+$"
- Changed
horizon_signin_email5 fields changed- changed
Input schema / properties / email / descriptionPrevious value: -"Email address"New value: +"Email address the account was registered with (max 40 characters)" - added
Input schema / properties / email / maxLengthAdded value: +40 - changed
Input schema / properties / password / descriptionPrevious value: -"Password"New value: +"Account password (max 128 characters); sent to the API only, never returned" - added
Input schema / properties / password / maxLengthAdded value: +128 - added
Input schema / properties / password / minLengthAdded value: +1
- Changed
horizon_signup_anonymous1 field changed- changed
Input schema / properties / displayName / descriptionPrevious value: -"Display name for the anonymous user (max 30 characters)"New value: +"Display name shown on leaderboards (max 30 characters)"
- Changed
horizon_signup_email5 fields changed- changed
Input schema / properties / displayName / descriptionPrevious value: -"Display name (max 30 characters)"New value: +"Display name shown on leaderboards (max 30 characters)" - changed
Input schema / properties / email / descriptionPrevious value: -"Email address (max 40 characters)"New value: +"Player email address (valid format, max 40 characters); must not be registered yet" - changed
Input schema / properties / password / descriptionPrevious value: -"Password (4-32 characters)"New value: +"Password, 8 to 128 characters; common passwords such as \"password1\" are rejected. Sent to the API only, never returned" - changed
Input schema / properties / password / maxLengthPrevious value: -32New value: +128 - changed
Input schema / properties / password / minLengthPrevious value: -4New value: +8
- Added
horizon_start_run - Changed
horizon_submit_feedback6 fields changed- changed
Input schema / properties / category / descriptionPrevious value: -"Feedback category, free text such as BUG, FEATURE or GENERAL (max 50 characters)"New value: +"Free text category (max 50 characters); the horizOn SDKs use BUG, FEATURE and GENERAL. Omit for none" - changed
Input schema / properties / deviceInfo / descriptionPrevious value: -"Device information (max 500 characters)"New value: +"Device and OS details for bug reports, for example 'Pixel 8, Android 14' (max 500 characters)" - changed
Input schema / properties / email / descriptionPrevious value: -"Contact email address"New value: +"Contact email address for a reply, if the player wants one" - changed
Input schema / properties / message / descriptionPrevious value: -"Feedback message (1-2048 characters)"New value: +"Full feedback text (1 to 2048 characters)" - changed
Input schema / properties / title / descriptionPrevious value: -"Feedback title (1-100 characters)"New value: +"Short summary shown in the dashboard list (1 to 100 characters)" - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*"
- Changed
horizon_submit_score4 fields changed- changed
Input schema / properties / leaderboardKey / descriptionPrevious value: -"Leaderboard key — selects a named board on the API key. Omit to use the default board."New value: +"Board key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board." - changed
Input schema / properties / score / descriptionPrevious value: -"Score to submit (non-negative integer)"New value: +"Score to submit, a non-negative integer" - changed
Input schema / properties / sessionToken / descriptionPrevious value: -"accessToken returned by horizon_signin_email or horizon_signin_anonymous for this user; sent as a Bearer session"New value: +"accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session" - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*"
- Added
horizon_submit_validated - Changed
horizon_test_connection1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "data": { + "anyOf": [ + { + "description": "The app's remote configs as returned by the API" + }, + { + "type": "null" + } + ] + }, + "success": { + "anyOf": [ + { + "description": "true when the API key and base URL work", + "type": "boolean" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" +}
- Added
horizon_upload_evidence - Changed
horizon_validate_gift_code4 fields changed- changed
Input schema / properties / code / descriptionPrevious value: -"Gift code to validate (max 50 characters)"New value: +"Gift code as the player typed it (max 50 characters)" - added
Input schema / properties / code / minLengthAdded value: +1 - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "valid": { + "anyOf": [ + { + "description": "true when the player can redeem the code now", + "type": "boolean" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" +}
14 tool updates
v1.5.5- Changed
horizon_check_auth2 fields changed- changed
Input schema / properties / sessionToken / descriptionPrevious value: -"Session token (max 256 characters)"New value: +"accessToken returned by a horizon_signin_* tool (max 256 characters)" - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
- Changed
horizon_create_log1 field changed- changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
- Changed
horizon_get_leaderboard_around1 field changed- changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
- Changed
horizon_get_leaderboard_top1 field changed- changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
- Changed
horizon_get_localization1 field changed- changed
Input schema / properties / key / descriptionPrevious value: -"Localization key (max 100 characters)"New value: +"Localization key as defined in the dashboard, e.g. 'ui.play_button' (max 100 characters)"
- Changed
horizon_get_remote_config1 field changed- changed
Input schema / properties / key / descriptionPrevious value: -"Configuration key (max 256 characters)"New value: +"Configuration key as defined in the dashboard, case-sensitive (max 256 characters)"
- Changed
horizon_get_user_rank1 field changed- changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
- Changed
horizon_load_cloud_data3 fields changed- added
Input schema / properties / sessionTokenAdded value: +{ + "description": "accessToken returned by horizon_signin_email or horizon_signin_anonymous for this user; sent as a Bearer session", + "maxLength": 256, + "minLength": 1, + "type": "string" +} - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool" - changed
Input schema / requiredPrevious value: -[ - "userId" -]New value: +[ + "userId", + "sessionToken" +]
- Changed
horizon_redeem_gift_code1 field changed- changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
- Changed
horizon_save_cloud_data4 fields changed- changed
Input schema / properties / data / descriptionPrevious value: -"Save data string (max 300,000 characters)"New value: +"Save data string, usually serialized JSON (max 300,000 characters; the tier limit is usually lower)" - added
Input schema / properties / sessionTokenAdded value: +{ + "description": "accessToken returned by horizon_signin_email or horizon_signin_anonymous for this user; sent as a Bearer session", + "maxLength": 256, + "minLength": 1, + "type": "string" +} - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool" - changed
Input schema / requiredPrevious value: -[ - "userId", - "data" -]New value: +[ + "userId", + "data", + "sessionToken" +]
- Changed
horizon_signin_anonymous1 field changed- changed
Input schema / properties / anonymousToken / descriptionPrevious value: -"Anonymous token (max 32 characters)"New value: +"anonymousToken returned by horizon_signup_anonymous (max 32 characters)"
- Changed
horizon_submit_feedback2 fields changed- changed
Input schema / properties / category / descriptionPrevious value: -"Feedback category (max 50 characters)"New value: +"Feedback category, free text such as BUG, FEATURE or GENERAL (max 50 characters)" - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
- Changed
horizon_submit_score3 fields changed- added
Input schema / properties / sessionTokenAdded value: +{ + "description": "accessToken returned by horizon_signin_email or horizon_signin_anonymous for this user; sent as a Bearer session", + "maxLength": 256, + "minLength": 1, + "type": "string" +} - changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool" - changed
Input schema / requiredPrevious value: -[ - "userId", - "score" -]New value: +[ + "userId", + "score", + "sessionToken" +]
- Changed
horizon_validate_gift_code1 field changed- changed
Input schema / properties / userId / descriptionPrevious value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
28 tool updates
v1.5.4- First observed
horizon_cancel_email - First observed
horizon_check_auth - First observed
horizon_create_crash_report - First observed
horizon_create_crash_session - First observed
horizon_create_log - First observed
horizon_get_all_localizations - First observed
horizon_get_all_remote_configs - First observed
horizon_get_email_status - First observed
horizon_get_leaderboard_around - First observed
horizon_get_leaderboard_top - First observed
horizon_get_localization - First observed
horizon_get_localization_languages - First observed
horizon_get_news - First observed
horizon_get_remote_config - First observed
horizon_get_user_rank - First observed
horizon_list_leaderboards - First observed
horizon_load_cloud_data - First observed
horizon_redeem_gift_code - First observed
horizon_save_cloud_data - First observed
horizon_send_email - First observed
horizon_signin_anonymous - First observed
horizon_signin_email - First observed
horizon_signup_anonymous - First observed
horizon_signup_email - First observed
horizon_submit_feedback - First observed
horizon_submit_score - First observed
horizon_test_connection - First observed
horizon_validate_gift_code
TDQS
Scored across 120 tools
Most tools map cleanly to a resource+action pair, and the descriptions are unusually explicit about 'Use when'/'Not for'. However, there are real collisions: horizon_get_marketplace and horizon_get_marketplace_limits share literally the same described purpose, and horizon_get_shared_collections vs horizon_get_shared_usage vs horizon_query_shared_objects have near-identical descriptions. With 120 tools, an agent must also distinguish many closely-related lifecycle verbs (e.g. start_match_ranked_run vs start_run vs start_match).
Every tool uses the horizon_namespace with a consistent snake_case verb_noun pattern (get_, create_, update_, delete_, list_, submit_, cancel_, accept_). Singular/plural resource names are used predictably (get_item vs get_items). No camelCase or ad-hoc verb mixing.
120 tools is far beyond what an agent can reliably navigate in one surface, placing it in the extreme-mismatch band. Even though the server legitimately spans many subsystems (accounts, groups, friends, inventory, marketplace, chat, matches, leaderboards, cloud save, stats), each domain could be exposed as a smaller focused endpoint set.
Coverage is remarkably thorough: full CRUD plus lifecycle and reconciliation for social, group, inventory, marketplace, chat, matches, leaderboards, validated runs, inbox, profile, cloud save, crash reporting, localization and email. Minor gaps exist (e.g. no explicit evidence-download/delete, limited chat moderation tooling), but nearly every workflow has a complete path with read-after-write recovery tools.
Maintenance
Related MCP Connectors
- NebllaOAuthcom.neblla
The backend and back office for apps your AI writes: accounts, data, payments, content, real-time.
Backend for AI-built apps: database, auth, files, email, AI, payments, deploy, realtime. 170+ tools.
Backend for AI agents: one batched tool over ~668 actions (hosting, storage, auth, payments).
Zero-setup MCP gateway securely connecting AI to your tools with authentication and workflows
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to interact with Godot game projects through real-time error detection, automated testing, code analysis, and safe git-based patching. Provides comprehensive project context and development workflow automation for Godot developers.MIT
- AlicenseNot gradedqualityCmaintenanceProvides a comprehensive integration between LLMs and the Godot Engine, enabling AI assistants to intelligently manipulate project files, scripts, and the live editor. It supports advanced workflows including version-aware documentation querying, automated E2E game testing, and real-time visual context capture.9 npm26MIT
- AlicenseNot gradedqualityDmaintenanceProvides AI assistants with access to the complete Godot Engine documentation, enabling developers to get answers about Godot classes, tutorials, and features directly in their chat interface.73MIT
- AlicenseCqualityCmaintenanceEnables AI agents to interact with the Godot game engine, including project inspection, scene/script parsing, headless exports, runtime control with live scene-tree inspection and evaluation, and API documentation search.100722 npm4MIT