Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Go API Overview

Audience: Go developers embedding Pulse in a binary or a service.

Pulse is library-first. The CLI in cmd/pulse/ is a thin adapter around the package documented here. If you’re reaching for os/exec to shell out to the binary from Go, stop and use the library directly — you’ll skip a process boundary and gain typed responses.

LLM agents using MCP: there is no LLM-facing skill that covers Go embedding directly. Agents speak MCP; this page is for the programs that host them.

Module path

import "github.com/frankbardon/pulse"

Sub-packages you’ll commonly touch:

PackagePurpose
github.com/frankbardon/pulsePublic facade (Pulse, Options, Request, Response, Ask, …)
github.com/frankbardon/pulse/typesRequest/response structs, component-type constants (AGG_*, …)
github.com/frankbardon/pulse/ioTabular adapter interfaces (Reader, Writer, ImportJob, ExportJob, ConvertJob)
github.com/frankbardon/pulse/io/<fmt>Per-format readers/writers (csv, tsv, ndjson, jsonarray, parquet, arrow, excel)
github.com/frankbardon/pulse/fsafero-backed filesystem config (fs.New, fs.Default, fs.NewMemMap)
github.com/frankbardon/pulse/errorsTyped CodedError system and code constants
github.com/frankbardon/pulse/descriptorManifest, predict, inspect (no-execute operations)
github.com/frankbardon/pulse/synthSynthetic data generator and profile types
github.com/frankbardon/pulse/skillsEmbedded skill pack — skills.List(), skills.Get(name)

The internal/ subtree (internal/cli, internal/mcp, internal/query) is exactly that — internal. Don’t import it.

The facade

Construct a Pulse once per process (or per filesystem boundary) and re-use it:

p, err := pulse.New(pulse.Options{
    DataDir: "/var/data/pulse",
})
if err != nil {
    return err
}

The full Options shape (custom afero.Fs, smart-default toggling) is documented at pulse.New & Options.

Public methods

From pulse.go:

MethodPurpose
Open(ctx, path) (*Cohort, error)Read header + schema, return a typed Cohort handle
Process(ctx, req) (*Response, error)Execute one request
ProcessStream(ctx, req) (RowIter, error)Same, pull-based iterator over result rows
Compose(ctx, req) ([]*Response, error)Execute a batch sequentially
ComposeParallel(ctx, req, opts) ([]*Response, error)Execute a batch in parallel with a worker pool
Ask(ctx, askReq) (*AskResponse, error)Unified entry: predict + (optionally) process, with natural-language query support
Import(ctx, job) (*ImportReport, error)Tabular → .pulse
Export(ctx, job) (*ExportReport, error).pulse → tabular
Convert(ctx, job) (*ConvertReport, error)Tabular → tabular, with .pulse as the transparent middle
Inspect(ctx, path) (*InspectResult, error)Read header + schema only (no record data)
Predict(ctx, req) (*PredictResult, error)Validate a request without executing
Sample(ctx, path, n) ([]Record, error)Up to n rows
Facet(ctx, path, field) ([]string, error)Distinct values of a field
Synth(ctx, spec, out, opts) (*SynthResult, error)Generate a synthetic cohort
Profile(ctx, path, opts) (*Profile, error)Statistical summary suitable for from-profile synthesis
Manifest(ctx) *ManifestDeterministic root self-description
Fs() afero.FsThe underlying filesystem (used by pulse mcp and other embedders)

Re-exported type aliases let you write pulse.Request instead of types.Request:

type (
    Request         = types.Request
    Response        = types.Response
    ComposedRequest = types.ComposedRequest
    SynthSpec       = synth.Spec
    Profile         = synth.Profile
    // … and so on
)

Minimum viable embed

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/frankbardon/pulse"
    "github.com/frankbardon/pulse/types"
)

func main() {
    ctx := context.Background()

    p, err := pulse.New(pulse.Options{DataDir: "/var/data/pulse"})
    if err != nil {
        log.Fatal(err)
    }

    resp, err := p.Process(ctx, &pulse.Request{
        Cohort: &types.Cohort{Filename: "sales.pulse"},
        Aggregations: []*types.Aggregation{
            {Type: types.AGG_AVERAGE, Field: "revenue", Label: "avg_revenue"},
        },
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(resp.Data)
}

Where to go from here