Skip to content

docs: reorganize the documentation around reader intent - #3016

Open
vmaerten wants to merge 21 commits into
mainfrom
docs/redesign-whole-site
Open

docs: reorganize the documentation around reader intent#3016
vmaerten wants to merge 21 commits into
mainfrom
docs/redesign-whole-site

Conversation

@vmaerten

@vmaerten vmaerten commented Sep 3, 2026

Copy link
Copy Markdown
Member

Summary

guide.md had grown to 2950 lines and 27 sections.
I tried to split it to make to more readable. I'll also edit our Algolia crawler to have better suggestion

The guide had grown to 2950 lines and 27 sections, a fifth of the whole
documentation in one file, and it was where every new feature ended up.
Each section is now its own page.

Two sections were rearranged rather than moved verbatim. "Prevent
unnecessary work" covered two different questions - whether the work is
already done (fingerprints, status) and whether it should happen at all
(preconditions, if, requires) - so it becomes three pages. "Running a
remote Taskfile" is dropped entirely: its prose, its danger admonition
and its three samples already appeared word for word in the Remote
Taskfiles page.

Every other heading keeps its exact text, so section anchors still
resolve; only the page they live on changed.
/docs/guide keeps its URL and becomes a grouped index of the pages the
guide was split into, so the many links to it in issues, blog posts and
Stack Overflow answers still land somewhere useful.

Their fragments need more than that. Netlify never receives the part of
a URL after the #, so a _redirects rule cannot route an anchor;
GuideRedirect.vue reads location.hash and resolves it in the browser
against a table of the 72 anchors the old page defined. Every entry was
checked against the anchors VitePress actually emits.
/docs was not a page: a Netlify rule caught it and sent visitors to
/docs/guide, so the section had no entry point of its own for the nav,
the sitemap or llms.txt to point at.

It is now a short hub that routes by intent - install it, learn it, look
something up, keep up - rather than a second copy of the sidebar. The
_redirects rule stays as it is: Netlify only applies an unforced rule
when no static file matches, so it goes quiet here while continuing to
serve the released channel, which has no such page yet.
Eight pages were missing a title, a description or both. The description
feeds two things at once: the meta tag the DocSearch crawler reads, and
the entry a page gets in llms.txt. Without one, a page is indexed and
listed with whatever text happens to come first.

Every page under docs/ now carries both.
Three conventions were in use: relative with .md, absolute without an
extension, and relative without one. Only the first is resolved and
verified by VitePress at build time, which makes it the only form that
cannot rot silently - and with no link checker in CI, that check is the
only one there is.

Also fixes two links that were already wrong: remote-taskfiles.md
reached for ../docs/reference from inside docs/, and the security
incident response plan pointed at ../security/ from inside security/.
Markdown link definitions are file-scoped. The three the guide used sat
at the very bottom of the file, inside the last section, so the split
handed all of them to watch.md - which uses none - and left
dependencies.md and variables.md rendering [`.taskrc.yml`][config] and
[templates][templating-reference] as literal text.

Each definition now lives on the page that uses it. [gotemplate] is
dropped: nothing referenced it, in the old guide either.
The nav is shared by both channels, so pointing Docs at /docs/ sent
taskfile.dev to a page that only exists on next until cmd/release
promotes it. The _redirects rule that used to catch this is written
/docs, without the trailing slash the nav emits, so it would not have
saved the link.
Chosen after building this grouping and a product-area one side by
side and comparing them on the rendered site.

The sidebar was a flat list of 16 entries in which contributor material
sat at the same level as user material. It is now five groups named for
what the reader is doing: Getting Started, Guide, Reference, Project,
Contributing. The guide pages move under /docs/guide/ so the URLs say
the same thing as the navigation.

Only the pages created by the split are moved. Everything else keeps its
URL, because src/public/_redirects is shared between the two channels
and any rule added here would take effect on the released site, which
still serves the old structure.

The DocSearch crawler puts the active sidebar section into
hierarchy.lvl0, so these five labels become the breadcrumbs on every
search result.
The guide says how to declare each kind of variable but never says which
one wins, and that is what people file issues about: seven of them are
about precedence or evaluation order, one titled "Documentation: Clarify
dotenv file precedence when multiple files are specified".

The page states the order once, and guide/variables.md now links to it
instead of carrying its own list. Two owners of the same rules would
drift, and nothing in CI compares the docs to the Go code.

Every claim was checked by running the built binary, not read off the
source. Three are worth calling out because they contradict what people
expect:

  - A task's own vars cannot be overridden from the command line;
    `task greet NAME=x` loses to a `vars:` on the task.
  - `vars:` on an `includes:` entry are defaults, not overrides: the
    included Taskfile's own `vars:` are applied after them and win.
  - Global variable names are shared across every Taskfile in a run, so
    a name declared in both the entrypoint and an included file resolves
    to the included one, even for entrypoint tasks.
Three issues ask about execution order (`the order of task under deps is
random`, `Glob-based matching and sequential or parallel execution`,
`Default concurrency`), and two of the four FAQ entries are really
questions about the execution model rather than about a procedure.

The guide is organised one feature per page, so nothing owns the part
that cuts across them: what runs together, what waits, and in which
order cleanup happens.

Behaviour verified by running the built binary: deps start together and
all finish before cmds; a task reference inside cmds runs at its
position; `run: once` collapses a shared dependency from two executions
to one; deferred commands run in reverse order of declaration.
vitepress-plugin-llms names its Markdown output by running the file
through VitePress's own `rewrites`. On the object form it matches
`<channel>/:path*`, gets `:path*` back as an array of segments, and
compiles it without separators - so every page landed at the root as
dist/docsreferencecli.md instead of dist/docs/reference/cli.md, and the
relative links inside them pointed nowhere.

Expressing the same rewrite as a function takes the plugin's other code
path and keeps the segments. The Markdown mirror is now addressable by
appending .md to a page's URL, which is what /llms.txt claims.

It also fixes the table of contents as a side effect: with paths that
match the sidebar again, llms.txt groups pages under their section
instead of listing all of them under a single "Other".
/agents is a compact map of the documentation plus the ten semantics an
agent is most likely to get wrong when writing a Taskfile: vars against
env, what deps guarantee, that each command gets its own shell, status
against preconditions, and the reverse order of defer.

Each claim was checked by running the built binary. Two of them are
counterintuitive enough to be worth stating outright - a task's own vars
cannot be overridden from the command line, and vars on an includes
entry are defaults rather than overrides.

Links are relative so VitePress checks them at build; they resolve the
same way for an agent reading the raw /agents.md.
The DocSearch crawler builds hierarchy.lvl0 - the breadcrumb shown on
every search result - from whichever sidebar link is active in the DOM.
That reads the navigation through the theme's markup, so it breaks
quietly on a theme upgrade and cannot be reviewed from this repo, where
the crawler configuration does not live.

Each page now states its own section and documentary type, and the
crawler can be pointed at meta[name="docsearch:section"] instead.

The frontmatter is derived from sidebar/next.ts rather than written by
hand, since the sidebar is what defines a section; the two cannot drift.
46 pages carry it. The only pages left without one are the two authoring
templates, which are already kept out of llms.txt and the sitemap.
The clean task removed ./vitepress/dist. The build writes to
./.vitepress/dist, with a leading dot, so the task has never deleted
anything since it was written.
"[Map Variables][map-variables]" had no matching definition, so it
rendered as literal text with the brackets showing. The post shipped
that way in 2024 and the same text is in both channels.

Map support has landed since, so the reference now points at the section
that documents it.
List entries of the form "[Link](x) — gloss" become "[Link](x): gloss".
Prose uses were rewritten one at a time, since the right replacement
depends on what the dash was standing in for: a colon before a list, a
comma around an aside, a full stop between two sentences.

Also removes the two that predate this branch, in the Nushell
completions note and the remote variables table.
Both snippets referenced tasks they did not define, so copying either
one and running it failed with "Task ... does not exist" and exit 201.
Every other example in the docs defines what it references.

The behaviour they describe was right; only the snippets were short.
Two claims were wrong, and one of them was dangerous.

The agent guidance said to keep credentials in `env:` and mark them
`secret: true` so they are masked. `secret: true` has no effect on
`env:` at all, and it never masks what a command itself prints -
testdata/secrets/Taskfile.yml has a case named for that limitation.
Following the advice would have produced Taskfiles that leak tokens into
CI logs while looking as though they did not.

The second claim was that a template sees any `env:` value. That holds
for `env:` at the root of the Taskfile, but a task's own `env:` is
assembled after the variable set is resolved, so `{{.FOO}}` renders
empty while `$FOO` works. Both pages now say which is which.
Two pages made a section of their own for subjects the guide already
owns, and gave Algolia a second set of records competing with Variables
and Dependencies for the same queries.

The resolution order, and what it means in practice, now sit in
guide/variables.md. Interleaved output, --concurrency, run: once and the
reverse order of defer join guide/dependencies.md. Nothing is dropped;
fail-fast and defer were already covered there and are not repeated.

Also quotes a command in the secret variables example. A plain YAML
scalar cannot contain ": ", so `curl -H "Authorization: {{.API_KEY}}"`
made the whole file unloadable - the example predates this branch and
was the only one of 115 Taskfile blocks in the docs that Task refuses to
parse. Quoted, it runs and prints the masked value the comment promises.
The crawler that fills the `taskfile` index has never been described
here: `git log --all -- '*algolia*' '*docsearch*'` returns nothing, so
the only copy lives in a web form. That is also why it still carries the
Docusaurus-era setup, years after the site moved to VitePress and every
selector and URL changed.

website/docsearch.config.js now holds it. It still has to be pasted into
the dashboard, which is where the crawler runs, but it can now be read,
reviewed and changed in a pull request. The write key is not in it.

Every selector was checked against the 46 built pages:

  - lvl0 comes from meta[name="docsearch:section"] rather than from the
    active sidebar link in the DOM, so the breadcrumbs no longer depend
    on the theme's markup.
  - Everything else is scoped to .vp-doc. VitePress renders the sidebar
    section labels as <h2 class="text"> inside <aside class="VPSidebar">,
    five per page, which an unscoped h2 selector would index 46 times.
  - The hidden "Are you an LLM?" banner the llms plugin injects sits
    inside .vp-doc and is stripped before extraction.
  - Only taskfile.dev is crawled. next.taskfile.dev serves the same URLs
    from the upcoming release into the same index, which would duplicate
    every record.
  - The changelog and the authoring templates are excluded, and
    deprecation pages carry a negative pageRank so they stay findable
    without outranking the page describing the replacement.
Safety and correctness settings that were missing from the first pass:
saveBackup, and a safety check that refuses to publish an index which
lost more than 10% of its records, so a crawl that breaks cannot empty
search. url_without_anchor and type join attributesToRetrieve; the
DocSearch client needs both to build a result link and group hits.

startUrls goes back to the site root. /docs/ does not exist on the
released site yet, so the crawler had no reachable entry point until the
refactor is promoted. A section is inferred from the URL for the same
reason, as a fallback for pages that do not carry the frontmatter yet.

Code blocks are copied into crawler-only paragraphs so a search can find
an exact Taskfile key or flag. Measured at +10% indexed content, and the
level weighting still puts headings ahead of code.

The two deprecation actions collapse into one, with pageRank computed
from the path.

The frontmatter field is renamed docsearch:doc_type to match what the
extractor reads.
@vmaerten
vmaerten force-pushed the docs/redesign-whole-site branch from ab23ead to a1454db Compare September 3, 2026 12:24
@vmaerten vmaerten changed the title docs(site): reorganize the documentation around reader intent docs: reorganize the documentation around reader intent Sep 3, 2026
@vmaerten
vmaerten marked this pull request as ready for review September 3, 2026 12:26
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.

1 participant