# \[Script for aiding\] round trip with collaborators/editors

**URL:** <https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717>\
**Category:** Scrivener\
**Tags:** usage-tips, collaboration\
**Created:** [September 23, 2026, 1:48am UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717 "2026-09-23T01:48:31Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dart](https://forum.literatureandlatte.com/letter_avatar_proxy/v4/letter/d/7bcc69/32.png) [@Dart](https://forum.literatureandlatte.com/u/Dart)\
**Post date:** [September 23, 2026, 1:48am UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717/1 "2026-09-23T01:48:31Z")

</div>

I read a post on the Reddit scrivener group about someone who had submitted a book to a publisher, in Word, as was their requirement.

The book came back with a bunch of changes marked. Now the user had to do one of two things: Transfer all the changes back to scrivener, or work in Word.

I have a similar problem. My copy editor wants to markup on paper. So I print her a PDF. But then to enter the stuff in scrivener, I have to find the passage in my document. I needed a temporary coodinate system that would help me find the same spot in my document that she had marked in the PDF.

So I, with help from Claude, came up with Scriv\_marker. Scriv\_marker puts a line in every 5 paragraphs in lighter grey. Each document is numbered from the start.

The idea for the workflow:

- close the project
- Run scriv\_marker from a command line to mark the document/project.
- print/compile the project and send to your collaborator. They do whatever, and send their copy back.
- Now you can find that spot in your project, and work on the modifications.
- _run it with_ –denumber to remove any markers

I did not like using Scrivener’s built in numbering for a few reasons:

- Numbering and denumbering hve to be done one document at a time.
- denumbering did not return a document to the format it had before.
- If, in my editing I added a paragraph after par 27, then all the numbering following changes.
- With Scriv\_Marker, I can number a document, and add or delete what I wish. Para 025 remains para 025

Example of after scriv\_marker has run.

 ![image](https://forum.literatureandlatte.com/uploads/default/original/3X/b/8/b82b3fa23dab20c1877b9e84dbedbea89840b6ac.png)

This is a command line tool. On mac, you run it in a terminal window.

It requires python 3  
It requires the script inself.  
It requires an external file scriv\_common.py which has stuff used by this and other scrivener utilities.

This has been tested enough that I’m using it with my current WiP. However I have not tested it in every combination. I do not know if files have any as yet undetected sentinels for Scrivener itself.

I have not tested on windows.

I have scrivener set to make a backup on project close.

I offer this script to the community at no charge and with no warranty. If L&L wish to incorporate the functionality of this script into the next version of Scrivener, they are free to do so, however, while I did my best to shepherd Claude’s work, I am neither a professional python programmer, nor an expert on Apple’s (per)version of RTF.

Thiis is the help accessed with the --help option, or a shorter version if given a missing or bad option.  
usage: scrive\_marker.py [-h] [-v] [–scriv-dir SCRIV\_DIR]  
[–walker-path WALKER\_PATH] [–renumber | --denumber |  
–repair] [–regex REGEX | --folder FOLDER]  
[–every EVERY] [–width WIDTH] [–color COLOR]  
[–dry-run] [–no-confirm] [–ignore-lock-check]  
[–title] [–binder] [–debug-dir DIR]  
[project]

scriv\_marker.py – insert or remove unobtrusive paragraph-count sequence  
markers directly in Scrivener content.rtf files, so a compiled/printed  
PDF carries a coordinate system (light-grey, centered “==\>para 005 \<==”  
lines every N paragraphs) that maps cleanly back onto the binder when  
re-entering an editor’s corrections.

Two operations (mutually exclusive, exactly one required):

```nohighlight
--renumber Strip any existing markers, then insert fresh ones at
             the current paragraph counts (use this any time the
             text has changed since markers were last inserted).
--denumber Strip existing markers and leave the prose clean --
             this is what you run before your own further editing,
             or before a mirror/diff pass, so markers never get
             treated as real content.

```

Scope (mutually exclusive, optional – default is the whole manuscript):

```nohighlight
(none) Entire Manuscript/Draft subtree (--manuscript-only
                     walk, same root scriv_mirror.py uses by default).
--regex PATTERN Match PATTERN (re.search) against each item's
                     Path, as scriv_walk.py reports it (relative to
                     the Manuscript root).
--folder REL/PATH Restrict to this one folder, relative to the
                     Manuscript root, and everything nested under it
                     (exact path or a '/'-prefixed descendant).

```

Markers are matched/stripped by their own fully-deterministic literal  
RTF structure (MARKER\_GROUP\_RE below) – see the note further down for  
why this replaced an earlier hidden-sentinel design.

Paragraph counting walks the raw RTF bytes tracking brace depth.  
CONFIRMED by byte-level inspection of a real Scrivener content.rtf  
(Dart, 2026-09): scenes contain NO literal \par at all – every  
paragraph break is written as Scrivener/Cocoa’s own shorthand, a bare  
backslash immediately followed by a raw newline. Both forms are  
recognized as paragraph breaks; only a top-level (brace depth == 1)  
occurrence counts, so one inside a nested group (footnote text, an  
embedded picture/object, etc.) is not a scene-paragraph break and is  
deliberately excluded.

RTF tables (\trowd … \row) are NOT brace-nested – a table row’s  
cells sit at the same depth as ordinary body text, so a paragraph  
break inside a cell would otherwise be miscounted as a real one and  
could land a marker in the middle of a row. Table ranges are detected  
separately (matching \trowd starts to their \row ends) and anything  
inside one is excluded from both the count and the set of valid  
insertion points.

Scrivener inline annotations are ALSO confirmed (same real-file  
inspection) to be excluded from the count, but for a different reason  
than tables: they are not real RTF groups either. Scrivener encodes  
them as literal ESCAPED text – { and \ (an escaped brace, an  
escaped backslash) rather than real { } grouping – so they sit at the  
same brace depth as surrounding prose and get no protection from the  
depth check above. A multi-paragraph annotation was confirmed to use  
the same backslash+newline shorthand internally as real prose, so  
without an explicit text-pattern exclusion its internal breaks would  
be miscounted, and a marker could end up spliced into the middle of  
the annotation’s own literal text field.

Marker insertion restates whatever paragraph formatting (alignment,  
indentation) was actually active at the insertion point, rather than  
resetting to RTF’s bare spec default. This matters because RTF’s  
group-scoping is asymmetric: character formatting reverts  
automatically when a {…} group closes, but paragraph formatting does  
not. A first real sample showed a scene relying on a single \pard  
declared once, never restated per paragraph – in that case, without  
this restoration, the marker’s own centering would silently bleed  
forward into every subsequent paragraph. A second real sample (Dart,  
2026-09) showed the OPPOSITE convention is also real: Scrivener  
restates a full \pard, including a completely different \tx tab-stop  
layout, on a single paragraph that had its own character style applied  
by hand – interleaved with literal \<$Scr…\> pagination/style-state  
tags (see scriv\_common.py’s own OUTPUT\_TEXT\_FIXES, which strips these  
from unrtf’s plain-text output; they’re inert here, since they contain  
no backslash or brace and can’t be mistaken for RTF structure). The  
lookback approach handles both conventions without needing to assume  
either: it always captures whatever \pard actually governed the  
PRECEDING paragraph, so when the following paragraph already restates  
its own (as in the second sample), the restored text is simply a  
harmless, immediately-overridden redundant \pard – never a  
correctness problem, just a few wasted bytes.

Markers are matched/stripped by their own fully-deterministic literal  
RTF structure (see MARKER\_GROUP\_RE) rather than a separate hidden-text  
sentinel – an earlier draft used RTF’s standard \v (hidden text) for  
that, but Scrivener choosing to invent its own escaped-text tag scheme  
for its OWN internal metadata, rather than trusting \v, is a strong  
signal \v may not reliably render as hidden in Scrivener’s own reader.  
Since the marker’s exact bytes are already fully known and controlled,  
no separate sentinel is needed.

Safety, per Dart’s spec:  
–dry-run List files that would be affected – Type,  
Path, and (for --denumber) how many existing  
markers were found, or (for --renumber) how  
many would be stripped and how many freshly  
inserted. No files are touched. Read-only, so  
this does NOT check Files/user.lock – safe to  
run while the project is open in Scrivener.  
(default) After listing the same summary, ask for  
y/n confirmation before writing anything.  
–no-confirm Skip that prompt and write immediately.  
–ignore-lock-check Skip the Files/user.lock check (see below) on  
an actual (non-dry-run) write. Off by default  
– this check exists specifically because Dart  
routinely has several Scrivener projects open  
at once, so it checks THIS project’s own lock  
file, not whether Scrivener itself is running.

Diagnostics (read-only, never touch content.rtf or check the lock  
file, usable alone or alongside --renumber/–denumber):  
–title Print what Scrivener would DISPLAY as each in-scope  
item’s title – its binder if manually set,  
else the RTF-derived fallback (the same value  
scriv\_walk.py uses to build Path).  
–binder Print the RAW binder XML value with nothing  
filled in – items with none print ‘(not set)’,  
revealing which ones rely on the RTF fallback that  
–title shows instead.  
–debug-dir DIR  
Copy each in-scope content.rtf into DIR, named by  
UUID, so a flat set of sample files can be pulled and  
shared without digging through Files/Data//.

Files/user.lock existing inside a .scriv package is exactly how  
Scrivener itself detects “this project is already open elsewhere” (see  
Literature & Latte’s own support notes) – its presence here means the  
project is very likely open right now in Scrivener, actively  
autosaving, which is exactly the condition under which we must not  
also be rewriting content.rtf out from under it. No separate .bak  
backup is written before modifying – Scrivener’s own snapshot/backup  
on close already covers this.

Usage:  
python3 scriv\_marker.py Rebel --renumber --dry-run  
python3 scriv\_marker.py Rebel --renumber --folder Volume\_2/Confession  
python3 scriv\_marker.py Rebel --denumber --regex ‘May\_1967/.\*’ --no-confirm  
python3 scriv\_marker.py Rebel --title --binder --folder Volume\_2/Confession  
python3 scriv\_marker.py Rebel --debug-dir /tmp/scriv\_samples --regex ‘Scene\_(One|Two)’

Part of the scriv\_\* toolset (scriv\_walk.py, scriv\_mirror.py,  
scriv\_history.py, scriv\_report.py, scriv\_marker.py), sharing common  
logic via scriv\_common.py.

positional arguments:  
project Project name, .scriv dir, or .scrivx path, same as the  
other scriv\_\* tools accept.

options:  
-h, --help show this help message and exit  
-v, --version show program’s version number and exit  
–scriv-dir SCRIV\_DIR  
–walker-path WALKER\_PATH  
Path to scriv\_walk.py (default: same directory as this  
script)  
–renumber Strip any existing markers, then insert fresh ones.  
–denumber Strip existing markers, insert nothing.  
–repair One-time cleanup for files already damaged by a fixed  
pre-1.4 bug (repeated redundant \pard blocks /  
truncated ’ hex escapes from renumbering the same  
file many times before the fix). Not needed on files  
that never hit that bug – run --dry-run first to see  
if anything is found.  
–regex REGEX Restrict to items whose Path (relative to the  
Manuscript root) matches this regex.  
–folder FOLDER Restrict to this one folder and everything nested  
under it, given relative to the Manuscript/Draft root  
– e.g. ‘Chapter\_One’ or ‘Chapter\_One/Scene\_One’,  
WITHOUT repeating the root’s own title.  
–every EVERY Insert a marker after every N paragraphs (default: 5)  
–width WIDTH Zero-padded digit width for the paragraph number  
(default: 3)  
–color COLOR Marker text color as R,G,B (default: 100,100,100)  
–dry-run List affected files and counts; write nothing.  
–no-confirm Skip the confirmation prompt and write immediately.  
–ignore-lock-check Skip the Files/user.lock open-project safety check  
(only consulted on an actual write, never on --dry-  
run).

diagnostics:  
Read-only inspection – never touch content.rtf, never check the lock file, safe to run any time. Usable alone or alongside --renumber/–denumber.

–title Print what Scrivener would DISPLAY as each in-scope  
item’s title – its binder if manually set,  
else the RTF-derived fallback title (same value  
scriv\_walk.py uses to build Path).  
–binder Print the RAW binder XML value for each in-  
scope item, with nothing filled in – reveals which  
items have no manually-set title at all (those print  
‘(not set)’) as distinct from --title’s  
resolved/fallback value.  
–debug-dir DIR Copy each in-scope content.rtf into DIR, named by UUID  
(e.g. DIR/.rtf) – makes it easy to pull a flat  
set of sample files to inspect or share, without  
digging through Files/Data//. Read-only: the  
project’s own files are never touched.

---

<div class="post-metadata">

**Author:** ![kewms](https://forum.literatureandlatte.com/user_avatar/forum.literatureandlatte.com/kewms/32/15720_2.png) [@kewms](https://forum.literatureandlatte.com/u/kewms)\
**Post date:** [September 23, 2026, 4:22am UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717/2 "2026-09-23T04:22:21Z")

</div>

FYI, the Compile command has an option to insert links back to the corresponding Scrivener document in each section. They’ll be working links in document formats that support them, and will also transform into live document links if imported back into Scrivener.

You’ll find the option under the “gear” icon, in the right hand pane of the main Compile screen.

---

<div class="post-metadata">

**Author:** ![GoalieDad](https://forum.literatureandlatte.com/user_avatar/forum.literatureandlatte.com/goaliedad/32/28584_2.png) [@GoalieDad](https://forum.literatureandlatte.com/u/GoalieDad)\
**Post date:** [September 23, 2026, 7:06am UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717/3 "2026-09-23T07:06:24Z")

</div>

Wow always learn something new in the Forums.

---

<div class="post-metadata">

**Author:** ![Dart](https://forum.literatureandlatte.com/letter_avatar_proxy/v4/letter/d/7bcc69/32.png) [@Dart](https://forum.literatureandlatte.com/u/Dart)\
**Post date:** [September 23, 2026, 4:05pm UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717/4 "2026-09-23T16:05:53Z")

</div>

That doesn’t help.

A: Looks like there are two separate features: Auto-number, and link-back. Auto-number means I have to place links everywhere. Link-back seems to create one link in the compiled document for each section. This isn’t enough.

At this point I can close the project, run the command, open the project in under a minute, and I have all 240 scenes numbered or renumbered throughout my entire project. Or I can do a subset.

B: But in the scivener document it shows up as a auto-number link for the auto-number stuff. with a variable that is evaluated at compile time. It doesn’t show up AS A NUMBER.

OR From reading the pop up on this option, the granularity is the section/document. I need something at the paragraph level. E.g.

I pass a 6000 word chapter to someone. A comment could read something like, “Late in the chapter Chris repeats pretty much what he said earlier on.

Instead with some form of coordinates, this can become. Chris at P221 seems to be making the same point as at P60

It means I can export as text, run MY grammar/spelling/punctuation correction, and get an accurate list to enter my own corrections. (Apple’s built in systems seem to fix about 2/3 of them, and a good fraction of those are wrong, or are correction a legimate word, or a name to something else, and THOSE can’t be spotted later.)

C: I need a system where I can send a NON-Scriverer format that has periodic labels.

AND

Those identical labels are present in my scrivener document, at a scale no further apart than every five paragraphs.

---

<div class="post-metadata">

**Author:** ![kewms](https://forum.literatureandlatte.com/user_avatar/forum.literatureandlatte.com/kewms/32/15720_2.png) [@kewms](https://forum.literatureandlatte.com/u/kewms)\
**Post date:** [September 23, 2026, 5:41pm UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717/5 "2026-09-23T17:41:25Z")

</div>

> [@Dart](#):
>
> OR From reading the pop up on this option, the granularity is the section/document. I need something at the paragraph level. E.g.

The Scrivener answer is to make your sections smaller. You can always merge them once you’re past this phase.

---

<div class="post-metadata">

**Author:** ![Dart](https://forum.literatureandlatte.com/letter_avatar_proxy/v4/letter/d/7bcc69/32.png) [@Dart](https://forum.literatureandlatte.com/u/Dart)\
**Post date:** [September 23, 2026, 8:30pm UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717/6 "2026-09-23T20:30:17Z")

</div>

You are suggesting that I make 5 sections per page of output? I want to look at someone’s scribbles, see Para 42, and be able to find Para 42. quickly. Not scanning down even one full page. I want to be able to hit command f enter 042, and hit next and find the only 042 in the document. I want to be able to slide the scroll bar a third down, see that the para marker in that screen is 025, and know I need to go about 1/6 down to find it.

In my post the screenshot shows a screenshot with two markers showing up. That is with interval 5. That is about the maximum amount of text I want to scan for a location. The number of paragraphs for renumbers is an internal variable in my program. If I routinely worked in 10 line paragraphs, I’d change 5 to 2 or even 1.

I tried this once: I exported file as text, corrected it. then it took me longer to transfer the corrections back, and most of that longer was, “find the paragraph that starts with ‘she ate pickles’”

I make software adapt to me. I push back hard adapting to the software.

Suppose I did what you want. Then to submit, I have to follow the publisher’s mandate and make 1 word file per chapter. Then when I want to work on the project again I have to break it back apart into sections.

No. I need a coordinate system that in intersystem operable. Scriverer doesn’t have it. I’m bolting a thousand line program kludge bolt on to give me that functionality.

Over and over in these files people say, “Do your writing in sciriverner. Do your format and presentation and publisher’s editing somewhere else.

no, No, and NO.

The nature of the stuff I write is that it goes through versions. E.g. I had a outdoor program manual that went through 4 major versions and 25 minor versions over 6 years. It’s not going to word, for formatting. Havi the original changed, then REFORMAT in word. Then get a minor uipdate, then REFORMAT in word.

Word is a PITA. Any publisher who wants substantial changes in word, can look for another author.

I write in one app. I love scrivener for many reasons. I can work on 100 documents in the course of a day. I can easily find all the documents that have Aardvark and Badger or I can find documents that have Aard\* _or_ \*vark.

Scrivener has big holes. I has crap support for presentation. It’s handling of tables sucks. It’s handling of illlustrations is awful.

There is a place for L&L to create a formatting engine that udnerstands Skrivener’s quirks. Or an add on module for it.

Meanwhile, I build tools that enable me to collaborate.

---

<div class="post-metadata">

**Author:** ![GoalieDad](https://forum.literatureandlatte.com/user_avatar/forum.literatureandlatte.com/goaliedad/32/28584_2.png) [@GoalieDad](https://forum.literatureandlatte.com/u/GoalieDad)\
**Post date:** [September 23, 2026, 11:39pm UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717/7 "2026-09-23T23:39:18Z")

</div>

Why not have editor reader with an issue could put xx to indicate an issue then if say repeat yourself in scene war, then search xx in project search find first instance then second. Xx can make marking text issues precisely.

---

<div class="post-metadata">

**Author:** ![suavito](https://forum.literatureandlatte.com/user_avatar/forum.literatureandlatte.com/suavito/32/15787_2.png) [@suavito](https://forum.literatureandlatte.com/u/suavito)\
**Post date:** [September 24, 2026, 4:18am UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717/8 "2026-09-24T04:18:10Z")

</div>

> [@Dart](#):
>
> Any publisher who wants substantial changes in word, can look for another author.

Great that you’re in a position to choose publishers.

---

<div class="post-metadata">

**Author:** ![Dart](https://forum.literatureandlatte.com/letter_avatar_proxy/v4/letter/d/7bcc69/32.png) [@Dart](https://forum.literatureandlatte.com/u/Dart)\
**Post date:** [September 24, 2026, 4:20am UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717/9 "2026-09-24T04:20:01Z")

</div>

Really, you aren’t? How come?

---

<div class="post-metadata">

**Author:** ![Dart](https://forum.literatureandlatte.com/letter_avatar_proxy/v4/letter/d/7bcc69/32.png) [@Dart](https://forum.literatureandlatte.com/u/Dart)\
**Post date:** [September 24, 2026, 4:21am UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717/10 "2026-09-24T04:21:34Z")

</div>

Because Editor Reader putting XX in his word document doesn’t put XX in MY scrivener document.

---

<div class="post-metadata">

**Author:** ![suavito](https://forum.literatureandlatte.com/user_avatar/forum.literatureandlatte.com/suavito/32/15787_2.png) [@suavito](https://forum.literatureandlatte.com/u/suavito)\
**Post date:** [September 24, 2026, 4:31am UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717/11 "2026-09-24T04:31:22Z")

</div>

Because I’m neither a best (or even good) selling author who can pick his publishers nor am I a hobbyist who has other sources of income.

---

<div class="post-metadata">

**Author:** ![GoalieDad](https://forum.literatureandlatte.com/user_avatar/forum.literatureandlatte.com/goaliedad/32/28584_2.png) [@GoalieDad](https://forum.literatureandlatte.com/u/GoalieDad)\
**Post date:** [September 24, 2026, 5:05am UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717/12 "2026-09-24T05:05:48Z")

</div>

If you import the document back into a fresh document then you could track the xx the reader put to mark his issues. as you fix then you replace the document in the original novel project. Again this is a workflow idea and it either makes sense to you or not.

---

<div class="post-metadata">

**Author:** ![Dart](https://forum.literatureandlatte.com/letter_avatar_proxy/v4/letter/d/7bcc69/32.png) [@Dart](https://forum.literatureandlatte.com/u/Dart)\
**Post date:** [September 24, 2026, 8:37pm UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717/13 "2026-09-24T20:37:21Z")

</div>

Yeah, I could do that. That’s actually a good idea.

What I haven’t figured out: a way where I can give them a file, and I can get back a copy edited file that I can use in scrivener directly, without having to reapply all my formatting.

You have experience what scrivener does with “track changes” and “comments” from word or word produced rtf?

It does NOT seem to work with PDF, but then not much does. The manual claims it does. But perhaps this counts as media and cannot be imported into the draft folder.

I prefer paragraph numbers, as it makes phone collaborating possible, as well as lists of issues.

I’m not confident in Scrivener’s ability to import other doc formats in anything like a readable format. I’ve tried with one doc file. It pretty much deformats it. I’d like to

The manual claims that it’s best to export from the word processor doc as rtf.

---

<div class="post-metadata">

**Author:** ![kewms](https://forum.literatureandlatte.com/user_avatar/forum.literatureandlatte.com/kewms/32/15720_2.png) [@kewms](https://forum.literatureandlatte.com/u/kewms)\
**Post date:** [September 24, 2026, 11:00pm UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717/14 "2026-09-24T23:00:02Z")

</div>

Scrivener can import Word’s comments, but not Track Changes markup. It should otherwise do a reasonable job of DOCX import. If it doesn’t for you, the support team would be happy to see a test file.

Yes, that’s correct, a PDF can’t go in the Draft folder.

---

<div class="post-metadata">

**Author:** ![Dart](https://forum.literatureandlatte.com/letter_avatar_proxy/v4/letter/d/7bcc69/32.png) [@Dart](https://forum.literatureandlatte.com/u/Dart)\
**Post date:** [September 25, 2026, 2:34pm UTC](https://forum.literatureandlatte.com/t/script-for-aiding-round-trip-with-collaborators-editors/154717/15 "2026-09-25T14:34:28Z")

</div>

That’s too bad. Makes it harder to review changes that an editor makes. Means I have to view in word.
