simhacker/moollm

subjective

First-person code — the "I" shifts based on who is speaking

First seen Jan 26, 2026

Installation

$ npx skills add simhacker/moollm --skill subjective

Also in this package

Other skills from simhacker/moollm · top by installs.

npx skills add simhacker/moollm

Browse all from simhacker/moollm

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Also listed on

Alternate registries and mirrors of this skill.

Repository health

Stars 52
License LICENSE
Default branch main
Open issues 1
Status Active

Skill metadata

Parsed from SKILL.md frontmatter.

Allowed toolsread_file, write_file

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 8,538 B
  • docs README.md 937 B
  • docs SUMMARY.md 79 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 14 installs

SKILL.md

Subjective-Oriented Programming

"i_have('key') reads naturally. 'Does the world have a key?' does not."
— The Gezelligheid Grotto Design Principles


What Is It?

Subjective-oriented programming uses i_ prefixed functions that speak from the current subject's perspective. The "I" shifts based on context:

Context Who is "I"?
Player action The player character
Object simulate() The object
NPC dialogue The NPC
Room description The room

The Problem with world.

// Third-person: "Does the world have a key?"
if (world.has("key")) ...

// But who has the key? The world? The player? Confusing!

The Solution: i_

// First-person: "Do I have a key?"
if (i_have("key")) ...

// Clear! The current subject is asking about themselves.

Core i_ Functions

Inventory

i_have("key")           // Do I have this item?
i_give("key")           // Give item to current target
i_take("key")           // Take item from current target
i_drop("key")           // Drop item in current room
i_has_tag("weapon")     // Do I have any item with this tag?
i_find_by_tag("food")   // Find all my items with this tag

State

i_am("lit")             // Am I in this state? (object.state.lit)
i_am_not("broken")      // Am I NOT in this state?
i_set("lit", true)      // Set my state
i_get("fuel")           // Get my state value

Buffs

i_have_buff("strength")     // Do I have this buff?
i_add_buff(buff)            // Apply buff to myself
i_remove_buff("strength")   // Remove buff from myself

Flags

i_flag("door_unlocked")     // Is this flag set?
i_set_flag("door_unlocked") // Set this flag

Location

i_am_in("pub/")             // Am I in this room?
i_can_see("treasure")       // Can I see this object?
i_go("north")               // Move in direction

Communication

i_say("Hello!")             // Emit dialogue
i_emote("grins widely")     // Emit emote
i_think("This is odd...")   // Emit internal thought

Context Shifting

The meaning of i_ changes based on who is "speaking":

Player Context

# In player action handlers
effect: |
  if i_have("key"):
    i_say("I found the key!")
    i_drop("key")  # Drop in current room

Object Context (simulate)

# In object's simulate field
simulate: |
  if i_am("lit"):
    i_set("fuel", i_get("fuel") - 1)
    if i_get("fuel") <= 0:
      i_set("lit", false)
      i_emit("The lamp dies!")

NPC Context

# In NPC dialogue/behavior
behavior: |
  if i_have("gold") and i_can_see("beggar"):
    i_give("gold")
    i_say("For you, friend.")

Room Context

# In room description/behavior
describe: |
  if i_am("dark"):
    i_emit("You can't see anything.")
  else:
    i_emit("A cozy room with a fireplace.")

Implementation

The i_ functions are bound to the current subject:

class World {
  // The current subject ("I")
  get subject() {
    return this.object || this.npc || this.player;
  }
  
  // === INVENTORY (subjective) ===
  
  i_have(itemId) {
    const inv = this.subject.inventory || [];
    return inv.includes(itemId);
  }
  
  i_give(itemId) {
    const inv = this.subject.inventory || [];
    const idx = inv.indexOf(itemId);
    if (idx > -1) {
      inv.splice(idx, 1);
      (this.target.inventory ??= []).push(itemId);
    }
  }
  
  i_take(itemId) {
    const targetInv = this.target.inventory || [];
    const idx = targetInv.indexOf(itemId);
    if (idx > -1) {
      targetInv.splice(idx, 1);
      (this.subject.inventory ??= []).push(itemId);
    }
  }
  
  i_drop(itemId) {
    const inv = this.subject.inventory || [];
    const idx = inv.indexOf(itemId);
    if (idx > -1) {
      inv.splice(idx, 1);
      (this.room.objects ??= []).push({ id: itemId });
    }
  }
  
