AI News
Loading...

Quill

Native macOS CLI v1.1.0 By Sol AI November 2026 ~20 min read

Quill is a native macOS writing studio built for novelists. A Zed-style editor in the middle, an AI writing partner on the right, a terminal / inbox / logs panel at the bottom, and a Python backend that orchestrates local and cloud LLMs behind the scenes. No Electron. No browser tab pretending to be an app. Just a real Mac app that happens to be very good at writing.

πŸͺΆ ✍️ πŸ€–

Quill β€” Writing Studio

Native macOS Β· SwiftUI + AppKit Β· MIT Licensed Β· Open Source

What is Quill?

Quill is a native macOS writing studio for novelists. The editor is Zed-style, the AI chat sits in a side panel, and a bottom panel hosts a terminal, an email inbox and a log stream. Underneath, a Python Flask backend routes requests to whichever model you have selected β€” Ollama on your own silicon, MLX, LM Studio, a MiniMax cloud model, or your own OpenAI-compatible endpoint.

The idea that makes Quill tick: the app is the AI writing partner. You're not switching between a manuscript editor and a chatbot. Quill is one surface where the prose, the model, and the tooling sit side by side. You type, the AI suggests, you accept, autosave fires.

πŸ–₯️ Native macOS

SwiftUI + AppKit. No Electron, no embedded browser. The editor is a real NSTextView subclass with Tab intercepted for AI fixes.

⌨️ Tab-to-Fix

Press Tab in the editor and Quill asks the model to fix typos and grammar on the current selection or paragraph β€” in place.

πŸ’¬ Writing-Partner Chat

The AI answers as Quill, your writing partner. Long-form mode writes straight into chapter files; short-form mode brainstorms.

🧩 Model Slots

Switch models without restarting anything. Slots cover Ollama, MLX, LM Studio, MiniMax cloud and any OpenAI-compatible endpoint.

🧠 Up to 45 Skills Injected

Your OpenClaw skills are discovered from disk and injected into the system prompt (up to 45 per request), so the AI knows what it can do.

πŸ–₯️ Bottom Panel

Cmd+J toggles a bottom panel with Terminal, Inbox and Logs tabs. A real REPL, a real inbox, real logs.

⏱️ Autosave

Every edit autosaves after a 2-second debounce, with a 30-second trailing save. Plus an explicit Save button and Cmd+S.

🧰 CLI + MCP

The quill CLI talks to the same backend from your shell, and an MCP server lets Claude Desktop or Cursor drive Quill.

πŸ“š Story Bible & Corkboard

A structured lore database (characters, locations, timeline, plot beats) and a Scrivener-style corkboard of chapter cards.

πŸ“€ Every Export

PDF, DOCX, Vellum-compatible DOCX, Markdown, TXT, HTML, ePub, RTF, OPML outline, or a ZIP bundle of the whole project.

The 30-second version

Clone the repo, start the Flask backend on http://127.0.0.1:5323, build the Swift app, open a project, and start writing. The AI is on the right. The terminal is at the bottom. The command line is quill.

Requirements

Quill is a developer install β€” there isn't a signed .app download. Here's what the source actually asks for.

Requirement Details Why
macOS 15+ Apple Silicon recommended SwiftUI + AppKit editor; MLX slots really want a Metal GPU.
Xcode 15+ Plus XcodeGen to regenerate the project You build the SwiftUI frontend from source.
Python 3.11+ Flask, Flask-CORS, PyYAML, ollama, pytest Runs the backend API, the model slots and the tool layer.
Ollama Running, serving http://127.0.0.1:11434 The default local model provider for nearly every slot.
pandoc Only for PDF / ePub / DOCX / RTF exports Quill shells out to pandoc to build binary formats.
OpenClaw Optional, for skill injection Skills are discovered under ~/.openclaw/skills and ~/.openclaw/workspace/skills.

Models you'll want

The default slot is Gemma 4 MLX 31B (via Ollama). Pull the ones that match your hardware:

# Big literary default (Apple Silicon, 24GB+)
ollama pull gemma4:31b-mlx

# Fast drafts
ollama pull gemma4:latest

