TALOSdocs

Example scripts

Talos ships a set of bundled reference scripts. Write one to talos/scripts/ and run it:

/talos example                 # list every bundled example
/talos example lumberjack      # writes talos/scripts/example_lumberjack.py
/talos script run example_lumberjack [maxTrees]

/talos example <name> overwrites its file every time — they're reference material, not saved state. Read them, then copy and adapt. Every one uses only the documented API (see Python scripting).

Example What it shows
goto A from-scratch pathless goto on raw primitives, plus overriding the built-in /talos goto
farm A tiny find → goto → harvest loop with humanized waits
follow Overriding /talos follow and a from-scratch follow loop
lumberjack A practical multi-wood tree feller
events Every talos.on(...) push event, printed live
sensors A live dashboard built entirely from talos.get() — a tour of the getter families
sim A wandering "sheep" — the talos.sim simulation framework (state machine + seeded RNG), plus a suggest=-completed control command. See Simulations & custom pathfinding
pygoto Write-your-own pathfinding from raw primitives + a /talos goto override (sibling of goto)
stdlib The Python standard library out of the box: random, json, math, collections, …

goto — custom goto + command override

/talos example goto — a pure-Python goto built on raw primitives (no pathfinder), plus a /talos goto override that wraps the built-in. This is the pattern for replacing or extending any built-in command from Python: register @talos.command("goto"), do your custom prep, then delegate to talos.aio.goto(...) (the original stays reachable).

# example_goto.py -- a pure-Python goto built on raw primitives, plus a
# /talos goto override. Reference material: /talos example goto rewrites it.
#
# Run:    /talos script run example_goto
# Then:   /talos pygoto <x> <y> <z>     (from-scratch goto, no pathfinder)
#         /talos goto xyz <x> <y> <z>   (now routed through goto_override)
# Stop:   /talos script stop            (handlers unregister automatically)

import math
import talos

ARRIVE = 0.5        # horizontal distance (blocks) that counts as "arrived"
TURN_STEP = 12.0    # max yaw correction per tick -- small = smooth turning
STALL_TICKS = 8     # ticks without progress before we tap jump


def yaw_toward(feet, x, z):
    # Minecraft yaw: 0 = south (+Z), 90 = west (-X) -- hence atan2(-dx, dz).
    return math.degrees(math.atan2(-(x - feet.x), z - feet.z))


async def naive_goto(x, y, z):
    # Once per tick: measure the offset, ease the yaw toward it, hold forward,
    # and tap jump when the distance stops shrinking (a step or lip ahead).
    tx, tz = x + 0.5, z + 0.5   # aim for the center of the target cell
    best = None                 # closest distance reached so far
    stall = 0                   # ticks since best last improved
    try:
        while True:
            feet = talos.player_feet()
            dx, dz = tx - feet.x, tz - feet.z
            dist = (dx * dx + dz * dz) ** 0.5
            if dist <= ARRIVE:
                talos.log(f"pygoto: arrived ({dist:.2f} blocks from target)")
                return

            # Eased steering: shortest signed turn toward the target, clamped.
            yaw, _pitch = talos.look_angle()
            delta = (yaw_toward(feet, tx, tz) - yaw + 180.0) % 360.0 - 180.0
            step = max(-TURN_STEP, min(TURN_STEP, delta))
            talos.look(yaw + step, 15.0)  # slight downward pitch: watch our feet

            talos.key("forward")          # HELD until released -- see finally

            # Progress watchdog: a ~1-block step ahead stops us; tap jump.
            if best is None or dist < best - 0.05:
                best, stall = dist, 0
            else:
                stall += 1
                if stall >= STALL_TICKS:
                    stall = 0
                    talos.tap("jump")     # one tick, releases itself

            await talos.next_tick()       # one control decision per game tick
    finally:
        talos.release_keys()              # never leave W held down


@talos.command("pygoto")
def pygoto(args):
    # /talos pygoto <x> <y> <z> -- returning the coroutine starts it as a task,
    # so chat (and other tasks) stay responsive while it walks.
    if len(args) != 3:
        talos.log("usage: /talos pygoto <x> <y> <z>")
        return
    x, y, z = (int(float(a)) for a in args)
    talos.log(f"pygoto: walking to {x} {y} {z} (raw inputs, no pathfinder)")
    return naive_goto(x, y, z)


