Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
target/
zig/.zig-cache/
zig/zig-out/
ghostty.incomplete.*/
dist/
*.tar.gz
.worktrees/
Expand Down
34 changes: 34 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,39 @@ For live agent/control-socket behavior, prefer the maintained smoke harness:
LIMUX_SMOKE_PROFILE=debug ./scripts/xvfb-smoke-test.sh
```

## Local Runtime Freshness

For user-visible fixes, make sure the local `limux` entrypoint the maintainer
actually runs is updated before handing off. The fast local install path is:

```bash
./scripts/install-local-build.sh
```

That script builds the CLI and GTK host, installs them under
`$LIMUX_LOCAL_PREFIX` or `~/.local`, installs a matching `libghostty.so`,
updates the desktop entry, and verifies that `command -v limux` resolves to the
freshly installed CLI and that the host resolves the matching local library.
Restart any already-running Limux GUI before validating the new behavior; a
running process keeps using the old mapped executable.

Use the status check when you need to confirm this PC is dogfooding the local
build:

```bash
./scripts/local-build-status.sh
```

If a change touches release packaging, Ghostty resources, system linker config,
or distro artifacts, use the full package path instead:

```bash
./scripts/package.sh
```

When a runtime fix is not installed locally, say so explicitly in the handoff
instead of implying the user's active Limux app includes it.

## Runtime Control Path

There are two control-server paths:
Expand Down Expand Up @@ -133,6 +166,7 @@ name addressing, and by-name send path.

Useful references:

- Feature and dogfood workflow: `docs/development-workflow.md`
- Roadmap/current bridge status: `docs/cmux-parity-plan.md`
- Maintainability rules: `docs/maintainability.md`
- CLI usage: `README.md` and `./target/debug/limux-cli --help`
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ resolver = "2"
authors = ["limux contributors"]
edition = "2021"
license = "MIT"
rust-version = "1.92"
version = "0.1.19"

[workspace.dependencies]
Expand Down
70 changes: 63 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,31 @@ sudo ./install.sh --uninstall
sudo apt install libgtk-4-1 libadwaita-1-0 libwebkitgtk-6.0-4
```

### Troubleshooting Launches

Installed packages expose `limux` as the CLI entrypoint. Running `limux` with
no arguments launches the private GTK host from `libexec/limux/limux-host`;
desktop files should point at the CLI, not directly at `limux-host`.

If launch fails with an error like:

```text
libghostty.so: undefined symbol: gladLoaderLoadGLContext
```

the CLI is usually finding a stale `limux-host` binary that does not match the
installed `libghostty.so`. Remove old manual-install host binaries from
`~/.local/bin/limux-host` or reinstall Limux so the CLI, host, and
`libghostty.so` come from the same package. Source builds also require the full
Ghostty submodule, including `ghostty/vendor/glad/src/gl.c`; a `ghostty/zig-out`
stub or copied `libghostty.so` is not enough to build a working host.

## Build from source

### Prerequisites

- Rust toolchain (stable)
- Rust toolchain 1.92 or newer. The checkout selects Rust 1.92 through
`rust-toolchain.toml` so local scripts do not depend on your global default.
- Zig
- GTK4, libadwaita, WebKitGTK dev packages
- Initialized Ghostty submodule
Expand All @@ -88,7 +108,7 @@ git submodule update --init --recursive
cargo build --release

# Run (point to libghostty.so location)
LD_LIBRARY_PATH=../ghostty/zig-out/lib:$LD_LIBRARY_PATH ./target/release/limux
LD_LIBRARY_PATH=ghostty/zig-out/lib:$LD_LIBRARY_PATH ./target/release/limux
```

### Package a release tarball
Expand All @@ -102,6 +122,9 @@ This builds the binary, bundles `libghostty.so`, icons, and an install script in

## Development

The contributor workflow for shipping features while dogfooding the local build
is documented in [`docs/development-workflow.md`](docs/development-workflow.md).

Run the canonical local quality gate before committing:

```bash
Expand All @@ -110,10 +133,27 @@ Run the canonical local quality gate before committing:

Repository maintainability rules live in [`docs/maintainability.md`](docs/maintainability.md).

For user-visible CLI or GTK host changes, install the active local build before
validating it through the desktop entry or the `limux` command on `PATH`:

```bash
./scripts/install-local-build.sh
```

The script builds the CLI and GTK host, installs them under
`$LIMUX_LOCAL_PREFIX` or `~/.local`, copies a matching `libghostty.so`, and
verifies that the active `limux` entrypoint resolves to the fresh local build.
Restart any already-running Limux GUI after installing, then confirm the active
local runtime:

```bash
./scripts/local-build-status.sh
```

## Agent integrations