# Long context for plotting
ollama pull qwen3:30b

# Thinking / research
ollama pull gpt-oss:20b

# The model Quill prefers for Tab-to-fix (precise, fast)
ollama pull llama3-groq-tool-use:8b

Cloud slots need a key

The MiniMax slots are cloud providers. Without an API key configured for that slot, the provider reports "no API key" and the slot fails its test. Local slots need nothing but Ollama.

Installation

Three pieces: the Python backend, the Swift frontend, and the quill CLI. Do them in that order.

Step 1: Clone and install backend deps

git clone https://github.com/TheSolai/quill.git
cd quill

# The dependency manifest lives in models/requirements.txt
pip install -r models/requirements.txt
# ...or just the essentials:
# pip install flask flask-cors pyyaml ollama

Heads up, the README misleads slightly

Some docs say cd backend && pip install -r requirements.txt. There is no backend/requirements.txt in the repo β€” the manifest is models/requirements.txt. Installing from the repo root works fine.

Step 2: Build the Swift frontend

The Xcode project is generated from frontend/project.yml with XcodeGen, so edit the YAML rather than the .xcodeproj.

cd frontend
xcodegen generate

# Build the app
xcodebuild -project Quill.xcodeproj -scheme Quill \
  -configuration Debug build

Or just open it in Xcode and hit Run:

open frontend/Quill.xcodeproj

Step 3: Install the quill CLI

The CLI is a single Swift file that talks to the same backend over HTTP. Symlink it into your PATH:

ln -sf /path/to/quill/frontend/Helpers/quill-ai-helper ~/.local/bin/quill

# Make sure ~/.local/bin is on your PATH
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc

quill --version   # quill 1.1.0

The CLI is optional but good manners

Everything the CLI does is also available in the app's bottom Terminal tab. But a shell that knows about your manuscript is a genuinely different tool.

First Launch

Start the backend first. The app can also auto-start it via its ProcessManager, but running it by hand is how you get to see the logs.

cd backend
python3 server.py
# -> [Quill Backend] Starting on http://localhost:5323

Then open the app. If you're building from the command line:

open frontend/Helpers/Quill.app
# or the Xcode build output:
open ~/Library/Developer/Xcode/DerivedData/Quill-*/Build/Products/Debug/Quill.app

What's on screen

Quill
β”Œβ”€ Sidebar ────────┬─ Editor ───────────────────┬─ AI ──────────┐
β”‚ QUILL            β”‚ chapter-03.md      βœ“ saved  β”‚ QUILL         β”‚
β”‚ [+ New Project]  β”‚                             β”‚ Gemma 4 MLX   β”‚
β”‚                  β”‚ The rain had not stopped  β”‚               β”‚
β”‚ PROJECTS         β”‚ for three days now, and   β”‚ > write      β”‚
β”‚  β–Έ Salt & Iron   β”‚ Maren had stopped counting β”‚   chapter 3   β”‚
β”‚ CHAPTERS         β”‚ on them.                   β”‚               β”‚
β”‚  1  The Salt Road β”‚                            β”‚  Generating…  β”‚
β”‚  2  Low Water    β”‚                            β”‚  β–Œ            β”‚
β”‚  3  The Drowned  β”‚                            β”‚               β”‚
β”‚  4  Smoke        β”‚                            β”‚               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ [Terminal] [Inbox] [Logs]                                       β”‚
β”‚ $ quill status                                                   β”‚
β”‚   backend: ok   ollama: ok   slot: gemma4-mlx                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • Sidebar (left) β€” projects and chapters. New Project and New Chapter buttons live here, and chapters can be renamed, duplicated or sent to the AI.
  • Editor (middle) β€” the manuscript. A save indicator sits in the header and shows unsaved β†’ saving… β†’ βœ“ saved.
  • AI panel (right) β€” the writing partner, plus a slot picker showing which model is live.
  • Bottom panel β€” Terminal, Inbox and Logs.

Where your work lives

