Minescript 5.0 / Pyjinn Fabric · Linux Zero prior experience needed

Python Scripting for
Minescript 5.0

A complete beginner's guide — from zero coding knowledge to writing real automation scripts inside Minecraft. No Python installation required.

01

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
ℹ️ About Minescript 5.0 / Pyjinn

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 .jar file.

  • 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 .jar files 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 \help and press Enter. If you see a list of commands, it works!

💡 Finding your minecraft folder on Linux

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.

⚠️ .pyj vs .py

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:

in-game chatminescript
\install_mappings
02

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 .pyj extension tells Minescript it's a Pyjinn script.

💡 Syntax highlighting tip

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.

03

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.

basics.pyjpython
# 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

TypeExampleWhat it's for
str"hello" or 'hello'Text — names, block IDs, messages
int42Whole numbers — coordinates, counts
float3.14Decimal numbers — player position
boolTrue / FalseYes/no values — is a block solid?

Lists — multiple values in one variable

A list stores multiple values in order, inside square brackets.

examplepython
# 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.

examplepython
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.

04

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.

examplepython
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

OperatorMeaningExample
==equal tox == 5
!=not equal tox != 5
>greater thanhealth > 10
<less thany < 60
>=greater than or equalcount >= 64
initem 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).

examplepython
# 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

examplepython
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
⚠️ Infinite loops

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

examplepython
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)
05

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.

examplepython
# 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.

examplepython
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!")
💡 Good habit

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.

06

Imports

Python and Minescript have extra libraries of pre-built functions. You import them at the top of your script to use them.

my_script.pyjpython
# 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
ℹ️ Pyjinn auto-import

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.

07

Your First Minescript Script

Let's write a real script and run it. Create a file called hello.pyj in your ~/.minecraft/minescript/ folder.

👋
hello.pyj
Your first working Minescript script
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

  • 1
    Save the file

    Press Ctrl+S in your text editor.

  • 2
    Load a Minecraft world

    Any world will do — creative mode is easiest for testing.

  • 3
    Open the Minescript console

    Press \ (backslash). A chat-like input appears.

  • 4
    Type the script name

    Type \hello and press Enter. You should see your name and coordinates appear in chat.

💡 echo vs 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.

08

Player Functions

Minescript gives you a rich set of functions for reading the player's state and controlling their actions.

Reading player state

player_info.pyjpython
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?

examplepython
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.

examplepython
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)
09

Blocks & World

Reading block types

blocks.pyjpython
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:

examplepython
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.

examplepython
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 need the right permissions

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.

10

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

movement.pyjpython
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)

examplepython
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)
💡 Always release keys!

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.

11

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

chat_listener.pyjpython
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.

tick_example.pyjpython
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

timer_example.pyjpython
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 typeWhen 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
12

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.

💬
chat_bot.pyj
Listens for !commands in chat and responds
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.")
💡 How to use it

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.

13

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.

🔍
block_scanner.pyj
Finds blocks of a given type in a radius around the player
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")
💡 Usage examples

\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

14

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.

⚠️ Before running

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.

🌳
tree_miner.pyj
Automatically finds and chops a tree trunk in front of the player
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.")
💡 Adjusting break time

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.

15

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.

🌾
auto_farm.pyj
Harvests and replants fully grown crops in a grid
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}")
💡 Usage & tips

\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.

16

API Quick Reference

A condensed cheat sheet of the most useful Minescript functions. For the full reference, see minescript.net/docs.

Output

echo("message")
Print to chat — visible only to you
chat("message")
Send to public chat (everyone sees it)
log("message")
Write to latest.log

Player — reading state

player_name()
Returns the player's username (str)
player_position()
Returns (x, y, z) as floats
player_orientation()
Returns (yaw, pitch) in degrees
player_health()
Returns health as float (0–20)
player_inventory()
Returns list of inventory item objects
player_get_targeted_block(n)
Block in crosshairs within n blocks

Player — movement & input

player_set_orientation(yaw, pitch)
Set facing direction in degrees
player_look_at(x, y, z)
Look toward world coordinates
player_press_forward(bool)
Hold / release W key
player_press_backward(bool)
Hold / release S key
player_press_left(bool)
Hold / release A key
player_press_right(bool)
Hold / release D key
player_press_jump(bool)
Hold / release Space
player_press_sprint(bool)
Hold / release sprint key
player_press_sneak(bool)
Hold / release Shift
player_press_attack(bool)
Hold / release left mouse button
player_press_use(bool)
Hold / release right mouse button
player_press_drop(bool)
Hold / release Q (drop item)

Blocks & World

getblock(x, y, z)
Block type at coordinates (str)
getblocklist(positions)
Block types for a list of positions
execute("command")
Run a Minecraft slash command
world_info()
World name, time, rain, spawn, etc.

Events (Pyjinn)

add_event_listener(type, fn)
Register a callback for an event
remove_event_listener(id)
Stop listening (uses returned int)
set_interval(fn, ms)
Call fn every N milliseconds
set_timeout(fn, ms)
Call fn once after N milliseconds

Useful Minescript console commands

CommandWhat it does
\helpList all available commands and scripts
\jobsList currently running scripts
\killjobsStop all running scripts immediately
\kill [id]Stop a specific script by ID
\suspendPause running scripts
\resumeResume paused scripts
\undoUndo the last setblock/fill commands
\install_mappingsInstall Fabric name mappings (run once)
\pyeval 1+2Evaluate a quick Python expression
17

Common Errors & How to Fix Them

IndentationError

Error message

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

Error message

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

Error message

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).

18

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

ResourceWhat's there
minescript.net/docsFull API reference — every function documented
minescript.net/pyjinnPyjinn-specific docs and differences from Python
minescript.net/exampleOfficial example script walkthrough
github.com/maxuser0/minescriptSource code, changelog, issue tracker
Minescript DiscordCommunity help, script sharing (link on minescript.net)
docs.python.org/3/tutorialOfficial 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)
💡 Final tip

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.