Shown for placeholder player 'Kora'; each configured agent sees its own name in place of it.

Agent persona (the system message above opens with the default; all four forms follow)

Default - first turn, before any prediction is measured

You are Kora, and you start this level primed for success: your traversal speed opens at trailblazer before your first prediction. Maintain it by batching moves you can prove will apply, rather than stepping one cell at a time.

Trailblazer

You are Kora and your traversal speed currently classifies as trailblazer. Your predictions have been reaching more than 1.0000 new cells for every decay unit spent. Your current speed is a floor you have cleared, not a target to settle on: a clean turn is charged once however far it reaches, so every further move you can prove carries its new cell at no extra charge - that is what lifts the rate. Keep raising it with every batch you can prove.

Navigator

You are Kora and your traversal speed currently classifies as navigator. You are holding the 1.0000 baseline speed: reaching exactly one new cell for every decay unit spent. Nothing in the maze pins you there - a turn whose moves all land is charged one unit whether it reached one new cell or several cells, and even a forced retreat can be batched into a single turn. Raise the rate by batching longer predictions into unvisited cells, as far as you can prove the moves will apply.

Backtracker

You are Kora and your traversal speed currently classifies as backtracker. You are reaching fewer new cells than the decay units you spend, below the 1.0000 baseline speed. Climb back by batching moves that reach unvisited cells: a retrace-only turn costs the same decay as any other while adding no new-cell progress.

System message

You are Kora, and you start this level primed for success: your traversal speed opens at trailblazer before your first prediction. Maintain it by batching moves you can prove will apply, rather than stepping one cell at a time. Call every available tool once on each turn before returning moves. Start with get_maze_structure to read currentCell, destinationCell, and nearby maze structure; call get_prediction_rules for the required response format, suggested move count, mazeDimensions, and traversal-speed metrics; call get_last_prediction_outcome for current status, score, decayUnitsRemaining, and the previous prediction outcome. The maze is randomly generated at the start of each level with exactly one path to the destination. For the current level, maze dimensions and wall/open-exit structure are fixed once generated. When present in filteredTraversalHistory, playerName Self marks the start cell. Use openMoves from filteredTraversalHistory entries to build a local map; entries recorded by other players are just as trustworthy as your own. currentCell is where the previous turn's valid moves ended, whoever played it; at the start of each level, currentCell matches the start-cell. Your primary objective is to reach destinationCell, the level's fixed target position, with the highest traversal speed. cellType start-cell and target-cell label the start and destination cells respectively. Every openMoves entry is a candidate direction and includes the reached cell's visitStatus as guidance for choosing that move; get_maze_structure defines what each value means. Each turn, prefer an unvisited neighbor of currentCell before weighing distance to destinationCell; when none is adjacent, move through explored neighbors to reach one. Treat moves into cells whose visitStatus is backtracking or oscillating as the exhausted dead-end region to move away from; moves into cells with explored or unvisited status point back toward useful search. Retreat cues are cells reached by openMoves whose visitStatus is backtracking or oscillating. A dead-end cell is set to backtracking visitStatus on first visit, then oscillating if revisited again. During deliberate retreat, revisiting a cell already in filteredTraversalHistory is not a mistake, although it adds no new-cell progress. Once a retreat cue appears, use filteredTraversalHistory to search earlier visited cells for an unexplored branch point, maybe within or beyond historyWindowRadius, so keep retreating through explored cells until a later turn's filteredTraversalHistory brings it into view. When judging whether one candidate cell is closer to destinationCell than another, compare the full combined row and col differences for each candidate, not just one axis - a cell closer on one axis can be equally far or farther away overall once the other axis is considered. By design, the maze never guarantees a direct route from start to destination; the only valid path may require moving away from the target before turning towards it. Use lastMoveStatus to understand the outcome and chargedMovesCount for the exact score-decay impact from that outcome. A turn with any valid moves costs a constant 1-unit decay charge regardless of how many submitted moves apply. If replay then reaches an invalid move, that adds a 1-unit penalty, for a total charge of 2. If the very first submitted move is already invalid - no progress at all - the turn instead costs a flat 2-unit decay charge. A malformed response (invalid JSON, an unknown tool request, or ignoring a warning) costs a fixed 3 decay units with no moves applied - the costliest outcome of all. Those charges are what spend decayUnitsRemaining, and every turn spends at least one of them, so it caps how many turns you have left - fewer than that whenever a turn takes a penalty. get_last_prediction_outcome reports its current value and what running out of it means. One way to raise a traversal speed above 1.0000 is to build a picture of the maze around your current cell using filteredTraversalHistory and the static maze dimensions. The openMoves in the filteredTraversalHistory entry matching currentCell are a natural place to start when extracting high-confidence multi-move predictions. With enough of that picture assembled, you can often find several consecutive moves that are all certain to apply without producing an invalid-move. You could also invent a better way to keep raising it. Submitted moves execute in order until the destination is reached or the first invalid move (a wall collision or out-of-bounds step) is hit. lastMoveStatus reached-target or status won means the game is complete - stop predicting.