Quill's base directory is ~/Quill/projects. At startup the backend also looks in ~/Projects/Quill/projects, ~/Projects/quill/projects and ~/quill/projects, and honours a QUILL_PROJECTS environment override. Each project gets a directory with chapter .md files, an exports/ folder, .quill_context.json and .quill_stats.json.

Check the wiring

curl http://127.0.0.1:5323/api/health returns backend status, whether Ollama answers, the active slot id, model id and slot type. /api/info returns the resolved base directory, the Ollama URL and the skill registry status.

The Editor & Tab-to-Fix

The editor is an AppKit NSTextView wrapped in SwiftUI β€” a real text view, not a web view. Quill subclasses it to intercept the Tab key before it inserts a literal tab character.

How Tab-to-fix works

  1. Select a passage β€” or just put the caret inside a sentence or paragraph.
  2. Press Tab.
  3. Quill posts the snippet to /api/edit-fix, which routes it to a fast, instruction-precise model. The backend prefers the groq-tool-use slot (llama3-groq-tool-use:8b) precisely because it follows instructions tightly and answers fast.
  4. The fixed text replaces the selection in place. Accept it, or hit ⌘Z to undo.

Why Tab and not a button

Because you don't want to leave the prose. You spot a typo mid-paragraph, you hit Tab, you keep writing. The correction is a keystroke, not a dialog. Zed-style, and it works.

Save behaviour

  • Autosave β€” a 2-second debounce after every edit, with a 30-second trailing save as a backstop for continuous typing.
  • Save button β€” in the editor header; its tooltip reads "Save (⌘S) β€” autosaves every 2s; press to save now".
  • ⌘S β€” the File β†’ Save menu item. βŒ˜β‡§S is Save As.

Useful keyboard shortcuts

Shortcut Action
TabInline AI fix on selection / paragraph
⌘SSave now
βŒ˜β‡§SSave As
⌘JToggle the bottom panel (Terminal / Inbox / Logs)
⌘LFocus the chapter editor
⌘KFocus the AI chat input
βŒƒβŒ˜SToggle the sidebar
⌘EExport Book…
βŒ˜β‡§PCompile Preview
⌘βŒ₯MEmail the Book…
⌘NNew Project…
βŒ˜β‡§NNew Chapter…
⌘,Settings

Story Bible & Corkboard

Two views beyond plain prose editing. The Story Bible (Codex) is the structured lore database β€” characters, locations, timeline, relationships, themes, motifs, glossary, voice and plot beats, alongside freeform text fields. quill extract can populate it by reading your chapters. The Corkboard shows chapters as visual cards with editable synopses, Scrivener-style.

The AI Chat & Model Slots

The chat panel is where Quill talks to you as a writing partner. The backend streams the reply over Server-Sent Events from /api/chat, routing to the active slot and parsing tool calls the model emits.

Long form vs short form

  • Long form (default) β€” "write chapter 3", "make chapter 1", "continue chapter 2". Quill switches to a prose-only system prompt: output is the chapter and nothing else β€” no preamble, no "here you go", no trailing question. The text is written straight into the chapter file.
  • Short form β€” brainstorming, questions, feedback. The default Quill persona, which is allowed to chat back.

Slash commands

Type / in the chat box to pop the command menu: /new, /list, /switch <id>, /delete <id>, /rename <title>. Arrow keys navigate, Return selects, Esc closes. The backend handles slash commands directly rather than sending them to the model.

What the AI knows about

Quill injects a curated block of your OpenClaw skills into the system prompt (up to 45 skills per request, selected by keyword relevance β€” the full SKILL.md is not dumped in, just enough for the AI to recognise when a skill applies). The skill registry auto-discovers any directory containing a SKILL.md under:

  • ~/.openclaw/skills/
  • ~/.openclaw/workspace/skills/
  • ~/Projects/thesolai.github.io/skills/

It also exposes a tool registry the model can call: web_search, web_fetch, email_send, email_list_inbox, email_reply, shell_exec, list_files, read_file, claude, codex, openclaw, clawhub and cli_status. Tool calls arrive as fenced JSON blocks that the backend executes and feeds back.

Model slots

A "slot" is a named model configuration. Switching slots switches models β€” no restart, no reload. The backend ships ten default slots:

