# Railway plugin

The Railway plugin lets a Vaubaan Gateway mission use Railway without handing the agent a credential. Deploy, redeploy, read logs and manage variables of Railway projects through the official Railway MCP server and GraphQL API.

- Version: `4.2.0` (package `@vaubaan/plugin-railway`)
- Status: stable
- Health: not enough reports yet — [what this means](/plugins/health)
- Source: [plugins/railway](https://github.com/vaubaan/gateway/tree/main/plugins/railway), catalog [risk-catalog.yaml](https://github.com/vaubaan/gateway/blob/main/plugins/railway/src/risk-catalog.yaml) version 4 of 2026-10-14
- How to connect an account: [Connect Railway](/docs/providers/railway)
- How it is modelled: [handbook](https://github.com/vaubaan/gateway/blob/main/docs/handbook/providers/railway.md)

One account is one Railway account reached through the company Railway app, or a workspace token (or an account token) pasted by hand; every tool runs either way. One resource is one project. Its owner labels each project with an environment (prod, staging, preview or dev); deploys and variable changes are held per label, and a project without a label can only be inspected.

## Permissions

Each permission is a named risk of the plugin's catalog: a mission holds an explicit list of them, never "all". The severity is computed from the permission's six axes (undo, blast radius, data, cost, visible to, lasts); nothing is decided from it.

| Permission | What it allows | Severity | Why it is a risk |
| --- | --- | --- | --- |
| `railway.read-account` | Read the account and the list of projects | low | Account metadata only (\`whoami\`, \`list-projects\`). No secret is returned ; the blast radius is the whole workspace because the call is not scoped to a project. |
| `railway.read-runtime` | Read services, deployments and statuses | low | Runtime metadata of a project (services, deployments, status). No secret payload. Broad by design : it co-matches every project-scoped read, so a more specific read permission (logs, variables) is required on top of it. |
| `railway.read-logs` | Read the logs of a deployment | low | Application logs often contain printed secrets (DSN, JWT, stack traces with PII). Classified \`data\` rather than \`secret\` because a well-run project does not log its secrets ; a strict creator leaves it out. |
| `railway.read-variables` | Read environment variables (including secrets) | low (only for `staging`, `preview`, `dev`, `prod`) | Returns variable values in clear by default. The main exfiltration surface for production credentials, hence env-scoped : holding it on staging says nothing about prod. |
| `railway.deploy` | Redeploy a service or accept staged changes (deploy) | medium (high on `prod`; only for `staging`, `preview`, `dev`, `prod`) | Reversible : a new deploy fixes a bad one, and Railway bills usage. On prod the deployed state is visible to customers until reverted, hence the per-env vector override. |
| `railway.upsert-variable` | Create, modify or delete an environment variable | medium (high on `prod`; only for `staging`, `preview`, `dev`, `prod`) | Scalar change of named variables (upsert or delete). Triggers an implicit redeploy unless \`skipDeploys\` is set. On prod a wrong value breaks the service immediately. |
| `railway.bulk-variables-replace` | Replace every environment variable in bulk (replace=true) | high | DESTRUCTIVE : every variable absent from the payload is deleted. Detected from \`replace\` set on \`upsert-variables\`, from an empty or malformed variable payload, and on every \`railway-agent\` call. Any environment, prod or not. |
| `railway.create-project` | Create a new Railway project | high | Account-level write. Not reversible from the MCP surface (deleting a project needs the dashboard) and may generate unbounded cost. |
| `railway.agent-action` | Invoke the Railway agent (conversational meta-tool) | high | The upstream agent decides alone what to mutate ; no fine classification is possible. Catch-all by construction : the classifier also emits the deployment, variable write and variable replace slices, so a mission must hold those permissions too. Explicit opt-in only ; absent from every preset. |
| `railway.uncategorized-write` | Uncategorized Railway write | medium (the catch-all: touched only by a call no other permission covers) | Catch-all for writes without a dedicated entry. Seen in production, it means a tool classifies to a slice no fine-grained entry covers : add the entry. |

## Presets

A preset pre-fills the permissions of a mission for one account, with a limit per period, a rate and whether each permission runs freely or asks the mission creator first. The person creating the mission adjusts it; the mission stores the explicit list.

### Read-only

`read-only` — Inspect projects, services, deployments and logs. No variable values, no write.

| Permission | What it allows | Limit per period | Rate | Runs |
| --- | --- | --- | --- | --- |
| `railway.read-account` | Read the account and the list of projects | 1000 | 60 per minute | runs freely |
| `railway.read-runtime` | Read services, deployments and statuses | 2000 | 120 per minute | runs freely |
| `railway.read-logs` | Read the logs of a deployment | 500 | 30 per minute | runs freely |

### Developer

`developer` — One mission per code project — deploy, redeploy and manage variables on non-production environments freely; read logs; production deploys and variable writes ask first.

| Permission | What it allows | Limit per period | Rate | Runs |
| --- | --- | --- | --- | --- |
| `railway.read-account` | Read the account and the list of projects | 1000 | 60 per minute | runs freely |
| `railway.read-runtime` | Read services, deployments and statuses | 5000 | 120 per minute | runs freely |
| `railway.read-logs` | Read the logs of a deployment | 2000 | 60 per minute | runs freely |
| `railway[dev].read-variables` |  | 200 | 20 per minute | runs freely |
| `railway[preview].read-variables` |  | 200 | 20 per minute | runs freely |
| `railway[staging].read-variables` |  | 200 | 20 per minute | runs freely |
| `railway[dev].deploy` |  | 300 | 10 per minute | runs freely |
| `railway[preview].deploy` |  | 300 | 10 per minute | runs freely |
| `railway[staging].deploy` |  | 300 | 10 per minute | runs freely |
| `railway[prod].deploy` |  | 20 | 2 per minute | ask me first |
| `railway[dev].upsert-variable` |  | 200 | 20 per minute | runs freely |
| `railway[preview].upsert-variable` |  | 200 | 20 per minute | runs freely |
| `railway[staging].upsert-variable` |  | 200 | 20 per minute | runs freely |
| `railway[prod].upsert-variable` |  | 20 | 5 per minute | ask me first |

### Operator

`operator` — Run production — every read including production variables, deploys everywhere, destructive variable replacement and project creation asking first.

| Permission | What it allows | Limit per period | Rate | Runs |
| --- | --- | --- | --- | --- |
| `railway.read-account` | Read the account and the list of projects | 2000 | 60 per minute | runs freely |
| `railway.read-runtime` | Read services, deployments and statuses | 10000 | 120 per minute | runs freely |
| `railway.read-logs` | Read the logs of a deployment | 5000 | 60 per minute | runs freely |
| `railway[dev].read-variables` |  | 500 | 30 per minute | runs freely |
| `railway[preview].read-variables` |  | 500 | 30 per minute | runs freely |
| `railway[staging].read-variables` |  | 500 | 30 per minute | runs freely |
| `railway[prod].read-variables` |  | 50 | 5 per minute | runs freely |
| `railway[dev].deploy` |  | 500 | 10 per minute | runs freely |
| `railway[preview].deploy` |  | 500 | 10 per minute | runs freely |
| `railway[staging].deploy` |  | 500 | 10 per minute | runs freely |
| `railway[prod].deploy` |  | 50 | 5 per minute | ask me first |
| `railway[dev].upsert-variable` |  | 500 | 30 per minute | runs freely |
| `railway[preview].upsert-variable` |  | 500 | 30 per minute | runs freely |
| `railway[staging].upsert-variable` |  | 500 | 30 per minute | runs freely |
| `railway[prod].upsert-variable` |  | 50 | 5 per minute | ask me first |
| `railway.bulk-variables-replace` | Replace every environment variable in bulk (replace=true) | 5 | 1 per minute | ask me first |
| `railway.create-project` | Create a new Railway project | 5 | 1 per minute | ask me first |

## Tools

| Tool | What it does |
| --- | --- |
| `railway__whoami` | Read who the account is |
| `railway__list-projects` | List projects |
| `railway__create-project` | Create a project |
| `railway__list-services` | List services and environments |
| `railway__list-deployments` | List deployments |
| `railway__get-status` | Read the deployment status |
| `railway__get-logs` | Read logs |
| `railway__redeploy` | Redeploy a service |
| `railway__accept-deploy` | Commit staged changes and deploy |
| `railway__railway-agent` | Ask Railway's agent to act |
| `railway__list-variables` | List environment variables |
| `railway__upsert-variable` | Set an environment variable |
| `railway__upsert-variables` | Set several environment variables |
| `railway__delete-variable` | Delete an environment variable |

## Health

Health: not enough reports yet. A plugin version is deemed validated by the community with at least 200 reports and 90 % of them successful, over the last 90 days, as reported by the instances whose operators turned community telemetry on. It is a community signal, not a security guarantee.
