Back to plugins
Quill
v1.0.0 fel

About

Quill

Markdown notes and todos in the Noctalia bar, with AI capture, summaries, rewriting and Q&A over your own files. Todos are plain - [ ] checkboxes, so the same notes work in any editor, in git, and with tools like Obsidian or Logseq.

Plugin

Field Value
ID fel/quill
Entries Bar widget: status; panel: panel; service: index; shortcut: toggle; launcher provider: capture; desktop widget: tile
Launcher Prefix /nt

Requirements

Notes and todos work with no dependencies. The optional extras are:

  • git — only for Git history (off by default). Enabling it runs git init in the notes folder if it is not already a repository, then commits after changes. It never pushes.
  • opencode — only for the opencode CLI AI provider. Every other provider talks HTTP directly and needs no binary.
  • An API key for whichever AI provider you pick, unless you use the opencode CLI or a local Ollama. See AI providers.

Usage

Add the bar widget to your bar in Settings → Bar (widget fel/quill:status).

Widget gestures:

Gesture Action
Left click Toggle the panel
Right click Capture the clipboard (one line → todo, multi-line → note)
Middle click Open the inbox in $EDITOR
Scroll Cycle through open todos in the bar for 15s, then back to the count

Toggle the panel from anywhere:

noctalia msg panel-toggle fel/quill:panel

Panel

  • Todos — capture box, open/overdue counts, per-todo check, due-date cycling, delete (click twice), and a click-through to the note a todo lives in. Clear done moves completed todos into the archive file.
  • Notes — search (titles and contents), create, open, edit inline, copy, open in $EDITOR, delete, and a Today button for the daily note. In a note you also get Summarize, Extract todos, AI edit (type an instruction like improve or fix grammar and review the rewrite before saving), and clickable [[wikilink]] targets.
  • Ask — ask a question over your notes and open todos, plus Plan my day and Weekly review one-click prompts. Answers cite the note titles used.

The Ask box also takes slash commands — type /help for the list: /clear, /plan, /review, /todo <text>, /note <title>, /daily, /save [title], /copy, /undo.

Every change is undoable from the panel header (one step, whole operation).

Capture with AI

With AI capture on, typing a sentence in the capture box sends it to the model, which returns a cleaned-up todo (with due date, tags and priority) or a note. Example: buy milk tomorrow- [ ] Buy milk 📅 2026-09-23 #groceries. Turn it off to append the raw text as a todo.

Launcher

Type /nt followed by a query. Results include matching todos (activating one completes it) and notes (activating one opens it), plus fallbacks to add a todo, create a note, or ask AI. Prefixes inside the query: + or todo to force a todo, # or note to force a note, ? to ask AI. Example:

/nt dentist
/nt + call the dentist tomorrow

Desktop widget

Place fel/quill:tile from Noctalia's desktop-widget editor. It lists the next open todos and opens the panel when clicked.

Shortcut

Add fel/quill:toggle from Settings → Control Center → Shortcuts. It shows the open count and lights up when something is due or overdue.

Daily notes, recurrence, reminders

  • Today creates Daily/YYYY-MM-DD.md from a small template and opens it.
  • A todo with @daily, @weekly or @monthly is rescheduled automatically when you tick it, in the same file.
  • When something becomes due or overdue, the service sends one notification (re-armed daily, and at most every 30 minutes).

Data layout

Everything lives in a normal folder of Markdown files (default ~/notes):

~/notes/
  Inbox.md          # quick captures land here
  project-ideas.md
  Daily/2026-09-22.md
  subfolder/...

A note is one .md file; the first # heading is its title and optional YAML frontmatter can set title and tags. A todo is any - [ ] or * [x] line anywhere in the folder; ticking a box rewrites that line in place. Inline metadata is parsed and hidden in the UI: 📅 2026-09-23 (also due: or @), @daily/@weekly/@monthly, #tags, and !!/#urgent or !p1/#important. Nothing is stored in a database.

AI providers

Pick one under AI provider. Everything except the CLI uses the provider's HTTP API directly; the key is resolved from the API key setting, then the API key environment variable setting, then the provider's usual environment variable, then (OpenCode Go only) opencode's own auth.json.

Provider Endpoint Key from
OpenCode Go opencode.ai/zen/go/v1 OPENCODE_API_KEY, OPENCODE_GO_API_KEY, OPENCODE_ZEN_API_KEY, or ~/.local/share/opencode/auth.json
opencode CLI the CLI's own configuration
OpenAI api.openai.com/v1 OPENAI_API_KEY
Anthropic api.anthropic.com ANTHROPIC_API_KEY
Google Gemini generativelanguage.googleapis.com GEMINI_API_KEY / GOOGLE_API_KEY
OpenRouter openrouter.ai/api/v1 OPENROUTER_API_KEY
Groq api.groq.com/openai/v1 GROQ_API_KEY
Ollama (local) localhost:11434/v1 none
OpenAI-compatible your API base URL OPENAI_API_KEY or API key env

Model ids are free text; set the provider's own model (for example gpt-4o-mini, claude-sonnet-4-5, gemini-2.0-flash, llama3.2). OpenCode Go defaults to deepseek-v4-flash.

Settings

Setting Type Default Description
notes_dir folder ~/notes Folder scanned for .md files; created if missing.
inbox_file string Inbox.md File inside the notes folder that quick captures are appended to.
poll_interval_ms int 5000 How often the folder is checked for changes, in milliseconds.
scan_depth int 3 How many levels of subfolders to scan.
ai_backend select opencode-go Provider: opencode-go, opencode-cli, openai, anthropic, google, openrouter, groq, ollama, openai-compatible, off.
ai_model string deepseek-v4-flash Model id for the selected provider.
ai_base_url string (empty) Provider API base URL override; required for a custom OpenAI-compatible endpoint.
api_key string (empty) Explicit API key. Stored in plain text in Noctalia's settings file.
api_key_env string (empty) Environment variable to read the key from, e.g. OPENAI_API_KEY.
ai_max_tokens int 0 Max tokens per reply; 0 uses the provider default.
ai_capture bool true Let the model turn a captured sentence into a todo or note.
max_context_notes int 4 How many notes are sent along with a question.
daily_dir string Daily Subfolder where the Today button creates YYYY-MM-DD notes.
archive_file string Archive.md Completed todos are moved here by Clear done; hidden from the index.
due_reminders bool true Notify once when a todo becomes due or overdue.
git_history bool false Commit the notes folder after changes (runs git init if needed).
git_debounce_ms int 8000 How long to wait after the last change before committing.
desktop_items int 6 How many open todos the desktop widget shows.
show_label bool true Widget: show the open count.
hide_when_empty bool false Widget: hide with no todos and no notes.
icon_color color primary Widget: icon color; turns red when something is overdue.

IPC

noctalia msg plugin fel/quill:index all refresh
noctalia msg plugin fel/quill:index all capture '{"text":"book a haircut friday"}'
noctalia msg plugin fel/quill:index all commit
noctalia msg plugin fel/quill:panel all ask     '{"text":"what is due this week?"}'
noctalia msg plugin fel/quill:panel all open    '{"path":"Inbox.md"}'
noctalia msg plugin fel/quill:panel all rewrite '{"path":"Inbox.md","text":"shorten"}'
noctalia msg plugin fel/quill:panel all daily
noctalia msg plugin fel/quill:panel all clear_done
noctalia msg plugin fel/quill:panel all plan
noctalia msg plugin fel/quill:panel all review
noctalia msg plugin fel/quill:panel all undo

The panel entry only has a runtime while the panel is open, so panel events should follow a panel-open/panel-toggle. capture uses AI structuring when AI capture is on. open, rewrite and clear_done accept paths relative to the notes folder only.

Notes

  • Network: the only requests are to the AI provider you selected, and only when you use an AI feature. For questions, the open todos and up to Notes in AI context notes chosen for that request are sent as context; nothing else leaves the machine. There is no telemetry.
  • Keys: the API key setting is stored in plain text in Noctalia's settings.toml, so an environment variable is preferable. The key is only ever sent in the provider's own auth header. If no key setting or environment variable is set, the OpenCode Go provider reads the key from opencode's auth.json; set a key or switch provider to avoid that read.
  • Files written: only inside the notes folder (notes, the inbox, the daily folder, the archive) and the plugin's own data folder (an AI session id and reminder state). Every read and write is resolved through a containment check that rejects absolute paths, ~ and .., so a note path cannot escape the notes folder.
  • Processes spawned: git (only with Git history) and the opencode CLI (only with that provider) run with argument arrays, never a shell string. The only shell command is opening $EDITOR in a terminal, with the path shell-quoted.
  • AI output is sanitised before it is written into notes: due dates must match YYYY-MM-DD, tags [A-Za-z0-9_-/], recurrence is a fixed set, and titles have whitespace collapsed, so a model cannot inject extra lines or frontmatter.
  • Debugging: logs go to ~/.cache/noctalia/noctalia.log; parse failures are logged with the file that failed.

Development

ln -s ~/dev/quill ~/.local/share/noctalia/plugins/quill
noctalia plugins lint ~/dev/quill
tail -f ~/.cache/noctalia/noctalia.log | grep -iE "plugin|luau"

plugin.toml changes need a config reload; adding or removing an entry needs a Noctalia restart. .luau edits hot-reload.

License

MIT

Versions

VersionPlugin APIUpdated
v1.0.0 latest24Sep 23, 2026

Older versions stay installable on a Noctalia release whose plugin API is below the latest version's.