Slot id Model Type Notes
gemma4-mlxgemma4:31b-mlxmlxDefault. 24GB, very high quality β€” the literary one.
gemma4-fastgemma4:latestollama8GB, very fast. Quick drafts.
qwen3-30bqwen3:30bollama32K context. Long coherent arcs.
gpt-oss-20bgpt-oss:20bollama131K context, thinking-heavy. Outlines and structural review.
qwen-coder-30bqwen3-coder:30bollamaCode and tooling.
llama3-70bllama3.3:70bollamaEpic-scale prose. 42GB.
groq-tool-usellama3-groq-tool-use:8bollamaAgentic, precise. Preferred for Tab-to-fix.
minimax-textMiniMax-Text-01minimaxCloud.
minimax-m27MiniMax-M2.7minimaxCloud, reasoning.
minimax-highspeedMiniMax-M2.7-highspeedminimaxCloud, fast.

Slots are persisted to models/slots.yaml, with the active slot id in models/.active_slot. The provider layer also supports lmstudio (local OpenAI-compatible server on port 1234) and custom (bring your own endpoint and model id).

Switching slots from the CLI

The CLI's quill slots command takes the slot id directly: quill slots gemma4-mlx activates that slot. Passing list or ls prints the table instead. The HTTP API also exposes POST /api/slots/active and POST /api/slots/<id>/activate.

The Bottom Panel

Press ⌘J (View β†’ Toggle Panel) and a panel slides up under the editor with three tabs. All three are visible by default and can be switched from the View β†’ Tabs submenu.

Terminal

A REPL-style embedded shell. Each command runs as a one-shot Process rather than a full PTY β€” deliberately, so a runaway command can't wedge the app. Output accumulates in a scrollable history, ↑/↓ walk the command history, and Tab does path completion. Because the CLI is on your PATH, all of quill works here:

quill status
quill ask "what does this chapter need?"
quill fix chapter-03.md
quill chapters
quill cat "The Drowned"

Inbox

A full email UI backed by AgentMail. The app polls /api/agentmail/inbox every 30 seconds and shows a list, a reader and a compose form. You can read, reply, draft and send. The backend also exposes /api/agentmail/send, /api/agentmail/reply and /api/agentmail/draft, and the AI can send email on your behalf through the email_send tool.

Logs

Two streams merged into one view:

  • Backend log β€” read from /tmp/quill_backend.log, polled every 2 seconds.
  • Action log β€” in-app actions: saves, fixes, sends, exports.

Filter by level (info / warn / error) and free-text search across both.

Why this matters

Most AI writing tools are a black box: you type, something comes back, no idea if it worked. Quill shows you the terminal, the logs and the inbox in the same window as the prose. You can see what the model actually did.

The quill CLI

A single Swift file, version 1.1.0, that talks to the same Flask backend over HTTP. It points at http://127.0.0.1:5323 by default β€” override with the QUILL_BACKEND environment variable. Output is colourised (auto-disabled when stdout isn't a TTY, or with NO_COLOR=1 or --no-color), and --json makes any command machine-readable.

Quick commands

quill status                       # backend, ollama, active slot + model
quill ask "what is 2+2?"           # one-shot Q&A with the active model
quill chat                          # interactive REPL (Tab autocompletes sessions)
quill fix chapter-03.md             # fix typos/grammar in place
quill expand chapter-03.md          # add sensory detail in place
quill condense chapter-03.md        # tighten prose in place

Writing commands

quill projects                     # list projects
quill chapters                      # list chapters in the current project
quill cat "The Drowned"             # print a chapter to stdout
quill write "The Drowned" "text"    # append to a chapter (--overwrite to replace)
quill bible                         # show the Story Bible
quill bible characters              # show one field of it
quill extract                       # build the Story Bible from your chapters

Inbox, search and external tools

quill inbox                        # list recent emails
quill inbox read <id>
quill inbox send "to@example.com" "Subject" "Body"
quill inbox reply <id> "text"
quill mail-book --to you@example.com # bundle the project and email it

