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:
289
docs/deacon-plugins.md
Normal file
289
docs/deacon-plugins.md
Normal 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.
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user