libghostty-ohos is a HarmonyOS HAR library for embedding a terminal surface in your own app.
It packages a native renderer, a Ghostty-powered terminal core, and a small ArkTS control surface. You bring the app-level UX: tabs, splits, settings, toolbar actions, session management, and persistence.
TerminalSurface: an ArkTS component backed by anXComponentsurfaceTerminalController: imperative control over terminal input/output wiring, scrollback, selection, theme, and config- bundled terminal themes and glyph fallback font assets
- a native
.sobuilt aroundlibghostty-vt
- terminal tabs, pane splits, or window management
- settings screens, preferences storage, or app chrome
- PTY, shell, exec, or SSH transport drivers
- terminal session orchestration beyond the controller/driver boundary
Current behavior is intentionally small: one TerminalController controls one terminal instance, and one TerminalSurface presents it.
Install the package from OHPM:
ohpm install libghostty-ohosOr add the HAR from OHPM in your consuming module:
{
"dependencies": {
"libghostty-ohos": "^0.1.0"
}
}Then run:
ohpm installFor local development, you can also add the HAR as a file dependency:
{
"dependencies": {
"libghostty-ohos": "file:../libghostty_ohos"
}
}If your project enables normalized OHM URLs, keep the dependency key exactly equal to the package name: libghostty-ohos.
import { TerminalController, TerminalSurface } from 'libghostty-ohos';
@Entry
@Component
struct TerminalPage {
private controller: TerminalController = new TerminalController();
aboutToAppear(): void {
this.controller.updateConfig({ fontSize: 16, scrollbackLines: 20000 });
this.controller.setTheme('Aizen_Dark');
this.controller.setInputListener((data: string) => {
this.driver.write(data);
});
}
build() {
Stack() {
TerminalSurface({
controller: this.controller,
surfaceId: 'main-terminal-surface',
surfaceColor: '#0B0D10'
})
}
.width('100%')
.height('100%')
.backgroundColor('#0B0D10')
}
}Exported from libghostty-ohos:
TerminalSurfaceTerminalControllerCursorPositionCellMetricsTerminalConfigTerminalConfigPatchTerminalInputListenerTerminalAttachmentListenerDEFAULT_TERMINAL_CONFIGDEFAULT_THEME_NAME
Important usage rules:
- Create one
TerminalControllerper terminal. - Do not reuse the same
surfaceIdacross visible surfaces. TerminalSurfaceowns the native bind/unbind lifecycle. App code should not callbindNative()orunbindNative().- Config is cached on the controller and applied when the surface binds.
- Query methods such as
getThemeList(),isRendererReady(), andgetRendererError()only become meaningful after the surface is attached.
This library is meant to be composed into your own terminal UX.
- For tabs: keep one controller per tab and mount the active
TerminalSurface. - For splits: render multiple
TerminalSurfaceinstances side by side, each with its own controller and unique IDs. - For custom actions: drive the controller directly with
write(),feed(),scrollView(),clearSelection(),setTheme(), andupdateConfig().
- A terminal instance starts when the surface binds.
- User input from hardware keyboard, IME, paste, or
controller.write()is emitted to your app-owned driver. - Driver output is rendered by feeding it back through
controller.feed(). - Touch drag scrolls the viewport. Long-press enters selection mode. Hardware keyboard input is translated to terminal escape sequences.
Refresh the upstream terminal archive:
./tools/build-ghostty-vt-docker.shBuild the example app:
/Applications/DevEco-Studio.app/Contents/tools/hvigor/hvigor/bin/hvigor.js assembleApp -m project --no-daemonlibghostty_ohos/: reusable HAR libraryexample/: minimal example app consuming the HAR and wiring an app-owned drivertools/build-ghostty-vt-docker.sh: refreshes the upstreamlibghostty_vt.aarchive in Dockertools/build-fish-ohos.sh: rebuilds the bundled fish/starship/fastfetch HNP used by the example app