@talos.command("goto")
def goto_override(args):
    # Replaces /talos goto while this script runs. The built-ins stay reachable
    # as talos.goto / talos.aio.goto / talos.aio.goto_block, so the override can
    # prep, then delegate. Handles both forms:
    #   /talos goto xyz <x> <y> <z>
    #   /talos goto block <blockId> [radius]
    async def wrapped_xyz(x, y, z):
        # Custom prep goes here (speedbridging, scaffolding, logging, ...).
        result = await talos.aio.goto(x, y, z)  # the ORIGINAL goto, unchanged
        talos.log(f"goto override: built-in finished -- {result}")

    async def wrapped_block(block_id, radius):
        result = await talos.aio.goto_block(block_id, radius)
        talos.log(f"goto override: goto_block finished -- {result}")

    if args and args[0] == "block":
        radius = int(args[2]) if len(args) > 2 else 64
        return wrapped_block(args[1], radius)
    if args and args[0] == "xyz":
        args = args[1:]
    if len(args) != 3:
        talos.log("this override handles xyz <x> <y> <z> and block <id> [radius]")
        return
    x, y, z = (int(float(a)) for a in args)
    return wrapped_xyz(x, y, z)


talos.log("example_goto loaded: /talos goto overridden, /talos pygoto added")

farm — find → goto → mine loop

/talos example farm — scan for a crop, walk to it, harvest, and wait a humanized moment before scanning again.

# example_farm.py -- a tiny farming loop: find a crop, walk to it, harvest
# it, and wait a humanized moment before scanning again. Reference material:
# /talos example farm rewrites it.
#
# Run:    /talos script run example_farm
# Stop:   /talos script stop

import talos

# Crops to harvest, in preference order. Add "minecraft:carrots" etc. here.
CROPS = ["minecraft:sugar_cane", "minecraft:wheat"]


@talos.task
async def farm():
    while True:
        target = None
        for crop in CROPS:
            target = await talos.aio.find_block(crop, 32)
            if target:
                break
        if target is None:
            talos.log("farm: nothing to harvest nearby, waiting...")
            await talos.aio.wait(2.0, 4.0)   # humanized pause between scans
            continue

        await talos.aio.goto_near(int(target.x), int(target.y), int(target.z), 2)
        await talos.aio.mine(target)

        # Replanting: for wheat, select the hotbar slot holding seeds and
        # place them back on the farmland, e.g.:
        #   talos.select_slot(0)                          # slot with seeds
        #   talos.place_block(target.x, target.y, target.z)
        # Sugar cane regrows from the stump, so it needs no replant.

        await talos.aio.wait(0.4, 0.9)       # human-ish pause per harvest

follow — override + from-scratch shadow

/talos example follow — override /talos follow with custom behaviour layered on the built-in, plus a from-scratch /talos shadow loop on raw primitives for full control.

# example_follow.py -- customize /talos follow. Reference material:
# /talos example follow rewrites it.
#
# Run:    /talos script run example_follow
# Then:   /talos follow <name|type|@e[...]> [distance]   (routed through here)
#         /talos shadow <target>                          (from-scratch loop)
# Stop:   /talos script stop
#
# Targets accept players AND any entity: "Steve", "zombie",
# "@e[type=cow,distance=..20]", "@p", "@n". The built-in stays reachable as
# talos.follow / talos.aio.follow.

import talos


@talos.command("follow")
def follow_override(args):
    # Peel a trailing number off as the keep-distance, like the built-in does.
    if not args:
        talos.log("usage: /talos follow <target> [distance]")
        return
    distance = 3.0
    if len(args) > 1:
        try:
            distance = float(args[-1])
            args = args[:-1]
        except ValueError:
            pass
    target = " ".join(args)

    async def wrapped():
        talos.log(f"following {target!r}, keeping ~{distance} blocks")
        # Custom behavior goes here: sprint-only follow, waypoint logging,
        # auto-eat while following, breaking off when health drops, ...
        try:
            await talos.aio.follow(target, distance)  # the ORIGINAL follow
        except talos.PathFailedError as error:
            talos.log(f"follow ended: {error}")

    return wrapped()


@talos.command("shadow")
def shadow(args):
    # A from-scratch follow on raw primitives: re-goto the target's feet
    # whenever they stray, with everything (pace, distance, pathing options)
    # under your control.
    if not args:
        talos.log("usage: /talos shadow <target>")
        return
    target = " ".join(args)

    async def loop():
        while True:
            entity = talos.find_entity(target, 64) if ":" in target \
                else next((p for p in talos.players()
                           if p.name.lower() == target.lower()), None)
            if entity is None:
                talos.log("shadow: target not in range, waiting...")
                await talos.aio.wait(1.0, 2.0)
                continue
            if entity.distance > 4.0:
                await talos.aio.goto_near(int(entity.pos.x), int(entity.pos.y),
                                          int(entity.pos.z), 2)
            await talos.aio.wait(0.3, 0.6)

    return loop()


