P0.1: Repository and module setup
Go module, Makefile with standard targets, golangci-lint v2 config, CLAUDE.md, and empty CLI/agent binaries. Build, vet, and lint all pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Binaries
|
||||||
|
/mcp
|
||||||
|
/mcp-agent
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
srv/
|
||||||
|
|
||||||
|
# Database files
|
||||||
|
*.db
|
||||||
|
*.db-wal
|
||||||
|
*.db-shm
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
80
.golangci.yaml
Normal file
80
.golangci.yaml
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
version: "2"
|
||||||
|
|
||||||
|
run:
|
||||||
|
timeout: 5m
|
||||||
|
tests: true
|
||||||
|
|
||||||
|
linters:
|
||||||
|
default: none
|
||||||
|
enable:
|
||||||
|
- errcheck
|
||||||
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
- unused
|
||||||
|
- errorlint
|
||||||
|
- gosec
|
||||||
|
- staticcheck
|
||||||
|
- revive
|
||||||
|
|
||||||
|
settings:
|
||||||
|
errcheck:
|
||||||
|
check-blank: false
|
||||||
|
check-type-assertions: true
|
||||||
|
|
||||||
|
govet:
|
||||||
|
enable-all: true
|
||||||
|
disable:
|
||||||
|
- shadow
|
||||||
|
- fieldalignment
|
||||||
|
|
||||||
|
gosec:
|
||||||
|
severity: medium
|
||||||
|
confidence: medium
|
||||||
|
excludes:
|
||||||
|
- G104
|
||||||
|
|
||||||
|
errorlint:
|
||||||
|
errorf: true
|
||||||
|
asserts: true
|
||||||
|
comparison: true
|
||||||
|
|
||||||
|
revive:
|
||||||
|
rules:
|
||||||
|
- name: error-return
|
||||||
|
severity: error
|
||||||
|
- name: unexported-return
|
||||||
|
severity: error
|
||||||
|
- name: error-strings
|
||||||
|
severity: warning
|
||||||
|
- name: if-return
|
||||||
|
severity: warning
|
||||||
|
- name: increment-decrement
|
||||||
|
severity: warning
|
||||||
|
- name: var-naming
|
||||||
|
severity: warning
|
||||||
|
- name: range
|
||||||
|
severity: warning
|
||||||
|
- name: time-naming
|
||||||
|
severity: warning
|
||||||
|
- name: indent-error-flow
|
||||||
|
severity: warning
|
||||||
|
- name: early-return
|
||||||
|
severity: warning
|
||||||
|
|
||||||
|
formatters:
|
||||||
|
enable:
|
||||||
|
- gofmt
|
||||||
|
- goimports
|
||||||
|
|
||||||
|
issues:
|
||||||
|
max-issues-per-linter: 0
|
||||||
|
max-same-issues: 0
|
||||||
|
|
||||||
|
exclusions:
|
||||||
|
paths:
|
||||||
|
- vendor
|
||||||
|
rules:
|
||||||
|
- path: "_test\\.go"
|
||||||
|
linters:
|
||||||
|
- gosec
|
||||||
|
text: "G101"
|
||||||
58
CLAUDE.md
Normal file
58
CLAUDE.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
MCP (Metacircular Control Plane) is the orchestrator for the Metacircular platform. It manages container lifecycle, tracks what services run where, and transfers files between the operator's workstation and managed nodes.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
MCP has two components:
|
||||||
|
- **CLI** (`mcp`) — thin client on the operator's workstation. Reads local service definition files, pushes intent to agents, queries status. No database.
|
||||||
|
- **Agent** (`mcp-agent`) — smart per-node daemon. Manages containers via podman, stores the registry (SQLite), monitors for drift, alerts the operator.
|
||||||
|
|
||||||
|
Services have one or more components (containers). Container naming: `<service>-<component>`.
|
||||||
|
|
||||||
|
## Build Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make all # vet → lint → test → build both binaries
|
||||||
|
make build # go build ./...
|
||||||
|
make test # go test ./...
|
||||||
|
make vet # go vet ./...
|
||||||
|
make lint # golangci-lint run ./...
|
||||||
|
make proto # regenerate gRPC code from .proto files
|
||||||
|
make proto-lint # buf lint + buf breaking
|
||||||
|
make mcp # build CLI binary
|
||||||
|
make mcp-agent # build agent binary
|
||||||
|
make clean # remove binaries
|
||||||
|
```
|
||||||
|
|
||||||
|
Run a single test: `go test ./internal/registry/ -run TestComponentCRUD`
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
- `cmd/mcp/` — CLI entry point
|
||||||
|
- `cmd/mcp-agent/` — Agent entry point
|
||||||
|
- `internal/agent/` — Agent core (deploy, lifecycle, sync, adopt, status, files)
|
||||||
|
- `internal/runtime/` — Container runtime abstraction (podman)
|
||||||
|
- `internal/registry/` — SQLite registry (services, components, events)
|
||||||
|
- `internal/monitor/` — Monitoring subsystem (watch loop, alerting)
|
||||||
|
- `internal/servicedef/` — Service definition file parsing (TOML)
|
||||||
|
- `internal/auth/` — MCIAS integration (token validation, interceptor)
|
||||||
|
- `internal/config/` — Configuration loading (CLI + agent)
|
||||||
|
- `proto/mcp/v1/` — Proto definitions
|
||||||
|
- `gen/mcp/v1/` — Generated Go gRPC code
|
||||||
|
|
||||||
|
## Critical Rules
|
||||||
|
|
||||||
|
1. Agent is gRPC-only (no REST). This is a deliberate exception to the platform's REST+gRPC parity rule.
|
||||||
|
2. Container naming convention: `<service>-<component>` (e.g., `metacrypt-api`, `metacrypt-web`).
|
||||||
|
3. File operations are scoped to `/srv/<service>/`. Path traversal is rejected.
|
||||||
|
4. Alert commands use exec-style invocation (argv array, no shell). Never use `sh -c`.
|
||||||
|
5. The agent binds to the overlay interface only, not all interfaces. It does NOT sit behind MC-Proxy.
|
||||||
|
6. Every RPC is audit-logged at info level (method, caller, timestamp).
|
||||||
|
7. `active: true/false` in service definitions controls desired state. `mcp stop/start` update the file.
|
||||||
|
|
||||||
|
## Module Path
|
||||||
|
|
||||||
|
`git.wntrmute.dev/kyle/mcp`
|
||||||
35
Makefile
Normal file
35
Makefile
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
.PHONY: build test vet lint proto proto-lint clean all
|
||||||
|
|
||||||
|
LDFLAGS := -trimpath -ldflags="-s -w -X main.version=$(shell git describe --tags --always --dirty)"
|
||||||
|
|
||||||
|
mcp:
|
||||||
|
CGO_ENABLED=0 go build $(LDFLAGS) -o mcp ./cmd/mcp
|
||||||
|
|
||||||
|
mcp-agent:
|
||||||
|
CGO_ENABLED=0 go build $(LDFLAGS) -o mcp-agent ./cmd/mcp-agent
|
||||||
|
|
||||||
|
build:
|
||||||
|
go build ./...
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test ./...
|
||||||
|
|
||||||
|
vet:
|
||||||
|
go vet ./...
|
||||||
|
|
||||||
|
lint:
|
||||||
|
golangci-lint run ./...
|
||||||
|
|
||||||
|
proto:
|
||||||
|
protoc --go_out=. --go_opt=module=git.wntrmute.dev/kyle/mcp \
|
||||||
|
--go-grpc_out=. --go-grpc_opt=module=git.wntrmute.dev/kyle/mcp \
|
||||||
|
proto/mcp/v1/*.proto
|
||||||
|
|
||||||
|
proto-lint:
|
||||||
|
buf lint
|
||||||
|
buf breaking --against '.git#branch=master,subdir=proto'
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f mcp mcp-agent
|
||||||
|
|
||||||
|
all: vet lint test mcp mcp-agent
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Phase 0: Project Scaffolding
|
## Phase 0: Project Scaffolding
|
||||||
|
|
||||||
- [ ] **P0.1** Repository and module setup
|
- [x] **P0.1** Repository and module setup
|
||||||
- [ ] **P0.2** Proto definitions and code generation
|
- [ ] **P0.2** Proto definitions and code generation
|
||||||
|
|
||||||
## Phase 1: Core Libraries
|
## Phase 1: Core Libraries
|
||||||
|
|||||||
33
cmd/mcp-agent/main.go
Normal file
33
cmd/mcp-agent/main.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
version = "dev"
|
||||||
|
cfgPath string
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
root := &cobra.Command{
|
||||||
|
Use: "mcp-agent",
|
||||||
|
Short: "Metacircular Control Plane agent",
|
||||||
|
}
|
||||||
|
root.PersistentFlags().StringVarP(&cfgPath, "config", "c", "", "config file path")
|
||||||
|
|
||||||
|
root.AddCommand(&cobra.Command{
|
||||||
|
Use: "version",
|
||||||
|
Short: "Print version",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println(version)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err := root.Execute(); err != nil {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
33
cmd/mcp/main.go
Normal file
33
cmd/mcp/main.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
version = "dev"
|
||||||
|
cfgPath string
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
root := &cobra.Command{
|
||||||
|
Use: "mcp",
|
||||||
|
Short: "Metacircular Control Plane CLI",
|
||||||
|
}
|
||||||
|
root.PersistentFlags().StringVarP(&cfgPath, "config", "c", "", "config file path")
|
||||||
|
|
||||||
|
root.AddCommand(&cobra.Command{
|
||||||
|
Use: "version",
|
||||||
|
Short: "Print version",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println(version)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err := root.Execute(); err != nil {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
10
go.mod
Normal file
10
go.mod
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
module git.wntrmute.dev/kyle/mcp
|
||||||
|
|
||||||
|
go 1.25.7
|
||||||
|
|
||||||
|
require github.com/spf13/cobra v1.10.2
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.9 // indirect
|
||||||
|
)
|
||||||
10
go.sum
Normal file
10
go.sum
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||||
|
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||||
|
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
|
||||||
|
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
Reference in New Issue
Block a user