> built 2026-09-22 17:17 UTC from abc162c (main) · opsward 0.0.14. Details: build_info.json

# index.html.md

<!-- generated by epythet -->

# opsward

Diagnose, generate, and maintain the AI agent setup of your projects —
CLAUDE.md, skills, subagents, rules, and supporting docs.

Opsward works in two modes:

- **CLI mode** — deterministic, pure-code analysis you run directly. No AI involved.
- **Claude Code mode** — install opsward as Claude Code skills so that Claude runs the
  CLI tools, interprets results intelligently, and acts on suggestions. No API keys
  needed — Claude Code is the AI engine.

## Install

```bash
pip install opsward
```

---

## CLI Mode (no AI)

These commands are deterministic Python code — regex scoring, filesystem checks,
template substitution. Same input always gives the same output.

### Diagnose

Score your project’s AI setup health:

```bash
opsward diagnose .
```

```default
Diagnosis Report: myproject
Project type: python
Overall score: 72/100  (Grade: C)

Components:
  CLAUDE.md quality         [################....] 81/100
  Documentation             [##############......] 70/100
  Skills                    [############........] 60/100
  Setup (rules/agents/hooks) [##########..........] 50/100
  Cross-references          [####################] 100/100

Missing:
  [ ] docs_guide.md
  [ ] docs/known_issues.md

Suggestions:
  1. Create a docs_guide.md to index your documentation
  2. Consider adding hooks in .claude/hooks.json
```

### Generate

Create missing artifacts (dry run by default):

```bash
opsward generate .
opsward generate . --write   # actually create files
```

Generates CLAUDE.md, docs (architecture, conventions, known_issues, etc.),
skill templates, and agents — only what’s missing, never overwrites existing files.

### Maintain

Find stale references and drift:

```bash
opsward maintain .
```

```default
myproject: 3 issue(s)

  [stale_path] CLAUDE.md references `src/old_module.py` but it does not exist
  [sync_issue] `new_doc.md` exists in docs/ but is not listed in docs_guide.md
  [empty_doc] `conventions.md` appears to be an empty stub (12 bytes)
```

### Output Formats

All CLI commands support `--format json` for machine-parseable output:

```bash
opsward diagnose . --format json
opsward generate . --format json
opsward maintain . --format json
```

---

## Claude Code Mode (AI-enhanced)

Install opsward’s skills into Claude Code, and Claude becomes an intelligent
layer on top of the deterministic tools. It doesn’t just run opsward — it goes
beyond the heuristic scores by reading actual source code, reasoning about
accuracy, and making intelligent edits.

### Install Skills

```bash
opsward install-skills --write                    # into ./.claude/ (project-level)
opsward install-skills --global-install --write   # into ~/.claude/ (all projects)
```

### What the Skills Do

Once installed, these skills activate automatically in Claude Code when you ask
the right thing:

| Skill              | Trigger                     | What it does                                                                           |
|--------------------|-----------------------------|----------------------------------------------------------------------------------------|
| `opsward`          | “check my setup”, “opsward” | Diagnose → decide next step → generate or maintain → re-diagnose                       |
| `opsward-diagnose` | “audit my AI config”        | Run `opsward diagnose`, then read code to assess semantic quality, offer fixes         |
| `opsward-generate` | “scaffold AI setup”         | Run `opsward generate`, then read the codebase and replace templates with real content |
| `opsward-maintain` | “check for staleness”       | Run `opsward maintain`, then check for semantic drift (docs that no longer match code) |

### How It Works

1. **Opsward CLI** runs deterministic checks (regex scoring, path validation, template substitution) — fast, reproducible, no AI
2. **Claude reads the output** and adds deeper analysis: reads actual source code, checks if docs match reality, verifies commands are correct
3. **Claude proposes fixes** — not just what opsward suggests, but what it discovers by understanding the code
4. **Claude applies fixes** with user approval, then re-runs opsward to show improvement

The CLI provides the structural analysis. Claude provides the semantic understanding and action.

### Permissions

The skills use Claude Code’s standard permission model — no special permissions are
assumed or required:

- **Read-only operations** (reading files, searching code, running `opsward diagnose`): always safe, used freely
- **Write operations** (creating docs, editing CLAUDE.md): Claude Code prompts the user for each action per their permission settings
- **Destructive operations** (deleting files, removing content): always ask for explicit confirmation

