superkick 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. checksums.yaml +7 -0
  2. data/CLA.md +91 -0
  3. data/CLAUDE.md +2226 -0
  4. data/CONTRIBUTING.md +104 -0
  5. data/LICENSE +108 -0
  6. data/LICENSE-COMMERCIAL.md +39 -0
  7. data/PLAN.md +161 -0
  8. data/README.md +1155 -0
  9. data/exe/superkick +6 -0
  10. data/lib/superkick/agent/runtime.rb +82 -0
  11. data/lib/superkick/agent/runtimes/local.rb +74 -0
  12. data/lib/superkick/agent/runtimes.rb +4 -0
  13. data/lib/superkick/agent.rb +209 -0
  14. data/lib/superkick/agent_store.rb +85 -0
  15. data/lib/superkick/attach/client.rb +245 -0
  16. data/lib/superkick/attach/protocol.rb +71 -0
  17. data/lib/superkick/attach/server.rb +371 -0
  18. data/lib/superkick/budget_checker.rb +120 -0
  19. data/lib/superkick/buffer/client.rb +91 -0
  20. data/lib/superkick/buffer/server.rb +127 -0
  21. data/lib/superkick/cli/agent.rb +524 -0
  22. data/lib/superkick/cli/completion.rb +591 -0
  23. data/lib/superkick/cli/goal.rb +71 -0
  24. data/lib/superkick/cli/mcp.rb +34 -0
  25. data/lib/superkick/cli/monitor.rb +47 -0
  26. data/lib/superkick/cli/notifier.rb +39 -0
  27. data/lib/superkick/cli/repository.rb +46 -0
  28. data/lib/superkick/cli/server.rb +106 -0
  29. data/lib/superkick/cli/setup.rb +166 -0
  30. data/lib/superkick/cli/spawner.rb +85 -0
  31. data/lib/superkick/cli/team.rb +407 -0
  32. data/lib/superkick/cli.rb +175 -0
  33. data/lib/superkick/client_registry.rb +30 -0
  34. data/lib/superkick/configuration.rb +178 -0
  35. data/lib/superkick/connection.rb +56 -0
  36. data/lib/superkick/control/client.rb +78 -0
  37. data/lib/superkick/control/reply.rb +43 -0
  38. data/lib/superkick/control/server.rb +1271 -0
  39. data/lib/superkick/cost_accumulator.rb +53 -0
  40. data/lib/superkick/cost_extractor.rb +65 -0
  41. data/lib/superkick/cost_poller.rb +70 -0
  42. data/lib/superkick/driver/profile_source.rb +134 -0
  43. data/lib/superkick/driver.rb +179 -0
  44. data/lib/superkick/drivers/claude_code.rb +110 -0
  45. data/lib/superkick/drivers/codex.rb +57 -0
  46. data/lib/superkick/drivers/copilot.rb +75 -0
  47. data/lib/superkick/drivers/gemini.rb +86 -0
  48. data/lib/superkick/drivers/goose.rb +74 -0
  49. data/lib/superkick/drivers.rb +16 -0
  50. data/lib/superkick/drop.rb +80 -0
  51. data/lib/superkick/drops.rb +76 -0
  52. data/lib/superkick/environment_executor.rb +90 -0
  53. data/lib/superkick/goal.rb +95 -0
  54. data/lib/superkick/goals/agent_exit.rb +41 -0
  55. data/lib/superkick/goals/agent_signal.rb +42 -0
  56. data/lib/superkick/goals/command.rb +103 -0
  57. data/lib/superkick/history_buffer.rb +38 -0
  58. data/lib/superkick/hosted/attach/bridge.rb +52 -0
  59. data/lib/superkick/hosted/attach/client.rb +208 -0
  60. data/lib/superkick/hosted/attach/relay.rb +313 -0
  61. data/lib/superkick/hosted/attach/relay_store.rb +48 -0
  62. data/lib/superkick/hosted/bridge.rb +263 -0
  63. data/lib/superkick/hosted/buffer/bridge.rb +42 -0
  64. data/lib/superkick/hosted/buffer/client.rb +63 -0
  65. data/lib/superkick/hosted/buffer/relay.rb +126 -0
  66. data/lib/superkick/hosted/buffer/relay_store.rb +42 -0
  67. data/lib/superkick/hosted/control/client.rb +84 -0
  68. data/lib/superkick/hosted/mcp_proxy.rb +144 -0
  69. data/lib/superkick/inject_handler.rb +24 -0
  70. data/lib/superkick/injection_guard.rb +26 -0
  71. data/lib/superkick/injection_queue.rb +177 -0
  72. data/lib/superkick/injector.rb +65 -0
  73. data/lib/superkick/input_buffer.rb +171 -0
  74. data/lib/superkick/integrations/bugsnag/README.md +98 -0
  75. data/lib/superkick/integrations/bugsnag/spawner.rb +307 -0
  76. data/lib/superkick/integrations/bugsnag/templates/error_opened.liquid +17 -0
  77. data/lib/superkick/integrations/bugsnag.rb +7 -0
  78. data/lib/superkick/integrations/circleci/README.md +75 -0
  79. data/lib/superkick/integrations/circleci/monitor.rb +185 -0
  80. data/lib/superkick/integrations/circleci/probe.rb +36 -0
  81. data/lib/superkick/integrations/circleci/templates/ci_failure.liquid +8 -0
  82. data/lib/superkick/integrations/circleci/templates/ci_success.liquid +1 -0
  83. data/lib/superkick/integrations/circleci.rb +8 -0
  84. data/lib/superkick/integrations/datadog/README.md +253 -0
  85. data/lib/superkick/integrations/datadog/alert_goal.rb +94 -0
  86. data/lib/superkick/integrations/datadog/alert_monitor.rb +163 -0
  87. data/lib/superkick/integrations/datadog/alert_spawner.rb +201 -0
  88. data/lib/superkick/integrations/datadog/notification_templates/default.liquid +10 -0
  89. data/lib/superkick/integrations/datadog/notifier.rb +294 -0
  90. data/lib/superkick/integrations/datadog/spawner.rb +201 -0
  91. data/lib/superkick/integrations/datadog/templates/alert_changed.liquid +8 -0
  92. data/lib/superkick/integrations/datadog/templates/alert_escalated.liquid +8 -0
  93. data/lib/superkick/integrations/datadog/templates/alert_recovered.liquid +14 -0
  94. data/lib/superkick/integrations/datadog/templates/alert_triggered.liquid +29 -0
  95. data/lib/superkick/integrations/datadog/templates/error_opened.liquid +15 -0
  96. data/lib/superkick/integrations/datadog.rb +14 -0
  97. data/lib/superkick/integrations/docker/README.md +256 -0
  98. data/lib/superkick/integrations/docker/client.rb +295 -0
  99. data/lib/superkick/integrations/docker/runtime.rb +218 -0
  100. data/lib/superkick/integrations/docker.rb +4 -0
  101. data/lib/superkick/integrations/git/repository_source.rb +66 -0
  102. data/lib/superkick/integrations/git/version_control.rb +119 -0
  103. data/lib/superkick/integrations/git.rb +8 -0
  104. data/lib/superkick/integrations/github/README.md +300 -0
  105. data/lib/superkick/integrations/github/check_failed_spawner.rb +199 -0
  106. data/lib/superkick/integrations/github/drops.rb +114 -0
  107. data/lib/superkick/integrations/github/goal.rb +135 -0
  108. data/lib/superkick/integrations/github/issue_goal.rb +104 -0
  109. data/lib/superkick/integrations/github/issue_spawner.rb +160 -0
  110. data/lib/superkick/integrations/github/monitor.rb +251 -0
  111. data/lib/superkick/integrations/github/probe.rb +30 -0
  112. data/lib/superkick/integrations/github/repository_source.rb +228 -0
  113. data/lib/superkick/integrations/github/templates/check_failed.liquid +10 -0
  114. data/lib/superkick/integrations/github/templates/ci_failure.liquid +5 -0
  115. data/lib/superkick/integrations/github/templates/ci_success.liquid +1 -0
  116. data/lib/superkick/integrations/github/templates/issue_opened.liquid +20 -0
  117. data/lib/superkick/integrations/github/templates/pr_comment.liquid +2 -0
  118. data/lib/superkick/integrations/github/templates/pr_review.liquid +4 -0
  119. data/lib/superkick/integrations/github.rb +16 -0
  120. data/lib/superkick/integrations/honeybadger/README.md +97 -0
  121. data/lib/superkick/integrations/honeybadger/notification_templates/default.liquid +8 -0
  122. data/lib/superkick/integrations/honeybadger/notifier.rb +250 -0
  123. data/lib/superkick/integrations/honeybadger/spawner.rb +214 -0
  124. data/lib/superkick/integrations/honeybadger/templates/error_opened.liquid +17 -0
  125. data/lib/superkick/integrations/honeybadger.rb +9 -0
  126. data/lib/superkick/integrations/shell/README.md +83 -0
  127. data/lib/superkick/integrations/shell/monitor.rb +87 -0
  128. data/lib/superkick/integrations/shell/templates/shell_alert.liquid +6 -0
  129. data/lib/superkick/integrations/shell/templates/shell_success.liquid +6 -0
  130. data/lib/superkick/integrations/shell.rb +7 -0
  131. data/lib/superkick/integrations/shortcut/README.md +193 -0
  132. data/lib/superkick/integrations/shortcut/drops.rb +91 -0
  133. data/lib/superkick/integrations/shortcut/monitor.rb +582 -0
  134. data/lib/superkick/integrations/shortcut/probe.rb +34 -0
  135. data/lib/superkick/integrations/shortcut/spawner.rb +264 -0
  136. data/lib/superkick/integrations/shortcut/templates/related_story_changed.liquid +6 -0
  137. data/lib/superkick/integrations/shortcut/templates/story_blocker.liquid +8 -0
  138. data/lib/superkick/integrations/shortcut/templates/story_comment.liquid +5 -0
  139. data/lib/superkick/integrations/shortcut/templates/story_description_changed.liquid +19 -0
  140. data/lib/superkick/integrations/shortcut/templates/story_owner_changed.liquid +10 -0
  141. data/lib/superkick/integrations/shortcut/templates/story_ready.liquid +41 -0
  142. data/lib/superkick/integrations/shortcut/templates/story_state_changed.liquid +9 -0
  143. data/lib/superkick/integrations/shortcut/templates/story_unblocked.liquid +5 -0
  144. data/lib/superkick/integrations/shortcut.rb +11 -0
  145. data/lib/superkick/integrations/slack/README.md +297 -0
  146. data/lib/superkick/integrations/slack/drops.rb +70 -0
  147. data/lib/superkick/integrations/slack/notifier.rb +426 -0
  148. data/lib/superkick/integrations/slack/spawner.rb +251 -0
  149. data/lib/superkick/integrations/slack/templates/default.liquid +17 -0
  150. data/lib/superkick/integrations/slack/templates/slack_reply.liquid +3 -0
  151. data/lib/superkick/integrations/slack/templates/spawn/slack_message.liquid +10 -0
  152. data/lib/superkick/integrations/slack/thread_monitor.rb +161 -0
  153. data/lib/superkick/integrations/slack.rb +12 -0
  154. data/lib/superkick/liquid.rb +129 -0
  155. data/lib/superkick/local/repository_source.rb +148 -0
  156. data/lib/superkick/mcp_server.rb +596 -0
  157. data/lib/superkick/monitor.rb +215 -0
  158. data/lib/superkick/notification_dispatcher.rb +280 -0
  159. data/lib/superkick/notifier.rb +173 -0
  160. data/lib/superkick/notifier_state_store.rb +55 -0
  161. data/lib/superkick/notifier_template.rb +121 -0
  162. data/lib/superkick/notifiers/command.rb +124 -0
  163. data/lib/superkick/notifiers/terminal_bell.rb +41 -0
  164. data/lib/superkick/output_logger.rb +54 -0
  165. data/lib/superkick/poller.rb +126 -0
  166. data/lib/superkick/process_runner.rb +87 -0
  167. data/lib/superkick/pty_proxy.rb +403 -0
  168. data/lib/superkick/registry.rb +75 -0
  169. data/lib/superkick/repository_source.rb +195 -0
  170. data/lib/superkick/server.rb +211 -0
  171. data/lib/superkick/session_recorder.rb +154 -0
  172. data/lib/superkick/setup.rb +160 -0
  173. data/lib/superkick/spawn/agent_spawner.rb +311 -0
  174. data/lib/superkick/spawn/approval_store.rb +113 -0
  175. data/lib/superkick/spawn/handler.rb +144 -0
  176. data/lib/superkick/spawn/injector.rb +119 -0
  177. data/lib/superkick/spawn/workflow_executor.rb +196 -0
  178. data/lib/superkick/spawn/workflow_validator.rb +77 -0
  179. data/lib/superkick/spawner.rb +67 -0
  180. data/lib/superkick/supervisor.rb +516 -0
  181. data/lib/superkick/team/artifact_store.rb +92 -0
  182. data/lib/superkick/team/log.rb +140 -0
  183. data/lib/superkick/team/log_entry_drop.rb +34 -0
  184. data/lib/superkick/team/log_monitor.rb +84 -0
  185. data/lib/superkick/team/log_notifier.rb +96 -0
  186. data/lib/superkick/team/log_store.rb +40 -0
  187. data/lib/superkick/template_filters.rb +24 -0
  188. data/lib/superkick/template_renderer.rb +223 -0
  189. data/lib/superkick/templates/team_log/planning_agent.liquid +38 -0
  190. data/lib/superkick/templates/team_log/team_digest.liquid +45 -0
  191. data/lib/superkick/templates/team_log/teammate_message.liquid +7 -0
  192. data/lib/superkick/templates/team_log/worker_kickoff.liquid +37 -0
  193. data/lib/superkick/templates/workflow/workflow_triggered.liquid +22 -0
  194. data/lib/superkick/version.rb +5 -0
  195. data/lib/superkick/version_control.rb +135 -0
  196. data/lib/superkick/yaml_config.rb +302 -0
  197. data/lib/superkick.rb +198 -0
  198. data/plan.md +267 -0
  199. metadata +404 -0
