install
source · Clone the upstream repo
git clone https://github.com/plurigrid/asi
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/plurigrid/asi "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/libghostty-aci" ~/.claude/skills/plurigrid-asi-libghostty-aci && rm -rf "$T"
manifest:
skills/libghostty-aci/SKILL.mdsource content
libghostty-aci: Terminal ACI Integration
Trit: 0 (ERGODIC - transport layer) Color: #46F27F (Coordinator stream) Seed: 1069
Overview
Integrates libghostty terminal emulation with Agent-Computer Interface (ACI) patterns:
| Integration | Trit | Color | Library |
|---|---|---|---|
| Emacs vterm/eat | -1 | #E7B367 | libghostty-vt |
| MCP Terminal | 0 | #46F27F | libghostty embedding |
| Daphne ASGI | +1 | #F0D127 | WebSocket streaming |
GF(3): -1 + 0 + 1 = 0 ✓
libghostty Type Mapping
Core Types (from lib_vt.zig)
// Terminal state machine pub const Terminal = terminal.Terminal; pub const Screen = terminal.Screen; pub const Parser = terminal.Parser; // Display elements pub const Cell = page.Cell; pub const Style = terminal.Style; pub const Cursor = Screen.Cursor; // Input handling pub const input = struct { pub const Key = key.Key; pub const KeyEvent = key.KeyEvent; pub const KeyMods = key.Mods; pub const encodeKey = key_encode.encode; pub const encodePaste = paste.encode; }; // Escape sequences pub const CSI = Parser.Action.CSI; pub const DCS = Parser.Action.DCS; pub const osc = terminal.osc;
Embedding Types (from embedded.zig)
// Application lifecycle pub const App.Options = extern struct { wakeup_callback: *const fn (*anyopaque) callconv(.C) void, action_callback: *const fn (*anyopaque, Action) callconv(.C) bool, clipboard_read: *const fn (*anyopaque, Clipboard) callconv(.C) void, clipboard_write: *const fn (Clipboard, [*:0]const u8, usize) callconv(.C) void, clipboard_write_small: *const fn (Clipboard, [*]const u8, usize) callconv(.C) void, }; // Surface management pub const Surface = struct { pub fn setSize(self: *Surface, width: usize, height: usize) void; pub fn handleInput(self: *Surface, event: KeyEvent) void; pub fn render(self: *Surface) RenderState; };
Emacs Integration (-1 MINUS)
vterm Backend
;; Use libghostty-vt for VT parsing instead of libvterm (defcustom vterm-backend 'ghostty "Terminal emulation backend: 'libvterm or 'ghostty" :type '(choice (const libvterm) (const ghostty))) (defun ghostty-vt-make-terminal (width height) "Create ghostty terminal with dimensions." (let ((term (ghostty-vt-new))) (ghostty-vt-resize term width height) term)) (defun ghostty-vt-process-output (term data) "Feed data through ghostty parser." (ghostty-vt-feed term data) (ghostty-vt-get-screen term))
eat Integration
;; eat (Emulate A Terminal) can use ghostty for parsing (defun eat-ghostty-adapter (process output) "Adapt ghostty-vt output to eat display." (let ((parsed (ghostty-parse-stream output))) (eat-render-cells (ghostty-cells-to-eat parsed))))
Key Encoding
;; Use ghostty key encoding for terminal input (defun ghostty-encode-key (key mods) "Encode key event for terminal using ghostty." (ghostty-input-encode-key (ghostty-make-key-event key mods)))
MCP Terminal Server (0 ERGODIC)
Terminal Streaming Protocol
// MCP server exposing terminal capabilities interface GhosttyMCPServer { tools: { "terminal/create": { params: { width: number; height: number; }; returns: { session_id: string; }; }; "terminal/write": { params: { session_id: string; data: string; }; returns: { cells_changed: number; }; }; "terminal/read": { params: { session_id: string; }; returns: { screen: Cell[][]; cursor: Position; }; }; "terminal/resize": { params: { session_id: string; width: number; height: number; }; returns: { success: boolean; }; }; "terminal/input": { params: { session_id: string; key: string; mods: string[]; }; returns: { encoded: string; }; }; }; }
Rust MCP Implementation
use ghostty_vt::{Terminal, Parser, Screen}; struct GhosttyMCP { terminals: HashMap<String, Terminal>, } impl GhosttyMCP { fn create_terminal(&mut self, width: u16, height: u16) -> String { let id = Uuid::new_v4().to_string(); let term = Terminal::new(width, height); self.terminals.insert(id.clone(), term); id } fn write(&mut self, id: &str, data: &[u8]) -> usize { let term = self.terminals.get_mut(id)?; term.process(data); term.screen().damage_count() } fn read(&self, id: &str) -> Screen { self.terminals.get(id)?.screen().clone() } }
WebSocket Streaming
async fn terminal_websocket(ws: WebSocket, term_id: String) { let (mut sink, mut stream) = ws.split(); // Input handler tokio::spawn(async move { while let Some(msg) = stream.next().await { if let Ok(Message::Binary(data)) = msg { term.process(&data); } } }); // Output streamer (60fps) loop { let screen = term.screen(); let json = serde_json::to_string(&screen)?; sink.send(Message::Text(json)).await?; tokio::time::sleep(Duration::from_millis(16)).await; } }
Daphne ASGI Integration (+1 PLUS)
Django Channels Terminal
# consumers.py from channels.generic.websocket import AsyncWebsocketConsumer import ghostty_vt # Python bindings class TerminalConsumer(AsyncWebsocketConsumer): async def connect(self): self.terminal = ghostty_vt.Terminal(80, 24) await self.accept() async def receive(self, text_data=None, bytes_data=None): if bytes_data: # Process input through ghostty self.terminal.process(bytes_data) # Send screen update screen = self.terminal.screen_json() await self.send(text_data=screen) async def disconnect(self, close_code): del self.terminal
ASGI Middleware
# middleware.py class GhosttyTerminalMiddleware: """ASGI middleware for terminal WebSocket connections.""" def __init__(self, app): self.app = app async def __call__(self, scope, receive, send): if scope["type"] == "websocket" and scope["path"].startswith("/terminal/"): await self.handle_terminal(scope, receive, send) else: await self.app(scope, receive, send) async def handle_terminal(self, scope, receive, send): term = ghostty_vt.Terminal(80, 24) while True: message = await receive() if message["type"] == "websocket.receive": data = message.get("bytes", b"") term.process(data) await send({ "type": "websocket.send", "text": term.screen_json() })
Daphne Configuration
# asgi.py import os from django.core.asgi import get_asgi_application from channels.routing import ProtocolTypeRouter, URLRouter from channels.auth import AuthMiddlewareStack os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') application = ProtocolTypeRouter({ "http": get_asgi_application(), "websocket": AuthMiddlewareStack( URLRouter([ path("terminal/<session_id>/", TerminalConsumer.as_asgi()), ]) ), }) # Run with: daphne -b 0.0.0.0 -p 8000 myproject.asgi:application
Cross-Integration: Terminal Mesh
┌─────────────────────────────────────────────────────────────┐ │ ACI Terminal Mesh │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Emacs (-1) MCP Server (0) Daphne (+1) │ │ #E7B367 #46F27F #F0D127 │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ vterm │◄──────►│ ghostty │◄────────►│ Django │ │ │ │ eat │ │ MCP │ │Channels │ │ │ └─────────┘ └─────────┘ └─────────┘ │ │ │ │ │ │ │ └──────────────────┼────────────────────┘ │ │ │ │ │ libghostty-vt │ │ (Zero Dependencies) │ │ │ └─────────────────────────────────────────────────────────────┘
Building libghostty
As Zig Module
// build.zig const ghostty_vt = b.dependency("ghostty-vt", .{ .target = target, .optimize = optimize, }); exe.root_module.addImport("vt", ghostty_vt.module("ghostty-vt"));
As C Library
cd ghostty zig build -Doptimize=ReleaseFast -Dtarget=native-native-musl lib # Outputs: zig-out/lib/libghostty-vt.a # Headers: zig-out/include/ghostty_vt.h
Python Bindings (cffi)
from cffi import FFI ffi = FFI() ffi.cdef(""" typedef struct ghostty_terminal ghostty_terminal_t; ghostty_terminal_t* ghostty_terminal_new(uint16_t width, uint16_t height); void ghostty_terminal_free(ghostty_terminal_t* term); void ghostty_terminal_process(ghostty_terminal_t* term, const uint8_t* data, size_t len); const char* ghostty_terminal_screen_json(ghostty_terminal_t* term); """) lib = ffi.dlopen("libghostty-vt.so")
GF(3) Triads
libghostty-aci (0) ⊗ sheaf-cohomology (-1) ⊗ gay-mcp (+1) = 0 ✓ libghostty-aci (0) ⊗ captp (-1) ⊗ goblins (+1) = 0 ✓ emacs-vterm (-1) ⊗ libghostty-aci (0) ⊗ daphne-ws (+1) = 0 ✓
Commands
# Build libghostty-vt just ghostty-build # Test Emacs integration emacs --eval '(vterm-ghostty-test)' # Start MCP terminal server just mcp-terminal-server # Run Daphne with terminal support daphne -b 0.0.0.0 -p 8000 project.asgi:application
Related Skills
| Skill | Trit | Relation |
|---|---|---|
| captp | 0 | Capability transport for terminal sessions |
| goblins | +1 | Actor model for terminal instances |
| autopoiesis | 0 | Self-modifying terminal config |
| tree-sitter | -1 | AST parsing of terminal output |
Skill Name: libghostty-aci Type: Terminal Integration Trit: 0 (ERGODIC) Seed: 1069 Dependencies: libghostty-vt (Zig), channels (Python), tokio (Rust)
Autopoietic Marginalia
The interaction IS the skill improving itself.
Every use of this skill is an opportunity for worlding:
- MEMORY (-1): Record what was learned
- REMEMBERING (0): Connect patterns to other skills
- WORLDING (+1): Evolve the skill based on use
Add Interaction Exemplars here as the skill is used.