Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
npx skills add https://github.com/SimHacker/moollm --skill postal
The command stays on one line. Scroll horizontally to inspect it before copying.
Prefer a local copy? Download the files currently available to SkillsMP.
"Any address can send and receive. Goals come from anyone, not just Mom."
โ The Gezelligheid Grotto Design Principles
What Is It?
The Postal System is the complete messaging infrastructure:
Feature
Description
Messages
Letters between any endpoints
Texts
SMS-style instant messages
Attachments
Items, gold, images, buffs, room access
Goals
Any character can assign/modify/complete goals
Phone
Always-available mobile access (it's 2026!)
Routing
Deterministic delivery without LLM
Core Concepts
Endpoints
Anything addressable can send/receive:
to:"player"# Reserved keywordto:"characters/family/mom/"# Character pathto:"characters/npcs/bartender/"# Any NPCto:"pub/"# Roomto:"storage/vault/"# Directoryto:"start/mailbox.yml"# Object
Deterministic Addressing
CRITICAL: Addresses are paths, not names. The simulator routes without LLM.
letter:id:"letter-001"from:"characters/family/mom/"to:"player"subject:"Your First Quest"body:|
Dearest child,
Ineedyoutofindsomethingforme.There'sabrasskeysomewhereinthemaze.Withlove,Momattachments: []
# Goal integration (optional โ ANY character can do this!)creates_goal:id:find-keyname:"Find the Key"complete_when:"player has brass-key"reward:letter:mom-reward-001item:family-locket# Metadatasent:nulldelivered:nullread:falsestatus:draft# draft | outbox | sent | delivered | read
Goal Integration
Any character can create/modify/complete goals โ not just Mom:
# Bartender assigns a questletter:from:"characters/npcs/bartender/"to:"player"subject:"A Favor to Ask"body:"Could you deliver this package to the mayor?"creates_goal:id:deliver-packagename:"Deliver the Package"complete_when:"player has talked to mayor with package"reward:gold:50# Don Hopkins updates your questletter:from:"characters/real-people/don-hopkins/"to:"player"subject:"Found something!"modifies_goal:id:find-keyextend_with:"also check the old chest"
Texts (Instant Messages)
Short, instant messages. It's 2026!
text:id:"text-001"from:"characters/npcs/bartender/"to:"player"body:"Hey, you left your hat here!"quick_replies:-"On my way!"-"Thanks, be there soon"-"Can you hold it?"delivery:instant# Not queued like letterstimestamp:nullread:false
Texts vs Letters
Feature
Text
Letter
Length
Short (< 160)
Long
Attachments
Photos only
Anything
Delivery
Instant
Next tick
Creates goals
Rarely
Yes
Formality
Casual
Can be formal
Attachments
Messages can carry anything:
attachments:# Objects-type:objectref:"brass-key"action:send# Remove from sender, give to recipient-type:objectref:"map"action:reference# Just mention, don't transfer# Currency-type:goldquantity:100action:send# Images-type:imageref:"images/treasure-map.png"action:copy-type:imageaction:generateprompt:"A hand-drawn map to the treasure..."# Buffs-type:buffref:name:"Blessed"effect:"+1 luck"duration:10action:apply# Room access-type:roomref:"maze/secret-chamber/"action:unlock
Attachment Actions
Action
Effect
send
Remove from sender, give to recipient
give
Give to recipient (sender keeps if applicable)
copy
Duplicate for recipient
reference
Mention without transfer
unlock
Grant access (for rooms)
apply
Apply effect (for buffs)
generate
Create on delivery (for images)
Inbox & Outbox
Inbox
# player/INBOX.ymlinbox:owner:"player"messages:-ref:"messages/mom-quest.yml"received:"2026-01-10T10:00:00Z"read:falsepriority:highfrom:"characters/family/mom/"subject:"Your First Quest"preview:"Dearest child, I need you to..."unread_count:1settings:max_messages:100forward_to:null
letter:from:"characters/family/mom/"to:"player"# Delivery simulationdelivery:method:letter# letter, express, text# Time calculationbase_time:3# Base turnsdistance_factor:1# Turns per "hop" of distancetotal_time:5# Calculated: base + (distance * factor)# Timestampssent:"2026-01-10T10:00:00Z"estimated_arrival:"2026-01-10T10:05:00Z"# 5 turns laterdelivered:null# Set when actually delivered# Statusstatus:in_transit# draft | outbox | in_transit | delivered | readturns_remaining:5
Delivery Methods
Method
Base Time
Cost
Features
text
0 (instant)
Free
Photos only, casual
letter
3 turns
1 gold
Full attachments, goals
express
1 turn
5 gold
Priority delivery
freight
10 turns
0.5 gold/kg
Heavy items, bulk
courier
2 turns
10 gold
Guaranteed, tracked
Distance Calculation
Distance is measured in "hops" through the room graph:
# Distance examples:# Same room: 0 hops# Adjacent room: 1 hop# Through maze: 5+ hops# Different "region": 10+ hopsdelivery:from_location:"pub/"to_location:"characters/family/mom/"# Mom's homehops:4time_per_hop:1total_delivery_time:7# base 3 + (4 * 1)
Postage Costs
Sending mail costs resources:
letter:from:"player"to:"characters/family/mom/"postage:method:letterbase_cost:1# Goldweight_cost:0# Per kg for heavy itemsdistance_cost:0.5# Per hoptotal_cost:3# Calculated# Paymentpaid:falsepaid_from:"player"# Who pays# Insufficient funds?requires_payment:truecan_send:true# false if can't afford
Free Messaging
Some messages are free:
# Texts are freetext:postage:method:texttotal_cost:0# System messages are freeletter:from:"narrator"postage:total_cost:0reason:"system message"# Within same location is freeletter:from:"pub/bartender.yml"to:"pub/patron.yml"postage:total_cost:0reason:"same location"
In-Transit Tracking
Track messages in transit:
# world.skills.postal statepostal:in_transit:-id:letter-001from:"player"to:"characters/family/mom/"turns_remaining:3-id:letter-002from:"characters/npcs/bartender/"to:"player"turns_remaining:1# Each tick, turns_remaining decrements# When 0, message is delivered
Delivery Simulation in Tick
# MAIL phase of simulationdefdeliver_mail(world):
postal = world.skills.postal
# Decrement turns for in-transit messages
still_in_transit = []
for message in postal.get('in_transit', []):
message['turns_remaining'] -= 1if message['turns_remaining'] <= 0:
# Deliver now!
actually_deliver(world, message)
world.trigger_event('MAIL_ARRIVED', {
'from': message['from'],
'to': message['to']
})
else:
still_in_transit.append(message)
postal['in_transit'] = still_in_transit
Express & Priority
Pay more for faster delivery:
letter:delivery:method:expresspostage:base_cost:5# Express premiumguaranteed_time:1# Arrives next turntracking:true# Can check statusinsurance:true# Compensated if lost
Lost Mail (Optional Mechanic)
For added realism/drama:
postal:settings:loss_chance:0.01# 1% chance of lossloss_recoverable:true# Can be found later# Lost mail goes to:lost_mail_location:"maze/lost-and-found/"
Deterministic Routing
The simulator delivers mail without LLM. See ROUTING.md.
Logistics Integration โ Postal IS the Transport Layer!
KEY INSIGHT: You don't need physical bots to move items between logistic containers.
The postal system IS the transport layer โ instantaneous, free, efficient!
The Unification
Factorio
MOOLLM
Logistics bots
Postal system (free, instant)
Flying between chests
Email/text delivery
Request list
Triggers automated mail
Active provider pushing
Auto-send attachments
Circuit signals
Text notifications
How It Works
When a logistics requester needs items, instead of dispatching a bot:
# Automatic postal delivery for logisticslogistics_delivery:trigger:"requester.request_unfulfilled"# Find a provider with matching itemsprovider:"nw/iron-ore/"requester:"forge/"item:"iron-ore"count:20# Generate a postal transfer (instant, free!)postal_transfer:type:internal-logistics# Special type: no cost, instantfrom:"nw/iron-ore/"to:"forge/"attachments:-type:objectref:"iron-ore"quantity:20action:send# No delivery time for internal logistics!delivery:method:logistics# New method: instant, freetotal_time:0cost:0
Logistics Delivery Methods
Method
Time
Cost
Use Case
logistics
0
Free
Internal network transfers
text
0
Free
Signals, notifications
letter
3+ turns
1+ gold
Player-to-player with drama
freight
10+ turns
Per weight
Physical bulk transport
Camera Phone = Image Generation!
Your phone's camera can generate images via prompts:
text:from:"player"to:"narrator"body:"Take a photo of this treasure map"attachments:-type:imageaction:generateprompt:"A weathered treasure map showing the maze layout..."save_to:"player/photos/treasure-map.png"
Text Messages = Circuit Signals!
Texts can carry logistics signals:
# Room emits signal when low on fuelroom:signals:enabled:trueemit:-signal:"low-fuel"when:"stacks.coal < 5"action:text:to:"player"body:"โ ๏ธ Forge is running low on coal!"
No Bots Needed (But You Can Have Them!)
Default: Logistics uses postal (instant, free)
Optional: Physical bots for gameplay/drama
logistic-container:transport:method:postal# Default: instant via mail# ORmethod:bot# Physical transport (slower, visible)bot_path:"characters/courier-kitten/"
When using bots:
Player sees the kitten carrying items
Can intercept, pet, or redirect
Adds gameplay and drama
But slower than postal!
The Complete Flow
1. REQUESTER: "I need 20 iron ore"
โ
โผ
2. LOGISTICS ENGINE finds provider with iron ore
โ
โผ
3. Generate POSTAL TRANSFER (internal, instant, free)
โ
โโโโ method: postal โโโโโ Instant delivery
โ No physical movement
โ Items "teleport"
โ
โโโโ method: bot โโโโโโโโ Dispatch courier kitten
Physical movement
Player can see/interact
โ
โผ
4. REQUESTER receives items
โ
โผ
5. on_request_fulfilled fires
Why This Is Better
Physical Bots
Postal Transport
Slow (travel time)
Instant
Visible (might break immersion)
Invisible (just works)
Can get stuck
Never fails
Limited cargo
Unlimited
Fun to watch
Efficient
Use bots for drama. Use postal for efficiency.
Commands
Command
Effect
CHECK PHONE
See notifications and quick access
READ MAIL
Open inbox
READ [letter]
Display letter
COMPOSE
Start writing
REPLY
Reply to current
ATTACH [item]
Add attachment
SEND
Send current message
TEXT [character]
Quick text
Mom as a Character
Mom isn't special infrastructure โ she's just a character:
# characters/family/mom/CHARACTER.ymlcharacter:id:momname:"Mom"type:correspondentpersonality:warmth:10worry:7pride:9voice:patterns:-"Dearest child"-"I'm so proud"-"Be careful out there"triggers:on_goal_complete:"Send congratulations letter"on_danger:"Send worried letter"on_long_silence:"Send 'are you okay?' letter"
Any character can have similar triggers. The bartender can send quests. Don Hopkins can send updates. Goals come from anyone!
Browser UI
See BROWSER-UI.md for the delightful mail interface.
Protocol Symbol
POSTAL-SYSTEM โ Complete messaging with deterministic routing