quill search "Tolkien influences"    # web search via DuckDuckGo
quill mmx "..."                     # MiniMax cloud AI
quill claude "..."                  # run the Claude Code CLI
quill codex "..."                   # run the OpenAI Codex CLI
quill openclaw "..."                # run OpenClaw
quill clawhub "..."                 # run ClawHub

Admin commands

quill slots                        # list AI slots
quill slots gemma4-fast             # switch the active slot
quill skills                        # list OpenClaw skills
quill skills show <name>            # show one skill
quill mcp serve                     # MCP server on stdio
quill setup                         # diagnostic report: CLI, backend, slots
quill version

Global flags and pass-through

  • --project ID β€” override the current project.
  • --slot ID β€” override the AI model slot.
  • --json β€” machine-readable output.
  • --no-color β€” disable ANSI colours.
  • -h, --help β€” general help, or quill help <cmd> for one command.

And the good trick: any unknown command is passed straight to /bin/sh -c. So quill ls, quill pwd and quill git status all work.

Heads up on the README's command list

The README advertises scenes and email subcommands. In the current CLI source those don't exist β€” the equivalents are quill inbox (for email) and quill bible / quill extract (for the story-bible side of things). The source is the authority; quill help prints the real list.

MCP Server

Quill speaks the Model Context Protocol, so an external agent β€” Claude Desktop, Cursor, or anything else that speaks MCP β€” can drive your manuscript.

stdio mode

The cleanest option for a desktop client. Add this to your MCP config:

{
  "mcpServers": {
    "quill": {
      "command": "quill",
      "args": ["mcp", "serve"]
    }
  }
}

Under the hood quill mcp serve re-executes the helper with --no-color mcp serve so stdin and stdout stay clean for the protocol. Ctrl-C to stop it.

HTTP mode

The backend also exposes JSON-RPC 2.0 over HTTP at http://127.0.0.1:5323/api/mcp. tools/list returns the tool catalogue; tools/call runs one.

Available MCP tools

Tool What it does
list_projectsList every Quill project
list_chaptersList chapters in a project
read_chapterRead a chapter's full content
write_chapterWrite content to a chapter (creates if missing)
edit_fixFix typos and grammar in a text snippet
search_webWeb search via DuckDuckGo
shell_execRun a shell command
list_files / read_fileBrowse and read local files
send_email / list_inboxAgentMail inbox and sending
list_skills / read_skillInspect the OpenClaw skill registry
claude / codex / openclaw / clawhub / cli_statusShell out to the external CLIs and report their status

The MCP server is powerful

shell_exec, write_chapter and send_email are real capabilities with real consequences. Anyone who can reach the MCP server can write to your manuscript and run commands on your machine. Keep it bound to 127.0.0.1 and don't expose it to a network you don't control.

Exporting Your Work

File β†’ Export Book… (⌘E) opens the export sheet, with a Compile Preview tab (βŒ˜β‡§P) to see the assembled manuscript before you commit. The backend endpoint is GET /api/projects/<project_id>/export/<format>.

Format What you get
PDFPrint-ready PDF with formatting (via pandoc)
DOCXStandard Microsoft Word document
Vellum DOCXVellum-compatible β€” auto-detects chapters and scene breaks
MDRaw markdown, all chapters merged
TXTPlain text, no formatting
HTMLStandalone styled web page for reading
ePubE-book format for Kindle, iBooks and friends
RTFRich Text Format β€” universal
OPMLOutline editor format (chapters only)
BundleZIP with all chapters plus manifest.json

Vellum-compatible DOCX

