Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .factory-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@
"description": "Pull request lifecycle skills: create PRs with consistent conventions and follow up on them until merge-ready",
"source": "./plugins/code-review",
"category": "productivity"
},
{
"name": "fly",
"description": "Deploy and operate Fly.io apps, Machines, volumes, and Managed Postgres; run development workloads in persistent Sprites.",
"source": "./plugins/fly",
"category": "deployment"
}
]
}
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,27 @@ Skills for continuous learning and improvement.

Autonomous experiment loop for optimization research. Try an idea, measure it, keep what works, discard what doesn't, repeat. Works standalone or as a mission worker.

### fly

Fly.io operations and persistent Sprite development environments. Inspect and
operate authorized resources through Fly MCP, deploy apps with flyctl, and run
tests remotely in Sprites with checkpoints, authenticated previews, and patch
export.

**Skills:**

- `fly` - Fly.io apps, Machines, volumes, Managed Postgres, and Sprite workflows
- `brand` - Fly.io naming and visual guidance

Includes a hosted OAuth MCP connection and confirmation hooks. Requires Factory
model access and a Fly.io account; Python 3 enables the hooks.

```bash
droid plugin install fly@factory-plugins
```

See [plugins/fly/README.md](plugins/fly/README.md) for setup and examples.

## Plugin Structure

Each plugin follows the Factory plugin format:
Expand Down
10 changes: 10 additions & 0 deletions plugins/fly/.factory-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "fly",
"version": "1.0.1",
"description": "Fly.io operations and persistent Sprite development environments for Factory Droid.",
"author": {"name": "Fly.io", "email": "support@fly.io"},
"homepage": "https://fly.io",
"repository": "https://github.com/superfly/fly-droid-plugin",
"license": "MIT",
"keywords": ["fly", "sprites", "deployment", "postgres", "remote-development", "mcp"]
}
21 changes: 21 additions & 0 deletions plugins/fly/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Fly.io

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
83 changes: 83 additions & 0 deletions plugins/fly/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Fly.io for Factory Droid

Use Fly.io from Droid: deploy apps with flyctl, inspect and operate authorized
resources through Fly MCP, and build or test code in persistent Sprites.

## Install

You need Factory Droid with model access and a Fly.io account. The hosted MCP
connection uses browser OAuth; no local Fly CLI is needed for MCP operations.
Install Python 3 for the confirmation hook. Local deploys and operations not
exposed by MCP need flyctl; the Fly skill includes setup instructions.

```bash
droid plugin marketplace add superfly/fly-droid-plugin
droid plugin marketplace list
droid plugin install fly@fly-droid-plugin --scope project
droid mcp auth
droid mcp list
```

Complete Factory login and project trust in Droid first. Authorize the plugin's
`fly` MCP server for the intended organization. Factory model access and Fly
authorization are separate. An empty list of authorized resources is a valid
result. Use `--scope user` instead for all projects. Pinned marketplaces can have
different names; use the name printed by `marketplace list`.

If you previously installed `fly@skills`, disable it in `/plugins` before enabling
this package in the same project. Do not configure a second standalone `fly`
server when the plugin already supplies it. Your existing Fly resources are
unaffected by changing the local plugin installation.

## Example requests

- "What Fly.io resources can this connection access?"
- "Check the health and recent logs for my Fly app."
- "Use a Sprite for this project's tests and give me a patch with the fix."
- "Resume the same Sprite workspace and verify its private preview."
- "Plan how to attach Managed Postgres to this app. Don't provision it yet."

Droid can select the `fly` skill from these requests. Skill selection depends on
the model; for an explicit invocation, ask it to use the installed `fly` skill.
The `brand` skill supplies Fly.io naming and visual guidance when relevant.

## Remote work

Droid's built-in file and shell tools still act on your local machine. Remote
edits, tests, and service commands must run through Sprite tools. Keep the Sprite
name, ID, and repository path in the handoff so the next session reuses it.

The [Sprite guide](skills/fly/references/sprites.md) covers source transfer,
baseline tests, checkpoints, patch export, supervised previews, and resuming work.
Preview URLs can require authentication. Keep existing access restrictions;
do not make a preview public merely to pass a health check.

## Access and safety

The MCP endpoint is `https://mcp.fly.io`. It can operate only within the OAuth
grant, including organization, app, product, and Sprite restrictions. Begin with
`get_fly_context`. The plugin does not broaden access or supply credentials.

The hook recognizes Droid's `Execute` and `fly___*` tool names and asks
before recognized destructive, disruptive, billable, and checkpoint-sensitive
operations. It is a command-pattern guard, not a shell sandbox. When Python 3
is missing or cannot run, it reports that the hook was skipped; ordinary Droid
permissions and server authorization still apply. Install Python 3 to enable it.

Fly.io resources can incur charges. Creation, deployment, scaling, restoration,
deletion, and changing public access require the corresponding user intent.
Never copy credentials into source files, logs, or preview responses.

## Troubleshooting

- Plugin missing: check `/plugins`, the project's scope, and marketplace name.
- Tools missing: check `droid mcp list`; authorize the bundled server with
`droid mcp auth`, then start a fresh session.
- Model requests fail: verify Factory model access separately from Fly OAuth.
- Grant denied: explain the missing access; do not switch credentials to bypass it.
- Runtime operation fails: inspect the resource before retrying. The dated
known-issue notes in the Sprite guide record tested workarounds, not guarantees
that every runtime has the same limitations.

See the [distribution repository](https://github.com/superfly/fly-droid-plugin)
for validation and the release process. MIT licensed. [Fly.io](https://fly.io)
20 changes: 20 additions & 0 deletions plugins/fly/assets/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions plugins/fly/hooks/hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"description": "Ask before destructive, disruptive, or billable Fly operations",
"hooks": {
"PreToolUse": [
{
"matcher": "^(mcp__(plugin_fly_fly|fly)__|fly___).*$",
"hooks": [
{
"type": "command",
"command": "python3 \"${GROK_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/scripts/fly_guard.py\" 2>/dev/null || { if ! python3 -c pass >/dev/null 2>&1; then printf '%s\\n' '{\"systemMessage\": \"Fly confirmation hook skipped: python3 was not found on PATH or cannot run. Install Python 3 to enable Fly confirmations. Normal client permissions still apply.\"}'; exit 0; fi; printf '%s\\n' 'Fly guard failed to inspect this call. Repair the guard before retrying.' >&2; exit 2; }",
"timeout": 10,
"onFailure": "block"
}
]
},
{
"matcher": "^(Bash|Execute)$",
"hooks": [
{
"type": "command",
"command": "python3 \"${GROK_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/scripts/fly_guard.py\" 2>/dev/null || { if ! python3 -c pass >/dev/null 2>&1; then printf '%s\\n' '{\"systemMessage\": \"Fly confirmation hook skipped: python3 was not found on PATH or cannot run. Install Python 3 to enable Fly confirmations. Normal client permissions still apply.\"}'; exit 0; fi; printf '%s\\n' 'Fly guard failed to inspect this call. Repair the guard before retrying.' >&2; exit 2; }",
"timeout": 10,
"onFailure": "block"
}
]
}
]
}
}
8 changes: 8 additions & 0 deletions plugins/fly/mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"mcpServers": {
"fly": {
"type": "http",
"url": "https://mcp.fly.io"
}
}
}
Loading