Skip to content

Cut the README from 1534 to 531 lines, and make --help the command reference - #145

Merged
willkg merged 15 commits into
mainfrom
readme-slim
Sep 12, 2026
Merged

Cut the README from 1534 to 531 lines, and make --help the command reference#145
willkg merged 15 commits into
mainfrom
readme-slim

Conversation

@willkg

@willkg willkg commented Sep 12, 2026

Copy link
Copy Markdown
Member

README.md was 1534 lines. It is now 531 — a 65% cut with nothing deleted that wasn't duplicated elsewhere, better placed elsewhere, or already available from the binary. Fixes #102.

The shape it converges on: the README is a 50,000-foot view of what markfluence can do and which command to reach for. It is not a command reference — that is what markfluence CMD --help is for. Keeping both meant keeping both in step, which is the failure this issue was really about.

Where the lines were

Measured first, because the distribution mattered more than the total:

section before after
## Usage — per-command reference 832 200
## Markdown page structure 333 24
## Configure 141 105
everything else 228 202

--help becomes the reference

Cobra has an Example field for worked invocations and no command used it — the README was carrying content the binary had a dedicated, empty slot for. Every command now has one, and the Long descriptions absorbed what only the README said: create's page_id-that-resolves-to-nothing being a failure rather than a fresh page; update's never writing back, which is why fixing a wrong id is always safe; fix's canonical key order; read's lossy transforms making it a reading aid rather than a guaranteed round-trip.

## Usage is now which command to reach for, three common workflows, and the three output shapes worth seeing before you run them (children's indented tree, find's current/archived/folder split, search's hit blocks).

docs/commands/ is that help text rendered by cobra's own doc generator, so the reference is browsable and linkable on GitHub without installing anything. Generated and checked in — which is a second copy, and only acceptable because it cannot drift: make docs-check regenerates into a temp dir and diffs, and runs inside make check, the same role fmt-check plays for formatting. DisableAutoGenTag, or a timestamp would make every regeneration a diff and turn the guard into noise.

TestSubcommandsDocumentThemselves closes the loop. Once --help is the reference, a command added with a one-line Long and no Example is documented nowhere and nothing else would notice. It requires a length floor rather than non-empty, since "Create pages." satisfies non-empty and explains nothing.

What moved out

lines why there
docs/markdown_file.md 356 the page format — every frontmatter field and every body construct. These were two halves of one reference split across two files, and the moved half's intro had to say so
docs/json-output.md 82 the per-command --json detail. The schema is the authoritative contract but cannot carry reasoning — why check's broken has no error/code, why find/search report failures on stderr rather than as a result
docs/github-actions.md 79 a task you follow once while wiring up CI

What was deleted as duplication

### Scoped tokens carried a second copy of docs/confluence/api.md's scope material, and the README was the lossier copy — 3 occurrences of granular scope names against api.md's 12. A live drift risk, not a theoretical one: #91 required updating the README's scope table and code review caught that a row had been missed.

## Development duplicated CONTRIBUTING.md line for line, then ended by linking to CONTRIBUTING.md for the rest — the duplication was its own argument. It became a pointer, then went away once CONTRIBUTING.md earned a row in the index table.

Three command sections repeated their own --help almost verbatim before the wholesale move.

Structure

A "Location of documentation" table instead of a hand-written TOC. GitHub already renders an outline for any markdown file, so a TOC duplicates it and becomes one more thing to update — precisely the rot that made the scope table wrong. What GitHub's outline cannot index is the other files, and "where is the thing about X" is the actual question.

### Moving files and assets moved under ## The documentation root. It was top-level and next to "Common workflows" while being a different kind of thing: no commands in it at all, every entry a consequence of the root and identity model that section establishes.

Three things worth flagging

My estimate for the --help de-duplication step was wrong. I projected ~300 lines on #102 from "227 lines of --help prose exist" — which conflated existing with being duplicated. Hand-trimming three sections yielded 45. What actually delivered was moving the reference wholesale and letting --help own it.

Testing the drift guard found two bugs in it. make docs silently did nothing, because docs/ is a real directory and make considered the target satisfied — a missing .PHONY. Without sabotaging it deliberately I would have shipped a regenerate target that never regenerates. The failure message also needed to name the file.

