Wave Terminal: where Go sits inside an AI-aware terminal app
The PR title calls this Crest, but the repository currently presents itself as Wave Terminal: an AI-integrated terminal with durable SSH sessions, local model support, remote file operations, and a desktop UI. The codebase is mixed: TypeScript/Electron for the shell and UI, Go for the backend pieces, command helpers, connection handling, schema generation, and server process.
That mix is what makes the repo interesting. A modern desktop app often has more than one runtime. Go is used where long-running services, filesystem work, connection management, and CLI tools fit well.
The Go server has explicit lifecycle hooks
The server command includes shutdown handling, telemetry loops, config watching, backup cleanup, and activity updates. The shape is conventional Go service code: start background loops, keep cancellation paths visible, and use bounded contexts for shutdown work.
func doShutdown(reason string) {
ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelFn()
// stop services and flush state
}
Desktop apps need this more than people expect. Users close windows, machines sleep, network connections disappear, and helper processes are restarted by the UI. A terminal app that manages remote sessions has to treat lifecycle as a first-class feature.
Schema generation keeps UI contracts typed
The cmd/generateschema package generates JSON schema files such as schema/connections.json, schema/settings.json, and schema/widgets.json.
func generateSchema(template any, dir string, allowNull bool) error {
// reflect Go types into JSON Schema
}
That is a practical use for Go reflection in a mixed frontend/backend repo. The UI needs to edit structured settings; the backend needs typed values; generated schemas keep those two sides from drifting.
One small detail stands out: the generator has support for allowing null values by wrapping existing schema nodes. That is the kind of glue code real products accumulate once settings need to be edited, reset, and partially updated.
Connection testing is a separate CLI
cmd/test-conn is a small harness for SSH connection flows. It sets up Wave environment variables, initializes the connection controller, applies a timeout, and tests basic connect, shell execution, WSH execution, or interactive shell behaviour.
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
err = conn.Connect(ctx, &wconfig.ConnKeywords{})
This is worth copying. If a product’s hardest bugs live in SSH sessions, auth prompts, reconnects, and shell startup, a targeted CLI harness is better than trying to reproduce everything through the full desktop UI.
The CLI provider models interactive prompts
The test harness has a CLIProvider that reads user input from stdin and returns a typed response:
type CLIProvider struct {}
func (p *CLIProvider) GetUserInput(ctx context.Context, req *userinput.UserInputRequest) (*userinput.UserInputResponse, error) {
reader := bufio.NewReader(os.Stdin)
// read prompt response
}
That is a clean boundary. Connection code can ask for user input without caring whether the answer came from a terminal prompt, a desktop dialog, or a test stub.
Pack and generate commands live beside the app
The repo includes Go commands for packing files, generating TypeScript types, generating schemas, and running connection tests. That is common in mature Go repos: not every Go package ships to users. Some packages exist to keep the product build reproducible.
For a desktop app with a TypeScript UI, those helper commands become part of the build system. They are still worth writing in Go when they need strong typing, filesystem traversal, or access to backend structs.
What to take from Wave
The useful Go lesson is not “write the whole terminal in Go”. The repo does not do that. The lesson is where Go fits well in a mixed application:
- backend services with explicit lifecycle management
- connection controllers and SSH/session testing
- CLI harnesses for difficult flows
- schema/type generation for frontend contracts
- helper commands that keep build artifacts consistent
That is a realistic architecture for desktop developer tools. Use TypeScript where it makes UI work easier. Use Go where long-running process logic, typed config, and operational helpers matter.