Skip to content

Task System

Tasks are the heart of Journey. They’re how you create quests, objectives, challenges, and anything else you want players to accomplish. “Catch 5 Pikachu,” “defeat the gym leader,” “explore 3 zones” — they’re all tasks.

A task contains one or more subtasks (individual objectives), and when a player completes all required subtasks, the task is done and rewards are given.


Here’s the simplest possible task — catch one Pokemon:

File: config/journey/tasks/first_catch.json

{
"name": "<gold>Catch Your First Pokemon",
"description": [
"<gray>Catch any wild Pokemon to begin your adventure!"
],
"sequential": "linear",
"icon": {
"item_id": "cobblemon:poke_ball"
},
"repeat_type": "NONE",
"rewards": [
{
"type": "currency",
"data": {
"currency_id": "impactor:pokedollars",
"amount": 100
}
}
],
"tasks": [
{
"id": "catch_one",
"name": "Catch a Pokemon",
"description": "Catch any wild Pokemon",
"event": "POKEMON_CAPTURE",
"filter": "1.0",
"target": 1
}
]
}

That’s it. When a player catches any Pokemon, they get 100 Pokedollars. Let’s break down every piece.


Every task file is a JSON object with these fields:

FieldTypeRequiredDescription
nameStringYesDisplay name (supports MiniMessage formatting)
descriptionString[]YesArray of description lines for the quest journal
sequentialStringYesProgression type: "linear", "sequential", or "randomized"
subtask_countNumberOnly for randomizedHow many subtasks to randomly select
start_requirementStringNoMolang condition that must be true to start the task
iconObjectNoItem icon shown in GUIs ({"item_id": "minecraft:compass"})
repeat_typeStringNoHow the task repeats (see Repeat Types)
repeat_intervalNumberNoInterval for repeats (meaning depends on repeat_type)
repeat_limitNumberNoMaximum number of times the task can repeat (0 = unlimited)
party_sharedBooleanNoDefault party sharing for all subtasks (default: false)
globalBooleanNoWhether this is a global (server-wide) task
rewardsArrayNoRewards given when the entire task is completed
tasksArrayYesArray of subtask definitions
available_markerObjectNoMarker shown when task is available but not started
areaObjectNoArea restriction for the task (supports Ceremony regions)

The sequential field controls how subtasks are presented to the player.

"sequential": "linear"

All subtasks are active at the same time. The player can complete them in any order.

Best for: Collection challenges, exploration objectives, parallel goals.

{
"name": "<gold>Starter Town Exploration",
"sequential": "linear",
"tasks": [
{
"id": "visit_lab",
"name": "Visit the Lab",
"event": "ENTER_ZONE",
"filter": "q.zone.uuid == 'lab-zone-uuid'",
"target": 1
},
{
"id": "visit_center",
"name": "Visit the Pokemon Center",
"event": "ENTER_ZONE",
"filter": "q.zone.uuid == 'center-zone-uuid'",
"target": 1
},
{
"id": "visit_mart",
"name": "Visit the Poke Mart",
"event": "ENTER_ZONE",
"filter": "q.zone.uuid == 'mart-zone-uuid'",
"target": 1
}
]
}

All three objectives appear immediately. The player can visit these locations in any order.

"sequential": "sequential"

Subtasks must be completed in order. Only the current subtask is active — the next one unlocks when the current one finishes.

Best for: Story progression, tutorial chains, ordered quest steps.

{
"name": "<gold>Gym Challenge",
"sequential": "sequential",
"tasks": [
{
"id": "enter_gym",
"name": "Enter the Gym",
"event": "ENTER_ZONE",
"filter": "q.zone.uuid == 'pewter-gym-uuid'",
"target": 1
},
{
"id": "defeat_trainers",
"name": "Defeat Gym Trainers",
"event": "BATTLE_VICTORY",
"filter": "q.battle.is_pvn",
"target": 3
},
{
"id": "talk_to_leader",
"name": "Challenge the Gym Leader",
"event": "ENTITY_INTERACT",
"filter": "q.entity.uuid == 'brock-npc-uuid'",
"target": 1
},
{
"id": "defeat_leader",
"name": "Defeat Brock",
"event": "BATTLE_VICTORY",
"filter": "q.battle.is_pvn",
"target": 1
}
]
}

The player must enter the gym first, then defeat 3 trainers, then talk to the leader, then win.

"sequential": "randomized",
"subtask_count": 3

A random subset of subtasks is selected from the pool. You define more subtasks than needed, and Journey picks subtask_count of them randomly.

