A cross‑platform desktop UI (Avalonia/.NET 8) for driving the Codex CLI app server using its JSON protocol. It lets you:
- Select a workspace folder and browse files via a lazy file tree
- Start a Codex session and stream assistant output in real time
- Send user input that is wrapped as protocol
Submissions (app server) - Auto‑approve exec/patch requests (automatic)
- Pick a model (built-in or from
config.tomlprofiles) and load MCP servers from the Codex CLIconfig.toml([mcp_servers]section); see Windows setup for a WSL recipe - Keep multiple Codex sessions active at once using the tabbed header (each tab title shows its live status, e.g.,
Session 2 – thinking…) – See live token usage and estimated context remaining in the header
Important: This app runs Codex through the
app-serversubcommand.
- .NET SDK 8.0+
- Codex CLI installed and on
PATH- Verify with:
codex app-server --help
- Verify with:
- No external Git required — uses LibGit2Sharp for repo init/staging/commit
Semantic Developer can drive the Codex CLI from Linux, macOS, or Windows.
- Install the .NET 8 SDK and the Codex CLI in your Linux environment.
- Profiles & MCP servers live under
~/.codex/config.toml(respects$CODEX_HOME); prompts under~/.codex/prompts/.
- Install .NET 8 (e.g.,
brew install dotnet-sdk) and the Codex CLI (brew install codexor the official installer). - Profiles & MCP servers:
~/.codex/config.toml(respects$CODEX_HOME); prompts under~/.codex/prompts/.
- RECOMMENDED see Windows setup recipe
- Install the Windows .NET 8 SDK and Codex CLI for Windows, ensuring
codex.exeis on your WindowsPATH. - Profiles & MCP servers default to
%USERPROFILE%\.codex\config.toml(respectsCODEX_HOME); prompts live under%USERPROFILE%\.codex\prompts\.
- Restore/build:
dotnet build SemanticDeveloper/SemanticDeveloper.sln
- Run the app:
dotnet run --project SemanticDeveloper/SemanticDeveloper
- Open the app, click “Select Workspace…” and choose a folder.
- If it isn’t a git repo and the Git library is available, you’ll be prompted to initialize one.
- You can also initialize later from the header via “Initialize Git…”.
- Click “Restart Session” to launch
codex app-serverin the workspace directory (a session also starts automatically after you select a workspace). - Type into the input box and press Enter to send. Output appears in the right panel.
- “CLI Settings” lets you change:
- Model & reasoning effort
- Before a session starts, the picker loads from
SemanticDeveloper/SemanticDeveloper/models.jsonso you can choose models offline. Keep this file updated as Codex releases new entries. - When the app connects to Codex, the dialog refreshes with the live catalog.
- Any profiles defined in
config.toml(e.g.,$CODEX_HOME/config.toml, defaulting to~/.codex/config.toml) are appended to the list and marked with an asterisk (*). Selecting a profile locks the reasoning controls and lets the profile determine the model/effort. - Profiles are optional—if you don’t have one, simply pick a built-in model.
- Before a session starts, the picker loads from
- Verbose logging (show suppressed output)
- Model & reasoning effort
- Enable MCP support (mirrors the
[mcp_servers]entries from your Codex CLIconfig.tomland passes them directly to Codex)- Config defaults to
~/.codex/config.tomlon Linux/macOS and%USERPROFILE%\.codex\config.tomlon Windows; both honor$CODEX_HOME.
- Config defaults to
- Use API Key for Codex CLI (pipes the key to
codex login --with-api-keybefore sessions; does not rely on existing CLI auth)- Allow network access for tools (sets sandbox_policy.network_access=true on turns so MCP tools can reach the network)
- Without API key enabled, the app proactively authenticates with
codex auth login(falling back tocodex login) before sessions so your chat/GPT token is used.
- Need a second workspace or want to keep another Codex stream alive? Hit the + button next to the session tabs to spin up a parallel session—tab titles update in real time so you can see whether each workspace is
disconnected,thinking…, oridle. - Right-click a tab to rename it or use the per-session Close Tab button/context menu to shut it down when you are done.
- Right-click any folder in the workspace tree and choose Create AGENTS.md to seed a directory-specific instruction file.
- The file is created inside the chosen folder (or opened if it already exists) and loaded into the editor so you can tailor the guidance.
- Codex CLI automatically honors the closest
AGENTS.mdwhen editing files: deeper files override parent folders, and rules apply to the entire subtree beneath the file. - Use these files to capture coding conventions, test commands, or “do/don’t” rules that the agent must follow for that part of the repo.
- Learn more about the convention at agents.md.
If you define profiles in config.toml, Semantic Developer surfaces them in the model picker (marked with *) alongside the built-in catalog. They’re entirely optional—the app works out of the box with the bundled models.
Example config.toml profiles:
[profiles.gpt-5-high]
model = "gpt-5"
model_provider = "openai"
approval_policy = "never"
model_reasoning_effort = "high"
model_reasoning_summary = "auto"
[profiles.gpt-5-medium]
model = "gpt-5"
model_provider = "openai"
approval_policy = "never"
model_reasoning_effort = "medium"
model_reasoning_summary = "auto"
[profiles.gpt-5-low]
model = "gpt-5"
model_provider = "openai"
approval_policy = "never"
model_reasoning_effort = "low"
model_reasoning_summary = "auto"
[profiles.gpt-5-codex-high]
model = "gpt-5-codex"
model_provider = "openai"
approval_policy = "never"
model_reasoning_effort = "high"
model_reasoning_summary = "auto"
[profiles.gpt-5-codex-medium]
model = "gpt-5-codex"
model_provider = "openai"
approval_policy = "never"
model_reasoning_effort = "medium"
model_reasoning_summary = "auto"-
The left file tree and right log pane are resizable using the vertical splitter between them.
-
The header shows:
- Current status:
idle,thinking…,responding…,applying patch…,starting…, orerror. - A soft indeterminate progress bar while busy.
- Token stats (when available):
tokens <blended-total> • <percent> left. The percent remaining is an estimate based on the model’s context window and may differ slightly from the server’s internal view. - When inside a Git repository: current branch and a small Git menu for quick actions.
- Current status:
The app integrates basic Git operations directly in the header. All actions use LibGit2Sharp (embedded libgit2); the system git command is not required.
-
Branch indicator
- Shows the current branch (e.g.,
main) after the workspace path when the selected folder is inside a Git repo.
- Shows the current branch (e.g.,
-
Git menu (Git ▾)
- Commit…
- Stages all changes (
*) and creates a commit with the provided message. - Uses your Git config for name/email if available; otherwise falls back to a local signature like
<user>@local. - If there are no changes, you’ll get a friendly “No changes to commit.” notice.
- Automatically pushes the current branch to its tracked remote (defaults to
origin). - Optional: tick Create Pull Request to open your browser to a GitHub compare page after a successful push.
- Stages all changes (
- New Branch…
- Creates and checks out a new branch based on the default branch when available.
- Behavior details:
- Performs a best‑effort
fetchfromoriginfirst (no merge/rebase into your working copy). - Bases the new branch on, in order of preference:
origin/main,origin/master, localmain, localmaster, then currentHEAD. - Example log:
Created and checked out 'feature-x' (based on origin/main).
- Performs a best‑effort
- Switch Branch…
- Checks out an existing branch by name (no automatic fetch/merge).
- Get Latest
- Fetches from the tracked remote (defaults to
origin) and fast-forwards the current branch when possible. - Requires the branch to track a remote counterpart; otherwise a helpful log message is shown.
- Stops early if a merge or rebase would be required (fast-forward only).
- Fetches from the tracked remote (defaults to
- Rollback Changes…
- Hard‑resets the working directory to
HEADand deletes untracked files. - Prompts for confirmation since this discards local changes.
- Hard‑resets the working directory to
- Refresh
- Refreshes the branch label and the file tree’s Git status coloring.
- Commit…
Example workflow
- Switch to an existing base branch (e.g.,
mainormaster). - Choose Git ▾ → Get Latest to fast-forward your local branch.
- Use Git ▾ → New Branch… with your preferred naming convention (e.g.,
feature/login-form). - After making changes, select Commit…, enter a message, let the app push the branch for you, and optionally enable Create Pull Request to jump straight to GitHub once the push completes.
- Initialize Git…
- When the workspace is not a Git repo, an “Initialize Git…” button appears in the header.
- Initializes a repository in the selected folder, stages files, and attempts an initial commit (best‑effort).
- This is the same capability offered right after selecting a non‑repo folder.
Notes
- Operations are local unless a remote call is required (the optional
fetchduring “New Branch…”, the fast-forward fetch performed by “Get Latest”, and the push that runs after each commit). - Open your workspace at the root of the Git repository (the folder containing
.git/) so the app can detect and enable Git features; selecting a subdirectory skips the Git UI. - Pull support is limited to fast-forwarding via Get Latest; pushing is still not exposed in the UI.
- On some Linux distros, libgit2 may require additional native dependencies. If the Git library can’t load, the UI will hide Git actions and log a helpful message.
-
Always uses the Codex app server: the app starts the CLI with
codex app-server. -
User input is wrapped as a protocol
Submissionwith a newidand anoppayload:- Defaults to
user_inputwithitems: [{ type: "text", text: "..." }]. - When the app infers that a full turn is required, it sends
user_turnand includescwd,approval_policy(defaults toon-request),sandbox_policy(defaults toworkspace-write), optionalmodel, and default reasoning fields.
- Defaults to
-
Auto‑approval: when the CLI emits an
exec_approval_requestorapply_patch_approval_request, the app automatically approves the request. There is no setting to toggle this. -
Conversation rendering (right pane):
- Messages are labeled and colorized:
You:,Assistant:, andSystem:. - Streaming assistant deltas append inline under a single
Assistant:header. - Noisy protocol JSON, unified diffs, and patch bodies are suppressed; concise system lines are logged instead (e.g.,
System: Applying patch…,System: Patch applied). - “System” lines denote app/system events and CLI housekeeping, so you can distinguish them from assistant content.
- Messages are labeled and colorized:
-
Status behavior during a turn:
thinking…while the model reasons or patches are being applied.responding…while streaming assistant deltas.- Returns to
idleonly when the server signalstask_complete(orturn_aborted).
-
Stop vs. Restart:
- Stop sends an
interruptto the app server to abort the current turn (like pressing Esc in the CLI) without killing the session; it falls back to terminating the process if needed. - Restart ends the current process and starts a fresh session in the same workspace.
- Stop sends an
-
Clear Log clears both the on‑screen log and the underlying editor document; it does not affect the session.
-
Prompts button (bottom-right toolbar):
- Lists every markdown prompt file in
$CODEX_HOME/prompts(defaults to~/.codex/prompts). - Selecting a prompt sends
/filename.mdthrough the active session—exactly like typing it in the CLI—without leaving the UI. - Prompts are sorted alphabetically; create or edit them directly on disk.
- Lists every markdown prompt file in
- The left pane includes an MCP section below the file tree:
- Servers list: a checkbox per server defined under
[mcp_servers]in your Codexconfig.toml. Only selected servers are injected at session start. - Tools list: after session starts, tools are grouped under their server names using short identifiers (the full identifier is available as a tooltip).
- Header buttons:
- ⚙ opens
config.tomlin your editor. - ↻ reloads the config and updates the server list.
- ⚙ opens
- Servers list: a checkbox per server defined under
- Only local stdio servers are supported (command/args/cwd/env). Remote transports (e.g., SSE) are not injected.
Config file location:
- Linux/macOS:
~/.codex/config.toml(or$CODEX_HOME/config.tomlif set) - Windows:
%USERPROFILE%\.codex\config.toml(honorsCODEX_HOME)
Semantic Developer now shares the same MCP source as the Codex CLI. Define servers once inside
config.tomland both the CLI and UI will pick them up automatically.
Selection behavior:
- The checkbox state in the MCP pane determines which servers are passed to Codex at session start.
- Change selections, then click “Restart Session” to apply.
-
“Failed to start 'codex'”: Ensure the CLI is installed and on
PATH. Test withcodex --helpandcodex app-server --help. -
Model selection: Prefer using
config.toml(via Profiles). You can setmodel,model_provider, and related options per the Codex docs. -
Git init issues: The app uses LibGit2Sharp (no Git CLI needed). If the native lib fails to load, the app skips initialization. Commits use your configured name/email if available; otherwise a fallback signature is used.
-
Authentication:
- If you are not using an API key and the Codex CLI is not logged in (no
~/.codex/auth.json), the app-server stream returns 401. The app detects this and prompts to runcodex auth loginfor you. Follow the browser flow; on success the app restarts the session automatically. - If your CLI version doesn’t support
auth login, the app falls back tocodex login. - When “Use API Key” is enabled in CLI Settings, the app pipes your key into
codex login --with-api-keybefore sessions and on 401. If login succeeds, it restarts the session automatically.
- If you are not using an API key and the Codex CLI is not logged in (no
- The bottom-right pane has a
Run Appbutton (next to Shell) that scans the workspace for common runnable targets and either runs the single best candidate or lets you choose among multiple options. - Detection heuristics (depth-limited, skipping heavy folders like
node_modules/,bin/,obj/):- Node:
package.jsonwithdevorstart→ prefersyarn(whenyarn.lock),pnpm(whenpnpm-lock.yaml), elsenpm. Builds first when abuildscript exists. - .NET:
*.slnand*.csproj→ enumerates projects and runsdotnet buildthendotnet run --project <csproj>for the selected one. - Rust:
Cargo.toml→ builds withcargo buildthen runscargo run. - Python:
main.pyorapp.py→python3/python. - Go:
go.mod→ builds withgo buildthen runsgo run .. - Java:
pom.xml(Maven) → runsmvn packagethen runs the jar fromtarget/.build.gradle/gradlew(Gradle) →gradle buildthengradle run. - HTML:
index.html→ opens in your default browser.
- Node:
- Output from commands streams into the log. For long-running dev servers, the process runs until you close it from its own console or terminate externally.
SemanticDeveloper/— App source (UI, services, models).Installers/— Installer projects for Linux, Mac OS and Windows - untested as of yet...
- App-server mode is enforced in code; the app does not fall back to legacy proto mode.
- Settings are stored under the OS‑specific application data directory and loaded on startup.
- The log view uses AvaloniaEdit + TextMate (Dark+) for better legibility and simple JSON syntax coloring.
- Windows: see
SemanticDeveloper/Installers/Windowsforbuild.ps1to produce a ZIP or Inno Setup installer. - macOS: see
SemanticDeveloper/Installers/macOSforcreate_dmg.shto produce a.appand.dmg. - Linux (Debian/Ubuntu): see
SemanticDeveloper/Installers/Linuxforbuild_deb.shto produce a.deb.
Each installer project contains detailed prerequisites and step-by-step instructions.
- Token stats in the header are derived from
token_countevents. The percent remaining is estimated (using a baseline of ~12k tokens for fixed prompts) and may be approximate.