docs: Add deacon plugin system design

- New docs/deacon-plugins.md with full plugin architecture
- Directory-based discovery at ~/gt/plugins/
- Gate types: cooldown, cron, condition, event
- Parallel execution support via Task tool subagents
- Updated mol-deacon-patrol plugin-run step to reference new docs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-21 17:41:50 -08:00
parent ac60318778
commit 4809037316
2 changed files with 308 additions and 7 deletions

289
docs/deacon-plugins.md Normal file
View File

@@ -0,0 +1,289 @@
# Deacon Plugins
Town-level plugins that run during the Deacon's patrol loop.
## Overview
The Deacon's patrol includes a `plugin-run` step. Rather than hardcoding what
runs, we use **directory-based discovery** at `~/gt/plugins/`. Each plugin
directory contains enough information for the Deacon to decide whether to run
it and what to do.
Plugins are not pre-validated by tooling. The Deacon reads each plugin's
metadata and instructions, decides if the gate is open, and executes
accordingly.
## Directory Structure
```
~/gt/plugins/
├── beads-cleanup/
│ ├── plugin.md # Gate info + instructions (combined)
│ └── state.json # Auto-managed runtime state
├── health-report/
│ ├── plugin.md
│ └── state.json
└── wisp-pressure/
├── plugin.md
└── state.json
```
Each plugin is a directory. If the directory exists, the plugin exists.
## Plugin Metadata (plugin.md)
The `plugin.md` file contains YAML frontmatter for gate configuration,
followed by markdown instructions for the Deacon.
```markdown
---
gate: cooldown
interval: 24h
parallel: true
---
# Beads Cleanup
Clean up old wisps daily.
## Actions
1. Run `bd cleanup --wisp --force`
2. Run `bd doctor` to verify health
3. Log summary of cleaned items
```
### Frontmatter Fields
| Field | Required | Description |
|-------|----------|-------------|
| `gate` | Yes | Gate type: `cooldown`, `cron`, `condition`, `event` |
| `interval` | For cooldown | Duration: `1h`, `24h`, `5m`, etc. |
| `schedule` | For cron | Cron expression: `0 9 * * *` |
| `check` | For condition | Command that outputs a number |
| `operator` | For condition | Comparison: `gt`, `lt`, `eq`, `ge`, `le` |
| `threshold` | For condition | Numeric threshold |
| `trigger` | For event | Event name: `startup`, `heartbeat` |
| `cooldown` | Optional | Min time between runs (for condition gates) |
| `parallel` | Optional | If true, can run concurrently with other plugins |
## Gate Types
### Cooldown
Run at most once per interval since last successful run.
```yaml
---
gate: cooldown
interval: 24h
---
```
### Cron
Run on a schedule (standard cron syntax).
```yaml
---
gate: cron
schedule: "0 9 * * *" # 9am daily
---
```
### Condition
Run when a command's output crosses a threshold.
```yaml
---
gate: condition
check: "bd count --type=wisp"
operator: gt
threshold: 50
cooldown: 30m # Don't spam even if condition stays true
---
```
The `check` command must output a single number. The Deacon compares it
against `threshold` using `operator`.
### Event
Run in response to specific events.
```yaml
---
gate: event
trigger: startup # Run once when daemon starts
---
```
Triggers: `startup`, `heartbeat` (every patrol), `mail` (when inbox has items).
## State Management
The Deacon maintains `state.json` in each plugin directory:
```json
{
"lastRun": "2025-12-21T10:00:00Z",
"lastResult": "success",
"runCount": 42,
"nextEligible": "2025-12-22T10:00:00Z"
}
```
This is auto-managed. Plugins don't need to touch it.
## Parallel Execution
Plugins marked `parallel: true` can run concurrently. During `plugin-run`,
the Deacon:
1. Scans `~/gt/plugins/` for plugins with open gates
2. Groups them: parallel vs sequential
3. Launches parallel plugins using Task tool subagents
4. Runs sequential plugins one at a time
5. Waits for all to complete before continuing patrol
Sequential plugins (default) run in directory order. Use sequential for
plugins that modify shared state or have ordering dependencies.
## Example Plugins
### beads-cleanup (daily maintenance)
```markdown
---
gate: cooldown
interval: 24h
parallel: true
---
# Beads Cleanup
Daily cleanup of ephemeral beads.
## Actions
1. Run `bd cleanup --wisp --force` to remove old wisps
2. Run `bd doctor` to check for issues
3. Report count of cleaned items
```
### wisp-pressure (condition-triggered)
```markdown
---
gate: condition
check: "bd count --type=wisp"
operator: gt
threshold: 100
cooldown: 1h
parallel: true
---
# Wisp Pressure Relief
Triggered when wisp count gets too high.
## Actions
1. Run `bd cleanup --wisp --age=4h` (remove wisps > 4h old)
2. Check `bd count --type=wisp`
3. If still > 50, run `bd cleanup --wisp --age=1h`
4. Report final count
```
### health-report (scheduled)
```markdown
---
gate: cron
schedule: "0 9 * * *"
parallel: false
---
# Morning Health Report
Generate daily health summary for the overseer.
## Actions
1. Run `gt status` to get overall health
2. Run `bd stats` to get metrics
3. Check for stale agents (no heartbeat > 1h)
4. Send summary: `gt mail send --human -s "Morning Report" -m "..."`
```
### startup-check (event-triggered)
```markdown
---
gate: event
trigger: startup
parallel: false
---
# Startup Verification
Run once when the daemon starts.
## Actions
1. Verify `gt doctor` passes
2. Check all rigs have healthy Witnesses
3. Report any issues to Mayor inbox
```
## Patrol Integration
The `mol-deacon-patrol` step 3 (plugin-run) works as follows:
```markdown
## Step: plugin-run
Execute registered plugins whose gates are open.
1. Scan `~/gt/plugins/` for plugin directories
2. For each plugin, read `plugin.md` frontmatter
3. Check if gate is open (based on type and state.json)
4. Collect eligible plugins into parallel and sequential groups
5. For parallel plugins:
- Use Task tool to spawn subagents for each
- Each subagent reads the plugin's instructions and executes
- Wait for all to complete
6. For sequential plugins:
- Execute each in order
- Read instructions, run actions, update state
7. Update state.json for each completed plugin
8. Log summary: "Ran N plugins (M parallel, K sequential)"
```
## Limitations
- **No polecat spawning**: Plugins cannot spawn polecats. If a plugin tries
to use `gt spawn`, behavior is undefined. This may change in the future.
- **No cross-plugin dependencies**: Plugins don't declare dependencies on
each other. If ordering matters, mark both as `parallel: false`.
- **No plugin-specific state API**: Plugins can write to their own directory
if needed, but there's no structured API for plugin state beyond what the
Deacon auto-manages.
## CLI Commands (Future)
```bash
gt plugins list # Show all plugins, gates, status
gt plugins check # Show plugins with open gates
gt plugins show <name> # Detail view of one plugin
gt plugins run <name> # Force-run (ignore gate)
```
These commands are not yet implemented. The Deacon reads the directory
structure directly during patrol.

View File

@@ -565,14 +565,26 @@ Needs: inbox-check
## Step: plugin-run
Execute registered plugins.
Run any plugins registered with the Deacon:
- Custom health checks
- Integration hooks (Slack, GitHub, etc.)
- Metrics collection
- External system sync
Scan ~/gt/plugins/ for plugin directories. Each plugin has a plugin.md with
YAML frontmatter defining its gate (when to run) and instructions (what to do).
Plugins are defined in the Mayor's config and run on each patrol cycle.
Skip this step if no plugins are registered.
See docs/deacon-plugins.md for full documentation.
Gate types:
- cooldown: Time since last run (e.g., 24h)
- cron: Schedule-based (e.g., "0 9 * * *")
- condition: Metric threshold (e.g., wisp count > 50)
- event: Trigger-based (e.g., startup, heartbeat)
For each plugin:
1. Read plugin.md frontmatter to check gate
2. Compare against state.json (last run, etc.)
3. If gate is open, execute the plugin
Plugins marked parallel: true can run concurrently using Task tool subagents.
Sequential plugins run one at a time in directory order.
Skip this step if ~/gt/plugins/ does not exist or is empty.
Needs: health-scan
## Step: orphan-check