Welcome! ProGhostty is a bilingual project — 中文界面, English code and docs. Whether you're fixing a typo or rewriting the scroll engine, we're glad you're here.
This guide covers everything you need to go from "I want to help" to a merged PR.
| You care about… | Jump in on… | Good first step |
|---|---|---|
| Daily-driver bugs | Repro + PR or detailed issue | Run the app, file what breaks |
| Scroll / split / resize | Pattern-2 smooth scroll, pane layout | Read docs/architecture/ownership-map.md |
| Themes & settings | Cohesive palettes, a11y contrast | Tweak Soft Dark / Soft Light, add previews |
| Docs & onboarding | Screenshots, build tips, translations | Improve this file or the README |
| Tests | Pure value types, scroll resolvers | Add edge-case tests to Tests/ |
| CI & release | Workflow hardening, DMG scripting | Check .github/workflows/ and scripts/ |
Not sure where to start? Browse open issues — anything labeled good first issue is a solid entry point.
git clone --recursive https://github.com/<your-username>/ProGhostty.git
cd ProGhosttyThe --recursive flag is required — it pulls in Vendor/ghostty (the Ghostty submodule that provides libghostty-vt). If you already cloned without it:
git submodule update --init --recursive| Tool | Version | Notes |
|---|---|---|
| macOS | 14+ | App target minimum |
| Swift | 6.1 | Language mode .v6 |
| Zig | 0.15.2 | Builds vendored libghostty-vt |
| Xcode | Latest stable | App bundle and signing tooling |
Verify your toolchain:
swift --version # Swift 6.1
zig version # 0.15.2
xcodebuild -versionA Debug VT library makes parsing pathologically slow. Always use ReleaseFast:
cd Vendor/ghostty
zig build \
--global-cache-dir ../../.zig-cache-global \
-Demit-lib-vt=true \
-Demit-xcframework=false \
-Doptimize=ReleaseFast
cd ../..Full notes: docs/libghostty-vt.md.
swift build
swift testBoth must pass green before you open a PR.
scripts/check-architecture.shThis script enforces the layering rules (e.g. Core cannot import SwiftUI). If it fails, your change violates an architecture boundary — fix the import before proceeding.
swift build alone does not produce a launchable .app bundle. For manual testing:
./scripts/build-app-bundle.sh release
open .build/arm64-apple-macosx/release/ProGhostty.appAlways hand-test renderer and scroll changes in the real app before submitting.
One pipeline. One owner per concern. Dependencies flow top-down only.
PTY bytes
→ PTYTerminalEngine session lifecycle & I/O
→ GhosttyVTBridge.write
→ libghostty-vt ★ sole terminal state truth
→ frame / scrollFrame / rows(at:)
→ TerminalRenderFrame immutable snapshot
→ Metal direct | cell-grid | text fallback
┌─────────────────────────────────────────────────────┐
│ App (ProGhosttyApp) — SwiftUI + AppKit host │
│ AppModel · RootView · window chrome │
└──────────────────────▲──────────────────────────────┘
│ protocols + value types only
┌──────────────────────┴──────────────────────────────┐
│ Core (ProGhosttyCore) — NO import SwiftUI │
│ Terminal · Workspace · Settings · Persistence │
└──────────────────────┬──────────────────────────────┘
│ C shims
▼
libghostty-vt (Zig)
Key constraint: ProGhosttyCore cannot import SwiftUI. This is enforced by scripts/check-architecture.sh in CI. AppKit usage in Core is restricted to a whitelist of renderer/PTY files.
Deep dive: docs/architecture/ownership-map.md.
Sources/
ProGhosttyApp/ macOS app, settings UI, windows
ProGhosttyCore/ PTY, VT bridge, renderer, workspace
ProGhosttyGhosttyVT/ C surface for libghostty-vt
ProGhosttyPTY/ forkpty / resize helpers
ProGhosttyPG/ `pg` helper CLI
Vendor/ghostty/ vendored Ghostty (MIT)
Tests/ swift-testing
scripts/ bundle, DMG, architecture guard
- Core cannot import SwiftUI. This is a hard rule enforced by CI.
- AppKit in Core is limited to a whitelist (renderer, PTY, mock files). See
scripts/check-architecture.shfor the exact allow-list. - App layer communicates with Core through protocols and value types only. Touching
GhosttyVTBridgeor C headers from App is a boundary violation.
- Prefer pure value types (
struct,enum) over reference types. Most of the Core → App contract is built onSendable/Equatablestructs. - Each concern has one owner type. Before adding a new type, check the ownership map — if a type already owns that concern, extend it instead of creating a parallel one.
- Dependency injection via composition root, not internal instantiation. Types receive their collaborators; they don't
newthem internally. - Swift 6.1 strict concurrency. The project uses
.v6language mode — all types crossing concurrency boundaries must beSendable.
- Tests live in
Tests/ProGhosttyCoreTests/andTests/ProGhosttyAppTests/. - Framework: swift-testing (not XCTest).
- Focus tests on pure value types and resolvers — they're the easiest to test and the most valuable to have covered.
ProGhostty uses Conventional Commits. Full spec: docs/git-workflow.md.
<type>(<scope>): <summary>
[optional body]
| Type | When |
|---|---|
feat |
User-visible feature |
fix |
Bug fix / regression |
refactor |
Behavior-preserving restructure |
test |
Test-only changes |
docs |
Documentation / specs |
chore |
Build scripts, dependencies |
ci |
Workflows / release pipeline |
perf |
Performance optimization |
scroll · render · pty · vt · workspace · settings · ci · release · arch
- Imperative mood, present tense:
fix false bottom when…— notfixed/fixes. - ≤ 72 characters in the summary line.
- One intent per commit. Don't mix unrelated changes.
- English summaries preferred; Chinese is fine in the body.
# Good
fix(scroll): stop cursor-rect rebuild thrashing during browse
feat(settings): add theme import from iTerm2 plist
refactor(workspace): extract PaneNode from PaneTreeReducer
# Bad
update stuff
fix bug
WIP
PTYTerminalEngine.swift changes
-
Fork the repo and create a branch from
main. -
Make your changes following the coding conventions above.
-
Run the full check:
swift build && swift test && scripts/check-architecture.sh
If your change touches UI or rendering, also:
./scripts/build-app-bundle.sh release # hand-test the .app -
Open a PR against
mainon the upstream repo. -
Fill the PR template — describe:
- User-visible behavior — what changed from the user's perspective?
- Layer touched — PTY / VT / renderer / workspace / settings?
- How you tested — unit tests, hand-testing, both?
-
CI must pass. The PR will not be merged with red CI.
-
Respond to review feedback. Maintainers may request changes — this is normal and collaborative.
- Correctness — does it do what the description says?
- Layering — no import violations, no boundary crossings.
- Tests — new behavior has tests; bug fixes have regression tests.
- Commit hygiene — clean history, conventional messages, one intent per commit.
- No drive-by refactors — keep unrelated cleanup in a separate PR.
- User impact — the description clearly states what the user will see or experience.
- Questions & ideas: GitHub Discussions
- Bug reports & feature requests: GitHub Issues
- Security issues: See SECURITY.md — do not file public issues for vulnerabilities.
We aim to respond to issues and PRs within a few days. If you haven't heard back in a week, a polite ping is welcome and encouraged.
By contributing to ProGhostty, you agree that your contributions will be licensed under the MIT License, the same as the project itself.
Thank you for making ProGhostty better. Every contribution — no matter how small — helps build a better terminal for everyone.