Skip to content

Latest commit

 

History

History
266 lines (188 loc) · 7.75 KB

File metadata and controls

266 lines (188 loc) · 7.75 KB

Project Development Guide

Instructions for AI-assisted development. This document defines how we build software together.


1. Core Principles

1.1 Interface-First Development

  • Define contracts before implementations
  • Interfaces belong in the consumer package
  • Accept interfaces, return concrete types
  • Small interfaces (1-3 methods) are preferred
  • Every major component should be swappable

1.2 Dependency Injection

  • Dependencies are explicit, passed via constructors
  • No global state, no hidden dependencies
  • No magic — if it's used, it's passed in

1.3 Leaf-First Build Order

  • Start with code that has zero internal dependencies
  • Build upward: utilities -> domain -> application -> infrastructure -> entry point
  • Each file should compile and test before moving to the next

1.4 Test Where It Matters

  • Business logic: always test
  • Complex algorithms: always test
  • I/O boundaries: integration test
  • Glue code: rarely needs tests
  • Offer to write tests when a unit of work is testable

2. Project Context

2.1 What This Is

mdview.nvim is a local markdown viewer for Neovim. It has three components:

  1. Rust server (server/) — HTTP + WebSocket server that discovers markdown files, renders them, and serves a web UI
  2. Lua plugin (lua/mdview/) — Neovim integration that manages the server lifecycle and syncs buffer state
  3. Browser frontend (server/static/) — Single-page app with sidebar navigation, markdown rendering, and dark mode

2.2 Architecture

Neovim (Lua) ──WebSocket──▶ Rust Server ──HTTP──▶ Browser
     │                          │
     │ BufEnter/BufWritePost    │ File discovery
     │ sends current file path  │ Markdown rendering
     │                          │ Static file serving
     └──────────────────────────┘

2.3 Key Design Decisions

  • Rust for the server — Single binary, fast startup, no runtime dependencies for the end user
  • Vanilla frontend — No build step. HTML/CSS/JS served directly. highlight.js for code blocks
  • WebSocket for sync — Bidirectional: Neovim tells server which file is active, server pushes updates to browser
  • Thin Lua layer — Neovim plugin only handles process lifecycle and autocmds. All logic lives in the server

3. Project Structure

mdview.nvim/
├── README.md
├── CLAUDE.md
├── docs/
│   ├── ARCHITECTURE.md
│   └── TREE.md
├── notes/
│   ├── rust/
│   ├── neovim/
│   └── patterns/
├── server/
│   ├── Cargo.toml
│   ├── src/
│   │   ├── main.rs          # Entry point, CLI args, server startup
│   │   ├── discovery.rs     # Recursive .md file discovery
│   │   ├── render.rs        # Markdown -> HTML rendering
│   │   ├── ws.rs            # WebSocket hub (Neovim + browser connections)
│   │   ├── routes.rs        # HTTP route handlers
│   │   └── state.rs         # Shared application state
│   └── static/
│       ├── index.html        # Single-page app shell
│       ├── style.css         # Styling + dark mode
│       └── app.js            # Sidebar tree, WebSocket client, navigation
├── lua/
│   └── mdview/
│       └── init.lua          # Commands, autocmds, server lifecycle
└── plugin/
    └── mdview.lua            # Auto-registration

3.1 Build Phases

Phase Files Goal
1 server/src/discovery.rs Walk directory tree, collect .md files
2 server/src/render.rs Markdown to HTML with pulldown-cmark
3 server/src/state.rs Shared state: file tree, active file, connected clients
4 server/src/routes.rs HTTP endpoints: file tree API, rendered content, static files
5 server/src/ws.rs WebSocket hub for Neovim + browser sync
6 server/src/main.rs Wire everything together, CLI args
7 server/static/* Browser UI: sidebar, content pane, dark mode
8 lua/mdview/init.lua Neovim commands, autocmds, process management
9 plugin/mdview.lua Auto-registration on load

4. Development Workflow

4.1 Per-File Process

  1. Confirm scope — Single responsibility, clear purpose
  2. Identify interfaces — What contracts does it need or provide?
  3. Implement — Keep it minimal, make it work
  4. Test — If it's testable and non-trivial, write tests
  5. Verify — No compile errors, tests pass
  6. Document — Update notes if something new was learned
  7. Confirm — Get approval before moving to next file

4.2 One File at a Time

  • Never output multiple files in a single response
  • Always confirm before writing the next file
  • Exception: multiple files only if explicitly requested

4.3 When Stuck or Unclear

  • Ask for relevant existing files or context
  • Don't assume implementation details
  • Clarify requirements before proceeding

5. Technology Specifics

5.1 Rust (Server)

  • Use axum for HTTP routing
  • Use pulldown-cmark for markdown rendering
  • Use tokio-tungstenite for WebSocket
  • Use notify for file watching
  • Use clap for CLI argument parsing
  • Error handling: use anyhow for application errors, thiserror for library errors
  • Async runtime: tokio

5.2 Lua (Neovim Plugin)

  • Use vim.fn.jobstart() for spawning the server process
  • Use vim.fn.system() for one-shot commands
  • Autocmds: BufEnter (sync active file), BufWritePost (trigger reload)
  • Keep the Lua layer as thin as possible — no business logic

5.3 Frontend

  • No framework, no build step
  • Use fetch() for API calls
  • Use native WebSocket for live sync
  • Use CSS custom properties for dark/light theming
  • Use highlight.js for code block syntax highlighting (loaded via CDN)

6. Documentation Standards

6.1 Notes

notes/
├── rust/       # Rust-specific: axum patterns, async idioms, error handling
├── neovim/     # Neovim plugin patterns: jobstart, autocmds, commands
└── patterns/   # Design patterns: WebSocket hub, file watching, state sync

Create a note when:

  • A new concept is used for the first time
  • A non-obvious technique solves a problem
  • A gotcha or edge case is discovered

6.2 Note Format

# {{Concept Name}}

## What

[One paragraph explanation]

## Why

[When to use this, what problem it solves]

## Example

[Code demonstrating the concept]

## Gotchas

[Common mistakes, edge cases]

## Related

[[other-note]], [[another-note]]

7. Testing Guidelines

7.1 What to Test

Priority What Why
High File discovery logic Core feature, many edge cases
High Markdown rendering Must handle malformed input
Medium WebSocket message routing Integration point
Medium API response shapes Contract with frontend
Low Server startup/wiring Glue code

7.2 Rust Tests

  • Unit tests in the same file (#[cfg(test)])
  • Integration tests in server/tests/
  • Use tempdir for file system tests

8. Communication Style

Asking for Context

"I need to see [specific file] to understand [what]."

Proposing Implementation

"Here's the plan for [component]:

  1. [Step]
  2. [Step] Does this approach work?"

Confirming Before Proceeding

"Ready to implement [file]. Confirm?"

Offering Tests

"This [component] is testable. Want me to write tests?"


9. Status Tracking

Maintain a STATUS.md file at the project root. This file tracks progress across sessions.

  • Update at the end of each session with what was accomplished
  • Include: what was built, decisions made, what's next
  • Keep it concise — a running log, not a report