- Multiple sub-agents are working in this repository. Don't be alarmed if something gets changed around your code. This is normal. Just get your work done without affecting the work of other sub-agents or breaking their work.
- Don't get stuck on stale git locks. You can delete those and continue on your work without confirmation.
The repository root was restructured on 2026-08-22. Old top-level folders
(gpui/, native/, ghostex-web/, gxserver-rs/, sidebar/, shared/,
components/, lib/, src/, zehn-rs/, ghostex-paths/, ghostex-history/,
mobile-chat/, mobile-find/, ghostty/, tui2/, zmx/, code-server/,
zehn/) no longer exist at the root. If you are working from an old plan,
transcript, or memory file, re-derive the path before you search or edit.
One-line vocabulary:
apps/= deliverables (things that ship and have an entry point).views/= embedded pages an app ships (never call these "webviews" or "surfaces").packages/= libraries imported by apps and by the server..dependencies/= ALL external-origin code, including code we edit.
Current root:
Ghostex/
├── .dependencies/ # ALL external-origin code (edited or not)
│ ├── ghostty/ ghostty-patches/ code-server/ tui2/ zmx/ zehn/
│ └── zed/ cef-rs/ gpui-component/
├── apps/
│ ├── desktop/ # Rust/GPUI desktop app (crate ghostex-gpui)
│ │ ├── src/ # Rust
│ │ ├── sidebar/ # CEF entry modules (main, chat, find, kanban, manage)
│ │ └── views/ # embedded pages: modal-host, titlebar-host, manage, kanban, meo
│ ├── web/ # static browser build of the shared workspace UI
│ ├── mobile/
│ │ ├── app/ # React Native / Expo submodule
│ │ └── views/ # chat/ + find/ view bundles embedded by the RN app
│ ├── editor/ # GhostexEditor daemon (Monaco prompt editor)
│ └── history-cli/ # `ghostex-history` CLI crate
├── server/ # gxserver crate (binaries: gxserver, ghostex)
├── packages/
│ ├── shared/ # cross-app contracts + logic
│ ├── core-ui/ # the shared React app UI (sidebar, chat, find, settings, assets)
│ ├── components/ # shadcn primitives (ui/) + utils.ts
│ ├── find/ # Rust prompt-history search (crate ghostex-find)
│ └── paths/ # Rust path resolution (crate ghostex-paths)
├── scripts/ media/ skills/ docs/
└── package.json tsconfig.json AGENTS.md CHANGELOG.md appcast*.xml bun.lock …
Imports: the @/ alias maps to the repo root only, and every import uses the
real path — @/packages/shared/…, @/packages/core-ui/…,
@/packages/components/…, @/packages/components/utils. There are no
per-package alias remaps, so every import is grep-able as a literal path.
The full move map, per-file referencer inventory, and split log live in
docs/2026-08-22/repo-restructure/ (PLAN.md, PROGRESS.md, REFERENCERS.md,
SPLITS.md). Read those before assuming a file is missing.
Only three Ghostex apps are active development targets:
- Desktop app —
apps/desktop/(Rust/GPUI shell + CEF React views). This is the desktop app.bun run start,bun run build, and everyrelease:*script inpackage.jsontarget it. - Web app —
apps/web/(static browser build of the shared workspace/Agents UI, talks to gxserver). - Mobile app —
apps/mobile/(React Native/Expo submodule inapps/mobile/app, ships Android).
Deprecated. Never route new features, refactors, parity work, or bug fixes to these:
- macOS Swift/AppKit app — removed on 2026-08-20. The Swift sources and their WKWebView sidebar host are gone; do not restore them, re-add a macOS Swift target, or treat the old app's behavior as the spec for new work.
- Native iOS app and Termux-fork Android app — already removed from this checkout; they live under
/Users/madda/dev/_active/ghostex-deprecated/and must never be restored as active release inputs.
Everything under apps/, packages/, and server/ is active. .dependencies/
is external-origin code: some of it we edit (ghostty, tui2, zmx, code-server),
some of it is a pure build input (zed, cef-rs, gpui-component), and one entry
(.dependencies/zehn) is reference-only.
apps/desktop/views/ holds the React pages the desktop app ships inside CEF.
apps/desktop/vite.config.ts builds them, together with the CEF entry modules in
apps/desktop/sidebar/, into the app's HTML bundles:
apps/desktop/views/modal-host.tsx→modal-host.html(app modals, dropdowns, toasts).apps/desktop/views/titlebar-host.tsx→titlebar-host.html, with its implementation split acrossapps/desktop/views/titlebar/. The desktop app only loads this page for the Tips and Resources dropdown panels. The gpui titlebar itself is native Rust, not this page. The project name, the Agents/Code/Browser/Kanban/Automate/Docs mode tabs, the buttons, and the tooltips are drawn byrender_titlebar/render_mode_tabinapps/desktop/src/app/render/mode_switcher_and_titlebar.rs; the titlebar menus, popups, tips and resources behaviour live inapps/desktop/src/app/titlebar/; the mode-tab list is built bytitlebar_mode_switcher_itemsinapps/desktop/src/app/helpers/titlebar.rs(with thin wrappers inapps/desktop/src/app/workarea.rsandapps/desktop/src/app/model/runtime_state.rs). Titlebar work for the desktop app belongs in those Rust files, not intitlebar-host.tsx.apps/desktop/views/manage.tsx(+apps/desktop/views/manage/) is the Docs surface, loaded throughapps/desktop/sidebar/manage-main.tsx.apps/desktop/views/tasks-placeholder.tsx(+apps/desktop/views/project-board/) is the Kanban surface, loaded throughapps/desktop/sidebar/kanban-main.tsx.apps/desktop/views/meo/is the markdown editor behind the Docs surface, reached throughmanage.tsx→meo/editor.ts.apps/desktop/views/project-board-shared.tsandapps/desktop/views/combined-sidebar-mode.tsare shared logic consumed by those pages.
Shared gxserver logic lives in packages/shared/ (for example
packages/shared/gxserver-presentation-cache.ts); the desktop runtime client is
apps/desktop/sidebar/gxserver-runtime.ts (+ gxserver-runtime/), and the web
app has its own client at apps/web/src/connections/gxserver-client.ts.
The shared React app UI is packages/core-ui/ (packages/core-ui/sidebar-app.tsx),
mounted by the desktop app through apps/desktop/sidebar/main.tsx and by the web
app. Its icons are in packages/core-ui/assets/.
This repository contains Ghostex app code plus large external terminal/editor code. Start searches in the smallest app-owned area that matches the task, and only expand after the first pass doesn't find what you need.
Default search posture:
.dependencies/**is THE exclusion for external code. Everything imported or vendored now lives there, so a single-g '!.dependencies/**'replaces the old per-tree ghostty/tui2-vendor/code-server excludes. Also exclude build, dependency, and cache trees:node_modules/**,.git/**,dist/**,build/**,out/**,target/**,storybook-static/**,tmp/**,artifacts/**,.cache/**,.turbo/**,.vite/**,.zig-cache/**,zig-out/**, andDerivedData/**.- Do not search
.dependencies/ghostty/first just because a symbol, setting, file, or bug report mentions "ghostty", "terminal", "session", "restore", "fork", "launch", or "pane"; many Ghostex-owned files use those words. - If a targeted app-owned search misses, expand one layer at a time and explain why the next folder is relevant before searching large external trees.
Search these app-owned areas first by task:
- Desktop app shell, window lifecycle, app startup, terminals/panes, titlebar, session restore/fork launch plans, terminal host integration:
apps/desktop/src/,apps/desktop/sidebar/,apps/desktop/native/macos/,apps/desktop/scripts/,packages/core-ui/,packages/shared/, andscripts/. - Frontend UI, React components, settings, project/sidebar interactions, Storybook stories:
packages/core-ui/,packages/components/,packages/components/ui/,packages/shared/,apps/desktop/sidebar/,apps/desktop/views/(for the modal host, titlebar host, Docs/manage, Kanban, andmeopages listed above). - Web app:
apps/web/src/, then the sharedpackages/core-ui/andpackages/shared/code it builds on. - Session grid, prompts, agent metadata, workspace/project state, contracts, shared tests:
packages/shared/, then the consuming surface inpackages/core-ui/,apps/desktop/sidebar/,apps/desktop/views/,apps/mobile/views/, orserver/src/. - Server, remote protocol, hooks, authentication, remote setup:
server/src/,packages/shared/,scripts/. The server crate is heavily modularized:server/src/server/(HTTP/WS core inmod.rsplus per-concern submodules),server/src/agents/, the flatserver/src/session_chat_*.rsfamily,server/src/domain/,server/src/zmx/,server/src/typed_operations/,server/src/portless/, andserver/src/agent_hooks/. Crate name isgxserver; it builds thegxserverandghostexbinaries. - TUI or zmx behavior:
.dependencies/tui2/and.dependencies/zmx/src/+.dependencies/zmx/test/. These are the deliberate exception to the.dependencies/**exclusion — Ghostex edits them — but keep.dependencies/tui2/vendor/**excluded unless the task is specifically about the vendored VT library. - Prompt-history search (
gx f, the Find surface):packages/find/for the engine,server/src/agent_prompt_search.rsfor the API,packages/core-ui/find/for the shared UI. - Mobile app work:
apps/mobile/is the only active mobile app and releases Android through the React Native/Expo project inapps/mobile/app(a git submodule). Its embedded chat and find pages areapps/mobile/views/chat/andapps/mobile/views/find/, bundled bybun run build:mobile-chat/bun run build:mobile-find. The retired native iOS and Termux-fork Android repositories live under/Users/madda/dev/_active/ghostex-deprecated/and must not be restored as active release inputs. - Assets, sounds, icons, and release tooling:
media/,apps/desktop/assets/,packages/core-ui/assets/,scripts/, andscripts/release-gpui/.
Search external Ghostty code only when the task is explicitly about upstream
Ghostty behavior, the embedded Ghostty source, Zig terminal internals, Ghostty
macOS internals, or a build/test failure whose failing file is already under
.dependencies/ghostty/**. Even then, target the relevant subfolder such as
.dependencies/ghostty/src/, .dependencies/ghostty/macos/,
.dependencies/ghostty/pkg/, or .dependencies/ghostty/test/, and continue
excluding .dependencies/ghostty/.zig-cache/** and
.dependencies/ghostty/zig-out/**. Ghostex's own patch series on top of
upstream is .dependencies/ghostty-patches/, re-applied by
scripts/sync-ghostty.sh.
Preferred rg shape for first-pass searches:
rg -n "pattern" apps/desktop/src apps/desktop/sidebar packages/core-ui packages/shared \
server/src apps/web/src scripts \
-g '!.dependencies/**' -g '!node_modules/**' -g '!storybook-static/**' -g '!tmp/**' \
-g '!dist/**' -g '!build/**' -g '!out/**' -g '!target/**' -g '!artifacts/**' -g '!.git/**'Add apps/desktop/views to that list only when the task is about the desktop
modal host, titlebar host, Docs/manage, Kanban, or meo pages, or about the
shared apps/desktop/views/*.ts logic. Add packages/components for shadcn
primitives, and apps/mobile/views for the mobile embedded pages.
gx f used to spawn a bundled Zig binary built from the zehn submodule. It
does not any more. Prompt-history search is the packages/find/ Rust crate
(crate name ghostex-find), compiled into gxserver and the ghostex CLI, so:
gx fruns the picker in-process. There is nobin/zehnto stage, noGHOSTEX_ZEHN_BIN, noZEHN_ZIG, and no Zig 0.16 requirement for a release..dependencies/zehn/is kept only as reference for the original implementation. Never build it, bundle it, add it back to a packaging list, or treat it as the spec for new work — changepackages/find/instead.- Two hotkeys moved in both the terminal picker and the GUI so the surfaces
share one key map: agents is
^g(was^t) and projects is^j(was^r), because browsers reserve Ctrl+T and Ctrl+R and will not hand them to a page. - The GUI (
packages/core-ui/find/) andgx fshare the same scanner, matcher, Codex cache, and favorites file, so a prompt starred in one is starred in the other. Anything that would make them rank or star differently is a bug.
Never generate fallbacks when the right solution is to actually correct the behavior itself to fix the issue. Fallbacks should be used in rare cases only because they add complexity and hide issues and introduce useless logic.
Example of adding bad fallback code:
Agent: I found the likely root cause: the Ghostty/Restty path is generating local font sources from your configured terminal font family, and VS Code webviews are blocking the local-fonts permission. I'm patching that helper to fall back cleanly instead of passing unusable local-font sources into Restty.
Example of what you should do instead:
We should make it not fall back but instead just do the right thing from the start. Yes. The clean fix is to stop generating local font sources at all when the current webview environment can't use the local-fonts capability. I'm wiring that check into the Restty font-source helper so Ghostty starts in the correct mode instead of trying-and-failing first.
This applies to the active desktop app (GPUI views, CEF pages, AppKit shims, Ghostty terminal hosts). The historical WKWebView wording below refers to the deprecated macOS Swift app; the rule itself is unchanged for the desktop app.
Ghostex native UI should be built with strict normal layout ownership: lay out interactive AppKit, WKWebView, CEF, Ghostty, sidebar, titlebar, pane, and divider regions as non-overlapping sibling or child frames wherever possible. Do not solve click, drag, hover, or focus bugs by stacking transparent views, extending webviews under native chrome, adding broad parent/window hit-test routing, or creating hidden overlap between interactive regions.
Use real, exact native views for interactive boundaries such as splitters and sidebar dividers. If a divider should be easy to understand, make the visible divider itself the grab target rather than adding invisible overlap over adjacent content. Keep visual-only chrome as non-interactive layers or non-overlapping decoration instead of views that can compete for input.
Before adding any hitTest override, NSWindow pre-dispatch mouse routing, synthetic coordinate rerouting, invisible interactive overlay, or intentional overlap between interactive regions, the agent must stop and explain the proposed exception to the user, including why strict normal layout cannot solve it. The agent must get explicit user confirmation before implementing that exception.
Native child windows are the accepted pattern for app modals, dropdowns, command palette, rename, Resources, Tips & Tricks, and similar overlay surfaces. Those windows own their own frames and input, so they should not be replaced with main-window transparent webview overlays or root-level hit-test shields.
When working from a Ghostex Project board ticket, use the bd CLI installed in the environment running that project—macOS, Linux, or the selected WSL distribution—and move the bead through the project swimlanes instead of leaving it in open/Todo. Ghostex's Kanban runtime uses this same system binary, so do not depend on a separate gx bd wrapper or a bundled Ghostex copy. If bd is missing or a board command fails, ask the user to install or update to the latest Beads release in that same environment before continuing.
- Park for later:
bd update <id> --status backlog - Claim work:
bd update <id> --status in_progress - Ready for test:
bd update <id> --status test - Ready for review:
bd update <id> --status review - Done:
bd close <id>
After each turn where you made progress on the bead, add a comment so humans can follow the ticket without reading the full agent transcript:
bd comment <id> "<summary>"- Focus on user-facing requirements delivered and high-level technical approach.
- Do not list specific files or line numbers.
The Project board "Start work" action copies a prompt that includes these commands and the comment guidance.
Never interpret "revert your changes" or "revert what you did" as permission to reset, restore, clean, delete, or otherwise discard the whole worktree. Other agents and the user may have unrelated uncommitted or untracked work in the same repo.
Before running any destructive command, including but not limited to git restore ., git checkout -- ., git reset --hard, git clean, rm -rf, or deleting untracked files, you must:
- Show the user the exact files/directories that would be affected.
- Explain whether each file is tracked or untracked.
- Confirm that those files are definitely your own changes, not user work.
- Ask for explicit approval before executing the destructive command.
If the user asks to revert only the agent's changes, use surgical reversal: inspect diffs, identify the exact hunks/files you changed, and revert only those. When uncertain, stop and ask. Never use broad restore/clean commands as a shortcut.
Multiple agents and the user work in this same checkout at the same time. Files you touched earlier in your session, or that you read a while ago, may have been changed by someone else since. Treat every uncommitted change you did not make yourself as protected user work.
- Before editing a file you last read a while ago (or that you carry from an earlier plan/worktree/thread), re-read its current on-disk content first and apply your change to that, as a targeted edit. Never write back a whole file from a stale copy in your context: that silently erases every change other agents made to it in between, with no way to recover it from git.
- Never run
git checkout,git restore,git stash, orgit reseton a path that has hunks you did not author. - When committing, never selectively drop pending hunks in files you commit. Either include a file's whole pending diff, or split it hunk-by-hunk only if you verify afterwards (
git status+git diff) that every hunk you excluded still exists in the working tree. A batch "split the working tree into topical commits" pass must end with zero silently-vanished hunks. - If you find changes in a file you are about to modify that you cannot attribute to your own task, keep them intact and mention them to the user instead of "cleaning them up".
Example of what this rule prevents (happened on 2026-07-09): one agent added the desktop sidebar persistence fix (cef_app_ui_profile_cache_path, in the CEF shell code that is now apps/desktop/src/cef/shell/ — its pre-restructure path was gpui/src/cef/shell.rs) as uncommitted working-tree state. Later that day, a concurrent agent's titlebar/attention work was committed in an automated batch that wrote that file from a version without the fix. The fix had never been committed anywhere, so it vanished without a trace, the user's bug came back, and the fix had to be re-diagnosed and re-applied from scratch.
Corollary: after you verify a surgical bug fix, tell the user it should be committed promptly (or commit it when they ask) so concurrent agents cannot wipe it.
- Never run "bun run start" or any command that would restart the app unless I ask you to.
- TypeScript is gated by three configs, not one:
bun run typecheck(root —packages/shared,packages/core-ui,packages/components,apps/desktop/views,apps/mobile/views),bun run web:typecheck(apps/web/tsconfig.json), andbun run desktop:typecheck(apps/desktop/tsconfig.json, which coversapps/desktop/sidebar/andapps/desktop/views/). A change underapps/desktop/sidebar/is only checked bydesktop:typecheck. - Run desktop-crate cargo commands from inside
apps/desktop/, not with--manifest-pathfrom the repo root. The crate pins its own toolchain inapps/desktop/rust-toolchain.toml(1.95.0), and--manifest-pathfrom the root resolves the root toolchain instead and fails on dependency code that needs the pin.
- Routine disk logs must have an explicit Diagnostic disk logging scenario and may write only while both Show debug UI controls and that unexpired scenario are enabled. Do not add unscoped routine disk logging. Errors, crashes, and important warnings remain unconditional.
- Before testing or requesting a reproduction that needs diagnostic logs, record the current logging settings, enable only the smallest set of scenarios needed, and prefer the shortest useful expiry.
- Reproduce the issue yourself when authorized and practical. Otherwise, ask the user to reproduce it after confirming the required scenarios are enabled.
- As soon as the needed evidence is collected—or the logging attempt is abandoned—restore the previous settings and turn off every scenario and debug switch that you enabled. Never leave extra diagnostics running because they can consume disk, CPU, and make the user's computer lag while they continue working.
- Do not turn off scenarios or debug settings that were already enabled by the user; restore exactly the state observed before the diagnostic session.
- We run multiple agents at a time on 1 worktree so agents should never switch the branch this folder is on away from main
- If you need to do work that requires switching to a new branch then please create a temp worktree and do the needed work there.