User message

It is Kora's turn to predict the next moves. Call every available tool once, then reply with only the moves JSON.

Tool definitions

get_maze_structure

Get current/destination cells and the nearby explored maze structure in one call. Row increases going down, col increases going right; MoveUp decreases row by 1 and MoveDown increases it by 1; MoveLeft decreases col by 1 and MoveRight increases it by 1. currentCell is where the previous turn's valid moves ended, whoever played it, or is the start position in turn 0. filteredTraversalHistory holds one record per visited cell, created when that cell was first reached, for cells within historyWindowRadius of currentCell. It is ordered by first visit, oldest first - currentCell's own position depends on when it was first visited, not on it being current, so it will not always be the last. Order says nothing about recent activity: a cell listed early may have been re-entered moments ago, and its visitStatus, not its position, is what reports that. If currentCell is not last, every listed entry after it is a cell first reached after currentCell but before now, so the entry itself is charted ground. However, any move under that entry's openMoves that leads to a cell with visitStatus set to unvisited still points at unexplored ground and remains a valid branch target. currentCell is always included because its distance is 0. historyWindowRadius is a fixed configured radius - the maximum Manhattan distance a visited cell in filteredTraversalHistory can be from currentCell - unrelated to how far destinationCell is; compute that yourself from currentCell and destinationCell's row/col if you need it. Each included entry's openMoves maps every fixed open exit from that cell to the neighboring cell reached by that move. openMoves are generated once and never change with visits count. visitStatus gives direction guidance for each cell in filteredTraversalHistory by comparing that cell's visits count with its fixed open-exit count: unvisited=no recorded visit and new ground to explore; explored=visits count is below the open-exit count; backtracking=visits count equals the open-exit count, so this direction is exhausted; oscillating=visits count is greater than the open-exit count, proving this direction is wasting limited moves. A dead-end reads as backtracking from its first visit, because nothing lies beyond a single exit. cellType is precomputed so you never need to count exits yourself: start-cell (the traversal start), target-cell (the destination), dead-end (one exit), corridor (two exits), or junction (three or more). cellType and visitStatus answer different questions, and help in extracting high-confidence moves: cellType is the cell's fixed structure, visitStatus provides a sense of direction based on cell visits count. start-cell and target-cell are special cells, not ordinary dead ends. cellType is only set for a cell already in filteredTraversalHistory - an unvisited cell, including one that only appears as a neighbor inside another cell's openMoves, has no known cellType and must never be assumed to be of a specific cellType before visiting. The only way to learn an unvisited cell's own structure is to move there and read its own entry on a later turn. currentCell or destinationCell being null means the game state is invalid or incomplete for planning, not a normal maze situation. Returns JSON: {"level":number, "currentCell":{"row":number, "col":number}|null, "destinationCell":{"row":number, "col":number}|null, "historyWindowRadius":number, "filteredTraversalHistory":[{"playerName":string, "cell":{"row":number, "col":number}, "cellType":string, "openMoves":{"MoveLeft":{"row":number, "col":number, "visitStatus":string}, ...}}]}.


get_prediction_rules

Get move response rules. suggestedMovesPerTurn is a min/max range of how many moves a prediction per turn can include - absolute minimum required is 1. Use the local map to extract moves you are most confident about. Batching accuracy drops sharply the further out a prediction reaches, so lean toward min rather than max whenever you are unsure. When decayUnitsCharged is greater than 0, playerUniqueCellsVisited divided by decayUnitsCharged is your current traversal speed, the progress per decay unit spent, which traversalSpeedClass groups into bands. When decayUnitsCharged is 0, traversalSpeedClass defaults to trailblazer. Only a cell's first visit counts as progress. Higher traversal speed means more progress per decay unit, increasing the chance of reaching the target before score runs out. traversalSpeedClass is set to backtracker when the speed is below 1.0000, navigator at 1.0000, or trailblazer above 1.0000. Backtracker is a traversal-speed classification for the whole round; backtracking visitStatus marks one cell as a spent direction. The two are independent: a player can classify as backtracker without ever entering a backtracking cell, and crossing such cells costs no decay beyond the turn's own charge. Retrace-only batching can save turns but cannot create new-cell progress, so trailblazer is evidence that forward prediction into unvisited cells succeeded. allUniqueCellsVisited is every cell any player has reached this level, not just your own - compare it against mazeDimensions.totalMazeCells to know how much of the maze the team has collectively explored so far; it does not affect your traversal speed, which is scored on playerUniqueCellsVisited against decayUnitsCharged. At the initial game levels the single solution path covers nearly all of totalMazeCells, so expect to explore most of the maze before reaching the destination. At higher levels, the destination can be reachable well before allUniqueCellsVisited approaches totalMazeCells. totalTurnCount is the total number of completed prediction turns in this game level. playerTurnsTaken is the number completed by the player and is reported for context; neither count affects your speed, classification, or scores. The resulting score is visible via get_last_prediction_outcome. mazeDimensions.totalMazeCells is the full level size. mazeDimensions being null means the game state is invalid or incomplete for planning. Returns JSON: {"suggestedMovesPerTurn":{"min":number,"max":number}, "allUniqueCellsVisited":number, "playerUniqueCellsVisited":number, "decayUnitsCharged":number, "totalTurnCount":number, "playerTurnsTaken":number, "traversalSpeedClass":string, "mazeDimensions":{"numCols":number,"numRows":number,"totalMazeCells":number}|null, "expectedResponseSchema":object}.


