plugin

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: May 3, 2026 License: MIT Imports: 30 Imported by: 0

Documentation

Overview

Package plugin defines the stable ABI for out-of-tree Praxis capability handlers (Phase 3 M3.1).

A plugin is a Go module that exports a `Plugin` symbol implementing this package's Plugin interface. The Praxis runtime loads it via the standard plugin discovery flow (manifest.json + signature verification, both of which are layered on top of this ABI in follow-up tasks):

  1. Plugin author writes a Go package exporting `var Plugin praxis.Plugin = ...`
  2. The author signs the build with cosign and places the artefact + manifest.json in $PRAXIS_PLUGIN_DIR.
  3. Praxis verifies the signature against a configured root, loads the symbol, and registers each Capability returned by Capabilities() with the in-process registry.

ABI version: v1. Breaking changes to this interface bump ABIVersion and the runtime refuses to load older plugins. Additive changes (new optional methods on the Plugin interface) are signalled by minor-version bumps and remain compatible.

Index

Constants

View Source
const (
	ResultSuccess        = "success"
	ResultManifest       = "manifest_invalid"
	ResultArtifact       = "artifact_missing"
	ResultUnsafeArtifact = "unsafe_artifact"
	ResultDuplicate      = "duplicate_name"
	ResultManifestMiss   = "manifest_missing"
	ResultSignature      = "signature_failed"
	ResultNoTrustedKeys  = "no_trusted_keys"
	ResultABIMismatch    = "abi_mismatch"
	ResultDlopen         = "dlopen_failed"
	ResultLoad           = "load_failed"
	ResultCrashed        = "crashed" // post-load: child process or IPC stream died
)

Failure-cause labels used by callers to populate the praxis_plugin_load_total{result} metric. Stable strings — operators build alerts against them.

View Source
const ABIVersion = "v1"

ABIVersion is the major version of the plugin ABI. Bump on any breaking change to Plugin or Handler.

View Source
const CertificateExtension = ".cert"

CertificateExtension is the suffix Praxis appends to a plugin artefact path to locate the keyless certificate emitted by Fulcio. `cosign sign-blob --output-certificate plugin.so.cert` produces this file unchanged.

View Source
const ManifestFilename = "manifest.json"

ManifestFilename is the fixed filename Praxis looks for in each plugin directory under PRAXIS_PLUGIN_DIR.

View Source
const SignatureExtension = ".sig"

SignatureExtension is the suffix Praxis appends to a plugin artefact path to locate its detached signature. Keeping the convention identical to `cosign sign-blob --output-signature plugin.so.sig` so operators can sign with the upstream tool unchanged.

View Source
const SymbolName = "Plugin"

SymbolName is the exported variable plugin authors must define. The runtime looks up this symbol after dlopen and asserts its type to the Plugin interface.

Variables

View Source
var (
	ErrManifestMissing = errors.New("manifest.json not found")
	ErrManifestInvalid = errors.New("manifest.json invalid")
	ErrUnsafeArtifact  = errors.New("artifact path escapes plugin directory")
	ErrArtifactMissing = errors.New("artifact file not found")
	ErrDuplicateName   = errors.New("duplicate plugin name")
)

Sentinel errors. Callers use errors.Is to branch on the failure mode.

View Source
var (
	ErrCertificateMissing   = errors.New("plugin certificate file not found")
	ErrCertificateUntrusted = errors.New("plugin certificate did not chain to a trusted Fulcio root")
	ErrCertificateExpired   = errors.New("plugin certificate expired or not yet valid")
	ErrIdentityMismatch     = errors.New("plugin certificate identity not in trust policy")
	ErrNoFulcioRoots        = errors.New("no Fulcio roots configured for keyless verification")
)

Sentinel errors. Operators branch on these to log precise reasons in strict-mode failures.

View Source
var (
	ErrSignatureMissing = errors.New("plugin signature file not found")
	ErrSignatureInvalid = errors.New("plugin signature does not verify under any trusted key")
	ErrNoTrustedKeys    = errors.New("no trusted plugin keys configured")
)

Sentinel errors. Callers branch on these to decide between "this load is forbidden, refuse" and "operator misconfiguration, fail loud".

View Source
var ErrEgressBlocked = errors.New("plugin egress blocked: host not in allowlist")

ErrEgressBlocked signals that a sandboxed plugin attempted to reach a host outside its declared AllowedHosts. The wrapped handler surfaces this error directly so audit detail records the blocked destination.

View Source
var ErrPluginNotLoaded = errors.New("plugin not loaded")

ErrPluginNotLoaded signals a reload request against a plugin name the Manager has no record of — typically a typo or a plugin that failed its initial load.

Functions

func BudgetEnvForTest

func BudgetEnvForTest(env []string, budget ResourceBudget) []string

BudgetEnvForTest exposes budgetEnv to the package's external test suite. Production callers should not depend on this.

func ClassifyError

func ClassifyError(err error) string

ClassifyError maps a per-plugin error to one of the Result* constants. Falls back to ResultLoad for unrecognised errors so the metric always labels something.

func HTTPClient

func HTTPClient(ctx context.Context) *http.Client

HTTPClient retrieves the sandbox-supplied http.Client from ctx. Plugin authors call this for every outbound HTTP request — the returned client honours the plugin's AllowedHosts policy. Returns nil if the context carries no sandbox client (handler is not sandboxed).

func Load

func Load(ctx context.Context, p Plugin, loader Loader) error

Load is the canonical plugin-load helper. The runtime calls this once per discovered plugin. It validates the ABI version, runs Capabilities, and routes each Registration through the supplied Loader.

If the plugin implements BudgetedPlugin, every handler in every Registration is wrapped in a Sandboxed wrapper that enforces the declared ResourceBudget. Plugins that don't opt in load unwrapped — existing untrusted-plugin-rejection happens upstream of Load (manifest validation + signature verification).

Returning an error short-circuits load — a partial registration is rolled back by the caller (the runtime must not allow half-loaded plugins).

func LoadFulcioRoots added in v0.2.0

func LoadFulcioRoots(paths []string) ([]*x509.Certificate, error)

LoadFulcioRoots reads PEM-encoded certificates (one or many per file) from each path. Mixed PEM bundles are supported so operators can drop the standard Sigstore `root.pem` in unchanged.

func LoadTrustedKeys

func LoadTrustedKeys(paths []string) ([]*ecdsa.PublicKey, error)

LoadTrustedKeys reads each PEM-encoded ECDSA P-256 public key from the given paths and returns the parsed bundle. Any unreadable file or non-ECDSA key fails the load — partial trust silently dropping a key would let an operator believe a stricter policy was active than really is.

func LoadWithHooks

func LoadWithHooks(ctx context.Context, p Plugin, loader Loader, hooks *LoadHooks) error

LoadWithHooks is Load with an optional WrapHandler hook. Used by the Manager to layer versioned-handler tracking on top of the existing sandbox wrapping without forking the load pipeline.

func Sandboxed

func Sandboxed(inner capability.Handler, budget ResourceBudget) capability.Handler

Sandboxed wraps a handler so each Execute and Simulate call runs under the supplied budget. The wrapper is always-on: if the caller invokes Sandboxed, the handler is sandboxed. Use this only when the budget was explicitly declared (e.g. plugin author opted in via BudgetedPlugin).

func VerifyDiscovered

func VerifyDiscovered(d Discovered, keys []*ecdsa.PublicKey) error

VerifyDiscovered verifies the cosign-blob signature for a Discovered plugin against the configured trust bundle. The signature is expected at <artifact>.sig as base64-encoded ASN.1 DER over SHA-256(artifact), matching `cosign sign-blob` output exactly.