Limux ships first-class hooks for coding agents (Codex, Claude Code, and
Gemini CLI). Every terminal limux spawns auto-exports
Limux ships first-class hooks for coding agents (Codex, Claude Code, Gemini
CLI, and Pi). Every terminal limux spawns auto-exports
`LIMUX_WORKSPACE_ID` / `LIMUX_SURFACE_ID` / `LIMUX_PANE_ID` /
`LIMUX_TAB_ID` / `LIMUX_SOCKET`, so the CLI auto-targets the right place
with no flags needed from inside the agent's own terminal.
Expand All @@ -128,6 +168,7 @@ limux hooks setup
# Drop-in hook handlers translate hook JSON on stdin into notify/session state
echo '{"event":"stop"}' | limux claude-hook --event stop
echo '{"event":"finished"}' | limux gemini-hook --event finished
echo '{"event":"stop"}' | limux pi-hook --event stop

# Spin up a multi-agent collaboration team — one workspace per agent,
# launches each agent's CLI, and writes AGENTS.md describing the
Expand Down Expand Up @@ -155,15 +196,30 @@ limux send --workspace "$LIMUX_WORKSPACE_ID" --surface "<peer-surface-id>" \
See the auto-generated `AGENTS.md` (written into the shared cwd) for
the full protocol spec, peer table, and editable Policies section.

Checked-in hook templates live in [`hooks/`](hooks/). They mirror
`limux hooks setup` for Codex, Claude Code, and Gemini CLI; OpenCode is
omitted until its hook integration is ready.
Checked-in JSON hook templates live in [`hooks/`](hooks/). They mirror
`limux hooks setup` for Codex, Claude Code, and Gemini CLI. Pi is installed as
a generated extension under `~/.pi/agent/extensions/`; OpenCode is omitted
from default setup until its hook integration is ready.

After installing Pi hooks, restart any already-running Pi session so it loads
the generated extension. Set `LIMUX_PI_HOOKS_DISABLED=1` to disable the Pi
extension without uninstalling it.

Coding agents working on **limux itself** should read [`AGENTS.md`](AGENTS.md)
and [`CLAUDE.md`](CLAUDE.md) in the repo root — those cover the build
loop, crate map, and the `feat/cmux-parity` roadmap tracked in
[`docs/cmux-parity-plan.md`](docs/cmux-parity-plan.md).

## Settings

Open Settings from the gear icon in any pane header. Limux writes preferences
to `~/.config/limux/settings.json` by default and preserves unrelated keys
when editing settings.

The Fonts & Icons page controls terminal text size, Limux chrome text sizes,
and pane header icon sizes. Terminal font shortcuts below update the same
saved terminal text setting.

## Keyboard shortcuts

Most default shortcuts use `Ctrl`. Fullscreen defaults to `F11`. Custom remaps may also use `Cmd`, which Limux maps to either the Linux `Meta` or `Super` modifier. `Opt` maps to `Alt`.
Expand Down
114 changes: 114 additions & 0 deletions docs/development-workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Development Workflow

This repo has one delivery loop: build the feature in the workspace, verify it
against the right runtime path, then install that same build for local
dogfooding when the change is user-visible.

The checkout pins Rust 1.92 in `rust-toolchain.toml`. Keep that in sync with
the `rust-version` inherited by every crate from the workspace manifest.

## Repository Layout

- `rust/limux-protocol`: shared JSON envelopes and protocol types.
- `rust/limux-core`: in-process command dispatcher and state engine.
- `rust/limux-control`: Unix socket auth, framing, and standalone server.
- `rust/limux-ghostty-sys`: raw Ghostty C API bindings.
- `rust/limux-host-linux`: GTK4/libadwaita host, pane UI, terminal embedding,
and the production control bridge.
- `rust/limux-cli`: user-facing `limux` CLI and agent integration commands.
- `scripts/`: quality, smoke, local install, and release packaging entrypoints.
- `docs/`: workflow, architecture notes, testing notes, and active plans.

Treat `ghostty/` as vendored input from Limux's point of view. Use Ghostty's C
API rather than editing the vendored tree for Limux features.

## Feature Loop

1. Make the smallest change that fits the crate boundary.
2. Run a narrow check while iterating:

```bash
cargo check -p limux-host-linux
cargo test -p limux-cli
cargo check --workspace
```

3. Run the canonical gate before handoff or commit:

```bash
./scripts/check.sh
```

4. For live CLI, socket, agent, pane, or notification behavior, exercise the
production GTK bridge with the smoke harness:

```bash
LIMUX_SMOKE_PROFILE=debug ./scripts/xvfb-smoke-test.sh
./scripts/xvfb-smoke-test.sh
```

The standalone dispatcher is useful for unit tests, but user-visible CLI
behavior must be checked through the running GTK bridge when possible.

## Local Dogfood Loop

Install the local build that this PC should actually run:

```bash
./scripts/install-local-build.sh
```