A claim in the fix workflow was wrong and I checked rather than trusted it. A draft said fix adopts a page somebody "labeled or retitled" in the UI. plannedChanges fills title only when the frontmatter's is missing or blank, so a renamed page does not rename your frontmatter. The README now says that outright, because "reconciles the file to the page" invites exactly that assumption.

Also here

cmd.Root() is newly exported, for the docs generator alone — a main() inside package cmd would be built into the binary, and a _test.go that writes files into the repo is not a test. That is new public surface for a tooling concern, and worth a look.

CONTRIBUTING.md no longer asks a bug reporter which Confluence flavour they are on "since the API differs" — markfluence now states Data Center is unsupported, so asking invites a report we have said we cannot act on.

Docs and help text only — no behaviour change, and make check passes at every commit.

The largest single subsection of the README (243 lines, 16% of the file) was a
construct-by-construct reference for what the converter does with each markdown
element. Nobody reads that top to bottom; they look one construct up. Moved
verbatim to docs/markdown.md, where docs/confluence/ and docs/guarantees.md
already live.

The README keeps a short pointer naming what is supported and what is lossy,
which is what a reader skimming it actually needs.

Content moved unchanged on purpose. Retitling or restructuring it in the same
commit would make the diff unreviewable as a move, and the bold run-in headings
it uses are worth revisiting separately -- 240 lines under one heading is not
much more navigable than it was in the README.