talos.log("example_follow loaded: /talos follow overridden, /talos shadow added")

lumberjack — fell trees

/talos example lumberjack — find a log of any wood type, walk to it, mine the trunk column upward, and move on to the next tree. Pass a count (/talos script run example_lumberjack 5) or omit it to run until you /talos script stop.

# example_lumberjack.py -- fell nearby trees: find a log, walk to it, mine
# the trunk column upward, then look for the next one. Reference material:
# /talos example lumberjack rewrites it.
#
# Run:    /talos script run example_lumberjack [maxTrees]   (0/omitted = forever)
# Stop:   /talos script stop

import talos

LOGS = ["minecraft:oak_log", "minecraft:birch_log", "minecraft:spruce_log",
        "minecraft:jungle_log", "minecraft:acacia_log", "minecraft:dark_oak_log",
        "minecraft:mangrove_log", "minecraft:cherry_log"]


def nearest_log(radius=48):
    # find_block returns the nearest of ONE id; scan every log type and keep
    # the closest hit across them all.
    best = None
    feet = talos.player_feet()
    for log in LOGS:
        pos = talos.find_block(log, radius)
        if pos is None:
            continue
        d = ((pos.x - feet.x) ** 2 + (pos.y - feet.y) ** 2 + (pos.z - feet.z) ** 2) ** 0.5
        if best is None or d < best[0]:
            best = (d, pos)
    return best[1] if best else None


@talos.task
async def chop():
    goal = int(talos.args[0]) if talos.args else 0   # 0 = run until stopped
    felled = 0
    while goal == 0 or felled < goal:
        tree = nearest_log()
        if tree is None:
            talos.hud("§6lumberjack §7» no trees in range, waiting...", id="lj")
            await talos.aio.wait(2.0, 4.0)
            continue

        tx, ty, tz = int(tree.x), int(tree.y), int(tree.z)
        talos.hud(f"§6lumberjack §7» felling tree at {tx} {ty} {tz}", id="lj")
        await talos.aio.goto_near(tx, ty, tz, 2)

        # Mine straight up the trunk: same X/Z column, block by block, for as
        # long as the block there is a log.
        y = ty
        while True:
            here = talos.block_at(tx, y, tz)
            if "log" not in here:
                break
            await talos.aio.mine(tx, y, tz)
            await talos.aio.wait(0.15, 0.4)   # humanized swing cadence
            y += 1

        felled += 1
        logs = talos.count("minecraft:oak_log") + talos.count("minecraft:birch_log")
        talos.hud(f"§6lumberjack §7» felled {felled} · logs carried {logs}", id="lj")
        await talos.aio.wait(0.5, 1.2)
    talos.log(f"lumberjack: done, felled {felled} trees")

talos.run()

events — every talos.on(...) handler

/talos example events — subscribe to every talos.on(...) push event and print what fires, so you can watch the live event stream. (These ten push callbacks are distinct from the 206 /talos on rule triggers — read those with talos.get; see sensors below.)

# example_events.py -- subscribe to EVERY talos.on(...) event and print what
# fires, so you can watch the live event stream. Reference material:
# /talos example events rewrites it.
#
# Run:    /talos script run example_events
# Stop:   /talos script stop
#
# NOTE: talos.on(...) push events (below) are a small set of worker-thread
# callbacks. They are NOT the 206 /talos on <trigger> rule names -- every one
# of those is readable instead via talos.get(name, *args); see example_sensors.

import talos

@talos.on("tick")
def _tick():
    # Fires ~20x/second. Keep it cheap. Here it does nothing but prove it runs.
    pass

@talos.on("chat")
def _chat(message, sender):
    # sender = a player name, or None for system lines. YOUR OWN messages echo
    # back here too -- always guard against reacting to yourself.
    who = sender if sender is not None else "<system>"
    talos.log(f"[chat] {who}: {message}")

@talos.on("health")
def _health(health):
    talos.hud(f"§chealth §f{health:.1f}", id="ev_health")

@talos.on("entity_hurt")
def _entity_hurt(type_id, entity_id, x, y, z):
    talos.log(f"[entity_hurt] {type_id} #{entity_id} @ {x:.1f} {y:.1f} {z:.1f}")

@talos.on("item_pickup")
def _pickup(item_id, amount):
    talos.log(f"[item_pickup] +{amount} {item_id}")

