How Flow's microkernel design works: core.Bundle is the contract through which bundles contribute actions, modifiers, directives, and operators. Default convention, multi-bundle variants, and local loose packages.
Nexss Flow uses a microkernel-style design: core.Bundle is the contract through which bundles contribute action libraries and compiler extensions. The CLI assembles its built-in bundles, while @require can load a bundle for a flow.
A package's presence under extensions/ alone does not enable it. The CLI must assemble the bundle at startup, or a flow must @require it. This keeps the runtime surface explicit: nothing is silently loaded.
const ID = "loop"
func init() {
core.Register(ID, Bundle)
}
func Bundle(opts map[string]string) core.Bundle {
return core.Bundle{
ID: ID,
Libraries: []action.Library{{Name: ID}},
Primaries: []core.PrimaryExtension{loopKeyword{}},
Fixtures: fixturesFS, // optional embed.FS
}
}ID is a short label ("loop", "sandbox", "fs") — never an import path. It survives forks, module moves, and vendor directories. Two extensions with the same ID panic at init().
Four resolution paths cover remote modules, explicit subpackages, local paths with go.mod, and local loose packages without go.mod.
@require github.com/org/repo automatically appends /nexssflow by convention.@require github.com/org/repo/nexssflow_dev is preserved as-is. Flow does not append /nexssflow.@require ./sub/dir walks upward for go.work or go.mod. If found, resolves natively as a subpackage.@require ./localtest with no ancestor go.mod is auto-vendored into the temporary execution harness as an internal subpackage. **Zero go.mod files are written to the user workspace.**nflow init --bundle.A single repository can provide multiple bundle flavors (dev mocks, production backends, specialized profiles) by naming explicit directories.
my-project/
├── nexssflow/ # Default profile
│ └── library.go
├── nexssflow_dev/ # Development mock profile
│ └── library.go
└── nexssflow_prod/ # Production hardened profile
└── library.go# Uses the custom variant directly without appending /nexssflow
@require github.com/nexssp/my-project/nexssflow_devTo quickly generate an extension bundle inside any existing repository, use nflow init.
# Scaffolds ./nexssflow/library.go in the current directory
nflow init --bundle
# Scaffolds a custom variant ./nexssflow_dev/library.go
nflow init --bundle nexssflow_dev
# Scaffolds a complete starter Flow project in ./my-pipeline
nflow init my-pipelineFlow is language-agnostic. Any repository (Python, Node.js, Rust, C++, or Go) can expose capabilities to Nexss Flow by adding an extension bundle directory.
The shim can be a thin wrapper over external.ExecAction, a sandbox engine, or a direct Go import if the repo is already in Go. This is the path to wire existing business actions directly into AI agent tools, HTTP routers, and orchestration graphs.
Prefer nflows/*.nflow fixtures over inline SelfTest(). A fixture is a real .nflow file the runner executes like any pipeline — it grows with the DSL, with no Go code to change when the feature evolves.
@description "Loop loop(...) until(...)"
@assert: result.n == 3
{ n: 0 } -> loop( { n: .n + 1 } ) until( .n >= 3 )Use inline SelfTest() only when the feature cannot be expressed in pure DSL: temporary files needed outside the workspace (Files: map), subprocesses requiring mocked systems (exec, http.request), or runtime-only middleware without observable state assertions (:cache=, :retry=).