Returns:

  • nil on a successful verification.
  • ErrNoTrustedKeys when keys is empty (fail-closed: never load unsigned plugins by accident if trust isn't configured).
  • ErrSignatureMissing if the .sig file is absent.
  • ErrSignatureInvalid if no trusted key validates the signature (covers wrong key, tampered artefact, malformed sig).

func VerifyKeyless added in v0.2.0

func VerifyKeyless(d Discovered, v KeylessVerifier) error

VerifyKeyless validates that the discovered plugin was signed under a Fulcio-issued certificate that:

  1. chains to a trusted root,
  2. was valid at signing time,
  3. encodes a (SAN, issuer) pair on the operator's allowlist, and
  4. produced an ECDSA signature that verifies over SHA-256(artifact).

The artefact's signature still lives at <artifact>.sig (cosign sign-blob format), and the certificate at <artifact>.cert. Returns nil only when every check passes.

Types

type ABIMismatchError

type ABIMismatchError struct {
	Want, Got string
}

ABIMismatchError signals an ABI-version mismatch between runtime and plugin.

func (*ABIMismatchError) Error

func (e *ABIMismatchError) Error() string

Error implements error.

type BudgetedPlugin

type BudgetedPlugin interface {
	Plugin
	Budget() ResourceBudget
}

BudgetedPlugin is the optional interface a plugin implements to declare its resource budget. The loader detects this via type assertion so the stable Plugin interface (ABI v1) does not break for plugins that don't opt in.

type DefaultOpener

type DefaultOpener struct{}

DefaultOpener loads a plugin artefact via Go's stdlib plugin package. Available on linux + darwin only; other platforms get the noop opener that always errors out (see opener_unsupported.go).

func (DefaultOpener) Open

func (DefaultOpener) Open(artefactPath string) (Plugin, error)

Open implements Opener.

type Discovered

type Discovered struct {
	Dir      string   // absolute path to the plugin directory
	Manifest Manifest // identity + provenance subset of the disk manifest
	ABI      string   // declared ABI version (validated against ABIVersion at load time)
	Artifact string   // absolute path to the plugin artefact file
}

Discovered is one validated plugin found on disk. The runtime consumes this list at startup, verifies signatures (follow-up task), then loads each artefact and calls plugin.Load.

type DiscoveryError

type DiscoveryError struct {
	Dir string
	Err error
}

DiscoveryError carries a per-plugin failure surfaced by Discover. The scan continues past these so a single bad plugin cannot hide healthy siblings.

func (*DiscoveryError) Error

func (e *DiscoveryError) Error() string

Error implements error.

func (*DiscoveryError) Unwrap

func (e *DiscoveryError) Unwrap() error

Unwrap exposes the underlying cause to errors.Is/As.

type DiscoveryResult

type DiscoveryResult struct {
	Plugins []Discovered
	Errors  []DiscoveryError
}

DiscoveryResult separates clean plugins from per-plugin errors so callers can decide whether to fail-closed (any error aborts startup) or fail-open (log errors, register healthy plugins).

func Discover

func Discover(root string) (DiscoveryResult, error)

Discover scans root for plugin directories. Each immediate subdirectory of root is treated as a candidate plugin: it must contain manifest.json declaring name, version, abi, and artifact. Files in root and other non-directory entries are ignored silently. Subdirectories without a manifest.json surface as ErrManifestMissing.

Per-plugin failures populate Errors and the scan continues. The first successfully discovered plugin with a given name wins; later duplicates surface as ErrDuplicateName. Plugins are returned sorted by name for deterministic startup behaviour.

type DiskManifest

type DiskManifest struct {
	Manifest
	ABI      string `json:"abi"`
	Artifact string `json:"artifact"`
}

DiskManifest is the on-disk manifest schema. It extends the in-process Manifest with deployment metadata: the ABI version the plugin was built against and the artefact filename relative to the plugin directory.

type Identity added in v0.2.0

type Identity struct {
	SubjectGlob string
	Issuer      string
}

Identity is one allowed (subject, issuer) pair. SubjectGlob accepts a literal SAN value or a single-asterisk suffix wildcard ("https://github.com/felixgeelhaar/*"). Issuer is matched literally against the OIDC issuer extension.

type KeylessVerifier added in v0.2.0

type KeylessVerifier struct {
	FulcioRoots       []*x509.Certificate
	Intermediates     []*x509.Certificate
	TrustedIdentities []Identity
	Now               func() time.Time
}

KeylessVerifier holds the trust policy for Fulcio-issued plugin signatures. Zero value is unusable: callers must populate at least FulcioRoots and TrustedIdentities before VerifyKeyless will succeed.

FulcioRoots is the operator's pinned root bundle (typically the production Sigstore root + any private Fulcio instance). Intermediates is optional — `cosign sign-blob` already attaches the chain inside the leaf cert when present.

TrustedIdentities is the allowlist that gates which build identities may produce loadable plugins. Any cert whose (SAN, issuer) pair fails to match every entry is rejected with ErrIdentityMismatch.

Now is injected so tests can pin a deterministic clock; production callers leave it nil for time.Now.

type LoadEvent

type LoadEvent struct {
	Name        string
	Version     string
	ABI         string
	Dir         string
	ArtifactSHA string
	Result      string
	Err         error
}

LoadEvent reports a single plugin's load outcome with enough metadata for /metrics labelling and `praxis plugins list` rendering. Phase 4.

type LoadHooks

type LoadHooks struct {
	// WrapHandler runs against every Registration's handler after the
	// optional Sandboxed wrap. The plugin's Manifest is supplied so the
	// caller can record per-plugin state. Returning the same handler
	// unchanged is the no-op default.
	WrapHandler func(manifest Manifest, h capability.Handler) capability.Handler

	// OnLoaded fires once after every Registration has been forwarded
	// to the Loader, with the plugin instance and the (possibly
	// wrapped) registrations the runtime now sees. Used by the Manager
	// to wire Watchable crash detection and record per-plugin
	// capability names. Phase 4 out-of-process loader.
	OnLoaded func(p Plugin, regs []Registration)
}

LoadHooks lets callers (the Manager) wrap handlers post-sandbox and post-budgeting. A nil LoadHooks reduces to the original Load behaviour. Phase 4 graceful rollover.

type Loader

type Loader interface {
	Register(reg Registration) error
}

Loader is the runtime interface that registers a plugin's capabilities. Implemented by cmd/praxis at startup; tested in this package against a fake plugin to lock down the contract.

type Manager

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

Manager owns the runtime state of loaded plugins. It serialises load and reload calls so a watcher event and a SIGHUP-driven full re-scan don't race against each other.

func NewManager

func NewManager(cfg ManagerConfig) *Manager

NewManager constructs a Manager. Mandatory fields (Dir, Loader, Opener) are validated lazily — LoadAll surfaces missing wiring as a clear error rather than panicking at construction.

func (*Manager) Drain

func (m *Manager) Drain(ctx context.Context, name string) error

Drain blocks until every retired wrapper for the given plugin has completed its in-flight calls. New traffic, which already routes to the post-reload version, is unaffected. Returns immediately if the plugin has no retired wrappers (fresh load with no prior version).

Drained wrappers are removed from the retired pool so a follow-up Drain call against the same name returns instantly rather than re-walking already-completed calls.

func (*Manager) LoadAll

func (m *Manager) LoadAll(ctx context.Context) (PipelineResult, error)

LoadAll runs the full discover→verify→open→Load pipeline once and records the outcome of every plugin. Returns the underlying pipeline error only if discovery fails outright; per-plugin failures populate the Manager's loaded state and are surfaced via OnEvent.

Existing wrappers are retired before the new pipeline runs so the graceful drain semantics apply across full reloads — in-flight calls finish on the version they started with, and Drain(name) on the retired wrapper unblocks once they do.

func (*Manager) ReloadOne

func (m *Manager) ReloadOne(ctx context.Context, name string) error

ReloadOne re-runs the pipeline scoped to a single plugin directory. The lookup is by plugin Name (the one returned by Manifest()), not by directory path — operators reload by capability identity, not by filesystem layout.

The plugin's previous wrappers are retired before the new ones are registered so in-flight calls drain naturally; Drain(name) is the supported way to wait for that completion.

func (*Manager) Snapshot

func (m *Manager) Snapshot() []LoadEvent

Snapshot returns the current set of loaded plugins, sorted by name for deterministic CLI rendering.

type ManagerConfig

type ManagerConfig struct {
	Dir         string
	TrustedKeys []*ecdsa.PublicKey
	Keyless     *KeylessVerifier
	Loader      Loader
	Opener      Opener
	Unregister  func(capName string)
	OnEvent     func(LoadEvent)
}

ManagerConfig parameters the plugin Manager. Loader, Opener, and Dir are required; TrustedKeys may be empty (the load pipeline will then reject every plugin via ErrNoTrustedKeys, which is the safe default).

Unregister, when set, is invoked for every capability name the Manager needs to remove from the runtime registry on a plugin crash. The host wires this to capability.Registry.Unregister so the in-process registry stays consistent with the Manager's snapshot of loaded plugins.

type Manifest

type Manifest struct {
	Name        string `json:"name"`
	Version     string `json:"version"`
	Author      string `json:"author,omitempty"`
	Description string `json:"description,omitempty"`
	Homepage    string `json:"homepage,omitempty"`
	License     string `json:"license,omitempty"`
}

Manifest describes the plugin's identity and build provenance. Required fields: Name, Version. Optional fields surface in audit detail.

type Opener

type Opener interface {
	Open(artefactPath string) (Plugin, error)
}

Opener loads a plugin artefact from disk and returns its exported Plugin symbol. The default implementation (DefaultOpener) wraps Go's stdlib `plugin` package and is build-tagged to Linux+macOS only — platforms where Go plugin loading is supported. Tests inject a fake Opener to exercise the pipeline without producing real .so artefacts.

type PipelineConfig

type PipelineConfig struct {
	Dir         string
	TrustedKeys []*ecdsa.PublicKey
	// Keyless, when populated with at least one Fulcio root, switches
	// the pipeline to keyless verification for any plugin that ships a
	// `<artifact>.cert` file. Plugins that do not ship a certificate
	// fall back to TrustedKeys (PEM-key path) so the two modes coexist
	// during a migration.
	Keyless *KeylessVerifier
	Loader  Loader
	Opener  Opener
	// LoadHooks is forwarded to LoadWithHooks for every plugin loaded
	// through the pipeline. Optional; nil reduces to the unhookable
	// Load path.
	LoadHooks *LoadHooks
}

PipelineConfig parameters the runtime plugin-load pipeline. Dir, Loader and Opener are required; TrustedKeys is required as soon as any plugin is discovered (the pipeline fail-closes when it finds a plugin with no trust bundle to verify against, even if Strict is false).

type PipelineError

type PipelineError struct {
	Dir string
	Err error
}

PipelineError pairs a discovered plugin's directory with the reason it failed to load. Wraps the underlying error so errors.Is/As works against the sentinel set (ErrSignatureMissing, ErrSignatureInvalid, ErrNoTrustedKeys, ABIMismatchError, dlopen and Capabilities errors).

func (*PipelineError) Error

func (e *PipelineError) Error() string

Error implements error.

func (*PipelineError) Unwrap

func (e *PipelineError) Unwrap() error

Unwrap exposes the underlying cause.

type PipelineResult

type PipelineResult struct {
	Loaded []Discovered
	Errors []PipelineError
}

PipelineResult describes the outcome of one Pipeline run. Loaded is the set of plugins that successfully reached the registry; Errors captures every per-plugin failure so the caller can decide whether to log, fail-soft, or abort.

func RunPipeline

func RunPipeline(ctx context.Context, cfg PipelineConfig) (PipelineResult, error)

RunPipeline executes the discover → verify → open → Load chain over every subdirectory of cfg.Dir. Per-plugin failures populate the returned PipelineResult.Errors and never stop the sweep — one bad plugin must not hide its healthy siblings. The function returns a hard error only when the operator-level setup is wrong: the plugin directory is missing, or filesystem walk fails.

Empty cfg.Dir is a no-op (plugin discovery disabled).

type Plugin

type Plugin interface {
	// ABI reports the ABI version this plugin was built against. Plugins
	// MUST return ABIVersion (the constant in this package as compiled at
	// build time). The runtime refuses to load plugins whose ABI does not
	// match the runtime's ABIVersion.
	ABI() string

	// Manifest returns identity + provenance metadata. Authors set Name
	// and Version; the runtime validates Name uniqueness against already-
	// registered capabilities and surfaces Version in audit detail.
	Manifest() Manifest

	// Capabilities returns one or more (descriptor, handler) pairs for
	// registration. A plugin may expose multiple capabilities — convenient
	// when one vendor has several related actions (e.g. github_create_issue
	// + github_add_comment).
	Capabilities(ctx context.Context) ([]Registration, error)
}

Plugin is the symbol every plugin must export. The runtime calls Capabilities() at load time and registers each returned descriptor + handler with the registry.

type ProcessOpener

type ProcessOpener struct {
	Binary string
	Budget ResourceBudget

	// CgroupParent, when non-empty, names a cgroup v2 subtree under
	// which each spawned plugin host runs. Phase 5: when the host
	// detects cgroup v2 availability the bootstrap sets this to
	// /sys/fs/cgroup/praxis so memory.max + cpu.max enforce the
	// declared budget. Empty falls back to the setrlimit-only path.
	CgroupParent string

	// OnUsageReport, when set, receives the cgroup-recorded high-water
	// memory peak and cumulative CPU time for the plugin just before
	// the cgroup is reclaimed on Close. Bootstrap wires this to the
	// praxis_plugin_memory_peak_bytes / praxis_plugin_cpu_seconds_total
	// metrics. Phase 5 t-cgroup-v2-usage-metrics.
	OnUsageReport func(pluginName string, peakBytes uint64, cpuNs uint64)

	// SpawnFn is the test seam: production uses exec.Command, tests
	// supply a custom transport pair without touching the OS.
	SpawnFn func(ctx context.Context, artefactPath string) (io.WriteCloser, io.ReadCloser, func() error, error)
	// contains filtered or unexported fields
}

ProcessOpener is an Opener implementation that spawns a praxis-pluginhost child process per plugin and proxies the Plugin interface over IPC. Phase 4 out-of-process loader.

The Binary field is the absolute path to the praxis-pluginhost binary; tests inject their own command for round-tripping the protocol against an in-process echo server. Budget, when non-zero, is forwarded to the child via PRAXIS_PLUGIN_BUDGET_* env vars and the child applies setrlimit at startup.

func (*ProcessOpener) Open

func (o *ProcessOpener) Open(artefactPath string) (Plugin, error)

Open spawns a child host for artefactPath and returns a Plugin that forwards every call across the IPC boundary. Manifest is fetched eagerly so the parent can fail fast on a child that doesn't speak the protocol.

type Registration

type Registration struct {
	Capability domain.Capability
	Handler    capability.Handler
}

Registration pairs a Capability descriptor with the handler that runs it. Returned by Plugin.Capabilities and consumed by the runtime registrar.

type ResourceBudget

type ResourceBudget struct {
	CPUTimeout     time.Duration
	MaxMemoryBytes uint64
	AllowedHosts   []string
}

ResourceBudget caps what a plugin handler may consume during a single Execute or Simulate call. Plugins opt in by implementing BudgetedPlugin; unknown plugins run unsandboxed.

Phase 3 M3.1 enforces:

  • CPUTimeout: real, via context.WithTimeout. Zero disables the cap.
  • AllowedHosts: real, via a runtime-supplied http.Client whose transport rejects unlisted destinations. Plugins that bypass the supplied client (e.g. instantiate their own net.Dialer) defeat this layer; the contract is "use plugin.HTTPClient(ctx) for any outbound call."
  • MaxMemoryBytes: NOT enforced in-process. Go's runtime does not expose per-handler accounting and the global allocator is shared with the rest of Praxis. The field is reserved so plugin authors can declare their intended ceiling today; the out-of-process loader (future task) will hold it to that limit.

type Watchable

type Watchable interface {
	Watch() <-chan error
}

Watchable is implemented by Plugin variants whose underlying transport can fail asynchronously — the out-of-process loader is the canonical example. The Manager type-asserts every loaded plugin against Watchable; matching plugins get a goroutine that listens for crash events and triggers capability deregistration. Phase 4 out-of-process loader (M3.1).

type Watcher

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

Watcher monitors PRAXIS_PLUGIN_DIR and triggers OnReload when a plugin's manifest.json or .sig changes. Sub-second event bursts are coalesced via Debounce so a single edit doesn't cause five reloads.

The watcher is opt-in: callers control startup (no goroutine starts implicitly) and pass the cancel context that ends the loop.

func NewWatcher

func NewWatcher(cfg WatcherConfig) (*Watcher, error)

NewWatcher constructs a Watcher rooted at cfg.Root. Returns an error if fsnotify cannot watch the directory (root missing, permissions, platform unsupported). Debounce defaults to 200ms.

func (*Watcher) Run

func (w *Watcher) Run(ctx context.Context)

Run blocks until ctx is cancelled, dispatching plugin reload events. New plugin subdirectories created at runtime are auto-watched so the operator can drop a fresh plugin into the directory and have it loaded without a process restart.

type WatcherConfig

type WatcherConfig struct {
	Root     string
	OnReload func(pluginDir string)
	Debounce time.Duration
}

WatcherConfig parameters the plugin-directory watcher. Root is the directory to watch (PRAXIS_PLUGIN_DIR); OnReload is invoked with the affected plugin directory after a debounce window. Debounce coalesces bursts of FS events (a manifest rewrite often produces several writes per second) into a single reload.

Directories

Path Synopsis
Package cgroup probes the host for cgroup v2 support and the presence of a delegated subtree the praxis runtime can use to enforce per-plugin memory and CPU caps.
Package cgroup probes the host for cgroup v2 support and the presence of a delegated subtree the praxis runtime can use to enforce per-plugin memory and CPU caps.
Package ipc carries the wire protocol between Praxis and a praxis-pluginhost child process.
Package ipc carries the wire protocol between Praxis and a praxis-pluginhost child process.

Jump to

Keyboard shortcuts

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