f4 uses an Out-of-Process RPC architecture based on stdin/stdout and the MessagePack binary protocol.
In earlier versions, f4 experimented with embedded WASM (wazero) and Lua (gopher-lua) interpreters to keep plugins strictly in-process while maintaining safety. This approach was abandoned due to several critical flaws:
- Binary Bloat: Embedding multiple interpreters bloated the
f4core binary. - Platform Access Limitations: WASM (WASI) severely restricts access to native OS capabilities (raw network sockets, complex file system operations), making it nearly impossible to write powerful plugins like process manager or Widows registry editor without building massive, fragile bridging layers.
- Language Lock-in: Forcing developers to write in a specific dialect of Lua constrained ecosystem growth.
By moving to a separate-process model communicating over standard pipes:
- Zero Core Bloat: The
f4binary remains extremely lean. - Language Agnostic: You can write a plugin in Go, Python, Rust, C++, Node.js, or LuaJIT. As long as the process can read/write MessagePack to stdin/stdout, it works.
- Unrestricted Power: Plugins run as native OS processes and can access the network, native libraries, and the full filesystem directly.
- Binary Efficiency: We chose
MessagePackoverJSON-RPCto minimize serialization overhead and reduce data transfer latency for largeReadDirchunks.
f4scans theplugins/directory for executable files.- It launches each executable via
os/exec, hooking into itsstdin,stdout, andstderr. stderris immediately piped tof4's internaldebug.logfor easy debugging.f4sends aPlugin.Initrequest overstdin.- The plugin replies with its capabilities (e.g., registered Virtual File Systems).
- When a user interacts with the plugin's VFS,
f4transparently routesReadDir,Stat,Open, etc., as RPC calls.
For Go developers, an SDK is provided in sdk/f4plugin. It handles all the multiplexing and binary protocol details, exposing a clean, synchronous interface. Check plugins/dummy/main.go for a reference implementation.