A next-generation terminal UI framework for Go featuring reactive state management, first-class command engine, secure plugins, and modern rendering.
DRAV (Sanskrit: द्रव, meaning "fluid" or "dynamic") is a comprehensive framework for building sophisticated terminal user interfaces in Go. Unlike traditional TUI libraries that require manual state synchronization and event wiring, DRAV provides:
- 🔄 Reactive State: Observable values that automatically trigger UI updates
- ⌨️ Command Engine: Built-in command palette with completion, history, and undo/redo
- 🧩 Plugin System: Hot-loadable, capability-secured plugins (WASM/out-of-process)
- 🎨 Modern Renderer: Diff-based rendering with flexbox-inspired layouts
- 🚀 Performance: 60 FPS targeting with <50MB baseline memory
- 🛡️ Security: Capability-based plugin isolation and input sanitization
go get github.com/TIVerse/dravpackage main
import (
"context"
"github.com/TIVerse/drav/pkg/dravya"
"github.com/TIVerse/drav/pkg/maya"
)
func main() {
app := dravya.NewApp()
// Set root component
app.SetRoot(maya.Text("Hello, DRAV! 🌊"))
// Run application
if err := app.Run(context.Background()); err != nil {
panic(err)
}
}package main
import (
"context"
"fmt"
"github.com/TIVerse/drav/pkg/dravya"
"github.com/TIVerse/drav/pkg/prana"
"github.com/TIVerse/drav/pkg/maya"
"github.com/TIVerse/drav/pkg/agni"
)
type Counter struct {
count *prana.Observable[int]
}
func (c *Counter) Render(ctx maya.RenderContext) maya.View {
return maya.Column(
maya.Text(fmt.Sprintf("Count: %d", c.count.Get())),
maya.Text("Press [+] to increment, [-] to decrement"),
)
}
func main() {
app := dravya.NewApp()
counter := &Counter{
count: prana.NewObservable(0),
}
// Handle keyboard input
// (event hub integration to be added)
app.SetRoot(counter)
if err := app.Run(context.Background()); err != nil {
panic(err)
}
}DRAV consists of seven core modules, each named after Sanskrit concepts:
- Dravya (द्रव्य): Runtime core — lifecycle, concurrency, main loop
- Agni (अग्नि): Event hub — dispatch, priorities, timers
- Māyā (माया): Renderer — virtual UI, diff, layout engine
- Prāṇa (प्राण): Reactive state — observables, stores, effects
- Vāk (वाक्): Command engine — parse, execute, history, undo/redo
- Vāyu (वायु): Plugin system — WASM/process loaders, capabilities
- Śrī (श्री): Theme engine — palettes, styles, animations
- Framework over Library: DRAV owns the main loop and coordinates all subsystems
- Reactive by Default: State changes automatically propagate to the UI
- Security First: Capability-based isolation for plugins and untrusted code
- Performance Engineering: Profiled, benchmarked, and optimized for 60 FPS
- Developer Experience: Quick starts, debugging tools, comprehensive docs
// Observable values
count := prana.NewObservable(0)
count.Watch(func(old, new int) {
fmt.Printf("Count changed: %d -> %d\n", old, new)
})
count.Set(42)
// Computed values with dependency tracking
doubled := prana.ComputedFromObservable(count, func(n int) int {
return n * 2
})
// Stores with actions and effects
type AppState struct {
User string
LoggedIn bool
}
store := prana.NewStore(AppState{})
store.RegisterReducer("LOGIN", func(state AppState, payload any) AppState {
state.User = payload.(string)
state.LoggedIn = true
return state
})// Priority-based event dispatch
dispatcher := agni.NewDispatcher(1000, 10)
// Register handlers
unsubscribe := dispatcher.On(agni.EventTypeKey, func(ctx context.Context, event agni.Event) error {
keyEvent := event.(*agni.KeyEvent)
fmt.Printf("Key pressed: %c\n", keyEvent.Rune)
return nil
}, agni.WithPriority(agni.PriorityHigh))
// Emit events
dispatcher.Emit(ctx, agni.NewKeyEvent(agni.KeyRune, 'a', agni.ModNone, false))
// Timers
dispatcher.After(ctx, "timeout", 5*time.Second, func(ctx context.Context) {
fmt.Println("Timeout!")
})// Register commands
registry.Register(vak.Command{
Name: "theme",
Summary: "Switch theme",
Flags: []vak.Flag{{Name: "name", Type: "string"}},
Execute: func(ctx context.Context, args []string) (vak.Result, error) {
// Switch theme logic
return vak.Success("Theme changed"), nil
},
Undo: func(ctx context.Context) error {
// Restore previous theme
return nil
},
})
// Execute with autocomplete
result, err := registry.Execute(ctx, "theme --name dark")// Load a WASM plugin with capabilities
plugin, err := pluginMgr.Load("./plugins/myplugin.wasm", vayu.Capabilities{
Filesystem: vayu.FSCapability{
Read: []string{"/tmp"},
Write: []string{"/tmp/output"},
},
Network: vayu.NetworkCapability{
AllowedDomains: []string{"api.example.com"},
},
})DRAV includes comprehensive testing infrastructure:
# Run tests
make test
# With coverage
make cover
# Benchmarks
make bench
# E2E tests
go test ./tests/e2e/...
# Fuzz tests
go test -fuzz=FuzzDiff ./tests/fuzz/- 60 FPS target: ~16ms per frame budget
- Baseline memory: <50MB for typical applications
- Startup time: <500ms
- Plugin load: <200ms (WASM)
Performance is continuously monitored with:
- pprof integration
- Frame timing metrics
- Memory profiling
- CI performance gates
- Input sanitization: ANSI escape sequence filtering
- Path traversal protection: Safe filesystem operations
- Plugin isolation: Capability tokens, resource limits
- Dependency scanning: Automated vulnerability checks
See SECURITY.md for details.
- v0.1: Foundation (Dravya, Agni, basic Māyā)
- v0.2: Reactivity (Prāṇa, auto re-render)
- v0.3: Commands (Vāk, palette basics)
- v0.4: Plugins (Vāyu with WASM)
- v0.5: Polish (Śrī themes/animations) → Beta
- v1.0: Stable APIs, production-ready
See ROADMAP.md for detailed milestones.
We welcome contributions! Please see:
- CONTRIBUTING.md — Development guidelines
- CODE_OF_CONDUCT.md — Community standards
- GitHub Issues — Bug reports and features
MIT License — see LICENSE for details.
Created by Abhineesh Priyam (@abhineeshpriyam)
Part of the TIVerse organization.
DRAV is inspired by:
- Elm Architecture — Unidirectional data flow
- React — Virtual DOM and diffing
- Bubbletea — Go TUI patterns
- Textual (Python) — Modern TUI framework design
Built with 💙 by Abhineesh Priyam