Best for: Daily quests, bounties, replayable content.

{
"name": "<gold>Daily Challenge",
"sequential": "randomized",
"subtask_count": 3,
"repeat_type": "DAILY",
"tasks": [
{
"id": "catch_pokemon",
"name": "Catch 5 Pokemon",
"event": "POKEMON_CAPTURE",
"filter": "1.0",
"target": 5
},
{
"id": "win_battles",
"name": "Win 10 Battles",
"event": "BATTLE_VICTORY",
"filter": "1.0",
"target": 10
},
{
"id": "harvest_berries",
"name": "Harvest 20 Berries",
"event": "BERRY_HARVESTED",
"filter": "1.0",
"target": 20
},
{
"id": "evolve_pokemon",
"name": "Evolve a Pokemon",
"event": "POKEMON_EVOLVE",
"filter": "1.0",
"target": 1
},
{
"id": "explore_zones",
"name": "Visit 3 Zones",
"event": "ENTER_ZONE",
"filter": "1.0",
"target": 3
}
]
}

Each day, 3 of these 5 subtasks are randomly selected. The player completes whichever 3 they’re given.


Subtasks are the individual objectives within a task:

FieldTypeRequiredDescription
idStringYesUnique identifier within the task
nameStringYesDisplay name for this objective
descriptionStringNoWhat the player needs to do
eventStringYesEvent type that triggers progress (see Events)
event_dataObjectNoExtra event-specific data
filterStringYesMolang expression to validate events
targetNumberYesHow many times the event must match
rewardsArrayNoRewards given when this specific subtask completes
locationObjectNoWaypoint coordinates ({"x": 100, "y": 64, "z": 200})
time_limitStringNoTime constraint (e.g., "30s", "5m", "1h")
optionalBooleanNoIf true, not required for task completion
party_sharedBooleanNoOverride task-level party sharing for this subtask
scriptStringNoMolang script to run when subtask completes
labelsString[]NoTags for categorization
markerObjectNoMarker configuration for this subtask
areaObjectNoArea restriction for this subtask

Filters are Molang expressions that decide whether an event counts toward progress. Every time the event fires, Journey evaluates the filter — if it returns a truthy value (non-zero), progress goes up by 1.

"filter": "1.0"

Always matches. Every event of this type counts.

"filter": "q.pokemon.species.identifier == 'cobblemon:pikachu'"

Only matches when the Pokemon is a Pikachu.

"filter": "q.battle.is_pvw && q.player.is_in_zone('forest-zone-uuid')"

Only matches wild battles while the player is in a specific zone.

See the Events page for what data each event provides, and the Molang page for all available functions.


Journey supports five reward types. You can use any of them on both tasks and subtasks.

Runs a server command. Use {player} as a placeholder for the player’s name:

{
"type": "command",
"data": {
"command": "give {player} minecraft:diamond 5"
}
}

Awards economy currency (requires Impactor):

{
"type": "currency",
"data": {
"currency_id": "impactor:pokedollars",
"amount": 500
}
}

Runs Molang scripts with full access to all player functions:

{
"type": "script",
"data": {
"scripts": [
"q.player.add_flag('gym_badge_boulder');",
"q.player.tell_minimessage('<gold>You earned the Boulder Badge!');",
"q.player.progress_levelable('trainer_rank', 100);"
]
}
}

Launches a timeline sequence:

{
"type": "timeline",
"data": {
"timeline": "journey:gym_victory"
}
}

Applies a buff to the player:

{
"type": "buff",
"data": {
"buff_id": "speed_boost",
"duration": 6000,
"amplifier": 0,
"source": "gym_reward"
}
}
  • duration is in ticks (20 ticks = 1 second, -1 = permanent)
  • amplifier is 0-based (0 = level 1, 1 = level 2, etc.)
  • source is an optional tag for tracking where the buff came from

Control when a task becomes available using start_requirement. This is a Molang expression that must return true for the player to start the task.

{
"start_requirement": ""
}
{
"start_requirement": "q.player.has_flag('tutorial_complete')"
}
{
"start_requirement": "q.player.has_completed_task('journey:first_gym')"
}
{
"start_requirement": "q.player.levelable_level('trainer_rank') >= 25"
}
{
"start_requirement": "q.player.has_flag('gym_badge_boulder') && q.player.has_flag('gym_badge_cascade') && q.player.has_flag('gym_badge_thunder')"
}

The repeat_type field controls whether and how a task resets after completion:

Repeat TypeDescription
NONEOne-time task (default)
MINUTELYResets every minute
HOURLYResets every hour
DAILYResets once per day
WEEKLYResets once per week
MONTHLYResets once per month
YEARLYResets once per year

Use repeat_limit to cap how many times a task can be repeated:

{
"repeat_type": "DAILY",
"repeat_interval": 1,
"repeat_limit": 30
}

This daily task can only be completed 30 times total.


When party_shared is true, progress from any party member counts for all party members who have the task.

{
"name": "<gold>Party Dungeon Quest",
"sequential": "linear",
"party_shared": true,
"tasks": [
{
"id": "defeat_bosses",
"name": "Defeat Dungeon Bosses",
"event": "BATTLE_VICTORY",
"filter": "q.battle.is_pvn",
"target": 5
},
{
"id": "find_treasure",
"name": "Find the Hidden Treasure",
"event": "ENTER_ZONE",
"filter": "q.zone.uuid == 'treasure-room-uuid'",
"target": 1,
"party_shared": false
}
]
}
  • party_shared on the task sets the default for all subtasks
  • party_shared on a subtask overrides the task default
  • In this example, boss defeats are shared but each member must find the treasure themselves

File: config/journey/tasks/rival_battle.json

{
"name": "<red>Rival Showdown",
"description": [
"<gray>Your rival has challenged you to a battle!",
"<gray>Meet them at the bridge and prove your strength."
],
"sequential": "sequential",
"start_requirement": "q.player.has_flag('starter_chosen') && q.player.has_completed_task('journey:route_1_exploration')",
"icon": {
"item_id": "minecraft:iron_sword"
},
"repeat_type": "NONE",
"rewards": [
{
"type": "script",
"data": {
"scripts": [
"q.player.add_flag('rival_defeated_1');",
"q.player.tell_minimessage('<gold>Your rival respects your strength!');"
]
}
},
{
"type": "timeline",
"data": {
"timeline": "journey:rival_defeated_celebration"
}
},
{
"type": "currency",
"data": {
"currency_id": "impactor:pokedollars",
"amount": 500
}
}
],
"tasks": [
{
"id": "go_to_bridge",
"name": "Go to Nugget Bridge",
"description": "Meet your rival at Nugget Bridge",
"event": "ENTER_ZONE",
"filter": "q.zone.uuid == 'nugget-bridge-uuid'",
"target": 1,
"location": {
"x": 500,
"y": 64,
"z": -200
}
},
{
"id": "talk_to_rival",
"name": "Talk to Your Rival",
"event": "ENTITY_INTERACT",
"filter": "q.entity.uuid == 'rival-npc-uuid'",
"target": 1,
"script": "q.player.launch_timeline('journey:rival_pre_battle_dialogue');"
},
{
"id": "defeat_rival",
"name": "Defeat Your Rival",
"event": "BATTLE_VICTORY",
"filter": "q.battle.is_pvn",
"target": 1,
"rewards": [
{
"type": "command",
"data": {
"command": "give {player} cobblemon:rare_candy 3"
}
}
]
}
]
}

File: config/journey/tasks/shiny_sprint.json

{
"name": "<rainbow>Shiny Sprint",
"description": [
"<gray>Catch a shiny Pokemon within 30 minutes!",
"<yellow>Good luck, trainer!"
],
"sequential": "linear",
"start_requirement": "q.player.has_flag('unlocked_shiny_sprint')",
"icon": {
"item_id": "cobblemon:shiny_stone"
},
"repeat_type": "WEEKLY",
"rewards": [
{
"type": "buff",
"data": {
"buff_id": "shiny_hunter",
"duration": -1,
"amplifier": 0,
"source": "shiny_sprint_reward"
}
}
],
"tasks": [
{
"id": "catch_shiny",
"name": "Catch a Shiny Pokemon",
"event": "POKEMON_CAPTURE",
"filter": "q.pokemon.is_shiny",
"target": 1,
"time_limit": "30m"
}
]
}

File: config/journey/tasks/elite_four_unlock.json

