engine

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 17, 2026 License: MIT Imports: 27 Imported by: 0

README

Detection and cleaning engine for blotless
Layer A Unicode · Layer B survey + AST/LLM · C2PA / files · origin heuristics
Zero CGO

blotless/engine

Walk, classify, detect, merge, score, plan patches — embeddable library

Language: English | Русский

CI Go Reference Go Report Card License Latest Release Go Version


Overview

engine is the library of the blotless ecosystem. The CLI in blotless/cli is a thin Cobra wrapper around engine.Scan / engine.Clean. Language transforms use blotless/ast. These are separate GitHub repositories.

Detectors receive a domain.Unit (already-loaded bytes). They do not read the filesystem.

Key Features

Category Capabilities
Layer A Invisible Unicode, exotic spaces, bidi, tags, VS, other Cf, Latin confusables
Origin Soft fingerprints → Score.Agent / Confidence / Evidence (not SynthID verify)
Layer B Eligibility survey; ast.Transform; optional Ollama / openai rewrite
Files C2PA / EXIF / XMP in PNG, JPEG, WebP, SVG, PDF, DOCX, ODT, HTML, Markdown
Web audit engine/webaudit — SSRF-safe sitemap fetch
Go source Homoglyph idents; protect spans via blotless/ast/golang
Stamps AI co-author / generator phrases in comments
Clean Strip / normalize / rewrite; optional NFKC; gofmt for Go
Build CGO_ENABLED=0, Go 1.26+; task preflight

Installation

go get github.com/blotless/engine

Requirements: Go 1.26+, CGO_ENABLED=0. Depends on github.com/blotless/ast.


Quick Start

package main

import (
	"context"
	"fmt"

	"github.com/blotless/engine"
)

func main() {
	eng, err := engine.New(engine.Config{
		Paths:      []string{"."},
		Aggressive: true,
		LayerB:     true,
	})
	if err != nil {
		panic(err)
	}
	defer eng.Close()

	res, err := eng.Scan(context.Background())
	if err != nil {
		panic(err)
	}
	fmt.Printf("findings=%d score=%d%% agent=%s conf=%s\n",
		len(res.Findings), res.Score.Percent, res.Score.Agent, res.Score.Confidence)
}

Clean with a WASM language plugin

Plugin tutorial: blotless/ast — WASM. Example crate: examples/wasm-rust.

eng, err := engine.New(engine.Config{
    Paths:   []string{"."},
    Write:   true,
    LayerB:  true,
    AstWASM: map[string]string{
        "rust": "./blotless_rust_transform.wasm", // also maps .rs
    },
    // AstExt: map[string]string{".zig": "zig"},
})
if err != nil {
    panic(err)
}
defer eng.Close()
_, err = eng.Clean(context.Background())

Equivalent CLI: blotless clean . --write --layer-b --ast-wasm rust=./blotless_rust_transform.wasm


Architecture

walk → classify → detect → protect → merge → score
                              │
clean ← plan ← ast.Transform / optional LLM ← Layer B survey

Public surface: engine.Config, engine.Scan, engine.Clean, engine.Rules, domain, ports.

Details: docs/ARCHITECTURE.md.


Ecosystem

Project Description
blotless/engine This repo
blotless/ast AST transform + WASM
blotless/cli CLI
blotless/skills Agent skills

Development

git clone https://github.com/blotless/engine
cd engine
CGO_ENABLED=0 go test ./...
task preflight

Disclaimer

Layer B is best-effort. Origin scores are heuristic. Do not claim certified human authorship.


License

MIT License — see LICENSE.


blotless — inspect first, then clean

Documentation

Index

Constants

View Source
const DefaultMaxFileBytes = 8 << 20

Variables

This section is empty.

Functions

func Report

func Report(w io.Writer, format string, res *Result, version string) error

Report writes findings using format (table|json|yaml|sarif).

func WriteFinding

func WriteFinding(w io.Writer, f domain.Finding, lastFile string) string

WriteFinding prints one live finding. Pass lastFile from the previous call.

Types

type Config

