Meet Corta — a native macOS terminal written in Swift, end to end.
I just shipped 1.0.0.
• Metal rendering + Core Text (real CJK / IME)
• Hand-written VT engine — zero third-party deps in the core
• AppKit-first: Secure Keyboard Entry, Shortcuts, Quick Terminal
• OpenSSH + SFTP + remote edit, still feels like a Mac app
• One config file. No AI bolted on. No scripting kitchen sink.
Built for people who live in the terminal on Mac — not a cross-platform port.
No special two-stage Escape on our side.
While a CJK candidate / preedit is open, Escape goes to the input context first. The IME almost always consumes it to dismiss (unmark / empty marked text) — we never see doCommand in that case.
cancelOperation → 0x1B only runs when the IME hands Escape back as a command, which is usually when there’s nothing left to dismiss. So in practice: dismiss-first at the IME layer; forward only after that.
Meet Corta — a native macOS terminal written in Swift, end to end.
I just shipped 1.0.0.
• Metal rendering + Core Text (real CJK / IME)
• Hand-written VT engine — zero third-party deps in the core
• AppKit-first: Secure Keyboard Entry, Shortcuts, Quick Terminal
• OpenSSH + SFTP + remote edit, still feels like a Mac app
• One config file. No AI bolted on. No scripting kitchen sink.
Built for people who live in the terminal on Mac — not a cross-platform port.
Corta 1.0.1 is out — a small patch, no new features.
• Theme cursor colour actually paints now
• Config / shell-integration writes follow symlinks (dotfiles stay yours)
• Directory history writes off the render path
• First release signed into the Sparkle feed from CI
Also: last build that runs on Intel Macs. Apple silicon from 1.1.0.
https://t.co/GbwtEf6e7E
#Swift #macOS
What’s next, already tracked on GitHub:
1.1.0 — performance. Apple silicon only, Metal 4 as the only render backend, hot-path cleanup (frame wake, search, allocations), then housekeeping.
1.2.0 — simplification. Window + menus in code, split the pane collaborators, SFTP as its own package, Liquid Glass chrome APIs.
Milestones:
https://t.co/HPAK37sJDX
https://t.co/9lz1wbVjdf
If you want to help shape either, issues/PRs welcome.
@ThomasNanc46829 That’s the leftover fight: candidate UI vs “same bytes as the non-IME path.”
If you ever want to poke the code (or file a repro), the repo’s open — https://t.co/gblZ4WG4py — no pressure. Or just DM me if that’s easier.
Option-as-Meta doesn’t touch bare Escape or Tab — those still have neither ⌘ nor ⌃, so they still go through the input context first.
What fights them is the candidate UI: a CJK IME window or a shell completion menu that resolves the key as a command instead of insertText. Escape comes back as cancelOperation → 0x1B; Tab / Shift-Tab as insertTab / insertBacktab → 0x09 / CSI Z. Without that forward they just vanish.
So the leftover fight isn’t Meta vs Esc/Tab — it’s composition / candidates vs “send the same bytes the non-IME path would have sent.”
Yeah. ⌘ and ⌃ bypass the input context entirely by design, so most app shortcuts never hit that path.
What still goes through IME first is everything else — Tab/Return/arrows/Escape landed in doCommand and had to be forwarded. Option-as-Meta is another seam: once ⌥ means Meta, it also bypasses IME.
Nothing dramatic left that I know is still “eating” shortcuts day to day, but I’m sure some IME + composition edge case will surprise me. If you hit one, please file it.
Appreciate that.
What broke first: marked text was invisible. Preedit has to overlay the Metal layer — never the grid/PTY — and without a layer-backed overlay it just doesn’t show.
Next: Tab/Return/arrows getting swallowed by the input context unless you forward doCommand. Classic seam stuff.
Fair ask.
I measure keypress-to-glass inside the app (drawable present time), not just frame CPU — method + numbers are in the README/PERFORMANCE notes, including where I’m still above target.
I haven’t published a polished side-by-side vs Terminal/iTerm on “real projects” yet. For 1.0 I’m standing behind input feel + CJK/IME more than startup claims. Happy to share the harness if useful.
Corta 1.0 is out — a native macOS terminal in pure Swift (Metal, Core Text, hand-written VT, zero deps in the core).
Looking for people who care about Mac-native software:
• File issues (bugs, “went back to my old terminal”, install blockers)
• PRs welcome — docs, VT correctness, IME/Metal rough edges
• Or just star + try it and tell me what breaks
If you want to sponsor / support the work as it grows, that helps too.
Repo: https://t.co/BpiIVo4mBY
Contributing: https://t.co/QISJ7dWHaE
#swift #macos #OpenSource
Taste call for sure. If I have to pick one: the input model. AppKit IME, marked text, Secure Keyboard Entry — that's when it stops feeling like a port and starts feeling like a Mac app.
Metal + Core Text rendering matters a lot too, but the "belongs on a Mac" moment for me is still when Chinese input just behaves.
@mitansh_j07 Appreciate that a lot. If the "hand-written VT / zero deps" direction resonates, I'd love to have you along — happy to co-build, review PRs, or just bounce ideas. Drop an issue or ping me if you want to dig in: https://t.co/gblZ4WG4py
Making text input + rendering feel native on macOS ate more calendar time.
Terminal state is hard, but it's a problem I could own end-to-end in Swift — parser, grid, fuzz, golden files.
The Mac-native side was the underestimated one. NSTextInputClient isn't "free": marked text has to overlay the Metal layer without ever hitting the PTY, firstRect has to track the cursor in screen space, and Tab/Return/arrows get eaten unless you forward doCommand correctly. Same story for Core Text fallback + glyph atlas under real CJK sessions.
So VT work was deep; IME/AppKit/Metal feel work was the one that kept surprising me. That's the pure-Mac bet showing up in the schedule.
Honestly? I'm just a macOS native believer.
I really like that pure-stack feeling — Swift end to end, AppKit, Metal, Core Text — the app feels like it belongs on a Mac, not like something ported sideways.
Pulling a C VT dependency would've broken that for me. Also more practical: I own the bugs, the fuzz tests, and the "every PTY byte is hostile" model. So yeah — taste first, engineering second. Pure Swift core was the bet I wanted to live with.
@yevloop Appreciate that. CJK/IME is unglamorous until it breaks — spent a lot of 1.0 making it feel native on Mac. Feedback welcome if anything still feels off.
If this sounds useful:
★ Star the repo — helps a lot at launch
↓ Try 1.0.0 (macOS 26+)
🐛 Issues / PRs welcome — docs, bugs, terminal correctness
Repo: https://t.co/BpiIVo4Urw
Download: https://t.co/11wnwsnUJW
Happy to take hard feedback from people who live in iTerm / Ghostty daily.
#Swift #macOS #OpenSource
I’m so thrilled to join the Grok Meetup Beijing today!
It was great to meet so many talented developers, exchange ideas, and learn more about what everyone is building.
A huge thank you to the xAI team, especially @wangyafang6 and @benln , for making this event possible.
Really enjoyed the conversations, the energy, and the developer community here in Beijing. Such a great experience!
@grok@bot