Nathan King86 downloadsA vault-scoped writing companion that lives in your sidebar — hatches an ASCII pet per vault and reacts to how you write.
A vault-scoped writing companion for Obsidian. Bestest Buddy hatches a persistent ASCII pet for each vault, watches how you write, and reacts with short, in-context observations — a companion that lives in your sidebar, not a chatbot you converse with.
It is built around three principles:
.----.
/ × × \ Capy Scribbles
| -- | Common Capybara
`-____-´
Each vault gets its own generated buddy with persistent traits:
· ✦ × ◉ @ °GRAMMARING, PATIENCE, CHAOS, WISDOM, SNARKThe buddy is derived deterministically from the vault seed, so it stays stable until reset.
Rarity is rolled by weight, so most buddies are common and a mythic is genuinely rare:
| Rarity | Weight | Notes |
|---|---|---|
| Common | 60 | |
| Uncommon | 25 | |
| Rare | 10 | |
| Epic | 4 | |
| Legendary | 1 | |
| Mythic | 0.1 | Animated rainbow sprite, background, and nameplate |
A dedicated right-sidebar view that opens automatically when the workspace is ready. It includes:
Enable Minimal mode to show only the sprite.
The pet is alive in the panel:
When enabled and not muted, the buddy occasionally reacts to vault activity: opening a daily note, creating a note, writing in a burst, sustaining a session, making a large revision cut, pausing, or returning after a pause. Reactions are deliberately selective — gated by cooldown, probability, session state, and your snark level — so they punctuate rather than interrupt.
Send the buddy a message from the panel, or use the command to ask about the current note. Replies are short, grounded in the buddy's personality and session state, and — when note context is enabled — informed by your current selection (or the full note if nothing is selected).
The plugin keeps a lightweight model of your session:
These influence the UI hints and the likelihood and tone of reactions.
Bestest Buddy is not yet in the community plugin directory, so install it manually.
1. Build it:
npm install
npm run build
2. Copy the build artifacts into your vault's plugin folder (id is bestest-buddy):
VAULT="/path/to/your/vault"
mkdir -p "$VAULT/.obsidian/plugins/bestest-buddy"
cp main.js manifest.json styles.css \
"$VAULT/.obsidian/plugins/bestest-buddy/"
Only those three files are needed — do not copy src/ or node_modules/.
3. Enable it: Obsidian → Settings → Community plugins → enable Bestest Buddy.
Updating an existing install? Obsidian doesn't hot-reload plugin files. After copying a new
main.js, toggle the plugin off/on or reload Obsidian (Cmd/Ctrl+R).
Requires Obsidian 1.5.0+. Works on desktop and mobile (isDesktopOnly: false).
All commands are available from the command palette under Bestest Buddy. A sparkles ribbon icon also opens the panel.
| Command | Action |
|---|---|
| Open panel | Reveal the sidebar view |
| Pet buddy | Trigger the petting animation and a reaction |
| Ask buddy about current note | Generate an observation about the active note |
| Mute / Unmute ambient reactions | Toggle automatic reactions |
| Reset buddy | New vault seed; clears companion, events, mood, session |
| Customize: choose species / eye style / hat / rarity / color | Override a generated trait |
| Customize: edit stats | Manually set stat values |
| Customize: toggle shiny | Toggle the shiny flag |
| Customize: reset appearance to generated | Clear all appearance overrides |
| Setting | Default | Description |
|---|---|---|
| LLM provider | OpenAI | OpenAI or Claude (Anthropic) |
| OpenAI API key | — | Used when provider is OpenAI (masked input) |
| Claude API key | — | Used when provider is Claude (masked input) |
| Model | gpt-4.1-mini |
Model name for the selected provider (e.g. gpt-4.1-mini, claude-haiku-4-5-20251001) |
| Ambient reactions | on | Allow the buddy to react to note activity |
| Reaction frequency | Normal | Quiet, Normal, or Chatty |
| Writing burst threshold | 50 | New words that trigger a writing-burst reaction (minimum 10) |
| Include current note context | on | Pass note title and excerpt to replies |
| Minimal mode | off | Show only the sprite in the panel |
| Snark level | 50 | 0 = rare and gentle, 100 = constant and merciless. Values above 90 can use significantly more tokens. |
The plugin listens to workspace and editor activity and records buddy events:
session_started, note_opened, new_note_created, writing_burst, steady_session, revision_spike, long_pause, returned_after_pause, daily_note_opened, direct_question, pet, manual_note_help_request, chatty_tick.
Writing-related events are inferred from editing behavior:
An ambient reaction only fires when all of these hold: a buddy exists, ambient reactions are enabled, the plugin is not muted, the cooldown has expired, the event type is reaction-eligible, and a probability roll passes. The cooldown and probability are modulated by reaction frequency, current session mode, detected patterns, and snark level.
When frequency is set to Chatty, a periodic chatty tick lets the buddy comment on the text near your cursor during active writing (subject to its own cooldown).
The buddy uses an LLM for two jobs: generating its name and personality at hatch time, and generating short reactions and direct replies.
| Provider | Endpoint | Example model |
|---|---|---|
| OpenAI | https://api.openai.com/v1/responses |
gpt-4.1-mini |
| Claude (Anthropic) | https://api.anthropic.com/v1/messages |
claude-haiku-4-5-20251001 |
Fallbacks: if no API key is configured or a request fails, hatching falls back to local name/personality generation and reactions fall back to local rule-based text. The plugin remains fully functional without any API key — responses are just less varied.
Beyond the generated buddy, you can override any visible trait via the Customize commands: species, eye style, hat, rarity, sprite color (presets or a custom #rrggbb hex), shiny, and individual stats. Overrides are stored separately from the generated companion, so Customize: reset appearance to generated restores the original at any time.
data.json): vault seed, hatched companion, appearance overrides, mute state, recent events (most recent 20), mood and session state, and your settings..obsidian data accordingly.These limits are intentional:
npm install
npm run dev # esbuild watch build
npm run build # production build
npm run typecheck # tsc --noEmit
npm test # vitest (unit tests)
The plugin is written in TypeScript and bundled with esbuild into main.js. The distributable consists of main.js, manifest.json, and styles.css.
Unit tests live in tests/ (vitest) and cover the pure generation and sprite logic. CI (.github/workflows/ci.yml) runs typecheck, tests, and build on every push and PR; tagging a commit X.Y.Z triggers release.yml to build and attach the release artifacts.
bestest-buddy/
├─ manifest.json plugin manifest (id, version, minAppVersion)
├─ versions.json plugin version → minimum app version map
├─ esbuild.config.mjs build configuration
├─ styles.css panel and sprite styling (incl. mythic animations)
├─ main.js bundled output (committed; also attached to releases)
├─ tests/ vitest unit tests
└─ src/
├─ main.ts plugin entry: lifecycle, commands, reaction logic
├─ view.ts sidebar panel rendering
├─ events.ts workspace/editor event detection
├─ store.ts persistence and companion state
├─ settings.ts settings tab
├─ customize.ts customization modals
├─ llm.ts OpenAI/Claude calls, prompts, local fallbacks
├─ constants.ts defaults and view type
├─ types.ts plugin/data/settings types
└─ lib/buddy/
├─ companion.ts seeded generation and rarity/stat rolls
├─ sprites.ts ASCII sprite frames per species
├─ reactions.ts local reaction text
└─ types.ts species, rarities, hats, eyes, stats
Author: Nathan King.
With thanks to Owen McGrath, a valued contributor.
Licensed under the MIT License — see LICENSE.