F-Mesh is a Flow-Based Programming (FBP) framework that lets you build applications as a graph of independent, reusable components. Think of it as connecting building blocks with pipes - data flows through your program like water through a network of connected components.
Inspired by J. Paul Morrison's FBP, F-Mesh brings the power of dataflow programming to Go with a clean, type-safe API.
go get github.com/hovsep/fmeshHere's a simple mesh that concatenates two strings and converts them to uppercase:
package main
import (
"fmt"
"os"
"strings"
"github.com/hovsep/fmesh"
"github.com/hovsep/fmesh/component"
"github.com/hovsep/fmesh/signal"
)
func main() {
if err := run(); err != nil {
fmt.Println("Error:", err)
os.Exit(1)
}
}
func run() error {
// Create the components
concat, err := component.New("concat",
component.WithInputs("i1", "i2"),
component.WithOutputs("res"),
component.WithActivationFunc(func(this *component.Component) error {
word1 := this.InputByName("i1").Signals().FirstPayloadOrDefault("").(string)
word2 := this.InputByName("i2").Signals().FirstPayloadOrDefault("").(string)
return this.OutputByName("res").PutSignals(signal.New(word1 + word2))
}))
if err != nil {
return err
}
uppercase, err := component.New("uppercase",
component.WithInputs("i1"),
component.WithOutputs("res"),
component.WithActivationFunc(func(this *component.Component) error {
str := this.InputByName("i1").Signals().FirstPayloadOrDefault("").(string)
return this.OutputByName("res").PutSignals(signal.New(strings.ToUpper(str)))
}))
if err != nil {
return err
}
// Create the mesh
fm, err := fmesh.New("hello world")
if err != nil {
return err
}
if err = fm.AddComponents(concat, uppercase); err != nil {
return err
}
// Connect components via a pipe
if err = concat.OutputByName("res").PipeTo(uppercase.InputByName("i1")); err != nil {
return err
}
// Set initial inputs
if err = concat.InputByName("i1").PutSignals(signal.New("hello ")); err != nil {
return err
}
if err = concat.InputByName("i2").PutSignals(signal.New("world!")); err != nil {
return err
}
// Run the mesh
if _, err = fm.Run(); err != nil {
return err
}
// Get the result
result, err := uppercase.OutputByName("res").Signals().FirstPayload()
if err != nil {
return err
}
fmt.Printf("Result: %v\n", result) // Result: HELLO WORLD!
return nil
}Build complex workflows from simple, reusable components. Each component is independent and testable.
Extend behavior at any execution point - mesh lifecycle, cycles, component activations, and port operations:
fm.SetupHooks(func(h *fmesh.Hooks) {
h.BeforeRun(func(fm *fmesh.FMesh) error {
fmt.Println("Starting mesh...")
return nil
})
h.AfterCycle(func(ctx *fmesh.CycleContext) error {
fmt.Printf("Cycle #%d complete\n", ctx.Cycle.Number())
return nil
})
})Run() returns a RuntimeInfo report with per-cycle activation results and timing — history retention is configurable for long runs.
Tag signals, components, and ports with labels (string) and scalars (numeric), then filter, route, and aggregate them with consistent collection APIs.
Components activate in cycles (artificial "time"), allowing multiple components to process simultaneously - like lighting multiple lamps at once.
Fluent, consistent interfaces with direct error returns — no hidden error state, no surprises.
All components in a single activation cycle run concurrently - no need to manage goroutines or other concurrency primitives yourself.
| Concept | Description |
|---|---|
| Component | The main building block - has inputs, outputs, and an activation function |
| Port | Entry/exit points on components. Unlimited inputs and outputs per component |
| Pipe | Connects an output port to an input port to transfer data |
| Signal | Data packets flowing through pipes. Type-agnostic with optional labels |
| Cycle | One "tick" of execution where all ready components activate |
F-Mesh excels at:
- Data transformation pipelines - ETL, data processing, format conversion
- Workflow automation - Multi-step business processes
- Computational graphs - Scientific computing, simulations
- Game logic - Entity systems, behavior trees
- Stream processing - Event handling, reactive systems
- Experimental architectures - Prototyping dataflow designs
- Wiki - Full documentation (source lives in
docs/wiki— edit via PR, it is auto-synced to the wiki) - Examples Repository - Working examples and patterns
- API Reference - Complete API docs
- Flow-Based Programming - Learn about FBP (by J. Paul Morrison)
F-Mesh is not a classical FBP implementation:
- Not suitable for long-running components
- No wall-clock time events (timers, tickers)
- Components execute in discrete cycles, not real-time
For real-time streaming or long-running processes, consider alternatives like traditional FBP systems or message queues.
Contributions are welcome! Please read the contributing guidelines, then:
- Check existing issues or create a new one
- Fork the repository
- Create a feature branch
- Submit a pull request
MIT License - see LICENSE file for details.
Made by @hovsep
Star us on GitHub if you find F-Mesh useful!
