postal

Complete messaging system — letters, texts, goals, rewards, attachments

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "postal" with this command: npx skills add simhacker/moollm/simhacker-moollm-postal

Postal System

"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:

FeatureDescription
MessagesLetters between any endpoints
TextsSMS-style instant messages
AttachmentsItems, gold, images, buffs, room access
GoalsAny character can assign/modify/complete goals
PhoneAlways-available mobile access (it's 2026!)
RoutingDeterministic delivery without LLM

Core Concepts

Endpoints

Anything addressable can send/receive:

to: "player"                       # Reserved keyword
to: "characters/family/mom/"       # Character path
to: "characters/npcs/bartender/"   # Any NPC
to: "pub/"                         # Room
to: "storage/vault/"               # Directory
to: "start/mailbox.yml"            # Object

Deterministic Addressing

CRITICAL: Addresses are paths, not names. The simulator routes without LLM.

# BAD: Symbolic (requires LLM)
from: mom
to: the bartender

# GOOD: Deterministic paths
from: "characters/family/mom/"
to: "characters/npcs/bartender/"

Reserved Keywords

KeywordResolves To
playerCurrent player character
partyAll party members
narratorSystem/narrative voice

It's 2026 — You Have a Phone!

You carry a phone at all times. Mail and texts are always available.

player:
  devices:
    phone:
      always_carried: true
      capabilities: [mail, text, notifications, camera, maps]

Notification Types

TypeExample
📬 Mail"New letter from Mom!"
💬 Text"Don: Meet me at the pub"
🎯 Quest"Quest updated: Find the Key"
⚠️ Alert"WARNING: Grue nearby!"
🎁 Reward"You received: Gold Coins (50)"

Letters (Full Messages)

Structure

letter:
  id: "letter-001"
  from: "characters/family/mom/"
  to: "player"
  subject: "Your First Quest"
  
  body: |
    Dearest child,
    
    I need you to find something for me.
    There's a brass key somewhere in the maze.
    
    With love,
    Mom
    
  attachments: []
  
  # Goal integration (optional — ANY character can do this!)
  creates_goal:
    id: find-key
    name: "Find the Key"
    complete_when: "player has brass-key"
    reward:
      letter: mom-reward-001
      item: family-locket
      
  # Metadata
  sent: null
  delivered: null
  read: false
  status: draft  # draft | outbox | sent | delivered | read

Goal Integration

Any character can create/modify/complete goals — not just Mom:

# Bartender assigns a quest
letter:
  from: "characters/npcs/bartender/"
  to: "player"
  subject: "A Favor to Ask"
  body: "Could you deliver this package to the mayor?"
  
  creates_goal:
    id: deliver-package
    name: "Deliver the Package"
    complete_when: "player has talked to mayor with package"
    reward:
      gold: 50
      
# Don Hopkins updates your quest
letter:
  from: "characters/real-people/don-hopkins/"
  to: "player"
  subject: "Found something!"
  
  modifies_goal:
    id: find-key
    extend_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 letters
  timestamp: null
  read: false

Texts vs Letters

FeatureTextLetter
LengthShort (< 160)Long
AttachmentsPhotos onlyAnything
DeliveryInstantNext tick
Creates goalsRarelyYes
FormalityCasualCan be formal

Attachments

Messages can carry anything:

attachments:
  # Objects
  - type: object
    ref: "brass-key"
    action: send       # Remove from sender, give to recipient
    
  - type: object
    ref: "map"
    action: reference  # Just mention, don't transfer
    
  # Currency
  - type: gold
    quantity: 100
    action: send
    
  # Images
  - type: image
    ref: "images/treasure-map.png"
    action: copy
    
  - type: image
    action: generate
    prompt: "A hand-drawn map to the treasure..."
    
  # Buffs
  - type: buff
    ref:
      name: "Blessed"
      effect: "+1 luck"
      duration: 10
    action: apply
    
  # Room access
  - type: room
    ref: "maze/secret-chamber/"
    action: unlock

Attachment Actions

ActionEffect
sendRemove from sender, give to recipient
giveGive to recipient (sender keeps if applicable)
copyDuplicate for recipient
referenceMention without transfer
unlockGrant access (for rooms)
applyApply effect (for buffs)
generateCreate on delivery (for images)

Inbox & Outbox

Inbox

# player/INBOX.yml
inbox:
  owner: "player"
  
  messages:
    - ref: "messages/mom-quest.yml"
      received: "2026-01-10T10:00:00Z"
      read: false
      priority: high
      from: "characters/family/mom/"
      subject: "Your First Quest"
      preview: "Dearest child, I need you to..."
      
  unread_count: 1
  
  settings:
    max_messages: 100
    forward_to: null

Outbox (Optional)

Stage messages before sending:

# player/OUTBOX.yml
outbox:
  owner: "player"
  
  drafts:
    - ref: "messages/draft-001.yml"
      started: "2026-01-10T09:00:00Z"
      
  pending:
    - ref: "messages/ready-001.yml"
      to: "characters/family/mom/"

Delivery Simulation

The postal system simulates realistic delivery:

Delivery Time

Messages don't arrive instantly (unless texting!):

letter:
  from: "characters/family/mom/"
  to: "player"
  
  # Delivery simulation
  delivery:
    method: letter           # letter, express, text
    
    # Time calculation
    base_time: 3             # Base turns
    distance_factor: 1       # Turns per "hop" of distance
    total_time: 5            # Calculated: base + (distance * factor)
    
    # Timestamps
    sent: "2026-01-10T10:00:00Z"
    estimated_arrival: "2026-01-10T10:05:00Z"  # 5 turns later
    delivered: null          # Set when actually delivered
    
    # Status
    status: in_transit       # draft | outbox | in_transit | delivered | read
    turns_remaining: 5

Delivery Methods

MethodBase TimeCostFeatures
text0 (instant)FreePhotos only, casual
letter3 turns1 goldFull attachments, goals
express1 turn5 goldPriority delivery
freight10 turns0.5 gold/kgHeavy items, bulk
courier2 turns10 goldGuaranteed, 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+ hops

delivery:
  from_location: "pub/"
  to_location: "characters/family/mom/"  # Mom's home
  hops: 4
  time_per_hop: 1
  total_delivery_time: 7  # base 3 + (4 * 1)

Postage Costs

Sending mail costs resources:

letter:
  from: "player"
  to: "characters/family/mom/"
  
  postage:
    method: letter
    base_cost: 1             # Gold
    weight_cost: 0           # Per kg for heavy items
    distance_cost: 0.5       # Per hop
    total_cost: 3            # Calculated
    
    # Payment
    paid: false
    paid_from: "player"      # Who pays
    
    # Insufficient funds?
    requires_payment: true
    can_send: true           # false if can't afford

Free Messaging

Some messages are free:

# Texts are free
text:
  postage:
    method: text
    total_cost: 0
    
# System messages are free
letter:
  from: "narrator"
  postage:
    total_cost: 0
    reason: "system message"
    
# Within same location is free
letter:
  from: "pub/bartender.yml"
  to: "pub/patron.yml"
  postage:
    total_cost: 0
    reason: "same location"

In-Transit Tracking

Track messages in transit:

# world.skills.postal state
postal:
  in_transit:
    - id: letter-001
      from: "player"
      to: "characters/family/mom/"
      turns_remaining: 3
      
    - id: letter-002
      from: "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 simulation
def deliver_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'] -= 1
        
        if 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: express
    
  postage:
    base_cost: 5             # Express premium
    guaranteed_time: 1       # Arrives next turn
    tracking: true           # Can check status
    insurance: true          # Compensated if lost

Lost Mail (Optional Mechanic)

For added realism/drama:

postal:
  settings:
    loss_chance: 0.01        # 1% chance of loss
    loss_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.

Routing Instructions

letter:
  from: "characters/family/mom/"
  to: "player"
  
  # Generated routing (deterministic)
  routing:
    destination_type: player
    destination_path: player
    delivery_point: inbox
    inbox_path: player/INBOX.yml
    
    attachments_transfer:
      - type: object
        ref: "brass-key"
        action: send
        from_inventory: "characters/family/mom/"
        to_inventory: "player"
        
    triggers:
      - event: MESSAGE_RECEIVED
        data: { from: "characters/family/mom/" }
      - event: GOAL_CREATED
        data: { goal_id: find-key }

Simulation Phase

Mail delivery is a phase in the simulation tick:

1. RESET     — foo_effective = foo
2. BUFFS     — Apply modifiers
3. SIMULATE  — Objects run
4. MAIL      — Deliver queued messages (deterministic!)
5. EVENTS    — Process queue
6. NAVIGATE  — Move player
7. DISPLAY   — Update UI

Storage Integration

Mail items to your vault:

letter:
  from: "player"
  to: "storage/vault/"
  subject: "Depositing treasure"
  
  attachments:
    - type: gold
      quantity: 500
      action: send

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

FactorioMOOLLM
Logistics botsPostal system (free, instant)
Flying between chestsEmail/text delivery
Request listTriggers automated mail
Active provider pushingAuto-send attachments
Circuit signalsText notifications

How It Works

When a logistics requester needs items, instead of dispatching a bot:

# Automatic postal delivery for logistics
logistics_delivery:
  trigger: "requester.request_unfulfilled"
  
  # Find a provider with matching items
  provider: "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, instant
    from: "nw/iron-ore/"
    to: "forge/"
    attachments:
      - type: object
        ref: "iron-ore"
        quantity: 20
        action: send
        
    # No delivery time for internal logistics!
    delivery:
      method: logistics         # New method: instant, free
      total_time: 0
      cost: 0

Logistics Delivery Methods

MethodTimeCostUse Case
logistics0FreeInternal network transfers
text0FreeSignals, notifications
letter3+ turns1+ goldPlayer-to-player with drama
freight10+ turnsPer weightPhysical 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: image
      action: generate
      prompt: "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 fuel
room:
  signals:
    enabled: true
    emit:
      - 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
    # OR
    method: 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 BotsPostal Transport
Slow (travel time)Instant
Visible (might break immersion)Invisible (just works)
Can get stuckNever fails
Limited cargoUnlimited
Fun to watchEfficient

Use bots for drama. Use postal for efficiency.


Commands

CommandEffect
CHECK PHONESee notifications and quick access
READ MAILOpen inbox
READ [letter]Display letter
COMPOSEStart writing
REPLYReply to current
ATTACH [item]Add attachment
SENDSend current message
TEXT [character]Quick text

Mom as a Character

Mom isn't special infrastructure — she's just a character:

# characters/family/mom/CHARACTER.yml
character:
  id: mom
  name: "Mom"
  type: correspondent
  
  personality:
    warmth: 10
    worry: 7
    pride: 9
    
  voice:
    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

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

self-repair

No summary provided by upstream source.

Repository SourceNeeds Review
General

dog

No summary provided by upstream source.

Repository SourceNeeds Review
General

persona

No summary provided by upstream source.

Repository SourceNeeds Review
General

probability

No summary provided by upstream source.

Repository SourceNeeds Review