CLI Audit
theneo audit checks a Theneo project on disk — the folder you get from theneo export — and reports structural problems before you import or publish. It runs locally, needs no login or API key, and exits with a non-zero code on errors, so you can gate CI on it.
Where it fits
Run the audit between editing your Markdown project and pushing it back to Theneo. Mistakes that would otherwise surface at import or publish time — a misnamed folder, a missing tab marker, a broken widget — are caught in seconds on your machine.
1
Export
Pull your project to disk with theneo export.
2
Edit
Change your Markdown, theneo.json, or section.json files in your editor or in a pull request.
3
Audit
Run theneo audit and fix every error it reports.
4
Import
Push the changes back with theneo import.
theneo export --project payments-api --dir docs
theneo audit --dir docs
theneo import --project payments-api --dir docs
Run an audit
Options
--dir <directory>— project directory to validate. Defaults to the current directory.--json— output findings as a JSON array, for scripts and CI.-h, --help— display help for the command.
Audit the current directory:
theneo audit
Audit a specific project folder:
theneo audit --dir ./docs
Get machine-readable output:
theneo audit --dir ./docs --json
theneo audit is available from CLI version 0.23.0. Run npm install -g @theneo/cli@latest to update.
Read the results
Each finding names the file (and line, where it applies), explains what’s wrong and how to fix it, and ends with the rule ID in brackets. A clean project prints ✔ No problems found.
error authentication/section.json section.json in "authentication" has an invalid HTTP method "FETCH". Use one of: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE, CONNECT. (section-json-http-verb)
error Getting-Started Folder "Getting-Started" does not match its declared slug "getting-started" (slugs are case-sensitive). (section-slug-matches-folder)
warning webhooks Folder "webhooks" looks like a section but is not declared in theneo.json. (orphan-on-disk-undeclared)
3 problem(s): 2 error(s), 1 warning(s)
Error
The project is broken and will fail or render incorrectly on import. Any error makes the command exit with code 1.
Warning
Something looks off but won’t break the project. Warnings alone still exit with code 0.
JSON output
With --json, the command prints only the findings array — no summary, no colors — so you can pipe it into other tools. line is included only when a finding points to a specific line. Exit codes work the same as in the default output.
[
{
"severity": "error",
"file": "authentication/section.json",
"message": "section.json in \"authentication\" has an invalid HTTP method \"FETCH\". Use one of: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE, CONNECT.",
"rule": "section-json-http-verb"
},
{
"severity": "warning",
"file": "webhooks",
"message": "Folder \"webhooks\" looks like a section but is not declared in theneo.json.",
"rule": "orphan-on-disk-undeclared"
}
]
What it checks
Rules are grouped by what they inspect. Rule IDs are stable, so you can safely match on them in scripts.
Structure
Checks that the folder layout matches theneo.json. See Project Folder Structure for the expected layout.
project-directory-exists | Error | The --dir path exists and is a directory. |
theneo-json-exists | Error | theneo.json is at the project root and is valid JSON. |
theneo-json-required-fields | Error | theneo.json has a non-empty name and a sections array. |
section-declaration-valid | Error | Every section entry is an object with a valid slug. |
duplicate-section-slug | Error | No section slug is declared twice. |
section-has-index-md | Error | Every section folder has an index.md. |
section-has-section-json | Error | Every section folder has a section.json. |
section-slug-matches-folder | Error | Folder names match their declared slugs exactly, including case. |
orphan-declared-missing | Error | Every section declared in theneo.json has a folder on disk. |
orphan-on-disk-undeclared | Warning | Every section folder on disk is declared in theneo.json. |
no-root-index-md | Error | There is no index.md at the project root. |
section-json-valid | Error | Every section.json is a valid JSON object. |
section-json-http-verb | Error | If endpoints.method is set, it’s a valid HTTP verb. |
Tabs
Checks that project tabs are declared correctly and that every section belongs to one. Tab markers use the format <!-- tab:slug --> and must be the first line of each index.md.
tabs-declaration-valid | Error | tabs in theneo.json, when present, is an array. |
tab-fields-required | Error | Every tab has a non-empty title and slug. |
duplicate-tab-slug | Error | Tab slugs are unique. |
tab-icon-xor-svg | Warning | Each tab sets exactly one of iconUrl or svgCode — not both, not neither. |
section-in-exactly-one-tab | Error | When tabs exist, every top-level section is listed in exactly one tab. |
tab-sections-resolve | Error | Every slug in a tab’s sections list points to a declared section. |
index-tab-marker | Error / Warning | Every index.md has a tab marker for a declared tab. A missing marker or unknown slug is an error; a marker that isn’t on the first line is a warning. |
MDX widgets
Checks widget markup inside index.md files. These findings include a line number.
mdx-attributes-json | Error | Every widget’s attributes prop is valid JSON. |
mdx-tags-balanced | Error | Every opening widget tag has a matching, correctly nested closing tag. |
mdx-tabpanel-parent | Error | A TabPanel sits directly inside a Tabs widget, and its tabTitle is one of that widget’s tabs. |
mdx-callout-datatype | Error | A Callout uses info, warning, error, or success. |
mdx-nesting-depth | Warning | Widgets aren’t nested more than one level deep. |
mdx-malformed-tag | Error | No widget tag is missing its closing bracket, and no attributes value has an unterminated quote. |
MDX checks apply only to Theneo widget tags. Angle brackets in prose, code samples, and math comparisons are ignored, and fenced code blocks are skipped entirely.
Run it in CI
Because the command exits with 1 on any error, you can block a merge or an import when the project is broken.
GitHub Actions
Audit the docs folder on every pull request that touches it:
name: Theneo audit
on:
pull_request:
paths:
- "docs/**"
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm install -g @theneo/cli@latest
- run: theneo audit --dir docs
Before import
Only import when the audit passes. No API key is needed for the audit step itself — only for import.
theneo audit --dir docs && theneo import --project payments-api --dir docs --publish
Fix common findings
Folder does not match its declared slug
Folder does not match its declared slug
Slugs are case-sensitive. Rename the folder to match the slug in theneo.json exactly — for example, Getting-Started becomes getting-started.
index.md is missing a tab marker
index.md is missing a tab marker
When your project uses tabs, add the tab marker comment as the first line of the file, before any heading. The slug in it must match a tab declared in theneo.json.
Folder looks like a section but is not declared
Folder looks like a section but is not declared
A folder with index.md or section.json exists on disk but isn’t in theneo.json. Add it to sections if it should be published, or delete the folder if it’s left over.
theneo.json is not valid JSON
theneo.json is not valid JSON
Fix this first — while theneo.json can’t be parsed, most other checks can’t run. Look for trailing commas and unclosed brackets.
Best practices
- Run
theneo auditbefore everytheneo import— it takes seconds and needs no network access. - Fix errors first, then warnings. Warnings won’t fail your build, but they usually point to leftover or inconsistent content.
- Use
--jsonin scripts and match on therulefield, not the message text — messages may be reworded, rule IDs won’t. - Keep the CLI updated to pick up new rules as they’re added.
On this page
- CLI Audit