The PwrAgent desktop

The desktop app is where you live day-to-day. It reads and writes the same on-disk session state Codex Desktop uses, so your threads, transcripts, and authentication are shared between the two by default — open either one and your work is there.

What makes the PwrAgent side worth running:

State lives under ~/.pwragent/ (overridable with PWRAGENT_HOME or --profile <name>). No cloud relay and no PwrAgent-owned account — see Settings for how the desktop discovers your local Codex install and how authentication works.

Install the desktop from GitHub Releases. macOS uses the signed DMG; Linux uses Debian packages with manual upgrades documented in Linux Install.

The rest of this page is the operator-facing tour of what the desktop does, what’s not in it yet, and what’s on the roadmap.

What’s in the desktop today

First-run onboarding wizard

First-run onboarding wizard on the Codex Profile step, showing three card options: Shared (reuse existing Codex login), Isolated (fresh Codex profile for PwrAgent), and Multiple (paired profiles for work / personal / projects). A progress strip at the top shows the wizard has walked from Welcome through Mission control, Models / Providers, and is now on Profiles, with Messaging and Review still to come.
The wizard's Profiles step (the in-page heading reads Codex Profile). Shared (default) reuses your existing Codex login so PwrAgent and Codex Desktop share threads; Isolated creates one named Codex profile just for PwrAgent; Multiple sets up several paired profiles in one pass for work / personal / projects separation.

The first time you launch PwrAgent on a fresh profile, a wizard walks you through a few short choices, applies them to that profile’s config.toml, and drops you on the main app with everything wired up. No surprise modals later — you do this once per profile.

Six progress-strip stops, every one skippable to a sensible default:

  1. Welcome. What the rest of the wizard is going to ask.
  2. Mission control. Theme (dark / light / system) and density (mission-control / compact). Both flip the UI live as you click so you can see what you’re picking.
  3. Models / Providers. Per-model API key and provider config (e.g. xAI key for Grok). Skip when you don’t need anything beyond Codex’s built-in auth.
  4. Profiles. Three ways to pair PwrAgent with Codex:
    • Shared — PwrAgent and Codex Desktop share a single Codex auth + thread list. Default; closest to “just install and go.”
    • Isolated — one named PwrAgent profile, one matching CODEX_HOME directory. Pick this when you want a clean split from Codex Desktop or from your other PwrAgent install.
    • Multiple — up to five paired PwrAgent + Codex profiles in one pass. Pick this when you already know you want work / personal / side-project separation.

    Isolated and Multiple prompt you to name the new profile(s) inline before moving on.

  5. Messaging. Short safety preamble (what messaging is for, what it isn’t, and what gets stored where), then a provider picker for the six platforms (Telegram, Discord, Slack, Mattermost, Feishu / Lark, LINE). Skip is the default — Continue is gated behind an explicit acknowledgement checkbox, so nobody wires a bot by accident. For each platform you tick, a compact inline setup card walks the credential paste / Test / pair flow without leaving the wizard. Scope-aware pairing flips into shared-space pairing where the provider has spaces (Slack workspaces, Discord servers, Telegram supergroups, etc.).
  6. Review. Recap of what you chose, what got created, and the entry points (Settings → Profiles, Settings → Messaging) for whatever you skipped.

On Finish, PwrAgent auto-switches into the new paired profile if you picked Isolated or Multiple, so the very next window is already operating under the right ~/.pwragent/profiles/<name>/ and the matching ~/.codex/profiles/<name>/.

Want to replay it? Help → Replay Onboarding. Reopens the wizard without resetting any of your settings — useful as a guided tour or when you forget where a specific setting lives.

The wizard auto-fires only on profiles that have never finished it (detected via [onboarding] completed = false in the profile’s config.toml). Existing profiles upgrade silently.

