plugins

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Nov 26, 2025 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package plugins defines Aether’s public plugin architecture.

Aether plugins allow developers to extend the Aether system without modifying its core. Plugins are optional, modular components that provide additional data sources, transformations, or renderers.

Plugins MUST respect Aether’s legal and ethical principles:

  • Robots.txt compliance
  • No CAPTCHA bypassing
  • No authentication circumvention
  • No scraping of disallowed or paywalled content

Aether exposes three primary plugin types:

  1. SourcePlugin ---------------- A SourcePlugin provides new legal/public data sources. It receives a free-form query string and returns a plugins.Document representing the fetched content. Source plugins integrate with Aether’s SmartQuery routing engine and high-level Search pipeline.

    Examples: • Custom Hacker News retrieval • Open government datasets • Legally accessible public JSON APIs • Local filesystem loaders

  2. TransformPlugin ---------------- A TransformPlugin receives a normalized plugins.Document and returns a modified/enriched version. Transform plugins are ideal for:

    • Metadata enrichment • Summaries • Entity extraction • Keyword extraction

    Transform plugins are applied after the primary Source pipeline and before final display output.

  3. DisplayPlugin ---------------- A DisplayPlugin renders a plugins.Document into an alternative output format. Markdown is built into Aether’s Display subsystem, but DisplayPlugins allow:

    • ANSI-styled CLI output • HTML rendering • TOON visualization • PDF generation (via legal libraries)

    Display plugins are connected to the Aether Client but operate outside the Markdown core.

Plugin Registration

Plugins are registered through methods exposed on the *aether.Client, for example:

cli := aether.NewClient(...)
cli.RegisterSourcePlugin(myPlugin)
cli.RegisterTransformPlugin(enricher)
cli.RegisterDisplayPlugin(htmlRenderer)

Aether maintains a thread-safe plugin registry. Source plugins are invoked based on SmartQuery routing rules or explicit use. Transform plugins apply to normalized outputs. Display plugins expose new output formats.

Plugin Safety Model

Plugins must never:

  • Modify Aether’s HTTP fetcher
  • Perform raw HTTP calls that ignore robots.txt
  • Attempt to bypass protections or access restricted content

Plugins MAY:

  • Call public APIs that explicitly allow programmatic access
  • Use Aether’s own high-level APIs (Search, OpenAPI, RSS)
  • Operate entirely on normalized documents

Aether enforces these rules by controlling fetch operations: plugins do not receive direct access to the internal HTTP client.

Plugin Document Model

Plugins work with the plugins.Document structure. This structure is intentionally similar to internal/model.Document, but independent of internal implementation details. Aether converts between these two formats during plugin execution.

The plugin Document format is intentionally LLM-friendly and structured.

Purpose and Philosophy

Aether plugins are designed to be:

  • Simple to implement
  • Safe by design
  • Flexible enough for enterprise extension
  • Stable across Aether versions

This package provides only interface definitions and documentation. Registration logic, routing, and execution glue live in the aether package and internal/plugin_registry components.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type DisplayPlugin

type DisplayPlugin interface {
	// Name returns a stable identifier for the display plugin.
	Name() string

	// Description explains what output this plugin produces.
	Description() string

	// Format returns a short format tag such as:
	//   "ansi", "html", "pdf", "text", "custom"
	Format() string

	// Render converts the given Document into the plugin's output
	// format. The returned byte slice may contain text, HTML, binary
	// document data, etc., depending on Format().
	Render(ctx context.Context, doc *Document) ([]byte, error)
}

DisplayPlugin renders a Document into a non-Markdown format.

Examples:

  • ANSI-colored CLI view
  • HTML view
  • PDF output (via a legal PDF library)
  • TOON-derived visual representations

Stage 13 defines the interface, but Aether will connect this into the Display subsystem and CLI/TUI layers in later stages.

type Document

type Document struct {
	// Source is a human-readable identifier for the origin of this
	// document, e.g. "plugin:hackernews", "plugin:my_api", etc.
	Source string `json:"source,omitempty"`

	// URL is an optional canonical URL for the document, if any.
	URL string `json:"url,omitempty"`

	// Kind is the broad category of the document (article, feed, text, etc.).
	Kind DocumentKind `json:"kind,omitempty"`

	// Title is the main title or name of the document.
	Title string `json:"title,omitempty"`

	// Excerpt is a short summary or teaser.
	Excerpt string `json:"excerpt,omitempty"`

	// Content is the primary body text, if there is a single dominant
	// body for the document.
	Content string `json:"content,omitempty"`

	// Metadata is an arbitrary, flat key/value map for additional data.
	Metadata map[string]string `json:"metadata,omitempty"`

	// Sections is an optional list of structured sections, such as
	// article body blocks, feed entries, or metadata sections.
	Sections []Section `json:"sections,omitempty"`
}

Document is the main data structure plugins work with.

It is intentionally similar (but not identical) to Aether's internal normalized document model. Aether will convert between this type and its internal representation during registration / execution.

