Skip to content
C.W.K.
Stream
Lesson 02 of 04 · published

Embed the Core, Never Rewrite It

~12 min · swiftterm, embed, pin, vt, core

Level 0Spark
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

The Complaint Was Never the Parser

A VT emulator is decades of edge cases: glyph fallback, combining marks, iTerm-style image protocols, bracketed paste, the way a Korean IME marks text while you are still composing. That work is real, and it is not the work Dad asked for. The frictions were tabs that did not feel like objects, sessions that died with the window, siblings that could not knock, a phone that could not watch without becoming an owner. Those live above the core.

So Smolder embeds a core and pins it. SwiftTerm, exact version, one terminal view per pane. The core is configured — font, colors, scrollback, Option as Meta, bell — and it is never patched. If a keyboard rule has to exist, it rides an app-level event monitor, not a fork of the emulator.

Why a Pin, Not a Range

A floating version is how a renderer change arrives on a Tuesday and the four-harness window feels different on Wednesday, with no commit in your tree that you can point at. An exact pin makes the core a chosen brick. Moving it is a decision, recorded, not a cargo-cult up.

The same day the pin was chosen, another core was read and left on the table: a faster one whose API was still in flux and whose version was not a version. It is revisited only if measurement of the four-harness lag demands it. Embedding a core does not prove performance. It proves you stopped rewriting the wrong layer.

Two Surfaces, One Core

The Mac host is AppKit. The phone is SwiftUI wrapping a UIKit terminal view. Both attach SwiftTerm. That is not an accident and not a preview of a language course — the language course is a sibling quest that does not exist yet. The product fact is: the emulator is a dependency both surfaces share, so a glyph bug is one pin, not two forks. Your code stays in layout, attachment, leases, chrome.

Configure the core. Never patch it. The moment you carry a local diff against the emulator, you own a terminal core you said you would not rewrite. Every family feature that cannot be expressed above that line is a feature you should refuse, or a measurement that says it is time to change cores in the open.

Code

The pin is the decision, written where the compiler can see it·swift
// swift-tools-version: 6.2
import PackageDescription

let package = Package(
    name: "Smolder",
    platforms: [
        .macOS(.v14), .iOS(.v17)  // shared package; iOS Xcode project links SmolderRemoteWire
    ],
    dependencies: [
        // Exact, not from:..to. The core does not move by accident.
        .package(
            url: "https://github.com/migueldeicaza/SwiftTerm.git",
            exact: "1.20.0"
        )
    ],
    targets: [
        // One view per pane. The daemon owns the PTY; this draws.
        .executableTarget(
            name: "SmolderApp",
            dependencies: [
                .product(name: "SwiftTerm", package: "SwiftTerm")
            ]
        )
        // iOS is a separate Xcode project with the same exact SwiftTerm 1.20.0 pin.
        // The shared wire target compiles without AppKit and without SwiftTerm.
    ]
)

External links

Exercise

Name a piece of terminal behavior you are tempted to "just fix in the emulator" — a key chord, a glyph, a paste mode. Write two columns: (1) can this live as configuration or an app-level monitor? (2) would a local patch against the core make you the owner of a parser you did not want to own? If column 2 is yes and column 1 is no, you do not have a patch. You have a core-change decision, and it has to be made in the open.
Hint
IME marked text and image protocols are why you paid for someone else's years. A family key chord is why you have an event monitor. Mixing those is how forks are born.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.