{
"name": "<gold>Road to the Elite Four",
"description": [
"<gray>Collect all 8 gym badges to unlock",
"<gray>the Elite Four challenge!"
],
"sequential": "linear",
"start_requirement": "q.player.has_flag('tutorial_complete')",
"icon": {
"item_id": "minecraft:nether_star"
},
"repeat_type": "NONE",
"rewards": [
{
"type": "script",
"data": {
"scripts": [
"q.player.add_flag('elite_four_unlocked');",
"q.player.tell_minimessage('<gold><bold>The Elite Four awaits you!');"
]
}
},
{
"type": "timeline",
"data": {
"timeline": "journey:elite_four_unlocked_cutscene"
}
}
],
"tasks": [
{
"id": "badge_boulder",
"name": "Boulder Badge",
"event": "BATTLE_VICTORY",
"filter": "q.battle.is_pvn && q.player.is_in_zone('pewter-gym-uuid')",
"target": 1,
"script": "q.player.add_flag('gym_badge_boulder');"
},
{
"id": "badge_cascade",
"name": "Cascade Badge",
"event": "BATTLE_VICTORY",
"filter": "q.battle.is_pvn && q.player.is_in_zone('cerulean-gym-uuid')",
"target": 1,
"script": "q.player.add_flag('gym_badge_cascade');"
},
{
"id": "badge_thunder",
"name": "Thunder Badge",
"event": "BATTLE_VICTORY",
"filter": "q.battle.is_pvn && q.player.is_in_zone('vermilion-gym-uuid')",
"target": 1,
"script": "q.player.add_flag('gym_badge_thunder');"
},
{
"id": "badge_rainbow",
"name": "Rainbow Badge",
"event": "BATTLE_VICTORY",
"filter": "q.battle.is_pvn && q.player.is_in_zone('celadon-gym-uuid')",
"target": 1,
"script": "q.player.add_flag('gym_badge_rainbow');"
},
{
"id": "badge_soul",
"name": "Soul Badge",
"event": "BATTLE_VICTORY",
"filter": "q.battle.is_pvn && q.player.is_in_zone('fuchsia-gym-uuid')",
"target": 1,
"script": "q.player.add_flag('gym_badge_soul');"
},
{
"id": "badge_marsh",
"name": "Marsh Badge",
"event": "BATTLE_VICTORY",
"filter": "q.battle.is_pvn && q.player.is_in_zone('saffron-gym-uuid')",
"target": 1,
"script": "q.player.add_flag('gym_badge_marsh');"
},
{
"id": "badge_volcano",
"name": "Volcano Badge",
"event": "BATTLE_VICTORY",
"filter": "q.battle.is_pvn && q.player.is_in_zone('cinnabar-gym-uuid')",
"target": 1,
"script": "q.player.add_flag('gym_badge_volcano');"
},
{
"id": "badge_earth",
"name": "Earth Badge",
"event": "BATTLE_VICTORY",
"filter": "q.battle.is_pvn && q.player.is_in_zone('viridian-gym-uuid')",
"target": 1,
"script": "q.player.add_flag('gym_badge_earth');"
}
]
}

Task files go in config/journey/tasks/. You can use subdirectories for organization:

config/journey/tasks/
├── tutorial/
│ ├── choose_starter.json → journey:tutorial/choose_starter
│ └── first_catch.json → journey:tutorial/first_catch
├── gyms/
│ ├── pewter_gym.json → journey:gyms/pewter_gym
│ └── cerulean_gym.json → journey:gyms/cerulean_gym
└── daily/
└── daily_challenge.json → journey:daily/daily_challenge

The task ID is journey:<path_without_extension>. Use this ID when referencing tasks in commands, Molang, and other configs.


CommandDescription
/journey starttask <player> <task_id>Give a task to a player
/journey completetask <player> <task_id>Force-complete a task
/journey removetask <player> <task_id>Remove a task from a player
/journey removecompleted <player>Clear a player’s completed task history
/journey completesubtask <player> <task_id> <subtask_id>Force-complete a specific subtask
/journey progresssubtask <player> <task_id> <subtask_id> <amount>Add progress to a subtask
/track <task_id>Track a task on your HUD
/track untrackStop tracking

  • Keep subtask counts reasonable (3-8 per task works well)
  • Use descriptive IDs: defeat_gym_leader not step3
  • Provide location coordinates for objectives so players know where to go
  • Set start_requirement to prevent players from being overwhelmed with quests
  • Start simple with "1.0" (matches everything), then add conditions
  • Test filters in-game before deploying to production
  • Use q.player.is_in_zone() to restrict objectives to specific areas
  • Combine conditions with && (AND) and || (OR)
  • Use subtask rewards for milestone feedback along the way
  • Mix reward types for variety (currency + items + flags)
  • Be careful with repeatable tasks — generous rewards add up fast
  • Use script rewards to set flags that gate future content
  • Avoid overly complex Molang expressions in filters for high-frequency events
  • For daily/weekly tasks, set repeat_limit to prevent infinite farming