1 DevOps-Tools
Virgil edited this page 2026-02-19 16:23:20 +00:00

DevOps Tools

API reference for the devops package -- portable development environments with LinuxKit, shell access, testing, serving, Claude sandboxing, and image management. See Home for installation.

DevOps Manager

The central DevOps struct orchestrates the portable dev environment backed by LinuxKit QEMU images.

import (
    "forge.lthn.ai/core/go-devops/devops"
    "forge.lthn.ai/core/go/pkg/io"
)

d, err := devops.New(io.Local)

Lifecycle

// Boot the dev environment
err := d.Boot(ctx, devops.BootOptions{
    Memory: 4096,  // MB
    CPUs:   2,
    Name:   "core-dev",
    Fresh:  false, // set true to destroy and recreate
})

// Check status
running, err := d.IsRunning(ctx)

// Get detailed status
status, err := d.Status(ctx)
// status.Installed, status.Running, status.ImageVersion,
// status.ContainerID, status.Memory, status.CPUs,
// status.SSHPort (default 2222), status.Uptime

// Stop
err := d.Stop(ctx)

// Install/update images
err := d.Install(ctx, progressCallback)
current, latest, hasUpdate, err := d.CheckUpdate(ctx)

BootOptions

type BootOptions struct {
    Memory int    // MB, default 4096
    CPUs   int    // default 2
    Name   string // container name, default "core-dev"
    Fresh  bool   // destroy existing and start fresh
}

opts := devops.DefaultBootOptions() // sensible defaults

DevStatus

type DevStatus struct {
    Installed    bool
    Running      bool
    ImageVersion string
    ContainerID  string
    Memory       int
    CPUs         int
    SSHPort      int           // default 2222
    Uptime       time.Duration
}

Shell Execution

Connect to the dev environment via SSH or serial console.

err := d.Shell(ctx, devops.ShellOptions{
    Console: false,           // true for serial console, false for SSH
    Command: []string{"ls"},  // empty for interactive shell
})

ShellOptions

type ShellOptions struct {
    Console bool     // Use serial console instead of SSH
    Command []string // Command to run (empty = interactive shell)
}

SSH connects to root@localhost:2222 with agent forwarding (-A) and strict host key checking using ~/.core/known_hosts.


Docker Image Management

The ImageManager handles downloading, installing, and updating LinuxKit dev images from multiple sources.

type ImageManager struct { /* ... */ }

// Platform-specific image name
name := devops.ImageName() // e.g. "core-devops-darwin-arm64.qcow2"

// Image paths
dir, err := devops.ImagesDir()   // ~/.core/images (or $CORE_IMAGES_DIR)
path, err := devops.ImagePath()  // ~/.core/images/core-devops-darwin-arm64.qcow2

Image Sources (devops/sources)

The ImageSource interface defines how images are downloaded:

type ImageSource interface {
    Name() string
    Available() bool
    LatestVersion(ctx context.Context) (string, error)
    Download(ctx context.Context, m io.Medium, dest string, progress func(downloaded, total int64)) error
}

Two built-in sources:

Source Type Availability Check
GitHubSource GitHub Releases via gh CLI gh auth status succeeds
CDNSource HTTP download from CDN/S3 URL CDN URL configured
import "forge.lthn.ai/core/go-devops/devops/sources"

cfg := sources.SourceConfig{
    GitHubRepo: "host-uk/core-images",
    CDNURL:     "https://cdn.example.com/images",
    ImageName:  "core-devops-darwin-arm64.qcow2",
}

gh := sources.NewGitHubSource(cfg)
cdn := sources.NewCDNSource(cfg)

Manifest

Tracks installed images in ~/.core/images/manifest.json:

type ImageInfo struct {
    Version    string    `json:"version"`
    SHA256     string    `json:"sha256,omitempty"`
    Downloaded time.Time `json:"downloaded"`
    Source     string    `json:"source"` // "github" or "cdn"
}

Testing

Run tests inside the dev environment with auto-detection of test frameworks.

err := d.Test(ctx, projectDir, devops.TestOptions{
    Name:    "",         // run named command from .core/test.yaml
    Command: []string{}, // override command (highest priority)
})

Auto-Detection Order

DetectTestCommand checks in this order:

  1. .core/test.yaml -- explicit command field
  2. composer.json with test script -- composer test
  3. package.json with test script -- npm test
  4. go.mod -- go test ./...
  5. pytest.ini or pyproject.toml -- pytest
  6. Taskfile.yaml -- task test

Test Config (.core/test.yaml)

version: 1
command: go test ./...
commands:
  - name: unit
    run: go test -short ./...
  - name: integration
    run: go test -run Integration ./...
env:
  GOFLAGS: -v

Serve Mode

Mount a project and start a development server inside the dev environment.

err := d.Serve(ctx, projectDir, devops.ServeOptions{
    Port: 8000, // default 8000
    Path: "",   // subdirectory (default: project root)
})

Auto-Detection Order

DetectServeCommand checks in this order:

  1. artisan (Laravel) -- php artisan octane:start --host=0.0.0.0 --port=8000
  2. package.json with dev script -- npm run dev -- --host 0.0.0.0
  3. package.json with start script -- npm start
  4. composer.json (PHP) -- frankenphp php-server -l :8000
  5. go.mod + main.go -- go run .
  6. manage.py (Django) -- python manage.py runserver 0.0.0.0:8000
  7. Fallback -- python3 -m http.server 8000

Project is mounted into the VM at /app via reverse SSHFS.


Claude Sandbox

Run Claude Code in an isolated dev environment with selective auth forwarding.

err := d.Claude(ctx, projectDir, devops.ClaudeOptions{
    NoAuth: false,                                // don't forward any auth
    Auth:   []string{"gh", "anthropic", "ssh", "git"}, // selective (default: all)
    Model:  "opus",                                // model override
})

ClaudeOptions

type ClaudeOptions struct {
    NoAuth bool     // Don't forward any auth
    Auth   []string // Selective auth: "gh", "anthropic", "ssh", "git"
    Model  string   // Model to use: opus, sonnet
}

Auth Forwarding

Auth Type What Gets Forwarded
ssh SSH agent forwarding (-A) -- always on unless NoAuth
anthropic ANTHROPIC_API_KEY env var
git GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL
gh GitHub CLI config copied via CopyGHAuth() using scp

Auto-boots the dev environment if not running. Project is mounted at /app.


SSH Utilities

Host Key Management

After booting, ensureHostKey automatically scans the VM's SSH host key and adds it to ~/.core/known_hosts (deduplicating entries). This enables StrictHostKeyChecking=yes for all subsequent SSH connections.

Set CORE_SKIP_SSH_SCAN=true to skip in tests.


Configuration

Global devops config is loaded from ~/.core/config.yaml:

type Config struct {
    Version int
    Images  ImagesConfig
}

type ImagesConfig struct {
    Source   string         // "auto", "github", "cdn"
    GitHub   GitHubConfig   // .Repo (owner/repo)
    Registry RegistryConfig // .Image (e.g. ghcr.io/host-uk/core-devops)
    CDN      CDNConfig      // .URL (base download URL)
}
cfg, err := devops.LoadConfig(medium) // returns DefaultConfig() if file missing
path, err := devops.ConfigPath()      // ~/.core/config.yaml

Defaults

version: 1
images:
  source: auto
  github:
    repo: host-uk/core-images
  registry:
    image: ghcr.io/host-uk/core-devops

See Infrastructure for the infra package API.