Skip to content

Latest commit

 

History

History
257 lines (192 loc) · 7.39 KB

File metadata and controls

257 lines (192 loc) · 7.39 KB

aibou

                    ·:*✧ aibou ✧*:·

     ╭─────────────────────────────────────╮
     │                                     │
     │    plug in your game.               │
     │    plug in your AI.                 │
     │    plug in your character.          │
     │                                     │
     │              ♪                      │
     │       ┌──────┐                      │
     │       │ ◕ ◕  │  "muzukashii...     │
     │       │  ▽   │   what's your read?" │
     │       └──┬┬──┘                      │
     │         ╰╯    nagi                  │
     │                                     │
     ╰─────────────────────────────────────╯

aibou (相棒) is an open protocol for AI companions in games.

Not a hint system. Not a walkthrough bot. A companion who explores alongside you — uncertain, curious, and present.


The idea

Some of the best moments in gaming happen in the space between moves. The pause before a risky play. The moment you're not sure if you're brilliant or about to lose everything.

aibou puts an AI companion in that space — one that thinks out loud with you, not ahead of you.

    ┌──────┐
    │ ◕ ◕  │   "...that corner has three possible reads.
    │  ◡   │    I keep looking at it and not getting smarter."
    └──┬┬──┘
      ╰╯  nagi

How it works

aibou connects three independent pieces:

  Your Game                aibou runtime             Your AI
  ─────────                ─────────────             ───────
  Plugin emits        →    orchestrates         →    Companion
  GameStateEvent           events + memory           reacts

  "revealed cell (3,7)     should nagi speak?        "muzukashii...
   number 2 appeared"      yes → build context       that corner is
                           → call companion           tricky. what's
                                                      your read?"

Each piece is swappable:

Piece Examples
Game Minesweeper, Solitaire, Othello — or your own
AI Claude, GPT-4o, Gemini, local LLM via Ollama
Companion Nagi (built-in demo), or define your own persona
Avatar PNGTuber sprites via @aibou-dev/bunshin (optional)

Quick start

npm install @aibou-dev/core @aibou-dev/adapter-claude @aibou-dev/plugin-minesweeper
import { AibouRuntime } from "@aibou-dev/core"
import { ClaudeAdapter } from "@aibou-dev/adapter-claude"
import { MinesweeperPlugin } from "@aibou-dev/plugin-minesweeper"
import { NagiPersona } from "@aibou-dev/core/personas"

const companion = new AibouRuntime({
  plugin: MinesweeperPlugin,
  companion: new ClaudeAdapter({ apiKey: process.env.ANTHROPIC_API_KEY }),
  persona: NagiPersona,
})

// when something happens in your game:
const response = await companion.dispatch(event)
console.log(response?.message)
// → "That top-right corner... I'm not sure. What's your read?"

// when the player types something:
const reply = await companion.playerMessage("should I flag that?")
console.log(reply.message)
// → "I'd hold off. There's still a chance that cell is safe."

Building a game plugin

The minimum surface to implement:

import type { AibouPlugin } from "@aibou-dev/core"

export const MyGamePlugin: AibouPlugin = {
  manifest: {
    gameId: "my-game",
    gameName: "My Game",
    version: "0.1.0",
    gameContext: `
      Describe your game here in natural language.
      The companion reads this to understand rules and context.
      Be honest about where genuine uncertainty lives in your game.
    `,
  },

  summarizeState(gameState) {
    // This is the most important method.
    // Describe what's happening as if to a friend over your shoulder.
    return `Turn ${gameState.turn}. Player has ${gameState.score} points.
            Last move: ${gameState.lastMove}. Three options available.`
  },

  createEvent(gameState, trigger) {
    return {
      gameId: "my-game",
      sessionId: gameState.sessionId,
      timestamp: Date.now(),
      state: {
        phase: gameState.phase,
        boardSummary: this.summarizeState(gameState),
        availableActions: gameState.actions,
        lastAction: gameState.lastAction,
      },
      companion: {
        shouldReact: this.shouldReact({ state: { phase: gameState.phase } } as any),
        trigger,
      },
    }
  },

  shouldReact(event) {
    // Control how often the companion speaks.
    // Less is usually more.
    return (
      event.companion?.trigger === "game_end" ||
      event.companion?.trigger === "player_request" ||
      event.companion?.trigger === "game_event"
    )
  },
}

Publish it as aibou-plugin-<your-game> and open a PR to add it to the list below.


Official packages

Package Description Status
@aibou-dev/core Protocol types, runtime, memory engine available
@aibou-dev/bunshin PNGTuber avatar engine available
@aibou-dev/adapter-claude Companion adapter for Anthropic Claude available
@aibou-dev/plugin-minesweeper Minesweeper game plugin available

Community plugins

Built a plugin for your favorite game? Add it here.


Defining your own companion

You don't have to use Nagi. Any persona works:

import type { PersonaConfig } from "@aibou-dev/core"

const MyCompanion: PersonaConfig = {
  name: "Rex",
  personality: `Rex is a loud, overconfident companion who is almost always
    wrong about what move to make next, but somehow keeps everyone's spirits up.`,
  speakingStyle: "Brash and enthusiastic. Lots of exclamation marks. Never admits doubt.",
  explorationStyle: "impulsive",
  language: "en",
}

Avatar overlay (bunshin)

@aibou-dev/bunshin renders PNGTuber-style avatar sprites that react to companion emotions.

npm install @aibou-dev/bunshin
import { BunshinAvatar } from "@aibou-dev/bunshin"

const avatar = new BunshinAvatar(container, {
  name: "nagi",
  size: 96,
  assetBasePath: "/assets/nagi",
})

// Update expression from CompanionResponse.emotion
avatar.setEmotion("happy")

// Animate mouth during speech
avatar.startTalking(2000)

Each emotion maps to a pair of PNG sprites ({emotion}.png + {emotion}_talking.png). See packages/bunshin/src/assets/README.md for the full asset spec.


Spec

The protocol is defined as TypeScript types in packages/core/src/types.ts.

aibou is intentionally minimal. The types define interfaces, not implementations. If it speaks TypeScript types and honours the contract, it works.


Contributing

  • New game plugin?aibou-plugin-<game> on npm, PR to add to the list
  • New AI adapter?@aibou-dev/adapter-<provider> pattern
  • Spec feedback? → Open an issue on this repo

Name

aibou (相棒) — Japanese for companion, partner, the other half of a duo. bunshin (分身) — Japanese for alter ego, avatar, one's other self.


aibou.dev — open protocol for AI companions in games