{
  "manifest_version": "1.0.0",
  "template": {
    "id": "37b01f2f-b3c8-4fe7-a304-41544450042c",
    "slug": "agenticos",
    "name": "AgenticOS",
    "description": "AI agents for teams: tools, knowledge bases, routines, Slack and Mattermost",
    "url": "https://railway.com/deploy/agenticos",
    "upstream": {
      "image": "ghcr.io/vstorm-co/agenticos-backend:1.27.0"
    }
  },
  "status": "unvalidated",
  "validated_at": null,
  "success_rate_30d": null,
  "services": [
    {
      "name": "API",
      "source": {
        "image": "ghcr.io/vstorm-co/agenticos-backend:1.27.0"
      },
      "needs_volume": true,
      "volume_mount_path": "/app/media",
      "http": true
    },
    {
      "name": "Postgres",
      "source": {
        "image": "ghcr.io/railwayapp-templates/postgres-ssl:16"
      },
      "needs_volume": true,
      "volume_mount_path": "/var/lib/postgresql/data",
      "http": false
    },
    {
      "name": "Redis",
      "source": {
        "image": "redis:8.2.1"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "AgenticOS",
      "source": {
        "image": "ghcr.io/vstorm-co/agenticos-frontend:1.27.0"
      },
      "needs_volume": false,
      "http": true
    }
  ],
  "required_inputs": [
    {
      "key": "PORT",
      "service": "API",
      "description": "Port the API listens on.",
      "secret": false,
      "strategy": "default",
      "default": "8000"
    },
    {
      "key": "DEBUG",
      "service": "API",
      "description": "Debug mode.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "API_KEY",
      "service": "API",
      "description": "Key for AgenticOS's internal API.",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "ORG_NAME",
      "service": "API",
      "description": "Name of the organization created on first boot.",
      "secret": false,
      "strategy": "default",
      "default": "My Organization"
    },
    {
      "key": "REDIS_HOST",
      "service": "API",
      "description": "Redis host.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "SECRET_KEY",
      "service": "API",
      "description": "Signs sessions and tokens.",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "ADMIN_EMAIL",
      "service": "API",
      "description": "Email for the owner account created on first boot. You sign in with it.",
      "secret": false,
      "strategy": "ask_user"
    },
    {
      "key": "BOOT_SCRIPT",
      "service": "API",
      "description": "Start-up script (migrations, first-boot setup, worker, API). Kept in a variable because Railway runs start commands without a shell file.",
      "secret": false,
      "strategy": "default",
      "default": "# AgenticOS on Railway: migrations, a one-time first-boot setup, then the background\n# worker and the API in one container. Upstream runs api and worker as two compose\n# services sharing a media volume; a Railway volume attaches to one service only, so\n# both run here. Railway restarts the container, not a process, hence the worker loop.\nset -e\ncd /app\necho \"[boot] applying database migrations\"\nagenticos db upgrade\n\nMARK=/app/media/.railway-bootstrapped\nif [ ! -f \"$MARK\" ]; then\n  # Owner account (made platform admin), organization, model profile and a demo agent.\n  # Idempotent upstream, but run once so deleting the demo org later is not undone.\n  echo \"[boot] first boot: creating the owner $ADMIN_EMAIL and organization\"\n  agenticos cmd bootstrap --email \"$ADMIN_EMAIL\" --password \"$ADMIN_PASSWORD\" \\\n    --org \"${ORG_NAME:-My Organization}\" --provider \"${BOOTSTRAP_PROVIDER:-anthropic}\"\n  # Sign-up is open by default upstream; on a public URL that admits anyone. Close it\n  # to invitations, only when no sign-up setting was ever saved.\n  python - <<'PY'\nimport asyncio\nfrom app.db.session import get_db_context\nfrom app.repositories import deployment_settings_repo\n\nasync def main():\n    async with get_db_context() as db:\n        if await deployment_settings_repo.get(db) is None:\n            await deployment_settings_repo.upsert(db, update_data={\"signup_mode\": \"invite_only\"})\n            print(\"[boot] sign-up set to invite only\")\n\nasyncio.run(main())\nPY\n  touch \"$MARK\"\nfi\n\n( while true; do\n    python -m app.worker || true\n    echo \"[boot] worker stopped; restarting in 5s\"\n    sleep 5\n  done ) &\n\necho \"[boot] starting the API on :${PORT:-8000}\"\n# --host :: covers IPv6 (Railway's private network) and IPv4 (its health checker):\n# with --workers uvicorn binds the socket itself and keeps the kernel's dual-stack default.\nexec uvicorn app.main:app --host :: --port \"${PORT:-8000}\" \\\n  --workers \"${UVICORN_WORKERS:-2}\" --timeout-worker-healthcheck 60 --ws websockets-sansio\n"
    },
    {
      "key": "ENVIRONMENT",
      "service": "API",
      "description": "Turns on AgenticOS's production checks.",
      "secret": false,
      "strategy": "default",
      "default": "production"
    },
    {
      "key": "POSTGRES_DB",
      "service": "API",
      "description": "Database name.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CORS_ORIGINS",
      "service": "API",
      "description": "Browser origins allowed to call the API.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "FRONTEND_URL",
      "service": "API",
      "description": "The web app's address.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "POSTGRES_HOST",
      "service": "API",
      "description": "Database host.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "POSTGRES_PORT",
      "service": "API",
      "description": "Database port.",
      "secret": false,
      "strategy": "default",
      "default": "5432"
    },
    {
      "key": "POSTGRES_USER",
      "service": "API",
      "description": "Database user.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PUBLIC_WS_URL",
      "service": "API",
      "description": "This API's websocket address.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "ADMIN_PASSWORD",
      "service": "API",
      "description": "Password for the owner account, generated. Read it here after deploying; change it in AgenticOS.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "PUBLIC_API_URL",
      "service": "API",
      "description": "This API's public address.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "REDIS_PASSWORD",
      "service": "API",
      "description": "Redis password.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PUBLIC_BASE_URL",
      "service": "API",
      "description": "This API's public address; chat buttons (Slack, Mattermost) and OAuth callbacks come back here.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "PUBLIC_SITE_URL",
      "service": "API",
      "description": "The web app's address.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "RAILWAY_RUN_UID",
      "service": "API",
      "description": "Runs as root so the API can write to the volume, which Railway mounts root-owned.",
      "secret": false,
      "strategy": "default",
      "default": "0"
    },
    {
      "key": "UVICORN_WORKERS",
      "service": "API",
      "description": "API worker processes, about 450 MB each. Upstream suggests 2 for a team of ten.",
      "secret": false,
      "strategy": "default",
      "default": "2"
    },
    {
      "key": "VAULT_MASTER_KEY",
      "service": "API",
      "description": "Encrypts stored secrets (API keys, tokens). Keep it: losing it makes them unreadable.",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "POSTGRES_PASSWORD",
      "service": "API",
      "description": "Database password.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "BOOTSTRAP_PROVIDER",
      "service": "API",
      "description": "Model provider for the demo agent: anthropic, openai, google or openrouter.",
      "secret": false,
      "strategy": "default",
      "default": "anthropic"
    },
    {
      "key": "WORKER_INGEST_CHILDREN",
      "service": "API",
      "description": "Parallel document ingestions in the background worker.",
      "secret": false,
      "strategy": "default",
      "default": "1"
    },
    {
      "key": "RATE_LIMIT_TRUST_FORWARDED_FOR",
      "service": "API",
      "description": "Rate limits per visitor rather than per Railway proxy; safe because only Railway's proxy reaches this service.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "PGDATA",
      "service": "Postgres",
      "description": "Data directory inside the volume (Railway volumes ship a lost+found at the root).",
      "secret": false,
      "strategy": "default",
      "default": "/var/lib/postgresql/data/pgdata"
    },
    {
      "key": "POSTGRES_DB",
      "service": "Postgres",
      "description": "Database name.",
      "secret": false,
      "strategy": "default",
      "default": "agenticos"
    },
    {
      "key": "POSTGRES_USER",
      "service": "Postgres",
      "description": "Database user.",
      "secret": false,
      "strategy": "default",
      "default": "postgres"
    },
    {
      "key": "POSTGRES_PASSWORD",
      "service": "Postgres",
      "description": "Database password.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "REDIS_PASSWORD",
      "service": "Redis",
      "description": "Redis password.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "PORT",
      "service": "AgenticOS",
      "description": "Port the web app listens on.",
      "secret": false,
      "strategy": "default",
      "default": "3000"
    },
    {
      "key": "HOSTNAME",
      "service": "AgenticOS",
      "description": "Listen on IPv6 and IPv4 (Railway's network uses both).",
      "secret": false,
      "strategy": "default",
      "default": "::"
    },
    {
      "key": "NODE_ENV",
      "service": "AgenticOS",
      "description": "Node environment.",
      "secret": false,
      "strategy": "default",
      "default": "production"
    },
    {
      "key": "BACKEND_URL",
      "service": "AgenticOS",
      "description": "The API over Railway's private network.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "PUBLIC_WS_URL",
      "service": "AgenticOS",
      "description": "The API's websocket address, used by your browser.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "PUBLIC_API_URL",
      "service": "AgenticOS",
      "description": "The API's public address, used by your browser.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "OAUTH_PROVIDERS",
      "service": "AgenticOS",
      "description": "Sign-in buttons to show (google, github, ...). none until you configure an OAuth app.",
      "secret": false,
      "strategy": "default",
      "default": "none"
    },
    {
      "key": "PUBLIC_SITE_URL",
      "service": "AgenticOS",
      "description": "This web app's address.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    }
  ],
  "deploy": {
    "mcp": {
      "server": "railway",
      "tool": "deploy_template",
      "args": {
        "template_code": "agenticos"
      }
    },
    "cli": "railway deploy --template agenticos",
    "api": {
      "method": "POST",
      "path": "/graphql/v2",
      "body": {
        "query": "mutation templateDeploy($input: TemplateDeployV2Input!) { templateDeployV2(input: $input) { projectId workflowId } }",
        "variables": {
          "input": {
            "templateId": "37b01f2f-b3c8-4fe7-a304-41544450042c",
            "serializedConfig": {
              "buckets": {},
              "services": {
                "83b92a3a-0185-4192-afb7-2a72540594c8": {
                  "icon": "https://raw.githubusercontent.com/vstorm-co/agenticos/v1.27.0/desktop/src-tauri/icons/Square284x284Logo.png",
                  "name": "API",
                  "deploy": {
                    "startCommand": "/bin/sh -c \"printenv BOOT_SCRIPT > /tmp/boot.sh && exec sh /tmp/boot.sh\"",
                    "healthcheckPath": "/api/v1/health",
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "ghcr.io/vstorm-co/agenticos-backend:1.27.0"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": false,
                      "description": "Port the API listens on.",
                      "defaultValue": "8000"
                    },
                    "DEBUG": {
                      "isOptional": false,
                      "description": "Debug mode.",
                      "defaultValue": "false"
                    },
                    "API_KEY": {
                      "isOptional": false,
                      "description": "Key for AgenticOS's internal API.",
                      "defaultValue": "{{API_KEY}}"
                    },
                    "ORG_NAME": {
                      "isOptional": false,
                      "description": "Name of the organization created on first boot.",
                      "defaultValue": "My Organization"
                    },
                    "REDIS_HOST": {
                      "isOptional": false,
                      "description": "Redis host.",
                      "defaultValue": "${{Redis.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "SECRET_KEY": {
                      "isOptional": false,
                      "description": "Signs sessions and tokens.",
                      "defaultValue": "{{SECRET_KEY}}"
                    },
                    "ADMIN_EMAIL": {
                      "isOptional": false,
                      "description": "Email for the owner account created on first boot. You sign in with it.",
                      "defaultValue": "{{ADMIN_EMAIL}}"
                    },
                    "BOOT_SCRIPT": {
                      "isOptional": false,
                      "description": "Start-up script (migrations, first-boot setup, worker, API). Kept in a variable because Railway runs start commands without a shell file.",
                      "defaultValue": "# AgenticOS on Railway: migrations, a one-time first-boot setup, then the background\n# worker and the API in one container. Upstream runs api and worker as two compose\n# services sharing a media volume; a Railway volume attaches to one service only, so\n# both run here. Railway restarts the container, not a process, hence the worker loop.\nset -e\ncd /app\necho \"[boot] applying database migrations\"\nagenticos db upgrade\n\nMARK=/app/media/.railway-bootstrapped\nif [ ! -f \"$MARK\" ]; then\n  # Owner account (made platform admin), organization, model profile and a demo agent.\n  # Idempotent upstream, but run once so deleting the demo org later is not undone.\n  echo \"[boot] first boot: creating the owner $ADMIN_EMAIL and organization\"\n  agenticos cmd bootstrap --email \"$ADMIN_EMAIL\" --password \"$ADMIN_PASSWORD\" \\\n    --org \"${ORG_NAME:-My Organization}\" --provider \"${BOOTSTRAP_PROVIDER:-anthropic}\"\n  # Sign-up is open by default upstream; on a public URL that admits anyone. Close it\n  # to invitations, only when no sign-up setting was ever saved.\n  python - <<'PY'\nimport asyncio\nfrom app.db.session import get_db_context\nfrom app.repositories import deployment_settings_repo\n\nasync def main():\n    async with get_db_context() as db:\n        if await deployment_settings_repo.get(db) is None:\n            await deployment_settings_repo.upsert(db, update_data={\"signup_mode\": \"invite_only\"})\n            print(\"[boot] sign-up set to invite only\")\n\nasyncio.run(main())\nPY\n  touch \"$MARK\"\nfi\n\n( while true; do\n    python -m app.worker || true\n    echo \"[boot] worker stopped; restarting in 5s\"\n    sleep 5\n  done ) &\n\necho \"[boot] starting the API on :${PORT:-8000}\"\n# --host :: covers IPv6 (Railway's private network) and IPv4 (its health checker):\n# with --workers uvicorn binds the socket itself and keeps the kernel's dual-stack default.\nexec uvicorn app.main:app --host :: --port \"${PORT:-8000}\" \\\n  --workers \"${UVICORN_WORKERS:-2}\" --timeout-worker-healthcheck 60 --ws websockets-sansio\n"
                    },
                    "ENVIRONMENT": {
                      "isOptional": false,
                      "description": "Turns on AgenticOS's production checks.",
                      "defaultValue": "production"
                    },
                    "POSTGRES_DB": {
                      "isOptional": false,
                      "description": "Database name.",
                      "defaultValue": "${{Postgres.POSTGRES_DB}}"
                    },
                    "CORS_ORIGINS": {
                      "isOptional": false,
                      "description": "Browser origins allowed to call the API.",
                      "defaultValue": "[\"https://${{AgenticOS.RAILWAY_PUBLIC_DOMAIN}}\"]"
                    },
                    "FRONTEND_URL": {
                      "isOptional": false,
                      "description": "The web app's address.",
                      "defaultValue": "https://${{AgenticOS.RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "POSTGRES_HOST": {
                      "isOptional": false,
                      "description": "Database host.",
                      "defaultValue": "${{Postgres.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "POSTGRES_PORT": {
                      "isOptional": false,
                      "description": "Database port.",
                      "defaultValue": "5432"
                    },
                    "POSTGRES_USER": {
                      "isOptional": false,
                      "description": "Database user.",
                      "defaultValue": "${{Postgres.POSTGRES_USER}}"
                    },
                    "PUBLIC_WS_URL": {
                      "isOptional": false,
                      "description": "This API's websocket address.",
                      "defaultValue": "wss://${{RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "ADMIN_PASSWORD": {
                      "isOptional": false,
                      "description": "Password for the owner account, generated. Read it here after deploying; change it in AgenticOS.",
                      "defaultValue": "{{ADMIN_PASSWORD}}"
                    },
                    "PUBLIC_API_URL": {
                      "isOptional": false,
                      "description": "This API's public address.",
                      "defaultValue": "https://${{RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "REDIS_PASSWORD": {
                      "isOptional": false,
                      "description": "Redis password.",
                      "defaultValue": "${{Redis.REDIS_PASSWORD}}"
                    },
                    "PUBLIC_BASE_URL": {
                      "isOptional": false,
                      "description": "This API's public address; chat buttons (Slack, Mattermost) and OAuth callbacks come back here.",
                      "defaultValue": "https://${{RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "PUBLIC_SITE_URL": {
                      "isOptional": false,
                      "description": "The web app's address.",
                      "defaultValue": "https://${{AgenticOS.RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "RAILWAY_RUN_UID": {
                      "isOptional": false,
                      "description": "Runs as root so the API can write to the volume, which Railway mounts root-owned.",
                      "defaultValue": "0"
                    },
                    "UVICORN_WORKERS": {
                      "isOptional": false,
                      "description": "API worker processes, about 450 MB each. Upstream suggests 2 for a team of ten.",
                      "defaultValue": "2"
                    },
                    "VAULT_MASTER_KEY": {
                      "isOptional": false,
                      "description": "Encrypts stored secrets (API keys, tokens). Keep it: losing it makes them unreadable.",
                      "defaultValue": "{{VAULT_MASTER_KEY}}"
                    },
                    "BOOTSTRAP_API_KEY": {
                      "isOptional": true,
                      "description": "Optional API key for that provider, so the demo agent answers right away. You can add keys later under Settings."
                    },
                    "POSTGRES_PASSWORD": {
                      "isOptional": false,
                      "description": "Database password.",
                      "defaultValue": "${{Postgres.POSTGRES_PASSWORD}}"
                    },
                    "BOOTSTRAP_PROVIDER": {
                      "isOptional": false,
                      "description": "Model provider for the demo agent: anthropic, openai, google or openrouter.",
                      "defaultValue": "anthropic"
                    },
                    "WORKER_INGEST_CHILDREN": {
                      "isOptional": false,
                      "description": "Parallel document ingestions in the background worker.",
                      "defaultValue": "1"
                    },
                    "RATE_LIMIT_TRUST_FORWARDED_FOR": {
                      "isOptional": false,
                      "description": "Rate limits per visitor rather than per Railway proxy; safe because only Railway's proxy reaches this service.",
                      "defaultValue": "true"
                    }
                  },
                  "networking": {
                    "serviceDomains": {
                      "<hasDomain>:8000": {
                        "port": 8000
                      }
                    }
                  },
                  "volumeMounts": {
                    "a8dbd17e-ddae-4733-905b-1e3f7dcefb73": {
                      "mountPath": "/app/media"
                    }
                  }
                },
                "bd623a9f-4888-4b39-966a-b1d5fe030e24": {
                  "icon": "https://cdn.simpleicons.org/postgresql",
                  "name": "Postgres",
                  "deploy": {
                    "startCommand": "/usr/bin/tini -g -- /usr/local/bin/wrapper.sh postgres -p 5432 -c listen_addresses=* -c max_connections=200 -c max_parallel_workers_per_gather=0",
                    "restartPolicyType": "ALWAYS"
                  },
                  "source": {
                    "image": "ghcr.io/railwayapp-templates/postgres-ssl:16"
                  },
                  "variables": {
                    "PGDATA": {
                      "isOptional": false,
                      "description": "Data directory inside the volume (Railway volumes ship a lost+found at the root).",
                      "defaultValue": "/var/lib/postgresql/data/pgdata"
                    },
                    "POSTGRES_DB": {
                      "isOptional": false,
                      "description": "Database name.",
                      "defaultValue": "agenticos"
                    },
                    "POSTGRES_USER": {
                      "isOptional": false,
                      "description": "Database user.",
                      "defaultValue": "postgres"
                    },
                    "POSTGRES_PASSWORD": {
                      "isOptional": false,
                      "description": "Database password.",
                      "defaultValue": "{{POSTGRES_PASSWORD}}"
                    }
                  },
                  "volumeMounts": {
                    "3dafb63b-42ea-4c1d-b6cd-977bf4275717": {
                      "mountPath": "/var/lib/postgresql/data"
                    }
                  }
                },
                "bf2edf94-f8dd-48ca-9b38-01d1b57d35d2": {
                  "icon": "https://cdn.simpleicons.org/redis",
                  "name": "Redis",
                  "deploy": {
                    "startCommand": "/bin/sh -c \"exec docker-entrypoint.sh redis-server --requirepass $REDIS_PASSWORD --maxmemory 384mb --maxmemory-policy allkeys-lru --save ''\"",
                    "restartPolicyType": "ALWAYS"
                  },
                  "source": {
                    "image": "redis:8.2.1"
                  },
                  "variables": {
                    "REDIS_PASSWORD": {
                      "isOptional": false,
                      "description": "Redis password.",
                      "defaultValue": "{{REDIS_PASSWORD}}"
                    }
                  }
                },
                "d55e176d-0810-4fa9-a4c0-2197369ff938": {
                  "icon": "https://raw.githubusercontent.com/vstorm-co/agenticos/v1.27.0/desktop/src-tauri/icons/Square284x284Logo.png",
                  "name": "AgenticOS",
                  "deploy": {
                    "healthcheckPath": "/api/health",
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "ghcr.io/vstorm-co/agenticos-frontend:1.27.0"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": false,
                      "description": "Port the web app listens on.",
                      "defaultValue": "3000"
                    },
                    "HOSTNAME": {
                      "isOptional": false,
                      "description": "Listen on IPv6 and IPv4 (Railway's network uses both).",
                      "defaultValue": "::"
                    },
                    "NODE_ENV": {
                      "isOptional": false,
                      "description": "Node environment.",
                      "defaultValue": "production"
                    },
                    "BACKEND_URL": {
                      "isOptional": false,
                      "description": "The API over Railway's private network.",
                      "defaultValue": "http://${{API.RAILWAY_PRIVATE_DOMAIN}}:8000"
                    },
                    "PUBLIC_WS_URL": {
                      "isOptional": false,
                      "description": "The API's websocket address, used by your browser.",
                      "defaultValue": "wss://${{API.RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "PUBLIC_API_URL": {
                      "isOptional": false,
                      "description": "The API's public address, used by your browser.",
                      "defaultValue": "https://${{API.RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "OAUTH_PROVIDERS": {
                      "isOptional": false,
                      "description": "Sign-in buttons to show (google, github, ...). none until you configure an OAuth app.",
                      "defaultValue": "none"
                    },
                    "PUBLIC_SITE_URL": {
                      "isOptional": false,
                      "description": "This web app's address.",
                      "defaultValue": "https://${{RAILWAY_PUBLIC_DOMAIN}}"
                    }
                  },
                  "networking": {
                    "serviceDomains": {
                      "<hasDomain>:3000": {
                        "port": 3000
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "post_deploy": {
    "healthcheck": {
      "service": "API",
      "method": "GET",
      "path": "/api/v1/health",
      "expect_status": 200
    }
  },
  "resources": {
    "expected_services": 4,
    "needs_volume": true
  },
  "generated_at": "2026-10-28T10:14:56.332Z",
  "generator_version": "0.1.0"
}
