Skip to content
Closed
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
214 changes: 214 additions & 0 deletions .agents/skills/railway-config/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
---
name: railway-config
description: Edit this project's Railway infrastructure-as-code configuration. Use this skill whenever the user asks to create, change, import, review, or troubleshoot Railway project infrastructure for the current repository, including services, databases, buckets, custom domains, replicas/regions, groups, environment variables, `railway config *`, or `.railway/railway.ts`.
---

# Railway configuration skill

Use this skill when editing this repository's Railway configuration.

The source of desired Railway project state is:

```txt
.railway/railway.ts
```

## Core rules

1. Express Railway product intent, not internal API details.
2. Do not write Railway UUIDs into `.railway/railway.ts`.
3. Do not write `EnvironmentConfigPatch`, `ServiceInstance`, Backboard internals, or generated Railway domains into source.
4. Prefer Railway configuration helpers like `service()`, `postgres()`, `redis()`, `mysql()`, `mongo()`, `bucket()`, `group()`, `github()`, and `image()`.
5. Use `service.env.VARIABLE` and `database.env.VARIABLE` for references.
6. Keep secrets out of source. Imported unknown secret values should use `preserve()` or be omitted when the user wants a smaller import.
7. Prefer product DSL names such as `domains`, `replicas`, and `group`; avoid internal names like `customDomains` and `multiRegionConfig`.
8. Do not add platform defaults unless the user explicitly wants them.
9. Do not manage a service from both `.railway/railway.ts` and `railway.json` / `railway.toml`; migrate the repo config first.
10. After editing `.railway/railway.ts`, run `railway config plan`.
11. Do not run `railway config apply` unless the user explicitly asks.
12. Never use `railway config apply --yes` or `railway config apply --confirm-destructive` from an agent session without explicit user approval for the exact plan.

## Commands

Initialize configuration files:

```bash
railway config init
```

Import current Railway state:

```bash
railway config pull
```

Import current Railway state with a smaller generated file that omits unknown variable values:

```bash
railway config pull --omit-preserved-variables
```

Preview changes:

```bash
railway config plan
```

Apply changes:

```bash
railway config apply
```

Machine-readable preview:

```bash
railway config plan --json
```

## Authoring

Use Railway configuration helpers:

```ts
import {
bucket,
defineRailway,
github,
group,
image,
mongo,
mysql,
postgres,
preserve,
project,
redis,
service,
} from "railway/iac";
```

Minimal local service:

```ts
const web = service("web", {
build: "bun run build",
start: "NODE_ENV=production bun src/index.ts",
});
```

GitHub service:

```ts
const web = service("web", {
source: github("owner/repo", { branch: "main" }),
build: "pnpm run build",
start: "pnpm start",
});
```

Docker image service:

```ts
const worker = service("worker", {
source: image("ghcr.io/acme/worker:latest"),
});
```

Database reference:

```ts
const db = postgres("postgres");

const web = service("web", {
env: {
DATABASE_URL: db.env.DATABASE_URL,
},
});
```

Service-to-service reference:

```ts
const api = service("api", {
env: {
INTERNAL_TOKEN: preserve(),
},
});

const web = service("web", {
env: {
API_TOKEN: api.env.INTERNAL_TOKEN,
API_HOST: api.env.RAILWAY_PRIVATE_DOMAIN,
},
});
```

Custom domains:

```ts
const web = service("web", {
domains: ["app.example.com"],
});
```

Replicas:

```ts
const web = service("web", {
replicas: 3,
});
```

Advanced placement:

```ts
const web = service("web", {
replicas: {
"us-west2": 2,
"europe-west4": 1,
},
});
```

Groups:

```ts
const api = service("api");
const worker = service("worker");
const backend = group("Backend", [api, worker]);
```

Bucket:

```ts
const media = bucket("media", { region: "iad" });
```

Project shape:

```ts
export default defineRailway(() => {
const db = postgres("postgres");
const web = service("web", {
env: {
DATABASE_URL: db.env.DATABASE_URL,
},
});

return project("my-app", {
resources: [db, web],
});
});
```

## Review checklist

Before applying changes, confirm:

- The user has reviewed the latest `railway config plan` output.
- `railway config plan` shows only expected changes.
- Secrets are not replaced with literal placeholder values.
- Existing Railway-managed variables are omitted or use `preserve()` when the value should remain untouched.
- Custom domains are declared with `domains`, not networking internals.
- Scaling is declared with `replicas`, not `multiRegionConfig`.
- No generated Railway service domains are committed.
45 changes: 45 additions & 0 deletions .railway/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Railway configuration

This project defines its Railway infrastructure in code.

```txt
.railway/railway.ts
```

Use this file to describe the Railway project you want: services, databases, buckets, custom domains, replicas, groups, and environment variables.

## Common commands

Create the configuration files:

```bash
railway config init
```

Import an existing Railway project into code:

```bash
railway config pull
```

Preview what Railway would change:

```bash
railway config plan
```

Apply the planned changes:

```bash
railway config apply
```

## Notes

- `railway config plan` is safe and does not change Railway.
- `railway config apply` previews changes and asks before applying unless you pass `--yes`.
- Destructive changes in non-interactive or agent sessions require `railway config apply --confirm-destructive` after reviewing the plan.
- Services already managed by `railway.json` / `railway.toml` must be migrated before `.railway/railway.ts` can manage them.
- Use `replicas` for scaling; advanced placement can still specify region names.
- Use `group("Name", [resources])` to keep large projects organized on the Railway canvas.
- Secrets imported from Railway are rendered as `preserve()` so existing values are retained without writing secret values to source. Use `railway config pull --omit-preserved-variables` for a smaller import.
30 changes: 30 additions & 0 deletions .railway/railway.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { defineRailway, github, preserve, project, service } from "railway/iac";

export default defineRailway(() => {
const voxl = github("OpenStaticFish/voxl", { branch: "master" });

const game = service("game", {
source: voxl,
build: { buildEnvironment: "V3", builder: "DOCKERFILE", dockerfilePath: "Dockerfile" },
healthcheck: "/",
healthcheckTimeout: 100,
replicas: 1,
env: {
PORT: preserve(),
},
});
const website = service("website", {
source: voxl,
build: { buildEnvironment: "V3", builder: "DOCKERFILE", dockerfilePath: "website/Dockerfile" },
healthcheck: "/",
healthcheckTimeout: 100,
replicas: 1,
env: {
PORT: preserve(),
},
});

return project("voxl", {
resources: [game, website],
});
});
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,3 +331,5 @@ node scripts/screenshot.ts → reached Chromium launch; failed ONLY because the
array indexing is pervasive and construction-bounds-safe; this trades a bit of
type rigor for readable code. With more time I'd add focused bounds helpers and
re-enable it.

<!-- preview-deploy verification (throwaway) -->
Loading
Loading