
Technical Writer
- 146 installs
- 178 repo stars
- Updated July 14, 2026
- erichowens/some_claude_skills
Draft, revise, and structure API references, READMEs, runbooks, and user guides that match audience skill level and product tone.
About
Technical writer skill for producing clear, scannable documentation during implementation. Covers API references, tutorials, architecture notes, and operational runbooks for SaaS, API, and CLI products so users and engineers can adopt features faster.
- API and SDK reference authoring
- README and quickstart optimization
- Runbooks and troubleshooting guides
- Audience-appropriate tone and structure
- Docs aligned to release scope
Technical Writer by the numbers
- 146 all-time installs (skills.sh)
- Ranked #569 of 1,879 Documentation skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/erichowens/some_claude_skills --skill technical-writerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 146 |
|---|---|
| repo stars | ★ 178 |
| Last updated | July 14, 2026 |
| Repository | erichowens/some_claude_skills ↗ |
What it does
Draft, revise, and structure API references, READMEs, runbooks, and user guides that match audience skill level and product tone.
Files
Technical Writer
Expert technical documentation specialist focusing on developer documentation, API references, system architecture docs, runbooks, and knowledge base articles.
Quick Start
1. Identify doc type using Diátaxis: Tutorial, How-to, Explanation, or Reference 2. Know your audience - what they know, what they need to accomplish 3. Start with structure - outline before writing, use templates 4. Include working examples - all code must be tested and runnable 5. Add troubleshooting - anticipate common problems 6. Validate completeness - links work, steps accurate, nothing assumed
Core Capabilities
| Doc Type | Purpose | Key Characteristics |
|---|---|---|
| Tutorials | Learning-oriented | Hands-on, step-by-step introduction |
| How-to Guides | Task-oriented | Solve specific problems |
| Explanations | Understanding-oriented | Background, context, concepts |
| References | Information-oriented | Accurate, complete, searchable |
Diátaxis Framework
PRACTICAL THEORETICAL
┌──────────────────────┬──────────────────────┐
LEARNING│ TUTORIALS │ EXPLANATIONS │
│ "Learning by doing" │ "Understanding why" │
├──────────────────────┼──────────────────────┤
WORKING │ HOW-TO GUIDES │ REFERENCE │
│ "Solve problems" │ "Look up facts" │
└──────────────────────┴──────────────────────┘Reference Templates
Complete templates in ./references/:
| Template | Use Case |
|---|---|
readme-template.md | Project README with all essential sections |
adr-template.md | Architecture Decision Records |
api-reference-template.md | REST API documentation |
runbook-template.md | Operational procedures |
Anti-Patterns (10 Critical Mistakes)
1. Wall of Text
Symptom: Dense paragraphs, no headings or visual breaks Fix: Headings, bullet points, tables, code blocks, whitespace
2. Outdated Examples
Symptom: Code samples that don't compile or use deprecated APIs Fix: Test all examples in CI, version-lock dependencies, add "last verified" dates
3. Missing Prerequisites
Symptom: Tutorials assume knowledge/setup without stating it Fix: List prerequisites upfront, link to setup guides, specify versions
4. Expert Blindness
Symptom: Skipping "obvious" steps that aren't obvious to beginners Fix: Have newcomers test docs, include all steps, explain the "why"
5. No Error Guidance
Symptom: Happy path only, no troubleshooting Fix: Include common errors and solutions, link to support channels
6. Broken Links
Symptom: 404s to moved or deleted pages Fix: Link checking in CI, relative links where possible, redirects for moved content
7. Inconsistent Formatting
Symptom: Different styles, code block languages, heading levels Fix: Style guide, linting (markdownlint), templates for common doc types
8. Missing Context
Symptom: Docs assume reader knows system architecture Fix: Brief context at top, link to architecture docs, explain "where this fits"
9. Stale Screenshots
Symptom: UI screenshots from 3 versions ago Fix: Automate screenshot capture, note UI version, prefer text over images
10. No Versioning
Symptom: Docs don't match user's installed version Fix: Version selector, version badges, maintain docs per major version
Quality Checklist
Structure:
- [ ] Follows Diátaxis framework (tutorial/how-to/explanation/reference)
- [ ] Appropriate for target audience level
- [ ] Consistent formatting and style
- [ ] Updated table of contents
Content:
- [ ] Code examples are tested and runnable
- [ ] All links work (no 404s)
- [ ] Version information where relevant
- [ ] Includes troubleshooting section
Completeness:
- [ ] Prerequisites listed upfront
- [ ] All steps included (no expert blindness)
- [ ] Error scenarios covered
- [ ] Related documentation linked
Validation Script
Run ./scripts/validate-docs.sh to check:
- README completeness
- Documentation structure
- ADR format compliance
- Broken links
- Common documentation issues
Documentation Tools
Static Sites: Docusaurus, MkDocs, VitePress, Astro API Docs: Swagger/Redoc, Stoplight, ReadMe.io Diagrams: Mermaid, PlantUML, Excalidraw, Diagrams.net
External Resources
Changelog
All notable changes to the technical-writer skill will be documented in this file.
[2.0.0] - 2024-12-12
Changed
- BREAKING: Restructured SKILL.md from 701 lines to ~160 lines for progressive disclosure
- Moved all large template examples to
./references/directory - Expanded anti-patterns section from 5 to 10 patterns
Added
references/readme-template.md- Complete README template with best practicesreferences/adr-template.md- Architecture Decision Record template and examplereferences/api-reference-template.md- API documentation format with examplesreferences/runbook-template.md- Operational runbook templatescripts/validate-docs.sh- Documentation validation script- Version field in frontmatter for skill tracking
Improved
- Anti-patterns section now covers 10 common documentation mistakes
- Quality checklist expanded with Diátaxis alignment
- Better cross-references to external documentation resources
[1.0.0] - 2024-01-01
Added
- Initial technical-writer skill
- Diátaxis framework guidance
- README, ADR, API Reference, and Runbook templates
- Documentation tooling recommendations
Architecture Decision Record (ADR) Template
Based on Michael Nygard's ADR format
# ADR-NNN: [Short Title of Decision]
## Status
[Proposed | Accepted | Deprecated | Superseded by ADR-XXX]
## Date
YYYY-MM-DD
## Context
[Describe the issue that motivates this decision. What is the problem we are trying to solve? What forces are at play? Include any constraints, requirements, or trade-offs that need to be considered.]
### Options Considered
1. **Option A** - Brief description
2. **Option B** - Brief description
3. **Option C** - Brief description
## Decision
[State the decision clearly. Use active voice: "We will use..." not "It was decided..."]
## Rationale
### Why [Chosen Option]
[Explain why this option was selected over alternatives. Include:]
- Key factors that led to this decision
- How it addresses the forces identified in Context
- Benefits this option provides
### Why Not [Other Options]
[Briefly explain why other options were rejected]
- **Option A**: [Reason for rejection]
- **Option B**: [Reason for rejection]
## Consequences
### Positive
[List the benefits and positive outcomes of this decision]
- Benefit 1
- Benefit 2
- Benefit 3
### Negative
[List the drawbacks and trade-offs accepted]
- Trade-off 1
- Trade-off 2
### Risks
[List any risks and mitigation strategies]
- **Risk 1**: [Description]
- **Mitigation**: [How we'll address this risk]
## Related Decisions
[List related ADRs]
- ADR-XXX: [Related decision title]
- ADR-YYY: [Another related decision]
## References
[Links to external resources, documentation, or research]
- [Link 1](url)
- [Link 2](url)---
Complete Example: Database Selection
# ADR-001: Use PostgreSQL as Primary Database
## Status
Accepted
## Date
2024-01-15
## Context
We need to select a primary database for the application. The requirements are:
- ACID compliance for transactional integrity
- Support for JSON data alongside relational data
- Horizontal read scalability
- Strong ecosystem and tooling support
- Team familiarity
### Options Considered
1. **PostgreSQL** - Open-source relational database
2. **MySQL** - Open-source relational database
3. **MongoDB** - Document-oriented NoSQL database
4. **CockroachDB** - Distributed SQL database
## Decision
We will use PostgreSQL as our primary database.
## Rationale
### Why PostgreSQL
- **JSONB support**: Native JSON storage with indexing solves our semi-structured data needs without requiring a separate document store
- **Strong consistency**: ACID compliance ensures data integrity for financial transactions
- **Mature ecosystem**: Excellent tooling (pgAdmin, pg_dump, logical replication)
- **Extensions**: PostGIS for geospatial, pg_trgm for fuzzy search, timescaledb for time-series
- **Team experience**: 3 of 4 developers have PostgreSQL production experience
- **Read replicas**: Can scale reads horizontally when needed
### Why Not Others
- **MySQL**: Less capable JSON support, fewer advanced features
- **MongoDB**: Team unfamiliar, eventual consistency concerns for transactions
- **CockroachDB**: Overkill for current scale, higher operational complexity
## Consequences
### Positive
- Single database technology reduces operational overhead
- JSONB eliminates need for separate document store
- Strong hiring pool familiar with PostgreSQL
- Clear upgrade path to managed services (RDS, Cloud SQL)
### Negative
- Must manage schema migrations carefully
- Write scaling limited to vertical scaling initially
- Need to monitor connection pooling (pgBouncer may be needed)
### Risks
- **Data growth**: If data exceeds single-node capacity, will need sharding strategy
- **Mitigation**: Monitor growth, plan sharding evaluation at 500GB
## Related Decisions
- ADR-002: Connection pooling strategy
- ADR-003: Backup and recovery procedures
## References
- [PostgreSQL 16 Documentation](https://www.postgresql.org/docs/16/)
- [The Twelve-Factor App: Backing Services](https://12factor.net/backing-services)---
ADR Best Practices
Naming Convention
ADR-001-use-postgresql-for-database.md- Numbered, lowercase, hyphen-separated
When to Write an ADR
- Significant architectural decisions
- Technology selections
- Design pattern choices
- Security-critical decisions
- Anything someone might question later
When NOT to Write an ADR
- Obvious choices with no alternatives
- Purely implementation details
- Temporary decisions during prototyping
ADR Lifecycle
1. Proposed - Under discussion 2. Accepted - Decision made, in effect 3. Deprecated - No longer recommended but still exists 4. Superseded - Replaced by newer decision
API Reference Documentation Template
Complete endpoint documentation format
# [Resource] API
[Brief description of what this API resource manages]
## Base URL
https://api.example.com/v1
## Authentication
[Explain authentication requirements]
All endpoints require authentication via Bearer token:
curl -H "Authorization: Bearer YOUR_API_TOKEN" \ https://api.example.com/v1/[resource]
---
## Endpoints
### List [Resources]
[Brief description of what this endpoint does]
GET /[resources]
#### Query Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `limit` | integer | 20 | Maximum items to return (1-100) |
| `cursor` | string | - | Pagination cursor from previous response |
| `status` | string | - | Filter by status: `active`, `inactive` |
| `sort` | string | `created_at` | Sort field |
| `order` | string | `desc` | Sort order: `asc`, `desc` |
#### Response
{ "data": [ { "id": "[prefix]_123abc", "field1": "value1", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } ], "meta": { "has_more": true, "next_cursor": "eyJpZCI6MTIzfQ" } }
#### Example Request
curl -X GET "https://api.example.com/v1/[resources]?limit=10" \ -H "Authorization: Bearer YOUR_API_TOKEN"
---
### Get [Resource]
Retrieve a single [resource] by ID.
GET /[resources]/:id
#### Path Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `id` | string | The [resource] ID |
#### Response
{ "data": { "id": "[prefix]_123abc", "field1": "value1", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } }
---
### Create [Resource]
Create a new [resource].
POST /[resources]
#### Request Body
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `field1` | string | Yes | Description of field1 |
| `field2` | string | No | Description of field2 |
| `metadata` | object | No | Custom key-value pairs |
#### Example Request
curl -X POST "https://api.example.com/v1/[resources]" \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "field1": "value1", "field2": "value2" }'
#### Response
{ "data": { "id": "[prefix]_456def", "field1": "value1", "field2": "value2", "created_at": "2024-01-15T14:22:00Z", "updated_at": "2024-01-15T14:22:00Z" } }
---
### Update [Resource]
Update an existing [resource].
PATCH /[resources]/:id
#### Request Body
All fields are optional. Only provided fields will be updated.
| Field | Type | Description |
|-------|------|-------------|
| `field1` | string | New value for field1 |
| `field2` | string | New value for field2 |
---
### Delete [Resource]
Delete a [resource].
DELETE /[resources]/:id
#### Response
{ "data": { "id": "[prefix]_123abc", "deleted": true } }
---
## Error Responses
All errors follow a consistent format:
{ "error": { "code": "ERROR_CODE", "message": "Human-readable error message", "details": [ { "field": "field_name", "issue": "Specific validation error" } ] } }
### Error Codes
| Code | HTTP Status | Description |
|------|-------------|-------------|
| `VALIDATION_ERROR` | 400 | Request validation failed |
| `UNAUTHORIZED` | 401 | Invalid or missing authentication |
| `FORBIDDEN` | 403 | Insufficient permissions |
| `NOT_FOUND` | 404 | Resource not found |
| `CONFLICT` | 409 | Resource already exists |
| `RATE_LIMITED` | 429 | Too many requests |
| `INTERNAL_ERROR` | 500 | Server error |
---
## Rate Limiting
API requests are rate limited based on your plan:
| Plan | Requests/minute | Requests/day |
|------|-----------------|--------------|
| Free | 60 | 1,000 |
| Pro | 600 | 50,000 |
| Enterprise | Custom | Custom |
Rate limit headers are included in all responses:
X-RateLimit-Limit: 60 X-RateLimit-Remaining: 45 X-RateLimit-Reset: 1640000000
---
## Pagination
List endpoints use cursor-based pagination.
### Request
First page
curl "https://api.example.com/v1/[resources]?limit=10"
Next page
curl "https://api.example.com/v1/[resources]?limit=10&cursor=eyJpZCI6MTIzfQ"
### Response Meta
{ "meta": { "has_more": true, "next_cursor": "eyJpZCI6MTIzfQ" } }
---
Best Practices
Endpoint Documentation Checklist
- [ ] HTTP method and path
- [ ] All path parameters
- [ ] All query parameters with types and defaults
- [ ] Request body schema with required fields marked
- [ ] Example request (curl or language-specific)
- [ ] Success response with realistic data
- [ ] Error responses for common cases
Writing Guidelines
- Use consistent ID prefixes (e.g.,
usr_,ord_,inv_) - Show realistic example data, not "foo" and "bar"
- Include timestamps in ISO 8601 format
- Document rate limits and pagination
- List all possible error codes
README Template Reference
Copy and customize for your project
# Project Name
Brief description of what this project does and who it's for.
[](https://github.com/org/repo/actions)
[](https://www.npmjs.com/package/package)
[](LICENSE)
## Features
- ✅ Feature one with benefit
- ✅ Feature two with benefit
- ✅ Feature three with benefit
## Quick Start
### Prerequisites
- Node.js 18+
- PostgreSQL 15+
### Installation
npm install package-name
### Basic Usage
import { Client } from 'package-name';
const client = new Client({ apiKey: process.env.API_KEY, });
const result = await client.doSomething({ input: 'value', });
console.log(result);
## Documentation
| Resource | Description |
|----------|-------------|
| \[Getting Started\](docs/getting-started.md) | First-time setup guide |
| \[API Reference\](docs/api-reference.md) | Complete API documentation |
| \[Examples\](examples/) | Code examples and recipes |
| \[FAQ\](docs/faq.md) | Frequently asked questions |
## Configuration
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `apiKey` | `string` | - | Your API key (required) |
| `timeout` | `number` | `30000` | Request timeout in ms |
| `retries` | `number` | `3` | Number of retry attempts |
## Examples
### Example 1: Basic Operation
// Description of what this example demonstrates const result = await client.basicOperation();
### Example 2: Advanced Usage
// Description of what this example demonstrates const result = await client.advancedOperation({ option1: 'value1', option2: true, });
## Troubleshooting
### Common Issues
**Error: Authentication failed**
Ensure your API key is valid and has the necessary permissions.
Verify your API key
curl -H "Authorization: Bearer $API_KEY" https://api.example.com/verify
**Error: Connection timeout**
Check your network connection and firewall settings.
## Contributing
We welcome contributions! Please see our \[Contributing Guide\](CONTRIBUTING.md) for details.
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## License
This project is licensed under the MIT License - see the \[LICENSE\](LICENSE) file for details.
## Support
- 📖 [Documentation](https://docs.example.com)
- 💬 [Discord Community](https://discord.gg/example)
- 🐛 [Issue Tracker](https://github.com/org/repo/issues)Structure Explanation
Essential Sections
1. Title + Description: What it is, who it's for 2. Badges: Build status, version, license (credibility signals) 3. Features: Quick value proposition 4. Quick Start: Get running in under 5 minutes 5. Documentation Links: Navigate to detailed docs 6. Configuration: All options in one place 7. Troubleshooting: Common issues and fixes 8. Contributing: How to help 9. License + Support: Legal and help channels
Best Practices
- Lead with value (features before installation)
- All code examples must be copy-pasteable
- Use tables for structured data (config, links)
- Include error scenarios, not just happy path
- Link to external docs rather than duplicate
Runbook Template Reference
Operational procedure for incident response
# Runbook: [Procedure Name]
## Overview
[Brief description of what this runbook covers and when to use it]
**Severity**: [SEV-1 | SEV-2 | SEV-3]
**Expected Duration**: [X-Y minutes]
**Required Access**: [List required permissions/roles]
## Prerequisites
- [ ] Access to [system/tool]
- [ ] [Permission/credential] available
- [ ] Communication channel access (#incidents)
- [ ] [Any other prerequisites]
## Detection
### Alerts That Trigger This Runbook
- `[AlertName]` - [Brief description]
- `[AlertName]` - [Brief description]
### Verification Steps
1. Check [specific metric/log]:[command to verify issue]
2. Confirm [condition]:[command to confirm]
## Procedure
### Step 1: [Step Name] ([X] min)
[Description of what to do]
[commands to execute]
**Expected Result**: [What you should see if successful]
### Step 2: [Step Name] ([X] min)
[Description]
[commands]
### Step 3: [Step Name] ([X] min)
[Description]
**If [condition A]:**[commands for condition A]
**If [condition B]:**[commands for condition B]
## Verification
After completing the procedure, verify success:
1. [ ] [Check 1]
2. [ ] [Check 2]
3. [ ] [Check 3]
## Rollback
If the procedure causes issues:
1. [Rollback step 1]
2. [Rollback step 2]
3. [Contact for escalation]
## Contacts
| Role | Name | Contact |
|------|------|---------|
| [Role] On-Call | Rotation | [Contact method] |
| [Team] Lead | [Name] | [Contact] |
| Escalation | [Name] | [Contact] |
## Related Documentation
- [Link to related doc 1]
- [Link to related doc 2]---
Complete Example: Database Failover
# Runbook: Database Failover
## Overview
This runbook covers the procedure for promoting a PostgreSQL replica to primary during a failover event.
**Severity**: SEV-1
**Expected Duration**: 15-30 minutes
**Required Access**: DBA on-call, Platform Engineer
## Prerequisites
- [ ] Access to AWS Console or CLI
- [ ] Database admin credentials
- [ ] Slack access for #incidents channel
- [ ] PagerDuty acknowledgment
## Detection
### Alerts That Trigger This Runbook
- `PostgresPrimaryDown` - Primary database unreachable
- `PostgresReplicationLag > 60s` - Replication significantly delayed
- `PostgresConnectionPoolExhausted` - No available connections
### Verification Steps
1. Check database connectivity:psql -h primary.db.internal -U admin -c "SELECT 1"
2. Check replication status:psql -h replica.db.internal -U admin -c "SELECT pg_is_in_recovery()"
3. Check CloudWatch metrics in AWS Console
## Procedure
### Step 1: Assess the Situation (2 min)
1. Confirm the alert is not a false positive
2. Check if the issue is network-related vs database-related
3. Notify in #incidents: "Investigating database issues, may need failover"
### Step 2: Attempt Primary Recovery (5 min)
If primary appears to be having transient issues:
Check process status
ssh primary-db 'sudo systemctl status postgresql'
Check disk space
ssh primary-db 'df -h'
Check logs
ssh primary-db 'sudo tail -100 /var/log/postgresql/postgresql-15-main.log'
If recoverable, restart the service:ssh primary-db 'sudo systemctl restart postgresql'
**If recovery fails after 5 minutes, proceed to failover.**
### Step 3: Initiate Failover (5 min)
1. **Stop writes to primary** (if still accessible):-- On primary ALTER SYSTEM SET default_transaction_read_only = on; SELECT pg_reload_conf();
2. **Promote replica**:AWS RDS
aws rds promote-read-replica --db-instance-identifier replica-db
Self-managed
ssh replica-db 'sudo -u postgres pg_ctl promote -D /var/lib/postgresql/15/main'
3. **Verify promotion**:psql -h replica.db.internal -U admin -c "SELECT pg_is_in_recovery()"
Should return 'f' (false)
### Step 4: Update Application Configuration (3 min)
1. **Update DNS** (if using DNS-based failover):aws route53 change-resource-record-sets \ --hosted-zone-id ZONE_ID \ --change-batch file://failover-dns.json
2. **Or update connection strings** via config management:Update Kubernetes secret
kubectl patch secret db-credentials -n production \ -p '{"data":{"host":"'$(echo -n "new-primary.db.internal" | base64)'"}}'
Restart application pods
kubectl rollout restart deployment/app -n production
### Step 5: Verify Application Health (5 min)
1. Check application logs for database errors
2. Monitor error rates in Datadog/Grafana
3. Verify key user flows are working
4. Check connection pool metrics
### Step 6: Post-Failover Tasks
1. **Create new replica** from new primary
2. **Investigate root cause** of original primary failure
3. **Update monitoring** to point to new topology
4. **Document incident** in post-mortem
## Rollback
If the failover causes issues:
1. **Stop application traffic** (enable maintenance mode)
2. **Restore original primary** from backup if needed
3. **Re-point applications** to original primary
4. **Investigate** why failover failed
## Contacts
| Role | Name | Contact |
|------|------|---------|
| DBA On-Call | Rotation | PagerDuty |
| Platform Lead | Jane Smith | @jane.smith |
| VP Engineering | John Doe | @john.doe (escalation) |
## Related Documentation
- \[Database Architecture\](../architecture/database.md)
- \[Backup & Recovery\](./backup-recovery.md)
- \[Incident Response Process\](../processes/incident-response.md)---
Runbook Best Practices
Structure
- Start with overview and severity
- List all prerequisites upfront
- Include verification at each step
- Always have a rollback section
- End with contacts and related docs
Commands
- All commands must be copy-pasteable
- Include expected output where helpful
- Use environment variables for secrets
- Show both success and failure indicators
Maintenance
- Review runbooks quarterly
- Update after every incident where used
- Include "last tested" date
- Conduct dry-runs for critical procedures
#!/bin/bash
# Technical Writer Skill Validation Script
# Validates documentation for best practices and completeness
set -e
ERRORS=0
WARNINGS=0
echo "═══════════════════════════════════════════════════════════════"
echo "Technical Writer Skill Validator"
echo "═══════════════════════════════════════════════════════════════"
echo ""
# Check README
check_readme() {
echo "📖 Checking README files..."
for readme in README.md README.rst readme.md; do
[ -f "$readme" ] || continue
echo " Found $readme"
# Check for required sections
if ! grep -qi "## Installation\|## Quick Start\|## Getting Started" "$readme" 2>/dev/null; then
echo "⚠️ WARN: $readme missing installation/quick start section"
((WARNINGS++))
fi
# Check for code examples
if ! grep -q '```' "$readme" 2>/dev/null; then
echo "⚠️ WARN: $readme has no code examples"
((WARNINGS++))
fi
# Check for license info
if ! grep -qi "license" "$readme" 2>/dev/null; then
echo "⚠️ WARN: $readme missing license information"
((WARNINGS++))
fi
# Check for broken markdown links
while IFS= read -r line; do
link=$(echo "$line" | grep -oE '\[.*\]\([^)]+\)' | head -1)
file=$(echo "$link" | sed 's/.*(\([^)]*\)).*/\1/' | sed 's/#.*//')
# Skip URLs
if echo "$file" | grep -qE '^https?://'; then
continue
fi
# Check if file exists
if [ -n "$file" ] && [ ! -f "$file" ]; then
echo "❌ ERROR: Broken link in $readme: $file"
((ERRORS++))
fi
done < "$readme"
done
}
# Check documentation structure
check_docs_structure() {
echo ""
echo "📁 Checking documentation structure..."
if [ -d "docs" ]; then
echo " Found docs/ directory"
# Check for index/getting started
if [ ! -f "docs/index.md" ] && [ ! -f "docs/getting-started.md" ]; then
echo "⚠️ WARN: docs/ missing index.md or getting-started.md"
((WARNINGS++))
fi
# Count documentation files
doc_count=$(find docs -name "*.md" 2>/dev/null | wc -l)
echo " Found $doc_count markdown files"
if [ "$doc_count" -lt 3 ]; then
echo "ℹ️ INFO: Consider adding more documentation"
fi
else
echo "ℹ️ No docs/ directory found"
fi
}
# Check for ADRs
check_adrs() {
echo ""
echo "📋 Checking Architecture Decision Records..."
adr_dirs=("docs/adr" "docs/adrs" "adr" "docs/decisions")
found_adr=false
for dir in "${adr_dirs[@]}"; do
if [ -d "$dir" ]; then
found_adr=true
adr_count=$(find "$dir" -name "*.md" 2>/dev/null | wc -l)
echo " Found $adr_count ADRs in $dir"
# Check ADR format
for adr in "$dir"/*.md; do
[ -f "$adr" ] || continue
if ! grep -qi "## Status" "$adr" 2>/dev/null; then
echo "⚠️ WARN: $adr missing Status section"
((WARNINGS++))
fi
if ! grep -qi "## Context\|## Decision\|## Consequences" "$adr" 2>/dev/null; then
echo "⚠️ WARN: $adr missing required ADR sections"
((WARNINGS++))
fi
done
fi
done
if [ "$found_adr" = false ]; then
echo "ℹ️ No ADR directory found (consider docs/adr/)"
fi
}
# Check API documentation
check_api_docs() {
echo ""
echo "🔌 Checking API documentation..."
if [ -f "openapi.yaml" ] || [ -f "openapi.yml" ] || [ -f "swagger.yaml" ]; then
echo " Found OpenAPI specification"
fi
if [ -f "docs/api-reference.md" ] || [ -d "docs/api" ]; then
echo " Found API documentation"
# Check for required API doc elements
for api_doc in docs/api*.md docs/api/*.md; do
[ -f "$api_doc" ] || continue
if ! grep -qi "## Authentication\|## Endpoints\|## Error" "$api_doc" 2>/dev/null; then
echo "⚠️ WARN: $api_doc may be missing key sections (Authentication, Endpoints, Errors)"
((WARNINGS++))
fi
done
fi
}
# Check for runbooks
check_runbooks() {
echo ""
echo "📕 Checking runbooks..."
runbook_dirs=("docs/runbooks" "runbooks" "docs/operations")
for dir in "${runbook_dirs[@]}"; do
if [ -d "$dir" ]; then
runbook_count=$(find "$dir" -name "*.md" 2>/dev/null | wc -l)
echo " Found $runbook_count runbooks in $dir"
for runbook in "$dir"/*.md; do
[ -f "$runbook" ] || continue
# Check for required runbook sections
if ! grep -qi "## Prerequisites\|## Procedure" "$runbook" 2>/dev/null; then
echo "⚠️ WARN: $runbook missing Prerequisites or Procedure section"
((WARNINGS++))
fi
# Check for rollback section (critical for ops)
if ! grep -qi "## Rollback\|## Recovery" "$runbook" 2>/dev/null; then
echo "⚠️ WARN: $runbook missing Rollback section"
((WARNINGS++))
fi
done
fi
done
}
# Check changelog
check_changelog() {
echo ""
echo "📝 Checking changelog..."
if [ -f "CHANGELOG.md" ]; then
echo " Found CHANGELOG.md"
# Check for Keep a Changelog format
if grep -qi "## \[Unreleased\]\|## \[[0-9]" CHANGELOG.md 2>/dev/null; then
echo " ✅ Follows Keep a Changelog format"
else
echo "⚠️ WARN: CHANGELOG.md may not follow Keep a Changelog format"
((WARNINGS++))
fi
else
echo "⚠️ WARN: No CHANGELOG.md found"
((WARNINGS++))
fi
}
# Check for common documentation issues
check_common_issues() {
echo ""
echo "🔍 Checking for common issues..."
# Check for TODO/FIXME in docs
todo_count=$(grep -ri "TODO\|FIXME\|TBD" docs/ README.md 2>/dev/null | wc -l)
if [ "$todo_count" -gt 0 ]; then
echo "⚠️ WARN: Found $todo_count TODO/FIXME/TBD markers in documentation"
((WARNINGS++))
fi
# Check for placeholder text
placeholder_count=$(grep -ri "lorem ipsum\|example.com\|foo@bar" docs/ README.md 2>/dev/null | wc -l)
if [ "$placeholder_count" -gt 5 ]; then
echo "⚠️ WARN: Found $placeholder_count instances of placeholder text"
((WARNINGS++))
fi
# Check for very short files (likely incomplete)
for doc in docs/*.md; do
[ -f "$doc" ] || continue
lines=$(wc -l < "$doc")
if [ "$lines" -lt 10 ]; then
echo "⚠️ WARN: $doc is very short ($lines lines) - may be incomplete"
((WARNINGS++))
fi
done
}
# Run all checks
check_readme
check_docs_structure
check_adrs
check_api_docs
check_runbooks
check_changelog
check_common_issues
# Summary
echo ""
echo "═══════════════════════════════════════════════════════════════"
echo "Validation Complete"
echo "═══════════════════════════════════════════════════════════════"
echo "Errors: $ERRORS"
echo "Warnings: $WARNINGS"
echo ""
if [ $ERRORS -gt 0 ]; then
echo "❌ Validation FAILED - fix errors before publishing"
exit 1
elif [ $WARNINGS -gt 5 ]; then
echo "⚠️ Validation PASSED with warnings - review recommended"
exit 0
else
echo "✅ Validation PASSED"
exit 0
fi