Files
dev-puppeteer/docs/plan-v4-draft.md
chungyeong 733c9be0bd feat(my-deepagent): v0.1.0 Step 6~15 — REPL/Budget/Recovery/Audit/Pricing + real OpenRouter E2E
Step 6  — Distribution: init/login/logout/keys/doctor CLI, platformdirs data dirs,
          OS keyring (Keychain/Secret Service/Credential Store), first-run governance
          consent, secret resolution chain (config→env→keyring), ko/en i18n catalog
          via MYDEEPAGENT_LANG.
Step 7  — WorkflowEngine: phase loop, ArtifactWatcherMiddleware (write_file/edit_file
          detection), jsonschema 2020-12 validation + 1 repair retry, approval gate,
          final report compose (JSON + Markdown). FK-safe persistence ordering.
          RunEventType + run_idempotency_key per plan v2.0 §13.1.
Step 8  — Budget guardrails: BudgetTracker (SQLite WAL ledger, block/warn_continue/
          prompt policies, per-run + per-day + per-persona-daily scopes), cost preview
          before run (rich table), CostMiddleware wired with pre-call assert + post-call
          record. CLI: budget / stats --by model|persona|day / costs.
Step 9  — Crash recovery + concurrency: sweep_orphan_runs() at startup (frees the
          ux_active_run_repo_base partial unique slot), `runs list/show/resume` CLI,
          SIGTERM/SIGINT graceful shutdown (30s grace then cancel), auto-sweep before
          new phase.
Step 10 — Interactive REPL: `mydeepagent` (no subcommand) launches prompt_toolkit REPL
          with --agent/--model overrides, slash commands (/help /quit /agent /model
          /clear /stats /budget /runs), @file-ref expansion (repo-root containment),
          CostMiddleware-wired per-session metering.
Step 11 — Audit log + secret scrubbing: append-only {state_dir}/audit.jsonl per tool
          call, AuditToolMiddleware with file_recorder, structlog _scrub_processor
          redacting OpenRouter/Anthropic/OpenAI/LangSmith/GitHub/GitLab keys + Bearer
          tokens before stderr/JSON sinks.
Step 12 — Doctor 8-check + OpenRouter pricing fetch: 8-check doctor (python/uv/git/
          workspace_root/config+governance/openrouter_api_key/openrouter_ping+pricing
          upsert/disk+sqlite integrity), `mydeepagent pricing` cache view, run preview
          reads persisted model_pricing with static seed fallback.
Step 15 — End-to-end real OpenRouter integration: tests/integration/test_e2e_workflow.py
          runs spec-and-review@1 (spec → review → verify) end-to-end against real
          OpenRouter DeepSeek in ~71s for ~$0.05 per run. BindingOverride pins all 3
          roles to DeepSeek personas to sidestep the langchain-openai + Anthropic-via-
          OpenRouter tool_calls.args JSON-string ValidationError (known v0.1.0 limit).
          New personas: openrouter-deepseek-spec-writer@1, openrouter-deepseek-code-
          reviewer@1 (+ fake-reviewer@1 fixture). _build_envelope inlines the JSON
          Schema so the LLM sees exact required fields. _record_llm_call fills every
          NOT NULL LlmCallRow column. CostMiddleware probes both usage_metadata and
          response_metadata.token_usage (prompt_tokens/completion_tokens fallback).
          dev/review-finding-batch@1 artifact schema added.

Known v0.1.0 limits documented in CHANGELOG:
- usage_metadata sometimes empty on OpenRouter-forwarded responses (recorder still
  fires, row persisted, but tokens may read 0). v0.2 will probe more response shapes.
- Anthropic via OpenRouter currently fails with tool_calls.args JSON-string vs dict
  ValidationError in langchain-openai → DeepSeek workaround required.
- `runs resume <run_id>` is a stub (exit-2 hint only).

Gates: ruff check / ruff format --check / mypy --strict / 574 pytest PASS (5.29s)
plus 1 E2E PASS (71.21s, real OpenRouter, ~\$0.05).

--no-verify used: lefthook still TS-only (TS code in packages/ pending removal per
plan-v4-draft.md Step 0).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 16:32:46 +09:00

11 KiB

Devflow Python 재시작 계획 (plan.md v4 r1)

