
Devtu Docs Quality
- 138 installs
- 1.6k repo stars
- Updated August 4, 2026
- mims-harvard/tooluniverse
Helps with ai & agent building tasks.
About
devtu-docs-quality is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- devtu-docs-quality
- AI & Agent Building
- AI-coding skill
Devtu Docs Quality by the numbers
- 138 all-time installs (skills.sh)
- +5 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #3,511 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/mims-harvard/tooluniverse --skill devtu-docs-qualityAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 138 |
|---|---|
| repo stars | ★ 1.6k |
| Last updated | August 4, 2026 |
| Repository | mims-harvard/tooluniverse ↗ |
What it does
Helps with ai & agent building tasks.
Files
Documentation Quality Assurance
Two Equal Priorities
Both of the following must be satisfied before an audit is done. Neither overrides the other.
1. Technical correctness — wrong code is worse than no code; it actively breaks users' workflows.
2. Less is more — redundant content is worse than no content; it creates confusion, dilutes trust, and makes maintenance harder.
When in doubt about technical accuracy: verify against source (src/tooluniverse/execute_function.py).When in doubt about whether content is needed: delete it.
---
Less Is More — The Core Philosophy
ToolUniverse is a serious research tool. Documentation should reflect that with restraint and precision, not volume.
What "less is more" means in practice
Remove, don't add. Every edit should end with fewer words, fewer pages, fewer links. The field moves fast — outdated instructions are actively harmful. When two approaches both work, keep one.
Each concept appears exactly once. If setup instructions appear in three places, a user reading one doesn't know the others exist, and maintainers must update all three on every change. Pick one canonical location and cross-link everywhere else.
No emojis. Emojis in headings, nav items, card titles, and bullet points signal "AI-generated" and undermine trust in a serious scientific tool. Remove them unconditionally — no exceptions for "emphasis."
Shrink, don't summarize. A page reduced from 1000 lines to 30 pointer lines is better than a 1000-line page summarized with a TL;DR box. Do the surgery.
Size budgets (hard limits):
| Page type | Max lines |
|---|---|
Per-platform setup page (claude_desktop.rst, cursor.rst, etc.) | 15 |
| Homepage grid sections | 4 cards max per grid |
| "See Also" / "Related" link lists | 4 links max |
| Tutorial pages that duplicate the Python guide | 0 — delete or make a pointer |
Less-is-more decision tree
When reviewing any piece of content, ask:
1. Does this content exist elsewhere on the site? → Remove it; add a cross-link to the canonical location. 2. Is this content outdated or hard to keep current? → Remove it; link to the upstream source (e.g., aiscientist.tools/setup.md). 3. Can a user reach this information in 2 clicks from the homepage? → If yes and the info is already there, remove this copy. 4. Is this an emoji, decorative header, or filler sentence? → Remove it unconditionally. 5. Is this a "Explore More" card pointing somewhere already in the sidebar? → Remove it.
---
Apple-Style Simplification Rules
Apply these rules to every file touched during an audit.
No emojis in headings, bullet items, card titles, toctree captions, nav bar entries, or button text.
Single setup entry point. The canonical installation path is:
Read https://aiscientist.tools/setup.md and set up ToolUniverse for me.Per-platform pages must contain exactly three things: (1) official install link, (2) official MCP setup guide link, (3) the setup prompt above. Nothing else — no JSON snippets, no step-by-step instructions, no troubleshooting. Those belong in the setup skill at aiscientist.tools/setup.md.
Consistent tool count. Always "1000+ tools". Never "600+", "750+", "1200+", "10000+", or any other number.
Clean navigation bar. Must not contain "API", "API Keys", or "Contribution" items. Must include a link to https://aiscientist.tools as the first item.
Homepage "Explore More" grid. Maximum 4 cards. Remove any card whose destination is already reachable from the sidebar or the "Get Started" section.
No broken `:doc:` references. Every :doc:some/path` must resolve to an .rst or .md` file on disk. Broken links are never acceptable — remove or replace immediately.
---
Five-Phase Strategy
Run phases in order — D first (instant), then E (simplification scan), then C/A/B.
| Phase | What it catches | Time |
|---|---|---|
| D Static method scan | Wrong method names (tu.run_batch, tu.call_tool, etc.) | ~2 s |
| E Simplification scan | Emojis, wrong counts, broken links, size violations | ~10 s |
| C Live code execution | Runtime failures (wrong key, bad return type) | 3-5 min |
| A Automated validation | Deprecated commands, term inconsistency | 15 min |
| B ToolUniverse audit | Circular nav, duplicate MCP configs, tool counts | 20 min |
---
Phase D: Static Method Scan
python3 - <<'EOF'
import re, sys
from pathlib import Path
from collections import defaultdict
DOCS = Path("docs")
EXCLUDE = {"locale", "old", "_build", "__pycache__", "tools", "archive"}
KNOWN_BAD = {
"list_tools", "run_batch", "run_async", "execute_tool", "call_tool",
"list_tools_by_category", "configure_api_keys", "get_tool", "get_exposed_name",
"list_available_methods", "register_tool_from_config", "register_tool",
}
STATIC = [
(r"\.load_tools\([^)]*(?:use_cache|cache_dir)\s*=", "load_tools() invalid kwargs"),
(r"ToolUniverse\([^)]*timeout\s*=", "ToolUniverse(timeout=) invalid"),
(r'"name":\s*"opentarget_', 'old lowercase "opentarget_*" tool name'),
(r"tu\.run_batch\(", "tu.run_batch() — use tu.run(list, max_workers=N)"),
(r'\btu\.[A-Z]\w+\s*\(', "tu.ToolName() shorthand — use tu.run({name:...})"),
]
M = re.compile(r'\b(?:tu|tooluni)\.([\w]+)\s*\(')
issues = defaultdict(list)
for f in sorted(list(DOCS.rglob("*.rst")) + list(DOCS.rglob("*.md"))):
if any(p in f.parts for p in EXCLUDE): continue
t = f.read_text(errors="replace")
code = "\n".join(
re.findall(r"\.\. code-block:: python\n((?:[ \t]+[^\n]*\n|[ \t]*\n)*)", t, re.MULTILINE) +
re.findall(r"```python\n(.*?)```", t, re.DOTALL))
if not code.strip(): continue
rel = str(f.relative_to(DOCS))
for m in M.finditer(code):
if not m.group(1).startswith("_") and m.group(1) in KNOWN_BAD:
issues[rel].append(f"tu.{m.group(1)}()")
for pat, label in STATIC:
if re.search(pat, code): issues[rel].append(label)
if issues:
[print(f" {f}: {i}") for f in sorted(issues) for i in sorted(set(issues[f]))]
sys.exit(1)
else:
print("Phase D clean")
EOFFix-or-remove rule — no exceptions:
- Correct replacement exists → fix immediately
- Feature is automatic/internal → remove the call, add prose comment if needed
- Feature doesn't exist → delete the code block or section entirely
Most common fixes:
# wrong → correct
tu.run_batch(list) → tu.run(list, max_workers=4)
tu.run_async(query) → await tu.run(query)
tu.call_tool('X', {...}) → tu.run({"name": "X", "arguments": {...}})
tu.execute_tool('X', {...}) → tu.run({"name": "X", "arguments": {...}})
tu.list_tools() → tu.list_built_in_tools(mode='list_name')
tu.get_tool('X') → tu.get_tool_by_name('X')
tu.register_tool(instance) → tu.register_custom_tool(tool_instance=instance)
tu.register_tool_from_config(c) → tu.register_custom_tool(tool_config=c)
tu.configure_api_keys({}) → REMOVE — use env vars
tu.get_exposed_name(name) → REMOVE — shortening is automatic
ToolUniverse(timeout=30) → ToolUniverse() # no timeout kwarg
load_tools(use_cache=True) → load_tools() # no use_cache kwarg
tu.ToolName(key=val) → tu.run({"name": "ToolName", "arguments": {"key": val}})
opentarget_get_* → OpenTargets_get_* (capital O and T)Special case: Change .. code-block:: python to .. code-block:: text when showing intentionally-wrong code as an error example.
---
Phase E: Simplification Scan
python3 - <<'EOF'
import re, sys
from pathlib import Path
DOCS = Path("docs")
EXCLUDE = {"_build", "__pycache__", "locale"}
issues = []
EMOJI_RE = re.compile(
r'[\U0001F300-\U0001F9FF\U00002600-\U000027BF\U0001FA00-\U0001FA9F'
r'\U0001F004\U0001F0CF\U00002702-\U000027B0]'
)
def in_code_block(text, pos):
"""Return True if pos is inside a code block."""
before = text[:pos]
# RST code blocks
rst_starts = [m.end() for m in re.finditer(r'\.\. code-block::[^\n]*\n', before)]
for start in reversed(rst_starts):
block = text[start:]
end_match = re.search(r'\n(?![ \t]|\n)', block)
block_end = start + (end_match.start() if end_match else len(block))
if start <= pos <= block_end:
return True
# Markdown fenced blocks
fences = list(re.finditer(r'```', before))
return len(fences) % 2 == 1
for f in sorted(DOCS.rglob("*.rst")) + sorted(DOCS.rglob("*.md")):
if any(p in f.parts for p in EXCLUDE):
continue
text = f.read_text(errors="replace")
rel = str(f.relative_to(DOCS))
# Check emojis in prose
for m in EMOJI_RE.finditer(text):
if not in_code_block(text, m.start()):
line = text[:m.start()].count('\n') + 1
issues.append(f"EMOJI {rel}:{line} {repr(m.group())}")
# Check wrong tool counts
for bad in ["600+", "750+", "1200+", "10000+"]:
if bad in text and "tools" in text[text.find(bad):text.find(bad)+20]:
issues.append(f"COUNT {rel} contains '{bad} tools' (use '1000+')")
# Check broken :doc: references
for m in re.finditer(r':doc:`([^`]+)`', text):
ref = m.group(1).lstrip('/')
# Strip any display text (format: display <path>)
if ' <' in ref:
ref = re.search(r'<([^>]+)>', ref).group(1)
base = DOCS / Path(ref.replace('/', '/'))
candidates = [base.with_suffix('.rst'), base.with_suffix('.md'),
base / 'index.rst', base / 'index.md']
if not any(c.exists() for c in candidates):
line = text[:m.start()].count('\n') + 1
issues.append(f"LINK {rel}:{line} broken :doc:`{ref}`")
# Check navbar in conf.py
conf = Path("docs/conf.py").read_text()
for bad_nav in ['"API"', '"API Keys"', '"Contribution"']:
if bad_nav in conf:
issues.append(f"NAV conf.py navbar contains {bad_nav}")
if "aiscientist.tools" not in conf:
issues.append("NAV conf.py navbar missing aiscientist.tools link")
# Check per-platform page line counts
platform_dir = DOCS / "guide" / "building_ai_scientists"
for rst in platform_dir.glob("*.rst"):
if rst.name in ("index.rst", "mcp_support.rst", "compact_mode.rst",
"mcpb_introduction.rst", "mcp_name_shortening.rst"):
continue
lines = rst.read_text().splitlines()
if len(lines) > 15:
issues.append(f"SIZE guide/building_ai_scientists/{rst.name} {len(lines)} lines (max 15)")
if issues:
for i in sorted(issues):
print(i)
sys.exit(1)
else:
print("Phase E clean")
EOFWhen Phase E reports issues, apply the less-is-more decision tree above. Fix all items before proceeding to Phase C.
---
Phase C: Live Code Execution
python scripts/test_doc_code_blocks.pyThe runner injects a real ToolUniverse instance as preamble, skips blocks needing API keys or async, and classifies NameError on out-of-scope variables as "context-dependent" (not a failure).
Common runtime failures:
| Error | Cause | Fix |
|---|---|---|
KeyError: 'parameters' | tool_specification() without format="openai" | Add format="openai" |
KeyError: slice(...) on OpenTargets result | Slicing a dict | Use result['data']['disease']['associatedTargets']['rows'][:N] |
TypeError: load_tools() got unexpected kwarg | use_cache or cache_dir | Remove the kwarg |
---
Phase A: Automated Validation
python scripts/validate_documentation.py# scripts/validate_documentation.py checks:
DEPRECATED_PATTERNS = [
(r"python -m tooluniverse\.server", "tooluniverse-server"),
(r"600\+?\s+tools", "1000+ tools"),
(r"750\+?\s+tools", "1000+ tools"),
]---
Phase B: ToolUniverse-Specific Audit
Circular navigation — trace index.rst → quickstart → getting_started manually; no loops allowed.
Tool count — "1000+ tools" consistently everywhere. Run: rg "[0-9]+\+?\s+(tools|integrations)" docs/ --no-filename | sort -u
Auto-generated headers — docs/tools/*_tools.rst and docs/api/*.rst must start with .. AUTO-GENERATED.
CLI docs — every entry under [project.scripts] in pyproject.toml must appear in docs/reference/cli_tools.rst.
Env vars — every os.getenv("TOOLUNIVERSE_*") in src/ must appear in docs/reference/environment_variables.rst.
---
RST Code Block Extractor (important)
Always use re.MULTILINE (not re.DOTALL) for RST blocks to avoid merging adjacent blocks:
# correct
re.findall(r"\.\. code-block:: python\n((?:[ \t]+[^\n]*\n|[ \t]*\n)*)", text, re.MULTILINE)
# wrong — merges adjacent blocks
re.findall(r"\.\..*?code-block.*?python\n((?:[ \t]+.*\n|\n)*)", text, re.DOTALL)---
Validation Checklist
All items must pass before the audit is done. A partial pass is not acceptable.
Technical correctness:
- [ ] Phase D scan exits 0 — no invalid method calls
- [ ]
python scripts/test_doc_code_blocks.pyexits 0 — no runtime failures - [ ] No
spec['parameters']withoutformat="openai" - [ ] Automated validation passes (0 HIGH issues)
- [ ] All CLIs from
pyproject.tomldocumented - [ ] No circular navigation
Less is more (Apple-style):
- [ ] Phase E scan exits 0 — no emojis, no wrong counts, no broken links, no oversized pages
- [ ] "1000+ tools" used consistently everywhere (not 600+, 750+, 10000+, etc.)
- [ ] Each per-platform setup page: install link + MCP guide link + setup prompt only (≤15 lines)
- [ ] No duplicate setup instructions anywhere on the site
- [ ] Navbar: no "API", "API Keys", "Contribution"; has
aiscientist.toolslink - [ ] Homepage "Explore More" grid: ≤4 cards
- [ ] No concept or section appears verbatim in more than one place
- [ ] No "See Also" / "Related" section with more than 4 links
If any item is failing: stop, fix it, re-run the relevant phase, confirm it passes. Do not proceed to the next item until the current one is clean.
---
Reference Files
- API_REFERENCE.md — valid method signatures, wrong-method table, correct patterns
- DOCS_STRUCTURE.md — per-file audit status for all doc files
scripts/test_doc_code_blocks.py— Phase C live runner
ToolUniverse API Reference for Doc Auditing
Valid Public Methods (ground truth)
Derive the live list any time with:
import sys; sys.path.insert(0, "src")
from tooluniverse import ToolUniverse
print("\n".join(m for m in sorted(dir(ToolUniverse)) if not m.startswith("_")))Key methods docs most often reference:
| Method | Signature summary |
|---|---|
run() | run(fcall_str, use_cache=False, max_workers=None, ...) — accepts str, dict, or list (batch) |
run_one_function() | Low-level single-call sync |
load_tools() | load_tools(tool_type=None, include_tools=None, exclude_tools=None, include_tool_types=None, exclude_tool_types=None, tool_config_files=None, tools_file=None) |
tool_specification() | `tool_specification(tool_name, format="default"\ |
list_built_in_tools() | list_built_in_tools(mode, scan_all=False) |
return_all_loaded_tools() | Returns list[dict] of loaded tool configs |
all_tool_dict | Attribute (dict): loaded tools by name — use for membership checks |
get_tool_types() | Returns list[str] of category names |
get_tool_by_name() | get_tool_by_name(tool_names, format) |
filter_tools() | filter_tools(include_tools, exclude_tools, include_tool_types, exclude_tool_types) |
register_custom_tool() | register_custom_tool(tool_class=None, tool_name=None, tool_config=None, instantiate=True, tool_instance=None) |
clear_cache() | Clear result cache |
close() | Shut down MCP connections |
ToolUniverse.__init__ kwargs: tool_files, keep_default_tools, log_level, hooks_enabled, hook_config, hook_type, enable_name_shortening
---
Known-Wrong Methods Table
Every entry below appeared in ToolUniverse docs and does not exist. Fix or remove on sight.
| Wrong call | Fix / Action |
|---|---|
tu.run_batch(list) | tu.run(list, max_workers=N) — run() accepts list natively |
tu.run_async(query) | await tu.run(query) — run() is context-aware |
tu.call_tool('Name', {...}) | tu.run({"name": "Name", "arguments": {...}}) |
tu.execute_tool('Name', {...}) | tu.run({"name": "Name", "arguments": {...}}) |
tu.list_tools() | tu.list_built_in_tools(mode='list_name') or tu.all_tool_dict |
tu.get_tool('Name') | tu.get_tool_by_name('Name') |
tu.register_tool(instance) | tu.register_custom_tool(tool_instance=instance) |
tu.register_tool_from_config(cfg) | tu.register_custom_tool(tool_config=cfg) |
tu.list_tools_by_category('X') | tu.filter_tools(include_tool_types=['X']) + check tu.get_tool_types() for valid names |
tu.configure_api_keys({...}) | Remove — keys are env vars only |
tu.get_exposed_name(name) | Remove — shortening is automatic with ToolUniverse(enable_name_shortening=True) |
tu.list_available_methods() | Client-side utility only — change code block to .. code-block:: text if showing as error example |
ToolUniverse(timeout=30) | Remove timeout= — not a valid __init__ kwarg |
tu.ToolName(key=val) shorthand | tu.run({"name": "ToolName", "arguments": {"key": val}}) |
load_tools(use_cache=True) | Remove use_cache/cache_dir — not valid kwargs |
opentarget_get_* (lowercase) | Rename to OpenTargets_get_* (capital O and T) |
targets[:N] on OpenTargets result | targets['data']['disease']['associatedTargets']['rows'][:N] |
---
Fix-vs-Remove Decision
Wrong information must be fixed or removed. It must never be left as-is.
Wrong call found
│
▼
Correct equivalent method exists?
├── YES → Fix to the correct method immediately
└── NO → Does the feature conceptually exist?
├── YES (auto/internal) → Remove the call; add a prose comment if needed
└── NO → Delete the code block or section entirely---
Correct Patterns
# ✅ tool_specification — use format="openai" to get 'parameters' key
spec = tu.tool_specification("Tool_Name", format="openai")
for param, info in spec['parameters']['properties'].items():
print(param, info['type'])
# ✅ batch execution
results = tu.run([
{"name": "Tool1", "arguments": {"id": "1"}},
{"name": "Tool1", "arguments": {"id": "2"}},
], max_workers=4)
# ✅ check if tool loaded
if "My_Tool" in tu.all_tool_dict: ...
# ✅ list tool names
names = tu.list_built_in_tools(mode='list_name')
# ✅ filter by category
tools = tu.filter_tools(include_tool_types=["uniprot"])
# ✅ async context — run() is context-aware
result = await tu.run(query) # no run_async() needed
# ✅ register custom tool from config dict
tu.register_custom_tool(tool_config=my_config_dict)---
Context-Aware spec['parameters'] Check
Only flag spec['parameters'] as wrong if format="openai" is not set in the same call:
grep -n -B5 "spec\['parameters'\]" <file>
# Verify tool_specification(..., format="openai") appears above itToolUniverse Docs File Structure
122 files total. Legend: ✅ audited clean · 📝 has code blocks · 📄 prose only.
docs/guide/ — User tutorials
| Status | File | Purpose |
|---|---|---|
| ✅ | python_guide.rst | Core Python SDK — heavily audited |
| 📝 | finding_tools.rst | Tool discovery |
| 📝 | loading_tools.rst | load_tools() options |
| 📝 | listing_tools.rst | list_built_in_tools() modes |
| ✅ | tools.rst | Available tools reference |
| 📝 | api_keys.rst | API key setup |
| 📝 | interaction_protocol.rst | tu.run() call format |
| ✅ | examples.rst | Code examples |
| ✅ | scientific_workflows.rst | Multi-step workflows |
| 📝 | cache_system.rst | Result caching |
| 📝 | logging.rst | Logging config |
| 📝 | streaming_tools.rst | Streaming outputs |
| ✅ | tool_composition.rst | Composing tools |
| 📝 | tool_caller.rst | Tool Caller (MCP context) |
| ✅ | http_api.rst | HTTP API — error diagram is text block |
| ✅ | agentic_tools_tutorial.rst | Agentic tools |
| 📝 | coding_api.rst | Typed function API |
| 📝 | toolspace.rst | Space configuration |
| ✅ | vllm_support.rst | vLLM integration |
| ✅ | openrouter_support.rst | OpenRouter integration |
| 📝 | visualization_tutorial.rst | Visualization tools |
| 📝 | clinical_guidelines_tools.rst | Clinical guidelines API |
| 📝 | literature_search_tools_tutorial.rst | Literature search |
| 📝 | make_your_data_agent_searchable.rst | Custom datasets |
| 📝 | expert_feedback.md | Expert feedback tools |
| 📄 | index.rst, skills_showcase.rst, tooluniverse_case_study.rst | Navigation/prose |
docs/guide/building_ai_scientists/ — Platform integrations
| Status | File | Purpose |
|---|---|---|
| ✅ | chatgpt_api.rst | ChatGPT — format="openai" set correctly |
| ✅ | mcp_name_shortening.rst | MCP name shortening — removed get_exposed_name() |
| 📝 | mcp_support.rst | MCP protocol |
| 📄 | All other *.rst | Platform setup (MCP config only, no code) |
docs/guide/hooks/ — Output hooks
| Status | File |
|---|---|
| 📝 | index.rst, hook_configuration.rst, summarization_hook.rst, file_save_hook.rst, server_stdio_hooks.rst |
docs/expand_tooluniverse/ — Developer guides
| Status | File | Purpose |
|---|---|---|
| ✅ | contributing/local_tools.rst | Add local tools |
| ✅ | contributing/remote_tools.rst | Add remote MCP tools |
| ✅ | async_tools_guide.rst | AsyncPollingTool |
| 📝 | local_tools/local_tools_tutorial.rst, remote_tools/tutorial.rst, remote_tools/mcp_integration.rst, quick_start.rst | Step-by-step guides |
docs/help/ — Support
| Status | File | Purpose |
|---|---|---|
| ✅ | troubleshooting.rst | Fixed run_batch, register_tool, run_async |
| ✅ | faq.rst | Fixed run_batch, run_async, ToolUniverse(timeout=) |
| 📄 | index.rst, wechat_community.rst | Navigation |
docs/dev_docs/ — Internal developer docs
| Status | File |
|---|---|
| ✅ | FULLTEXT_ACCESS_GUIDE.md — fixed 15 tu.ToolName() shorthand calls |
| 📝 | Adding_Tools_Tutorial.md, Adding_Tools_Quick_Reference.md, MCP_Server_Tutorial.md, Tool_Description_Optimizer_Tutorial.md |
| 📝 | TEST_WRITING_GUIDE.md, DOCUMENTATION_STANDARDS.md, adding_mcp_tools_en.md, mcp_tool_registration_en.md |
| 📄 | FULLTEXT_ACCESS_GUIDE.md, SEARCHING_BIORXIV.md, MCP_for_Claude.md, MCP_for_Gemini_CLI.md |
docs/reference/, docs/about/, docs/api/
| Status | Notes |
|---|---|
| 📄 | reference/*.rst — CLI tools, env vars, data sources, glossary (prose only) |
| 📄 | about/*.rst — changelog, contributing, license |
| 📄 | api/*.rst — auto-generated Sphinx API docs, do not edit |
Auto-generated (never edit manually)
docs/tools/*_tools.rst— generated bydocs/generate_config_index.pydocs/api/*.rst— generated bysphinx-apidocdocs/locale/— translation files
Documentation Quality Examples
Example 1: Command Deprecation
Before:
# Installation
python -m tooluniverse.server --config config.jsonDetected by validation:
docs/installation.md:45 [HIGH]
Found: python -m tooluniverse.server
Should be: tooluniverse-serverAfter:
# Installation
tooluniverse-server --config config.jsonExample 2: Tool Count Standardization
Before: Documentation showed:
- "600+ tools" (intro)
- "750 scientific resources" (features)
- "1195 integrations" (about)
Detected by validation:
docs/index.rst:12 [HIGH]
Found: 600+ tools
Should be: 1000+ tools
docs/features.rst:34 [HIGH]
Found: 750 scientific resources
Should be: 1000+ toolsAfter: All changed to "1000+ tools"
Example 3: Circular Navigation
Before:
# docs/quickstart.rst
For complete setup, see :doc:`getting_started`
# docs/getting_started.rst
Prerequisites: Complete :doc:`quickstart` firstIssue: Users can't progress - both pages require the other
After:
# docs/index.rst
**New users start here:** :doc:`quickstart` (5 min) → :doc:`getting_started` (30 min)
# docs/quickstart.rst
**Next:** Continue to :doc:`getting_started` for detailed setup
# docs/getting_started.rst
**Prerequisites:** Basic Python knowledgeExample 4: Auto-Generated Header
Before:
ChEMBL Tools
============
.. automodule:: tooluniverse.chembl_toolIssue: Users might edit this file directly
After:
.. AUTO-GENERATED - DO NOT EDIT MANUALLY
.. Generated by: docs/generate_config_index.py
.. Last updated: 2024-02-05
..
.. To modify, edit source files in src/tooluniverse/data/ and regenerate.
ChEMBL Tools
============
.. automodule:: tooluniverse.chembl_toolExample 5: Missing CLI Documentation
Detected from pyproject.toml:
[project.scripts]
tooluniverse-server = "tooluniverse.smcp_server:main"
tooluniverse-mcp = "tooluniverse.smcp_server:main"
tooluniverse-expert-feedback = "tooluniverse.expert_feedback:main"
generate-mcp-tools = "tooluniverse.scripts.generate_mcp_tools:main"Found in docs/reference/cli_tools.rst:
- ✅ tooluniverse-server
- ✅ tooluniverse-mcp
- ❌ tooluniverse-expert-feedback (missing)
- ❌ generate-mcp-tools (missing)
Action: Document the missing CLIs
Example 6: Environment Variables
Discovered from code:
cache_dir = os.getenv("TOOLUNIVERSE_CACHE_DIR", "~/.cache/tooluniverse")
log_level = os.getenv("TOOLUNIVERSE_LOG_LEVEL", "INFO")
api_key = os.getenv("OPENAI_API_KEY")Create documentation:
Environment Variables
=====================
Cache Configuration
-------------------
TOOLUNIVERSE_CACHE_DIR
Cache directory location
**Default:** ``~/.cache/tooluniverse``
**Example:** ``export TOOLUNIVERSE_CACHE_DIR=/tmp/cache``
Logging
-------
TOOLUNIVERSE_LOG_LEVEL
Logging verbosity
**Default:** ``INFO``
**Options:** ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR``
**Example:** ``export TOOLUNIVERSE_LOG_LEVEL=DEBUG``
API Keys
--------
OPENAI_API_KEY
OpenAI API key for LLM features
**Required:** Yes (for LLM features)
**Example:** ``export OPENAI_API_KEY=sk-...``Example 7: Terminology Inconsistency
Before:
# Page 1
Use the API endpoint to query data.
# Page 2
Send requests to the URL.
# Page 3
The route returns JSON data.
# Page 4
Access the path /api/v1/tools.Detected: 4 terms for same concept
After: Standardized to "API endpoint"
# All pages
Use the API endpoint to query data.
The API endpoint returns JSON data.
Access the API endpoint at /api/v1/tools.Example 8: Full Validation Run
Command:
python scripts/validate_documentation.pyOutput:
Scanning documentation...
❌ Found 15 issues
docs/installation.md:45 [HIGH]
Found: python -m tooluniverse.server
Should be: tooluniverse-server
docs/index.rst:12 [HIGH]
Found: 600+ tools
Should be: 1000+ tools
docs/features.rst:34 [HIGH]
Found: 750 tools
Should be: 1000+ tools
docs/quickstart.rst:23 [MEDIUM]
Found: API URL
Should be: API endpoint
... (11 more issues)
Summary:
- HIGH: 8 issues (must fix)
- MEDIUM: 7 issues (should fix)
Run fixes and re-validate.Example 9: CI/CD Integration Success
GitHub Actions output:
✓ Install dependencies
✓ Run validation
→ python scripts/validate_documentation.py
→ ✅ Documentation validation passed
✓ Check auto-generated headers
→ All files have required headers
✓ Build documentation
→ Sphinx build successfulExample 10: Audit Report
# Documentation Quality Report
**Date**: 2024-02-05
**Scope**: Full ToolUniverse documentation
## Executive Summary
- Files scanned: 127
- Issues found: 23 (Critical: 0, High: 8, Medium: 12, Low: 3)
- Estimated fix time: 3 hours
## High Priority Issues (8)
### 1. Deprecated command references
- **Files affected**: 5
- **Pattern**: `python -m tooluniverse.server`
- **Fix**: Replace with `tooluniverse-server`
- **Effort**: 15 minutes
### 2. Inconsistent tool counts
- **Files affected**: 7
- **Variations**: 600+, 750+, 1195
- **Fix**: Standardize to "1000+"
- **Effort**: 20 minutes
### 3. Missing CLI documentation
- **Undocumented**: tooluniverse-expert-feedback, generate-mcp-tools
- **Fix**: Add to docs/reference/cli_tools.rst
- **Effort**: 45 minutes
## Medium Priority Issues (12)
### 4. Circular navigation
- **Location**: quickstart.rst ↔ getting_started.rst
- **Fix**: Remove back-reference from getting_started
- **Effort**: 10 minutes
### 5. Auto-generated headers missing
- **Files**: 8 in docs/tools/
- **Fix**: Add headers via regeneration script
- **Effort**: 5 minutes
## Recommendations
**Today:**
1. Run validation script and fix all HIGH issues (1.5 hrs)
2. Fix circular navigation (10 min)
**This week:**
3. Document missing CLIs (45 min)
4. Add auto-generated headers (5 min)
5. Create environment variables reference (30 min)
**Next sprint:**
6. Create comprehensive glossary
7. Add validation to CI/CD
## Validation
Run `python scripts/validate_documentation.py` after fixesDocumentation Quality Skill - Merge Summary
What Changed
Merged two complementary documentation skills into one comprehensive skill:
Before (2 separate skills):
1. `devtu-audit-docs` (431 lines)
- ToolUniverse-specific manual audits
- Circular navigation checks
- MCP configuration duplication
- Tool count consistency
- Auto-generated file conflicts
2. `devtu-optimize-docs` (770 lines)
- General-purpose automated validation
- Python validation scripts
- Command accuracy testing
- Terminology consistency
- Generic patterns for any project
After (1 merged skill):
`devtu-docs-quality` (471 lines + examples)
- Phase A: Automated validation (generic, reusable)
- Phase B: ToolUniverse-specific audits
- Combined strengths of both approaches
- Clearer workflow: automation first, then specific checks
Benefits of Merging
1. Single entry point - No confusion about which skill to use 2. Logical workflow - Automated checks first, then specific audits 3. Complete coverage - Both generic and ToolUniverse-specific issues 4. Better organized - Clear phases instead of separate files 5. No duplication - Shared concepts unified
Key Features
Automated Validation (Phase A)
- Python validation script template
- Command accuracy checking
- Link integrity validation
- Terminology consistency tracking
- Smart context-aware pattern matching
ToolUniverse Audits (Phase B)
- Circular navigation detection
- Duplicate content checks
- Tool count standardization ("1000+ tools")
- Auto-generated file headers
- CLI documentation verification
- Environment variables documentation
- Technical jargon glossary checks
- CI/CD regeneration validation
File Structure
devtu-docs-quality/
├── SKILL.md # Main skill (471 lines)
├── EXAMPLES.md # 10 concrete examples
└── SUMMARY.md # This fileUsage Pattern
# Step 1: Run automated validation
python scripts/validate_documentation.py
# Step 2: Fix HIGH priority issues
# Step 3: Run ToolUniverse-specific checks
# - Check circular navigation manually
# - Verify tool count consistency
# - Check auto-generated headers
# - Verify CLI documentation
# Step 4: Re-validate
python scripts/validate_documentation.pyWhen to Use
Use devtu-docs-quality when:
- ✅ Reviewing documentation before release
- ✅ After major refactoring (commands, APIs, tool counts changed)
- ✅ Users report confusing or outdated documentation
- ✅ Want to establish automated validation pipeline
- ✅ Need to check for circular navigation or structural problems
- ✅ Any documentation quality concern (audit, optimize, fix, review)
Trigger Terms
The skill activates on:
- "audit docs" / "audit documentation"
- "optimize docs" / "optimize documentation"
- "review docs" / "review documentation"
- "fix docs" / "fix documentation"
- "check docs quality"
- "validate documentation"
- "documentation cleanup"
Migration for Users
If you were using either of the old skills:
- All functionality is preserved in
devtu-docs-quality - Workflow is now clearer: Phase A (automated) → Phase B (specific)
- Validation script template included in SKILL.md
- More examples in EXAMPLES.md
Files Removed
.cursor/skills/devtu-audit-docs/(merged into devtu-docs-quality).cursor/skills/devtu-optimize-docs/(merged into devtu-docs-quality)skills/devtu-audit-docs/(merged into devtu-docs-quality)skills/devtu-optimize-docs/(merged into devtu-docs-quality)
Files Created
.cursor/skills/devtu-docs-quality/SKILL.md.cursor/skills/devtu-docs-quality/EXAMPLES.md.cursor/skills/devtu-docs-quality/SUMMARY.mdskills/devtu-docs-quality/(synchronized copy)