tipcatalog

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 26, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

README

tipcatalog

Go Reference CI License Go Report Card

Shared tip/suggestion content catalog for the bluefunda CLI (bai), the cai-iOS app, and editor plugins. One schema, one set of tip content, rendered differently per surface.

Why

Each client (CLI, iOS, editor) needs contextual tips, but authoring and maintaining separate copy per surface drifts fast. tipcatalog is the single source of truth: a Tip schema with per-surface render copy, a validator, and a signed, versioned distribution format so clients can fetch updates without redeploying.

Installation

go get github.com/bluefunda/tipcatalog

Usage

import tipcatalog "github.com/bluefunda/tipcatalog"

// Offline fallback baked into the binary via go:embed.
tips, err := tipcatalog.Embedded()

// Or load from a directory of tip JSON files (e.g. this repo's tips/ during CI).
tips, err := tipcatalog.LoadDir("tips")

// Verify a fetched manifest before trusting it.
ok := tipcatalog.Verify(manifestBytes, sig, tipcatalog.PublicKey)

Schema

Each tip is one JSON file under tips/, validated against the fields documented in schema/tip.schema.json (used by the Swift side to codegen matching types). See tip.go for the canonical Go definition. To add or edit tip content, see CONTENT_GUIDE.md.

Distribution

On every GitHub Release, CI compiles tips/*.json into a single catalog.json, signs it with Ed25519, and attaches both catalog.json and catalog.json.sig to the release. Clients fetch the latest release's assets, verify the signature against PublicKey (in pubkey.go), and fall back to the embedded copy on any failure.

Contributing

See CONTRIBUTING.md.

License

Apache 2.0 — see LICENSE.

Documentation

Overview

Package tipcatalog defines the shared tip/suggestion content catalog consumed by the bluefunda CLI, the cai-iOS app, and editor plugins — one schema, one set of tip content, rendered differently per surface.

Installation

go get github.com/bluefunda/tipcatalog

Usage

import tipcatalog "github.com/bluefunda/tipcatalog"

// Offline fallback baked into the binary via go:embed.
tips, err := tipcatalog.Embedded()

// Or load from a directory of tip JSON files.
tips, err := tipcatalog.LoadDir("tips")

// Verify a fetched manifest before trusting it.
ok := tipcatalog.Verify(manifestBytes, sig, tipcatalog.PublicKey)

Distribution

On every GitHub Release, CI compiles tips/*.json into a single catalog.json, signs it with Ed25519, and attaches both catalog.json and catalog.json.sig to the release. Consumers fetch the latest release's assets, verify the signature against PublicKey, and fall back to the embedded copy on any failure.

Index

Constants

View Source
const (
	SurfaceCLI    = "cli"
	SurfaceIOS    = "ios"
	SurfaceVSCode = "vscode"
	SurfaceADT    = "adt"
)

Known surface identifiers. A Tip's Surfaces field gates which clients may show it; Render must carry a matching entry for each declared surface.

Variables

View Source
var EmbeddingDim = len(Topics)

EmbeddingDim is the length of every Tip's derived Embedding vector — one dimension per entry in Topics.

View Source
var PublicKey ed25519.PublicKey = mustDecodeKey(publicKeyB64)

PublicKey is the Ed25519 public key that Verify checks manifest signatures against. It is decoded once at package init from publicKeyB64.

View Source
var Topics = []string{
	"auth",
	"sessions",
	"mcp",
	"memory",
	"plugins",
	"worktree",
	"cost-budget",
	"model-selection",
	"output-format",
	"config",
	"diagnostics",
	"updates",
	"automation",
	"onboarding",
	"errors",
}

Topics is the shared taxonomy tip content is tagged against (via DomainScope) and the client's interest vector is scored against, in place of a real embedding model. Order is significant: it fixes each topic's position in every derived Embedding vector.

Appending a new topic is safe — existing embeddings just gain a new always-zero dimension until tips are re-tagged to use it. Reordering or removing a topic invalidates every previously-computed embedding and client-side interest vector; don't do either without a coordinated re-embed of the whole catalog (and bumping catalog_version).

Functions

func Compile

func Compile(tips []Tip) ([]byte, error)

Compile validates tips and marshals them into the single JSON document published as catalog.json.

func EmbeddingFromDomainScope added in v1.1.0

func EmbeddingFromDomainScope(domainScope []string) []float64

EmbeddingFromDomainScope derives a multi-hot vector over Topics from a tip's DomainScope: 1.0 at each recognized topic's position, 0 elsewhere. Unrecognized entries are ignored here — Validate separately rejects an unknown domain_scope topic so authoring typos surface immediately instead of silently vanishing from the embedding.

func Sign

func Sign(data []byte, priv ed25519.PrivateKey) []byte

Sign returns an Ed25519 signature over data using priv. Used by the publish-manifest CI workflow to sign the compiled catalog.json.

func Validate

func Validate(tips []Tip) error

Validate checks every tip in tips for required fields, valid surfaces, matching per-surface render copy, correct embedding dimensionality, recognized domain_scope topics, and duplicate IDs across the set. It returns the first error found.

func Verify

func Verify(data, sig []byte, pub ed25519.PublicKey) bool

Verify reports whether sig is a valid Ed25519 signature over data for pub. Consumers should call this (with PublicKey) before trusting a fetched manifest.

Types

type Render

type Render struct {
	CLI    *RenderContent `json:"cli,omitempty"`
	IOS    *RenderContent `json:"ios,omitempty"`
	VSCode *RenderContent `json:"vscode,omitempty"`
	ADT    *RenderContent `json:"adt,omitempty"`
}

Render holds per-surface copy for a Tip. A field is set only when the corresponding surface appears in the Tip's Surfaces list.

type RenderContent

type RenderContent struct {
	Title string `json:"title"`
	Body  string `json:"body"`
}

RenderContent is the copy shown for one surface.

type Tip

type Tip struct {
	ID                string   `json:"id"`
	Family            string   `json:"family"`
	Surfaces          []string `json:"surfaces"`
	DomainScope       []string `json:"domain_scope,omitempty"`
	PersonaGate       string   `json:"persona_gate,omitempty"`
	TriggerConditions []string `json:"trigger_conditions,omitempty"`
	MinTier           string   `json:"min_tier,omitempty"`
	Cooldown          string   `json:"cooldown,omitempty"`
	Render            Render   `json:"render"`
	DeepLink          string   `json:"deep_link,omitempty"`
	// Embedding is derived automatically from DomainScope by the loader
	// (see EmbeddingFromDomainScope in topics.go) — don't hand-author this
	// in tips/*.json source files; any value present there is overwritten.
	Embedding      []float64 `json:"embedding"`
	CatalogVersion string    `json:"catalog_version"`
}

Tip is one entry in the shared catalog.

func Embedded

func Embedded() ([]Tip, error)

Embedded returns the tip set baked into the binary at compile time — the offline fallback consumers fall back to when a fetched manifest is unavailable or fails signature verification.

func LoadDir

func LoadDir(dir string) ([]Tip, error)

LoadDir reads every *.json file in dir, parses it as a Tip, and validates the resulting set. Tips are returned sorted by ID.

Directories

Path Synopsis
cmd
catalogtool command
Command catalogtool compiles tips/*.json into a single catalog.json and, optionally, signs it with the Ed25519 key in TIP_CATALOG_SIGNING_KEY.
Command catalogtool compiles tips/*.json into a single catalog.json and, optionally, signs it with the Ed25519 key in TIP_CATALOG_SIGNING_KEY.

Jump to

Keyboard shortcuts

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