Hacking on con
September 24, 2026 · View on GitHub
Quick contributor map for con.
Read these first:
README.md— public project overviewAGENTS.md— development conventionsDESIGN.md— architecture and product directiondocs/README.md— documentation index
Workspace Map
Terminal crates do not depend on the UI. The agent crate does not depend on a specific terminal backend.
| Crate | Role |
|---|---|
con | GPUI shell: windows, tabs, panes, agent UI, settings, command surfaces |
con-core | Config, sessions, shared app logic, harness wiring |
con-terminal | Theme + palette helpers shared across backends |
con-ghostty | Per-platform terminal backends: macOS embedded libghostty + Metal, Windows libghostty-vt + ConPTY + D3D11/DirectWrite, Linux Unix PTY + libghostty-vt + GPUI-owned StyledText paint |
con-agent | Rig integration, tools, hooks, conversation, skills |
con-cli | CLI + socket client for the live local control plane |
Each platform exposes the same GhosttyApp / GhosttyTerminal /
TerminalColors type names from con-ghostty, so the rest of the
workspace consumes the backend without per-call-site cfg gates.
See docs/impl/{linux,windows}-port.md for the per-platform plans
and the path to the long-term GPU-accelerated grid renderer.
Agent Model
- Shared Tokio runtime per window
- Per-tab agent sessions
- Tool and model events flow to the UI over channels
- Rig
PromptHookdrives streaming, approvals, and lifecycle events
For the full breakdown, see docs/impl/agent-harness.md.
Prerequisites
- Rust (stable, edition 2024)
cmake- Zig: use Zig 0.16.0 exactly for full terminal builds. The pinned Ghostty revision requires this version; older Zig releases cannot build it, and newer releases may change the build APIs again.
Quick setup with mise (recommended)
If you use mise, the repo root mise.toml
pins the exact Zig version. Run:
mise install # installs the pinned toolchain
mise exec -- just build # runs with Zig 0.16.0 on PATH
Run the just commands below through mise exec -- so the pinned tools are
available even when mise shell activation is not configured. For example,
mise exec -- just test runs the platform-appropriate test set. If your shell
already activates mise, you can use just directly.
Manual setup
If you do not use mise, install the prerequisites yourself:
- Zig: download the official 0.16.0 archive from
https://ziglang.org/download/0.16.0/and put the directory onPATH, or setCON_ZIG_BIN=/path/to/zig. - macOS:
cmakeplus Zig 0.16.0. The macOS release workflow installs Zig 0.16.0 explicitly before building embedded libghostty. - Windows: Zig 0.16.0, Visual Studio 2022 Build Tools with the Windows 10/11 SDK. Run full builds from a Developer Command Prompt for VS 2022 so
rc.exeis onPATH. If Windows Defender is on, either add an exclusion for the repo dir or disable real-time scanning — Zig's sub-build exes get briefly locked by MpEngine and spawn withFileNotFound. - Linux: Zig 0.16.0, plus the GPUI runtime apt deps the CI job already installs:
Thesudo apt-get install -y --no-install-recommends \ libxcb-composite0-dev libxcb-dri2-0-dev libxcb-glx0-dev \ libxcb-present-dev libxcb-xfixes0-dev libxkbcommon-x11-dev \ libwayland-dev libvulkan-dev libfreetype-dev libfontconfig1-dev \ mesa-vulkan-driversmesa-vulkan-driversline gives you a software ICD (llvmpipe) as a fallback for headless / VM environments; on a real desktop with a hardware GPU you can skip it.
CI mirrors this deliberately:
release-macos.yml,release-linux.yml, andrelease-windows.ymlinstall Zig 0.16.0 before release builds.- macOS app packaging sets
CON_GHOSTTY_PREFETCH_DEPS=1to populate Zig's package cache through curl/git and localzig fetchbefore building. This avoids a reproducible Zig direct Git-fetch failure in release CI. Ordinary development builds do not prefetch; they retain the on-failure retry. SetCON_GHOSTTY_PREFETCH_DEPS=0to opt out while diagnosing a local package issue. ci-macos-ghostty.ymlbuilds the native Ghostty binding on an Intel runner when the build path changes. Its manual dispatch also builds the full release binaries without signing.- The Linux PR smoke check in
ci-portable.ymlalso installs Zig 0.16.0 because it type-checkscon-ghosttywithlibghostty-vt. - The Windows and Linux PR jobs build and link the real libghostty-vt backend, then run
con-ghosttytests. Do not replace these withCON_SKIP_GHOSTTY_VTor check-only coverage: removed symbols and calling-convention drift otherwise remain invisible until release.
Build
# macOS / Linux
cargo build
# Windows — must use the `w*` aliases. The default `con` binary cannot
# exist on Windows because `CON` is a reserved DOS device name, so the
# Windows build ships as `con-app.exe` via a feature-gated alias bin
# target. `cargo wbuild` is `cargo build --no-default-features
# --features con/bin-con-app`; `wrun`, `wcheck`, `wtest` mirror it.
cargo wbuild -p con --release # → target\release\con-app.exe
If you have just installed, the root justfile wraps the common local
flows:
just build # debug build for the current platform
just run # run from source
just test # platform-appropriate test set
just check # fast type check
just install # build and install to the local platform install path
On Windows, those default recipes dispatch through the cargo w* aliases
above, so they produce and run con-app.exe instead of trying to build a
reserved con.exe name. Platform-specific release helpers are also available,
for example just channel=beta macos-release,
just channel=beta linux-release, just arch=x86_64 macos-bundle, and
just windows-build-release.
Run
# macOS / Linux
cargo run -p con
# Windows
cargo wrun -p con
With optional arguments:
RUST_LOG=con_agent::flow=info,con_agent=warn,con_core=warn,con::suggestions=debug,con_core::suggestions=debug cargo run -p con
Test
cargo test --workspace # macOS / Linux
cargo wtest -p con-core -p con-cli -p con-agent -p con-terminal # Windows (portable crates only)
Release Build
cargo build --release -p con # macOS / Linux
cargo build --release -p con-cli # control-plane CLI
cargo wbuild -p con --release # Windows → target\release\con-app.exe
cargo build --release -p con-cli # Windows → target\release\con-cli.exe
For signed macOS release artifacts, use:
./scripts/macos/release.sh
The macOS app bundle contains both Contents/MacOS/con and
Contents/MacOS/con-cli; the release verifier fails if the CLI is
missing. The Homebrew cask and Unix installer expose that bundled
con-cli on PATH so orchestrators such as pi-interactive-subagents
do not need a separate source checkout.
Release CI also has a final promotion gate. Platform jobs verify the
artifact shape before upload, and release-finalize.yml keeps the
GitHub Release drafted unless all expected assets, appcasts, and
gh-pages installer scripts are present for the same tag. A broken
artifact should fail private, not become /releases/latest. Internal
v*-dev.* smoke tags are prereleases, never update public
stable/beta appcasts or Homebrew casks, do not embed a Sparkle feed URL,
and are only gated on artifact and installer-script shape.
For a Linux release tarball (un-signed; mirrors the Windows preview's distribution shape), use:
CON_RELEASE_VERSION=0.1.0-beta.X CON_RELEASE_CHANNEL=beta \
./scripts/linux/release.sh
Output lands in dist/con-<version>-linux-<arch>.tar.gz with a
SHA256 sum next to it. The CI workflow at
.github/workflows/release-linux.yml runs the same script on every
v* tag, attaches the tarball to the shared GitHub release, and
updates the Sparkle-shaped appcast at
https://con-releases.nowledge.co/appcast/<channel>-linux-x86_64.xml
that the in-app notify-only updater polls.
Useful Paths
crates/con-app/src— app shell and GPUI surfaces (the crate directory iscon-appbecauseconis a reserved DOS device name on Windows; the Cargo package and binary are still namedconon macOS, socargo run -p conworks as before — seedocs/impl/windows-port.md)crates/con-core/src— shared app logiccrates/con-agent/src— agent provider, hooks, tools, skillsdocs/design— design handoff setdocs/impl— implementation notespostmortem— issue writeups and lessons learned