Skip to content

feat: replace Python MCP plugin with Go runtime (v0.4.0)#155

Open
esifea wants to merge 226 commits into
mainfrom
feat/go-migration
Open

feat: replace Python MCP plugin with Go runtime (v0.4.0)#155
esifea wants to merge 226 commits into
mainfrom
feat/go-migration

Conversation

@esifea
Copy link
Copy Markdown
Contributor

@esifea esifea commented Jun 2, 2026

Replace Python MCP server with rune CLI + rune-mcp + runed written in Go.

couragehong and others added 30 commits April 16, 2026 16:22
5-agent 외부 독립검증(mcp/ + agents/ 전수 스캔)에서 발견한 scope 경계 모호성 해소.

P0 (scope 명확화):
- architecture.md: 최상단에 Scope (SOT) 박스 신설. Python v0.3.x agent-delegated
  경로만 canonical 선언 + scope 밖 8항목 표 (legacy 3-tier, synthesizer,
  _parse_multilingual, auto-provider, local embedder 등). Python도 같은 방향으로
  수렴 명시
- types.md: §3a Agent extraction types 추가. ExtractedFields /
  PhaseExtractedFields / ExtractionResult Go struct + IsMultiPhase/IsBundle +
  phase_chain 7 / bundle 5 상한 + wire↔internal 매핑 표 (CaptureRequest의
  flat JSON이 Detection + ExtractionResult로 split되는 규칙)
- envector.md / vault.md / rune-mcp.md: 3-레이어 복호화 경계 통일. envector SDK
  는 opaque string만 취급 / service 레이어(Python searcher.py:L444,L455 ↔ Go
  recall.go Phase 5)가 Vault.DecryptMetadata 직접 호출

P1 (divergence 명시):
- vault.md: agent_dek 32B 검증 — Python (envector_sdk.py:L139)에 없는 보안 gap을
  Go가 fail-fast로 막음 (의도적 개선)
- recall.md: _calculate_confidence의 "/2.0" 의도 주석 — top-5 position_weight
  합(≈2.283)의 근사 정규화 상수
- rune-mcp.md: capture_log flock — Python은 O_APPEND만(kernel atomic),
  Go는 보수적 flock 추가 (multi-session 대비)
- python-parity-final.md: get_related 전역 grep 0 caller 확정 (2026-04-22)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
rune-mcp Go port skeleton. No internal logic — types, signatures, TODOs,
and Python references only. Builds with `go build ./...` using stdlib only;
no external dependencies (MCP SDK, gRPC, envector-go SDK) yet.

