nomadcode/services/core
2026-05-23 11:45:50 +09:00
..
bin update plane integration and core http handlers 2026-05-23 11:45:50 +09:00
cmd update plane integration and core http handlers 2026-05-23 11:45:50 +09:00
internal update plane integration and core http handlers 2026-05-23 11:45:50 +09:00
migrations feat: plane integration and workflow updates 2026-05-22 13:37:47 +09:00
queries feat: plane integration and workflow updates 2026-05-22 13:37:47 +09:00
.gitignore chore: import nomadcode-core into services/core 2026-05-21 13:35:20 +09:00
docker-compose.yml feat: plane integration and workflow updates 2026-05-22 13:37:47 +09:00
Dockerfile chore: import nomadcode-core into services/core 2026-05-21 13:35:20 +09:00
go.mod chore: import nomadcode-core into services/core 2026-05-21 13:35:20 +09:00
go.sum chore: import nomadcode-core into services/core 2026-05-21 13:35:20 +09:00
goose.env.example chore: import nomadcode-core into services/core 2026-05-21 13:35:20 +09:00
Makefile chore: import nomadcode-core into services/core 2026-05-21 13:35:20 +09:00
README.md update plane integration and core http handlers 2026-05-23 11:45:50 +09:00
sqlc.yaml chore: import nomadcode-core into services/core 2026-05-21 13:35:20 +09:00

NomadCode Core

NomadCode Core는 사용자 요청을 작업 단위로 받고, 작업 상태를 저장하며, 비동기 Agent 작업 흐름을 관리하기 위한 서버입니다.

초기 목표는 작업 생성과 조회, PostgreSQL 기반 작업 상태 저장, River 기반 비동기 작업 실행, Plane/Mattermost Adapter stub 구성, 이후 IOP / Agent Integrator와 연결 가능한 구조 확보입니다.

현재 구현 범위

  • Go HTTP Server
  • GET /healthz, GET /readyz
  • task 생성 / 조회 / 목록 / enqueue API
  • PostgreSQL 연결
  • goose migration
  • sqlc 기반 DB query 생성 구조
  • River task job
  • IOP Edge/OpenAI-compatible 모델 호출 경로(Ollama direct fallback 가능)
  • IOP Edge/A2A-compatible agent 호출 인터페이스
  • Plane work item lookup, comment, and state update adapter
  • Mattermost Adapter stub
  • 선택적 Docker Compose 실행 환경(PostgreSQL, Redis)

현재 구현하지 않은 범위

  • 실제 Mattermost 메시지 발송
  • IOP native protocol 연동
  • Agent Integrator 연동
  • Outline / Forgejo / Nextcloud 연동
  • MCP 서버
  • Web Agent UI
  • Flutter 앱
  • 복잡한 권한 정책
  • 복잡한 workflow DSL

실행 방법

로컬 실행은 현재 개발 호스트의 Go와 code-server compose에 붙은 PostgreSQL/Redis가 있다는 전제로 진행합니다. local 기본 DATABASE_URLpostgres://nomadcode:nomadcode@code-server-postgres:5432/nomadcode-core-local?sslmode=disable 이고, local 기본 REDIS_URLredis://code-server-redis:6379/3, REDIS_KEY_PREFIXnomadcode-core:local 입니다. dev 배포는 Docker Compose로 실행하며, 같은 code-server-postgres Postgres와 code-server-redis Redis를 사용합니다. dev DB명은 nomad-core-dev 이고, dev 기본 REDIS_URLredis://code-server-redis:6379/4, REDIS_KEY_PREFIXnomadcode-core:dev 입니다. AUTH_PASSWORD를 설정하면 /readyz/api/*에 HTTP Basic Auth가 적용됩니다. 모델 호출의 장기 대상은 IOP Edge의 OpenAI-compatible input surface이며, 현재 core model client는 Responses API 형식을 사용합니다. fallback 기본값은 direct Ollama MODEL_BASE_URL=http://192.168.0.91:11434, MODEL_NAME=qwen3.6:35b-a3b-bf16, MODEL_CONTEXT_SIZE=262144, MODEL_TIMEOUT_SEC=300 입니다. A2A agent 호출 endpoint는 A2A_EDGE_URL로 설정하고, 기존 A2A_AGENT_URL도 fallback alias로 받습니다. bearer token은 A2A_TOKEN, timeout은 A2A_TIMEOUT_SEC로 설정합니다. Plane 연동은 PLANE_BASE_URL, PLANE_TOKEN으로 설정하며, toki-labs dev Plane 기본 URL은 https://plane.toki-labs.com 입니다.

code-server PostgreSQL 컨테이너에 DB를 생성하는 예시:

docker exec code-server-postgres psql -U nomadcode -d postgres -c 'CREATE DATABASE "nomadcode-core-local" OWNER nomadcode;'
docker exec code-server-postgres psql -U nomadcode -d postgres -c 'CREATE DATABASE "nomad-core-dev" OWNER nomadcode;'

Migration 실행:

./bin/migrate-up

서버 실행:

./bin/run

간단한 암호를 걸고 실행:

AUTH_PASSWORD="change-me" ./bin/run
curl -u nomadcode:change-me localhost:8080/api/tasks

다른 DB 주소를 사용할 경우:

DATABASE_URL="postgres://user:password@localhost:5432/dbname?sslmode=disable" ./bin/migrate-up
DATABASE_URL="postgres://user:password@localhost:5432/dbname?sslmode=disable" ./bin/run

다른 모델 endpoint를 사용할 경우:

