# NomadCode

NomadCode는 AI 기반 개발 작업을 제품 흐름으로 운영하기 위한 원레포입니다. Go 기반 core 서비스, Flutter 앱, 공유 계약 공간, 그리고 AI 에이전트 작업 규칙과 로드맵을 한 작업 흐름으로 묶습니다.

NomadCode는 IOP를 사용하는 개발 워크플로우 셸입니다. 사용자와 외부 provider 요청을 개발 작업으로 구조화하고, project/session/workspace 상태와 실행 결과를 사용자에게 보여줍니다. 모델 런타임, 모델 라우팅, RAG, MCP 정책, output validation 엔진은 NomadCode가 직접 소유하지 않고 IOP 책임으로 둡니다.

## 현재 상태

- `services/core`는 health/readiness endpoint, task API, PostgreSQL persistence, goose migration, sqlc query 생성 구조, River job, IOP OpenAI-compatible Responses client 경로, 향후 A2A agent delegation scaffolding, Plane/Jira adapter, Mattermost REST post adapter를 포함합니다.
- `apps/client`는 NomadCode 제품 UI의 기준 Flutter 앱이며 모바일/데스크톱/선택적 web target, Firebase Messaging, local notifications, HTTP client 의존성을 포함합니다. 현재 top titlebar, 우측 activity rail, 우측 Agent dock panel을 가진 workbench shell scaffold가 들어가 있고, Agent dock은 공통 `agent_shell` package를 사용합니다. IOP는 우측 rail 하단 아이콘으로 분리되어 있으며, IOP package/widget이 없을 때도 빌드가 깨지지 않는 선택적 `iopContent` slot으로 조립합니다.
- `apps/web`은 이전 React/Vite 운영 콘솔 scaffold였으며, Flutter-first 통합에 따라 완전히 폐기 및 제거되었습니다.
- `packages/contracts`는 향후 OpenAPI, protobuf, generated client, fixture, compatibility asset을 담을 공유 계약 공간입니다.
- 활성 계획과 Milestone 상태는 `agent-roadmap/`에서 관리합니다. README에는 현재 작업 상태를 복사하지 않고 진입 문서만 연결합니다.

## 제품 경계

NomadCode는 제품과 워크플로우 계층을 소유합니다.

- agent chat, project workspace 관리, task queue 상태, 실행 상태 표시
- Plane/Jira 스타일 work item intake, provider projection, comment, status update
- 사용자에게 노출되는 file change, diff, branch, commit, PR 흐름
- 모바일/데스크톱/선택적 web target의 Flutter project management surface
- top titlebar, 우측 activity rail, 중앙 content 전환, 우측 Agent dock, 하단 IOP section slot으로 구성되는 workbench shell
- IOP 관리 page/tab에 외부 IOP console package 또는 widget을 선택적으로 mount하는 제품 조립 경계
- IOP OpenAI-compatible 호출에 넘길 task/workspace/session metadata 구성

IOP는 실행과 최적화 계층을 소유합니다.

- OpenAI-compatible model call, 현재 NomadCode 통합 목표인 Responses API 지원
- local/cloud model routing, model profile, runtime selection, usage log, quality signal
- OpenCode, Aider, Claude Code, Gemini CLI, Codex CLI 같은 CLI agent/runtime adapter
- RAG, context compression, MCP/tool policy, output validation, retry/fallback, token/speed/quality optimization

NomadCode는 IOP가 제공하는 외부 표면을 통해 IOP를 호출합니다. 현재 기본 경로는 IOP의 OpenAI-compatible Responses API입니다. NomadCode는 OpenAI-compatible request/response shape를 기본 계약으로 채택하고, NomadCode/IOP 고유의 task, workspace, session, approval, artifact, notification 문맥은 별도 `iop` wrapper field가 아니라 `metadata` 확장으로 전달합니다. A2A는 향후 외부 agent delegation 작업을 위한 표면이며, IOP native protocol은 NomadCode의 기본 외부 호출 경로가 아닙니다.

## 빠른 시작

사용하는 workspace 영역에 필요한 runtime만 설치하면 됩니다.

```bash
# 사용 가능한 service/app 개발 entrypoint 확인
bin/dev

# 설치된 toolchain 기준으로 workspace 검증
bin/test
bin/lint
bin/build
```

Core service를 로컬에서 실행합니다. 스크립트는 local 기본값을 제공하지만, PostgreSQL과 Redis가 접근 가능해야 합니다. 현재 `code-server` database setup 관련 메모는 `services/core/README.md`를 확인합니다.

```bash
cd services/core
./bin/migrate-up
./bin/run
```

Flutter 앱을 실행합니다.

```bash
cd apps/client
flutter pub get
flutter run
```

## 주요 명령

| 목적 | 명령 | 비고 |
|------|------|------|
| 개발 entrypoint 확인 | `bin/dev` | core와 Flutter app 실행 명령을 출력합니다. |
| workspace 테스트 | `bin/test` | `go test ./...`, `flutter test`를 실행하고 없는 toolchain은 건너뜁니다. |
| workspace lint | `bin/lint` | `go vet ./...`, `flutter analyze --no-fatal-infos`를 실행하고 없는 toolchain은 건너뜁니다. |
| workspace build | `bin/build` | core `go build ./...`, Flutter web build를 실행하고 없는 toolchain은 건너뜁니다. |
| core 실행 | `cd services/core && ./bin/run` | 스크립트 기본값을 사용하며 env로 override할 수 있습니다. |
| core DB migration | `cd services/core && ./bin/migrate-up` | goose로 PostgreSQL migration을 적용합니다. |
| core 테스트 | `cd services/core && ./bin/test` | `go test ./...` wrapper입니다. |
| core build | `cd services/core && ./bin/build` | 기본 출력 경로는 `.build/nomadcode-core`입니다. |
| client 테스트 | `cd apps/client && flutter test` | Flutter test suite입니다. |

## 포트와 endpoint 표준

현재 runtime 기본값은 기존 local 개발 흐름을 깨지 않도록 유지하고, workspace/remote runner에서 외부로 노출하는 포트만 공통 대역으로 정렬합니다.

| 표면 | 현재 compatibility baseline | workspace 기준 | 비고 |
|------|-----------------------------|----------------|------|
| Flutter web/code-server preview | local smoke에서 빈 포트를 고르고 `/proxy/<port>/` base href를 사용합니다. 기존 예시는 `8081`입니다. | remote local profile은 `13010`, remote dev profile은 `13011`입니다. 병렬 임시 preview는 이후 빈 포트를 고릅니다. | code-server가 proxy prefix를 유지하거나 제거해도 정적 리소스가 열려야 합니다. |
| code-server workspace entry | client mock workspace URL은 `http://localhost:8080/?folder=...`를 사용합니다. | 유지 | 이 값은 code-server entry URL 호환성이고 Flutter preview 포트가 아닙니다. |
| Core HTTP/API | process/container 내부 기본값은 `HTTP_ADDR=:8080`, Docker `EXPOSE 8080`, local curl 예시는 `localhost:8080`입니다. | remote local profile은 `18010:8080`, remote dev profile은 `18011:8080`입니다. | 기존 `8080` local default는 migration compatibility로 유지하고, compose에서 필요하면 `NOMADCODE_CORE_HOST_PORT=8080`으로 되돌립니다. |
| PostgreSQL | compose와 local script는 `code-server-postgres:5432` service DNS를 사용합니다. | host 노출이 꼭 필요하면 local `15410:5432`, dev `15411:5432`를 후보로 둡니다. | 기본은 service DNS이며 host publish를 추가하지 않습니다. |
| Redis | compose와 local script는 `code-server-redis:6379` service DNS를 사용합니다. | host 노출이 꼭 필요하면 local `16310:6379`, dev `16311:6379`를 후보로 둡니다. | 기본은 service DNS이며 host publish를 추가하지 않습니다. |
| IOP Edge / provider endpoints | `MODEL_*`, `A2A_*`, `PROTO_SOCKET_*`, `PLANE_*`, `JIRA_*`, `MATTERMOST_*` env로 분리합니다. | public port를 예약하지 않고 각 provider endpoint를 env로 주입합니다. | token, password, API key 원문은 tracked 문서에 쓰지 않고 ignored local env/secret 파일에서만 관리합니다. |

## 구조

| 경로 | 역할 |
|------|------|
| `services/core/` | Go backend. orchestration, persistence, scheduling, HTTP API, 외부 service adapter를 담당합니다. |
| `apps/client/` | Flutter 기반 제품 UI source of truth, workbench shell, 우측 Agent dock, 모바일/데스크톱/선택적 web 클라이언트와 notification 연동 표면입니다. |
| `apps/web/` | [Legacy/Retired] React/Vite 운영 콘솔 scaffold입니다. Flutter-first 클라이언트 통합에 따라 완전히 폐기 및 제거되었습니다. |
| `packages/contracts/` | 서비스와 클라이언트가 공유할 API/schema 계약 공간입니다. |
| `docs/` | 아키텍처와 운영 문서입니다. |
| `bin/` | root test, lint, build, dev helper 명령입니다. |
| `agent-ops/` | AI 에이전트 규칙, 도메인 라우팅, 로드맵, 반복 작업 skill입니다. |
| `agent-test/local/` | local 테스트 profile과 runner별 검증 규칙입니다. |

## 작업 맥락

AI 에이전트는 파일을 변경하기 전에 루트 지침과 프로젝트 규칙을 먼저 확인합니다.

- `AGENTS.md`
- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/private/rules.md`가 있으면 해당 파일

README 같은 workspace-level 파일을 다룰 때는 아래 문서를 함께 확인합니다.

- `agent-ops/rules/project/domain/workspace-ops/rules.md`
- `agent-ops/skills/common/create-readme/SKILL.md`
- `agent-roadmap/current.md`

로드맵 상세 상태는 `agent-roadmap/`에, 도메인별 세부 규칙은 `agent-ops/rules/project/domain/`에 둡니다. 사용자가 명시적으로 요청하지 않는 한 `agent-task/archive/**`와 `agent-roadmap/archive/**`는 읽지 않습니다.

IOP 경계가 걸린 작업은 같은 workspace에 sibling IOP repository가 있을 때 함께 확인합니다. NomadCode roadmap은 제품/워크플로우 범위의 기준 문서이고, IOP roadmap은 실행/runtime 범위의 기준 문서입니다.

`agent_shell`은 제품 표면이 아니라 공통 chat/agent shell package입니다. NomadCode는 이 package를 우측 Agent dock UI에 사용하고, IOP 자체 기능은 NomadCode 코드에 직접 복제하지 않고 별도 IOP console package/widget 경계로 조립하는 방향을 유지합니다.

## 개발 흐름

- 전체 workspace 작업은 가능한 한 root `bin/test`, `bin/lint`, `bin/build`, `bin/dev` entrypoint를 우선 사용합니다.
- 변경은 소유 도메인 규칙 범위에 맞춰 좁게 유지합니다.
- contract, service, client 경계가 함께 움직이는 변경은 같은 브랜치에서 닫습니다.
- core DB 변경은 `services/core/migrations/`와 `services/core/queries/`를 기준으로 반영하고, `services/core/internal/db/`의 생성 파일은 직접 수정하지 않습니다.
- `agent-ops/rules/common/**`와 `agent-ops/skills/common/**`는 framework 동기화 영역입니다. 프로젝트 특화 규칙은 `agent-ops/rules/project/**`에 둡니다.

## 환경 변수

| Runtime | 이름 | 필수 | 설명 |
|------|------|------|------|
| Core | `DATABASE_URL` | 스크립트 사용 시 선택 | Core script는 local 기본값을 제공합니다. 다른 PostgreSQL을 쓰거나 binary를 직접 실행할 때 설정합니다. |
| Core | `REDIS_URL`, `REDIS_KEY_PREFIX` | 스크립트 사용 시 선택 | worker/queue 상태에 사용할 Redis 주소와 key prefix입니다. |
| Core | `AUTH_USERNAME`, `AUTH_PASSWORD` | 선택 | `AUTH_PASSWORD`를 설정하면 `/readyz`와 `/api/*`에 HTTP Basic Auth가 적용됩니다. |
| Core | `NOMADCODE_CORE_HOST_PORT` | 선택 | Docker Compose host publish 포트입니다. remote local 기본값은 `18010`, remote dev 기준은 `18011`이고 container 내부는 `8080`입니다. |
| Core | `MODEL_BASE_URL`, `MODEL_API_KEY`, `MODEL_NAME`, `MODEL_CONTEXT_SIZE`, `MODEL_TIMEOUT_SEC` | 선택 | worker execution에서 사용할 IOP Edge OpenAI-compatible Responses endpoint 설정입니다. IOP/NomadCode 전용 실행 문맥은 요청 `metadata`로 전달하는 방향을 기준으로 합니다. |
| Core | `A2A_EDGE_URL`, `A2A_AGENT_URL`, `A2A_TOKEN`, `A2A_TIMEOUT_SEC` | 선택 | 향후 A2A-compatible agent delegation 경로 설정입니다. 현재 기본 실행 경로는 아닙니다. |
| Core/Client | `PROTO_SOCKET_PATH`, `PROTO_SOCKET_HEARTBEAT_INTERVAL_SEC`, `PROTO_SOCKET_HEARTBEAT_WAIT_SEC`, `PROTO_SOCKET_HOST`, `PROTO_SOCKET_PORT`, `PROTO_SOCKET_SECURE`, `PROTO_SOCKET_ENABLED`, `PROTO_SOCKET_HEARTBEAT_INTERVAL_SECONDS`, `PROTO_SOCKET_HEARTBEAT_WAIT_SECONDS` | 선택 | Core proto-socket endpoint와 Flutter client connector 설정입니다. Client는 host가 없으면 연결을 비활성화합니다. |
| Core | `WORKFLOW_TASK_TIMEOUT_SEC` | 선택 | workflow task timeout 기본값을 조정합니다. |
| Core | `MATTERMOST_BASE_URL`, `MATTERMOST_TOKEN`, `MATTERMOST_CHANNEL_ID` | 선택 | Mattermost task completion message 발송용 설정입니다. token 값은 문서에 기록하지 않습니다. |
| Core | `PLANE_BASE_URL`, `PLANE_TOKEN` | 선택 | Plane work item 조회, comment, state update 연동용 설정입니다. token 값은 문서에 기록하지 않습니다. |
| Core | `GITO_WEBHOOK_SECRET`, `GITO_REPO_ID`, `GITO_DEVELOP_REPO_PATH`, `GITO_BRANCH`, `GITO_REMOTE_NAME`, `ROADMAP_CREATION_TODO_STATE_ID`, `PLANE_TODO_STATE_ID`, `GITO_PROTO_SOCKET_URL` | 선택 | Gito signed HTTP webhook `branch.updated` consumer 설정입니다. signing secret, repo id, local develop checkout, Todo state id가 모두 있을 때 HTTP consumer가 켜집니다. Gito local `18060`은 NomadCode local `18010`으로, Gito dev `18061`은 NomadCode dev `18011`로 delivery합니다. `GITO_PROTO_SOCKET_URL`은 이전 proto-socket 호환 경로가 필요할 때만 설정합니다. `ROADMAP_CREATION_TODO_STATE_ID`가 `PLANE_TODO_STATE_ID`보다 우선합니다. |
| Core | `JIRA_BASE_URL`, `JIRA_EMAIL`, `JIRA_API_TOKEN` | 선택 | Jira issue 조회, comment, status transition 연동용 설정입니다. Jira Cloud Basic auth(`Email:APIToken`) 형식을 사용합니다. |

## 참고 문서

- `services/core/README.md`
- `apps/client/README.md`
- `packages/contracts/README.md`
- `agent-roadmap/current.md`