Package layout (follows spec/components/rune-mcp.md + each flow's "Package
layout" section):

  cmd/rune-mcp/main.go                       # stdio entry + signal handling
  go.mod                                      # module github.com/envector/rune-go (go 1.24)

  internal/domain/       (7)  # types.md §1-6 1:1
    schema.go                 # 6 schema enums + 9 sub-models + DecisionRecord v2.1 + GenerateRecordID/GroupID (word-level slug, unicode.IsLetter/Digit) + §7 helpers
    extraction.go             # §3a ExtractionResult hierarchy (3 structs + IsMultiPhase/IsBundle)
    capture.go                # §4.1 CaptureRequest/Response + RawEvent
    query.go                  # §1.7-8, §4.2, §5.1-3 (RecallArgs/Result, SearchHit, ParsedQuery, Detection, ExtractPayloadText strict v2.1)
    novelty.go                # §5.4 NoveltyInfo (inverted score, 4 classes)
    errors.go                 # 10 error codes (Python 7 + EMBEDDER_UNREACHABLE + EMPTY_EMBED_TEXT + EXTRACTION_MISSING)
    logio.go                  # §6 CaptureLogEntry (NoveltyScore *float64 for omitempty)

  internal/policy/       (6)  # pure functions, no I/O
    novelty.go                # ClassifyNovelty + D11 thresholds 0.3/0.7/0.95
    rerank.go                 # HalfLifeDays=90, (0.7xraw + 0.3xdecay) x status_mul, TimeRanges map
    query.go                  # Parse stub + IntentRules/TimeRules/StopWords/TechPatterns placeholders (31+16+81+4 TODO)
    record_builder.go         # BuildPhases stub + MaxInputChars=12_000 + Quote/Rationale placeholders
    payload_text.go           # RenderPayloadText stub (D15 canonical ref + subtle behavior notes)
    pii.go                    # RedactSensitive + 5 SENSITIVE_PATTERNS placeholder

  internal/adapters/     (12)
    config/loader.go          # Config 3-section (vault/state/metadata) + DirPerm/FilePerm (0700/0600)
    vault/client.go           # Client interface (3 RPCs) + MaxMessageLength 256MB + ValidateAgentDEK (Go fail-fast)
    vault/endpoint.go         # NormalizeEndpoint 4-form URL parsing (tcp://, http(s)://, host:port, host)
    vault/health.go           # HealthFallback Tier 2 HTTP /health (strip /mcp /sse)
    vault/errors.go           # 5 sentinels + ErrNotHTTPScheme + MapGRPCError
    envector/client.go        # Client interface + InsertRequest/MetadataRef/Entry
    envector/aes_ctr.go       # Seal/Open stubs (AES-256-CTR envelope {"a","c"})
    envector/errors.go        # 4 sentinels + MapSDKError (Python 11 patterns NOT ported — intentional)
    embedder/client.go        # Client interface + RetryBackoffs [0, 500ms, 2s]
    embedder/info_cache.go    # infoCache sync.Once + Get/Snapshot
    embedder/retry.go         # retry[R any] generic helper + retryable(gRPC codes) stub
    logio/capture_log.go      # Append (flock) + Tail (reverse jsonl) stubs

  internal/service/      (5)  # 7-phase orchestration (business logic lives here, not in handlers)
    capture.go                # CaptureService.Handle/Batch + Phase 2-7 helpers + BatchCaptureArgs/Result
    recall.go                 # RecallService.Handle + searchWithExpansions/searchSingle/resolveMetadata/classifyMetadata/toSearchHit/expandPhaseChains/assembleGroups/applyMetadataFilters/buildResult/calculateConfidence
    lifecycle.go              # LifecycleService.{VaultStatus,Diagnostics,CaptureHistory,DeleteCapture,ReloadPipelines} + 8 result types
    search.go                 # SearchByID (shared by recall + delete_capture) — "ID: {id}" hack
    diagnostics_classify.go   # ClassifyEnvectorError (gRPC code-based, not Python string patterns)

  internal/mcp/          (2)
    tools.go                  # 8 MCP tool handler stubs + Deps + Register (SDK wiring)
    state.go                  # CheckState + ValidateCaptureRequest/RecallArgs + TruncateTitle/ClampConfidence + state-specific recovery hints

  internal/lifecycle/    (2)
    boot.go                   # State enum (4 values, atomic) + Manager + BootBackoffs (1s->60s cap) + RunBootLoop stub
    shutdown.go               # GracefulShutdown 3-step (drain inflight 30s + adapter Close + DEK zeroize) + InflightTracker + ZeroizeDEK

  internal/obs/          (1)
    slog.go                   # SensitiveFilter 2 regex placeholder + request_id context

Every file includes:
- Python source file:line references
- docs/v04 spec section references
- Relevant decision numbers (D2/D3/D11/D13-17/D22-28/D30-32)
- TODO comments pointing to where real implementation lives

Next step (separate PR): add external deps (go-sdk, grpc, envector-go-sdk),
then fill in real implementation following the Phase 1-7 roadmap
(docs/v04/README.md).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
README.md:
  - Add §구현 로드맵 section — 7 phases (external deps → domain/policy →
    record_builder/payload_text port → adapters → service orchestration →
    MCP SDK wiring → verification) with scope notes and priority tips
  - Add "Go skeleton ✅ 완료" row to §상태 table, referencing 2eb167d

notes/implementability-report.md:
  - Update §Go 구현 진입 로드맵 — mark Phase 0 (docs P0/P1 + skeleton)
    done; point to README §구현 로드맵 as single source for Phase 1+

Rationale: skeleton is now compile-clean and covers every doc section, so
the next actionable step is a documented phase-by-phase implementation
plan that contributors can pick up as separate PRs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Enable new developers to locate their first PR target within 10 minutes
without reading the entire docs/v04/ tree upfront.

New files:
  internal/README.md
    - Package dependency graph (domain → policy/adapters/lifecycle/obs →
      service → mcp → cmd) with import rules
    - Per-file table for every package: role · Python origin ·
      spec doc · relevant Phase
    - Working rules (Python as canonical · no ad-hoc decision changes ·
      build baseline · TODO lifetime · dependency direction)
    - Links to every relevant docs/v04/ document

  docs/v04/onboarding.md
    - 10-minute route (context → navigation → first target)
    - Environment setup (Go toolchain · IDE · build/vet/lint/test commands)
    - Reading order per Phase (only read what the current Phase needs)
    - First-PR recommendations per Phase with concrete starter tasks:
      * Phase 2: ParseDomain / ClassifyNovelty / GenerateRecordID tests /
                 MakeError
      * Phase 3: RedactSensitive regex port
      * Phase 4: NormalizeEndpoint edge-case tests
      * Heavy: RenderPayloadText full canonical port
    - Conventions (Python bit-identical · TODO format · test layout ·
      directory boundaries · commit messages · PR size)
    - FAQ (Python source · decision changes · external deps · float
      precision · scope · agent contract · Python deviation detection)

Updated:
  docs/v04/README.md
    - Reading order "Go로 구현할 개발자" section: onboarding.md first,
      then internal/README.md, then spec docs
    - Status table: add row for "개발자 onboarding 가이드 ✅ 완료"

Rationale: the skeleton (2eb167d) covers every doc section, but new
developers still face a cold-start problem — 16 design docs + 37 Go files.
These two files are the navigation map that collapses that surface into
a predictable entry path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
docs/v04/notes/flow-matrix.md:
- 10 플로우 (8 MCP tool + boot/shutdown) 인벤토리
- 플로우 × 파일 매트릭스 (Infra/MCP · Service · Adapter · Policy/Domain 4 분할)
- Tier S/A/B 공통 모듈 분류 + 팀 분업 제안
- §0 TL;DR: 결론 4줄, I/O 한눈 요약, 핵심 인사이트 4개, 역할별 읽기 가이드

internal/mcp/tools.go:
- ToolDeleteCapture 주석 Python line ref 정정 (L1113 → L1123).
  실제 async def tool_delete_capture 시작 라인, service/lifecycle.go와 일관화.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cmd/rune-mcp/main.go: MCP server bootstrap (NewServer + Register +
StdioTransport.Run). Empty Deps, no boot loop / config.Load yet.
isNormalShutdown() drops exit 1 for stdin EOF · ctx cancel ·
jsonrpc2.ErrServerClosing (internal SDK error, matched by message).

internal/mcp/tools.go: Register binds all 8 tools via stubHandler[In, Out].
Input/output schema auto-inferred; tools/call returns IsError
"not yet implemented (skeleton phase A)". Phase 5 swaps the stub for
service-layer wrappers.

go.mod/go.sum: modelcontextprotocol/go-sdk v1.5.0 (D2). Go 1.24 → 1.25
per SDK requirement.

.gitignore: bin/ + *.test + coverage.out.

Smoke tests:
  ./bin/rune-mcp < /dev/null  → exit 0
  echo '{"method":"initialize",...}' | ./bin/rune-mcp
    → {"result":{"serverInfo":{"name":"rune-mcp","version":"0.4.0-alpha"},
       "capabilities":{"tools":{"listChanged":true},...}}}, exit 0

다음: ~/.claude/mcp.json에 별도 entry로 등록 → Claude Code에서 8개 tool 인식 확인.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
새 디렉토리 docs/v04/progress/ 신설 — spec(How)·overview(Why)·notes
(검증 로그)와 별개로 "실제 구현이 어디까지 동작하는가 + 어떻게 직접
검증하는가"를 vertical slice 단위로 추적.

phase-a-mcp-boot.md (직전 커밋 19b7bf6과 한 쌍):
- 동작하는 기능 6가지 (빌드 · initialize · tools/list · schema 자동 추론
  · tools/call stub · 정상 종료)
- 동작하지 않는 것 (Phase A 한계 표 — Vault·envector·embedder·service
  레이어 전부 미구현)
- 확인법 3 레벨: CLI 직접 / Claude Code 등록 / MCP Inspector
  각 레벨마다 step + 기대 출력 + 합격 기준
- Troubleshooting + 코드 변경 요약 + 다음 마일스톤 후보

progress/README.md (인덱스):
- 디렉토리 목적 · spec/notes와의 차이
- 문서 명명 규칙 + "Phase A vs Phase 1~7" 관계
- 현재까지 추적된 마일스톤 표 (Phase A only) + 예정 마일스톤

docs/v04/README.md: 디렉토리 구조 표에 progress/ + notes/flow-matrix.md
한 줄씩 추가.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
esifea and others added 28 commits June 1, 2026 19:08
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…dance

The MCP server advertises recall's call signature and parameter types to
the session, so the hand-written call block duplicated it. Replace with
prose covering only what the schema omits: status enum, domain examples,
since ISO format, and topk default.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The MCP server advertises capture's `extracted` param as type=object
(additionalProperties: true), so passing a JSON string fails schema
validation. The "JSON string, not a JSON object" instruction was stale
from when the server json.loads'd a string param. Note batch_capture's
`items` is genuinely type=string and is left unchanged. Fixed across the
claude, gemini, and codex agent docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cument

 refactor: remove deprecated v0.3 artifacts, fix dangling refs
runed and rune-mcp now name their release assets by build OS
(runed-<ver>-ubuntu-2204-amd64.tar.gz / runed-<ver>-mac-14-arm64.tar.gz,
rune-mcp-ubuntu-2204-amd64, ...) instead of GOOS, to encode the glibc
baseline — see CryptoLabInc/runed#9 and the matching rune-mcp change.

The manifest generator hardcoded the old runed-<ver>-<goos>-<arch>.tar.gz
and rune-mcp-<goos>-<arch> names, so it would build dead URLs and fail to
read the sha256 entries.

Resolve each platform's asset from the downloaded sha256 / checksums.txt
files instead: map the manifest platform's GOOS to the os-type the
downstream repos emit (linux -> ubuntu, darwin -> mac) and glob the exact
OS version from the filenames, so a downstream runner bump needs no change
here. The manifest platform keys (linux-amd64, darwin-arm64, ...) — the
GOOS-GOARCH keys the rune CLI looks up at runtime — are unchanged.
ci: resolve downstream asset names by build OS in manifest
chore: remove stale gemini-extension.json (v0.4 dropped contextFileName)
runed/rune-mcp now report an idle-suspended embedder as IDLE. Add a /rune:status rendering rule so IDLE shows a paused/ready marker and the resumes-on-next-request message instead of looking broken.
feat(status): render embedder IDLE as healthy, not an error
@esifea esifea marked this pull request as ready for review June 3, 2026 10:10
@esifea esifea requested a review from a team June 3, 2026 10:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants