Installation & Setup
Before writing any scripts, you need Minecraft running with the right mods. Here's exactly what to install and where everything lives.
What you need
- Minecraft Java Edition — any version that matches the mod versions below
- Fabric Loader — the mod loader framework
- Fabric API — required by almost all Fabric mods
- Minescript 5.0 (beta) — the scripting mod itself
Minescript 5.0 includes Pyjinn, a built-in Python interpreter. This means you do not need to install Python on your computer — the mod handles everything. Your scripts will use the .pyj file extension (instead of .py), but the language is identical Python syntax.
Step-by-step installation
-
1
Install Fabric Loader
Go to fabricmc.net, download the installer, and run it. Select the Minecraft version you want to use. This creates a new Fabric profile in your launcher.
-
2
Download Fabric API
Search "Fabric API" on modrinth.com. Download the version matching your Minecraft version. This is a
.jarfile. -
3
Download Minescript 5.0
Go to modrinth.com/mod/minescript. Switch to the "Beta" tab, and download the latest 5.0 beta for Fabric matching your Minecraft version.
-
4
Place both .jar files in your mods folder
On Linux, open a file manager and navigate to:
~/.minecraft/mods/(create the folder if it doesn't exist). Drop both.jarfiles inside it. -
5
Launch Minecraft with the Fabric profile
In the Minecraft Launcher, select the Fabric profile and click Play. On first launch, Minescript will auto-create the
~/.minecraft/minescript/folder — this is where all your scripts live. -
6
Verify it's working
Load any world. Open the Minescript console by pressing \ (backslash). You should see a special chat-like input. Type
\helpand press Enter. If you see a list of commands, it works!
Press Ctrl+L in your file manager and type /home/YOUR_USERNAME/.minecraft. Or open a terminal and run ls ~/.minecraft to see its contents.
Where your scripts go
All scripts live in the ~/.minecraft/minescript/ folder. You'll create .pyj files (Pyjinn scripts) here. To run a script called my_script.pyj, you press \ in-game and type \my_script.
With Minescript 5.0, Pyjinn scripts use the .pyj extension. They run directly inside the game with no external Python needed. Classic .py scripts still work too, but require Python installed on your system. This guide focuses entirely on .pyj.
Installing Mappings (important for Fabric)
Mappings let your scripts talk to Minecraft's internal Java code using readable names. Run this once from inside the game:
\install_mappings
Your Text Editor
Scripts are just plain text files. You need a text editor to write them. On Linux, the best free choice for beginners is VSCodium or VS Code.
Setting up VS Code / VSCodium
-
1
Install VS Code
Most Linux distros: open your software manager and search "VS Code" or "VSCodium". Or download from code.visualstudio.com.
-
2
Open your minescript folder
In VS Code, go to File → Open Folder and select
~/.minecraft/minescript. You'll see your scripts listed on the left sidebar. -
3
Create a new file
Click the "New File" icon in the sidebar and name it
hello.pyj. The.pyjextension tells Minescript it's a Pyjinn script.
For nice code colors, associate .pyj files with Python. In VS Code, click the language name in the bottom-right corner when a .pyj file is open, then choose "Configure File Association" → Python.
Variables & Data Types
A variable is a named container that holds a value. Think of it like a labelled box. You create a variable by writing its name, an equals sign, and a value.
# This is a comment — Python ignores lines starting with # # Comments are notes for you (and future you) # Text (called a "string") player_name = "Steve" # Whole numbers (called "integers") tree_count = 5 # Decimal numbers (called "floats") health = 18.5 # True or False (called "booleans") is_raining = False # You can change a variable at any time tree_count = 10 # now it's 10 instead of 5
The four basic types
| Type | Example | What it's for |
|---|---|---|
| str | "hello" or 'hello' | Text — names, block IDs, messages |
| int | 42 | Whole numbers — coordinates, counts |
| float | 3.14 | Decimal numbers — player position |
| bool | True / False | Yes/no values — is a block solid? |
Lists — multiple values in one variable
A list stores multiple values in order, inside square brackets.
# A list of wood block types wood_types = ["oak_log", "birch_log", "spruce_log"] # Access items by position (counting starts at 0!) first_wood = wood_types[0] # "oak_log" second_wood = wood_types[1] # "birch_log" # Add something to a list wood_types.append("jungle_log") # How many items are in the list? count = len(wood_types) # 4
F-strings — putting variables into text
An f-string (formatted string) lets you embed variable values directly into text. Put f before the quote, then use {} around variable names.
x = 100 y = 64 z = -200 message = f"Player is at X={x} Y={y} Z={z}" # message is now: "Player is at X=100 Y=64 Z=-200"
F-strings are used constantly in Minescript scripts — for building Minecraft command strings and echo messages.
Logic & Loops
If / elif / else — making decisions
Use if to run code only when a condition is true. Indentation (the spaces at the start of a line) is critical — Python uses it to know which code belongs inside the if block.
block = "oak_log" if block == "oak_log": echo("Found an oak log!") # runs if True elif block == "birch_log": echo("Found a birch log!") # runs if second condition is True else: echo("Unknown block type") # runs if nothing above was True
Comparison operators
| Operator | Meaning | Example |
|---|---|---|
| == | equal to | x == 5 |
| != | not equal to | x != 5 |
| > | greater than | health > 10 |
| < | less than | y < 60 |
| >= | greater than or equal | count >= 64 |
| in | item is in a list | "oak_log" in wood_types |
For loops — repeat for each item
A for loop runs a block of code once for each item in a list (or range of numbers).
# Loop over a list wood_types = ["oak_log", "birch_log", "spruce_log"] for wood in wood_types: echo(f"Checking for: {wood}") # Loop a specific number of times using range() for i in range(5): # i = 0, 1, 2, 3, 4 echo(f"Step {i}") # range(start, stop) — e.g. range(1, 6) = 1,2,3,4,5 for y_level in range(60, 70): echo(f"Scanning Y level {y_level}")
While loops — repeat while a condition is true
crops_harvested = 0 while crops_harvested < 10: echo(f"Harvested: {crops_harvested}") crops_harvested = crops_harvested + 1 # or shorter: crops_harvested += 1 # After the loop, crops_harvested == 10
If a while loop's condition never becomes False, the script runs forever. Always make sure something inside the loop eventually makes the condition false — or use break to exit early. To stop a stuck script in-game, press \ and type \killjobs.
Breaking out early with break and continue
for i in range(100): if i == 5: break # immediately exits the loop if i == 3: continue # skip to the next iteration echo(f"i = {i}") # Prints: 0, 1, 2, 4 (skips 3, stops at 5)
Functions
A function is a reusable block of code with a name. You define it once with def, then call it whenever you need it. This keeps your scripts organised and avoids repeating yourself.
# Define a function def greet_player(name): echo(f"Welcome, {name}!") # Call it (use it) greet_player("Alex") # echoes "Welcome, Alex!" greet_player("Steve") # echoes "Welcome, Steve!"
Functions that return values
Use return to send a value back to whoever called the function.
def is_wood_block(block_name): # Returns True if the block is a type of log wood_types = ["oak_log", "birch_log", "spruce_log", "jungle_log", "acacia_log", "dark_oak_log", "mangrove_log", "cherry_log"] # Remove "minecraft:" prefix if present clean = block_name.replace("minecraft:", "") return clean in wood_types # Use it: if is_wood_block("minecraft:oak_log"): echo("It's wood!")
Write functions for anything you do more than once. In Minescript scripts this is especially useful — your tree-miner script will have a function like chop_tree(x, y, z) that you can call for each tree.
Imports
Python and Minescript have extra libraries of pre-built functions. You import them at the top of your script to use them.
# Import everything from minescript (most common way) from minescript import * # Or import specific functions only from minescript import echo, player_position, execute # Import with a short alias import minescript as m m.echo("Hello!") # call functions with m. prefix # Time module (for delays between actions) import time time.sleep(1.0) # pause for 1 second
In Pyjinn (.pyj) scripts, if you don't write any import at the top, Minescript functions like echo, execute, player_position etc. are available automatically. For clarity, this guide will always import explicitly.
Your First Minescript Script
Let's write a real script and run it. Create a file called hello.pyj in your ~/.minecraft/minescript/ folder.
from minescript import echo, player_position, player_name # Get the player's name name = player_name() # Get the player's current position # player_position() returns three decimal numbers: x, y, z x, y, z = player_position() # Convert to whole numbers for display x = int(x) y = int(y) z = int(z) # Echo is like "print but in Minecraft" — only you can see it echo(f"Hello, {name}!") echo(f"You are at X={x} Y={y} Z={z}")
Running it
- 1Save the file
Press Ctrl+S in your text editor.
- 2Load a Minecraft world
Any world will do — creative mode is easiest for testing.
- 3Open the Minescript console
Press \ (backslash). A chat-like input appears.
- 4Type the script name
Type
\helloand press Enter. You should see your name and coordinates appear in chat.
echo("message") shows a message only to you — other players can't see it. chat("message") sends a message to public chat that everyone sees. Use echo for feedback/debugging.
Player Functions
Minescript gives you a rich set of functions for reading the player's state and controlling their actions.
Reading player state
from minescript import echo, player_name, player_position, player_orientation, player_health, player_inventory # Name name = player_name() # Position — returns floats (decimals) x, y, z = player_position() # Facing direction — yaw (left/right), pitch (up/down) yaw, pitch = player_orientation() # Health (0.0 to 20.0) hp = player_health() echo(f"Name: {name}") echo(f"Position: {int(x)}, {int(y)}, {int(z)}") echo(f"Facing: yaw={yaw:.1f}, pitch={pitch:.1f}") echo(f"Health: {hp}/20") # Inventory — returns a list of item objects for item in player_inventory(): if item.item != "air": # skip empty slots echo(f"{item.item} x{item.count}")
What block is the player looking at?
from minescript import echo, player_get_targeted_block # Look within 10 blocks for a targeted block target = player_get_targeted_block(10) if target: # target has .type, .position, .side properties echo(f"Looking at: {target.type}") bx, by, bz = target.position echo(f"Block at: {bx}, {by}, {bz}") else: echo("Not looking at any block")
Setting facing direction
Scripts can rotate the player's view, which is essential for targeting specific blocks.
from minescript import player_set_orientation, player_look_at # Set yaw and pitch directly (in degrees) # yaw: 0=south, 90=west, 180=north, -90=east # pitch: 0=horizontal, -90=up, 90=down player_set_orientation(0, 0) # face south, level player_set_orientation(0, -45) # face south, looking up # Or look at a specific coordinate player_look_at(100, 64, 200)
Blocks & World
Reading block types
from minescript import echo, player_position, getblock, getblocklist # Get the type of a single block at x, y, z x, y, z = player_position() x, y, z = int(x), int(y), int(z) block_below = getblock(x, y - 1, z) echo(f"You're standing on: {block_below}") # Result will look like "minecraft:grass_block" or "minecraft:stone" # Get multiple blocks at once (more efficient) positions = [(x, y, z), (x + 1, y, z), (x - 1, y, z)] block_types = getblocklist(positions) for i, block in enumerate(block_types): bx, by, bz = positions[i] echo(f"Block at ({bx},{by},{bz}): {block}")
Stripping the "minecraft:" prefix
Block names from Minescript always include the namespace like minecraft:oak_log. When comparing, strip it off for cleaner code:
raw_block = "minecraft:oak_log" # Remove "minecraft:" prefix clean = raw_block.replace("minecraft:", "") # clean is now "oak_log" # Block states like "minecraft:wheat[age=7]" — strip state too: raw2 = "minecraft:wheat[age=7]" clean2 = raw2.replace("minecraft:", "").split("[")[0] # clean2 is now "wheat"
Running Minecraft commands
execute() runs any Minecraft command — the same ones you'd type with a / in chat.
from minescript import execute, player_position x, y, z = player_position() x, y, z = int(x), int(y), int(z) # Teleport to coordinates execute(f"/tp @p {x} {y + 10} {z}") # Give yourself items execute("/give @p minecraft:diamond_axe 1") # Set a block at specific coordinates execute(f"/setblock {x} {y - 1} {z} minecraft:grass_block") # Note: tilde ~ means "relative to player position" execute("/setblock ~ ~-1 ~ minecraft:stone")
Commands like /give, /setblock, and /tp only work if you have cheat permissions. In a singleplayer world, enable cheats when creating it (or use /gamemode creative). On servers, you need operator status.
Movement & Input Simulation
Minescript can simulate key presses — the same as if you pressed W, Space, or left-clicked the mouse. This is how automation scripts physically move and interact.
Movement keys
from minescript import player_press_forward, player_press_backward, player_press_left, player_press_right, player_press_jump, player_press_sprint, player_press_sneak import time # Pass True to "press" the key, False to "release" it # Walk forward for 2 seconds player_press_forward(True) time.sleep(2.0) player_press_forward(False) # Sprint forward for 1 second player_press_sprint(True) player_press_forward(True) time.sleep(1.0) player_press_forward(False) player_press_sprint(False) # Jump briefly player_press_jump(True) time.sleep(0.15) player_press_jump(False)
Mouse buttons (attack & use)
from minescript import player_press_attack, player_press_use import time # Left click (attack / break block) for 3 seconds player_press_attack(True) time.sleep(3.0) player_press_attack(False) # Right click (use item / interact) once briefly player_press_use(True) time.sleep(0.1) player_press_use(False)
Every key you press with True must be released with False when done. If your script crashes mid-run with a key still held, the player will keep moving. Use a try/finally block to ensure keys are released even on error — shown in the full scripts below.
Events (Pyjinn Style)
Events let your script react to things happening in the game — a chat message arrives, a block changes, a tick happens. In Pyjinn (.pyj), you register an event listener using add_event_listener(). This is inspired by how JavaScript handles events.
Listening for chat messages
from minescript import echo, add_event_listener # Define what happens when a chat message is received def on_chat(event): msg = event.message # the text of the message sender = event.sender # who sent it (may be empty) echo(f"Received: {msg}") # Register the listener — "chat" is the event type add_event_listener("chat", on_chat)
Listening to game ticks
The game runs at 20 ticks per second. The "tick" event fires every tick — useful for things that need to check state regularly.
from minescript import echo, add_event_listener, player_health tick_count = 0 def on_tick(event): global tick_count tick_count += 1 # Every 100 ticks (≈ 5 seconds), check health if tick_count % 100 == 0: hp = player_health() if hp < 8: echo("⚠ Low health! Find food!") add_event_listener("tick", on_tick)
Timers with set_interval and set_timeout
from minescript import echo, set_interval, set_timeout, remove_event_listener # Call a function every 5000 milliseconds (5 seconds) def reminder(): echo("Don't forget to eat!") interval_id = set_interval(reminder, 5000) # Cancel the interval after 30 seconds def cancel(): remove_event_listener(interval_id) echo("Reminders stopped.") set_timeout(cancel, 30000) # run cancel() once after 30 000ms
Available event types
| Event type | When it fires |
|---|---|
| "tick" | Every game tick (20x per second) |
| "render" | Every rendered frame |
| "chat" | When a chat message arrives |
| "outgoing_chat_intercept" | When you send a chat message |
| "key" | Keyboard key press/release |
| "mouse" | Mouse button press/release |
| "block_update" | A nearby block changes |
| "add_entity" | An entity spawns nearby |
| "take_item" | Player picks up an item |
| "damage" | Player takes damage |
| "chunk" | A chunk loads/unloads |
Full Script: Chat Command Bot
This script listens for special commands typed in chat (prefixed with !) and performs actions. Great for triggering scripts hands-free, or for use on servers.
from minescript import echo, chat, execute, player_position, player_health, add_event_listener # ─── Command handler functions ─── def cmd_pos(): """Show current position.""" x, y, z = player_position() echo(f"📍 Position: {int(x)}, {int(y)}, {int(z)}") def cmd_health(): """Show current health.""" hp = player_health() hearts = int(hp / 2) echo(f"❤ Health: {hp}/20 ({hearts} hearts)") def cmd_time(part): """Set the time of day. Usage: !time day / night / noon""" times = { "day": 1000, "noon": 6000, "night": 13000, "midnight": 18000, } if part in times: execute(f"/time set {times[part]}") echo(f"🕐 Time set to {part}") else: echo(f"Unknown time: {part}. Use: day, noon, night, midnight") def cmd_help(): """Show available commands.""" echo("─── Chat Bot Commands ───") echo("!pos — show your position") echo("!health — show your health") echo("!time [part] — set time (day/noon/night/midnight)") echo("!help — show this list") # ─── Main event listener ─── def on_chat(event): msg = event.message.strip() # Only react to messages starting with ! if not msg.startswith("!"): return # Split into command and optional argument # e.g. "!time day" → parts = ["!time", "day"] parts = msg.split() command = parts[0].lower() # "!time" arg = parts[1].lower() if len(parts) > 1 else "" if command == "!pos": cmd_pos() elif command == "!health": cmd_health() elif command == "!time": cmd_time(arg) elif command == "!help": cmd_help() else: echo(f"Unknown command: {command}. Type !help for a list.") # Register the listener and notify the player add_event_listener("chat", on_chat) echo("✅ Chat bot is running! Type !help for commands.")
Run \chat_bot in-game, then type !help in normal chat. The bot will listen as long as the script is running. To stop it, type \killjobs.
Full Script: Block Scanner / Finder
This script scans a cubic region around the player and reports where specific blocks are. Useful for finding ores, crops, or any block type nearby.
from minescript import echo, player_position, getblocklist import sys # ─── Configuration ─── # You can pass arguments when running the script: # \block_scanner diamond_ore 10 # (target_block, radius) if len(sys.argv) >= 2: target_block = sys.argv[1] # e.g. "diamond_ore" else: target_block = "diamond_ore" # default to diamond ore if len(sys.argv) >= 3: radius = int(sys.argv[2]) else: radius = 15 # scan 15 blocks in each direction # ─── Get player position ─── px, py, pz = player_position() px, py, pz = int(px), int(py), int(pz) echo(f"🔍 Scanning {radius*2+1}³ region for: {target_block}") echo(f" (Centred on {px}, {py}, {pz})") # ─── Build list of all positions to check ─── # This collects every (x, y, z) in the scan cube positions = [] for dx in range(-radius, radius + 1): for dy in range(-radius, radius + 1): for dz in range(-radius, radius + 1): positions.append((px + dx, py + dy, pz + dz)) echo(f" Checking {len(positions)} blocks...") # ─── Fetch all block types at once ─── # getblocklist is much faster than calling getblock in a loop block_types = getblocklist(positions) # ─── Search for matching blocks ─── found = [] for i, block in enumerate(block_types): # Strip "minecraft:" and block states for comparison clean = block.replace("minecraft:", "").split("[")[0] if clean == target_block: found.append(positions[i]) # ─── Report results ─── if len(found) == 0: echo(f"❌ No {target_block} found within radius {radius}") else: echo(f"✅ Found {len(found)} {target_block} blocks:") # Sort by distance to player (closest first) def distance(pos): bx, by, bz = pos return ((bx - px)**2 + (by - py)**2 + (bz - pz)**2) ** 0.5 found.sort(key=distance) # Show the 10 closest results for bx, by, bz in found[:10]: d = round(distance((bx, by, bz)), 1) echo(f" → ({bx}, {by}, {bz}) — {d} blocks away") if len(found) > 10: echo(f" ... and {len(found) - 10} more")
\block_scanner — finds diamond ore in radius 15
\block_scanner oak_log 20 — finds oak logs in radius 20
\block_scanner wheat 8 — finds wheat crops nearby
Full Script: Auto Tree Miner
This script looks for a tree log in front of the player, faces it, and chops the whole trunk by breaking each log from the bottom up. It uses player_look_at to aim precisely and player_press_attack to break blocks.
Stand in front of a tree holding an axe. Make sure you have a clear line of sight to the bottom log. This script works best in singleplayer. Servers may have anti-automation protections.
from minescript import (echo, player_position, player_orientation, player_get_targeted_block, player_look_at, player_press_attack, getblock) import time # ─── All wood log block IDs ─── WOOD_LOGS = { "oak_log", "birch_log", "spruce_log", "jungle_log", "acacia_log", "dark_oak_log", "mangrove_log", "cherry_log", "oak_wood", "birch_wood", "spruce_wood", "jungle_wood", } def is_log(block_name): """Return True if the block is a type of wood log.""" clean = block_name.replace("minecraft:", "").split("[")[0] return clean in WOOD_LOGS def break_block_at(x, y, z, break_time): """Look at coordinates and hold left-click to break the block.""" player_look_at(x, y, z) time.sleep(0.2) # short pause to let the view settle player_press_attack(True) time.sleep(break_time) player_press_attack(False) time.sleep(0.15) # brief pause between blocks # ─── Step 1: Find a log block ─── # Look at the targeted block in crosshairs (up to 8 blocks away) target = player_get_targeted_block(8) if target is None: echo("❌ Not looking at any block. Face a tree log first.") elif not is_log(target.type): echo(f"❌ That's not a log: {target.type}") else: start_x, start_y, start_z = target.position start_x, start_y, start_z = int(start_x), int(start_y), int(start_z) echo(f"🌳 Found log at ({start_x}, {start_y}, {start_z})") echo(f" Type: {target.type}") # ─── Step 2: Find the full trunk height ─── # Scan upward from the first log to find where the trunk ends trunk = [] scan_y = start_y while True: block = getblock(start_x, scan_y, start_z) if is_log(block): trunk.append((start_x, scan_y, start_z)) scan_y += 1 if scan_y > start_y + 30: # safety cap: max 30 blocks tall break else: break echo(f" Trunk height: {len(trunk)} blocks") # ─── Step 3: Chop from bottom to top ─── # Breaking the bottom log first causes the higher logs to drop too # But we face each log individually to avoid missing any chopped = 0 try: for lx, ly, lz in trunk: # Check if the block is still there current = getblock(lx, ly, lz) if is_log(current): echo(f"⛏ Chopping Y={ly}") break_block_at(lx, ly, lz, 0.8) # 0.8s per block (adjust for axe type) chopped += 1 finally: # Always make sure attack is released, even if script crashes player_press_attack(False) echo(f"✅ Done! Chopped {chopped} logs.")
The 0.8 in break_block_at(lx, ly, lz, 0.8) is how long (seconds) to hold left-click per block. Adjust based on your axe: a stone axe needs ~1.15s, an iron axe ~0.75s, a diamond axe ~0.5s, a netherite axe ~0.45s.
Full Script: Auto Crop Farm
This script scans a flat farmland area in front of the player for fully grown crops (age=7), harvests them by left-clicking, and then right-clicks to replant (if you have seeds). Works for wheat, carrots, potatoes, and beetroot.
from minescript import (echo, player_position, player_orientation, player_look_at, player_press_attack, player_press_use, getblock, getblocklist) import time import sys # ─── Configuration ─── # How wide and deep is the farm to scan? FARM_WIDTH = int(sys.argv[1]) if len(sys.argv) > 1 else 9 # east-west FARM_DEPTH = int(sys.argv[2]) if len(sys.argv) > 2 else 9 # forward # Crops that are considered "harvestable" when fully grown HARVESTABLE = {"wheat", "carrots", "potatoes", "beetroots"} def is_mature_crop(block_name): """Return True if block is a fully grown (age=7) crop.""" if "minecraft:" not in block_name: return False clean = block_name.replace("minecraft:", "") # Clean looks like "wheat[age=7]" or "carrots[age=7]" crop_name = clean.split("[")[0] if crop_name not in HARVESTABLE: return False # Check if it's fully grown if "age=7" in block_name: return True # Beetroot is fully grown at age=3 if crop_name == "beetroots" and "age=3" in block_name: return True return False def harvest_block(x, y, z): """Look at a block and left-click to harvest it.""" player_look_at(x, y, z) time.sleep(0.15) player_press_attack(True) time.sleep(0.1) player_press_attack(False) time.sleep(0.1) def replant_block(x, y, z): """Look at farmland and right-click to plant a seed.""" player_look_at(x, y, z) time.sleep(0.15) player_press_use(True) time.sleep(0.1) player_press_use(False) time.sleep(0.1) # ─── Main ─── # Get player position and facing direction px, py, pz = player_position() px, py, pz = int(px), int(py), int(pz) yaw, _ = player_orientation() echo(f"🌾 Scanning {FARM_WIDTH}×{FARM_DEPTH} farm area...") # Build list of crop positions to check (at player's Y level) # We check the block at eye level (py), crops are at foot level (py-1) positions = [] for dz in range(0, FARM_DEPTH): # forward for dx in range(-FARM_WIDTH // 2, FARM_WIDTH // 2 + 1): # side positions.append((px + dx, py - 1, pz + dz)) # Fetch all block types at once block_types = getblocklist(positions) # Find mature crops mature_crops = [] for i, block in enumerate(block_types): if is_mature_crop(block): mature_crops.append(positions[i]) echo(f" Found {len(mature_crops)} mature crops to harvest") if len(mature_crops) == 0: echo("❌ No mature crops found in this area.") else: harvested = 0 replanted = 0 try: for cx, cy, cz in mature_crops: # Double-check it's still there before harvesting current = getblock(cx, cy, cz) if is_mature_crop(current): harvest_block(cx, cy, cz) harvested += 1 time.sleep(0.2) # wait for item to drop # Try to replant: right-click on the farmland below # The player must have seeds/crops in their hotbar replant_block(cx, cy, cz) replanted += 1 finally: # Release keys if anything goes wrong player_press_attack(False) player_press_use(False) echo(f"✅ Harvested: {harvested} | Replanted: {replanted}")
\auto_farm — scans a 9×9 area in front of you
\auto_farm 5 10 — 5 wide, 10 deep
Stand at one end of your farm facing down the rows. Make sure the relevant seed type (wheat seeds, carrot, potato, or beetroot seeds) is in your hotbar and selected. The script uses right-click to replant, so the correct seed must be in hand.
API Quick Reference
A condensed cheat sheet of the most useful Minescript functions. For the full reference, see minescript.net/docs.
Output
Player — reading state
Player — movement & input
Blocks & World
Events (Pyjinn)
Useful Minescript console commands
| Command | What it does |
|---|---|
| \help | List all available commands and scripts |
| \jobs | List currently running scripts |
| \killjobs | Stop all running scripts immediately |
| \kill [id] | Stop a specific script by ID |
| \suspend | Pause running scripts |
| \resume | Resume paused scripts |
| \undo | Undo the last setblock/fill commands |
| \install_mappings | Install Fabric name mappings (run once) |
| \pyeval 1+2 | Evaluate a quick Python expression |
Common Errors & How to Fix Them
IndentationError
IndentationError: expected an indented block
Cause: Python uses spaces to define code blocks. You either used a mix of tabs and spaces, or forgot to indent the code inside an if, for, or def block.
Fix: Always use 4 spaces per indent level. In VS Code, configure it to "Insert Spaces" (not tabs) with tab size 4.
NameError
NameError: name 'echo' is not defined
Cause: You used a function without importing it first.
Fix: Add from minescript import echo at the top of your script — or use from minescript import * to import everything.
TypeError
TypeError: can only concatenate str (not "int") to str
Cause: Trying to join a number and a string with +. Python won't silently convert types.
Fix: Use an f-string: echo(f"Score: {score}") instead of echo("Score: " + score).
Script doesn't appear when pressing \
Cause: The script file has a typo in the name, is in the wrong folder, or doesn't have the .pyj extension.
Fix: Check that the file is at ~/.minecraft/minescript/your_script.pyj. Type \help to see a list of detected scripts.
Script runs but nothing happens / wrong blocks
Cause: The chunks around the player may not be fully loaded, or coordinates are off by one.
Fix: Test with echo(getblock(x, y, z)) to verify what block is at a given position before acting on it.
Player keeps moving after script stops
Cause: A key press was never released because the script crashed before the player_press_X(False) line ran.
Fix: Always wrap your movement code in try/finally and release all keys in the finally block (as shown in the full scripts above).
Next Steps & Resources
Ideas for your next scripts
- Auto-smelter — detect a chest, open it with
container_get_items(), move items to a furnace - Ore announcer — listen for
"block_update"events; echo when a diamond ore is exposed nearby - Health monitor — use a
"tick"listener to check health and auto-eat if below a threshold - Waypoint system — save coordinates to a list in your script, teleport to them with
!go waypoint_name - Auto replant 2.0 — combine the block scanner with the farm script to scan the whole area automatically
- XP farm helper — detect mobs with
entities()and aim at the closest one
Essential resources
| Resource | What's there |
|---|---|
| minescript.net/docs | Full API reference — every function documented |
| minescript.net/pyjinn | Pyjinn-specific docs and differences from Python |
| minescript.net/example | Official example script walkthrough |
| github.com/maxuser0/minescript | Source code, changelog, issue tracker |
| Minescript Discord | Community help, script sharing (link on minescript.net) |
| docs.python.org/3/tutorial | Official Python tutorial for deeper learning |
Python concepts worth learning next
- Dictionaries — key-value stores, great for mapping block names to actions
- List comprehensions — concise way to build lists:
[x*2 for x in range(10)] - try/except — catch errors gracefully so scripts don't crash unexpectedly
- Classes — group related functions and data together (not essential for beginner scripts)
- Sets — like lists but faster for "is X in this collection?" checks (used in the tree miner above)
The best way to learn is to break things and fix them. Take any script in this guide and try modifying one thing — change the radius in the scanner, add a new !command to the chat bot, or try scanning for a different block. Reading error messages is a skill you build over time, and Minescript's echo output makes it easy to debug by printing variable values as your script runs.