# Migration Guide > How to move from an existing agent pipeline (e.g., a Lobster-based `hanarang-harness` install) to `hanarang-rails`. ## Summary `hanarang-rails` replaces the legacy "권고 기반" pipeline with a **deterministic, contract-enforced** one. The migration is safe: nothing in the archive is deleted, and rails can run side-by-side until you cut over. ## Before you start - **Back up the old install.** Keep the archive read-only; don't delete it. - **Install rails on a neutral host** — ideally the same machine that holds the SSOT repository, not one of the agent workers. - **Confirm Node 22+ and pnpm are available** via `rails doctor`. ## Step 0 — Install rails ```bash bash install.sh --dir /path/to/hanarang-rails --repo cd /path/to/hanarang-rails cp .env.example .env # fill DATABASE_URL, DISCORD_TOKEN, etc. pnpm prisma migrate deploy pnpm rails doctor ``` ## Step 1 — Scan the archive ```bash rails migrate from-hanarang-harness /path/to/hanarang-harness-archive ``` This reports: - Agents (md files) — candidates to port - Scripts — portable vs deprecated (bridge.sh is deprecated) - Workflows — Lobster files are flagged as deprecated - Warnings — e.g., any `xhigh` thinking tier reference (forbidden) No files are modified. Review the report and decide. ## Step 2 — Bring over agent definitions Copy the agent markdown files you want to keep into the rails `agents/` directory. Rails does not prescribe a naming scheme; `rails.config.yaml` maps **stage** → **agent**, so you can keep role-specific personas. ```bash mkdir -p agents/ cp /path/to/archive/agents/*.md agents/ ``` Review each file and remove anything that references: - `xhigh` thinking tier (forbidden in rails — causes infinite waits) - Mention-based handoff instructions - Direct discord bot behavior (rails now posts on their behalf) ## Step 3 — Port scaffolding The legacy `scaffold.sh` is now `rails scaffold`: ```bash rails scaffold /path/to/new-project --name my-project ``` This creates `.plans/` with the standard directory structure (`design/`, `sprints/`, `migration/`) plus a root `Plans.md`. ## Step 4 — Wire `rails.config.yaml` ```yaml pipeline: stages: [plan, implement, review, deploy] agents: plan: role: plan displayName: Planner transport: discord channelId: ${PLAN_CHANNEL} timeoutMs: 30000 implement: role: implement displayName: Generator transport: discord channelId: ${IMPL_CHANNEL} timeoutMs: 60000 review: role: review displayName: Evaluator transport: discord channelId: ${REVIEW_CHANNEL} timeoutMs: 30000 deploy: role: deploy displayName: Deploy transport: local timeoutMs: 60000 discord: enabled: true railsToken: ${RAILS_DISCORD_TOKEN} guildId: ${DISCORD_GUILD_ID} pipelineChannelId: ${PIPELINE_THREAD_PARENT} ``` All secrets live in `.env`. The config file uses `${VAR}` interpolation — no token bytes in the repo. ## Step 5 — Update agent runtimes Each agent host (e.g., a sister container) needs one change to its message handler: ```js // Pseudocode — plug into your agent's discord event handler onDiscordMessage(msg) { if (msg.content.includes("")) { const req = extractJsonBlock(msg.content, "rails:invoke"); // Structured pipeline mode — LLM 우회 const result = await handleRailsInvoke(req); await postResultMarker(msg.channel, result); return; } // Otherwise: existing free-form conversation path llmRespond(msg); } ``` See `docs/discord-setup.md` for the full marker format. ## Step 6 — Cutover 1. **Smoke test with mock transport** first: ```bash rails run --mock test-project -r "hello world" rails status ``` This exercises the full FSM without touching real agents. 2. **Switch one stage at a time to discord**: ```yaml agents: plan: transport: discord # flip this first implement: transport: mock # keep others on mock until plan is green ``` 3. **Monitor escalations**: ```bash rails status ``` Any unexpected escalation triggers discord alert (if configured). 4. **Disable legacy mention-based handoff** on the old agents once all stages run through rails. ## Step 7 — Decommission legacy bridge After rails handles 100% of traffic: 1. Stop the old `bridge.sh` process(es). 2. Keep the archive as read-only reference. 3. Remove any cron jobs or systemd units that referenced the old install. ## Rollback If rails fails badly: ```bash rails abort # stop the misbehaving pipeline pm2 stop hanarang-rails # stop the orchestrator # Start the legacy bridge again if it's still present ``` The SSOT repository is untouched — both systems write to the same Gitea. ## Known limitations (v0.1.0) - **Discord bot wiring requires an operator task.** Rails ships the `DiscordTransport` class but does not auto-connect discord.js; you plug in a client via the `DiscordPoster` interface. A default implementation will ship in v0.2.0. - **Gitea webhook receiver** is scaffolded but not yet exposed as an HTTP endpoint in `rails serve` — tracked for v0.2.0. - **Manual QA checks** are stubbed (SKIPPED by default). Provide a `manualResolver` to `runQaTemplate` to wire up a reviewer LLM. ## Further reading - [`.plans/failure-audit.md`](../.plans/failure-audit.md) — why rails exists (F1–F6) - [`.plans/design/`](../.plans/design/) — architecture docs - `docs/operations.md` — day-to-day operations guide