- .beads-ephemeral/ -> .beads-wisp/ - Rename doctor checks: EphemeralCheck -> WispCheck - Update all docs to use 'transient' for polecats, 'wisp' for molecules - Preserve 'ephemeral' only as descriptive adjective for wisps - Steam engine metaphor: wisps are steam vapors that dissipate Part of Christmas launch wisp terminology unification.
290 lines
6.5 KiB
Markdown
290 lines
6.5 KiB
Markdown
# 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 wisp storage.
|
|
|
|
## 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.
|