Of course. Here is the complete, clean PRD (Version 1.2) with all the performance and scalability revisions fully integrated. You can copy and paste the entire text.
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0 | 2023-10-15 | [Your Name] | Initial draft based on development iteration. |
| 1.1 | 2023-10-25 | [Your Name] | Added MCP server integration with tool definitions. |
| 1.2 | 2023-10-26 | [Your Name] | Revised API endpoints for performance (/vault-tree, /vault-tag) to handle large vaults. Updated core architecture to serve from an in-memory archive, eliminating slow startup file extraction. |
Obsidian Vault Server is a lightweight, self-contained CLI application that transforms an Obsidian Markdown-based knowledge vault into a web-accessible static server. It embeds the entire vault (compressed for minimal binary size) and provides a simple HTTP API for browsing and querying content. On startup, it scans the embedded vault into an in-memory index for high-performance access, enabling front-end applications to render dynamic views without requiring Obsidian or a full file system. Additionally, it supports integration as an MCP (Model Control Plane) server, exposing the core APIs as structured tools for AI agents or tool-calling systems (e.g., LangChain, OpenAI function calling).
The app is built in Go for cross-platform compatibility (Linux, macOS, Windows) and zero external dependencies at runtime. During build, it compresses the vault using tar + gzip (max level 9) and generates a tag index for fast querying.
Obsidian vaults are powerful for personal knowledge management but are file-system bound and not easily shareable or integrable with web apps or AI workflows. Users need a portable, secure way to serve vault content over HTTP without exposing raw files or running complex servers (e.g., no Node.js, Docker). Furthermore, AI agents require standardized tool interfaces to query and retrieve vault data programmatically.
- Primary: Provide a single binary (~20-50MB including vault) that serves an embedded Obsidian vault via HTTP.
- Secondary: Enable API-driven exploration (tree structure, tag-based search) for front-end integration; expose MCP-compatible tools for AI agent use.
- Success Metrics:
- Binary size < 100MB for typical vaults.
- Startup time < 500ms; API response < 50ms for tree and tag lookups.
- 100% uptime during runtime; graceful shutdown.
- Tool schema validation passes for standard MCP/tool-calling frameworks.
- In Scope: Vault embedding/compression, static file serving, tree API, tag API, MCP tool endpoints/schema.
- Out of Scope: User authentication, real-time editing, Markdown rendering (raw text only), multi-vault support, advanced AI orchestration (e.g., agent chaining).
- Primary Users: Obsidian power users (developers, researchers, writers) who want to share vaults via web links or integrate with custom front-ends (e.g., React/Vue apps).
- Secondary Users: Teams collaborating on knowledge bases; front-end developers building vault UIs; AI engineers integrating vaults into agentic workflows.
- User Personas:
- Alex the Developer: Builds a personal wiki; needs quick API for tree navigation and tag filtering; uses MCP tools for AI-powered querying.
- Jordan the Writer: Shares notes publicly; requires simple static serving without hosting costs.
- Sam the AI Engineer: Chains vault tools in an LLM agent to answer questions like "Summarize notes tagged #project".
-
Vault Embedding and Compression (Build-Time):
- Input:
./vaultdirectory (Obsidian-compatible Markdown files, attachments). - Process: Walk directory, create tarball, compress with gzip level 9.
- Output: Embedded
embedded_vault.tar.gzin binary (reduces size by 70-90% for text-heavy vaults). - Tag Indexing: Parse
.mdfiles fortags: [foo, bar]frontmatter; generatetag_index.json(map of tag → file paths).
- Input:
-
Static File Serving (Runtime):
- Endpoint:
GET /<path>(e.g.,/notes/foo.md). - Behavior: Scans the embedded
tar.gzarchive into an in-memory index on startup. Files are served directly from memory, eliminating disk I/O and temporary directories. Serves files with appropriate MIME types (text/plain for .md, octet-stream for others). - Security: Path sanitization to prevent traversal.
- Endpoint:
-
Vault Tree API:
- Endpoint:
GET /vault-tree?path=<path>(e.g.,?path=notesor empty for root). - Response: JSON object containing the immediate children of the requested path. Directories include a flag to indicate if they contain children, allowing UIs to render an expand icon.
// Request: GET /vault-tree?path=notes { "path": "notes", "children": [ { "name": "sub", "path": "notes/sub", "type": "directory", "is_expandable": true }, { "name": "foo.md", "path": "notes/foo.md", "type": "file" } ] }
- Errors: 400 (invalid path), 404 (not found), 500 (internal).
- Endpoint:
-
Tag Search API:
- Endpoint:
GET /vault-tag/<name>?limit=50&offset=0(case-insensitive).limit(int, optional): The maximum number of results to return. Defaults to 50.offset(int, optional): The starting index for the results. Defaults to 0.
- Response: JSON object containing pagination metadata and a list of files for the current page.
{ "tag": "foo", "pagination": { "offset": 0, "limit": 50, "total": 123 }, "files": [ "/notes/foo.md", "/other/bar.md" // ... up to 50 files ] } - Errors: 400 (invalid tag), 404 (no matches).
- Endpoint:
The server exposes the core APIs as MCP-compatible tools, allowing AI agents to call them via standardized function-calling interfaces (e.g., JSON schema for OpenAI tools or LangChain tools). This enables programmatic access for tasks like knowledge retrieval in LLM workflows.
- Activation: Run with
--mcpflag to enable tool endpoints and schema exposure. - Tool Schema Endpoint:
GET /mcp/tools– Returns JSON array of tool definitions (OpenAI-compatible format).[ { "type": "function", "function": { "name": "get_vault_tree", "description": "Retrieve the children (files and subdirectories) of a specific directory path in the vault.", "parameters": { "type": "object", "properties": { "path": { "type": "string", "description": "Optional directory path to list children from (e.g., 'notes'). Empty for full vault root." } }, "required": [] } } }, { "type": "function", "function": { "name": "get_vault_file", "description": "Fetch the raw content of a specific file from the vault.", "parameters": { "type": "object", "properties": { "path": { "type": "string", "description": "Full path to the file (e.g., 'notes/foo.md')." } }, "required": ["path"] } } }, { "type": "function", "function": { "name": "get_vault_files_by_tags", "description": "Retrieve a paginated list of file paths in the vault that have a specific tag (case-insensitive).", "parameters": { "type": "object", "properties": { "tag": { "type": "string", "description": "The tag name to search for (e.g., 'project')." }, "limit": { "type": "integer", "description": "Optional number of results to return per page. Defaults to 50." }, "offset": { "type": "integer", "description": "Optional starting index for pagination. Defaults to 0." } }, "required": ["tag"] } } } ] - Tool Execution Endpoints:
POST /mcp/execute– Body: JSON withtool_nameandarguments(e.g.,{"tool_name": "get_vault_tree", "arguments": {"path": "notes"}}).- Response: JSON with
result(tool output). - Errors: 400 (invalid args), 404 (tool not found), 500 (execution error).
- Tool Outputs:
get_vault_tree(path: str) -> dict: Returns the JSON object with children for the given path, as defined in 3.1.3.get_vault_file(path: str) -> str: Returns the raw file content as a string.get_vault_files_by_tags(tag: str, limit: int, offset: int) -> dict: Returns a structured dictionary with pagination info and a list of matching file paths, as defined in 3.1.4.
- Command:
./obsidian-server [--port=8080] [--mcp]. - Output: Startup message with endpoints (including MCP tools if enabled); logs errors.
- Shutdown: Graceful on Ctrl+C (SIGINT/SIGTERM).
- Script:
go run build.go(compresses vault, builds index). - Then:
go build -o obsidian-server main.go(embeds files). - Requirements: Go 1.16+;
./vaultdir.
- I want to build the app so that my vault is embedded securely.
- I want to start the server so that I can access my vault via browser/HTTP.
- I want to browse the vault structure so that my front-end can render a file tree.
- I want to search by tags so that I can find related notes quickly.
- I want secure access so that paths can't escape the vault.
- As an AI Engineer, I want MCP tools so that I can integrate vault querying into LLM agents.
- Language: Go 1.16+ (embed package, standard libs only).
- Libraries:
archive/tar,compress/gzip: Compression/in-memory reading.net/http: Server.encoding/json: API responses.regexp: Tag parsing.
- Embedding:
//go:embed embedded_vault.tar.gzandtag_index.json. - Build Tool: Custom
build.gofor compression/indexing. - MCP Support: Hardcoded JSON schema in code;
http.Handlerfor/mcp/*routes.
- Build Phase: Walk
./vault; tar + gzip; parse tags → JSON. - Runtime Phase:
- Startup: Extract to
/tmp/obsidian-vault-<pid>; load tag index. - Server: HTTP mux with handlers for
/,/vault-tree,/vault-tag/*, and/mcp/*(if enabled). - MCP Execution: Parse POST body, route to internal functions (e.g., tree walker, file reader, tag lookup), serialize output.
- Shutdown:
contexttimeout;os.RemoveAlltemp dir.
- Startup: Extract to
- Data Flow:
- API/Tool Call → Temp FS → JSON/string serialization.
- Tags: In-memory map (loaded once).
- Vault size: < 500MB uncompressed (for reasonable binary size and memory footprint).
- No persistent storage; all data served from memory per run.
- Cross-platform: Handle Windows paths during build.
- MCP: Schema fixed; no dynamic tool registration.
- Startup: < 2s extraction for 100MB vault.
- API Latency: < 100ms for tree (depth-limited if huge); < 10ms for tags/files.
- MCP Execution: < 200ms per tool call.
- Throughput: Handles 100 concurrent requests (static files buffered).
- Path traversal prevention:
filepath.Clean+ prefix checks. - No auth (local-only by default).
- MCP: Validate args (e.g., path length < 1024); rate-limit POSTs.
- Error Handling: Log + HTTP status codes; fail-fast on startup error. MCP errors include descriptive messages.
- Logging: Stdout for startup/errors; no files.
- Testing: Unit tests for in-memory indexing, APIs, MCP execution (80% coverage).
- CLI: Simple flags (incl.
--mcp); clear console output. - APIs/Tools: RESTful, JSON-only.
- Assumptions:
- Vault follows Obsidian structure (
.mdfiles, optional attachments). - Tags in format
tags: [foo, bar](single line, top of file). - User has Go installed for build; binary is standalone.
- MCP clients handle standard OpenAI tool schema.
- Vault follows Obsidian structure (
- Dependencies:
- None at runtime.
- Build: Go toolchain.
- Risks:
- Large vaults: Slow extraction (mitigate: async extract?).
- Tag parsing: Misses complex frontmatter (mitigate: Extend regex).
- MCP Compatibility: Schema drift (mitigate: Versioned endpoint
/mcp/tools/v1).
- Phase 2: Markdown-to-HTML rendering (
/render/<path>); tool for rendered content. - Phase 3: Search API (
/search?q=query); authentication; dynamic tool registration. - Phase 4: Multi-vault support; Docker image; advanced MCP (e.g., streaming responses).
- Product Owner: [TBD]
- Engineering Lead: [TBD]
- Status: Updated Draft – Ready for Review
Below is a well-structured prompt you can copy-paste or adapt for your Project Manager (PM) and Scrum Master (SM). It's designed to guide them in collaboratively breaking down the Obsidian Vault Server PRD (version 1.1) into actionable, workable user stories. The focus is exclusively on the server (backend) features, excluding the front-end viewer. I've emphasized Scrum best practices: using INVEST criteria for stories, grouping into epics/themes, including acceptance criteria, and prioritizing for an initial sprint or backlog.
Prompt for Project Manager and Scrum Master: Breaking Down Obsidian Vault Server PRD into Workable User Stories
Context:
We have the updated PRD for the Obsidian Vault Server (v1.1), which includes core features like vault embedding/compression, static file serving, Vault Tree API, Tag Search API, MCP server integration, CLI interface, and build process. Our immediate focus is on implementing the server backend only—no front-end work yet. The goal is to create a prioritized backlog of user stories that can be pulled into sprints, ensuring the server is buildable, runnable, and testable end-to-end.
Your Task:
As PM and SM, collaborate to decompose the PRD (sections 3-5, plus existing user stories in section 4) into 15-25 user stories. Group them into 3-5 high-level Epics/Themes (e.g., "Build-Time Preparation", "Runtime Serving", "API Endpoints", "MCP Integration").
Guidelines for Stories:
- Format: Use the standard user story template: As a [user/persona], I want [feature] so that [benefit].
- Personas: Draw from PRD section 2 (e.g., Alex the Developer, Jordan the Writer, Sam the AI Engineer).
- INVEST Criteria: Ensure stories are:
- Independent (can stand alone).
- Negotiable (details flexible).
- Valuable (delivers user/business value).
- Estimable (sized for 1-3 days of effort).
- Small (fits in one sprint; split large ones).
- Testable (clear acceptance criteria).
- Acceptance Criteria: For each story, include 3-6 bullet points with testable outcomes (e.g., "Run command X; verify output Y"). Reference PRD specs (e.g., endpoints, JSON schemas, error codes).
- Prioritization: Use MoSCoW (Must-have, Should-have, Could-have, Won't-have) or business value/effort matrix. Flag 5-8 stories as "Sprint 1 Ready" (e.g., core build and serving).
- Technical Notes: Stories should align with Go tech stack (section 5.1); include any dependencies (e.g., build script before runtime). Assume unit/integration tests for 80% coverage (section 6.3).
- Output Structure:
- Epics/Themes: List with brief description and contained stories.
- User Stories: Numbered list, each with:
- Story title.
- User story sentence.
- Acceptance criteria (bullets).
- Priority (Must/Should/etc.).
- Estimated effort (e.g., 3 story points).
- Sprint 1 Backlog: Top 5-8 stories ready to groom.
- Risks/Dependencies: Bullet list of any cross-cutting concerns (e.g., temp dir cleanup).
Deliverable:
Share a Google Doc, Notion page, or Markdown file with the full backlog by [insert deadline, e.g., EOD Friday]. Schedule a 30-min refinement session next week to validate. This will feed directly into Jira/Trello for sprint planning.
Key PRD Sections to Decompose:
- 3.1: Vault Embedding/Compression, Static Serving, Tree API, Tag API.
- 3.2: MCP Integration (tools schema, execution endpoint).
- 3.3-3.4: CLI and Build Process.
- 4.1: Existing user stories (enhance with AC).
- 5.2-5.3: Architecture/Constraints (e.g., path security, performance).
Let's make this server rock-solid for Alex, Jordan, and Sam—focus on quick wins like embedding and basic APIs first!