Plugin authors should focus on filling in as much useful, LLM-friendly content as possible (Title, Excerpt, Content, Sections, Metadata).

type DocumentKind

type DocumentKind string

DocumentKind represents the broad category of a plugin-produced document.

This is intentionally similar to Aether's internal normalized document kinds, but defined separately here to avoid import cycles and to keep the plugin API stable even if internals change.

const (
	DocumentKindUnknown DocumentKind = "unknown"
	DocumentKindArticle DocumentKind = "article"
	DocumentKindHTML    DocumentKind = "html_page"
	DocumentKindFeed    DocumentKind = "feed"
	DocumentKindJSON    DocumentKind = "json"
	DocumentKindText    DocumentKind = "text"
	DocumentKindBinary  DocumentKind = "binary"
)

type Registry

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

Registry holds all registered plugins. It is safe for concurrent use by the Aether client and plugins.

Aether creates one Registry per client instance.

func NewRegistry

func NewRegistry() *Registry

NewRegistry constructs an empty, thread-safe plugin registry. This function is used internally by the Aether client.

func (*Registry) FindDisplayByFormat

func (r *Registry) FindDisplayByFormat(format string) DisplayPlugin

func (*Registry) GetDisplay

func (r *Registry) GetDisplay(name string) DisplayPlugin

GetDisplay returns a DisplayPlugin by name.

func (*Registry) GetSource

func (r *Registry) GetSource(name string) SourcePlugin

GetSource returns a SourcePlugin by name, or nil if not found.

func (*Registry) GetTransform

func (r *Registry) GetTransform(name string) TransformPlugin

GetTransform returns a TransformPlugin by name.

func (*Registry) ListDisplayFormats

func (r *Registry) ListDisplayFormats() []string

ListDisplayFormats returns all supported display formats deduplicated and lexicographically sorted.

func (*Registry) ListDisplays

func (r *Registry) ListDisplays() []string

ListDisplays returns a sorted list of display plugin names.

func (*Registry) ListSources

func (r *Registry) ListSources() []string

ListSources returns a sorted list of SourcePlugin names.

func (*Registry) ListTransforms

func (r *Registry) ListTransforms() []string

ListTransforms returns a sorted list of transform plugin names.

func (*Registry) RegisterDisplay

func (r *Registry) RegisterDisplay(p DisplayPlugin) error

RegisterDisplay registers a DisplayPlugin. Names must be unique.

func (*Registry) RegisterSource

func (r *Registry) RegisterSource(p SourcePlugin) error

RegisterSource registers a SourcePlugin. Names must be unique.

func (*Registry) RegisterTransform

func (r *Registry) RegisterTransform(p TransformPlugin) error

RegisterTransform registers a TransformPlugin. Names must be unique.

type Section

type Section struct {
	Role  SectionRole       `json:"role,omitempty"`
	Title string            `json:"title,omitempty"`
	Text  string            `json:"text,omitempty"`
	Meta  map[string]string `json:"meta,omitempty"`
}

Section is a logical chunk of content within a plugin Document, such as an article body, a feed item, or a metadata block.

type SectionRole

type SectionRole string

SectionRole is a free-form role label for a document section. Common examples: "body", "summary", "feed_item", "metadata".

type SourcePlugin

type SourcePlugin interface {
	// Name returns a short, stable identifier for the plugin.
	// Example: "hackernews", "my_org_api", "eu_press".
	Name() string

	// Description returns a human-readable explanation of what the
	// plugin does, which may be surfaced in logs or introspection.
	Description() string

	// Capabilities declares what kinds of queries or intents this
	// plugin is good at handling. Examples:
	//
	//   []string{"news", "tech", "hn"}
	//   []string{"weather"}
	//
	// Aether’s SmartQuery router can use these tags to decide when
	// to invoke the plugin.
	Capabilities() []string

	// Fetch executes a plugin-specific retrieval based on the incoming
	// query. The query may be a free-form question, a keyword, or a
	// structured string depending on how the plugin is used.
	//
	// The returned Document should be as normalized and clean as the
	// plugin can reasonably make it.
	Fetch(ctx context.Context, query string) (*Document, error)
}

SourcePlugin is responsible for providing new documents from legal, public data sources. Examples:

  • A Hacker News source plugin
  • A public government dataset plugin
  • A custom internal API plugin (when used in a private deployment)

SourcePlugin implementations should be stateless or internally safe for concurrent use.

type TransformPlugin

type TransformPlugin interface {
	// Name returns a stable identifier for this transform plugin.
	Name() string

	// Description describes what transformation this plugin performs.
	Description() string

	// Apply transforms the input Document and returns the resulting
	// Document. Implementations may modify the input in place or
	// allocate a new Document, but must document their behavior.
	Apply(ctx context.Context, doc *Document) (*Document, error)
}

TransformPlugin receives an existing Document and returns a new (or modified) Document. Examples:

  • Post-hoc summarization
  • Keyword extraction
  • Entity extraction
  • Additional metadata enrichment

Transform plugins must be pure functions in spirit: given the same input Document, they should produce the same output Document, barring non-deterministic external services.

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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