@talos.on("death")
def _death():
    talos.hud("§4you died", id="ev_death")

@talos.on("goto_start")
def _goto_start(x, y, z):
    talos.log(f"[goto_start] planning to {x} {y} {z}")

@talos.on("goto_done")
def _goto_done(success, detail):
    talos.log(f"[goto_done] success={success} -- {detail}")

@talos.on("goto_stuck")
def _goto_stuck(detail):
    talos.log(f"[goto_stuck] replanning -- {detail}")

@talos.on("disconnect")
def _disconnect():
    talos.log("[disconnect] left the world")

talos.hud("§aevent monitor armed §7» watch the log", id="ev_title")
talos.run()

sensors — live talos.get() dashboard

/talos example sensors — a live HUD dashboard built entirely from talos.get(), with a startup tour of every getter family: plain metrics, descriptive strings, booleans, spatial getters (coords), parameterized getters (selectors/items/enchants/regions), and event getters. Every one of the 206 /talos on triggers is also a getter — /talos get list dumps them all.

# example_sensors.py -- a live dashboard built entirely from talos.get(). Every
# one of the 206 /talos on triggers is ALSO a getter: talos.get(name, *args).
# Numbers come back as int/float, booleans as bool, everything else as str.
# Reference material: /talos example sensors rewrites it.
#
# Run:    /talos script run example_sensors
# Stop:   /talos script stop
# See:    /talos get list   (dumps every observable + all 206 trigger names)

import talos

def dump_catalog_demo():
    # A guided tour of the getter FAMILIES, printed once at startup.
    talos.log("== talos.get() families ==")

    # 1) plain live numeric metrics (no args)
    for name in ("health", "hunger", "air", "xp_level", "armor_points",
                 "speed", "server_tps", "fps", "ping", "light_level"):
        talos.log(f"  {name} = {talos.get(name)}")

    # 2) descriptive string getters
    for name in ("position", "dimension", "biome", "held_item", "weather", "time"):
        talos.log(f"  {name} = {talos.get(name)}")

    # 3) boolean state getters
    for name in ("sneaking", "sprinting", "on_ground", "moving", "inventory_full"):
        talos.log(f"  {name} = {talos.get(name)}")

    # 4) spatial getters accept coords: absolute, ~ feet-relative, or ^ local frame
    talos.log(f"  light_level(^ ^ ^8 ahead) = {talos.get('light_level', '^ ^ ^8')}")
    talos.log("  block_count(diamond_ore r16, 4 below) = "
              f"{talos.get('block_count', 'minecraft:diamond_ore', 16, '~', '~-4', '~')}")

    # 5) parameterized getters: selectors, items, enchants, regions
    talos.log(f"  entity_count(@e[type=zombie] r32) = {talos.get('entity_count', '@e[type=zombie]', 32)}")
    talos.log(f"  item_count(diamond) = {talos.get('item_count', 'minecraft:diamond')}")
    talos.log(f"  held_enchant(efficiency) = {talos.get('held_enchant', 'minecraft:efficiency')}")
    talos.log(f"  entered_region(100 60 100..120 80 120) = "
              f"{talos.get('entered_region', 100, 60, 100, 120, 80, 120)}")

    # 6) event getters: latest occurrence + '[N.NNs ago]', or 'never observed'
    for name in ("damage_taken", "item_picked_up", "villager_profession_changed",
                 "sound", "explosion", "block_at_feet"):
        talos.log(f"  {name} = {talos.get(name)}")

dump_catalog_demo()

@talos.every(ticks=5)
def dashboard():
    # A compact vitals HUD refreshed 4x/second, every value straight from get().
    hp = talos.get("health"); food = talos.get("hunger")
    tps = talos.get("server_tps"); spd = talos.get("speed")
    hostile = talos.get("nearest_hostile_distance")
    talos.hud(f"§chp§f {hp:.0f}  §6food§f {food:.0f}  §aTPS§f {tps:.1f}  "
              f"§dspd§f {spd:.1f}  §chostile§f {hostile:.1f}m", id="dash_vitals")
    talos.hud(f"§7{talos.get('position')} · {talos.get('dimension')} · "
              f"{talos.get('biome')}", id="dash_where")
    talos.hud(f"§7looking at §f{talos.get('looking_at')}", id="dash_look")

talos.hud("§asensor dashboard live §7» /talos get list for all 206", id="dash_title")
talos.run()
Client-side Fabric mod for Minecraft 1.21.11 / 26.1 / 26.2 · GitHub · Releases. Responsible use: automation may violate individual server rules — use in singleplayer or where permitted.