Your style guide was a suggestion

Taskless turns a correction into a constraint that runs on every check. Until now that rule was an ast-grep pattern, which means it could only see code structure. 0.11 adds Vale as a second static-tier engine, so the same loop now covers prose: your docs, your READMEs, your product copy.
A second static engine means more ways to validate the output of agents, and a higher quality bar in everything that you ship. Before 0.11, Taskless was never designed to support multiple static engines.
What shipped
taskless check now dispatches by engine and runs all three concurrently, merging their findings into one result set.
sgis ast-grep. Code structure, matched as a pattern.valeis Vale, and it's new here. Prose and docs, matched as terms, phrases, and style.runtimeis an executablecheck.tsfor corrections that have to read across files. It arrived in 0.10.0.
sg and vale are both static tier. No login, no reconcile, no signing. A Vale rule can't reach your host, and that's a property of Vale rather than a promise from us: its Tengo scripting sandbox exposes text, math, and fmt, and nothing else. We checked, and os, io, and exec all report "module not found."
If Vale can't run, the check says so and the other engines still report. A Vale that times out or rejects its config fails the run rather than exiting clean, because a checker that can't look has to say it couldn't look.
This one is a breaking change. Every rule is now a single directory: .taskless/rules/<engine>/<id>/ holds the rule, its per-engine config, and its fixtures in .tests/. Existing layouts need npx @taskless/cli to migrate.
The shape is deliberate. A constraint is the enforcement file and the tests that prove it, so colocating them makes what is being checked, and why, readable in one place. Writing a rule means creating a directory and deleting one means rm -rf, with nothing outside it touched either way.
Vale rules carry their own .vale.ini declaring which files they apply to. The config Vale actually reads is assembled from those on every run, gitignored, and regenerated, so there's no shared file to hand-edit.
One directory per rule also minimizes conflicts on rebase. A large shared config, an .eslintrc or a ruff.toml, is a collision waiting to happen once several people are tightening the system at once.
The thing we didn't expect
We put Vale in front of a room of founders at a dogfooding event, and John had something we hadn't accounted for. His team already kept a list of banned prose terms, written down and built by hand over time, naming the words and phrases they didn't want in their product. That list lived in their AGENTS.md.
So it was already being read. Every agent working in that repo loaded that file, saw the banned terms, and proceeded. They had done the hard part, which is deciding what they believe, and they had put it exactly where the tooling says to put it.
John turned it into a Vale rule in a few minutes. The run came back with 175 findings. A single banned phrase appeared more than twenty times.
Every one of those 175 findings is a recorded instance of an agent reading the instruction and doing something else.
Why nobody knew
This generalizes past one team.
A markdown file is advisory. An agent reads AGENTS.md, holds it in context, and complies at some rate below 100%. That rate is real, it varies by model and by how full the context window is, and you have no way to observe it, because a miss produces the same artifact as never having written the instruction at all. Compliance is invisible and so is non-compliance.
Nothing in that loop is dishonest. The instruction was written, it was read, and it mostly worked. What's missing is a measurement.
An enforced rule is a measurement. The first run against a repo that's been operating on good intentions doesn't tell you the code got worse. It tells you what the gap between the instruction and the output has been the whole time. That's why the number is high on the first run and low afterward, and why the first number is the interesting one.
John's own reaction, watching the findings scroll past, was to recognize which ones came from where:
"This is some of my clauded code."
Where a Vale rule belongs
Taskless doesn't want every correction to become a Vale rule. taskless agent route looks at what you already have and picks the lightest thing that does the job: your existing linter if it fits, an sg rule if the correction is structural, a runtime rule only when the check needs to read across files. It names the concrete authoring procedure to follow, so an agent goes from a correction to create-vale-rule without a human deciding the engine.
Vale earns the slot when the correction is about language rather than structure. Banned terms. Product names spelled the way your brand guide spells them. The phrase your support team hates. Docs that must say "sign in" and never "log in."
These all have one quality in common. They're things a team already agreed on and wrote down somewhere nobody enforces. A style guide in Notion. A section of the onboarding doc. A thread in Slack that everyone remembers differently. Or, increasingly, an AGENTS.md that agents read and partially follow.
Keep the AGENTS.md, but treat it as a suggestion. In an ideal world an agent follows your guidance and Taskless never needs to get involved. Trust, but verify: move the part that's a constraint into something that fails the check.
What it doesn't cover
Vale 3.20.0 parses a lot of markup natively and shells out to an external converter for the rest. AsciiDoc, reStructuredText, XML/DITA and Typst need asciidoctor, rst2html, dita or typst2vast respectively, and we ship the Vale binary without them. MDX used to be on that list and isn't anymore, since it got a native parser.
Rather than let a missing converter take down the run, the CLI excludes those extensions from Vale's walk and names the skipped files in a notice telling you which converter would put them back in scope. We measured every extension against the pinned binary rather than transcribing the documentation, which is how two alternate AsciiDoc spellings that crash identically ended up covered.
If your docs are AsciiDoc, install asciidoctor and they come back.
Getting it
The Vale binary installs alongside the CLI as a per-platform optionalDependency, so there's no lifecycle script and nothing to download at runtime. Only your platform's package installs; a host we don't publish for installs cleanly with none of them and falls back to a vale on PATH. How that works is its own post, and it's the next one in this series.
npx @taskless/cliIf you have a list of banned words sitting in a doc somewhere, that's the first constraint to write. You already know what it says. Run it and see how many times it was ignored.