For agents & their humans

Connect an AI to your library.

Writing Station keeps your research as plain markdown on your own disk — which means any agent that can run a command or speak MCP can file notes into it. Safely: every note is previewed and approved by you before it is written, tags come only from the vocabulary you manage in the app, and the router can only ever add files — never edit or delete.

Agents: fetch /ai.md for this page as plain markdown.

How it works

Three steps, every time — and you’re in charge the whole way.

  1. You hand it something to keep. A quote, a thought, a book you’re reading, a paragraph you spoke out loud — whatever you want saved. Your assistant reads it and works out where it belongs in your library.
  2. It checks with you first. Before saving anything, it tells you exactly what it’s about to do — something like “I’ll save this as a quote, tag it Quotes, and link it to Edwards and John 1:16. Look right?” If it’s not right, you say so and it tries again. Nothing is ever saved until you say yes.
  3. It files it, and it’s there. Once you approve, the note lands in your library and shows up in Writing Station right away — sorted and searchable like everything else. It can only ever add notes; it can never change, move, or delete anything you already have.

What you need

The CLI — ws-note

Run from the toolkit folder. Add --json to any command for machine-readable output. First, learn the vocabulary:

pnpm -s ws-note types     # the 5 note types + when to use each
pnpm -s ws-note tags      # the tag vocabulary (managed in the app — never invent)
pnpm -s ws-note people    # people already in the library ("Last, First")

Then the two-step filing:

pnpm -s ws-note propose --type snip \
  --title "Grace upon grace" \
  --tags "Quotes" \
  --people "Edwards, Jonathan" \
  --refs "John 1:16" \
  --source "Religious Affections" \
  --body "Of his fullness we have all received, grace for grace."

# → prints the destination, metadata, the exact markdown, and a token:
#   ── confirm with: ws-note commit a1b2c3d4e5 ──

pnpm -s ws-note commit a1b2c3d4e5   # ONLY after the human agrees

Body can also come from a file (--file note.md) or stdin. People are ;-separated (names contain commas). Unconfirmed proposals simply expire. ws-note proposals lists what’s pending.

The MCP server — writing-station-notes

The same engine, exposed as native tools for MCP clients (Claude Code, Claude Desktop, OpenClaw, anything that speaks MCP over stdio):

toolwhat it does
list_typesthe 5 fixed types + their vault folders
list_tagsthe app-owned tag vocabulary — call fresh each session
list_peoplepeople in the vault, with note counts
list_proposalspending (unexpired) proposals
propose_notevalidate + preview + token; writes nothing
commit_notewrite a previously-approved proposal

Claude Code — sessions started inside the toolkit repo get the server automatically (it ships a .mcp.json). From anywhere else:

claude mcp add writing-station-notes -- \
  npx tsx /path/to/writing-station-repo/tools/notewriter/mcp.mts

Claude Desktop / other clients — register a stdio server (in Desktop: claude_desktop_config.json):

{
  "mcpServers": {
    "writing-station-notes": {
      "command": "npx",
      "args": ["tsx", "/path/to/writing-station-repo/tools/notewriter/mcp.mts"]
    }
  }
}

The contract (read this, agents)

If something refuses

The library stays the human’s. The agent is a very careful librarian.