data/README.md ADDED
@@ -0,0 +1,1155 @@
1
+ # Superkick
2
+
3
+ **An autonomous development environment (ADE) for AI coding agents.**
4
+
5
+ AI coding agents work heads-down in a single terminal session. Meanwhile, CI
6
+ fails, reviewers leave comments, teammates flag blockers — a whole world the
7
+ agent can't see.
8
+
9
+ Superkick fixes that. It wraps your AI CLI in a transparent proxy, monitors the
10
+ outside world, and injects relevant context directly into the session at idle
11
+ moments. It can also spawn and coordinate entire teams of agents autonomously —
12
+ picking up new issues, running multi-step workflows, and managing their own
13
+ working copies.
14
+
15
+ ## How it works
16
+
17
+ Superkick wraps AI coding CLIs (Claude Code, GitHub Copilot, OpenAI Codex, Google
18
+ Gemini, Goose) in a transparent PTY proxy and runs background **monitors** that watch
19
+ external services — GitHub CI, PR reviews, CircleCI pipelines, Shortcut stories,
20
+ or any shell command you configure.
21
+
22
+ When something happens, Superkick waits for the agent to go idle, then injects the
23
+ relevant context directly into the session as a prompt. CI fails? The agent
24
+ already knows. PR review comes in? It's reading it.
25
+
26
+ ```
27
+ superkick agent (one per AI CLI session)
28
+ +--------------------------------------+
29
+ | PtyProxy | superkick server
30
+ | | | Control +-----------------------------------+
31
+ | +---> Buffer::Server |<------->| Control::Server (server.sock) |
32
+ | | (buffer-<id>.sock) | | |
33
+ | +---> OutputLogger | | AgentStore |
34
+ | | (logs/<id>.log) | | +-- Agent |
35
+ | +---> SessionRecorder | | +-- recording_path |
36
+ | | (recordings/<id>.cast) | | (transient link) |
37
+ | +---> Attach::Server | | +-- monitors: { ... } |
38
+ | | (attach-<id>.sock) | | +-- buffer_socket_path <-----+-+
39
+ | +---> InputBuffer | | (transient link) | |
40
+ | (partial input + guards) | | | |
41
+ | | | Supervisor | |
42
+ | proxy_stdin --> InputBuffer -->PTY | | +-- owns monitor threads | |
43
+ | proxy_output --> guard detect -->out | | | |
44
+ | drain_inject ------------------>PTY | | Injector | |
45
+ +--------------------------------------+ | +-- reads buffer_socket----------+-+
46
+ | PTY | |
47
+ v | Spawners |
48
+ +--------------------------------------+ | +-- spawn new agents on events |
49
+ | AI CLI (claude / copilot / ...) |--MCP--> | |
50
+ +--------------------------------------+ | | McpServer |
51
+ +--->| (16 tools for AI CLI) |
52
+ +-----------------------------------+
53
+ ```
54
+
55
+ 1. **`superkick agent start`** wraps your AI CLI in a PTY proxy that tracks terminal output and idle state
56
+ 2. The **server** (`superkick server start`) runs monitors that poll external services
57
+ 3. When the CLI is idle and a noteworthy event occurs, Superkick injects a context prompt directly into the PTY
58
+ 4. The AI CLI also communicates with Superkick via **MCP tools** to discover and manage monitors
59
+
60
+ ## Quick start
61
+
62
+ ```bash
63
+ gem install superkick
64
+ superkick setup
65
+ ```
66
+
67
+ The setup wizard walks you through driver selection, monitor configuration,
68
+ and MCP integration. For manual configuration, see the [getting started tutorial](docs/tutorials/getting-started.md).
69
+
70
+ Once configured:
71
+
72
+ ```bash
73
+ # Start the server (background)
74
+ superkick server start -d
75
+
76
+ # Launch your AI CLI through Superkick
77
+ superkick agent start
78
+
79
+ # Enable tab completion (add to .bashrc / .zshrc)
80
+ eval "$(superkick completion bash)" # or zsh
81
+ ```
82
+
83
+ When the AI CLI starts, Superkick detects your GitHub repo and branch from git,
84
+ starts monitoring for CI results and PR activity, and injects context when
85
+ events occur. No copy-pasting needed.
86
+
87
+ ## Documentation
88
+
89
+ Beyond this README, Superkick has documentation organized by learning style:
90
+
91
+ | | |
92
+ |---|---|
93
+ | **Tutorials** | [Getting started](docs/tutorials/getting-started.md) · [First spawner pipeline](docs/tutorials/first-spawner-pipeline.md) · [Team workflow](docs/tutorials/team-workflow.md) |
94
+ | **How-to guides** | [Customize templates](docs/how-to/customize-templates.md) · [Configure notifications](docs/how-to/configure-notifications.md) · [Troubleshooting](docs/how-to/troubleshooting.md) |
95
+ | **Explanation** | [How injection works](docs/explanation/injection-model.md) · [Spawner workflows](docs/explanation/spawner-workflows.md) · [Agent teams](docs/explanation/agent-teams.md) |
96
+ | **Reference** | [Template variables](docs/reference/templates.md) · [Event types & payloads](docs/reference/event-types.md) |
97
+
98
+ See the [full documentation index](docs/README.md) for everything.
99
+
100
+ ## Key concepts
101
+
102
+ | Concept | Description |
103
+ |---------|-------------|
104
+ | **Driver** | Describes how to drive a specific AI CLI: executable name, idle prompt patterns, injection guards, and MCP installer. |
105
+ | **Monitor** | Watches an external service and emits events (e.g. CI failure, new PR comment). Optionally includes a `Probe` class for auto-detection from the local environment. |
106
+ | **Spawner** | Server-level poller that watches for external events and spawns new agent processes (e.g. new Shortcut stories trigger new coding agents). |
107
+ | **Goal** | Defines what "finished" means for a spawned agent — the server checks it periodically and terminates the agent on completion (e.g. PR merged, CLI exited). |
108
+ | **VersionControl** | Adapter for VCS operations — acquires isolated working copies (clone or worktree) and cleans them up. Spawners declare a `repository:` key and the appropriate adapter handles the rest. |
109
+ | **RepositorySource** | Catalog of repositories with metadata (tags, descriptions, dependencies). Used by planning agents to discover where work belongs. Supports static entries, directory scanning, and GitHub organization fetching. |
110
+ | **Team** | A group of agents working toward a shared objective. A planning agent (lead) decomposes tasks and spawns workers. Workers communicate via a shared team log. |
111
+ | **InjectionQueue** | Agent-side queue that checks injection preconditions locally (CLI must be idle for `idle_threshold` seconds) and writes to the PTY. Supports TTL, priority, and supersede-by-key semantics. |
112
+ | **Injector** | Orchestrates injection: renders a Liquid template and enqueues it on the agent's `InjectionQueue` via the buffer socket. |
113
+ | **Notifier** | Alerts the user after a successful injection (terminal bell, shell command, etc.). Pluggable — add custom notifiers for OS notifications, webhooks, or chat integrations. |
114
+
115
+ ## Built-in drivers
116
+
117
+ | Driver | CLI command | Prompt patterns | MCP config file |
118
+ |--------|-------------|-----------------|-----------------|
119
+ | `claude_code` | `claude` | `> `, `Human: `, `$ ` | `~/.claude/settings.json` |
120
+ | `copilot` | `copilot` | `@ ` | `~/.copilot/mcp-config.json` |
121
+ | `codex` | `codex` | `codex> ` | `~/.codex/config.toml` |
122
+ | `gemini` | `gemini` | `gemini> `, `> ` | `~/.gemini/settings.json` |
123
+ | `goose` | `goose` | `goose> `, `> ` | `~/.config/goose/config.yaml` |
124
+
125
+ ## Built-in integrations
126
+
127
+ ### GitHub
128
+
129
+ Provides: **monitor**, **spawners**, **goals**
130
+
131
+ - **Monitor** (`:github`) — watches CI check runs, PR comments, and PR reviews. Auto-detected from your git remote and branch.
132
+ - **Spawner** (`:github_issues`) — watches for newly created or reopened issues and spawns agents. Supports filtering by labels, assignee, milestone, and creator.
133
+ - **Spawner** (`:github_check_failed`) — watches check suites for failures on configured branches and spawns agents to fix them. Works across CI providers.
134
+ - **Goal** (`:github_pr_merged`) — completes a spawned agent when its PR is merged. Auto-detects repo and branch from the agent's working directory.
135
+ - **Goal** (`:github_issue_resolved`) — completes a spawned agent when the associated issue is closed (any close reason).
136
+
137
+ See [GitHub integration README](lib/superkick/integrations/github/README.md) for full details.
138
+
139
+ ### CircleCI
140
+
141
+ Provides: **monitor**
142
+
143
+ - **Monitor** (`:circleci`) — watches pipeline workflows for success/failure, lists failed jobs. Auto-detected from `.circleci/config.yml` and your git remote.
144
+
145
+ See [CircleCI integration README](lib/superkick/integrations/circleci/README.md) for full details.
146
+
147
+ ### Shortcut
148
+
149
+ Provides: **monitor**, **spawner**
150
+
151
+ - **Monitor** (`:shortcut`) — watches a story for state changes, comments, blockers, owner changes, description updates, and related story changes. Auto-detected from the `sc-XXXXX` branch pattern.
152
+ - **Spawner** (`:shortcut`) — watches a search query for new stories and spawns agents to work on them.
153
+
154
+ See [Shortcut integration README](lib/superkick/integrations/shortcut/README.md) for full details.
155
+
156
+ ### Bugsnag
157
+
158
+ Provides: **spawner**
159
+
160
+ - **Spawner** (`:bugsnag`) — watches Bugsnag for open errors and spawns agents to fix them. Supports filtering by severity, release stage, error class, version, and minimum event count.
161
+
162
+ See [Bugsnag integration README](lib/superkick/integrations/bugsnag/README.md) for full details.
163
+
164
+ ### Datadog
165
+
166
+ Provides: **notifier**, **spawner** (error tracking + alerts), **monitor**, **goal**
167
+
168
+ - **Notifier** (`:datadog`) — sends events and metrics to Datadog via DogStatsD (UDP). See [Notifications](#notifications) for details.
169
+ - **Spawner** (`:datadog`) — watches Datadog Error Tracking for open error groups and spawns agents to fix them. Supports filtering by service, environment, source, and minimum event count.
170
+ - **Alert Spawner** (`:datadog_alerts`) — watches Datadog monitors for triggered alerts and spawns agents to triage them. Supports filtering by status, tags, monitor type, and priority. Monitors that recover and re-alert are re-dispatched as new agents.
171
+ - **Alert Monitor** (`:datadog_alert`) — polls a specific Datadog monitor for status changes and injects events when the alert recovers, escalates, or changes state. Typically auto-configured by the alert spawner.
172
+ - **Alert Goal** (`:datadog_alert_resolved`) — completes when the Datadog monitor returns to OK status. Auto-terminates the agent when the alert resolves.
173
+
174
+ See [Datadog integration README](lib/superkick/integrations/datadog/README.md) for full details.
175
+
176
+ ### Honeybadger
177
+
178
+ Provides: **notifier**, **spawner**
179
+
180
+ - **Notifier** (`:honeybadger`) — sends structured events to Honeybadger Insights via the Events API. See [Notifications](#notifications) for details.
181
+ - **Spawner** (`:honeybadger`) — watches Honeybadger for unresolved faults and spawns agents to fix them. Supports filtering by environment, fault class, and minimum occurrence count.
182
+
183
+ See [Honeybadger integration README](lib/superkick/integrations/honeybadger/README.md) for full details.
184
+
185
+ ### Shell
186
+
187
+ Provides: **monitor**
188
+
189
+ - **Monitor** (`:shell`) — runs a custom command each poll interval, dispatches events based on exit status. Supports multiple named instances. Auto-detected from executable scripts in `.superkick/shell/`.
190
+
191
+ See [Shell integration README](lib/superkick/integrations/shell/README.md) for full details.
192
+
193
+ ### Slack
194
+
195
+ Provides: **notifier**, **spawner**, **monitor**
196
+
197
+ - **Notifier** (`:slack`) — posts rich Block Kit messages to Slack. See [Notifications](#notifications) for details.
198
+ - **Spawner** (`:slack`) — watches a Slack channel for new messages and spawns agents to handle them. Auto-attaches a per-agent Slack notifier that posts lifecycle events back to the originating thread, and a thread monitor for follow-up replies.
199
+ - **Thread Monitor** (`:slack_thread`) — polls a Slack thread for new replies and injects them as high-priority events.
200
+
201
+ See [Slack integration README](lib/superkick/integrations/slack/README.md) for full details.
202
+
203
+ ## Notifications
204
+
205
+ Superkick fires **notifiers** on two kinds of events:
206
+
207
+ 1. **Monitor injections** — after context is injected into an agent session
208
+ 2. **Agent lifecycle events** — when spawned agents change state (`agent_spawned`, `agent_completed`, `agent_failed`, `agent_timed_out`, `agent_blocked`, `agent_stalled`, `agent_terminated`, `agent_claimed`, `agent_unclaimed`, `agent_pending_approval`, `workflow_triggered`, `workflow_iterations_exceeded`, `budget_warning`, `budget_exceeded`)
209
+ 3. **Attach events** — when attach client modes change (`attach_promoted`, `attach_demoted`, `attach_idle_timeout`, `attach_force_takeover`)
210
+
211
+ This is especially useful when you step away from the terminal — you'll know when agents finish, stall, or need approval.
212
+
213
+ ### Terminal bell (default)
214
+
215
+ When no `notifications:` section is configured, Superkick writes a BEL character (`\a`) to stderr. Most terminal emulators respond with a visual or audible alert:
216
+
217
+ - **iTerm2** bounces the dock icon
218
+ - **tmux** marks the window with activity
219
+ - **GNOME Terminal** flashes the tab title
220
+ - **Windows Terminal** flashes the taskbar
221
+
222
+ ### Command notifier
223
+
224
+ Run any shell command when an injection occurs. Event details are available as environment variables:
225
+
226
+ | Variable | Example |
227
+ |----------|---------|
228
+ | `SUPERKICK_EVENT_TYPE` | `ci_failure`, `pr_comment` |
229
+ | `SUPERKICK_MONITOR_TYPE` | `github`, `shell` |
230
+ | `SUPERKICK_MONITOR_NAME` | `github`, `disk-check` |
231
+ | `SUPERKICK_AGENT_ID` | `abc123` |
232
+ | `SUPERKICK_MESSAGE` | `Superkick: ci_failure from github` |
233
+
234
+ ```yaml
235
+ # config.yml
236
+ notifications:
237
+ - type: terminal_bell
238
+ - type: command
239
+ run: "notify-send 'Superkick' '$SUPERKICK_MESSAGE'"
240
+ - type: command
241
+ run: "curl -s -X POST $SLACK_WEBHOOK -d '{\"text\": \"$SUPERKICK_MESSAGE\"}'"
242
+ events: # optional — restrict which events fire
243
+ - agent_blocked
244
+ - agent_completed
245
+ - agent_pending_approval
246
+ ```
247
+
248
+ Commands are killed after `timeout_seconds` (default 10) to prevent hung processes. Multiple notifiers can be configured — each runs independently, so one failure doesn't block the others. When `events:` is absent on a notifier, it receives all events.
249
+
250
+ ### Slack notifier
251
+
252
+ Post rich Block Kit messages to Slack. Supports two authentication modes:
253
+
254
+ **Incoming Webhook** — simplest setup, posts to a single channel:
255
+
256
+ ```yaml
257
+ notifications:
258
+ - type: slack
259
+ webhook_url: <%= env("SLACK_WEBHOOK_URL") %>
260
+ ```
261
+
262
+ **Web API** — can target any channel, requires a bot token with `chat:write` scope:
263
+
264
+ ```yaml
265
+ notifications:
266
+ - type: slack
267
+ token: <%= env("SLACK_BOT_TOKEN") %>
268
+ channel: "#superkick-notifications"
269
+ events:
270
+ - agent_completed
271
+ - agent_failed
272
+ - agent_blocked
273
+ ```
274
+
275
+ Messages include a header with an event-specific emoji, the notification message, and a context line with agent/monitor metadata. In Web API mode, messages for the same agent are automatically **threaded** — the first event creates a new thread, and subsequent events (blocked, completed, failed) reply to it, keeping the channel clean. Webhook mode sends standalone messages (Slack webhooks don't support threading).
276
+
277
+ The Slack spawner automatically attaches a **per-agent Slack notifier** to each spawned agent, pre-seeded with the originating thread's `thread_ts`. This means lifecycle events (spawned, completed, failed, etc.) are posted back to the Slack thread where the message originated — no global notifier configuration needed.
278
+
279
+ ### Datadog notifier
280
+
281
+ Send events and metrics to Datadog via DogStatsD (UDP). Events appear in the Event Explorer; counters and gauges appear in Metrics Explorer for dashboards and alerts. No gem dependency — uses the standard DogStatsD UDP protocol directly.
282
+
283
+ ```yaml
284
+ notifications:
285
+ - type: datadog
286
+ statsd_host: localhost # default — your Datadog Agent
287
+ statsd_port: 8125 # default DogStatsD port
288
+ prefix: superkick # metric name prefix
289
+ tags:
290
+ - "env:production"
291
+ - "team:platform"
292
+ ```
293
+
294
+ Emitted metrics (tagged with `agent_id`, `event_type`, `monitor_type`, `monitor_name`, plus global tags):
295
+
296
+ | Metric | Type | Description |
297
+ |--------|------|-------------|
298
+ | `<prefix>.event` | Counter | Incremented on every event |
299
+ | `<prefix>.agent.duration` | Gauge | Seconds from spawn to terminal event |
300
+
301
+ Events include the notification message, an alert type mapped from the event (success/error/warning/info), and all standard tags. Duration is computed automatically — the notifier tracks spawn times per agent and emits duration on terminal events.
302
+
303
+ ### Honeybadger notifier
304
+
305
+ Send structured events to [Honeybadger Insights](https://www.honeybadger.io/for/insights/) via the Events API. Events appear in the Insights dashboard for search, filtering, graphing, and alerting.
306
+
307
+ ```yaml
308
+ notifications:
309
+ - type: honeybadger
310
+ api_key: <%= env("HONEYBADGER_API_KEY") %>
311
+ tags:
312
+ - production
313
+ - team-alpha
314
+ ```
315
+
316
+ Each event includes `event_type`, `agent_id`, `severity` (mapped from event type), `message`, monitor metadata, and optional `duration_seconds` on terminal events. Like the Datadog notifier, duration is computed automatically from tracked spawn times.
317
+
318
+ ### Custom notifiers
319
+
320
+ Notifiers are pluggable. See the [notifier skill](skills/superkick-new-notifier/SKILL.md) for a step-by-step guide to adding your own.
321
+
322
+ ## Spawners
323
+
324
+ Spawners are server-level pollers that watch external services and automatically spawn new agent processes in response to events. While monitors inject context into an existing agent, spawners create entirely new agents.
325
+
326
+ ```yaml
327
+ # config.yml
328
+ spawners:
329
+ shortcut:
330
+ token: <%= env("SHORTCUT_TOKEN") %>
331
+
332
+ search: "owner:me state:'In Progress'"
333
+ driver: claude_code
334
+ repository: my-app
335
+ branch_template: "fix-{{ agent_id }}"
336
+ goal:
337
+ type: github_pr_merged
338
+ max_duration: 7200 # hard timeout in seconds
339
+ cooldown: 300 # minimum seconds between spawns
340
+ approval_required: true # require human approval before spawning
341
+ stall_threshold: 600 # seconds idle before agent_stalled notification
342
+ ```
343
+
344
+ ### Approval gates
345
+
346
+ When `approval_required: true`, spawn events are held for human review instead of spawning immediately. An `agent_pending_approval` notification fires, and the user approves or rejects via the CLI:
347
+
348
+ ```bash
349
+ superkick approvals # list pending approvals
350
+ superkick approve <id> # approve a pending spawn
351
+ superkick reject <id> -r "reason" # reject (persistent within server lifetime)
352
+ superkick reject --clear <id> # clear a rejection to allow re-dispatch
353
+ superkick reject --clear-all # clear all rejections
354
+ ```
355
+
356
+ ### Agent claim & handoff
357
+
358
+ Spawned agents run autonomously with goal checking, but you can **claim** an agent to take manual control — pausing goal checking, stall detection, and the `max_duration` timer:
359
+
360
+ ```bash
361
+ superkick agent claim AGENT_ID # pause autonomous operation
362
+ superkick agent unclaim AGENT_ID # resume autonomous operation
363
+ ```
364
+
365
+ When attached to a running agent (`superkick agent attach AGENT_ID -i`), you can also use escape sequences (default: Ctrl-A prefix):
366
+
367
+ | Sequence | Action |
368
+ |----------|--------|
369
+ | Ctrl-A, d | Detach from agent |
370
+ | Ctrl-A, c | Claim agent (pauses autonomous operation; auto-promotes to RW if slot is vacant) |
371
+ | Ctrl-A, u | Unclaim agent (resumes autonomous operation) |
372
+ | Ctrl-A, w | Request read-write promotion (only if RW slot is vacant) |
373
+ | Ctrl-A, W | Force read-write promotion (demotes existing RW holder) |
374
+ | Ctrl-A, r | Voluntarily demote to read-only |
375
+
376
+ The escape prefix is configurable for tmux/screen users (see [Configuration](#configuration-settings)).
377
+
378
+ RW clients are automatically demoted to read-only after `attach_rw_idle_timeout` seconds (default 300) of no input. Use `--force` / `-f` on the attach command to take over RW from another client at connect time.
379
+
380
+ ### Repository acquisition
381
+
382
+ When a spawner specifies `repository:`, the system automatically acquires an isolated working copy using the appropriate **VersionControl** adapter:
383
+
384
+ ```yaml
385
+ spawners:
386
+ fix_issues:
387
+ repository: api # looks up from repository source
388
+ branch_template: "fix-{{ agent_id }}" # Liquid template (default: "superkick-{{ agent_id }}")
389
+ base_branch: main # branch to base from (default: "main")
390
+ ```
391
+
392
+ The Git adapter uses **worktrees** when the repository has a local path (fast, shared objects) and falls back to **clone** when only a URL is available. Working copies are created under `~/.superkick/workspaces/<agent_id>` and cleaned up when the agent ends.
393
+
394
+ ### Goals
395
+
396
+ A **goal** defines what "finished" means for a spawned agent. The server checks the goal periodically and terminates the agent when it reaches a terminal status.
397
+
398
+ | Goal | Description |
399
+ |------|-------------|
400
+ | `agent_exit` | Completes when the AI CLI process exits |
401
+ | `command` | Runs a shell command periodically; exit code determines status |
402
+ | `agent_signal` | Completes when the AI CLI calls the `superkick_signal_goal` MCP tool (**default** — can be omitted) |
403
+ | `github_pr_merged` | Completes when the agent's GitHub PR is merged (see [GitHub integration](lib/superkick/integrations/github/README.md)) |
404
+ | `github_issue_resolved` | Completes when the associated GitHub issue is closed (any close reason) |
405
+ | `datadog_alert_resolved` | Completes when a Datadog monitor returns to OK status (see [Datadog integration](lib/superkick/integrations/datadog/README.md)) |
406
+
407
+ ### Spawner workflows
408
+
409
+ When a spawned agent reaches its goal (or fails), Superkick can automatically spawn the **next agent** in a pipeline using `on_complete:` and `on_fail:` hooks. This enables multi-stage workflows:
410
+
411
+ ```
412
+ Issue spawner → implementation agent completes → review agent spawns → PR merged → done
413
+ └─ fails → retry agent spawns
414
+ ```
415
+
416
+ #### Configuration
417
+
418
+ Add `on_complete:` and/or `on_fail:` to any spawner config. Two forms are supported:
419
+
420
+ **Inline config** — define the next stage directly:
421
+
422
+ ```yaml
423
+ spawners:
424
+ implement:
425
+ type: github_issues
426
+ repo: org/app
427
+ driver: claude_code
428
+ repository: app
429
+ on_complete:
430
+ goal:
431
+ type: github_pr_merged
432
+ prompt_template: review # template name for the kickoff prompt
433
+ max_duration: 1800
434
+ on_fail:
435
+ prompt_template: fix_and_retry
436
+ ```
437
+
438
+ **Spawner reference** — point to another named spawner:
439
+
440
+ ```yaml
441
+ spawners:
442
+ implement:
443
+ type: github_issues
444
+ repo: org/app
445
+ on_complete:
446
+ spawner: review_pr # reuse another spawner's full config
447
+ on_fail:
448
+ spawner: notify_failure
449
+ ```
450
+
451
+ #### How it works
452
+
453
+ 1. A spawned agent's goal reaches a terminal status (`:completed` or `:failed`)
454
+ 2. The Supervisor calls `Spawn::WorkflowExecutor#fire`
455
+ 3. The executor resolves the workflow config (inline or spawner reference)
456
+ 4. An enriched event is built — the parent's serialized context (Drops like `issue`, `story`, plus scalars like `repo`, `branch`) is forwarded wholesale so the next agent has full context
457
+ 5. The new agent is spawned in a background thread through the normal spawn path (workspace setup, kickoff injection, goal checking)
458
+ 6. A `workflow_triggered` lifecycle notification fires
459
+
460
+ #### VCS inheritance
461
+
462
+ By default, a workflow spawn **inherits the parent's VCS state** — the parent's working copy is handed to the child without teardown. This means:
463
+
464
+ - The child starts in the same working directory (e.g. the same git worktree)
465
+ - The last agent in the chain handles cleanup
466
+ - No redundant repository acquisition between stages
467
+
468
+ To give a workflow step its own working copy instead, add an explicit `repository:` key:
469
+
470
+ ```yaml
471
+ on_complete:
472
+ repository: app
473
+ base_branch: main
474
+ ```
475
+
476
+ #### Iteration limiting
477
+
478
+ For cyclic workflows (`allow_cycles: true`), you **must** set `max_iterations` to prevent infinite recursion. This controls how many times a specific spawner can fire within a single workflow chain. Acyclic workflows don't need any limit — they're naturally bounded by graph structure.
479
+
480
+ ```yaml
481
+ spawners:
482
+ implement:
483
+ allow_cycles: true
484
+ max_iterations: 3 # this spawner can fire at most 3 times per chain
485
+ on_fail:
486
+ spawner: implement # retry on failure
487
+ ```
488
+
489
+ When the limit is reached, a `workflow_iterations_exceeded` notification fires and no further agents are spawned.
490
+
491
+ #### Cycle detection
492
+
493
+ At server startup, Superkick validates all spawner configs for reference cycles (e.g. `A → B → A`). Cycles are detected statically via chain walking on the spawner reference graph and prevent the server from starting. Inline configs are leaf nodes — they don't create edges in the graph.
494
+
495
+ ## Repository source
496
+
497
+ When working across multiple repositories, Superkick needs to know what repositories exist and what they do. The **repository source** provides a structured catalog that planning agents use to decompose tasks and spawn workers in the right places.
498
+
499
+ ### Configuration
500
+
501
+ Each key under `repositories:` is a user-chosen name. Entries without a `type:` key are static repository definitions. Entries with a `type:` key are repository sources that discover repositories automatically.
502
+
503
+ ```yaml
504
+ # config.yml
505
+ repositories:
506
+ # Static entries — you define each repository directly
507
+ api_service:
508
+ path: ~/projects/api-service
509
+ url: git@github.com:org/api-service
510
+ description: "Core REST API — user, auth, billing endpoints"
511
+ tags: [backend, api, ruby]
512
+ context_documents: [readme, claude_md] # include these docs in planning context
513
+ dependencies: [shared_types]
514
+
515
+ web_frontend:
516
+ path: ~/projects/web-frontend
517
+ description: "React SPA consuming api-service"
518
+ tags: [frontend, react, typescript]
519
+
520
+ # Directory scan — auto-detects repos in a local directory
521
+ local:
522
+ type: directory
523
+ path: ~/projects
524
+ version_controlled_only: true # only include dirs under version control (default)
525
+ depth: 1 # subdirectory depth (default 1, max 5)
526
+ exclude: [node_modules, deprecated]
527
+
528
+ # GitHub organization — fetches repos from a GitHub org
529
+ company:
530
+ type: github_organization
531
+ organization: my-company
532
+ token: <%= env("GITHUB_TOKEN") %>
533
+ topic_filter: [production] # only repos with ALL listed topics
534
+ exclude: [legacy-app]
535
+ visibility: all # public, private, or all
536
+ ```
537
+
538
+ Static entries and typed sources can be freely mixed. When there's a single source, it's returned directly. When there are multiple, they're composited automatically (first-found wins on name collisions).
539
+
540
+ ### Source types
541
+
542
+ | Type | Description |
543
+ |------|-------------|
544
+ | *(no type)* | Static repository entry — you define name, path, URL, tags, and dependencies directly |
545
+ | `directory` | Scans a local directory for subdirectories. Auto-detects git remotes, project language tags, and git descriptions |
546
+ | `github_organization` | Fetches repositories from a GitHub organization or user account via the API. All metadata comes from the API — no SSH keys needed |
547
+
548
+ ### How it's used
549
+
550
+ - **Planning agents** receive the repository catalog as part of their kickoff prompt, giving them a structured view of available repositories
551
+ - The **`repository:`** spawner config key resolves a repository from the source and acquires an isolated working copy via the appropriate **VersionControl** adapter
552
+ - Repositories serve as a **whitelist** — planning agents can only spawn workers for repositories in the source
553
+
554
+ ## Agent teams
555
+
556
+ Teams coordinate multiple agents working toward a shared objective. A **planning agent** (the team lead) reads a task, discovers which repositories are affected, decomposes the work, and spawns **worker agents** — one per repository. The team succeeds when all workers finish.
557
+
558
+ ### Team workflow
559
+
560
+ When a spawner has `workflow: team`, it creates a planning agent instead of a normal worker:
561
+
562
+ ```yaml
563
+ # config.yml
564
+ repositories:
565
+ api_service:
566
+ path: ~/projects/api-service
567
+ description: "Core REST API"
568
+ tags: [backend, ruby]
569
+ context_documents: [readme]
570
+ web_frontend:
571
+ path: ~/projects/web-frontend
572
+ description: "React SPA"
573
+ tags: [frontend, react]
574
+
575
+ spawners:
576
+ feature_team:
577
+ type: github_issues
578
+ repo: org/api-service
579
+ labels: [multi-repo]
580
+ workflow: team # creates a planning agent, not a worker
581
+ driver: claude_code
582
+ max_duration: 7200 # 2 hours for the entire team
583
+ approval_required: true
584
+ ```
585
+
586
+ ### How it works
587
+
588
+ ```
589
+ GitHub issue created
590
+ → Spawner detects new issue
591
+ → Planning agent spawns (team lead)
592
+ → Reads issue + repository source
593
+ → Decomposes work: "API needs a new endpoint, frontend needs a new page"
594
+ → Spawns worker agent in api_service (git worktree)
595
+ → Spawns worker agent in web_frontend (git worktree)
596
+ → Workers execute in parallel, broadcasting status to team log
597
+ → Planning agent monitors progress, coordinates if needed
598
+ → All workers complete → lead signals goal complete via MCP → done
599
+ ```
600
+
601
+ The planning agent uses MCP tools to manage the team:
602
+
603
+ | Tool | Description |
604
+ |------|-------------|
605
+ | `superkick_spawn_worker` | Spawn a worker agent in a specific repository (with optional `role` label) |
606
+ | `superkick_discover_repositories` | List available repositories with descriptions, tags, and dependencies |
607
+ | `superkick_team_status` | Read the team log — see what teammates are doing |
608
+ | `superkick_post_update` | Broadcast a status update or send a targeted message to a teammate |
609
+ | `superkick_list_teammates` | List all agents on the team with roles and status |
610
+ | `superkick_publish_artifact` | Share structured data (plans, specs) with the team |
611
+ | `superkick_read_artifact` | Read an artifact published by a teammate |
612
+ | `superkick_list_artifacts` | List all artifacts for the team |
613
+
614
+ ### Team log
615
+
616
+ Each team has a shared, append-only log where agents broadcast updates. This is the primary communication channel — agents radiate status rather than polling each other:
617
+
618
+ ```bash
619
+ superkick team status TEAM_ID
620
+ # Team: github-issue-org-app-42 (3 agents)
621
+ #
622
+ # github-issue-org-app-42 lead/Lead [in_progress]
623
+ # github-issue-org-app-42-api worker/API dev [in_progress]
624
+ # github-issue-org-app-42-web worker/Frontend [in_progress]
625
+ #
626
+ # Latest updates:
627
+ # [github-issue-org-app-42] [decision] Decomposed into api-service + web-frontend
628
+ # [github-issue-org-app-42-api] [progress] Added /preferences endpoint, writing tests
629
+ # [github-issue-org-app-42-web] [blocker] Waiting for api-service PreferencesResponse type
630
+ ```
631
+
632
+ Targeted messages (`superkick_post_update` with `target_agent_id`) are for directed coordination — they're injected into the target's prompt and recorded in the team log (visible to the whole team). Agents can also share structured data via **artifacts** (`superkick_publish_artifact` / `superkick_read_artifact`).
633
+
634
+ Team leads automatically receive a **team feed** — a monitor that injects digest summaries of teammate activity. Workers can opt in via `superkick_add_monitor`.
635
+
636
+ Watch team activity in real time:
637
+
638
+ ```bash
639
+ superkick team watch TEAM_ID # streams color-coded updates (Ctrl-C to stop)
640
+ ```
641
+
642
+ Interactive agents can join an existing team as human members:
643
+
644
+ ```bash
645
+ superkick agent start --team TEAM_ID --role "Code reviewer" # --no-feed to disable digest
646
+ ```
647
+
648
+ ### Team lead goal
649
+
650
+ Team leads default to the `:agent_signal` goal — the planning agent signals completion via the `superkick_signal_goal` MCP tool once all workers have finished and results are satisfactory. Since `agent_signal` is the default goal type, this does not need to be explicitly configured.
651
+
652
+ ### Driver profiles
653
+
654
+ Named driver configurations can be defined under `drivers.profiles` and referenced by name from spawner configs:
655
+
656
+ ```yaml
657
+ drivers:
658
+ profiles:
659
+ review:
660
+ type: claude_code
661
+ config_dir: ~/.superkick/driver-configs/review/.claude
662
+ env:
663
+ ANTHROPIC_API_KEY: <%= env("REVIEW_KEY") %>
664
+ worker:
665
+ type: claude_code
666
+ config_dir: ~/.superkick/driver-configs/worker/.claude
667
+ args: ["--verbose"]
668
+ ```
669
+
670
+ Reference a profile from a spawner with `driver: { profile: :review }`. Inline overrides are deep-merged on top:
671
+
672
+ ```yaml
673
+ spawners:
674
+ my_spawner:
675
+ driver:
676
+ profile: review
677
+ env:
678
+ EXTRA_VAR: value # merged on top of profile env
679
+ ```
680
+
681
+ ### Driver cascade
682
+
683
+ Driver config follows a three-level cascade (most specific wins), with deep-merging at each level:
684
+
685
+ 1. **Top-level default** — `driver:` in config root
686
+ 2. **Per-spawner** — `driver:` on the spawner config (string or hash, may reference a profile)
687
+ 3. **Per-role** — nested `team:` config on a `workflow: team` spawner
688
+
689
+ Deep merge rules: scalar keys (`type`, `config_dir`, `command`) — more-specific wins; `args` — arrays are concatenated; `env` — hashes are merged. A string at a more-specific level replaces the entire config (no merge).
690
+
691
+ ```yaml
692
+ spawners:
693
+ feature_team:
694
+ workflow: team
695
+ driver:
696
+ profile: review # base from named profile
697
+ team:
698
+ lead:
699
+ driver: # planning agent gets overrides
700
+ config_dir: ~/.superkick/driver-configs/lead/.claude
701
+ worker:
702
+ driver: # workers can use a different model
703
+ env:
704
+ CLAUDE_MODEL: claude-sonnet-4-6
705
+ ```
706
+
707
+ ### Resource limits
708
+
709
+ | Setting | Default | Description |
710
+ |---------|---------|-------------|
711
+ | `max_workers_per_team` | `5` | Maximum workers a planning agent can spawn |
712
+ | `max_duration` | — | Hard timeout for the entire team (lead + all workers) |
713
+ | `max_concurrent` | — | Total agents (lead + workers) across all active teams for a spawner |
714
+
715
+ ## Cost tracking
716
+
717
+ Superkick tracks token usage and cost for spawned agents. Cost data comes from two sources:
718
+
719
+ 1. **PTY output parsing** — driver-specific patterns extract cost from the CLI's output (e.g. Claude Code's `Total cost: $1.50` status bar)
720
+ 2. **MCP self-reporting** — the AI CLI calls `superkick_report_cost` with cumulative totals
721
+
722
+ Both sources handle cumulative-to-delta conversion automatically, so refreshing status bars or repeated reports don't double-count.
723
+
724
+ ### Viewing costs
725
+
726
+ ```bash
727
+ superkick agent cost # show costs for all agents
728
+ superkick agent cost AGENT_ID # show cost for a specific agent
729
+ ```
730
+
731
+ ### Budget enforcement
732
+
733
+ Budgets can be set at three levels — per-agent, per-spawner, and global:
734
+
735
+ ```yaml
736
+ # config.yml
737
+ budget:
738
+ max_cost_usd: 100.0 # global cap across all agents
739
+ window_hours: 24 # time window for aggregate tracking
740
+ warning_threshold_percentage: 80 # fire warning at 80% of max
741
+
742
+ spawners:
743
+ feature_team:
744
+ type: github_issues
745
+ budget:
746
+ max_cost_usd: 50.0 # aggregate cap for this spawner's agents
747
+ window_hours: 24
748
+ per_agent:
749
+ max_cost_usd: 5.0 # cap per individual agent
750
+ ```
751
+
752
+ When a budget threshold is crossed, `budget_warning` or `budget_exceeded` lifecycle notifications fire. Budget checking only applies to spawned agents — interactive agents are always exempt.
753
+
754
+ ### Cost polling
755
+
756
+ For headless spawned agents, the **cost poller** periodically injects the driver's cost command (e.g. `/cost`) when cost data goes stale. This ensures cost tracking stays current even for long-running agents.
757
+
758
+ | Setting | Default | Description |
759
+ |---------|---------|-------------|
760
+ | `cost_poll_interval` | `300` (5 min) | How often to check for stale cost data |
761
+ | `cost_stale_after` | `600` (10 min) | Seconds before cost data is considered stale |
762
+
763
+ ## Configuration
764
+
765
+ Superkick loads configuration from `~/.superkick/` (override with `SUPERKICK_DIR` env var):
766
+
767
+ ### `config.yml`
768
+
769
+ ```yaml
770
+ # Which AI CLI driver to use
771
+ driver: claude_code
772
+
773
+ # Superkick tuning
774
+ superkick:
775
+ poll_interval: 30 # seconds between monitor ticks
776
+ idle_threshold: 5.0 # seconds idle before injection allowed
777
+ inject_clear_delay: 0.15 # sleep between PTY writes
778
+ rate_limit_backoff: 60 # seconds to sleep on API rate limit
779
+ error_backoff: 10 # seconds to sleep on error
780
+ log_level: info # debug, info, warn, error
781
+ attach_escape_key: ctrl-a # escape prefix for attach sessions (ctrl-a through ctrl-z)
782
+ attach_rw_idle_timeout: 300 # seconds before idle RW attach client is demoted to RO (0 to disable)
783
+ attach_replay_buffer_size: 65536 # bytes of output history replayed to new attach clients (hosted mode)
784
+ attach_max_connections: 10 # max concurrent attach users per agent (hosted mode)
785
+
786
+ # Hosted server connection (omit for local mode)
787
+ # server:
788
+ # url: https://superkick.example.com
789
+ # api_key: <%= env("SUPERKICK_API_KEY") %>
790
+
791
+ # Named monitor configs (merged with auto-detected config)
792
+ monitors:
793
+ github:
794
+ token: <%= env("GITHUB_TOKEN") %>
795
+ privileged: true # prevent AI from adding/removing this monitor
796
+
797
+ # Post-injection notifications (defaults to terminal_bell when absent)
798
+ notifications:
799
+ - type: terminal_bell
800
+ - type: command
801
+ run: "notify-send 'Superkick' '$SUPERKICK_MESSAGE'"
802
+ - type: slack
803
+ webhook_url: <%= env("SLACK_WEBHOOK_URL") %>
804
+
805
+ # Spawners — server-level pollers that spawn new agents
806
+ spawners:
807
+ shortcut:
808
+ token: <%= env("SHORTCUT_TOKEN") %>
809
+
810
+ search: "owner:me state:'In Progress'"
811
+ driver: claude_code
812
+ repository: my-app
813
+ branch_template: "fix-{{ agent_id }}"
814
+
815
+ # Repository source — catalog for planning agents
816
+ repositories:
817
+ api_service:
818
+ path: ~/projects/api-service
819
+ description: "Core REST API"
820
+ tags: [backend, ruby]
821
+ company:
822
+ type: github_organization
823
+ organization: my-company
824
+ token: <%= env("GITHUB_TOKEN") %>
825
+
826
+ # Global cost budget
827
+ budget:
828
+ max_cost_usd: 100.0
829
+ window_hours: 24
830
+
831
+ # Gem-based plugins
832
+ plugins:
833
+ - name: superkick-my-service
834
+ ```
835
+
836
+ The config file is processed through ERB before YAML parsing, so you can use `<%= env("VAR") %>` to reference environment variables.
837
+
838
+ ### `config.rb`
839
+
840
+ For programmatic configuration (loaded after `config.yml`, always wins):
841
+
842
+ ```ruby
843
+ Superkick.use(:claude_code)
844
+
845
+ Superkick.configure do |c|
846
+ c.poll_interval = 15
847
+ c.idle_threshold = 3.0
848
+ end
849
+ ```
850
+
851
+ ### Configuration settings
852
+
853
+ | Setting | Default | Description |
854
+ |---------|---------|-------------|
855
+ | `poll_interval` | `30` | Seconds between monitor ticks |
856
+ | `idle_threshold` | `5.0` | Seconds the CLI must be idle before injection |
857
+ | `inject_clear_delay` | `0.15` | Sleep between PTY write chunks |
858
+ | `rate_limit_backoff` | `60` | Sleep on API rate limit errors |
859
+ | `error_backoff` | `10` | Sleep on general errors before retry |
860
+ | `log_level` | `:info` | Logger level (`:debug`, `:info`, `:warn`, `:error`) |
861
+ | `attach_escape_key` | `ctrl-a` | Escape prefix for attach sessions (`ctrl-a` through `ctrl-z`). tmux/screen users may prefer `ctrl-b` or `ctrl-]` |
862
+ | `attach_rw_idle_timeout` | `300` | Seconds of inactivity before an RW attach client is auto-demoted to read-only. Set to `0` to disable |
863
+ | `attach_replay_buffer_size` | `65536` | Bytes of output history replayed to new attach clients in hosted mode |
864
+ | `attach_max_connections` | `10` | Maximum concurrent attach user connections per agent in hosted mode |
865
+ | `max_workers_per_team` | `5` | Maximum workers a planning agent can spawn per team |
866
+ | `cost_poll_interval` | `300` | Seconds between cost staleness checks for headless agents |
867
+ | `cost_stale_after` | `600` | Seconds before cost data is considered stale |
868
+ | `notifications` | `[]` | Array of notifier configs; defaults to terminal bell when empty |
869
+ | `repositories` | `{}` | Repository source config (see [Repository source](#repository-source)) |
870
+ | `budget` | `{}` | Global cost budget (`max_cost_usd`, `window_hours`) |
871
+ | `runtime` | `{}` | Agent runtime config (see [Docker runtime](#docker-runtime)) |
872
+ | `session_recording.enabled` | `true` | Record timestamped sessions in asciicast v2 format |
873
+ | `session_recording.max_size` | `104857600` | Max recording file size in bytes (100 MB) before rotation |
874
+
875
+ ### Session recording
876
+
877
+ Superkick records complete, timestamped agent sessions (all input and output) in the [asciicast v2](https://docs.asciinema.org/manual/asciicast/v2/) format. Recordings are saved to `~/.superkick/recordings/<agent-id>.cast` and can be played back with `asciinema play` or in a browser via [asciinema-player](https://docs.asciinema.org/manual/player/).
878
+
879
+ Session recording is enabled by default. To disable it:
880
+
881
+ ```yaml
882
+ session_recording:
883
+ enabled: false
884
+ ```
885
+
886
+ To adjust the max recording file size (default 100 MB, with one rotated `.1` file):
887
+
888
+ ```yaml
889
+ session_recording:
890
+ max_size: 209715200 # 200 MB
891
+ ```
892
+
893
+ In hosted mode, completed recordings are automatically uploaded to the hosted server when the agent exits.
894
+
895
+ ### Docker runtime
896
+
897
+ By default, spawned agents run as local processes on the same machine. To provision agents in Docker containers instead, configure the Docker runtime:
898
+
899
+ ```yaml
900
+ runtime:
901
+ type: docker
902
+ docker:
903
+ image: superkick/agent:latest # required
904
+ host: unix:///var/run/docker.sock # Docker daemon (default: Unix socket)
905
+ pull_policy: missing # always, missing, never
906
+ memory: 4G # container memory limit
907
+ cpu: 2 # CPU cores
908
+ network: superkick-net # Docker network name
909
+ stop_timeout: 30 # seconds before SIGKILL
910
+ auto_remove: true # remove container after exit
911
+ env: # additional env vars
912
+ GITHUB_TOKEN: <%= env("GITHUB_TOKEN") %>
913
+ volumes: # host:container mounts
914
+ - /home/user/.ssh:/root/.ssh:ro
915
+ - /home/user/.gitconfig:/root/.gitconfig:ro
916
+ labels: # container labels
917
+ app: superkick
918
+ privileged: false # run in privileged mode (for DinD)
919
+ cap_add: # Linux capabilities to add
920
+ - SYS_ADMIN
921
+ security_opt: # security options
922
+ - seccomp:unconfined
923
+ container_runtime: sysbox-runc # OCI runtime (for unprivileged DinD)
924
+ registry: # private registry auth
925
+ username: <%= env("DOCKER_REGISTRY_USER") %>
926
+ password: <%= env("DOCKER_REGISTRY_PASSWORD") %>
927
+ server: ghcr.io
928
+ tls: # TLS for TCP connections
929
+ ca: /path/to/ca.pem
930
+ cert: /path/to/cert.pem
931
+ key: /path/to/key.pem
932
+ ```
933
+
934
+ When running with a local server, the runtime auto-mounts the server's Unix socket directory into the container for seamless connectivity. Container names follow the pattern `superkick-<agent-id>`. All containers are labeled with `superkick.agent_id` for identification.
935
+
936
+ ### Filesystem layout
937
+
938
+ ```
939
+ ~/.superkick/
940
+ config.yml # YAML configuration
941
+ config.rb # Ruby configuration (optional)
942
+ superkick.log # Server log file
943
+ sessions/ # JSON agent persistence files
944
+ templates/ # User template overrides
945
+ teams/ # Team logs (ndjson, one per team)
946
+ logs/ # Per-agent output logs
947
+ recordings/ # Per-agent session recordings (asciicast v2)
948
+ run/ # Runtime files (transient)
949
+ server.sock # Server IPC socket
950
+ server.pid # Server PID file
951
+ buffer-<id>.sock # Per-agent PTY buffer sockets
952
+ attach-<id>.sock # Per-agent attach sockets
953
+ ```
954
+
955
+ ## CLI commands
956
+
957
+ | Command | Description |
958
+ |---------|-------------|
959
+ | `superkick server start [-d]` | Start the server (`-d` to daemonize) |
960
+ | `superkick server stop` | Send SIGTERM to the server |
961
+ | `superkick server status` | Show server and agent status |
962
+ | `superkick server log [-n LINES]` | Tail the server log file |
963
+ | `superkick agent start [--driver NAME] [-- ARGS]` | Launch an AI CLI through the PTY proxy |
964
+ | `superkick agent list [--json]` | List all active agents |
965
+ | `superkick agent log AGENT_ID [-n LINES] [-f]` | Tail an agent's output log |
966
+ | `superkick agent stop AGENT_ID` | Stop a spawned agent |
967
+ | `superkick agent attach AGENT_ID [-i] [-f]` | Attach to a running agent (read-only; `-i` for read-write; `-f` / `--force` to take over RW from another client) |
968
+ | `superkick agent claim AGENT_ID` | Claim a spawned agent (pause autonomous operation) |
969
+ | `superkick agent unclaim AGENT_ID` | Release a claimed agent back to autonomous operation |
970
+ | `superkick agent cost [AGENT_ID]` | Show cost tracking for an agent or all agents |
971
+ | `superkick team list [--json]` | List active teams |
972
+ | `superkick team status TEAM_ID [--full]` | Show team log summary (or full log) |
973
+ | `superkick team watch TEAM_ID [--no-color]` | Watch team activity in real time |
974
+ | `superkick team stop TEAM_ID` | Terminate all agents in a team |
975
+ | `superkick spawner list [--json]` | List configured spawners and their status |
976
+ | `superkick spawner start NAME` | Start a stopped spawner |
977
+ | `superkick spawner stop NAME` | Stop a running spawner |
978
+ | `superkick spawner install-templates [--force]` | Copy default spawner Liquid templates |
979
+ | `superkick approve ID` | Approve a pending spawn |
980
+ | `superkick reject ID [--reason REASON]` | Reject a pending spawn |
981
+ | `superkick approvals [--json] [--rejections]` | List pending approvals or rejections |
982
+ | `superkick monitor list` | List available monitor types |
983
+ | `superkick monitor install-templates [--force]` | Copy default monitor Liquid templates to `~/.superkick/templates/` |
984
+ | `superkick mcp configure` | Configure the MCP server for the active driver |
985
+ | `superkick completion SHELL` | Print shell completion script (`bash` or `zsh`) |
986
+
987
+ Global option: `--dir PATH` (or `-C PATH`) overrides the Superkick base directory.
988
+
989
+ ## MCP tools
990
+
991
+ These tools are exposed via the MCP stdio server (`superkick mcp`) and called by the AI CLI. In local mode, tool calls are handled by `McpServer` over a Unix socket. In hosted mode, `Hosted::McpProxy` transparently forwards requests to the hosted server's MCP endpoint over HTTP. The agent's identity is read from the `SUPERKICK_AGENT_ID` environment variable (set automatically by the PTY proxy) — tools do not require `agent_id` as a parameter:
992
+
993
+ | Tool | Description |
994
+ |------|-------------|
995
+ | `superkick_discover_monitors` | List available monitor types and probe-detected configs |
996
+ | `superkick_discover_goals` | List available goal types and their configuration options |
997
+ | `superkick_add_monitor` | Add a monitor to this agent |
998
+ | `superkick_remove_monitor` | Remove a monitor from this agent |
999
+ | `superkick_signal_goal` | Signal goal status (`completed`, `failed`, `errored`, `in_progress`) |
1000
+ | `superkick_report_cost` | Report cumulative token usage and cost (delta computed server-side) |
1001
+ | `superkick_status` | Report server and agent status |
1002
+ | `superkick_spawn_worker` | Spawn a worker agent in a specific repository (with optional `role` label) |
1003
+ | `superkick_discover_repositories` | List available repositories with descriptions, tags, and dependencies |
1004
+ | `superkick_post_update` | Broadcast a status update or send a targeted message to a teammate |
1005
+ | `superkick_team_status` | Read the team log summary or full history |
1006
+ | `superkick_list_teammates` | List all agents on the team with roles and status |
1007
+ | `superkick_publish_artifact` | Share structured data with the team (plans, specs) |
1008
+ | `superkick_read_artifact` | Read an artifact published by a teammate |
1009
+ | `superkick_list_artifacts` | List all artifacts for the team |
1010
+
1011
+ ## Extending Superkick
1012
+
1013
+ Superkick is designed for extension via eight plugin points:
1014
+
1015
+ - **Drivers** — add support for a new AI CLI. See the [driver skill](skills/superkick-new-driver/SKILL.md) for a step-by-step guide.
1016
+ - **Monitors** — add a new event source (CI system, chat service, etc.). See the [monitor skill](skills/superkick-new-monitor/SKILL.md) for a step-by-step guide.
1017
+ - **Spawners** — add a new agent spawning trigger (project management tools, queues, etc.). See the [spawner skill](skills/superkick-new-spawner/SKILL.md) for a step-by-step guide.
1018
+ - **Goals** — define completion criteria for spawned agents (PR merged, command exit code, etc.). See the [goal skill](skills/superkick-new-goal/SKILL.md) for a step-by-step guide.
1019
+ - **Version control adapters** — add support for a new VCS (Mercurial, Subversion, etc.). See the [version control skill](skills/superkick-new-version-control/SKILL.md) for a step-by-step guide.
1020
+ - **Repository sources** — add a new repository discovery source (GitLab, Bitbucket, a custom catalog API). See the [repository source skill](skills/superkick-new-repository-source/SKILL.md) for a step-by-step guide.
1021
+ - **Agent runtimes** — add a new compute backend for spawned agents (Kubernetes, Firecracker, etc.). The runtime interface is documented in [CLAUDE.md](CLAUDE.md).
1022
+ - **Notifiers** — add a new notification channel (OS notifications, chat webhooks, sound effects, etc.). See the [notifier skill](skills/superkick-new-notifier/SKILL.md) for a step-by-step guide.
1023
+
1024
+ All eight can be extracted into standalone gems and loaded via `plugins:` in `config.yml`.
1025
+
1026
+ ## Development
1027
+
1028
+ ```bash
1029
+ # Install dependencies
1030
+ bundle install
1031
+
1032
+ # Run the full test suite
1033
+ bundle exec rake test
1034
+
1035
+ # Run a single test file
1036
+ bundle exec rake test TEST=test/monitor_test.rb
1037
+
1038
+ # Run a specific test by name
1039
+ bundle exec rake test TEST=test/monitor_test.rb TESTOPTS="-n test_dispatches_event"
1040
+
1041
+ # Run all tests matching a name pattern
1042
+ bundle exec rake test TESTOPTS="-n /rate_limit/"
1043
+
1044
+ # Lint with Standard.rb
1045
+ bundle exec rake standard
1046
+
1047
+ # Auto-fix lint violations
1048
+ bundle exec rake standard:fix
1049
+
1050
+ # Run tests + lint together (the default)
1051
+ bundle exec rake
1052
+ ```
1053
+
1054
+ For a detailed guide to the architecture, key classes, design patterns, and how to extend Superkick, see [CLAUDE.md](CLAUDE.md).
1055
+
1056
+ ### Project structure
1057
+
1058
+ ```
1059
+ lib/superkick/
1060
+ cli.rb # Thor CLI interface (server, agent, monitor, spawner, team, mcp)
1061
+ cli/ # CLI subcommands (server, agent, monitor, spawner, team, mcp)
1062
+ server.rb # Server lifecycle
1063
+ mcp_server.rb # MCP stdio server — local mode (16 tools)
1064
+ hosted/mcp_proxy.rb # MCP stdio-to-HTTP proxy — hosted mode
1065
+ configuration.rb # Global settings
1066
+ yaml_config.rb # config.yml loader
1067
+ version.rb # Gem version constant
1068
+ pty_proxy.rb # PTY wrapper (stdin/output/inject threads)
1069
+ input_buffer.rb # Partial input tracking + guard state
1070
+ injection_queue.rb # Agent-side injection queue with TTL, priority, supersede-by-key
1071
+ injection_guard.rb # PatternGuard data class for suppressing injection
1072
+ injector.rb # Injection orchestration
1073
+ inject_handler.rb # Monitor event handler
1074
+ output_logger.rb # Tees PTY output to per-agent log files
1075
+ history_buffer.rb # Ring buffer of recent PTY output for attach replay
1076
+ process_runner.rb # Subprocess execution with reliable timeouts
1077
+ connection.rb # Newline-delimited JSON framing (shared by control + data plane)
1078
+ client_registry.rb # Shared module for client factory methods
1079
+ registry.rb # Test isolation for class-level registries
1080
+ buffer/
1081
+ server.rb # Per-agent buffer socket server
1082
+ client.rb # Buffer client (Unix socket transport)
1083
+ attach/
1084
+ server.rb # Per-agent attach endpoint with RW exclusivity
1085
+ client.rb # CLI client for attach sessions
1086
+ protocol.rb # Binary frame protocol for attach
1087
+ control/
1088
+ server.rb # Control plane Unix socket server
1089
+ client.rb # Control plane client (Unix socket transport)
1090
+ reply.rb # Typed response wrapper
1091
+ hosted/
1092
+ bridge.rb # Abstract base class for agent-side WebSocket bridges
1093
+ buffer/ # Hosted buffer transport (client, bridge, relay, relay_store)
1094
+ attach/ # Hosted attach transport (client, bridge, relay, relay_store)
1095
+ control/
1096
+ client.rb # HTTPS control client for remote servers
1097
+ template_renderer.rb # Liquid rendering with template filters
1098
+ template_filters.rb # Core Liquid filters (time, short_sha, truncate)
1099
+ liquid.rb # Liquid DSL module for declaring filters/blocks/tags
1100
+ drop.rb # Base class for Liquid Drops with serialize/rehydrate
1101
+ drops.rb # Core Drops (TeamDrop, SpawnerDrop, MonitorDrop, AgentDrop)
1102
+ notifier.rb # Abstract Notifier base class + registry
1103
+ notifier_state_store.rb # Injectable state storage for stateful notifiers
1104
+ notifier_template.rb # Structured template rendering for notifiers
1105
+ notification_dispatcher.rb # Stateful notification dispatcher
1106
+ notifiers/ # Built-in notifiers (terminal_bell, command)
1107
+ poller.rb # Abstract Poller base class — shared run loop
1108
+ monitor.rb # Abstract Monitor base class + Monitor::Probe
1109
+ spawner.rb # Abstract Spawner base class (server-level pollers)
1110
+ spawn/
1111
+ agent_spawner.rb # Repository acquisition + agent subprocess lifecycle
1112
+ handler.rb # Spawner event handler (dedup, approval gates)
1113
+ injector.rb # Kickoff prompt injection into spawned agents
1114
+ approval_store.rb # Pending spawn approvals + rejection tracking
1115
+ workflow_executor.rb # Orchestrates workflow spawns (on_complete/on_fail)
1116
+ workflow_validator.rb # Static cycle detection for workflow configs
1117
+ agent.rb # Live agent object (id, monitors, team, cost)
1118
+ agent_store.rb # Agent registry (JSON persistence)
1119
+ agent/
1120
+ runtime.rb # Abstract runtime base class + registry
1121
+ runtimes/
1122
+ local.rb # Local process spawning (default)
1123
+ team/
1124
+ log.rb # Append-only ndjson team communication log
1125
+ log_store.rb # Server-level lazy registry of Team::Log instances
1126
+ log_entry_drop.rb # Liquid Drop for team log entries
1127
+ artifact_store.rb # Per-team persistent artifact storage
1128
+ log_monitor.rb # Polls team log, injects digest events
1129
+ log_notifier.rb # Internal notifier that writes team log entries
1130
+ supervisor.rb # Supervisor — monitor + spawner + goal checker thread lifecycle
1131
+ repository_source.rb # Repository catalog (static, directory, composite)
1132
+ version_control.rb # Abstract VersionControl base class + registry
1133
+ version_controls/ # Built-in VCS adapters (git)
1134
+ cost_accumulator.rb # Thread-safe per-agent cost tracking
1135
+ cost_extractor.rb # Line-buffered PTY output cost parser
1136
+ cost_poller.rb # Periodic cost command injection for stale agents
1137
+ budget_checker.rb # Multi-level budget evaluation (agent/spawner/global)
1138
+ driver.rb # Abstract Driver base class + CostPattern + registry
1139
+ driver/
1140
+ profile_source.rb # Named driver profile sources
1141
+ drivers/ # Built-in CLI drivers (claude_code, copilot, codex, gemini, goose)
1142
+ goal.rb # Abstract Goal base class + registry
1143
+ goals/ # Built-in goals (agent_exit, command, agent_signal)
1144
+ integrations/ # Built-in integrations (github, circleci, shortcut, shell, slack,
1145
+ # bugsnag, datadog, honeybadger, docker)
1146
+ ```
1147
+
1148
+ ## License
1149
+
1150
+ [Business Source License 1.1](LICENSE) — source-available with production use
1151
+ permitted (except competing SaaS offerings). Converts to [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0)
1152
+ after four years per version.
1153
+
1154
+ A [commercial license](LICENSE-COMMERCIAL.md) is available for use cases outside
1155
+ the BSL's Additional Use Grant. See the [CLA](CLA.md) for contributor terms.