If you want faster workflows (e.g., auto-approve file creation during generation),
you can configure that in your Claude Code permission settings — but opsward skills
never assume it.

---

## What It Checks

**CLAUDE.md quality** (6 dimensions):

- Commands & workflows — are build/test/lint commands documented?
- Architecture clarity — is there a module map with role descriptions?
- Conventions — are project-specific style rules present?
- Conciseness — is the file scannable, not bloated?
- Currency — do referenced paths actually exist?
- Actionability — are instructions specific enough to act on?

**Documentation completeness**: docs_guide.md, architecture.md, conventions.md,
known_issues.md, and content quality.

**Skills & agents**: SKILL.md presence, descriptions, setup-auditor agent.

**Cross-references**: paths in CLAUDE.md validated against the filesystem.

**Overall health**: weighted score (A–F grade) combining all components.

## Python API

```python
from pathlib import Path
from opsward import scan, diagnose, generate, generate_skills, maintain
from opsward import recommend_skills, validate_skill_spec

sr = scan(".")
report = diagnose(sr)
print(report)  # human-readable report card
print(report.grade)  # 'A', 'B', 'C', 'D', or 'F'

files = generate(sr)  # list[GeneratedFile]
issues = maintain(sr)  # list[MaintenanceSuggestion]

# Recommend ecosystem skills based on tech stack
recs = recommend_skills(sr)  # list[SkillRecommendation]

# Validate skills against agentskills.io spec
for skill in sr.skills:
    violations = validate_skill_spec(skill)

# Install skills programmatically
skill_files = generate_skills(Path.home() / ".claude")
```

## CI Integration

Use opsward in CI to enforce AI setup quality:

```bash
# Fail if overall score drops below 60
opsward diagnose . --min-score 60

# Machine-parseable output for CI tooling
opsward diagnose . --format json --min-score 60
```

```yaml
# .github/workflows/ai-setup-check.yml
name: AI Setup Check
on: [pull_request]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install opsward
      - run: opsward diagnose . --min-score 60
```

## Related Work

| Project                                                                                  | Relationship                                                                     |
|------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
| [spec-kit](https://github.com/github/spec-kit) (GitHub)                                  | Template-based scaffolding for 20+ AI agents. No diagnosis/scoring/maintenance.  |
| [claude-code-skill-factory](https://github.com/alirezarezvani/claude-code-skill-factory) | Inside-agent builders for skills, agents, hooks. Good for interactive authoring. |
| [ccexp](https://github.com/nyatinte/ccexp)                                               | Interactive TUI for browsing Claude Code config files. Complements opsward.      |
| [npx skills](https://github.com/vercel-labs/skills) (Vercel)                             | Cross-platform skill package manager. Opsward-generated skills are compatible.   |
| [awesome-agent-skills](https://github.com/VoltAgent/awesome-agent-skills)                | 549+ community skills from official dev teams.                                   |
| [awesome-claude-code](https://github.com/hesreallyhim/awesome-claude-code)               | Best single index of the Claude Code ecosystem.                                  |
| [wshobson/agents](https://github.com/wshobson/agents)                                    | Pre-built plugin monorepo (72 plugins, 112 agents, 146 skills).                  |
| [Mintlify skill.md](https://www.mintlify.com/blog/skill-md)                              | Auto-generates skill.md from docs sites. Same philosophy, different input.       |
<p class="epythet-aggregates">This documentation as a single file: <a href="opsward.md">opsward.md</a> (Markdown, for agents).</p>


# _autosummary/opsward.base.html.md

# opsward.base

All dataclasses and type definitions for opsward.

### Classes

| [`AgentInfo`](_autosummary/opsward.base.html.md#opsward.base.AgentInfo)(name, path[, description])            | An agent found in .claude/agents/.                                 |
|--------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|
| [`ComponentScore`](_autosummary/opsward.base.html.md#opsward.base.ComponentScore)(name, score[, max_score, notes]) | Score for a single component (0–100) with optional notes.          |
| [`DiagnosisReport`](_autosummary/opsward.base.html.md#opsward.base.DiagnosisReport)(project_root, project_type)     | Report card produced by scoring a ScanResult.                      |
| [`DocSpec`](_autosummary/opsward.base.html.md#opsward.base.DocSpec)(name, path[, size_bytes])               | A document found in the docs directory.                            |
| [`GeneratedFile`](_autosummary/opsward.base.html.md#opsward.base.GeneratedFile)(target_path, content[, ...])      | A file to be written by the generate step.                         |
| [`MaintenanceSuggestion`](_autosummary/opsward.base.html.md#opsward.base.MaintenanceSuggestion)(category, description)    | A single maintenance action proposed by maintain.py.               |
| [`ProjectType`](_autosummary/opsward.base.html.md#opsward.base.ProjectType)(\*values)                           | Detected project type.                                             |
| [`RuleInfo`](_autosummary/opsward.base.html.md#opsward.base.RuleInfo)(name, path[, content])                 | A rule found in .claude/rules/.                                    |
| [`ScanResult`](_autosummary/opsward.base.html.md#opsward.base.ScanResult)(project_root[, project_type, ...])   | Everything we learned by reading (never writing) a target project. |
| [`SkillInfo`](_autosummary/opsward.base.html.md#opsward.base.SkillInfo)(name, path[, has_skill_md, ...])      | A skill found in .claude/skills/.                                  |

### *class* opsward.base.AgentInfo(name, path, description='')

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

An agent found in .claude/agents/.

### *class* opsward.base.ComponentScore(name, score, max_score=100, notes=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Score for a single component (0–100) with optional notes.

### *class* opsward.base.DiagnosisReport(project_root, project_type, scores=<factory>, missing_items=<factory>, suggestions=<factory>, weighted_score=0.0)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Report card produced by scoring a ScanResult.

#### *property* grade *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

A (90-100), B (80-89), C (70-79), D (60-69), F (<60).

* **Type:**
  Letter grade

#### *property* overall_score *: [float](https://docs.python.org/3/builtins/functions.html#float)*

Weighted score if set, else simple average.

### *class* opsward.base.DocSpec(name, path, size_bytes=0)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A document found in the docs directory.

### *class* opsward.base.GeneratedFile(target_path, content, overwrite_policy='skip')

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A file to be written by the generate step.

### *class* opsward.base.MaintenanceSuggestion(category, description, diff='')

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A single maintenance action proposed by maintain.py.

### *class* opsward.base.ProjectType(\*values)

Bases: [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Detected project type.

### *class* opsward.base.RuleInfo(name, path, content='')

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A rule found in .claude/rules/.

### *class* opsward.base.ScanResult(project_root, project_type=ProjectType.unknown, claude_md_path=None, claude_md_content='', skills=<factory>, agents=<factory>, rules=<factory>, hooks_path=None, hooks_config=None, docs=<factory>, has_docs_guide=False, docs_guide_path=None, agents_md_path=None, agents_md_content='', is_monorepo=False, monorepo_packages=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Everything we learned by reading (never writing) a target project.

### *class* opsward.base.SkillInfo(name, path, has_skill_md=False, description='', frontmatter=<factory>, line_count=0)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A skill found in .claude/skills/.


# _autosummary/opsward.cli.html.md

# opsward.cli

CLI dispatch for opsward.

### Functions

| [`diagnose`](_autosummary/opsward.cli.html.md#opsward.cli.diagnose)(\*project_roots[, format, verbose, ...])   | Diagnose the AI agent setup of one or more projects.                          |
|------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------|
| [`find`](_autosummary/opsward.cli.html.md#opsward.cli.find)(query, \*project_roots[, kinds, ...])          | Find assets (skills, agents, docs) across one or more projects by QUERY.      |
| [`generate`](_autosummary/opsward.cli.html.md#opsward.cli.generate)(\*project_roots[, write, format, ...])     | Generate missing AI setup artifacts for one or more projects.                 |
| [`install_skills`](_autosummary/opsward.cli.html.md#opsward.cli.install_skills)([target, global_install, ...])       | Install opsward's Claude Code skills (and agents) into a project or globally. |
| [`maintain`](_autosummary/opsward.cli.html.md#opsward.cli.maintain)(\*project_roots[, format])                 | Check for stale references, out-of-sync docs, and other drift.                |
| [`recommend`](_autosummary/opsward.cli.html.md#opsward.cli.recommend)(\*project_roots[, format])                | Recommend ecosystem skills based on the project's tech stack.                 |

### opsward.cli.diagnose(\*project_roots, format='text', verbose=False, min_score=80)

Diagnose the AI agent setup of one or more projects.

* **Parameters:**
  * **project_roots** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – one or more paths to project directories
  * **format** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – output format — ‘text’ or ‘json’
  * **verbose** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – show additional detail in text output
  * **min_score** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – minimum overall score to pass (exit 0); below this exits 1

### opsward.cli.find(query, \*project_roots, kinds='skill,agent', semantic=False, limit=10)

Find assets (skills, agents, docs) across one or more projects by QUERY.

Cross-repo asset discovery via the toolery package
(install with: pip install ‘opsward[discovery]’).

* **Parameters:**
  * **query** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – search query
  * **project_roots** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – one or more project directories (default: current dir)
  * **kinds** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – comma-separated asset kinds — skill, agent, doc
  * **semantic** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – use toolery’s ir semantic backend (needs toolery[ir])
  * **limit** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – max results to show

### opsward.cli.generate(\*project_roots, write=False, format='text', agents_md=False, hooks=False)

Generate missing AI setup artifacts for one or more projects.

By default, shows what would be created (dry run). Use –write to
actually write files. Existing files are never overwritten.

* **Parameters:**
  * **project_roots** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – one or more paths to project directories
  * **write** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – actually write files (default: dry run)
  * **format** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – output format — ‘text’ or ‘json’
  * **agents_md** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – also generate AGENTS.md (cross-platform agent instructions)
  * **hooks** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – also generate starter hook scripts

### opsward.cli.install_skills(target='.', , global_install=False, agents=True, write=False)

Install opsward’s Claude Code skills (and agents) into a project or globally.

By default, shows what would be created (dry run). Use –write to
actually write files. Existing files are never overwritten.

* **Parameters:**
  * **target** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – project directory (ignored when –global is set)
  * **global_install** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – install into ~/.claude/ instead of the project
  * **agents** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – also install agent definitions (default: True)
  * **write** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – actually write files (default: dry run)

### opsward.cli.maintain(\*project_roots, format='text')

Check for stale references, out-of-sync docs, and other drift.

* **Parameters:**
  * **project_roots** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – one or more paths to project directories
  * **format** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – output format — ‘text’ or ‘json’

### opsward.cli.recommend(\*project_roots, format='text')

Recommend ecosystem skills based on the project’s tech stack.

Analyzes dependencies and suggests skills from the community catalog.

* **Parameters:**
  * **project_roots** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – one or more paths to project directories
  * **format** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – output format — ‘text’ or ‘json’


# _autosummary/opsward.data.html.md

# opsward.data

Bundled package resources for opsward, accessed via `importlib.resources.files("opsward.data")`.

Holds the generation templates (under `templates/`) and any other static
assets the generator installs into target projects. Never hardcode filesystem
paths to these resources – resolve them through `importlib.resources`.

### Modules

| [`templates`](_autosummary/opsward.data.templates.html.md#module-opsward.data.templates)   | Generation templates organized by target project type.   |
|--------------------------------------------------------------------------------------------|----------------------------------------------------------|


# _autosummary/opsward.data.templates.html.md

# opsward.data.templates

Generation templates organized by target project type.

`shared/` holds templates (and installable Claude Code skills) that apply to
any project; `python/` and `jsts/` hold language-specific variants. The
generator reads these via `importlib.resources` and substitutes
`${variable}` placeholders (`string.Template`) before writing to a target.


# _autosummary/opsward.discover.html.md

# opsward.discover

Optional cross-repo asset discovery, delegating to the `toolery` package.

opsward scans and *scores* the AI setup of one repo; this adds *finding* assets — skills,
subagents, docs — across one or more repos. It is opt-in and keeps opsward’s core
dependency-light: `pip install 'opsward[discovery]'` pulls in `toolery` (add
`toolery[ir]` for semantic search). Conceptually this is opsward’s per-repo/fleet
orchestration meeting toolery’s discovery engine (epic #12 → #13).

### Functions

| [`find_assets`](_autosummary/opsward.discover.html.md#opsward.discover.find_assets)(\*roots, query[, kinds, ...])   | Find assets matching `query` across one or more project `roots`.   |
|----------------------------------------------------------------------------------------------|--------------------------------------------------------------------|

### opsward.discover.find_assets(\*roots, query, kinds='skill,agent', semantic=False, limit=10)

Find assets matching `query` across one or more project `roots`.

Harvests the requested `kinds` (comma-separated string or a sequence of
`"skill"`/`"agent"`/`"doc"`) from each root via `toolery` and returns ranked
`(Card, score)` results. With `semantic=True`, uses `toolery`’s ir federated
backend (needs `toolery[ir]`). Defaults to the current directory when no roots given.


# _autosummary/opsward.generate.html.md

# opsward.generate

### opsward.generate(scan_result, , agents_md=False, hooks=False)

Determine which artifacts are missing, render templates, return files to create.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`GeneratedFile`](_autosummary/opsward.base.html.md#opsward.base.GeneratedFile)]

```pycon
>>> from pathlib import Path
>>> from opsward.base import ScanResult
>>> files = generate(ScanResult(project_root=Path('/tmp/empty')))
>>> any(f.target_path.name == 'CLAUDE.md' for f in files)
True
```


# _autosummary/opsward.html.md

# opsward

Diagnose, generate, and maintain the AI agent setup of your projects.

### Modules

| [`base`](_autosummary/opsward.base.html.md#module-opsward.base)                                       | All dataclasses and type definitions for opsward.                                                |
|-----------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------|
| [`cli`](_autosummary/opsward.cli.html.md#module-opsward.cli)                                         | CLI dispatch for opsward.                                                                        |
| [`data`](_autosummary/opsward.data.html.md#module-opsward.data)                                       | Bundled package resources for opsward, accessed via `importlib.resources.files("opsward.data")`. |
| [`discover`](_autosummary/opsward.discover.html.md#module-opsward.discover)                               | Optional cross-repo asset discovery, delegating to the `toolery` package.                        |
| [`generate`](_autosummary/opsward.generate.html.md#opsward.generate)(scan_result, \*[, agents_md, hooks]) | Determine which artifacts are missing, render templates, return files to create.                 |
| [`maintain`](_autosummary/opsward.maintain.html.md#opsward.maintain)(scan_result, \*[, previous_report])  | Detect maintenance issues and return suggestions.                                                |
| [`recommend`](_autosummary/opsward.recommend.html.md#module-opsward.recommend)                             | Recommend skills from the ecosystem based on project tech stack.                                 |
| [`scan`](_autosummary/opsward.scan.html.md#opsward.scan)(project_root)                                | Scan *project_root* and return a ScanResult.                                                     |
| [`score`](_autosummary/opsward.score.html.md#module-opsward.score)                                     | Pure scoring functions.                                                                          |
| [`util`](_autosummary/opsward.util.html.md#module-opsward.util)                                       | Shared helpers for opsward.                                                                      |


# _autosummary/opsward.maintain.html.md

# opsward.maintain

### opsward.maintain(scan_result, , previous_report=None)

Detect maintenance issues and return suggestions.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`MaintenanceSuggestion`](_autosummary/opsward.base.html.md#opsward.base.MaintenanceSuggestion)]

```pycon
>>> from pathlib import Path
>>> from opsward.base import ScanResult
>>> maintain(ScanResult(project_root=Path('/tmp/empty')))
[]
```


# _autosummary/opsward.recommend.html.md

# opsward.recommend

Recommend skills from the ecosystem based on project tech stack.

Maps detected dependencies and frameworks to curated skill sources.

### Functions

| [`recommend_skills`](_autosummary/opsward.recommend.html.md#opsward.recommend.recommend_skills)(scan_result)   | Recommend ecosystem skills based on detected tech stack.   |
|----------------------------------------------------------------------------------|------------------------------------------------------------|

### Classes

| [`SkillRecommendation`](_autosummary/opsward.recommend.html.md#opsward.recommend.SkillRecommendation)(name, reason, source)   | A recommended skill from the ecosystem.   |
|----------------------------------------------------------------------------------------------|-------------------------------------------|

### *class* opsward.recommend.SkillRecommendation(name, reason, source)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A recommended skill from the ecosystem.

### opsward.recommend.recommend_skills(scan_result)

Recommend ecosystem skills based on detected tech stack.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`SkillRecommendation`](_autosummary/opsward.recommend.html.md#opsward.recommend.SkillRecommendation)]

```pycon
>>> from pathlib import Path
>>> from opsward.base import ScanResult
>>> recommend_skills(ScanResult(project_root=Path('/tmp/empty')))
[]
```


# _autosummary/opsward.scan.html.md

# opsward.scan

### opsward.scan(project_root)

Scan *project_root* and return a ScanResult.

* **Return type:**
  [`ScanResult`](_autosummary/opsward.base.html.md#opsward.base.ScanResult)

```pycon
>>> import tempfile, pathlib
>>> r = scan(pathlib.Path(tempfile.mkdtemp()))
>>> r.project_type
<ProjectType.unknown: 'unknown'>
```


# _autosummary/opsward.score.html.md

# opsward.score

Pure scoring functions. ScanResult -> DiagnosisReport.

All functions are pure — same input, same output.

### Functions

| [`diagnose`](_autosummary/opsward.score.html.md#opsward.score.diagnose)(scan_result)      | Score a ScanResult and return a DiagnosisReport.               |
|-----------------------------------------------------------------------------|----------------------------------------------------------------|
| [`validate_hooks_config`](_autosummary/opsward.score.html.md#opsward.score.validate_hooks_config)(cfg) | Validate a hooks config against Claude Code's expected shape.  |
| [`validate_skill_spec`](_autosummary/opsward.score.html.md#opsward.score.validate_skill_spec)(skill) | Validate a SkillInfo against the agentskills.io specification. |

### opsward.score.diagnose(scan_result)

Score a ScanResult and return a DiagnosisReport.

* **Return type:**
  [`DiagnosisReport`](_autosummary/opsward.base.html.md#opsward.base.DiagnosisReport)

```pycon
>>> from pathlib import Path
>>> from opsward.base import ScanResult
>>> r = diagnose(ScanResult(project_root=Path('/tmp/empty')))
>>> r.grade
'F'
```

### opsward.score.validate_hooks_config(cfg)

Validate a hooks config against Claude Code’s expected shape.

Returns a list of human-readable violation strings (empty = valid). Catches
the silent-failure traps: a non-string `matcher`, an unknown event name,
or an entry with no runnable `command` hook — none of which Claude Code
honors, so the hook never fires even though the file “looks” configured.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

```pycon
>>> validate_hooks_config({'hooks': {'PostToolUse': [
...     {'matcher': 'Edit', 'hooks': [{'type': 'command', 'command': 'x'}]}]}})
[]
>>> validate_hooks_config({'pre_commit': ['ruff']})
['no top-level `hooks` key']
>>> 'matcher' in validate_hooks_config({'hooks': {'PostToolUse': [
...     {'matcher': {'tool_name': 'Edit'}, 'hooks': [
...         {'type': 'command', 'command': 'x'}]}]}})[0]
True
```

### opsward.score.validate_skill_spec(skill)

Validate a SkillInfo against the agentskills.io specification.

Returns a list of human-readable violation strings (empty = compliant).

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

```pycon
>>> from pathlib import Path
>>> from opsward.base import SkillInfo
>>> s = SkillInfo(name='good-skill', path=Path('.'), has_skill_md=True,
...     frontmatter={'name': 'good-skill', 'description': 'Does X.'}, line_count=50)
>>> validate_skill_spec(s)
[]
```


# _autosummary/opsward.util.html.md

# opsward.util

Shared helpers for opsward.

### Functions

| [`iter_files`](_autosummary/opsward.util.html.md#opsward.util.iter_files)(directory, \*[, suffix])   | Yield files in *directory* (non-recursive), optionally filtered by suffix.   |
|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------|
| [`iter_subdirs`](_autosummary/opsward.util.html.md#opsward.util.iter_subdirs)(directory)               | Yield immediate subdirectories of *directory*, sorted by name.               |
| [`read_json_safe`](_autosummary/opsward.util.html.md#opsward.util.read_json_safe)(path)                  | Read a JSON file, returning None on any failure.                             |
| [`read_text_safe`](_autosummary/opsward.util.html.md#opsward.util.read_text_safe)(path)                  | Read a text file, returning '' if it doesn't exist or can't be decoded.      |

### opsward.util.iter_files(directory, , suffix='')

Yield files in *directory* (non-recursive), optionally filtered by suffix.

### opsward.util.iter_subdirs(directory)

Yield immediate subdirectories of *directory*, sorted by name.

### opsward.util.read_json_safe(path)

Read a JSON file, returning None on any failure.

* **Return type:**
  [`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)]

### opsward.util.read_text_safe(path)

Read a text file, returning ‘’ if it doesn’t exist or can’t be decoded.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> from pathlib import Path
>>> read_text_safe(Path('/nonexistent/file.txt'))
''
```


# about-this-build.html.md

<!-- generated by epythet -->

# About this build

This documentation was built on **2026-09-22 17:17 UTC** from commit <a href="https://github.com/thorwhalen/opsward/commit/abc162ca99dc88196ee52dbcd08ae0e614db7dd9"><code>abc162c</code></a> on branch <code>main</code>, for **opsward 0.0.14** (from <code>pyproject.toml</code>).

#### WARNING
The documentation and the package may be misaligned:

- The documented version (0.0.14) is behind the latest release on PyPI (0.0.15): `pip install opsward` gives newer code than these docs describe.

## Source

|                     |                                                                                                                                                           |
|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|
| Commit              | <a href="https://github.com/thorwhalen/opsward/commit/abc162ca99dc88196ee52dbcd08ae0e614db7dd9"><code>abc162ca99dc88196ee52dbcd08ae0e614db7dd9</code></a> |
| Branch              | <code>main</code>                                                                                                                                         |
| Tags at this commit | none                                                                                                                                                      |
| Working tree        | clean                                                                                                                                                     |
| Remote              | <code>https://github.com/thorwhalen/opsward</code>                                                                                                        |

## Continuous integration

|              |                                                                                            |
|--------------|--------------------------------------------------------------------------------------------|
| Repository   | <code>thorwhalen/opsward</code>                                                            |
| Run          | <a href="https://github.com/thorwhalen/opsward/actions/runs/35759548607">35759548607</a>   |
| Ref          | <code>refs/heads/main</code>                                                               |
| Event commit | <code>abc162ca99dc88196ee52dbcd08ae0e614db7dd9</code> (in the history of the built commit) |

## Tools

|          |         |
|----------|---------|
| epythet  | 0.2.12  |
| Sphinx   | 9.1.0   |
| docutils | 0.22.4  |
| Python   | 3.12.14 |

## Configuration as resolved

|               |                                                                  |
|---------------|------------------------------------------------------------------|
| theme         | <code>auto</code> (Sphinx theme <code>shibuya</code>)            |
| accent        | <code>#8f3254</code>                                             |
| api_generator | <code>autosummary</code>                                         |
| ignore        | <code>tests/</code>, <code>scrap/</code>, <code>examples/</code> |
| agent_outputs | <code>true</code>                                                |
| aggregates    | <code>md</code>                                                  |
| ai_artifacts  | <code>true</code>                                                |

## Package on PyPI

Latest release: <a href="https://pypi.org/project/opsward/0.0.15/">0.0.15</a>, newer than the documented version (0.0.14).

## Reproduce

```bash
git clone https://github.com/thorwhalen/opsward && cd opsward
git checkout abc162ca99dc88196ee52dbcd08ae0e614db7dd9
pip install "epythet==0.2.12"
epythet quickstart . --ignore tests/ scrap/ examples/
```

The same data, for machines: <a href="build_info.json"><code>build_info.json</code></a> (schema version 1).


# ai-agents.html.md

<!-- generated by epythet -->

# For AI agents

`opsward` ships artifacts for coding agents alongside its code. This page lists
them, says where each lives in the repository, and points at the
machine-readable copies of this documentation.

## Skills

Skills are folders holding a `SKILL.md` (the [Agent Skills](https://agentskills.io) format): a description that tells an agent when to use it and a body with the procedure. Install one into your agent with `gh skill` (any host: `--agent claude-code`, `copilot`, `cursor`, `codex`, `gemini`), or use the copy bundled in the wheel.

### `opsward`

Run opsward to assess and improve this project’s AI agent setup. Use when the user says ‘opsward’, ‘check my setup’, ‘improve my AI config’, or wants a full audit and remediation.

Source: [`.claude/skills/opsward`](https://github.com/thorwhalen/opsward/tree/HEAD/.claude/skills/opsward).

### `opsward-add-recommendation`

Add a tech-stack→skill mapping to opsward’s recommendation engine in recommend.py, so `opsward recommend` suggests an ecosystem skill when it detects a dependency or framework (e.g. Supabase, FastAPI, Tailwind). Use when extending the curated `_RECOMMENDATIONS` list, adding a new detection signal, or changing where recommended skills are sourced from.

Source: [`.claude/skills/opsward-add-recommendation`](https://github.com/thorwhalen/opsward/tree/HEAD/.claude/skills/opsward-add-recommendation).

### `opsward-add-scoring`

Add or adjust opsward’s quality scoring — a CLAUDE.md sub-dimension, a whole weighted component, or the skill/spec validation rules — in score.py. Use when changing how `opsward diagnose` grades a project, tuning weights or point thresholds, adding a new ComponentScore, or modifying validate_skill_spec. Explains the pure-function contract, the weighting math, and the constants to keep balanced.

Source: [`.claude/skills/opsward-add-scoring`](https://github.com/thorwhalen/opsward/tree/HEAD/.claude/skills/opsward-add-scoring).

### `opsward-add-template`

Add or edit a generation template in opsward — a doc template (architecture.md, testing.md, …), an installable skill (SKILL.md), or an agent definition — and wire it into generate.py so opsward produces it. Use when adding a new artifact opsward should scaffold into target projects, adding a template variable, or changing what `opsward generate` / `install-skills` emit. Covers string.Template rules and the python/jsts/shared layout.

Source: [`.claude/skills/opsward-add-template`](https://github.com/thorwhalen/opsward/tree/HEAD/.claude/skills/opsward-add-template).

### `opsward-dev`

Contributor guide for developing opsward itself — its architecture, hard invariants, and where each kind of change goes. Use when modifying opsward’s own source (scan/score/generate/maintain/recommend/cli), adding a template, scoring dimension, or skill recommendation, or when unsure which module owns a change. NOT for running opsward on a target project (use the `opsward` skill for that).

Source: [`.claude/skills/opsward-dev`](https://github.com/thorwhalen/opsward/tree/HEAD/.claude/skills/opsward-dev).

### `opsward-diagnose`

Diagnose the health of this project’s AI agent setup. Use when the user asks to check, audit, or score the project’s CLAUDE.md, skills, docs, or agent configuration.

Source: [`.claude/skills/opsward-diagnose`](https://github.com/thorwhalen/opsward/tree/HEAD/.claude/skills/opsward-diagnose).

### `opsward-generate`

Generate missing AI setup artifacts for this project. Use when the user asks to scaffold, create, or bootstrap CLAUDE.md, docs, skills, or agent configuration.

Source: [`.claude/skills/opsward-generate`](https://github.com/thorwhalen/opsward/tree/HEAD/.claude/skills/opsward-generate).

### `opsward-maintain`

Check documentation and AI setup for staleness, drift, or inconsistency. Use when the user asks to maintain, refresh, or update project docs and AI configuration.

Source: [`.claude/skills/opsward-maintain`](https://github.com/thorwhalen/opsward/tree/HEAD/.claude/skills/opsward-maintain).

## Subagents

Subagents are Markdown files with a frontmatter (`name`, `description`, `tools`) and a system prompt as the body. Copy one into your project’s `.claude/agents/` (or your agent host’s equivalent) to delegate the task it describes.

### `setup-auditor`

Read-only diagnostic agent that audits the project’s AI setup (CLAUDE.md, skills, docs, rules). Use when you want to check the health of the project’s agent configuration without making changes.

Source: [`.claude/agents/setup-auditor.md`](https://github.com/thorwhalen/opsward/tree/HEAD/.claude/agents/setup-auditor.md).

## Instruction files

Files agents read before working in this repository.

- [`CLAUDE.md`](https://github.com/thorwhalen/opsward/tree/HEAD/CLAUDE.md): read by Claude Code
- [`AGENTS.md`](https://github.com/thorwhalen/opsward/tree/HEAD/AGENTS.md): read by Codex, Copilot, Cursor and other agents

## Machine-readable documentation

This site publishes the same documentation in forms that fit an agent’s context window:

- [`llms.txt`](https://thorwhalen.github.io/opsward/llms.txt): an index of every page with a one-line description ([llms.txt](https://llmstxt.org) format)
- [`opsward.md`](https://thorwhalen.github.io/opsward/opsward.md): the whole documentation as one Markdown file
- `<page>.html.md`: a rendered Markdown twin of every page, advertised from each page’s `<head>` with `<link rel="alternate" type="text/markdown">`
- [`objects.inv`](https://thorwhalen.github.io/opsward/objects.inv): the Sphinx inventory: a symbol-to-URL index (`sphobjinv convert plain objects.inv -`)


# api.html.md

# API reference

| [`opsward`](_autosummary/opsward.html.md#module-opsward)   | Diagnose, generate, and maintain the AI agent setup of your projects.   |
|---------------------------------------------------------------------------|-------------------------------------------------------------------------|