The Vellum export is the nerdier corner of Quill, and it's good. The builder follows Vellum's import rules precisely:

  • Chapter titles are Word's Heading 1 style.
  • Each chapter starts with a page break, then the Heading 1.
  • Scene breaks are detected from a single blank line, or a centred *** (also ### and +++).
  • No manual indentation in paragraphs β€” Vellum handles that.
  • Subheads use Heading 2 / Heading 3.

Drop the file into Vellum and your chapters and scene breaks appear, already structured. No manual cleanup.

pandoc does the heavy lifting

PDF, ePub, DOCX and RTF are produced by shelling out to pandoc on the compiled markdown. Markdown, plain text and HTML are generated in pure Python and need no external tool. Install pandoc (brew install pandoc) or those four formats will fail with "could not build … (is pandoc installed?)".

Emailing the manuscript

File β†’ Email the Book… (⌘βŒ₯M) packages the project and sends it. The backend exposes /api/projects/<id>/email-the-book, email-the-chapter, email-compiled and email-zip. The compiled-book endpoint accepts pdf, epub, docx, html, md, txt and rtf. From the shell, quill mail-book --to you@example.com does the same thing β€” with --dry-run to preview before it sends.

Troubleshooting

quill status says the backend isn't reachable

Start it:

cd backend && python3 server.py
# -> [Quill Backend] Starting on http://localhost:5323

Then check what the CLI is actually talking to β€” the CLI honours QUILL_BACKEND:

echo $QUILL_BACKEND          # should be empty or http://127.0.0.1:5323
curl http://127.0.0.1:5323/api/health

Ollama shows as down

The health check pings http://127.0.0.1:11434/api/tags with a 2-second timeout. If Ollama isn't running, start it with ollama serve. If you're using a non-default Ollama port, the slot's endpoint needs updating in models/slots.yaml.

Tab-to-fix does nothing

  • The backend picks the first slot whose model id mentions groq-tool-use. If you don't have that model pulled, point it at another slot β€” or pull ollama pull llama3-groq-tool-use:8b.
  • Make sure the editor has focus and there is a selection or caret inside a paragraph.
  • Check the Logs tab in the bottom panel for a /api/edit-fix error.

The AI chat hangs with no output

Chat is streamed over SSE. Check the backend log at /tmp/quill_backend.log (also visible in the Logs tab). A 30-minute URLSession timeout applies to long generations, but a stalled slot will still look like nothing is happening. Run quill setup for a one-shot diagnostic of backend, slots and CLI tooling.

Export fails for PDF / ePub / DOCX / RTF

pandoc is missing or not on the PATH. brew install pandoc. Markdown, TXT and HTML work without it.

No skills are being injected

  • Check quill skills β€” if the registry is empty, the skill directories aren't where Quill looks. It scans ~/.openclaw/skills, ~/.openclaw/workspace/skills and ~/Projects/thesolai.github.io/skills.
  • Each skill needs a real SKILL.md β€” the registry auto-discovers by directory scan, and reads YAML-ish frontmatter for the description and keywords.
  • quill skills hits /api/skills; /api/skills/reload forces a rescan.

Model looks slow or rambles

Switch slots. The default gemma4-mlx slot is optimised for literary prose with a long context; gemma4-fast is much quicker for drafts. For structural work, gpt-oss-20b has a 131K context window. Each slot carries its own temperature, top_p and context length, editable in models/slots.yaml.

Reset the model layer

# Wipe slots and the active-slot pointer (defaults are rewritten on next run)
rm -f models/slots.yaml models/.active_slot

Credits & Links

Quill is open source and MIT licensed. The repo is the guide; this page just makes it easier to read.

Built with

  • SwiftUI + AppKit β€” the native frontend and the NSTextView subclass behind Tab-to-fix
  • Flask β€” the backend API, streaming SSE chat, and the MCP endpoint
  • Ollama β€” the default local model provider
  • MLX β€” Apple Silicon inference for the MLX slots
  • python-docx β€” the Vellum-compatible DOCX builder
  • pandoc β€” PDF, ePub, DOCX and RTF conversion
  • DuckDuckGo β€” the HTML-scraped web search behind quill search
  • AgentMail β€” the inbox behind the Inbox tab

Tests

The backend ships a pytest suite:

cd backend
python3 -m pytest tests/ -v

Why Quill exists

Because the best AI writing tool isn't a chat window with a document picker β€” it's a writing app that happens to know a model. Quill puts the prose in the middle, the partner on the right, and the machine's guts in plain sight at the bottom. No Electron. No browser. Just an app that writes.

πŸ’¬ Join the Discussion

Share your thoughts. Requires a free GitHub account.