# Tool System

## Purpose

Every Teddy capability that reads or changes WordPress data must be a **tool**:
a named, typed, capability-gated unit of work. The agent never calls raw WP APIs
directly.

## Lifecycle (mandatory)

1. Resolve tool from `ToolRegistryInterface`
2. Check `required_capability()` via `PermissionPolicyInterface`
3. Validate input against JSON Schema (`InputValidator`)
4. If `is_dangerous()` and not approved → return `ToolPreview`
5. Write audit log (running)
6. Execute `ToolInterface::execute()`
7. Write audit log (success/error)
8. Dispatch domain events

## Classes

| Layer | Path |
|-------|------|
| Contract | `src/Domain/Tool/ToolInterface.php` |
| Context / result | `ToolContext`, `ToolResult`, `ToolPreview` |
| Registry | `src/Infrastructure/Tool/InMemoryToolRegistry.php` |
| Executor | `src/Application/Agent/ToolExecutor.php` |
| Abilities bridge | `src/Infrastructure/Tool/DomainToolAbilityRegistrar.php` |
| Legacy bridge | `src/Infrastructure/Tool/LegacyToolsBridge.php` |

## Naming

- Domain names: `post.create`, `wc.product.list`, `system.ping`
- Ability names: `teddy/post-create` via `DomainToolNaming`
- Extension tools must include a vendor prefix: `myplugin.appointment.list`

## Manager tools (v1.4)

| Name | Dangerous | Notes |
|------|-----------|-------|
| `site.briefing` | no | Daily digest: stats, comments, backup, updates, Woo, actionable |
| `content.gaps` | no | Missing image/excerpt/short title / stale |
| `content.scheduled` | no | Future posts |
| `comment.list` | no | Inbox by status |
| `comment.set_status` | yes | approve/spam/trash/hold |
| `ops.recent_changes` | no | Audit log recent |
| `ai.usage.summary` | no | Token/cost summary |
| `knowledge.status` | no | RAG readiness |

## Recent domain tools (Vision gap slice)

| Name | Dangerous | Notes |
|------|-----------|-------|
| `post.delete` | yes | Trash by default; `force=true` permanent |
| `wc.product.find_missing_images` | no | Products without featured image |
| `wc.product.list_expired_promotions` | no | Sale ended, sale price still set |
| `wc.product.clear_expired_sales` | yes | Clears those sale prices |
| `wc.report.revenue` | no | day/week/month/year gross |
| `system.clear_cache` | no | Object cache + expired transients + `teddy_clear_cache` |
| `system.optimize_db` | yes | OPTIMIZE TABLE (site prefix only) |
| `system.backup.run` | yes | UpdraftPlus / `teddy_run_backup` |
| `system.send_email` | yes | `wp_mail` to administrators only |
| `system.wp_cli` | yes | Whitelist: cache flush, plugin list, cron list, transient cleanup |
| `media.generate_image` | no | GD placeholder PNG; optional featured image |

## Feature flags

- `use_agent_pipeline` — admin Copilot uses domain tools + audit
- `enable_database_access` — gates legacy/public read tools
- `enable_extension_sdk` — unlocks `dev.*` code-generation tools

## External agents (MCP / OpenClaw)

Domain tools are also available over MCP via [`mcp-server/`](../../../mcp-server/) — see [mcp-bridge](../mcp-bridge/README.md).

## Verification

```bash
composer test:unit
php tests/e2e-agent-pipeline.php   # Laragon PHP 8.2+
```
