# Clone and install
git clone https://github.com/docToolchain/dacli.git
cd dacli
uv tool install .
# Verify installation
dacli --version
dacli Tutorial: CLI for Documentation Access
Introduction
This tutorial demonstrates how the dacli (Docs-As-Code CLI) tool works and what capabilities it provides.
|
Important
|
This CLI is not intended for manual use by humans. It is designed as an interface for Large Language Models (LLMs) that do not have native MCP (Model Context Protocol) support but can execute shell commands. The examples in this tutorial serve to illustrate the tool’s functionality and output formats. |
Prerequisites
The CLI is included with dacli. Install it globally:
Expected output:
dacli, version 0.1.0
|
Note
|
Alternatively, use uv sync and prefix all commands with uv run. See Installation Guide for details.
|
Global Options
All commands support these global options:
dacli [OPTIONS] COMMAND [ARGS]
Options:
--docs-root DIRECTORY Documentation root directory (default: current directory)
--format [json|yaml|text] Output format (default: text)
--pretty Pretty-print output for human readability
--version Show the version and exit
--help Show help message
Tutorial Examples
For these examples, we assume a documentation project at /path/to/docs.
Example 1: Exploring Document Structure
Get an overview of the documentation hierarchy:
dacli --docs-root /path/to/docs structure --max-depth 1
Output:
{
"sections": [
{"path": "introduction", "title": "Introduction", "level": 1, "children": []},
{"path": "architecture", "title": "Architecture", "level": 1, "children": []},
{"path": "api-reference", "title": "API Reference", "level": 1, "children": []}
],
"total_sections": 45
}
To see nested sections, increase the depth:
dacli --docs-root /path/to/docs structure --max-depth 2
Example 2: Reading Section Content
Read a specific section by its path:
dacli --docs-root /path/to/docs section introduction
Output:
{
"path": "introduction",
"title": "Introduction",
"content": "== Introduction\n\nThis document describes...",
"location": {
"file": "/path/to/docs/chapters/01_intro.adoc",
"start_line": 1,
"end_line": 25
},
"format": "asciidoc"
}
For nested sections, use dot notation:
dacli --docs-root /path/to/docs section architecture.decisions
Example 3: Handling Non-Existent Sections
When requesting a section that doesn’t exist, the CLI provides helpful suggestions:
dacli --docs-root /path/to/docs section intro
Output (exit code 3):
{
"error": {
"code": "PATH_NOT_FOUND",
"message": "Section 'intro' not found",
"details": {
"requested_path": "intro",
"suggestions": ["introduction", "intro-page"]
}
}
}
Example 4: Searching Documentation
Search for content across all documentation:
dacli --docs-root /path/to/docs search "authentication"
Output:
{
"query": "authentication",
"results": [
{
"path": "security.authentication",
"line": 45,
"context": "...implements OAuth2 authentication for all API endpoints...",
"score": 0.95
},
{
"path": "api-reference.auth",
"line": 12,
"context": "...authentication tokens must be included in the header...",
"score": 0.82
}
],
"total_results": 2
}
Limit results and scope the search:
dacli --docs-root /path/to/docs search "database" --scope architecture --max-results 5
Example 5: Getting Sections at a Specific Level
List all chapters (level 1 sections):
dacli --docs-root /path/to/docs sections-at-level 1
Output:
{
"level": 1,
"sections": [
{"path": "introduction", "title": "Introduction"},
{"path": "architecture", "title": "Architecture"},
{"path": "deployment", "title": "Deployment"}
],
"count": 3
}
Example 6: Extracting Code Blocks
Get all code blocks from the documentation:
dacli --docs-root /path/to/docs elements --type code
Output:
{
"elements": [
{
"type": "code",
"parent_section": "examples.python",
"location": {"file": "/path/to/docs/examples.adoc", "start_line": 25}
},
{
"type": "code",
"parent_section": "api-reference.endpoints",
"location": {"file": "/path/to/docs/api.adoc", "start_line": 102}
}
],
"count": 15
}
Filter by section:
dacli --docs-root /path/to/docs elements --type table --section architecture
Example 7: Getting Metadata
Get project-level metadata:
dacli --docs-root /path/to/docs metadata
Output:
{
"path": null,
"total_files": 15,
"total_sections": 87,
"total_words": 12450,
"last_modified": "2026-01-22T10:30:00+00:00",
"formats": ["asciidoc", "markdown"]
}
Get section-level metadata:
dacli --docs-root /path/to/docs metadata architecture.decisions
Output:
{
"path": "architecture.decisions",
"title": "Architecture Decisions",
"file": "/path/to/docs/chapters/09_decisions.adoc",
"word_count": 2340,
"last_modified": "2026-01-19T10:15:00+00:00",
"subsection_count": 7
}
Example 8: Validating Documentation Structure
Check for structural issues:
dacli --docs-root /path/to/docs validate
Output (when valid):
{
"valid": true,
"errors": [],
"warnings": [
{
"type": "orphaned_file",
"path": "chapters/unused.adoc",
"message": "File is not included in any document"
}
],
"validation_time_ms": 45
}
Example 9: Updating Section Content
Update a section’s content:
dacli --docs-root /path/to/docs update introduction --content "== Introduction
This is the updated introduction content.
It now includes more details about the project."
Output:
{
"success": true,
"path": "introduction",
"location": {"file": "/path/to/docs/intro.adoc", "line": 1},
"previous_hash": "a1b2c3d4",
"new_hash": "e5f6g7h8"
}
Use optimistic locking to prevent concurrent edit conflicts:
dacli --docs-root /path/to/docs update introduction \
--content "New content..." \
--expected-hash a1b2c3d4
Example 10: Inserting New Content
Insert a new section after an existing one:
dacli --docs-root /path/to/docs insert architecture \
--position after \
--content "== New Architecture Section
This section was added programmatically."
Output:
{
"success": true,
"inserted_at": {"file": "/path/to/docs/architecture.adoc", "line": 150},
"previous_hash": "a1b2c3d4",
"new_hash": "e5f6g7h8"
}
Position options:
- before - Insert before the section
- after - Insert after the section
- append - Append at the end of the section (before children)
Output Formats
JSON
Compact JSON for machine parsing:
dacli --docs-root /path/to/docs --format json metadata
{"path":null,"total_files":15,"total_sections":87,"total_words":12450}
Pretty JSON
Formatted JSON for debugging:
dacli --docs-root /path/to/docs --format json --pretty metadata
{
"path": null,
"total_files": 15,
"total_sections": 87,
"total_words": 12450
}
YAML
YAML format:
dacli --docs-root /path/to/docs --format yaml metadata
path: null
total_files: 15
total_sections: 87
total_words: 12450
Text (Default)
Human-readable text format:
dacli --docs-root /path/to/docs --format text metadata
path: total_files: 15 total_sections: 87 total_words: 12450
Exit Codes
The CLI uses standardized exit codes for error handling:
| Code | Meaning |
|---|---|
0 |
Success |
1 |
General error |
2 |
Invalid arguments |
3 |
Path not found |
4 |
Validation error |
5 |
Write error |
Piping & Scripting
When using dacli --format json in shell pipelines, keep these tips in mind.
Don’t combine uv sync and dacli in one command
Running uv sync before dacli in the same shell invocation can cause empty stdout:
# BROKEN - dacli may produce empty stdout after uv sync
uv sync --all-extras && dacli --format json structure | python3 -c "..."
# WORKS - run as separate commands
uv sync --all-extras
dacli --format json structure | python3 -c "..."
This is a uv issue: modifying the virtual environment can invalidate tool entrypoints within the same shell session.
Don’t redirect stderr into JSON pipes
Using 2>&1 merges informational messages into the JSON stream, breaking parsers:
# BROKEN - stderr mixes into JSON
dacli --format json structure 2>&1 | jq .
# WORKS - leave stderr alone or discard it
dacli --format json structure | jq .
dacli --format json structure 2>/dev/null | jq .
Capture output to a variable
The safest approach for scripting is to capture output into a variable first:
# Capture JSON, then process
output=$(dacli --format json --docs-root ./docs structure)
echo "$output" | jq '.sections | length'
# Or use a temp file for large results
dacli --format json --docs-root ./docs sections-at-level 2 > /tmp/sections.json
python3 -c "import json; d=json.load(open('/tmp/sections.json')); print(d['count'])"
LLM Integration Pattern
A typical LLM workflow using dacli:
# 1. Understand the documentation structure
structure=$(dacli --docs-root /project/docs structure --max-depth 2)
# 2. Search for relevant content
results=$(dacli --docs-root /project/docs search "database configuration")
# 3. Read the relevant section
content=$(dacli --docs-root /project/docs section deployment.database)
# 4. Update the documentation
dacli --docs-root /project/docs update deployment.database \
--content "Updated database configuration documentation..."
# 5. Verify the structure is still valid
dacli --docs-root /project/docs validate
Command Reference
| Command | Description |
|---|---|
|
Get hierarchical document structure |
|
Read section content by path |
|
Get all sections at a nesting level |
|
Full-text search across documentation |
|
Get code blocks, tables, images, etc. |
|
Get project or section metadata |
|
Validate documentation structure |
|
Update section content |
|
Insert content before/after a section |
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.