Five README anchors pointed into the moved section (#body) and now point at the
new file. Part of #102.
The scopes section carried a second copy of docs/confluence/api.md's scope
material, and the README was the lossier copy -- 3 occurrences of granular scope
names against api.md's 12. It was a live drift risk rather than a theoretical
one: #91 required updating the README's per-command scope table, and code review
caught that a row had been missed.

Kept what somebody configuring a token needs at hand: when a cloud ID is
required and why, how to find it, the copy-pasteable scope list, that scopes are
fixed at issue time, that the mixed vocabularies are deliberate, and a 401-vs-403
table -- which is the one genuinely actionable diagnosis and was buried in prose
before.

Dropped what api.md owns and covers in more depth: the per-command scope table
(which scope each call needs, with provenance), the full classic/granular
explanation, and the token-probing recipe -- api.md has that with the story of
how the first scoped service-account token's missing scope was found.

92 lines to 57. Part of #102.
A hand-written TOC would duplicate something GitHub already renders -- the
outline button on any markdown file -- and would become one more place to update
when a section is added. That is the failure mode the two previous commits
removed: the scope table rotted because it was a second copy.

What GitHub's outline cannot do is index the other files, and "where is the
thing about X" is the actual question, with X often living in docs/markdown.md
or docs/confluence/. So this points across the doc set rather than mirroring
this file's own headings, and names --help as the authoritative per-command
description. Top-level entries are stable enough not to rot.

Part of #102.
Each command's cobra long description already carries its reasoning, and these
three repeated it nearly verbatim -- children's "a folder can hold the only
pages in a subtree" and "a folder counts as a level", search's ANDing and
archived-pages-are-invisible, export's --depth and --space walks. Removed from
the README, which now points at `markfluence COMMAND --help` for the why.

Kept what --help cannot carry and a reader genuinely wants: example
invocations, sample output, and the details that are not in the help text
(search's excerpt highlighting, export's markfluence.yaml and the absent
--attachments-dir, children's output alignment and the stderr depth hint).

78+88+77 = 243 lines down to 198.

Worth recording that this is less than claimed: the estimate on #102 was ~300
lines for this step across all commands, derived from 227 lines of --help prose
existing. That conflated "help prose exists" with "the README duplicates it".
These were the three most duplicative sections and they yielded 45 lines, so the
remaining ten are worth perhaps 40 more, not 250. Part of #102.
The --json section was 124 lines, the second-largest in the file, and most of it
was a field-by-field walkthrough: per-command status verbs, what counts as one
result for each command, check's broken semantics, create's preflight abort,
search's summary extras.

Moved rather than deleted, which is what #102 originally proposed. The schema at
schema/json-output/v1.json is the authoritative contract and a test validates
real output against it, but the schema cannot carry the *reasoning* -- why
check's broken status has no error/code (its broken/warnings arrays already say
everything), why find and search report an operational failure on stderr rather
than as a result (an empty results array would be worse, since "no matches" is
an answer a caller acts on). That belongs somewhere, just not in the README.

The README keeps what a script author needs at hand: what --json is, a jq
example, the worked envelope, and the exit codes -- now a table rather than
prose, since which of 0/1/2 you get and whether an envelope is on stdout is the
most actionable thing in the section and was the hardest to find.

124 lines to 73, with 71 moved. Part of #102.
The README's Development section duplicated CONTRIBUTING.md line for line --
Go 1.25+, make build/test/check, "run make with no target", and putting a .env
in the working directory were all already over there, several with more detail.
It ended by linking to CONTRIBUTING.md for the rest, which made the duplication
its own argument.

Now a pointer that names what is over there, so a reader can tell whether to
click.

Also removes a claim CONTRIBUTING.md should no longer make: it asked a bug
reporter to "say which Confluence flavor you're on (Cloud or Data Center), since
the API differs". markfluence now states that Data Center is unsupported, so
asking would invite a report we have already said we cannot act on.

Includes uncommitted wording and formatting edits to the Configure and scopes
sections that were already in the working tree -- not mine, carried along rather
than reverted.

Part of #102.
Retitled to "Using with GitHub Actions", which says what it is rather than
naming a product, and moved out of the README: it is a task somebody follows
once while wiring up CI, not something a reader of the README needs in front of
them.

The README keeps a pointer naming what is over there -- a working workflow,
credential storage, and the service-account argument -- so a reader can tell
whether to click.

Its two cross-references into the README (scoped tokens, --json output) now
point back at ../README.md, and its opening paragraph loses the sentence the
README's pointer now carries, keeping only the fact a reader needs: you have to
know each page's page_id.

75 lines out of the README, which is now 1108 -- down from 1534 when #102 was
picked up. Part of #102.
The file arrived as one "Supported constructs" section with bold run-in
headings, which meant 240 lines under a single heading and nothing for GitHub's
outline to show -- not much more navigable than it was inside the README.

Now eleven headings, with the three table topics nested under Tables since that
is the actual structure: fenced code blocks, tables (cell background colors,
multi-line cells, lists in cells), GitHub alerts, images, links to other pages,
comment directives, and raw storage format.

Also fixes two links this file's own move broke. Both "(#the-documentation-root)"
anchors pointed at a README section that stayed in the README, so they resolved
to nothing here -- when the section moved I checked the README's anchors
pointing *in* and not this file's pointing *out*.

Three dangling GFM reference links folded into the sentences they belong to,
where they had been left stranded at the end of a paragraph by the original
prose style.
A mention is a body construct, the same as an image or a link, so it belongs
with the others. Two signs it was misplaced: it sat under "Markdown page
structure" immediately beside *frontmatter*, and docs/markdown.md already
referred to mentions in passing -- "a mention, an attachment link, or an
external URL was never meant to resolve here" -- while not documenting them.

Placed directly after "Links to other pages", because a mention *is* a link
form and the two explain each other: that section's closing sentence now hands
off to it rather than naming a construct the reader has no section for.

The README's Body pointer names mentions and the table-cell conventions, so a
reader skimming it knows those are covered rather than missing.

README 1109 -> 1072, down from 1534 when #102 was picked up. Part of #102.
The file was the body half of a reference whose other half -- the frontmatter
block -- was still in the README, and its intro had to say so. Both halves now
live together: what a markfluence markdown file is, every frontmatter field and
what each verb does with it, then every body construct.

Named markdown_file.md rather than markdown_page.md because the subject is the
file. A reader has one open in their editor and wants to know what goes in it;
the page is the result, and the doc's own first line is "each Markdown file is
one Confluence page".

Headings nest to match: Frontmatter and Body as the two halves, with the
constructs under Body. Body as a *peer* of Tables read wrong -- the constructs
are the body.

The README keeps the shape (the annotated example block, which is what somebody
skimming wants) plus a pointer. 66 lines to 24; README 1074 -> 1032, down from
1534 when #102 was picked up. Part of #102.
@willkg willkg changed the title Cut the README from 1534 to 1025 lines Cut the README from 1534 to 1016 lines Sep 12, 2026
@willkg willkg changed the title Cut the README from 1534 to 1016 lines Cut the README from 1534 to 1017 lines Sep 12, 2026
Every command now carries its own reasoning and a worked Example block, so
`markfluence CMD --help` answers what it does, why, and how to invoke it. Cobra
has an Example field for exactly this and **no command used it** -- the README
was carrying content the binary had a dedicated, empty slot for.

The Long descriptions absorb what only the README said: create's page_id-that-
resolves-to-nothing being a failure rather than a fresh page and what a run
interrupted after the reserve phase leaves behind; update's never writing back
(so fixing a wrong id is always safe) and the mtime skip; fix's canonical key
order and that labels are reconciled even for a file with no labels: line; read's
lossy transforms making it a reading aid rather than a guaranteed round-trip;
info's omitted-empty-fields rule.

Also adds TestSubcommandsDocumentThemselves, which is what makes --help usable
as *the* reference rather than one of two places. The move creates a new way to
regress -- a command added with a one-line Long and no Example would be
documented nowhere and nothing would notice -- so the test requires both. A
length floor rather than non-empty, since "Create pages." satisfies non-empty
and explains nothing.

The README still duplicates much of this; that comes out next. Part of #102.
…commands/

## Usage was 736 lines of per-command reference. It is now 200: which command to
reach for, a typical workflow in both directions, and the three output shapes
worth seeing before you run them (children's indented tree, find's three-way
current/archived/folder split, search's hit blocks). Everything else moved into
the commands themselves in the previous commit.

The README should be a 50' view of what markfluence can do and which command is
used for what. It should not be a command reference -- that is what
`markfluence CMD --help` is for, and keeping both meant keeping them in step,
which is the failure this issue has been unwinding.

docs/commands/ is that help text rendered to markdown by cobra's own doc
generator, so the reference is browsable and linkable on GitHub without
installing anything. Generated and checked in, which is a second copy -- and
only acceptable because it cannot drift: `make docs-check` regenerates into a
temp dir and diffs, and it runs inside `make check`, the same role fmt-check
plays for formatting. DisableAutoGenTag, or a timestamp would make every regen
a diff and turn the guard into noise.

cmd.Root() is exported for the generator alone. A main() inside package cmd
would be built into the binary, and a _test.go that writes files into the repo
is not a test.

Two things the sabotage test of the guard caught, which is the argument for
testing a guard rather than trusting it: `make docs` silently did nothing,
because docs/ is a real directory and make considered the target satisfied
(missing .PHONY); and the diff output needed to name the file, or "out of date"
tells you nothing about what to look at.

README 1017 -> 481, from 1534 when #102 was picked up. Part of #102.
Two changes to the README's narrative sections.

**A fix workflow.** fix is the only command whose direction is opposite to every
other -- it writes to your files from Confluence -- and nothing demonstrated it,
which makes it the command most likely to surprise somebody later. Shows the
--dry-run first, since "what disagrees?" is the question you actually have, and
names the asymmetry it settles: update leaves a field alone when your file does
not mention it, while fix fills that field in from the page.

It also states what fix does *not* do. A first draft of this said fix adopts a
page somebody "labeled or retitled" in the UI. Checking the code rather than
trusting the sentence: plannedChanges fills a title only when the frontmatter's
is missing or blank, so a page renamed in Confluence does not rename your
frontmatter. Worth saying outright, because "reconciles the file to the page"
invites exactly that assumption.

**Common tasks becomes ### Moving files and assets, under The documentation
root.** It was a top-level section sitting next to "Common workflows" while
being a different kind of thing entirely: it contains no commands at all, and
all its entries are consequences of the root and identity model the section
above establishes -- which is what made the two similar names confusing. Now it
reads as the consequences half of that section, and is titled for what it is.

Its fourth entry is dropped. "Setting up a shared assets directory needs a
markfluence.yaml at the shared root" restated what the root section says two
paragraphs above it.
@willkg willkg changed the title Cut the README from 1534 to 1017 lines Cut the README from 1534 to 531 lines, and make --help the command reference Sep 12, 2026
@willkg
willkg merged commit b2fb467 into main Sep 12, 2026
1 check passed
@willkg
willkg deleted the readme-slim branch September 12, 2026 18:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

README.md is getting too long to navigate — split it up

1 participant