Files
hanarang-rails/docs/migration-guide.md
이랑이 2cadb3e0df feat(sprint-007): 마이그레이션 도구 + 운영 문서 + v0.1.0 릴리즈 준비
Sprint 007 전체 구현 — 마지막 스프린트. 프로젝트 완성:

CLI:
- rails doctor — 환경 헬스체크 (Node/pnpm/git/env/프로젝트 파일)
- rails scaffold [dir] — 신규 프로젝트 .plans/ 구조 생성
- rails migrate from-hanarang-harness <path> — 레거시 아카이브 스캐너
  agents/scripts/workflows 분류 (portable vs deprecated)
  xhigh 참조 경고 등 위험 패턴 감지

Docs (신규 3종):
- docs/migration-guide.md — 레거시 하네스 → rails 단계별 이전 가이드
- docs/operations.md — PM2, health check, 트러블슈팅, DB 유지보수
- docs/discord-setup.md — 봇 생성, DiscordPoster 구현 예시,
  marker 프로토콜 완전 명세

README 대폭 업데이트:
- v0.1.0 상태 선언
- 빠른 시작 가이드
- CLI 13 서브커맨드 목록
- 문서 링크

Tests (4 신규, 105 total pass):
- 마이그레이션 스캐너 (agents/scripts/workflows 감지)
- node_modules/.git 제외
- 빈 아카이브 처리
- scaffold 디렉토리 구조 검증

검증: tsc --noEmit ✓ | vitest 105/105 ✓ | build ✓
       rails doctor → 정상 출력 ✓
       rails --help → 13 subcommands ✓

마감 상태:
- F1~F6 모든 실패 모드 코어에서 해결
- 7 스프린트 완료 (000: 계획, 001~006: 코어, 007: 릴리즈)
- 105 테스트, 19 문서 (.plans/) + 3 운영 문서 (docs/)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:53:54 +09:00

5.5 KiB
Raw Permalink Blame History

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 install.sh --dir /path/to/hanarang-rails --repo <your-rails-repo-url>
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

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 stageagent, so you can keep role-specific personas.

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:

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

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:

// Pseudocode — plug into your agent's discord event handler
onDiscordMessage(msg) {
  if (msg.content.includes("<!-- rails:invoke v1 -->")) {
    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:

    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:

    agents:
      plan:
        transport: discord  # flip this first
      implement:
        transport: mock     # keep others on mock until plan is green
    
  3. Monitor escalations:

    rails status <pipeline-id>
    

    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:

rails abort <pipeline-id>              # 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