Yep - if you just want the assistant to access your Obsidian vault, you can point it to the vault during chat. If you’d like it to show up in the UI as well, or don't want to point to it on every chat, you can copy the vault to a folder under knowledge: ~/.rowboat/knowledge/obsidian-vault.
1. We chose Markdown deliberately so each node is human-readable and editable. The idea is that a project or person note represents the current state of that entity, so you can just open it and understand what’s going on. That also lets users add updates manually, for example from offline conversations that aren’t captured in email or meetings.
In terms of performance, the graph mainly acts as an index over structured notes, and retrieval happens at the note level rather than through complex graph queries. So for our use case, plain files have been sufficient and keep the system simple and transparent.
2. It’s actually Obsidian-compatible. The notes use Obsidian-style backlinks, and you can open the folder directly as an Obsidian vault if you’d like.
Thanks, completely agree. UX is probably the hardest part here. Prompting should not be a prerequisite for getting value. We have been thinking about making the system more proactive, for example surfacing relevant notes ahead of meetings or highlighting changes that need attention. Would love to hear how you think this should ideally work.
Nice, that sounds like an interesting approach. We did try simpler setups first, including giving the model direct access to raw emails and meeting notes. It works to some extent, but it’s harder to maintain a clear notion of “current state” for different entities. Without links, the model also has to do entity resolution at query time, which can require multiple passes.
A design choice we made was that each note should be usable by the user too, not just the AI. For example, if someone opens a project note, they should be able to immediately understand its current status. Linking notes and using backlinks became a natural way to surface relationships and references while keeping things human-readable.
The raw sync layer (Gmail, calendar, transcripts, etc.) is idempotent and file-based. Each thread, event, or transcript is stored as its own Markdown file keyed by the source ID, and we track sync state to avoid re-ingesting the same item. That layer is append-only and not deduplicated.
Entity consolidation happens in a separate graph-building step. An LLM processes batches of those raw files along with an index of existing entities (people, orgs, projects and their aliases). Instead of relying on string matching, the model decides whether a mention like “Sarah” maps to an existing “Sarah Chen” node or represents a new entity, and then either updates the existing note or creates a new one.
> the model decides whether a mention like “Sarah” maps to an existing “Sarah Chen” node or represents a new entity, and then either updates the existing note or creates a new one.
Thanks! How much context does the model get for the consolidation step? Just the immediate file? Related files? The existing knowledge graph? If the graph, does it need to be multi-pass?
The graph building agent processes the raw files (like emails) in a batch. It gets two things: a lightweight index of the entire knowledge graph, and the raw source files for the current batch being processed.
Before each batch, we rebuild an index of all existing entities (people, orgs, projects, topics) including aliases and key metadata. That index plus the batch’s raw content goes into the prompt. The agent also has tool access to read full notes or search for entity mentions in existing knowledge if it needs more detail than what’s in the index.
It’s effectively multi-pass: we process in batches and rebuild the index between batches, so later batches see entities created earlier. That keeps context manageable while still letting the graph converge over time.