By default this installs under `~/.local`. Set `LIMUX_LOCAL_PREFIX` to install
somewhere else, and set `LIMUX_LOCAL_PROFILE=debug` when a debug build is more
useful than release:

```bash
LIMUX_LOCAL_PROFILE=debug ./scripts/install-local-build.sh
```

After installing, restart any already-running Limux GUI. A running process keeps
using the executable and library it mapped at startup.

Confirm the machine is dogfooding the local build:

```bash
./scripts/local-build-status.sh
```

The expected local runtime layout is:

- CLI entrypoint: `$LIMUX_LOCAL_PREFIX/bin/limux` or `~/.local/bin/limux`.
- Host wrapper: `$LIMUX_LOCAL_PREFIX/libexec/limux/limux-host`.
- Host binary: `$LIMUX_LOCAL_PREFIX/libexec/limux/limux-host.bin`.
- Ghostty library: `$LIMUX_LOCAL_PREFIX/lib/limux/libghostty.so`.
- Build info: `$LIMUX_LOCAL_PREFIX/share/limux/local-build.txt`.

If `command -v limux` points at an older package, put the local prefix's `bin`
directory earlier on `PATH` before dogfooding:

```bash
export PATH="$HOME/.local/bin:$PATH"
```

## Release Loop

Use the release packaging path when a change touches packaging, Ghostty
resources, system linker behavior, distro metadata, or release artifacts:

```bash
./scripts/package.sh
```

CI release workflows build the Linux tarball, deb, AppImage, and RPM on the
Ubuntu 24.04 GLIBC floor. The AUR workflow publishes from release tarballs.

## Handoff Checklist

- Intended files only are changed.
- `./scripts/check.sh` passes, unless an explicit blocker is documented.
- Live GTK bridge behavior is smoke-tested for CLI or runtime changes.
- `./scripts/install-local-build.sh` has been run for user-visible local fixes.
- `./scripts/local-build-status.sh` confirms this PC's `limux` resolves to the
local build.
- Any already-running Limux GUI has been restarted before claiming dogfood
coverage.
11 changes: 11 additions & 0 deletions docs/maintainability.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,14 @@ That script is the source of truth for the repository quality gate and currently
- Keep pure logic separate from GTK widget wiring where possible.
- Move test modules out of large production files when they obscure the main codepath.
- Treat clippy findings as maintainability work, not optional cleanup.

## GTK UI Styling

- Sidebar workspace rows intentionally override the theme-provided
`.navigation-sidebar > row` horizontal padding and margins so selected and
unread row backgrounds span the full sidebar width.
- Keep the sidebar unread indicator as an inset `box-shadow`, not a border,
so marking a workspace unread does not change row width or text alignment.
- When changing sidebar row CSS in `rust/limux-host-linux/src/window.rs`, keep
the row-inset and unread-width regression tests updated with the intended
visual contract.
18 changes: 15 additions & 3 deletions hooks/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Limux Agent Hooks

These templates wire supported coding-agent hook systems into Limux session
restore tracking. They are intentionally limited to Codex, Claude Code, and
Gemini CLI until the OpenCode hook path is ready.
restore tracking. Default setup covers Codex, Claude Code, Gemini CLI, and Pi.
OpenCode remains omitted from default setup until its hook path is ready.

The preferred install path is the CLI installer:

Expand All @@ -17,19 +17,31 @@ That writes the equivalent configuration into each agent's user config:
| Codex | `$CODEX_HOME/hooks.json` or `~/.codex/hooks.json` |
| Claude Code | `$CLAUDE_CONFIG_DIR/settings.json` or `~/.claude/settings.json` |
| Gemini CLI | `~/.gemini/settings.json` |
| Pi | `~/.pi/agent/extensions/limux-hooks.ts` |

Use the files in this directory as canonical examples when reviewing or
manually repairing an agent config:
manually repairing JSON-based agent configs:

- `codex-hooks.json`
- `claude-settings.json`
- `gemini-settings.json`

Pi uses a generated TypeScript extension instead of a checked-in JSON template.
Regenerate it with:

```bash
limux hooks pi install
```

Restart any already-running Pi session after installing so Pi loads the
extension. New Pi sessions will load it automatically.

Each command calls `limux --json hooks <agent> <event>` and is guarded by a
per-agent disable variable:

```bash
LIMUX_CODEX_HOOKS_DISABLED=1
LIMUX_CLAUDE_HOOKS_DISABLED=1
LIMUX_GEMINI_HOOKS_DISABLED=1
LIMUX_PI_HOOKS_DISABLED=1
```
4 changes: 4 additions & 0 deletions rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[toolchain]
channel = "1.92"
components = ["rustfmt", "clippy"]
profile = "minimal"
1 change: 1 addition & 0 deletions rust/limux-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
rust-version.workspace = true

[dependencies]
anyhow.workspace = true
Expand Down
Loading