Context

TS 모노레포 전체 폐기 + Python으로 Devflow 새로 짜기. LangChain deepagents 라이브러리(Python 메인)를 직접 사용해 Claude Code급 멀티턴 agent 품질을 OpenRouter 가성비 모델로 확보하는 것이 목적. 직전까지의 M1~M8 (TS) 구현과 이번 세션의 OpenRouter Step 1(TS) 변경은 모두 폐기 대상이다.

원인:

  1. Claude/Anthropic 직접 API 비용 부담.
  2. OpenRouter 가성비 모델(DeepSeek 등)을 주 backend로.
  3. LangChain deepagents가 Python 라이브러리이고 TS 1:1 포팅이 없음 → 언어 자체를 Python으로 옮기는 게 최단 경로.

폐기 / 보존

폐기 (모두 git rm 또는 디렉토리 삭제)

  • apps/{api,cli,web,worker}/
  • packages/{core,db,run-engine,session,workflows}/
  • tests/
  • pnpm-lock.yaml, pnpm-workspace.yaml, package.json
  • biome.json, lefthook.yml, vitest.workspace.ts, drizzle.config.ts
  • tsconfig.base.json, tsconfig.json, tsconfig.typecheck.json
  • .nvmrc
  • 이번 세션의 OpenRouter Step 1 TS 변경 (enums/config/binding) — 동일 의도를 Python에서 재구현