type Config struct {
	Paths          []string
	Include        []string
	Exclude        []string
	Aggressive     bool
	FailOn         domain.Confidence
	LLM            LLMConfig
	Write          bool
	Backup         string
	MaxFileBytes   int64
	DisabledRules  []string
	Gofmt          bool
	LayerB         bool
	LayerBStrength string
	AstWASM        map[string]string // lang -> local .wasm path
	AstExt         map[string]string // ".rs" -> "rust"
	NFKC           bool
	ForceText      bool
	ForceKind      string // auto|text|image|container
	Logger         *slog.Logger
	Progress       ports.Progress
}

Config is the CLI-facing engine configuration. Cobra/Viper must not leak in.

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine orchestrates walk, detect, merge, and clean.

func New

func New(cfg Config) (*Engine, error)

New constructs an engine from config. LLM adapters are wired here.

func (*Engine) Clean

func (e *Engine) Clean(ctx context.Context) (*Result, error)

Clean plans patches and optionally writes them.

func (*Engine) Close

func (e *Engine) Close() error

Close stops a managed Ollama process if this engine started it.

func (*Engine) Scan

func (e *Engine) Scan(ctx context.Context) (*Result, error)

Scan walks paths and returns findings. It never writes files.

type LLMConfig

type LLMConfig struct {
	Mode     string
	Model    string
	Endpoint string
	Timeout  time.Duration
	APIKey   string
}

LLMConfig selects an optional language-model adapter.

type Result

type Result struct {
	FilesScanned int
	FilesSkipped int
	Findings     []domain.Finding
	Patches      []domain.Patch
	DryRun       bool
	Score        domain.Score
	After        *domain.Score
	Leftover     []domain.Finding
	Streamed     bool
	TextFiles    int            `json:"text_files,omitempty" yaml:"text_files,omitempty"`
	ImageFiles   int            `json:"image_files,omitempty" yaml:"image_files,omitempty"`
	DocFiles     int            `json:"doc_files,omitempty" yaml:"doc_files,omitempty"`
	DetectorHits map[string]int `json:"detector_hits,omitempty" yaml:"detector_hits,omitempty"`
	LayerA       int            `json:"layer_a"`
	LayerFiles   int            `json:"layer_files"`
	LayerB       int            `json:"layer_b"`
	LayerBOpt    int            `json:"layer_b_optional,omitempty"`
	LayerBFiles  []string       `json:"layer_b_files,omitempty"`
}

Result is the outcome of Scan or Clean.

func (Result) ShouldFail

func (r Result) ShouldFail(failOn domain.Confidence) bool

ShouldFail reports whether findings meet FailOn.

type RuleInfo

type RuleInfo struct {
	ID          string `json:"id" yaml:"id"`
	Family      string `json:"family" yaml:"family"`
	Severity    string `json:"severity" yaml:"severity"`
	Confidence  string `json:"confidence" yaml:"confidence"`
	Clean       string `json:"clean" yaml:"clean"`
	Description string `json:"description" yaml:"description"`
}

RuleInfo is a public view of an embedded rule spec.

func Explain

func Explain(id string) (RuleInfo, error)

Explain returns one rule spec.

func Rules

func Rules() ([]RuleInfo, error)

Rules returns the embedded catalog.

Directories

Path Synopsis
internal
detect/origin
Package origin detects soft AI-origin heuristics (not SynthID verification).
Package origin detects soft AI-origin heuristics (not SynthID verification).
layerb
Package layerb plans best-effort rewrites against token-sampling watermarks (Kirchenbauer / SynthID-Text).
Package layerb plans best-effort rewrites against token-sampling watermarks (Kirchenbauer / SynthID-Text).
llm
Package rewrite implements the Layer B text rewrite hook (WR rewrite_text.py).
Package rewrite implements the Layer B text rewrite hook (WR rewrite_text.py).
Package webaudit audits URLs from a sitemap (WR audit_website.py), SSRF-safe.
Package webaudit audits URLs from a sitemap (WR audit_website.py), SSRF-safe.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL