This is a small project with Taskless rules in it. Everything here is real: the same layout you get after installing, so you can read it before you commit to anything.
Two rules, one per engine.
| Path | What it is |
|---|---|
example.cjs |
A CommonJS module that calls eval on file contents |
example.html |
A page with a Title Case heading and some hedging prose |
.taskless/ |
The rules. No build output, no cached state. |
A rule is one directory. It holds everything that defines it. Adding a rule means adding a directory. Removing one means removing that directory. No shared file gets edited either way.
.taskless/rules/
sg/no-eval/
no-eval.yml the rule
.tests/no-eval-20260814-test.yml its test cases
vale/no-simply/
no-simply.yml the rule
.vale.ini which files it applies to
.tests/fail/hedged.md prose it must flag
.tests/pass/direct.md prose it must leave alone
Two details in there need explaining.
.tests/ is dot-prefixed on purpose. ast-grep discovers rules by walking
the rules tree, and it reads every .yml it finds as a rule. A plain tests/
directory would make it parse the test files as rules and fail the whole scan.
A dot-directory gets skipped by that walk. The test runner still finds it.
Only Vale has a per-rule .vale.ini. Vale can't express "which files does
this apply to" inside the rule file, because it rejects unknown keys. Scope
needs somewhere else to live. ast-grep puts its equivalent (files, ignores)
inside the rule, so an sg rule gets no second file.
You won't find a project-wide .vale.ini or sgconfig.yml here. Both get
assembled from the per-rule configs when a check runs, and both are gitignored.
They're build output.
$ npx @taskless/cli check
example.cjs:7:10
error[no-eval] Avoid eval. It executes whatever string it's handed.
> eval("(" + raw + ")")
note: `eval` runs arbitrary code with the caller's permissions. Parse the value
instead: `JSON.parse` for JSON, a real parser for anything else.
example.html:7:11
warning[no-simply] Avoid 'simply'. It tells the reader the work was easy.
> simply
2 issues (1 error, 1 warning) across 2 files
One finding from each engine, merged into one report. The exit code follows
severity, so this run exits 1 on the error.
npx @taskless/cli fetches the published CLI. To run the one in this
checkout, build it first and then call it from here:
pnpm --filter @taskless/cli build # from the repo root
cd example
../packages/cli/dist/index.js check
Substitute that path for npx @taskless/cli in every command below.
Note that check writes the two assembled configs into .taskless/, so
expect them to appear after the first run. Both are gitignored.
check runs rules against your code. Two other commands run against the rules:
$ npx @taskless/cli validate # are these rules well-formed?
$ npx @taskless/cli verify # do they fire where they should, and only there?
Both take a path: a rule directory, an engine directory, or nothing at all for
everything. verify runs validate first and stops if it fails. That way a broken
rule tells you what's broken.
packages/cli/test/example-project.test.ts runs check, validate, and verify
against this directory and asserts on what comes back. A demo that's drifted
from the layout it demonstrates is worse than no demo. If the layout changes
and this stops being true, the build fails.