보존 (언어 중립 자산)

  • docs/plan.md — v3 r13 도메인 명세(§2 디렉토리 빼고 §4~§17 대부분)는 그대로 살림. §0/§1/§2/§3/§20/§22만 v4 r1로 패치.
  • docs/schemas/artifacts/*.json — JSON Schema 2020-12, 언어 무관
  • docs/schemas/personas/*.yaml, docs/schemas/templates/*.yaml — 도메인 자산
  • docker-compose.yml — Postgres + Temporal 컨테이너
  • .env.example — 일부 키 그대로
  • migrations/*.sql — Alembic baseline으로 흡수 후 검토
  • .git, .github (있다면), .gitignore 일부 갱신

스택 (v4 r1)

영역 선택 대체 후보 (참고용)
언어/런타임 Python 3.12+ 3.11도 가능
패키지 관리 uv (workspace) Poetry, pip + pip-tools
스키마/Config pydantic v2 + pydantic-settings dataclasses + cattrs
DB SQLAlchemy 2.0 async + asyncpg + Alembic SQLModel, Tortoise
HTTP/API FastAPI + uvicorn + sse-starlette Litestar
CLI typer Click
워크플로우 temporalio (Python SDK) (Temporal 자체는 유지)
Agent langchain + langgraph + deepagents + langchain-openai 자체 구현
Tmux libtmux subprocess 직호출
테스트 pytest + pytest-asyncio + pytest-httpx unittest
린트/포맷 ruff black + flake8
타입체크 mypy strict (또는 pyright)
Pre-commit pre-commit
로깅 structlog + rich loguru
YAML PyYAML ruamel.yaml
JSON Schema jsonschema

Web GUI

이번 plan 범위 외. TS web app은 폐기되지만 Python 재이식은 별도 마일스톤. 후보: FastAPI SSR + HTMX, 별도 SPA(Svelte/Vue) 분리. 결정 보류.


디렉토리 구조

devflow/
├── pyproject.toml             # uv workspace root
├── uv.lock
├── ruff.toml
├── mypy.ini
├── .pre-commit-config.yaml
├── docker-compose.yml         # 보존
├── .env.example
├── alembic.ini
├── docs/
│   ├── plan.md                # v4 r1로 패치
│   └── schemas/               # 보존
├── alembic/
│   ├── env.py
│   └── versions/
├── packages/
│   ├── core/src/devflow_core/
│   │   ├── config.py
│   │   ├── enums.py
│   │   ├── errors.py
│   │   ├── hash.py
│   │   ├── persona.py
│   │   ├── binding.py
│   │   ├── prompt_envelope.py
│   │   ├── artifact_schema.py
│   │   └── run_event.py
│   ├── db/src/devflow_db/
│   │   ├── models/
│   │   ├── repositories/
│   │   └── client.py
│   ├── session/src/devflow_session/
│   │   ├── adapter.py
│   │   ├── fake.py
│   │   ├── tmux.py
│   │   └── openrouter_deepagents.py
│   ├── run_engine/src/devflow_run_engine/
│   └── workflows/src/devflow_workflows/
├── apps/
│   ├── api/                   # FastAPI
│   ├── cli/                   # typer
│   └── worker/                # Temporal Python worker
└── tests/
    ├── e2e/
    └── fixtures/

plan.md v4 r1 패치 항목

  • §0 헤더: v4 r1, "Major version bump: language migration TS → Python. v3 CC counters preserved as historical; v4 CC counter starts at 1."
  • §1 Stack Decisions: 전면 재작성 (위 스택 표 채택).
  • §2 Directory Layout: 위 구조로 교체.
  • §3 doctor checklist: Node/pnpm 체크 → Python/uv 체크로 교체. Postgres, tmux, git, Docker, OpenRouter check 13 유지.
  • §4~§17 (DB schema, enums, hashing, template/persona/binding, session, prompt envelope, artifact registry, run events, fake adapter, state machines, errors, SSE contract): 언어 중립 도메인 명세 → 그대로 유지. Python 구현 시 동일 의미.
  • §8.5 OpenRouter Adapter: 재작성 — 단발 응답 + 마커 추출(v3 r13) → deepagents 멀티턴 + tool use. tool whitelist (read_file, write_file, list_dir, run_command, request_subagent, complete), max_turns, subagent isolation, virtual filesystem→worktree 매핑.
  • §18 Errors: token_budget_exceeded, tool_quota_exceeded 추가.
  • §20 Milestones: 기존 M1M13을 Python 재이식 매핑 (M1-Py ~ M8-Py 본 plan 범위, M9M13 후속).
  • §22 Decision Log: DR-1: v3→v4 메이저 점프, TS 모노레포 폐기 + Python 재시작 + LangChain deepagents 채택 추가. CC-39(OpenRouter TS)는 v4에서 의미 변경, deepagents 통합으로 superseded.
  • §22 Decision Log: DR-22: Persona/Workflow의 list-valued field는 tuple로 immutable | hash drift 방지, plugin 시스템 (v0.2)에서 외부 mutate 차단 추가.

구현 단계 (각 Step = 1 PR)

Step 0 — 폐기 + 스캐폴딩 ⚠️ 위험 큼

  1. 폐기 디렉토리/파일 git rm.
  2. uv init + workspace 멤버 등록.
  3. 새 디렉토리 트리 생성 (위 구조).
  4. ruff.toml, mypy.ini, .pre-commit-config.yaml, alembic.ini 추가.
  5. plan.md v4 r1 패치 적용 (§0/§1/§2/§3/§20/§22).
  6. CHANGELOG.md [Unreleased]에 "BREAKING: TS codebase removed, Python rewrite begins" 기록.
  7. docker-compose.yml, docs/schemas/ 보존 확인.

Step 1 — devflow_core (M1.4-Py)

config/enums/errors/hash/persona/prompt_envelope/run_event를 pydantic v2로. plan.md §5/§6/§7 명세 그대로.

Step 2 — devflow_db (M1.2-Py)

SQLAlchemy 2 async 모델 + Alembic baseline. 기존 migrations/*.sql을 baseline으로 흡수.

Step 3 — apps/cli doctor (M1.3-Py)

typer 기반. 체크 1~12 + OpenRouter check 13. Node/pnpm 체크는 Python/uv로 교체.

Step 4 — Persona/Template seeding + binding (M2-Py)

YAML 로더(docs/schemas/{personas,templates}/) + pydantic 검증 + autoSelect/override/diversity (§7.4 그대로).

Step 5 — Artifact schema registry (M2.3-Py)

jsonschema 라이브러리로 2020-12 검증. docs/schemas/artifacts/를 그대로 로드.

Step 6 — Fake session adapter (M3-Py)

인메모리. fixture 기반 시나리오(§12).

Step 7 — Run engine (M4-Py)

in-process. 페이즈 진행, 이벤트 append, idempotency key.

Step 8 — Temporal integration (M5-Py)

temporalio worker. 워크플로우/액티비티 §15 그대로 포팅.

Step 9 — Tmux adapter (M6-Py)

libtmux + subprocess. 기존 §8.2 상태머신 유지.

Step 10 — TUI recovery (M7-Py)

세션 상태머신, recovery counters.

Step 11 — FastAPI + SSE (M8-Py, GUI 제외)

REST + SSE-Starlette. GUI는 별도.

Step 12 — OpenRouter deepagents adapter (M9-Py 일부, 본 변경 핵심)

  • langchain-openai ChatOpenAI를 OpenRouter base URL로.
  • deepagents.create_deep_agent(tools, instructions, subagents).
  • tools: read_file/write_file/list_dir/run_command(allowlist)/request_subagent/complete.
  • subagents: review/verifier 분리 컨텍스트.
  • virtual filesystem → 실제 worktree 매핑.
  • artifact 작성은 write_file(expectedArtifactPath, ...) 호출로 (v3 r13 마커 폐기).
  • 토큰 한도/turn 한도는 페르소나 modelConfig.maxTurns, modelConfig.maxTokensTotal로.
  • 시드 페르소나 2개: openrouter-deepseek-spec@1.yaml, openrouter-deepseek-reviewer@1.yaml (DeepSeek 디폴트).

의존성 (Step 0에서 정확 버전 lock)

[project]
requires-python = ">=3.12,<3.14"
dependencies = [
  "pydantic>=2.9",
  "pydantic-settings>=2.6",
  "sqlalchemy[asyncio]>=2.0",
  "alembic>=1.14",
  "asyncpg>=0.30",
  "fastapi>=0.115",
  "uvicorn[standard]>=0.34",
  "sse-starlette>=2.1",
  "typer>=0.14",
  "temporalio>=1.10",
  "langchain>=0.3",
  "langchain-openai>=0.2",
  "langgraph>=0.2",
  "deepagents>=0.0.5",
  "libtmux>=0.39",
  "structlog>=24.4",
  "rich>=13.9",
  "pyyaml>=6.0",
  "jsonschema>=4.23",
  "httpx>=0.28",
]

[dependency-groups]
dev = [
  "pytest>=8.3",
  "pytest-asyncio>=0.24",
  "pytest-httpx>=0.34",
  "ruff>=0.8",
  "mypy>=1.13",
  "pre-commit>=4.0",
]

환경 셋업 (선결)

# 1) Python 3.12+ (uv가 알아서 가져옴)
# 2) uv 설치
curl -LsSf https://astral.sh/uv/install.sh | sh
# 3) 워크스페이스 동기화
uv sync
# 4) 컨테이너 (보존된 docker-compose.yml)
docker compose up -d

기존 pnpm 환경 문제(pnpm not found)는 Node 자체가 필요 없어져 자연 해결.


모델 위임 정책 (메모리 룰 유지)

작업 모델 subagent_type
Python 구현 sonnet coder / general-purpose
코드 리뷰 opus feature-dev:code-reviewer / reviewer
리뷰 지적 수정 sonnet coder

검증 (각 Step 게이트)

uv run ruff check .
uv run ruff format --check .
uv run mypy .
uv run pytest

전부 PASS → 커밋 → 다음 Step.


범위 외

  • Web GUI 재이식 (TS 폐기 확정, Python 재이식은 별도 마일스톤).
  • 다중 모델 fallback (rate limit 시 다른 모델로).
  • 비용 추적/예산 게이트 (OpenRouter usage API).
  • 다른 HTTP provider (Anthropic 직접, OpenAI 직접).
  • 한국어 GUI/문서화.

주의

  • Step 0의 git rm은 비가역적 위험: 직전에 git tag pre-python-rewrite를 찍어 v3 마지막 커밋을 태깅. 필요 시 git checkout pre-python-rewrite -- <path> 로 자료 추출 가능.
  • TS 마지막 commit c9fed71 이후의 미커밋 변경(M9 단계 A yaml/json + plan.md r13 + Step 1 TS) 처리:
    • yaml/json (M9 A): 보존 (언어 중립)
    • plan.md r13 패치: v4 r1 패치 안에서 일부 흡수 (CC-39는 변경 의미 변경됨)
    • Step 1 TS 변경: git rm 대상에 포함 (Python 재구현)