Vibed

by Roman
5
4
3
2
1
Score: 50/100

Description

Reviews

No reviews yet.

Stats

4
stars
133
downloads
0
forks
31
days
1
days
1
days
1
total PRs
0
open PRs
0
closed PRs
1
merged PRs
0
total issues
0
open issues
0
closed issues
55
commits

README file from

Github

Vibed (Obsidian plugin)

Install from the Obsidian community directory: https://community.obsidian.md/plugins/vibed

An agent-session browser for Obsidian. Browse your OpenCode v2 sessions directly in Obsidian — as a dedicated view or as dashboards embedded in any note — then open any session and watch it stream in real time, send follow-up prompts, and interrupt runs.

Since v0.9 the plugin is multi-backend: alongside interactive OpenCode v2 connectors (local or remote), you can add read-only connectors for OpenCode v1, Claude Code, Codex CLI, and Cursor Agent histories. OpenCode v2 remains the first-class citizen; everything else is a read-only companion.

A session dashboard embedded in a note: live session card with a Running… badge, filter, and refresh

version Obsidian community plugin

Connectors

Connectors are named backend instances — add as many as you like in settings (two remote OpenCode servers, three Codex installs, …). The first connector is created for you: the local OpenCode v2 one (opencode, zero-config).

kind default name source mode
OpenCode v2 opencode, opencode-2, … ~/.local/share/opencode/opencode.db + v2 server API interactive: live SSE, prompt/stop, approvals, models, new sessions
OpenCode v1 opencode-v1, … legacy session/message/part tables in the same DB read-only, historical
Claude Code claude, claude-2, … ~/.claude/projects/<slug>/<uuid>.jsonl read-only transcripts
Codex CLI codex, codex-2, … ~/.codex/sessions/**/rollout-*.jsonl (+ .zst via zstd) read-only transcripts
Cursor Agent cursor, cursor-2, … ~/.cursor/projects/*/agent-transcripts/<uuid>/*.jsonl read-only transcripts

Names are editable and unique; a second connector of a kind auto-names <base>-2, -3, … One connector is the default (used by dashboards and chats that don't name one) — pick it in settings.

OpenCode v2 connector modes

  • Local hybrid (default): SQLite session_v2 listing (works when the server is down) + auto-discovered local server (~/.local/state/opencode/ service.json) for live streaming and chat.
  • API-only: untick Use local database — listing comes from GET /api/session.
  • Remote: set a Server URL override (and password). The override is authoritative — no silent fallback to a local server. Pair with API-only listing, or point at a reachable DB path for hybrid mode. API listing pages the server's /api/session (cursor-based, like the TUI) and filters client-side, so /* subtrees work — but dirs entries must be absolute: ~ can't be resolved against a remote server and surfaces an error in the dashboard instead.

Backend caveats

titles per-message time tokens cost tool outputs
OpenCode v2/v1 stored ✓ ✓ ✓ ✓
Claude Code ai-title ✓ summed on open (incl. cache) ✖ ✓
Codex first prompt ✓ cumulative totals ✖ ✓ (incl. apply_patch)
Cursor first prompt ✖ (file mtime only) ✖ ✖ ✖ (never recorded)

Claude/Cursor project folders encode the directory path lossily (non-alphanumerics → -); configured Directories entries disambiguate. Transcripts refresh on the plugin's interval; open chats poll every few seconds. Very large transcripts (>128 MB) are refused with a clear message.

Features

  • Note-embedded dashboards via a vibed code block (cards or table layout) — no other plugins required. Compact icon toolbar (filter, copy-as-block, refresh, new session) that keeps the top-right corner free for Obsidian's block-edit button; a filter that matches nothing leaves a one-card-tall empty state with a Clear filter escape hatch instead of collapsing the widget.
  • Block authoring support: a command palette form that inserts a new block (with live preview), autocomplete inside every vibed fence, and Copy as vibed block on dashboard toolbars. See Authoring dashboards.
  • Embedded agent reference: one command writes/updates an AGENTS.md cheatsheet for AI sessions into any vault folder — vaults never hand-maintain their own copy.
  • Dedicated view (command palette: Open OpenCode sessions, or the ribbon icon).
  • Live state tracking from the v2 event stream (GET /api/event): Running…, Idle, Needs approval, Needs answer, Interrupted, Error — updated the instant they change. Falls back to SQLite heuristics when the server is unreachable.
  • Subsessions (task-tool subagents): subagent sessions never clutter the list — they nest under their parent's card. A parent waiting on running subagents gets a Subagents running state (derived — OpenCode reports parent and child both as plain "running"), and the card lists its subsessions: active ones by default, all via the expand toggle. Table layout nests the same strip in a sub-row. Opening a subsession chat shows a subsession chip in the header that links back to the main session.
  • Session chat view: messages stream in live (text + reasoning + tool calls with input/output); history loads the newest page first and pages in older messages as you scroll to the top. Works for every connector (read-only ones simply don't stream).
  • Jump to latest: scroll up and a floating button appears above the composer; it counts the messages that arrived while you were away and snaps back to the newest message on click. Sending always jumps back down.
  • Slash commands: type / in the composer to get the TUI's command menu — filter by name, ↑/↓ to move, Tab/Enter to complete (an exact name sends right away). Commands run server-side via the command endpoint with arguments, multi-line included; unknown /names are sent as plain prompts, like the TUI.
  • Session environment popup: a header button shows what the server provides for the session's directory — MCP servers with live statuses (connect/disconnect inline, errors shown), slash commands, and skills. Same picture as the TUI sidebar, one Refresh away.
  • Find in chat: Ctrl+F / Cmd+F opens a browser-style find bar over the transcript — live match count, all-matches highlighting, Enter/Shift+Enter (also F3, Cmd/Ctrl+G) to navigate with wrap-around, Aa toggles case sensitivity, Esc closes and restores focus. Searches exactly what's on screen: collapsed Thinking / tool Input / Output sections are skipped until you expand them (expanding re-runs the search live), and streaming or newly paged-in messages refresh the results automatically.
  • Prompt & stop: send messages to a session and interrupt a running one right from the composer (OpenCode v2 connectors).
  • New sessions: the New OpenCode session command picks one of your configured directories and starts a draft chat; the server session is created with your first message. Each directory card carries a ⋮ menu with the working-directory actions — copy path, open in the file manager, open in a terminal — so you can inspect a candidate before picking it.
  • Snippet session config: a vibed block can configure the sessions it starts — model/agent/permissions/environment per session, plus skills, mcp, commands, agents, providers, references as the desired config of the working directory. Matching config starts silently; a diff opens a dialogue to install (config merge + skill installers) or proceed as-is. See Snippet session config.
  • Chat header menu: the chat's ⋮ button gathers Copy ID and Refresh plus the same working-directory actions for the session's own directory.
  • Model selector: defaults match OpenCode exactly — the last-used model and its persisted variant, falling back to the server's location-aware default; existing sessions switch live.
  • Agent selector: pick the session's agent (e.g. build, plan, custom agents) next to the model selector; hidden and subagent-only entries are filtered out, descriptions show on hover, and existing sessions switch live (drafts apply the choice at creation).
  • Approvals: permission banners with Allow / Always allow / Reject, synced with replies made anywhere (TUI, other tabs).
  • Agent questions: answer the agent's question tool inline — options (single/multi-select), yes/no, or custom text — or dismiss it; synced with answers made anywhere. Surfaced through the v2 form API.
  • Offline fallback: when the server is down, v2 chats show the conversation read-only from session_v2/session_message.
  • Session notes: attach a markdown note to any session (every connector) — a side panel in the chat view with autosave, backed by a normal vault file found by session: frontmatter, not filename. See Session notes.
  • Session tags: note tags (Obsidian semantics — frontmatter tags: + inline #tags) become session tags — editable in the notes panel, shown on cards, filterable (#tag in the filter, an advanced filter popover, and a tags: widget option). See Session tags & filtering.
  • Also exposes an API (globalThis.vibed) for e.g. Datacore JSX consumers.

Screenshots

Live chat with streaming — messages, reasoning, and tool calls appear as they happen; the composer can send follow-ups or stop a running turn:

Session chat view streaming a reply: thinking blocks, tool calls with input/output, model picker in the composer

Approvals in-app — permission requests show up as a banner; allow, always allow, or reject without leaving the note:

Session chat with a Needs approval banner and Reject / Always allow / Allow buttons

New sessions — pick one of your configured directories; the server session is created with your first message:

New OpenCode session dialog with working-directory cards

Authoring dashboards

Three ways to never memorize the block syntax:

  • Insert — command palette: Insert session dashboard block. A form (connector, layout, directories, tags, pinned session ids, page size, title, advanced session-config fields) composes the block and inserts it at the cursor. A live preview shows the exact block text as you type — the fastest way to learn the keys is to watch them appear.
  • Autocomplete — inside every vibed fence: key names with one-line docs, connector: names from your settings, layout: values, and - items under dirs: from the connector's configured directories.
  • Copy as block — the clipboard icon on any dashboard toolbar serializes the block's config plus the active filter back into a vibed block. Filter criteria the DSL can't express (is:, dir:, model:, free text) ride along as a # filter: … comment.

For AI sessions editing the vault, Save AI agent reference (AGENTS.md) writes or updates a managed <!-- vibed:begin/end --> section with the full block reference into any folder — re-runs replace only the managed section, never your own content.

Embed in a note

A vibed code block renders a dashboard inside any note. The config is simple key: value lines (or a JSON object).

Session list — a directory dashboard, one card per session:

```vibed
connector: claude
layout: cards
basedir: ~/
dirs:
  - projects/my-project
```

Single session — pin one session id and the block renders a clean widget: just the card, no toolbar (ideal for a project status note):

```vibed
sessions:
  - ses_abc123def456
```

A missing id renders as a dashed "(not found)" card rather than an error.

Options (simple key: value lines or a JSON object):

Option Default Description
connector default connector Connector name (e.g. claude, codex-2). Unknown names render an inline error.
dirs connector setting Directories to list sessions for. Relative entries resolve against basedir; ~/… expands to your home folder (local-access listings only — API-only remote connectors reject it with a dashboard error); an entry ending in /* matches the whole subtree (the entry's directory plus everything beneath it) in every listing mode — plain entries match the session's working directory exactly. On OpenCode connectors this overrides the connector's configured directories; on Claude/Codex/Cursor it adds to them (a filter).
sessions – Explicit session ids (list). With only sessions the block renders a clean widget: just the cards, no toolbar. Missing ids render as dashed "(not found)" cards.
basedir – Prefix for relative dirs; cards/tables show directories relative to it.
tags – Only sessions whose note carries all of these tags (list or comma string; intersected with dirs).
layout cards cards or table.
pageSize plugin setting Sessions per page.
title – Optional heading above the dashboard.
config keys – model, agent, permissions, environment (per session) and skills, mcp, commands, agents, providers, references, default_agent (desired directory config) — see Snippet session config.

Click a card (or table row) to open the live chat view; click a session ID to copy it. Sessions with an attached note show a sticky-note button on their card / title cell — click it to open the note file. Tagged sessions show tag chips next to the session ID — click one to filter by it.

Snippet session config

A block can also configure the sessions it starts. Two key groups:

  • Ephemeral — model (provider/model[#variant]), agent, permissions, environment: applied to every session created from the block. Model and agent prefill the draft's selectors (you can still change them); permissions and environment ride on session creation. Never gated, never written to disk.
  • Root state — skills, mcp, commands, agents, providers, references, default_agent: the desired OpenCode config of the working directory. At session-start time (your first message) vibed diffs them against the directory's live config — a match starts silently; a diff opens a dialogue showing what's missing, with Install & start (merge into .opencode/opencode.json, run skill installers, reload the server config) or Proceed as-is. The dialogue re-appears on every start while a diff exists — nothing about your choice is remembered.
```vibed
connector: opencode
dirs:
  - ~/spaces/my-project
model: zai/glm-5.3
agent: build
mcp: {"kangram": {"type": "remote", "url": "https://kangram.app/mcp"}}
skills:
  - ./skills/analysis
  - {"id": "deep-research", "install": "npx skills add owner/repo"}
```

Notes:

  • Install writes exactly two files in the target directory: .opencode/opencode.json — deep-merged, user keys never deleted, with an x-vibed marker tracking what vibed placed — and .opencode/vibed.json, a manifest remembering which skills each install command produced (that is how already-installed skills stay silent). Config files that cannot be parsed (JSONC) are left alone with a clear message.
  • The dialogue never renders values read from your live config — they can contain API keys. Only key paths, change kinds, and the snippet's own declared values are shown. Don't put secrets in snippets; use OpenCode's {env:VAR} substitution instead.
  • Skill installs are shell commands run in the working directory (npx skills add owner/repo, …). Without a declared id, the first consented install learns what the command produced; an edited command re-asks. Closing the dialogue mid-install never kills a running installer.
  • Install requires a local OpenCode server. Remote connectors show the diff but can only proceed as-is.

Linking to sessions

Markdown links open the chat tab for a session:

[Yesterday's refactor](obsidian://vibed?sessionId=ses_abc123)
[A claude session](obsidian://vibed?connector=claude&sessionId=<uuid>)

opencode-v1:<id>-style prefixed ids also work in Open session by ID (and in api.open("claude:<uuid>")). Bare ids resolve against the default connector.

Session notes

Every session chat has a notes toggle (the sticky-note button in the header). It opens a side panel next to the transcript: click Create note and type — edits autosave (600 ms debounce); Open in editor hands the note to the normal markdown editor. Notes work for all connectors, including the read-only ones.

Notes are ordinary vault files. The attachment is a frontmatter id — never the filename — so you can rename or move them anywhere in the vault and they stay attached (the plugin looks them up through Obsidian's metadata cache):

---
session: ses_abc123def456
connector: opencode
title: "Refactor the export pipeline"
created: 2026-09-09T12:00:00.000Z
---

Context, decisions, follow-ups…

By default notes are created in vibed-notes/ at the vault root as <session-id>-<title>.md — change the folder in Settings → General → Session notes folder. The panel hides the frontmatter (but preserves it and any properties you add on save). Editing the note elsewhere syncs back into an open panel; a note whose session: frontmatter you remove simply reads as not attached.

Back in the session list, cards and table rows of noted sessions get a sticky-note button that opens the note file directly — it appears and disappears live as notes are created, renamed, or detached.

Session tags & filtering

A session's tags are its note's tags, with full Obsidian semantics — the frontmatter tags: property plus inline #tags in the body, exactly what the tag pane and tag: search see. Tag a session from the notes panel (chips row above the editor: + to add, × to remove — inline body tags are marked read-only, edit the body for those) or from the note's properties in the normal editor.

Tags surface in the lists:

  • Cards & tables show tag chips next to the session ID — click a chip to filter by that tag.

  • The filter input is a small query language — prefixes make each criterion explicit, everything ANDs together: #tag (session tags), is:<state> (is:running, is:idle, …), dir:<path> and model:<name> (substrings; quote values with spaces, e.g. model:"Sonnet 4.5"), and free text (matches the session title). Example: #urgent is:running model:"Sonnet 4.5" deploy.

  • The funnel button next to the input opens an advanced filter popover — per-criteria chips for Tags, State, Model, and Directory with live counts. It edits the same query string, so what you see in the input is always the truth.

  • Widgets accept a tags: option (list or comma string); only sessions carrying all of the tags are listed, intersected with dirs:

    ```vibed
    connector: opencode
    dirs:
      - projects/my-project
    tags:
      - urgent
    ```
    

globalThis.vibed.notes.tags("<sessionId>") returns a session's tags as [{tag, frontmatter, inline}].

Settings

General — default connector, items per page, refresh interval (seconds; 0 disables the timer), session notes folder (default vibed-notes).

Connectors — one card per connector: editable name, enable toggle, health status, duplicate/delete, and per-kind fields:

  • OpenCode v2: server URL override (empty = auto-discover), password, Use local database toggle, DB path, sqlite3 executable, directories, custom SQL (WHERE fragment — qualify columns like session_v2.title when the listing join makes bare names ambiguous).
  • OpenCode v1: DB path, sqlite3, directories, custom SQL.
  • Claude Code / Cursor: projects root, directories filter.
  • Codex: sessions root, zstd executable, directories filter.

Privacy & data access

Vibed runs entirely on your machine and contains no telemetry. For transparency, it does access:

  • Files outside your vaults (read-only): OpenCode v2/v1 ~/.local/share/opencode/opencode.db, Claude Code ~/.claude/projects/, Codex ~/.codex/sessions/, Cursor ~/.cursor/projects/ — that's where the agent histories live. The only writes outside your vault happen through snippet session config, after you click Install in its dialogue: a merged .opencode/opencode.json plus a small vibed manifest in the target directory, and the snippet's own skill install commands run there. Inside your vault, the only thing written is session notes you explicitly create (see Session notes).
  • Local network: the auto-discovered OpenCode v2 server (~/.local/state/opencode/service.json) for live streaming, chat, prompts, and approvals. With a remote Server URL override, the plugin talks to that host only — and nothing else.
  • Helper binaries: the system sqlite3 binary (path configurable) and an optional zstd for Codex transcripts are spawned locally, detached — as are the file-manager/terminal helpers behind the ⋮ menu's directory actions and, only through the snippet-config Install action, the shell commands a block explicitly declares (e.g. npx skills add …).
  • System clipboard (write-only): used solely when you explicitly copy a session ID (clicking the ID on a card, or Copy ID in the chat's ⋮ menu) or a working-directory path (Copy path in the ⋮ menus). The clipboard is never read.
  • Workspace directory actions: the ⋮ menus (chat header, new-session picker cards) can open a session's working directory in the system file manager (open / explorer / xdg-open) or in a terminal (open -a Terminal on macOS, cmd.exe on Windows, your $TERMINAL or a common Linux emulator). These commands run only when you click those menu items.

The file reads and helper binaries above are the entire reason the plugin uses Node's fs and child_process (and therefore is desktop-only) — no other files are touched and no other commands are run.

Install (manual)

Copy main.js, manifest.json, and styles.css into <vault>/.obsidian/plugins/vibed/, then enable Vibed under Settings → Community plugins. Desktop only (spawns sqlite3/zstd, talks to local servers).

API

globalThis.vibed (version 4):

const api = globalThis.vibed;
api.connectors();                    // [{ id, name, kind, enabled, capabilities }]
api.defaultConnector();              // name of the default connector
const claude = api.connector("claude");
const rows = await claude.list({ dirs: ["/abs/path"] });
await claude.messages("<uuid>", { limit: 100, order: "asc" });
const unsubscribe = api.subscribe(() => {});
api.config();
api.notes.find("ses_…");             // { path, basename } | null — note attached by frontmatter
api.notes.folder();                  // configured notes folder ("vibed-notes")
api.notes.tags("ses_…");             // [{tag, frontmatter, inline}] — Obsidian-semantics tags
api.open("claude:<uuid>");           // also "ses_…" (default connector)
await api.server.health();           // v2-only namespace
await api.server.messages("ses_…", { limit: 100, order: "asc" });
await api.server.prompt("ses_…", "fix the failing test");
await api.server.stop("ses_…");

Rows come pre-formatted: titleLabel, stateLabel, updatedLabel, modelLabel, directoryLabel, tokensLabel, plus connectorId, connectorName, source (kind), readOnly, and raw backend fields.

How state detection works

OpenCode v2 (primary): one SSE connection per v2 connector maps session.execution.* → Running…/Idle/Interrupted/Error and permission.asked → Needs approval. Fallback (server unreachable): a session is Running when its latest assistant message has no time.completed yet, or the newest message is still the user's — within a 15-minute freshness window.

Read-only backends: freshness heuristics — a transcript whose last line suggests an open turn (Claude: last line is the user prompt; Codex: last event is task_started; Cursor: last line is an assistant message without turn_ended) reads as Running within the same 15-minute window; otherwise Idle. OpenCode v1 uses the message-table variant of the v2 fallback.

Contact

Development

Plain single-file plugin, no build step (main.js is hand-written ES2022). node --check main.js to syntax-check; node scripts/dashboard-smoke.js runs the dashboard mount/load/render paths against a stubbed DOM (run it before releases). Design docs live in spec/. Excluded from the repo: data.json (local settings) and .hotreload (dev marker).