alfworldpythonverified
alfworld task parser
parse_task(task, receptacles) -> (entry_point, object_type, target_type) for ALFWorld task sentences; lets a tiny executor, or no executor, call the household rungs correctly.
rec_5b4f46bfc96244809e4cb6bc8c5dfc0a · banked 2026-09-04 · by neruva
Not yet certified
This skill has no published checker, so its evidence cannot be reproduced from here.
Scorecard
Turn a benchmark task sentence into the call that satisfies it.
Score on the benchmark
134/134
Without it
n/a
Model turns per task
no model call needed
Cost
free
Smallest model measured
no model at all
Cost to build it once
$0.11
Checked by
300 training pairs, then 100 held-out pairs
Where it does not apply
- Only works because this benchmark's sentences are templated. It is not a general parser.
Evidence
- forged by claude-sonnet-5 for $0.11 against 400 train (task, ground-truth call) pairs: ratchet 300/300, generality gate 100/100 held-out train pairs
- ALFWorld valid_unseen 134 games, parser rung alone with zero model calls + household rungs v1: 127/134; Qwen3-1.7B + rungs + parser repair: 130/134
Use it
# in Claude Code (MCP tools from neruva-mcp)
rung_search(q="alfworld_task_parser")
rung_install(id="rec_5b4f46bfc96244809e4cb6bc8c5dfc0a", dir="~/.claude/skills")
# the skill folder is now loaded like any other skillUsage guide
What the model reads to call the skill. This is the whole interface.
Show the guide
call parse_task(task_sentence, room_receptacles); returns (entry, obj, target); then call entry(w, obj, target) from alfworld_household_rungs
Code
89 lines of python, hashed and signed below.
Show the code
import re
def parse_task(task: str, receptacles: list[str]) -> tuple[str, str, str]:
t = task.strip().lower()
if t.endswith('.'):
t = t[:-1]
recep_types = set()
for r in receptacles:
parts = r.split()
if parts:
recep_types.add(parts[0])
def strip_plural(word, prefer_set=None):
if not word:
return word
if prefer_set is not None:
if word in prefer_set:
return word
if word.endswith('s') and word[:-1] in prefer_set:
return word[:-1]
if word.endswith('s'):
return word[:-1]
return word
if word.endswith('s'):
return word[:-1]
return word
obj = None
target = None
entry = None
# --- examine / look-at cases ---
if re.search(r'\bexamine\b', t) or 'look at' in t:
entry = 'examine_in_light'
m = re.search(r'examine the (\w+) with the (\w+)', t)
if not m:
m = re.search(r'look at (\w+) under the (\w+)', t)
if not m:
m = re.search(r'(\w+).*?(desklamp)', t)
obj_raw, target_raw = m.group(1), m.group(2)
obj = strip_plural(obj_raw)
target = strip_plural(target_raw, recep_types)
return entry, obj, target
# --- determine entry type ---
if re.search(r'\btwo\b', t):
entry = 'pick_two_and_place'
elif re.search(r'\bclean\b', t):
entry = 'clean_and_place'
elif re.search(r'\bhot\b', t) or re.search(r'\bheat\b', t):
entry = 'heat_and_place'
elif re.search(r'\bcool\b', t):
entry = 'cool_and_place'
else:
entry = 'pick_and_place'
# --- extract object and target using common patterns ---
obj_raw = None
target_raw = None
# pattern: "clean/heat/cool some X and put it in Y"
m = re.search(r'(?:clean|heat|cool) some (\w+) and put it in (\w+)', t)
if m:
obj_raw, target_raw = m.group(1), m.group(2)
# pattern: "find two X and put them in Y"
if obj_raw is None:
m = re.search(r'find two (\w+) and put them in (\w+)', t)
if m:
obj_raw, target_raw = m.group(1), m.group(2)
# pattern: "put a/some/two ... X in/on Y"
if obj_raw is None:
m = re.search(r'put (?:a |some |two )?(?:clean |hot |cool )?(\w+) (?:in|on) (\w+)', t)
if m:
obj_raw, target_raw = m.group(1), m.group(2)
# generic fallback
if obj_raw is None:
words = re.findall(r'\w+', t)
obj_raw = words[-3] if len(words) >= 3 else words[0]
target_raw = words[-1]
obj = strip_plural(obj_raw)
target = strip_plural(target_raw, recep_types)
return entry, obj, target
Certificate
Code sha256 4da333e9977fd2b6f3a501cc6065b3098d566371c66c265ad4f50de35eec6291
Signature ed25519, present
Last re-checked
passing
Re-checked today. The signature was recomputed from the code served by the API, and the certificate matched.
A certificate proves the code has not changed. Re-running the check proves it still works today, on today's libraries.