Skip to content

SuperAlignHQ/scanner-ext

Repository files navigation

scanner-ext

Language-agnostic plugin contract for the Surface scanner. Extensions are out-of-process binaries that speak a small gRPC service over a unix socket; the scanner spawns them, dials in, and treats each one as a peer of its built-in discovery modules.

  • Module: github.com/superalignhq/scanner-ext
  • Contract: scannerpb/scanner.proto
  • Wire format: gRPC over a unix socket (SURFACE_EXT_SOCKET env var)
  • License: Apache-2.0

Quick start (Go)

package main

import (
    "context"
    "log"

    pb "github.com/superalignhq/scanner-ext/scannerpb"
    "github.com/superalignhq/scanner-ext/sdk"
)

type my struct{ pb.UnimplementedScannerServer }

func (*my) Metadata(_ context.Context, _ *pb.MetadataRequest) (*pb.MetadataResponse, error) {
    return &pb.MetadataResponse{Name: "My Scanner", Category: "my_category"}, nil
}

func (*my) Scan(_ *pb.ScanRequest, s pb.Scanner_ScanServer) error {
    return s.Send(&pb.AIAsset{
        Name:     "An Asset",
        StableId: "ext:my:asset-1",
        Category: "my_category",
    })
}

func main() {
    if err := sdk.Serve(&my{}); err != nil {
        log.Fatal(err)
    }
}

Build it, then point a Surface scanner at the resulting config.json:

go build -o my-scanner .
sudo surface extension load /path/to/config.json

See examples/hello/ for a complete, runnable example.

Authoring in another language

Run protoc (or your language's buf generator) against scannerpb/scanner.proto, implement the Scanner service, and listen on the unix socket named in the SURFACE_EXT_SOCKET env variable. Exit cleanly on SIGTERM. The Surface host writes a PID lockfile at the path in SURFACE_EXT_PID_PATH; remove it on graceful shutdown for clean liveness reporting.

Stable IDs

Every emitted asset must carry a stable_id prefixed uniquely to your extension — e.g. ext:<slug>:<thing>. The host deduplicates assets across all scanners (built-in and extensions) by stable_id, so collisions silently merge.

Versioning

This module follows semver. Breaking changes to the proto bump the major version. Run buf breaking against the previous tag before tagging a new release.

Layout

scannerpb/        # the gRPC contract — source of truth
sdk/              # Go SDK (sdk.Serve hides the boilerplate)
examples/hello/   # smoke-test extension that emits one asset
buf.yaml          # buf module config
buf.gen.yaml      # protoc plugin pipeline
Makefile          # gen / lint / build / test

Contributing

Open an issue or PR. The proto under scannerpb/ is the contract; any change there must keep buf breaking clean across releases.

About

Language-agnostic plugin contract for the Surface scanner — gRPC over unix socket + Go SDK + reference extension

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages