krz/orgstar

A native macOS editor for org-mode files. editor org-mode swift

docs/manual/guide/08-capture.org

191ddb506f3a91b93c755ba6e8123a4e8ac4f90d
orgstar/docs/manual/guide/08-capture.org rendered · source · history · blame · raw

349 lines · 29058 bytes

  1#+TITLE: Capture
  2#+DESCRIPTION: Capture templates, the capture window, date trees, org-protocol, Shortcuts and the iOS share sheet.
  3#+LEDE: Capture files a note, task or link into the right place in your org files without leaving what you are doing.
  4
  5* Starting a capture
  6
  7Capture mirrors =org-capture=. Start it from anywhere in the app:
  8
  9| Preset | Key                                    |
 10|--------+----------------------------------------|
 11| Mac    | =⇧⌘N= (File ▸ Capture…)                |
 12| Emacs  | =C-c c= or =⇧⌘N=                       |
 13| Doom   | =SPC X= (normal state), =C-c c= or =⇧⌘N= |
 14
 15=⌃⌥Space= opens the capture window from any app, with Orgstar in the background. Turn it off in Settings ▸ Capture, or in =config.toml=:
 16
 17#+BEGIN_SRC toml
 18[orgstar]
 19global-capture-hotkey = false
 20#+END_SRC
 21
 22The shortcut is registered as a system hot key and needs no accessibility permission.
 23
 24Captures can also arrive from a browser through org-protocol, from Shortcuts, and on iOS from the share sheet; see the sections below.
 25
 26* The capture window
 27
 28A capture goes through up to three steps.
 29
 301. *Choose a template.* The window lists your templates with their keys and targets. Type a template's key, or click it. For a key of several characters, such as =wb=, each character you type narrows the list to the templates whose keys start with what you typed, and the header shows the keys so far (=Capture: w=). =Delete= removes the last key typed. The template is chosen as soon as the keys match one.
 312. *Answer its questions.* If the template has prompts (=%^{…}=, =%^g=, =%^t= and the others below), they appear as a form. Leave a field empty for its default. Press Return (Continue) to go on.
 323. *Edit and file.* The filled template appears in an editor, headed with the template's name and target, with the cursor where =%?= was. Press =⌘Return= (File It) to file it.
 33
 34Press Esc (Cancel) at any step to close the window without filing anything, as =org-capture-kill= does.
 35
 36Filing, the equivalent of =org-capture-finalize=, places the text in its target and saves it through the open buffer if the file is open, or into the file otherwise. A target file that doesn't exist is created, with its folders. The status line in the main window then says where the entry went.
 37
 38If filing fails, for example because a heading on an =olp= path is missing, the window stays open with your text and shows the error in red below it, so you can try again after fixing the file or cancel.
 39
 40Limits compared with Emacs:
 41
 42- The editor is a plain text editor. Org editing commands and keys such as =C-c C-c= and =C-c C-k= don't work in it; use =⌘Return= and Esc.
 43- There is no refile from the capture window (=C-c C-w= in an Emacs capture buffer). Capture to an inbox heading and refile from the agenda or the editor.
 44- The target is not shown while you edit (the capture buffer in Emacs is narrowed to the new entry in the target file).
 45
 46* Capturing onto an agenda day
 47
 48The + at the right of a day's header in the agenda, or =k= in the Mac agenda (=org-agenda-capture=), starts a capture for that day; see [[file:07-agenda.org][The agenda]]. Choose a template as usual. The day then stands in for today, as =org-overriding-default-time= makes it do in Org:
 49
 50- =%t=, =%T=, =%u= and =%U= give that day. The escapes with a time use the current time of day.
 51- An empty answer to a date prompt (=%^t= and the others) is that day.
 52- With =datetree = true=, the entry goes under that day in the date tree.
 53
 54When the filled template is a heading without an active timestamp, Orgstar adds =SCHEDULED:= with that day on the line after the heading, or at the end of the planning line when the template has one:
 55
 56#+BEGIN_SRC org
 57,* TODO Call the bank
 58SCHEDULED: <2026-10-09 Fri>
 59#+END_SRC
 60
 61The line is part of the text you edit, so you can change or remove it before filing. A template with an active timestamp of its own, such as =%t= or =%^t=, gets no =SCHEDULED= line. On the Mac, the window's header names the day, as =Capture, scheduled Fri 9 Oct=.
 62
 63* Capture templates
 64
 65Templates live in =capture.toml= in the configuration folder (=~/.config/orgstar/capture.toml= by default; see [[file:13-configuration.org][Configuration]]). Settings ▸ Capture shows its path. Each template is a =[[template]]= table:
 66
 67#+BEGIN_SRC toml
 68[[template]]
 69key = "t"
 70name = "Personal todo"
 71type = "entry"
 72file = "todo.org"
 73headline = "Inbox"
 74template = "* TODO %?\n%i\n%a"
 75prepend = false
 76#+END_SRC
 77
 78The file is read each time the capture window opens. If it doesn't exist, or none of its templates is valid, these two built-in templates are used:
 79
 80| Key | Name           | Target                      | Template              |
 81|-----+----------------+-----------------------------+-----------------------|
 82| =t= | Personal todo  | =todo.org=, heading =Inbox= | =* TODO %?\n%i\n%a=   |
 83| =n= | Personal notes | =notes.org=, heading =Inbox= | =* %u %?\n%i\n%a=   |
 84
 85A problem in the file, such as a table without a key, shows in red at the bottom of the window; the other templates still load.
 86
 87Templates are a flat list. Keys of several characters are typed one character at a time, as in Emacs, but Emacs's template groups (an entry with only a key and a description) have no equivalent: the list shows every template whose key starts with what you typed.
 88
 89** Keys
 90
 91| Key                  | Value             | Meaning                                                                                       | Org property            |
 92|----------------------+-------------------+-----------------------------------------------------------------------------------------------+-------------------------|
 93| =key=                | string, required  | What you press to choose the template                                                         | key                     |
 94| =name=               | string            | The name in the list; the key when omitted                                                    | description             |
 95| =type=               | string            | =entry= (the default), =item=, =checkitem=, =plain= or =table-line=                           | type                    |
 96| =template=           | string, required  | The text to fill; see [[*Template escapes][Template escapes]]                                 | template                |
 97| =file=               | string            | The target file; required except with =id= or =clock=                                         | target                  |
 98| =headline=           | string            | A heading in =file=                                                                           | =file+headline=         |
 99| =olp=                | string            | An outline path in =file=, titles separated by =/=                                            | =file+olp=              |
100| =datetree=           | boolean           | Today's entry in a date tree in =file=, under =olp= if given                                  | =file+olp+datetree=     |
101| =tree-type=          | string            | =day= (the default), =week= or =month=, for =datetree=                                        | =:tree-type=            |
102| =id=                 | string            | The heading with this =ID= property, in any file                                              | =id=                    |
103| =clock=              | boolean           | The entry the clock is running in                                                             | =clock=                 |
104| =prepend=            | boolean           | Put the text first rather than last                                                           | =:prepend=              |
105| =immediate-finish=   | boolean           | File without showing the editor                                                               | =:immediate-finish=     |
106| =empty-lines=        | integer           | Blank lines before and after the captured text                                                | =:empty-lines=          |
107| =empty-lines-before= | integer           | Blank lines before; overrides =empty-lines=                                                   | =:empty-lines-before=   |
108| =empty-lines-after=  | integer           | Blank lines after; overrides =empty-lines=                                                    | =:empty-lines-after=    |
109| =jump-to-captured=   | boolean           | Show the new entry in the editor after filing                                                 | =:jump-to-captured=     |
110| =clock-in=           | boolean           | Clock in to the captured entry                                                                | =:clock-in=             |
111| =clock-keep=         | boolean           | With =clock-in=, keep the clock running after filing                                          | =:clock-keep=           |
112| =clock-resume=       | boolean           | With =clock-in=, restart the clock that was running before                                    | =:clock-resume=         |
113| =table-line-pos=     | string            | Where a =table-line= goes, such as ="II-3"=                                                   | =:table-line-pos=       |
114
115=capture.toml= uses a subset of TOML: basic strings in double quotes, literal strings in single quotes, booleans and integers. Multi-line strings (="""…"""=) are not supported, so write a newline in a template as =\n= inside a double-quoted string. A double-quoted string accepts only the escapes =\"=, =\\=, =\n=, =\t=, =\uXXXX= and =\UXXXXXXXX=; any other backslash is an error. A template backslash, as in =%\1= or =\%=, is therefore written =%\\1= or =\\%= in double quotes, or as it is in a single-quoted string, which has no escapes and no =\n=.
116
117#+BEGIN_SRC toml
118[[template]]
119key = "m"
120name = "Meeting"
121file = "work.org"
122olp = "Meetings"
123template = "* %^{Topic} :meeting:\n%U\n- Attendees: %^{Attendees}\n- Topic again: %\\1\n%?"
124#+END_SRC
125
126** Targets
127
128The target keys are checked in this order: =id=, =clock=, =datetree=, =headline=, =olp=; with none of them the target is =file= itself.
129
130| Target                    | Where the text goes                                                                                             |
131|---------------------------+-----------------------------------------------------------------------------------------------------------------|
132| =file= alone              | The file's top level: an =entry= becomes a top-level heading at the end (or start, with =prepend=)              |
133| =headline = "Inbox"=      | Under the first heading with that exact title, at any level. If there is none, =* Inbox= is added at the end of the file |
134| =olp = "Projects/Work"=   | Under =Work=, a child of =Projects=. Every heading on the path must exist; otherwise filing fails with =Heading not found on outline path= |
135| =datetree = true=         | Under today's heading in a date tree; see [[*Date trees][Date trees]]                                           |
136| =id = "…"=                | Under the heading with that =ID=, found through the workspace index. Fails with =Cannot find target ID= if no heading has it |
137| =clock = true=            | Under the heading the running clock is in. Fails with =No running clock= when no clock runs                    |
138
139=file= may be absolute (=/Users/me/org/todo.org=), start with =~/=, or be relative. A relative path is relative to the first folder in the sidebar (your home folder if you have none). Heading titles match the title text without its TODO keyword, priority or tags. Because =olp= uses =/= as its separator, a heading whose title contains =/= can't be on an outline path; use =headline= or =id= for it.
140
141Emacs's =file+regexp=, =file+function= and =function= targets, and templates read from a file (=(file "…")=), are not supported.
142
143** Template types
144
145| Type         | What is inserted                                                                                                                                         |
146|--------------+----------------------------------------------------------------------------------------------------------------------------------------------------------|
147| =entry=      | An Org entry. If the text has no heading, =* = is added. Its level is adjusted to be one below the target heading, or 1 at the top level. Placed as the last child (first with =prepend=). Text whose first heading isn't its highest is refused: =Template is not a valid Org entry or tree= |
148| =item=       | A list item. A =- = bullet is added if the text has none. Goes after the last item of the first list in the target entry (or the file), with that list's indentation; if there is no list, at the end of the entry's text |
149| =checkitem=  | As =item=, with a =[ ]= checkbox added if there is none                                                                                                   |
150| =plain=      | The text as it is, at the end of the entry's body (with =prepend=, right after the heading line)                                                          |
151| =table-line= | A table row, in the first table in the target entry (or the file); a new table is made if there is none |
152
153For =table-line=, a text that doesn't start with a vertical bar gets one. The row goes at the end of the table. With =prepend= it goes before the first data row after the first rule. With =table-line-pos=, =II-3= means three lines above the second horizontal rule and =I+1= the first line below the first rule; an impossible position fails with =Invalid table line specification=. After the row is placed, the table is aligned and its formulas recomputed; a table whose formulas need Emacs makes the capture fail with a message that says so (see [[file:10-tables.org][Tables]]).
154
155Placement follows =org-capture-place-entry= and its siblings, including how blank lines are kept: without =empty-lines= options, a new heading gets a blank line before it when its neighbors have one (=org-blank-before-new-entry= =(heading . auto)=). Within an existing list, at most one blank line goes between items.
156
157** Clocking while capturing
158
159With =clock-in = true=, the captured entry gets a clock entry from when the template was filled to when you filed it, as Emacs clocks in while the capture buffer is open and out on finalize. With =clock-keep = true= as well, the clock keeps running in the new entry. With =clock-resume = true=, the clock that was running before the capture starts again after filing. With no clock running, clocking in to the entry first asks about open clocks, as Clock In does, as of when the capture began; on the Mac the questions are in the main window's echo area. See [[file:06-dates-and-clocking.org][Dates, scheduling and clocking]].
160
161* Template escapes
162
163These follow =org-capture-fill-template=. Escapes that need no answer are filled first; prompts are then asked in order.
164
165** Inserted values
166
167| Escape     | Inserts                                                                                                         |
168|------------+-----------------------------------------------------------------------------------------------------------------|
169| =%?=       | Nothing; the cursor goes here                                                                                   |
170| =%i=       | The initial text: the selection in the editor, or the body from org-protocol, Shortcuts or the share sheet. Later lines get the indentation of the line =%i= is on |
171| =%a=       | A link to where capture started, =[[target][description]]=                                                      |
172| =%A=       | The same link, asking for its description                                                                       |
173| =%l=       | The link as =[[target]]=, without description                                                                   |
174| =%L=       | The link target alone                                                                                           |
175| =%c=, =%x= | The clipboard's text                                                                                            |
176| =%f=       | The name of the file capture started from                                                                       |
177| =%F=       | The full path of that file                                                                                      |
178| =%n=       | Your full name from macOS                                                                                       |
179| =%k=       | The title of the entry the clock is running in                                                                  |
180| =%K=       | A link to that entry                                                                                            |
181| =%t=       | Today's date as an active timestamp, =<2026-10-07 Wed>=                                                         |
182| =%T=       | Active timestamp with the current time                                                                          |
183| =%u=       | Inactive timestamp, =[2026-10-07 Wed]=                                                                          |
184| =%U=       | Inactive timestamp with the current time                                                                        |
185| =%<…>=     | The current time formatted with a =format-time-string= pattern, such as =%<%Y-%m-%d %H:%M>=                     |
186| =%:name=   | A link property; see below                                                                                      |
187
188From the Mac capture window, =%a= links to the heading at the cursor in the open file, as =[[file:~/org/work.org::*Heading][Heading]]=, or to the file itself before the first heading. It is empty with no file open.
189
190=%<…>= understands =%Y=, =%m=, =%d=, =%e=, =%H=, =%M=, =%S=, =%a=, =%A=, =%b=, =%B=, =%F=, =%R= and =%%=, with English day and month names. Other =format-time-string= codes are left in the text as they are.
191
192=%:name= inserts a property of the link being captured. From org-protocol these are =%:link=, =%:description= (the page title), =%:type= (the link's scheme, such as =https=), =%:annotation= (the same as =%a=) and =%:initial= (the same as =%i=). Without org-protocol, =%:annotation= and =%:initial= still work and other names insert nothing.
193
194** Prompts
195
196| Escape                         | Asks for                                                                                   |
197|--------------------------------+--------------------------------------------------------------------------------------------|
198| =%^{Prompt}=                   | A line of text                                                                             |
199| =%^g=                          | Tags, offering the tags used in the target file                                            |
200| =%^G=                          | Tags, offering every tag in your folders                                                   |
201| =%^t=, =%^T=                   | A date, inserted as an active timestamp; =%^T= always includes a time                      |
202| =%^u=, =%^U=                   | The same as an inactive timestamp                                                          |
203| =%^C=                          | Text, offering the initial text and the clipboard                                          |
204| =%^L=                          | As =%^C=, inserted as a link                                                               |
205| =%^{NAME}p=                    | A value for the property =NAME=, set in the entry's property drawer                        |
206
207=%^{Prompt|default|a|b}= asks for text with a default and suggested choices, separated by vertical bars.
208
209A name in braces before any of the keyed forms becomes its prompt: =%^{Start}T=, =%^{Context}g=. Leave a text answer empty for the default. Tags are typed separated by colons (=work:urgent=); on a heading line they are aligned to =org-tags-column=. A date takes the same input as the editor's date prompt, such as =+2d=, =fri= or =fri 14:00= (see [[file:06-dates-and-clocking.org][Dates, scheduling and clocking]]); an empty answer is today, or now for =%^T= and =%^U=. A time in the answer makes =%^t= include it.
210
211After the prompts are answered, =%\1=, =%\2= and so on insert the answer to the first, second, … text prompt (=%^{…}= only), and =%\*1=, =%\*2= the answer to the first, second, … prompt of any kind.
212
213** Escaping and unsupported escapes
214
215Put a backslash before =%= to keep it literally: =\%t= inserts =%t= (in a double-quoted TOML string, write =\\%t=). Two backslashes insert one backslash followed by the escape's value.
216
217=%(…)= runs Emacs Lisp in Org and is not supported; a template that contains it fails with a message saying so. =%[file]= (insert a file's contents) is not supported either. Any other =%= sequence is left as it is.
218
219* Date trees
220
221With =datetree = true=, the entry goes under today's date in a tree of headings, as =org-datetree-find-create-entry= builds it. Missing levels are created in date order among their siblings.
222
223| =tree-type= | Levels                                                    |
224|-------------+-----------------------------------------------------------|
225| =day=       | =* 2026=, =** 2026-10 October=, =*** 2026-10-07 Wednesday= |
226| =week=      | =* 2026=, =** 2026-W41=, =*** 2026-10-07 Wednesday= (ISO week and its year) |
227| =month=     | =* 2026=, =** 2026-10 October=                            |
228
229#+BEGIN_SRC toml
230[[template]]
231key = "j"
232name = "Journal"
233file = "journal.org"
234datetree = true
235template = "* %<%H:%M> %?\n%i"
236#+END_SRC
237
238With =olp=, the tree goes under that outline path, one level down, instead of at the top of the file. The date is the day you file the capture. There is no =:time-prompt= to choose another day.
239
240* org-protocol
241
242Orgstar registers the =org-protocol:= URL scheme and handles the two handlers browser bookmarklets use, as =org-protocol.el= does in Org 9.8.7. Both the =?key=value= form and the older =:/a/b/c= form work.
243
244** capture
245
246#+BEGIN_SRC text
247org-protocol://capture?template=w&url=https%3A%2F%2Fexample.com&title=Example&body=Selected%20text
248#+END_SRC
249
250This opens the capture window with:
251
252- =template= chosen. Without =template=, the template list shows. A key with no template reports =No capture template "w"=.
253- =%a= and =%:annotation= set to =[[url][title]]= (the URL as its own description when the title is blank; the title alone when there is no URL).
254- =%i= and =%:initial= set to =body=.
255- =%:link= set to the URL, =%:description= to the title, and =%:type= to the URL's scheme.
256
257In the query form, =+= stands for a space, as in Org; encode a literal =+= as =%2B=.
258
259** store-link
260
261#+BEGIN_SRC text
262org-protocol://store-link?url=https%3A%2F%2Fexample.com&title=Example
263#+END_SRC
264
265This stores the link, so =C-c C-l= in the editor offers it (see [[file:09-links.org][Links]]), and puts the URL on the clipboard.
266
267Other handlers, such as =open-source=, report that Orgstar handles only capture and store-link. On iOS only =capture= links are handled.
268
269** Bookmarklets
270
271Bookmarklets written for Emacs's org-protocol work unchanged. Add a bookmark with one of these as its address:
272
273#+BEGIN_SRC js
274javascript:location.href='org-protocol://capture?template=w&url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title)+'&body='+encodeURIComponent(window.getSelection())
275#+END_SRC
276
277#+BEGIN_SRC js
278javascript:location.href='org-protocol://store-link?url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title)
279#+END_SRC
280
281A matching web capture template:
282
283#+BEGIN_SRC toml
284[[template]]
285key = "w"
286name = "Web page"
287file = "inbox.org"
288headline = "Web"
289template = "* %:description\n:PROPERTIES:\n:URL: %:link\n:END:\n%U\n%i\n%?"
290#+END_SRC
291
292* Shortcuts
293
294The Shortcuts action Capture to Orgstar files text with a template, without the capture window. It has two parameters:
295
296| Parameter    | Meaning                                                                 |
297|--------------+-------------------------------------------------------------------------|
298| Text         | The text, inserted as =%i=                                              |
299| Template Key | A template's =key= in =capture.toml=; the first template when empty     |
300
301Every prompt in the template takes its default (an empty answer: today for dates, no tags), and =%?= is ignored. =%a= is empty. On the Mac, =%c= is the clipboard and =%n= your name; on iOS both are empty, because reading the pasteboard would ask for permission on every run. The action returns a message, =Captured to …= with the target on the Mac and =Captured with …= with the template name on iOS, or fails with the same messages as the capture window. You can also say "Capture to Orgstar" to Siri.
302
303On the Mac, the action opens Orgstar if it isn't running and waits up to five seconds for it to be ready.
304
305* Capture on iOS
306
307The Capture button (a square with a pencil) at the top of the Agenda and Folders tabs opens the capture sheet. The + on a day's header in the Agenda tab opens it for that day, as described in [[*Capturing onto an agenda day][Capturing onto an agenda day]]; date prompts then show that day as their default. The templates come from the =capture.toml= in your synced configuration folder (see [[file:14-ios.org][iOS]]).
308
309The sheet works as on the Mac, in a form:
310
311- The Template picker chooses the template; it starts on the first one.
312- Prompts appear as fields. Date prompts have a date picker; choices and tags appear as buttons, and tapping a tag adds it.
313- Continue fills the template and shows the text to edit; File files it; Cancel discards it.
314
315Differences from the Mac: there is no selection, clipboard, current file, user name or clock link to insert, so =%i= and =%a= are empty unless the capture came from a link or the share sheet, and =%c=, =%x=, =%f=, =%F=, =%n=, =%k= and =%K= are empty. An org-protocol link naming a template key that doesn't exist opens the sheet on the first template and shows =No capture template "x"= with the key.
316
317** The share sheet
318
319In another app, share a web page or text and choose Orgstar. The share form has:
320
321- a Template picker, with the templates the app read the last time it ran;
322- for a link, its title (editable) and address;
323- a Text field, filled with shared text.
324
325Capture saves the item in the app group's capture inbox. The next time you open Orgstar, it opens the capture sheet with the item as an org-protocol capture: the link becomes =%a= and =%:link=, the title =%:description=, and the text =%i=. Several waiting items open one after another, oldest first. If the extension says Orgstar's shared folder isn't available, the app group is missing from the build and nothing can be saved.
326
327The share form lists no templates until Orgstar has run once with your configuration folder; the capture sheet then starts on the first template.
328
329* Importing templates from Emacs
330
331Import from Emacs (see [[file:13-configuration.org][Configuration]] and [[file:15-alongside-emacs.org][Alongside Emacs]]) reads =org-capture-templates= and appends a =[[template]]= table to =capture.toml= for each template whose key isn't there already.
332
333| Emacs                                        | Imported as                              |
334|----------------------------------------------+------------------------------------------|
335| types =entry=, =item=, =checkitem=, =plain=, =table-line= | =type=                      |
336| =(file "f")=                                 | =file=                                   |
337| =(file+headline "f" "H")=                    | =file=, =headline=                       |
338| =(file+olp "f" "A" "B")=                     | =file=, =olp = "A/B"=                    |
339| =(file+olp+datetree "f" …)=                  | =file=, =datetree=, =olp= if a path is given |
340| =(file+datetree "f")=                        | =file=, =datetree=                       |
341| =(file+weektree "f")=                        | =file=, =datetree=, =tree-type = "week"= |
342| =(id "…")=                                   | =id=                                     |
343| =(clock)=                                    | =clock=                                  |
344| =:prepend=, =:immediate-finish=, =:jump-to-captured=, =:clock-in=, =:clock-keep=, =:clock-resume= | the boolean of the same name |
345| =:empty-lines=, =:empty-lines-before=, =:empty-lines-after=, =:table-line-pos=, =:tree-type= | the key of the same name |
346
347A file name given as a variable or a simple form is evaluated where the importer can. The import report lists what it left out: other targets, templates that aren't strings, unknown =:tree-type= values, and other properties such as =:time-prompt=, =:kill-buffer= or =:unnarrowed=. Template groups are skipped.
348
349Emacs resolves relative target files against =org-directory=; Orgstar resolves them against the first folder in the sidebar. If =org-directory= isn't your first folder, edit the imported =file= values or make them absolute.