  i_has_tag(tag) {
    const inv = this.subject.inventory || [];
    for (const itemId of inv) {
      const item = this.getObject(itemId);
      if (item && (item.tags || []).includes(tag)) {
        return true;
      }
    }
    return false;
  }
  
  // === STATE (subjective) ===
  
  i_am(stateKey) {
    return this.subject.state?.[stateKey] === true;
  }
  
  i_am_not(stateKey) {
    return !this.i_am(stateKey);
  }
  
  i_get(stateKey) {
    return this.subject.state?.[stateKey];
  }
  
  i_set(stateKey, value) {
    this.subject.state ??= {};
    this.subject.state[stateKey] = value;
  }
  
  // === BUFFS (subjective) ===
  
  i_have_buff(buffId) {
    const buffs = this.subject.buffs || [];
    return buffs.some(b => b.id === buffId);
  }
  
  i_add_buff(buff) {
    this.subject.buffs ??= [];
    this.subject.buffs.push(buff);
  }
  
  i_remove_buff(buffId) {
    const buffs = this.subject.buffs || [];
    this.subject.buffs = buffs.filter(b => b.id !== buffId);
  }
  
  // === LOCATION (subjective) ===
  
  i_am_in(roomPath) {
    return this.subject.location === roomPath ||
           this.room?.path === roomPath;
  }
  
  i_can_see(objectId) {
    const objects = this.room?.objects || [];
    return objects.some(o => o.id === objectId);
  }
  
  i_go(direction) {
    this._pendingNavigation = direction;
  }
  
  // === COMMUNICATION (subjective) ===
  
  i_say(message) {
    this.emit(`${this.subject.name}: "${message}"`);
  }
  
  i_emote(action) {
    this.emit(`${this.subject.name} ${action}`);
  }
  
  i_think(thought) {
    this.emit(`(${this.subject.name} thinks: "${thought}")`);
  }
  
  i_emit(message) {
    this.emit(message);
  }
}

Python Equivalent

class World:
    @property
    def subject(self):
        """The current 'I' — object, NPC, or player."""
        return self.object or self.npc or self.player
    
    def i_have(self, item_id: str) -> bool:
        inv = self.subject.get('inventory', [])
        return item_id in inv
    
    def i_am(self, state_key: str) -> bool:
        return self.subject.get('state', {}).get(state_key) == True
    
    def i_get(self, state_key: str):
        return self.subject.get('state', {}).get(state_key)
    
    def i_set(self, state_key: str, value):
        state = self.subject.setdefault('state', {})
        state[state_key] = value
    
    def i_say(self, message: str):
        self.emit(f"{self.subject.get('name')}: \"{message}\"")
    
    def i_emit(self, message: str):
        self.emit(message)
    
    # ... etc

Natural Language Compilation

The LLM compiles natural language to i_ calls:

# Natural language
guard: "I have the key and I am not cursed"

# Compiled
guard_js: (world) => world.i_have("key") && !world.i_have_buff("cursed")
guard_py: lambda world: world.i_have("key") and not world.i_have_buff("cursed")
# Natural language (object context)
simulate: |
  if I am lit and fuel > 0:
    consume 1 fuel
    if fuel reaches 0:
      I am no longer lit
      say "The lamp dies!"

# Compiled
simulate_js: (world) => {
  if (world.i_am("lit") && world.i_get("fuel") > 0) {
    world.i_set("fuel", world.i_get("fuel") - 1);
    if (world.i_get("fuel") <= 0) {
      world.i_set("lit", false);
      world.i_emit("The lamp dies!");
    }
  }
}

The i_ vs world. Split

Use i_ when... Use world. when...
Acting as current subject Accessing global state
Checking own inventory Checking adventure flags
Modifying own state Navigating rooms
Speaking in first person Managing party
// Mixed example
if (i_have("key") && world.flag("door_visible")) {
  i_say("I can unlock this door!");
  world.set_flag("door_unlocked", true);
}

Benefits

  1. Readable — i_have("key") reads like English
  2. Context-aware — "I" shifts naturally
  3. Object-oriented — Objects think for themselves
  4. Compilable — LLM can translate natural language easily
  5. Debuggable — Clear who is speaking in logs

Protocol Symbol

SUBJECTIVE-ORIENTED — The "I" shifts based on who is speaking