Sidebar with the default lens active, showing pinned threads at the top and recent activity below
The default lens, populated. Pins sit in a statically-ordered shelf at the top; unpinned threads sort by most-recent activity below. (Captured on an earlier build where the lens was labeled Updated; it's named Inbox today.)

The left sidebar carries three thread lenses you can switch between with the segmented toggle at the top of the list. All three start from the same pool of active (non-archived) threads — they differ only in how they sort and group:

Lens Sort Grouping
Inbox (default) Most-recently-updated first. Active threads bubble up as the agent posts. Flat list with user-curated Pins pinned to the top in their own statically-ordered section.
Created Most-recently-created first. Stable sort — threads don’t jump around mid-work the way they do in Inbox. Same Pins section at the top.
Directories Within each directory, most-recently-created first (stable). Grouped by the project / repository the thread is rooted in. Per-directory Pins sit at the top of their group.

Use Inbox when you want “what’s the agent doing right now” front and center. Use Created when you’d rather the order stay put while you work through a list. Use Directories when you’re deliberately switching between several repos and want them visually separated.

The sidebar remembers which lens you left it on, per profile — relaunching the app reopens the last-used lens rather than resetting to Inbox.

Thread rows also carry status chips as features engage: a Scheduled or Queued chip when a composer send is waiting (see Scheduled sends), an integrated terminal running chip when a terminal is live in that thread (see Integrated terminal), and PR-state chips (draft / conflicted / merged / closed) on threads with an associated pull request.

Pins

A pin keeps a thread visible at the top of the list regardless of activity. The pinned section is statically ordered (you set the order yourself) and scrolls independently of the rest of the list, so a long pin section never buries the rest of your threads.

In Directories, pins belong to their parent directory rather than to the global list, so each directory gets its own statically- ordered pin shelf.

The Directories lens also lets you pin entire directories (and workspaces) above the divider so your active projects stay on top regardless of which one most recently woke up. Pinned directories carry over across restarts.

To pin or change pin order:

Unread marker

When a thread you haven’t actively viewed gets new agent output, its row picks up an orange cookie — a small filled circle next to the thread title. The cookie clears the next time you open the thread (or select it in the sidebar). Same indicator across all three lenses.

Thread workspaces: Local and Worktree

Each PwrAgent thread is rooted in a project (a Git repository). Within a project, a thread runs in one of two workspaces:

Threads can be handed off between Local and Worktree from the status card — PwrAgent moves the thread’s working state and updates the binding. Local-to-Worktree handoff asks which branch should remain checked out in Local before it moves you over; Worktree-to- Local handoff asks for confirmation.

Worktree storage location is configurable — see Settings → Worktrees.

When you archive a thread that owns a managed worktree, PwrAgent removes the worktree for you (with safety checks — it refuses to touch your primary checkout and skips worktrees shared with other threads). The thread’s status surface tells you whether the worktree was cleaned up or kept. The same applies when a Worktree thread hands off back to Local. Note this is worktree removal — environment teardown hooks are still on the roadmap (see Coming soon).

Linked project directories

A thread isn’t limited to the single project it launched from. You can link additional project directories to a thread — from the thread context rail’s Linked Projects tab or by referencing a directory in the composer — without changing the transcript or moving the workspace. Each linked directory gets its own branch scoping and pull-request discovery, so a thread that spans a service repo and its client repo tracks both.

Sub-threads, forks, and handoffs

Threads can have children. Right-click a thread row and you’ll find two families of actions, each offered for Same Worktree, New Worktree, or Local:

Forked threads don’t re-bill the inherited history — the Pricing tab marks the fork point and costs only what the child itself runs.

Handoffs are the agent-initiated version: an agent working a thread can delegate a task into a new child thread (optionally in its own isolated worktree), send messages to other threads, or move its own thread into a linked worktree and keep working there. Delegated children group under the root thread the same way manual sub-threads do, and pending worktree setup is visible on the child while it materializes. Handoff targets are restricted to directories the thread already trusts.

Integrated terminal

Every thread can open an integrated terminal from the thread header — a real shell rooted in the thread’s current workspace (Local or Worktree, whichever the thread is on). It renders as a resizable pane inside the thread view.

The part that earns its keep: terminals are owned by the main process, so a running terminal survives navigation. Switch threads, open Settings, come back — the shell is still there, scrollback intact. Thread rows wear a live-dot chip while a terminal is running in that thread, and the quit dialog counts running terminals as active work before letting the app close.

Codex environments

When you start a thread on a worktree, PwrAgent can run a Codex environment before the thread takes its first turn. Environments are configured at the Codex level (alongside AGENTS.md and .codex/ metadata) and PwrAgent surfaces them in the launchpad alongside the model and access-mode pickers:

Environments are usable today but not yet editable inside the PwrAgent UI — you author them at the Codex level and PwrAgent picks them up. In-app editing is on the roadmap.

Per-thread settings

Unlike Codex Desktop, where model / reasoning effort / Fast mode / permissions mode are global, PwrAgent scopes them per thread. You can run an experiment on a cheaper model with Default Access while a refactor runs on a stronger model with Full Access — the settings stay scoped to their thread. Set them on the Start Card before sending the first prompt, or on the bound-thread status card afterward.

The model picker tracks what Codex actually offers — the GPT-5.6 family (Sol / Terra / Luna) shows up with its model-specific max / ultra reasoning tiers, and PwrAgent remembers your preferred reasoning level per model. Fast mode maps to Codex’s priority service tier — same model, faster scheduling.

Auto-naming

PwrAgent gives threads automatic names so the sidebar list is scannable as it grows. The first prompt is the primary signal; the agent’s responses adjust the name as the thread takes shape. You can rename manually from the thread header at any time.

Project breadcrumb

The selected thread’s header shows a compact project breadcrumb so directory-launched threads read like PwrSnap › AI API Rate Limiting instead of leaving the project context implicit. Useful when several threads share similar titles across repos — at a glance you know which checkout you’re operating in.

The thread title in that breadcrumb is clickable: clicking it scrolls the selected row back into view in the sidebar thread list, which matters when you’ve scrolled the sidebar away from the currently-open thread.

Access modes

The two access modes that gate what the agent can do:

The mode is per-thread (see above). Mid-turn changes queue at the turn boundary — see Using Codex via Messaging → Start Card buttons for the queueing details, which apply equally on the desktop.

Approval surface

When a thread is in Default Access and the agent wants to run something approval-gated, the desktop shows an inline approval card inside the transcript. Approvals are mirrored to any bound messengers so you can approve from wherever you happen to be reading the conversation.

Transcript copy buttons

Every user and assistant message in the transcript exposes a Copy affordance on hover/focus in its header — one click puts the full message on your clipboard, no manual text selection.

Code blocks and blockquotes get their own scoped copy controls so you can lift a replay prompt, a command snippet, or a quoted section cleanly without picking up the surrounding prose.

If the agent’s reply is wide enough that the transcript splits it across multiple visual segments (large tables in particular), the copy button on the first segment puts the whole original message on your clipboard — the rendered layout doesn’t change what gets copied.

Markdown composer

The composer parses Markdown as you type:

Codex Desktop doesn’t have this yet.

Pasting is fidelity-preserving: mixed prose + code pastes, nested code fences, lists inside blockquotes, and HTML-only clipboard content all reconstruct as proper Markdown instead of flattening to plain text — and what you copy back out of the composer matches what you pasted in. Pasted images become managed attachments that keep their filenames through the composer and transcript.

The slash menu carries more than local skills: backend-native commands (Codex’s and each ACP agent’s own slash commands) are surfaced in the same autocomplete, so / shows you everything the bound backend can do. And File → New Thread (⌘N / Ctrl+N) opens a fresh launchpad from anywhere.

@ directory & file references

Type @ in the composer and an autocomplete opens over your tracked project directories (most-recently-used first, filtered as you type). Picking one mints a durable @label chip at the cursor; the outgoing message carries it as a tilde-shortened path the agent can act on.

Undo / redo (per-thread)

While a thread is focused, Cmd+Z undoes the most recent change to that thread’s composer, and Cmd+Shift+Z (or Cmd+Y) redoes. Each thread carries its own independent undo stack — switching threads doesn’t merge the histories, and undo never crosses thread boundaries.

Undo also restores a $skill chip you just removed with Backspace, recovering both the chip and its position in the surrounding text — so an accidental delete doesn’t cost you the chip you spent time picking.

For recovery across threads or app restarts, see Composer draft history below — the mechanic there reaches further back than the per-thread undo stack does.

Composer draft history (↑ recovers your last message)

Every keystroke in the composer is autosaved to a per-profile store, including the text, any $skill chips, pasted images, and any rich formatting you applied. Drafts survive everything that historically lost them in other agent UIs:

To recover a previous draft, focus an empty composer and press (ArrowUp). The composer fills with the most recent candidate. Keep pressing to cycle further back through up to 20 recent candidates (per-profile); (ArrowDown) cycles forward through the same list.

Candidates include:

The recovery cycle is anchored on the blank composer state. Start typing once you’ve found the draft you want and the cycle ends — the next will move the cursor in the usual way.

Draft history is per PwrAgent profile — switching profiles via --profile <name> gives that profile its own independent history. Drafts never leave your machine.

Codex Desktop doesn’t have this yet either.

Thread context rail

The edited-files surface above the composer mid-turn. The header reads 'EDITED 2 FILES, +4, -1' with a SIDEBAR toggle on the right. Two file rows below: Update AGENTS.md (+3 / -0) and Update README.md (+1 / -1). The agent is 'Thinking…' and the composer's Send button is replaced by Stop / Queue while the turn is in flight.
The edited-files surface mid-turn — today this lives in the rail's Edits tab. EDITED 2 FILES, +4, -1 is the cumulative diff summary; each file row expands inline to show its diff. (Captured on an earlier build with the single-panel rail; the tabbed rail supersedes it.)

The right side of the thread view is the thread context rail — a tabbed panel, pinned open by default, that carries everything about the thread that isn’t the transcript:

The rail toggles from the thread header, and keyboard chords jump straight to a tab. While a turn is in flight, the Edits tab is the live “what has it actually changed” answer — when the turn completes the final state stays put, so walking back to the desk after a ten-minute turn you’re one glance from the answer instead of scrolling the transcript for it.

Pricing and usage

Every thread keeps a persistent cost ledger in the rail’s Pricing tab: per-turn usage cards (cached / uncached / reasoning / image tokens), per-turn durations, a Live marker on the in-flight turn, and running totals in USD and/or Codex Credits (display units are toggleable in Settings → Experimental). Forked threads show a zero-cost fork point — inherited history isn’t re-billed. Sub-agent runs carry their own usage cards, including cold / hot context-replay estimates.

Down in the composer’s footer sits the context-window moon — a moon-phase glyph that fills as the thread’s context window does. Hover it for the structured usage card: percent full, remaining tokens, and current-request vs session-total breakdowns with cache-hit meters. When you’re deep into the window it shifts to the warning treatment before Codex starts compacting.

Multi-message queueing

Composer with a turn in flight on the "Convert OAuth flow to PKCE" thread; "Review changes against main" (a queued /review against the base branch) and "now squash and push --force-with-lease" stacked as queued chips above the composer
The two QUEUED chips above the composer will fire FIFO when the in-flight make a branch and PR turn finishes. The composer's Send is replaced by Stop / Queue while a turn is active.

You don’t have to wait for the agent to finish a turn before queueing the next thing. While a turn is running, the composer’s Send stages your message as a queued turn instead of discarding the click — the queued message appears as a chip above the composer with a small × for cancel.

You can queue as many follow-ups as you want, and they dispatch FIFO, one turn at a time. The pattern that earns its keep:

  1. Send make a branch and PR for the OAuth refactor (turn 1).
  2. While that’s running, queue /review (turn 2).
  3. While that’s queued, queue now squash and push --force-with-lease (turn 3).

You walk away. By the time you come back, turn 1 has produced a branch and a PR, turn 2 has run a review pass and addressed findings, turn 3 has squashed and force-pushed. Slash commands queue exactly like free-form messages — /review, /status, and the rest are first-class queueable.

Queued turns are visible in the composer (chips with cancel ×) and in the transcript (a “queued: …” pill on the in-flight turn showing what’s next). Cancel any queued turn by clicking its × in the composer chip — earlier and later queue items keep their order.

This is the desktop counterpart to the messaging queue / steer flow; the two read and write the same per-thread queue, so a turn you queued from your phone shows up in the desktop’s composer chip list immediately, and vice versa.

Scheduled sends

The composer’s Send button is split — the chevron opens a schedule menu: Send in 15m / 30m / 1h / 2h, plus “at the next usage-limit reset” when the backend reports one (handy for queueing work to fire the moment your 5-hour Codex window rolls over).

Scheduled messages sit in the same queued-message area with a live countdown. Until dispatch they stay editable and deletable; while editing you get an explicit schedule checkbox and a Send now bypass. Sidebar thread rows carry a solid Scheduled chip (or the softer Queued chip) so you can see at a glance which threads have work waiting to fire.

/review — Codex code reviews

Type /review in the composer and an inline review composer opens: pick the target — the thread’s base branch (the default, derived from the thread’s own git state), a specific commit (--commit <sha>), or custom instructions (--custom …) — and hit Start review. The review runs as a Codex review turn and the findings render directly in the transcript.

Threads with multiple linked worktrees ask which project / workspace to review first, so the diff is always against the workspace you meant. Reviews show up as sub-agent runs in the rail, with their own usage accounting.

Skills browser ($ autocomplete and chips)

Composer mid-message ("Let&#39;s use $ce") with the Skills autocomplete listbox open below it, showing matching skill rows like $ce:plan, $ce:brainstorm, $ce:compound
Typing $ in the composer opens the Skills listbox. Subsequent characters filter incrementally — here $ce narrows to skills whose names start with ce. Pick a row to insert it as an inline chip.

PwrAgent surfaces Codex skills (including plugin-exposed skills) directly in the composer. Type $ and an autocomplete dropdown opens with every skill the bound Codex profile exposes — the same $skill-name mention syntax Codex itself uses, but with inline picking and rich tooltips so you don’t have to remember the exact name.

Pick a skill → it lands as an inline chip at the cursor (the chip carries the skill name, a tooltip with the skill’s description, and a small × to remove it). The chip expands into the skill’s full mention markdown when the turn is submitted, so the agent sees $skill-name exactly as if you’d typed it.

You can mix skill chips with free-form text in any order: prose, chip, more prose, another chip. Multiple chips in one message are each prepended once.

The skill list is shared with the messaging Skills browser — both surfaces draw from the same Codex App Server skill registry. Adding a new plugin-exposed skill makes it appear in $ autocomplete on the desktop and in the paged Skills browser on every bound messenger automatically.

Search and navigation

Three search surfaces, plus browser-style history:

The sidebar’s inline filter still accepts branch names, PR numbers, emoji markers, and free text — filtering applies to whichever lens is active and respects its sort order.

Pin behavior is covered above under Sidebar lenses → Pins.

Agent tool results that reference other threads (a handoff’s child, a cross-thread message) come back with clickable thread links — click one and the app navigates straight to that thread. The links use an internal pwragent://thread/… scheme that resolves inside the app only; it’s deliberately navigation-only (no action verbs) and is never handed to the OS, so a link can take you somewhere but can never do something.

Native notifications

Opt-in system notifications for the moments that actually need you: an approval waiting, an agent asking a question, and turn completion / failure / cancellation. The approval notification is actionable — Approve from the notification resolves it without raising the window. Notifications auto-close when the thing they announced is handled, and clicking one routes you to the right thread.

Quit confirmation

If threads are mid-turn, sends are queued or scheduled, or integrated terminals are running, quitting asks first — with a rundown of what’s active so you’re not killing a 20-minute turn by muscle memory. Opt out in Settings → General if you like to live dangerously.

Files window

Local Markdown files the agent mentions in the transcript open as in-app previews instead of bouncing to an external editor, and a detached Files window can hold several Markdown files from the thread’s workspace side by side — handy when the agent writes a plan or a report you want open while the conversation continues.

Multiple profiles

PwrAgent has two independent profile mechanisms that compose. Read once; the rest of the section is a worked setup.

PwrAgent profiles

A PwrAgent profile is selected by the PWRAGENT_PROFILE env var at launch. Each profile carries its own:

Creating a new PwrAgent profile is trivial: pick a name, set the env var, launch. PwrAgent creates the profile on first run under ~/.pwragent/profiles/<name>/.

Use case. Two PwrAgent profiles pointed at the same Codex auth share the underlying Codex threads, settings, and account — but they’re independent at the PwrAgent layer. That’s how you run multiple bots of the same platform (e.g. one Telegram bot for personal work and another Telegram bot for a small team, both driving the same Codex thread list).

Codex profiles

A Codex profile is an isolated CODEX_HOME directory the Codex App Server uses for its own state — auth tokens, thread history, config. Each Codex profile points at its own OpenAI Codex identity (or the same identity, if you want).

Use case. Two Codex profiles for a single PwrAgent install: ~/.codex/profiles/work/ (your day-job Codex account) and ~/.codex/profiles/personal/ (your personal account). Threads stay separated; auth stays separated. Switch between them by changing the Codex auth profile selection in Settings → Models.

Cheekier use case. Four Codex profiles, each pointed at a different Codex Pro account, because you are an animal and need four accounts worth of tokens to rule the world. PwrAgent will not stop you.

How the two profile mechanisms compose

What’s isolated PwrAgent profile Codex profile
PwrAgent settings (config.toml)
PwrAgent state DB (state.db)
Messaging adapters + bot tokens
Codex threads + history
Codex auth (OpenAI account)
Per-thread settings stickiness

You can compose them however you want. Examples:

Managing profiles in the app

Both kinds of profiles are managed from Settings → Profiles:

Existing Codex threads can also be copied or moved between Codex profiles from Settings → Thread Management — see Settings → Thread Management.

Settings → Profiles panel listing PwrAgent profiles
Settings → Profiles. Every PwrAgent profile under ~/.pwragent/profiles/ is listed; the active one is highlighted. Switching restarts the app under the selected profile.

Profiles app menu

The macOS menu bar has a Profiles menu (between View and Window) that lists every PwrAgent profile and lets you switch without going through Settings.

Switching from this menu is window-aware: if a target profile already has a running PwrAgent process, the menu focuses that process’s main window instead of spawning a second one. If the process is alive but its window has been closed, the menu re-creates the main window inside the existing process. A new process spawns only when the target profile isn’t running at all.

The menu refreshes after profile creates and deletes so the entries stay current with whatever’s on disk under ~/.pwragent/profiles/.

Launching a profile from the command line

For automation or when you want to pin a specific PwrAgent profile at launch:

Installed .app — recommended:

open -na PwrAgent --args --profile work

The --profile <name> argument is the supported launch flag — it flows through Launch Services into the app’s argv, so the app shows up correctly in the Dock and Cmd-Tab list.

From source:

PWRAGENT_PROFILE=dev pnpm dev:no-messaging

The PWRAGENT_PROFILE env var still works as a fallback for any context where passing argv isn’t convenient (the dev server and shell-script launchers being the typical cases).

Under the hood

The in-app profile management writes to your config file the same shape an experienced operator would write by hand:

Verifying without going through the UI:

# Confirm the active PwrAgent profile selected the right Codex auth
# profile.
rg -n 'profile = "work"|\[models.codex\]' \
  ~/.pwragent/profiles/<your-pwragent-profile>/config.toml

# Once a Codex thread runs under the selected profile, confirm
# Codex state lands in the isolated CODEX_HOME.
find ~/.codex/profiles/work -maxdepth 4 -type f | sort | head -80

You should see entries like auth.json, config.toml, session_index.jsonl, sessions/, and (if used) worktrees/.

Mental model

The two settings live at different layers and don’t interact. Pick each one for its own reason.

Not yet

Features the desktop doesn’t have today that operators have asked about — captured here so you can plan around them:

Coming soon

Active development areas that have shipped designs but aren’t in release builds yet:

Watch the GitHub repo for the relevant PRs.

See also