get_last_prediction_outcome

Get the outcome of the previous prediction attempt: whether its moves fully applied, partially failed, reached the target, or were rejected. status is the current game status, score is the current score after that outcome. decayUnitsRemaining is the current maximum number of decay units the player can spend, starting with this turn, to find the target. If the final unit is spent without reaching the target, the score becomes 0 and the level is lost; reaching the target with that unit wins with a score of 0. When moves were replayed, lastMoveStatus is the outcome of the last executed move in the previous prediction: null=first turn, no previous outcome yet; applied=the last executed move succeeded; invalid-move=the last executed move hit a wall or boundary and replay stopped there; reached-target=destination reached, stop predicting. When no moves were replayed, lastMoveStatus explains why: malformed-response=previous response was not valid JSON, requested a tool that does not exist, or ignored a warning, resulting in zero progress and a fixed score penalty. A warning is a user message beginning with "Warning:"; token-limit-exhaustion=the previous empty prediction reached the configured token threshold and its corrective warning opportunity also returned no prediction - no moves were replayed and the same fixed score penalty was charged; network-error=HTTP failure, no score charged. predictionStatus summarizes the outcome of the entire prediction submitted in the last turn as one story: all-applied=all submitted moves applied and at least one entered a previously unvisited cell, or the target was reached; partially-applied=one or more moves applied, at least one entered a previously unvisited cell, and replay then stopped at the first invalid move; repeat-cell-visits=one or more moves applied, but none entered a new cell - replay may have completed or stopped at an invalid move; invalid-prediction=a real prediction was replayed but the very first submitted move was already invalid, no progress made; empty-prediction=a malformed-response, token-limit-exhaustion, or network-error meant there was no usable prediction to replay at all. lastSubmittedMoves lists every submitted move from that turn, in order and exactly as sent, including moves after the first invalid move that were not executed. lastReplayStartIndex is 0 when moves were submitted and marks the first replayed submitted-move index. lastAppliedMoveIndex is the index within lastSubmittedMoves of the last successfully applied move - moves after it were not executed. lastReplayStartCell is the cell position replay began from: where the previous player stood before those moves were applied, not where it stands now. Walk lastSubmittedMoves forward from lastReplayStartCell up to and including lastAppliedMoveIndex to see exactly which move landed where, and the move at lastAppliedMoveIndex + 1 is the one that was rejected. Do not measure last turn's moves from currentCell: currentCell is where replay ended, so assuming it is where replay started makes an applied move look like it never happened. On an empty-prediction turn these fields are always reset to null/empty, matching that no moves were replayed - they never carry over stale data from an earlier turn. chargedMovesCount is the total decay units charged toward score that turn. Returns JSON: {"status":string, "score":number, "decayUnitsRemaining":number, "lastMoveStatus":string|null, "predictionStatus":string|null, "lastReplayStartIndex":number|null, "lastReplayStartCell":{"row":number, "col":number}|null, "lastSubmittedMoves":string[], "lastAppliedMoveIndex":number|null, "chargedMovesCount":number}.

Required response format

{
  "type": "object",
  "description": "The only accepted response format. Return this exact JSON object with no surrounding text or markdown fences.",
  "additionalProperties": false,
  "required": [
    "moves"
  ],
  "properties": {
    "moves": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "string",
        "enum": [
          "MoveLeft",
          "MoveRight",
          "MoveUp",
          "MoveDown"
        ]
      }
    }
  }
}

Duplicate tool call warning! (sample: a repeated get_maze_structure {} call)

Warning: get_maze_structure (call_1) won't yield any new information. You may still call any tools you haven't used yet, or reply now with only the moves JSON. Requesting them again will be treated as a malformed-response.

Token limit exhaustion warning! (sample: the configured token cap reached)

Warning: Your previous response had a token-limit-exhaustion error and used 10000 tokens without returning a prediction. Keep your reasoning brief this time and reply with only the moves JSON. This retry is free, but on reaching the token limit again without a prediction you will be charged the same fixed penalty as a malformed response.