OpenNSWM-Lab/FAROS · LICENSE 파일 없음(라이선스 미명시) · 백엔드 Python 3.11+ · FastAPI 0.109 / 프런트엔드 React 18.2 + TypeScript + Vite 5 · 현재 릴리스 1.1.0-rc1(RELEASE_PHASE=faros-llm) · 최신 커밋 044e425(2026-07-29) · 정리 기준일 2026-07-29)
FAROS(Foundation AutoResearch Operating System)는 "아이디어 구상 → 실험 → 논문 작성 → 리뷰"로 이어지는 연구 과정을 자동으로 굴리는 백엔드 런타임이다. 저장소 안에는 이미 완성된 "AI 과학자 앱" 하나가 들어있는 게 아니라, backend/app/faros 아래에 이 워크플로를 실행하는 범용 엔진이 있고, 그 위에서 첫 번째 실제 워크플로인 ml_paper 블루프린트가 돌아간다.
README는 이 릴리스를 스스로 "완성된 크로스도메인 플랫폼이 아니라, LLM 연구 도메인용 첫 실행 가능 베이스라인(FAROS-LLM)"이라고 못 박는다. 즉 지금 당장은 "논문 쓰는 AI" 한 개 용도지만, 설계 자체는 나중에 다른 연구 도메인(생물학·화학 실험 등)의 워크플로도 같은 틀에 얹을 수 있도록 층을 나눠뒀다는 것이 이 레포의 핵심 정체성이다.
실제로 백엔드는 FastAPI로 짜여 있고, idea·code·paper·review·platform이라는 기존 "도메인 모듈"들을 FAROS 런타임이 캡핑(capability adapter)으로 감싸 오케스트레이션한다. 프런트엔드는 React + Vite로 만든 대시보드형 콘솔이며, 실행 결과(연구 아이디어, 코드 프로젝트, LaTeX 논문, 리뷰 리포트)를 페이지별로 보여준다.
보통의 "AI 사이언티스트" 프로젝트는 "아이디어 내고 → 코드 짜고 → 논문 쓰고" 순서가 통째로 하나의 프로그램 안에 박혀 있는 레시피 한 장짜리 요리책과 같다. FAROS는 대신 "어떤 순서로 무엇을 하는가"(블루프린트=레시피)와 "그 단계를 실제로 누가 요리하는가"(프로필+프로바이더=요리사와 도구)를 분리한 주방 시스템을 만들었다. 오늘은 사람 요리사(사람 승인) 대신 로봇 팔(LLM)을 끼워도 되고, 내일은 완전히 다른 레시피(다른 연구 도메인 블루프린트)를 같은 주방에 올릴 수 있다.
2026년 현재 "AI가 논문까지 써주는" 자동연구 프로젝트가 여럿 등장했다. 이 흐름 속에서 FAROS가 눈에 띄는 이유는 크게 세 가지다.
README는 첫 문장부터 "FAROS is not a single hardcoded AI scientist agent"라고 선언한다. 대신 블루프린트(Blueprint)·능력(Capability)·프로필(Profile)·프로바이더(Provider)라는 4개의 독립된 개념으로 워크플로를 조립한다. 개발 문서(docs/DEVELOPER_GUIDE.md)에는 이미 블루프린트·에이전트·스킬·검증자(verifier) 4종류를 패키지 형태로 설치·검증·롤백할 수 있는 거버넌스 체계까지 설계돼 있다 — "언젠가 서드파티가 새 연구 워크플로를 패키지로 끼워 넣는" 미래를 이미 겨냥한 구조다.
워크플로 각 단계는 edges로 선후 관계만 정의돼 있고, 런타임이 매 순간 "지금 실행 가능한(ready) 단계가 뭔지"를 다시 계산한다(4장에서 코드로 확인). 이 덕분에 skip(건너뛰기)·retry(재시도)·resume(재개)·replay(특정 단계부터 하류 전체 재실행)가 전부 "그래프를 다시 굴리는" 방식으로 자연스럽게 구현된다. 단순히 "1→2→3→4"를 순서대로 부르는 스크립트가 아니라는 뜻이다.
README의 "Release Scope" 표에는 "Not Yet Included" 항목으로 전체 DAG 병렬 오케스트레이션, 비-LLM 프로바이더 생태계, 완전한 실험 실행 루프, FAROS 프런트엔드 콘솔이 명시돼 있다. docs/FAROS_TODO.md도 "지금은 experiment 단계가 진짜 실험이 아니라 스캐폴딩(뼈대) 생성 수준"이라고 스스로 적어둔다. 과대 포장 없이 "여기까지 됐고, 여기부터는 안 됐다"를 문서로 명시하는 태도가, 완성도를 부풀리는 다른 프로젝트들과 대비된다.
지금 이 레포를 열어서 얻을 수 있는 건 "논문을 잘 쓰는 AI"가 아니라, 블루프린트/프로필/능력/프로바이더로 워크플로를 분리 설계하는 법, 의존성 그래프 기반 실행·복구 상태 머신, 패키지 신뢰·호환성 거버넌스 같은 범용 오케스트레이션 설계 패턴이다.
| 영역 | 선택 | 비고 |
|---|---|---|
| 웹 프레임워크 | FastAPI 0.109.0 | backend/app/main.py가 진입점. uvicorn으로 구동, OpenAPI 문서는 /api/docs |
| 데이터 검증 | Pydantic 2.5.3 | FAROS의 Blueprint·Profile·WorkflowNode 등 런타임 모델 전부가 Pydantic BaseModel |
| DB / ORM | SQLModel(>=0.0.14) + Alembic(>=1.13) | 기존 idea·code·paper·review 모듈이 쓰는 관계형 저장소. alembic.ini와 backend/alembic/ 마이그레이션 존재 |
| LLM 연동 | LiteLLM 1.82.0 | 여러 LLM 프로바이더(README에 minimax 명시)를 통일된 인터페이스로 호출. app.llm.provider_client가 감싼다 |
| 비동기 파일 I/O | aiofiles(>=23.0.0) | FAROS 런타임은 상태·이벤트·아티팩트를 파일 기반으로 영속화(5-2절) |
| 논문 PDF 생성 | latexmk/pdflatex(외부 도구) + fpdf(폴백) | ICML·NeurIPS·ICLR·ACL 스타일 LaTeX 템플릿을 채워 컴파일. 실패 시 fpdf로 간이 PDF 폴백 |
| 차트/시각화(백엔드측) | matplotlib | 실험 결과 figure 생성용으로 requirements에 포함 |
| HTTP 클라이언트 | httpx(<0.28) | FastAPI TestClient·외부 LLM 호출 등에 사용 |
| 테스트 | pytest | backend/tests/에 스모크 테스트 3종(test_faros_smoke.py 등) |
| 영역 | 선택 | 비고 |
|---|---|---|
| UI 프레임워크 | React 18.2 + TypeScript 5.2 + Vite 5.0.8 | frontend/src/main.tsx 진입점, App.tsx가 라우팅 트리 정의 |
| 라우팅 | react-router-dom 6.21 | Research/Runs/Experiments/Papers/Review/Settings/System/Code 등 8개 이상 섹션을 lazy() 코드 스플리팅으로 로드 |
| 서버 상태 관리 | @tanstack/react-query 5.17 | main.tsx에서 staleTime 5분·재시도 1회 등으로 QueryClient 설정 |
| 대용량 표/리스트 | @tanstack/react-table 8.11 · @tanstack/react-virtual 3.0 | 실행 기록·아티팩트 목록처럼 행이 많은 화면의 가상 스크롤·정렬 |
| 그래프 시각화 | @antv/g6 5.1 (+ g6-extension-3d) | 워크플로 의존성 그래프 같은 노드-엣지 다이어그램을 그리는 데 쓰는 그래프 렌더링 라이브러리 |
| 차트 | recharts 2.10 | 실험 메트릭 대시보드용 차트 컴포넌트 |
| 스타일링 | Tailwind CSS 3.4 + class-variance-authority + tailwind-merge | shadcn/ui 계열 컴포넌트 패턴(components/ui)과 함께 쓰는 조합 |
| 아이콘 | lucide-react 0.303 | 사이드바·버튼 아이콘 |
| 테스트 | Vitest 1.1 + Testing Library + Playwright 1.40 | 단위 테스트와 E2E 테스트 둘 다 스캐폴딩돼 있음 |
| 영역 | 내용 |
|---|---|
| 배포 형태 | Dockerfile·docker-compose 없음 — README가 명시하는 배포 단위는 "백엔드 프로세스 1개 + 프런트엔드 프로세스(또는 정적 빌드) 1개 + 쓰기 가능한 데이터 디렉터리 1개 + LLM 프로바이더 설정" |
| 데이터 저장 | DB(SQLModel) + 파일 기반 FAROS 런타임 데이터(backend/data/faros 등)가 병행. FAROS 런타임 자체는 아직 "DB-backed"가 아니라고 README가 명시 |
| 설정 | 백엔드는 API_HOST/API_PORT/DATA_DIR/ACTIVE_PROVIDER_NAME, 프런트는 FRONTEND_HOST/FRONTEND_PORT/VITE_API_BASE_URL/VITE_USE_MOCK 환경변수로 제어 |
| 검증 스크립트 | scripts/check_release.sh·backend/scripts/check_backend_release.sh·frontend/scripts/check_frontend_release.sh 등 릴리스 전 점검 스크립트 다수 |
FAROS의 설계는 README의 표 하나로 요약된다. 각 층은 서로의 존재를 몰라도 되게 분리돼 있다.
| 층 | 책임 | 이 레포의 실제 파일 |
|---|---|---|
| Blueprint(블루프린트) | 워크플로 그래프·제약·출력 계약·검증 요구사항을 정의 | backend/app/faros/blueprints/ml_paper/blueprint.json |
| Capability(능력) | 아이디어 정제·실험 프로비저닝·논문 초안·리뷰 시뮬레이션 같은 실행 가능한 연구 단계 하나를 구현 | backend/app/faros/capabilities/adapters/*.py |
| Profile(프로필) | 블루프린트를 구체적 실행 전략(어떤 프로바이더·모델·메모리 정책을 쓸지)에 바인딩 | backend/app/faros/profiles/faros_llm/profile.json |
| Provider(프로바이더) | 능력 뒤에서 실제로 일하는 엔진 — LLM, 도구, 실행기, 사람 | backend/app/faros/providers/{llm,tool,execution,human}_provider.py |
실제 ml_paper 블루프린트(blueprint.json)를 보면 idea → experiment → paper → review 4단계가 edges로 순서만 정의돼 있고, 각 단계가 만들어야 할 산출물 타입(artifact_schema)과 반드시 채워야 할 출력 키(verification_rules)까지 선언돼 있다. "무엇을 해야 하는가"는 블루프린트가 정하고, "누가·어떤 모델로 하는가"는 프로필(faros_llm/profile.json)이 정한다 — 실제로 이 프로필은 4개 에이전트(researcher/experimenter/writer/reviewer) 전부를 minimax 프로바이더의 MiniMax-M2.5 모델에 바인딩해뒀다.
블루프린트는 "공연 대본"이고, 프로필은 "이번 공연의 캐스팅표"다. 대본에는 "1막에서 탐정이 단서를 찾고, 2막에서 범인을 지목한다"는 흐름만 있지, 배우가 누구인지는 안 적혀 있다. 캐스팅표(프로필)가 "탐정 역은 이 배우, 이 대역을 쓴다"를 정한다. 같은 대본(ml_paper)에 다른 캐스팅표를 끼우면 완전히 다른 배우진(다른 LLM·다른 사람 승인 단계)으로 같은 이야기를 공연할 수 있다.
FarosOrchestrator.execute_run()(backend/app/faros/runtime/orchestrator.py)의 핵심 루프는 이렇다.
이 구조에서 중요한 점 세 가지. 첫째, "다음 단계"가 하드코딩된 순서가 아니라 매 반복마다 그래프에서 다시 계산된다(graph_builder.ready_node_ids). 둘째, 각 단계 실행 결과는 능력 실행 직후 검증기(Verifier)를 반드시 통과해야 다음 단계로 넘어간다 — 예를 들어 idea_refinement는 ideaSessionId·selectedCandidateId가 실제로 채워졌는지 확인한다. 셋째, 매 단계마다 체크포인트(어떤 노드가 ready/completed/failed/skipped인지, 마지막 오퍼레이터 액션이 뭐였는지)를 기록해, 실패해도 resume·retry·replay로 정확히 어디부터 다시 시작할지 판단할 수 있게 한다.
edges로 이런 그래프를 표현하고, "화살표가 전부 해소된 노드만 실행 가능"이라는 규칙으로 실행 순서를 스스로 계산한다. 다만 README가 스스로 밝히듯 지금은 "완전한 DAG 스케줄링·병렬 오케스트레이션"까지는 아니고, 매번 준비된 노드 중 하나씩 순차 실행하는 단계다.오케스트레이터가 노출하는 복구 동작은 성격이 각각 다르다. 실제 메서드 시그니처 기준으로 정리하면:
| 동작 | 대상 상태 | 효과 |
|---|---|---|
skip_step | completed/running이 아닌 스텝 | 해당 노드를 skipped로 표시하고 그 자리에서 흐름을 이어간다(재실행 없음) |
retry_step | failed/blocked/skipped | 스텝을 pending으로 되돌리고 retry_count를 증가시켜 다시 실행 대상에 포함 |
resume_run | run 전체(완료 아님) | failed 상태였던 스텝들을 ready로 되돌리고 execute_run을 다시 호출 |
replay_step | completed/failed/skipped | 지정한 노드 + (옵션으로) 그 하류 전체를 pending으로 되돌려 처음부터 다시 계산 |
replay_step이 특히 흥미로운데, include_downstream=True면 _downstream_node_ids()가 의존성 맵을 스택으로 순회해 영향받는 모든 하류 노드를 함께 되돌린다. "논문 단계에서 사용한 실험 결과가 잘못됐다"를 뒤늦게 알았을 때, experiment부터 그 하류인 paper·review까지 한 번에 무효화하고 다시 굴릴 수 있는 이유가 이것이다.
각 능력 실행 결과는 VerifierDispatcher.verify()를 통과해야 한다. 검증 정책은 프로필 전역 정책 + 블루프린트의 노드별 규칙(verification_rules) + 노드 자체의 verifier 필드가 합쳐져 결정된다(_verification_policy_for_node). 즉 "이 논문 작성 단계는 최소한 paperId와 paperStatus를 반드시 반환해야 한다" 같은 계약이 블루프린트 JSON 안에 선언적으로 박혀 있다.
단계 사이에 넘겨주는 데이터는 ResearchMemory가 관리한다. 프로필의 memory_policy(faros_llm/profile.json)를 보면 summary_keys(항상 요약에 남길 핵심 키), volatile_prefixes(tmp_/draft_/scratch_로 시작하면 휘발성 취급), max_history_entries(히스토리 32개 제한), compaction_mode(summary_only) 같은 설정으로 메모리가 무한정 커지지 않고 압축(compaction)되도록 명시적으로 정책화돼 있다.
docs/DEVELOPER_GUIDE.md에 따르면 FAROS는 이미 4종류 패키지(blueprint/agent/skill/verifier)에 대해 validate·install·refresh·uninstall·rollback·audit·trust·compatibility API를 갖추고 있다(backend/app/faros/registry/package_trust.py, package_compatibility.py, package_lifecycle.py). 이는 "지금 당장 서드파티 마켓플레이스가 있다"는 뜻이 아니라, 나중에 커뮤니티가 새 연구 도메인 블루프린트나 검증자를 패키지로 배포할 수 있도록 미리 신뢰·버전 호환성·롤백 체계를 설계해둔 것이다. 개발 가이드는 이 영역에 "신뢰할 수 없는 파이썬 코드를 동적 실행하는 설계는 릴리스 브랜치에 넣지 않는다"는 안전 원칙도 명시해뒀다.
README의 "Not Yet Included"와 FAROS_TODO.md를 그대로 옮기면, 이번 릴리스는 ① 완전한 DAG 병렬 오케스트레이션, ② 일반화된 비-LLM 프로바이더 생태계, ③ 완전한 실험 실행·평가 루프, ④ FAROS 전용 프런트엔드 콘솔, ⑤ DB 기반 FAROS 런타임 메타데이터를 아직 포함하지 않는다. 특히 experiment 능력은 실제로 코드를 작성·실행하는 게 아니라 프로젝트 스캐폴드(뼈대 파일)를 생성하는 수준이다(6장·9장에서 코드로 확인).
저장소 최상위는 README에 그려진 그대로다. 실제로 클론해 find로 전수 확인한 파일 수 기준이다.
backend/backend/라는 중첩 폴더가 실제로 존재한다클론해서 열어보면 backend/ 바로 아래에 또 backend/backend/data/ideas/candidates/*.json 같은 파일 586개가 들어있다. 이건 설계된 구조가 아니라, 백엔드를 실행할 때 상대 경로 기준으로 backend/data를 만들어야 할 스크립트가 잘못된 작업 디렉터리에서 실행돼 backend/backend/data를 또 만들어버린 흔적으로 보인다. .gitignore에 data/가 빠져 있어 이 실수가 그대로 커밋됐다. 레포를 처음 여는 사람은 "구조가 원래 이런가?"하고 헷갈리기 쉬운데, 정식 소스는 backend/app/ 하나뿐이고 backend/data·backend/backend는 전부 런타임 산출물(아이디어 후보 JSON, 코드 프로젝트, 논문 파일 등)이라고 이해하면 된다.
backend/data/(정상 위치) 아래에는 code_projects/(실제 51개 프로젝트 폴더), experiments/, faros/(FAROS 런타임 상태·이벤트·아티팩트 파일), papers/, reviews/가 들어있다. 이건 FAROS가 실제로 여러 번 실행되며 만든 실제 산출물이라, 코드를 읽을 때 "이 데이터가 어떤 모양으로 남는지" 살아있는 예시로 참고할 수 있다는 장점도 있다.
experiment 능력이 만드는 code_projects/는 실제로 실험을 실행하는 코드가 아니라 README.md·src/main.py·tests/test_smoke.py 같은 뼈대 파일들이다.
Blueprint(backend/app/faros/models/blueprint.py)와 Profile(models/profile.py)을 나란히 읽어보면, Pydantic 모델 하나로 "이 워크플로가 지켜야 할 계약"을 완전히 표현하는 법을 배울 수 있다. WorkflowNode는 능력 ID·에이전트·스킬·출력 키만 갖고, 실제 실행 엔진(프로바이더)은 전혀 모른다. 이렇게 "정의"와 "실행"을 분리하면 같은 블루프린트를 테스트 환경(모의 프로바이더)과 운영 환경(실제 LLM)에 그대로 재사용할 수 있다 — 의존성 주입(Dependency Injection) 패턴을 워크플로 레벨로 확장한 사례로 볼 수 있다.
backend/app/main.py는 의도적으로 짧게 유지된다("This file stays intentionally small"). 실제 기능은 전부 app.modules.*와 app.faros.api.faros_api의 router를 app.include_router(..., prefix=...)로 조립하는 식으로 들어온다. 메인 파일은 배선(wiring)만 하고, 비즈니스 로직은 각 모듈에 둔다는 원칙을 실제 프로덕션급 FastAPI 앱에서 어떻게 지키는지 볼 수 있다.
// backend/app/main.py — 라우터 조립부 (요지)
app.include_router(platform_router, prefix="/api/v1")
app.include_router(idea_router, prefix="/api/v1")
app.include_router(code_router, prefix="/api/v1")
app.include_router(paper_router, prefix="/api/v1")
app.include_router(review_router, prefix="/api/v1")
app.include_router(faros_router, prefix="/api") // 신규 FAROS 계층은 별도 prefix
실전 팁으로 옮기면: 기존 /api/v1/*(레거시 호환 계층)와 새 /api/faros/*(FAROS 런타임 계층)를 같은 앱 안에서 병존시키면서 신규 개발은 후자에만 집중시키는 방식이다. 개발 가이드에도 "새 플랫폼 능력은 api/v1에 다시 쌓지 말라"는 규칙이 명시돼 있다.
GraphBuilder.dependency_map()·ready_node_ids()·refresh_step_statuses()(runtime/graph_builder.py)는 각각 40줄 안팎의 순수 파이썬 함수다. 그래프 이론에서 배우는 위상 정렬(topological sort)의 축소판을 실전 코드로 볼 좋은 예제다 — "업스트림 전부 완료(completed/skipped)면 ready, 하나라도 failed면 blocked" 같은 규칙이 딕셔너리 순회 몇 줄로 구현돼 있다. 알고리즘 수업에서 배운 개념이 실제 프로덕션 오케스트레이터에서 어떤 모습인지 보여주는 좋은 사례다.
VerifierDispatcher.verify()(verification/rules.py)와 블루프린트의 verification_rules를 같이 읽으면, "검증 로직을 코드에 if문으로 흩뿌리지 않고 데이터(JSON 규칙)로 선언한다"는 패턴을 배울 수 있다. 새 검증 규칙을 추가할 때 파이썬 코드를 고칠 필요 없이 블루프린트 JSON의 verification_rules 배열에 항목 하나만 추가하면 되는 구조다.
frontend/src/App.tsx는 20개 이상의 페이지를 전부 lazy(() => import(...))로 불러온다. 이렇게 하면 사용자가 /papers를 클릭하기 전까지 PaperEditor 관련 JS 번들이 아예 다운로드되지 않는다 — 초기 로딩 속도를 지키면서 페이지 수를 무한히 늘릴 수 있는 실전 패턴이다. Suspense + 공용 PageLoader 컴포넌트로 로딩 상태를 한곳에서 처리하는 구조도 함께 눈여겨볼 만하다.
backend/templates/latex/{icml,neurips,iclr,acl,generic}/에 실제 학회별 LaTeX 템플릿이 들어있고, templates.json이 이들을 매핑한다. README에 따르면 latexmk 컴파일을 우선 시도하고, 실패하면 fpdf로 "미리보기 가능한 대체 PDF"를 만든다. 외부 도구(LaTeX 배포판) 의존을 깨끗하게 폴백 처리하는 법을 실전 예시로 볼 수 있다.
| 항목 | 요구사항 |
|---|---|
| Python | 3.11 이상 또는 3.12(README 명시). 개발 시 conda 환경 aist 사용 언급 |
| Node.js | 18 이상(package.json의 engines.node = >=18.0.0) |
| LaTeX 도구체인 | latexmk + pdflatex — 학회 스타일 PDF를 실제로 조판하려면 필요. 없으면 fpdf 폴백 PDF로 대체됨 |
| LLM 프로바이더 설정 | 실제 LLM 백엔드 실행 워크플로(idea_refinement·paper_drafting·reviewer_simulation)를 진짜로 돌리려면 ACTIVE_PROVIDER_NAME 등 프로바이더 키 설정 필요. /api/system/version의 llm.configured가 true일 때만 "준비됨" |
| GPU | 불필요 — FAROS 자체는 오케스트레이션·검증·저장만 담당하고, 실제 텍스트 생성은 외부 LLM API 호출(litellm)로 위임한다. 로컬에서 모델을 직접 추론하지 않는다 |
| 디스크 | 런타임이 코드 프로젝트·LaTeX 산출물·PDF·이벤트 로그를 전부 파일로 쌓기 때문에(backend/data/) 반복 실행할수록 디스크 사용량이 누적된다. 실제로 이 레포 자체에 이미 693개 파일 분량의 누적 데이터가 커밋돼 있다 |
| 포트 | 백엔드 기본 8005, 프런트엔드 기본 5173대(Vite 기본값). CORS 허용 목록에 localhost:5173~5176·3000이 하드코딩돼 있다 |
FAROS는 로컬 GPU도, 대용량 모델 다운로드도 요구하지 않는다. LLM 계정(API 키) 하나만 있으면 노트북에서도 전체 워크플로(idea → experiment → paper → review)를 끝까지 돌려볼 수 있다. 다만 plan 모드(계획만 세우고 실제 실행은 안 함)로 먼저 시도해보면 API 키 없이도 오케스트레이션 로직 자체는 확인할 수 있다.
README의 "Example: Plan-Only Run" 그대로 백엔드를 띄우고 POST /api/faros/runs에 executionMode: "plan"으로 요청을 보낸다. 그 다음 GET /api/faros/runs/{run_id}로 응답을 열어, steps 배열의 각 노드가 ready→blocked로 어떻게 나뉘는지 직접 확인해본다. LLM API 키 없이도 그래프 계산 로직만으로 여기까지는 확인할 수 있다.
blueprint.json의 verification_rules에 새 항목을 하나 추가해(예: experiment 단계에 experimentStatus 키를 필수로 요구) 실제로 검증이 통과/실패하는 게 바뀌는지 관찰한다. Blueprint Pydantic 모델(models/blueprint.py)의 어떤 필드가 이 값을 받는지부터 추적해보면 "선언적 검증"의 흐름 전체를 손으로 따라갈 수 있다.
graph_builder.py에 새 스케줄링 정책 추가현재 ready_node_ids()는 fifo/reverse/wave 세 가지 정책만 지원한다. 여기에 "가장 적은 업스트림을 가진 노드부터"같은 새 정책(예: shortest-path)을 추가하고, _normalize_runtime_options()가 이 값을 검증하도록 고쳐본다. 오케스트레이터 코드를 건드리지 않고 그래프 빌더만 확장하는 게 핵심 제약이다.
replay_step의 하류 전파를 시각화하기임의의 완료된 run에 대해 중간 노드 하나를 replay_step(include_downstream=True)로 리플레이시킨 뒤, _downstream_node_ids()가 실제로 어떤 노드 집합을 되돌리는지 로그로 찍어본다. 이걸 @antv/g6(프런트엔드에 이미 설치돼 있음)로 그래프 다이어그램에 "영향받는 노드"를 색칠해 보여주는 미니 시각화 페이지를 만들어보면, 그래프 순회 알고리즘과 프런트엔드 시각화를 한 번에 연습할 수 있다.
experiment 능력을 "진짜 실행"으로 확장FAROS_TODO.md가 최우선 과제로 꼽는 것 그대로다. 현재 ExperimentCapability는 src/main.py·tests/test_smoke.py 같은 정적 스캐폴드 파일만 만든다. 이걸 실제로 scripts/run.sh를 서브프로세스로 실행하고, 표준출력을 파싱해 metrics 아티팩트로 등록하도록 확장해본다. CapabilityResult.artifacts에 새 아티팩트 타입(예: experiment_metrics)을 추가하고 블루프린트의 artifact_schema도 함께 갱신해야 한다는 점에서, 이 레포의 "능력-블루프린트-검증"이 어떻게 삼각으로 맞물리는지 가장 깊이 이해하게 되는 과제다.
DAG(방향성 비순환 그래프)와 위상 정렬 개념을 복습한 뒤, graph_builder.py의 dependency_map()·ready_node_ids()·refresh_step_statuses()를 손으로 따라 그려본다. Airflow·Prefect·Temporal 같은 범용 워크플로 엔진의 "노드=태스크, 엣지=의존성" 개념이 FAROS와 어떻게 닮고 다른지 비교 정리해본다.
backend/app/main.py의 라우터 조립 방식, app.faros.models.*의 Pydantic 모델 설계, SQLModel+Alembic 마이그레이션 구조를 따라가며 "작은 진입점 + 모듈별 라우터 + 공용 스키마"라는 실전 패턴을 자기 프로젝트에 옮겨본다. FastAPI 공식 튜토리얼의 "Bigger Applications" 섹션과 나란히 보면 이해가 빠르다.
App.tsx의 lazy 라우팅, @tanstack/react-query를 이용한 서버 상태 관리, @tanstack/react-table/react-virtual로 대량 데이터를 렌더링하는 법을 프런트엔드 소스에서 직접 읽는다. 이어서 @antv/g6 공식 예제로 노드-엣지 그래프 시각화를 따로 연습해, FAROS의 워크플로 그래프를 실제로 화면에 그려보는 미니 프로젝트를 만든다.
docs/DEVELOPER_GUIDE.md·docs/FAROS_TODO.md를 정독하며 "기반 계층에 쓸 것"과 "도메인 모듈에 쓸 것"의 경계를 이해한다. 그 다음 ml_paper가 아닌 완전히 새로운 3~4단계짜리 블루프린트(예: 데이터 정제 → 분석 → 리포트 작성)를 JSON으로 설계하고, 새 능력(Capability) 어댑터와 최소한의 검증 규칙을 붙여 실제로 오케스트레이터가 굴리게 만들어본다. 이 레포에서 가장 깊은 배움은 여기서 나온다 — "이미 있는 워크플로를 고치는" 게 아니라 "이 런타임 위에 새 워크플로를 얹는" 경험이다.
ml_paper(idea→experiment→paper→review)다.backend/app/faros/capabilities/adapters/에 4종류(idea_refinement, experiment, paper_drafting, reviewer_simulation)가 구현돼 있다.capability_bindings), 메모리를 어떻게 압축할지(memory_policy) 등을 정의한다.llm(언어모델)·tool(도구)·execution(실행기)·human(사람 승인) 네 종류를 구분해서 관리한다.verification_rules 배열로 선언한다.experiment 능력이 만드는 코드 프로젝트는 실행 가능한 실험이 아니라 README.md·src/main.py 같은 뼈대 파일 모음이다.