MODEL_BASE_URL="http://localhost:11434" \
MODEL_NAME="qwen3.6:35b-a3b-bf16" \
MODEL_CONTEXT_SIZE="262144" \
MODEL_TIMEOUT_SEC="300" \
./bin/run

모델 호출은 OpenAI-compatible Responses API의 non-streaming POST /v1/responses 형식을 사용합니다. IOP Edge OpenAI-compatible listener를 MODEL_BASE_URL로 쓰려면 해당 listener가 /v1/responses를 제공해야 합니다. direct Ollama fallback에서는 MODEL_CONTEXT_SIZE를 Ollama 전용 option인 options.num_ctx로 전달합니다.

A2A agent 호출 인터페이스는 JSON-RPC 2.0 message/send, tasks/get, tasks/cancel을 우선 지원합니다. A2A_EDGE_URL을 설정하면 worker는 A2A message/send를 blocking 호출하고, 완료된 task/message 응답만 local task completion으로 반영합니다. 기존 A2A_AGENT_URL도 fallback alias로 받습니다. 설정하지 않으면 기존 OpenAI-compatible 모델 호출 경로를 사용합니다.

Plane 연동은 Plane API key를 PLANE_TOKEN으로 받고 X-Api-Key header로 호출합니다. 현재 toki-labs dev Plane은 https://plane.toki-labs.com에 있고, 예시 workspace/project 값은 workspace_slug=general, project_id=a6beb42f-7a8a-410c-b50f-ea3ca94828f3 입니다.

PLANE_BASE_URL="https://plane.toki-labs.com" \
PLANE_TOKEN="<plane-api-key>" \
./bin/run

Plane work item에서 pending task를 수동 생성하는 예시:

curl -X POST localhost:8080/api/integrations/plane/tasks \
  -H 'Content-Type: application/json' \
  -d '{
    "workspace_slug": "general",
    "project_id": "a6beb42f-7a8a-410c-b50f-ea3ca94828f3",
    "work_item_id": "8f3861ff-49e4-4944-8ab3-7a7a4e0b95d1",
    "state_id": "ea2e5b48-8bf1-4723-b749-de7723be41e9",
    "external_url": "https://plane.toki-labs.com/general/projects/a6beb42f-7a8a-410c-b50f-ea3ca94828f3/issues/NOMAD-11",
    "comment": "NomadCode core thin e2e smoke"
  }'

현재 endpoint는 Plane work item 조회와 state_id를 포함한 external ref 저장만 검증합니다. 실제 Plane 상의 state update는 smoke 작업 단계에서 별도로 검증합니다. 자동 enqueue와 완료/실패 결과 발행은 pipeline 설계 이후 별도 마일스톤에서 다룹니다.

Plane Smoke 테스트

실제 Plane API와의 통신(조회, 코멘트 추가, 상태 업데이트)을 검증하기 위한 툴을 제공합니다.

1. 조회 Smoke 테스트 (Read-Only)

PLANE_BASE_URL="https://plane.toki-labs.com" \
PLANE_TOKEN="<plane-api-key>" \
PLANE_WORKSPACE_SLUG="general" \
PLANE_PROJECT_ID="a6beb42f-7a8a-410c-b50f-ea3ca94828f3" \
PLANE_WORK_ITEM_ID="<test-work-item-id>" \
./bin/plane-smoke

2. 쓰기 Smoke 테스트 (Write-Apply)

실제 코멘트 작성 및 상태 변경을 유발하므로 테스트용 work item에서만 수행해야 합니다.

PLANE_BASE_URL="https://plane.toki-labs.com" \
PLANE_TOKEN="<plane-api-key>" \
PLANE_WORKSPACE_SLUG="general" \
PLANE_PROJECT_ID="a6beb42f-7a8a-410c-b50f-ea3ca94828f3" \
PLANE_WORK_ITEM_ID="<test-work-item-id>" \
PLANE_SMOKE_COMMENT="NomadCode core Plane smoke" \
PLANE_SMOKE_STATE_ID="ea2e5b48-8bf1-4723-b749-de7723be41e9" \
PLANE_SMOKE_APPLY=1 \
./bin/plane-smoke

테스트 실행:

./bin/test

sqlc 실행:

./bin/sqlc

DB 접근 코드는 migrations/의 스키마와 queries/의 SQL을 기준으로 internal/db/에 생성합니다. internal/db/db.go, internal/db/models.go, internal/db/tasks.sql.go는 생성 파일이므로 직접 수정하지 않습니다.

Docker Compose 실행은 dev 배포용입니다. compose는 외부 Docker 네트워크 net_nginx에 붙고, 같은 네트워크의 code-server-postgresnomad-core-dev DB로, code-server-redis의 Redis DB 4번과 nomadcode-core:dev key prefix로 접속합니다. dev Redis 주소나 prefix를 바꿀 때는 local 실행용 REDIS_URL, REDIS_KEY_PREFIX와 분리된 DEV_REDIS_URL, DEV_REDIS_KEY_PREFIX를 사용합니다. 외부 노출 테스트에서는 AUTH_PASSWORD를 함께 지정합니다.

AUTH_PASSWORD="change-me" ./bin/docker-up

Makefile은 같은 명령을 감싸는 얇은 alias입니다.

make migrate-up
make run
make test
make sqlc

API 테스트:

curl localhost:8080/healthz
curl localhost:8080/readyz
curl -X POST localhost:8080/api/tasks \
  -H 'Content-Type: application/json' \
  -d '{"title":"README 수정 작업","source":"manual","payload":{"message":"README 초안을 정리해줘"}}'
curl localhost:8080/api/tasks
curl localhost:8080/api/tasks/{id}
curl -X POST localhost:8080/api/tasks/{id}/enqueue