# Irgo
A hypermedia-driven application framework that uses Go as a runtime kernel with Datastar. Build native iOS, Android, and **desktop** apps using Go, HTML, and Datastar - no JavaScript frameworks required.
## Key Features
- **Go-Powered Apps**: Write your backend logic in Go, compile to native mobile frameworks or desktop apps
- **Datastar for Interactivity**: Use Datastar's hypermedia approach with SSE instead of complex JavaScript
- **Cross-Platform**: Single codebase for iOS, Android, desktop (macOS, Windows, Linux), and web
- **Virtual HTTP (Mobile)**: No network sockets - requests are intercepted and handled directly by Go
- **Native Webview (Desktop)**: Real HTTP server with native webview window
- **Type-Safe Templates**: Use [templ](https://templ.guide) for compile-time checked HTML templates
- **Hot Reload Development**: Edit Go/templ code and see changes instantly
## Architecture
### Mobile Architecture (iOS/Android)
```
┌─────────────────────────────────────────────────────────────┐
│ Mobile App │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ WebView (Datastar) │ │
│ │ • HTML rendered by Go templates │ │
│ │ • Datastar handles interactions via irgo:// scheme │ │
│ └──────────────────────┬────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼────────────────────────────────┐ │
│ │ Native Bridge (Swift / Kotlin) │ │
│ │ • Intercepts irgo:// requests │ │
│ │ • Routes to Go via gomobile │ │
│ └──────────────────────┬────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼────────────────────────────────┐ │
│ │ Go Runtime (gomobile bind) │ │
│ │ • HTTP router (chi-based) │ │
│ │ • Template rendering (templ) │ │
│ │ • Business logic │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### Desktop Architecture (macOS/Windows/Linux)
```
┌─────────────────────────────────────────────────────────────┐
│ Desktop App │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Native Webview Window │ │
│ │ (System webview engine - Chromium/WebKit) │ │
│ │ Navigates to: http://localhost:PORT │ │
│ └──────────────────────┬────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼────────────────────────────────┐ │
│ │ Go HTTP Server (localhost:PORT) │ │
│ │ • Page Routes (Templ → HTML) │ │
│ │ • API Routes (SSE responses) │ │
│ │ • Static Asset Server (/static/*) │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## Quick Start
### Prerequisites
- Go 1.21+
- [templ](https://templ.guide): `go install github.com/a-h/templ/cmd/templ@latest`
- [air](https://github.com/air-verse/air): `go install github.com/air-verse/air@latest`
**For mobile development:**
- [gomobile](https://pkg.go.dev/golang.org/x/mobile/cmd/gomobile): `go install golang.org/x/mobile/cmd/gomobile@latest && gomobile init`
- [entr](https://github.com/eradman/entr): `brew install entr` (macOS)
- For iOS: Xcode with iOS Simulator
- For Android: Android Studio with SDK and emulator
**For desktop development:**
- CGO enabled (C compiler required)
- macOS: Xcode Command Line Tools (included with Xcode)
- Windows: MinGW-w64 or similar C compiler
- Linux: GCC and WebKit2GTK dev packages (`apt install libwebkit2gtk-4.0-dev`)
### Install Irgo CLI
```bash
go install github.com/stukennedy/irgo/cmd/irgo@latest
```
Or build from source:
```bash
git clone https://github.com/stukennedy/irgo.git
cd irgo/cmd/irgo
go install .
```
### Create a New Project
```bash
irgo new myapp
cd myapp
go mod tidy
bun install # or: npm install
```
### Run as Desktop App
```bash
irgo run desktop # Run as desktop app
irgo run desktop --dev # With devtools enabled
```
### Development with Hot Reload (Web)
```bash
irgo dev # Start dev server at http://localhost:8080
```
### iOS Development
```bash
irgo run ios --dev # Hot-reload with iOS Simulator
irgo run ios # Production build
```
### Build for Production
```bash
# Desktop
irgo build desktop # Build for current platform
irgo build desktop macos # Build macOS .app bundle
irgo build desktop windows # Build Windows .exe
irgo build desktop linux # Build Linux binary
# Mobile
irgo build ios # Build iOS framework
irgo build android # Build Android AAR
```
## Project Structure
```
myapp/
├── main.go # Mobile/web entry point (build tag: !desktop)
├── main_desktop.go # Desktop entry point (build tag: desktop)
├── go.mod # Go module definition
├── .air.toml # Air hot reload configuration
├── package.json # Node dependencies (Tailwind CSS)
│
├── app/
│ └── app.go # Router setup and app configuration
│
├── handlers/
│ └── handlers.go # HTTP handlers (business logic)
│
├── templates/
│ ├── layout.templ # Base HTML layout
│ ├── pages.templ # Page templates
│ └── components.templ # Reusable components
│
├── static/
│ ├── css/
│ │ ├── input.css # Tailwind source
│ │ └── output.css # Generated CSS
│ └── js/
│ └── datastar.js # Datastar library
│
├── mobile/
│ └── mobile.go # Mobile bridge setup
│
├── ios/ # iOS Xcode project
├── android/ # Android project
│
└── build/
├── ios/ # Built iOS framework
├── android/ # Built Android AAR
└── desktop/ # Built desktop apps
├── macos/ # macOS .app bundle
├── windows/ # Windows .exe
└── linux/ # Linux binary
```
## Desktop Development
### How Desktop Mode Works
Desktop mode uses a different architecture than mobile:
1. **Real HTTP Server**: A Go HTTP server starts on an auto-selected localhost port
2. **Native Webview**: A native window with an embedded browser engine opens
3. **Standard HTTP**: The webview navigates to the localhost URL - standard HTTP requests
This means your app works identically to the web dev server, but packaged as a native desktop app.
### Desktop Entry Point
Projects include a `main_desktop.go` with build tag `//go:build desktop`:
```go
//go:build desktop
package main
import (
"flag"
"fmt"
"net/http"
"myapp/app"
"github.com/stukennedy/irgo/desktop"
)
func main() {
devMode := flag.Bool("dev", false, "Enable devtools")
flag.Parse()
r := app.NewRouter()
mux := http.NewServeMux()
staticDir := desktop.FindStaticDir()
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(staticDir))))
mux.Handle("/", r.Handler())
config := desktop.DefaultConfig()
config.Title = "My App"
config.Debug = *devMode
desktopApp := desktop.New(mux, config)
fmt.Println("Starting desktop app...")
if err := desktopApp.Run(); err != nil {
fmt.Printf("Error: %v\n", err)
}
}
```
### Desktop Configuration
```go
config := desktop.Config{
Title: "My App", // Window title
Width: 1024, // Window width
Height: 768, // Window height
Resizable: true, // Allow window resize
Debug: false, // Enable browser devtools
Port: 0, // 0 = auto-select available port
}
```
### Running Desktop Apps
```bash
# Run directly (compiles and runs)
irgo run desktop
# With devtools (for debugging)
irgo run desktop --dev
```
### Building Desktop Apps
```bash
# Build for current platform
irgo build desktop
# Build for specific platform
irgo build desktop macos # Creates build/desktop/macos/MyApp.app
irgo build desktop windows # Creates build/desktop/windows/MyApp.exe
irgo build desktop linux # Creates build/desktop/linux/MyApp
```
### Desktop vs Mobile: Key Differences
| Aspect | Mobile | Desktop |
|--------|--------|---------|
| HTTP | Virtual (no sockets) | Real localhost server |
| Bridge | gomobile + native code | None (direct HTTP) |
| Entry point | `main.go` | `main_desktop.go` |
| Build tag | `!desktop` | `desktop` |
| CGO | Not required | Required (webview) |
## Writing Handlers
Irgo supports two types of handlers:
### Standard Handlers (Full Page Loads)
Return `(string, error)` with HTML:
```go
r.GET("/about", func(ctx *router.Context) (string, error) {
return renderer.Render(templates.AboutPage())
})
```
### Datastar SSE Handlers
Return `error` and use `ctx.SSE()` for responses:
```go
r.DSPost("/todos", func(ctx *router.Context) error {
var signals struct {
Title string `json:"title"`
}
ctx.ReadSignals(&signals)
todo := createTodo(signals.Title)
sse := ctx.SSE()
sse.PatchTempl(templates.TodoItem(todo))
sse.PatchSignals(map[string]any{"title": ""}) // Clear input
return nil
})
```
## Writing Templates
Templates use [templ](https://templ.guide) with Datastar attributes:
```go
// templates/pages.templ
package templates
templ HomePage() {
@Layout("Home") {
<main class="container mx-auto p-4">
<h1 class="text-2xl font-bold">Welcome to Irgo</h1>
<div data-signals="{name: ''}">
<input
type="text"
data-bind:name
placeholder="Your name"
class="border p-2 rounded"
/>
<button
data-on:click="@post('/greeting')"
class="bg-blue-500 text-white px-4 py-2 rounded"
>
Greet
</button>
<div id="greeting"></div>
</div>
</main>
}
}
templ TodoItem(todo Todo) {
<div id={ "todo-" + todo.ID } class="flex items-center gap-2 p-2">
<input
type="checkbox"
checked?={ todo.Done }
data-on:click={ fmt.Sprintf("@patch('/todos/%s')", todo.ID) }
/>
<span>{ todo.Title }</span>
<button
data-on:click={ fmt.Sprintf("@delete('/todos/%s')", todo.ID) }
class="text-red-500"
>Delete</button>
</div>
}
```
## CLI Commands
```bash
# Create new project
irgo new myapp
irgo new . # Initialize in current directory
# Development
irgo dev # Start dev server with hot reload (web)
irgo run desktop # Run as desktop app
irgo run desktop --dev # Desktop with devtools
irgo run ios --dev # Hot reload with iOS Simulator
irgo run android --dev # Hot reload with Android Emulator
# Production builds
irgo build desktop # Build desktop app for current platform
irgo build desktop macos/windows/linux # Cross-platform builds
irgo build ios # Build iOS framework
irgo build android # Build Android AAR
irgo build all # Build all mobile platforms
irgo run ios # Build and run on iOS Simulator
irgo run android # Build and run on Android Emulator
# Utilities
irgo templ # Generate templ files
irgo install-tools # Install required dev tools
irgo version # Print version
irgo help [command] # Show help
```
## Datastar Overview
[Datastar](https://data-star.dev) is a lightweight (~11KB) hypermedia framework that powers Irgo's interactivity:
- **SSE (Server-Sent Events)**: Server pushes HTML fragments to update the DOM
- **Reactive Signals**: Client-side state with `data-signals` and `$variable` syntax
- **Declarative Actions**: `data-on:click="@get('/api')"` triggers server requests
### Key Datastar Attributes
| Attribute | Description | Example |
|-----------|-------------|---------|
| `data-signals` | Initialize state | `data-signals="{count: 0}"` |
| `data-bind:X` | Two-way binding | `data-bind:name` |
| `data-on:event` | Event handler | `data-on:click="@post('/api')"` |
| `data-text` | Dynamic text | `data-text="$count"` |
| `data-show` | Conditional display | `data-show="$visible"` |
## Troubleshooting
### Desktop: "CGO_ENABLED=0" error
Desktop builds require CGO. Ensure you have a C compiler:
- macOS: `xcode-select --install`
- Windows: Install MinGW-w64
- Linux: `apt install build-essential`
### Desktop: Webview not showing
Check that WebKit2GTK is installed (Linux):
```bash
apt install libwebkit2gtk-4.0-dev
```
### "Module not found" errors
```bash
go mod tidy
```
### Hot reload not working
1. Check if air is running
2. Verify `.air.toml` configuration
3. Make sure `_templ.go` is NOT in `exclude_regex`
### Port 8080 already in use
```bash
lsof -i :8080
kill <PID>
```
## License
MIT License - see [LICENSE](LICENSE) for details.
## Acknowledgments
- [Datastar](https://data-star.dev) - The hypermedia framework that powers Irgo
- [templ](https://templ.guide) - Type-safe HTML templating for Go
- [chi](https://github.com/go-chi/chi) - Lightweight Go router
- [webview](https://github.com/webview/webview) - Native webview for desktop
- [gomobile](https://pkg.go.dev/golang.org/x/mobile) - Go on mobile platforms
- [air](https://github.com/air-verse/air) - Live reload for Go