Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# AI
.codex
.decodex
!apps/decodex-app/.codex/
!apps/decodex-app/.codex/environments/
!apps/decodex-app/.codex/environments/environment.toml

# Editor
.vscode
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[workspace]
exclude = ["apps/decodex-app"]
members = ["apps/*"]
resolver = "3"

Expand Down
38 changes: 34 additions & 4 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,11 @@ args = [
]

# Test
# | task | type | cwd |
# | --------- | --------- | --- |
# | test | composite | |
# | test-rust | command | |
# | task | type | cwd |
# | ----------------------- | --------- | --- |
# | test | composite | |
# | test-rust | command | |
# | test-decodex-app-stage | script | |

[tasks.test]
clear = true
Expand All @@ -224,6 +225,35 @@ args = [
"--all-features",
]

[tasks.test-decodex-app-stage]
workspace = false
script = '''
if [ "$(uname -s)" != "Darwin" ]; then
echo "Decodex App staging is macOS-only; skipping."
exit 0
fi

./apps/decodex-app/script/build_and_run.sh stage
COMMON_ROOT="$(cd "$(git rev-parse --git-common-dir)/.." && pwd)"
STAGE_DIR="${DECODEX_APP_STAGE_DIR:-$COMMON_ROOT/target/decodex-app}"
APP_PATH="$STAGE_DIR/Decodex App.app"
test -d "$APP_PATH"
test -x "$APP_PATH/Contents/MacOS/DecodexApp"
test -x "$APP_PATH/Contents/Helpers/decodex-app-helper"
test -f "$APP_PATH/Contents/Info.plist"
test -f "$APP_PATH/Contents/Resources/AppIcon.icns"
test -f "$APP_PATH/Contents/Resources/StatusBarIcon.png"
codesign --verify --deep --strict "$APP_PATH"
codesign --verify --strict "$APP_PATH/Contents/Helpers/decodex-app-helper"
codesign -dv --verbose=4 "$APP_PATH" 2>&1 | grep -q '^TeamIdentifier='
codesign -dv --verbose=4 "$APP_PATH" 2>&1 | grep -q 'flags=.*runtime'
plutil -extract CFBundleName raw "$APP_PATH/Contents/Info.plist" | grep -qx 'Decodex App'
plutil -extract CFBundleDisplayName raw "$APP_PATH/Contents/Info.plist" | grep -qx 'Decodex App'
plutil -extract CFBundleIconFile raw "$APP_PATH/Contents/Info.plist" | grep -qx 'AppIcon'
plutil -extract CFBundleIdentifier raw "$APP_PATH/Contents/Info.plist" | grep -qx 'space.decodex.app'
plutil -extract LSUIElement raw "$APP_PATH/Contents/Info.plist" | grep -qx 'true'
'''

# Build
# | task | type | cwd |
# | ---------- | ------- | ---- |
Expand Down
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Repo-native agent orchestration and public Codex signal publishing.
## Feature Highlights

- Rust CLI and runtime for repo-native retained coding-agent lanes.
- Native macOS app for Decodex Codex account-pool management.
- Explicit project registry under `~/.codex/decodex/projects/<service-id>/`.
- Local operator listener with a dashboard at `/` and `/dashboard`, WebSocket
snapshot/control traffic at `/dashboard/control`, and `GET /livez` for liveness.
Expand Down Expand Up @@ -55,6 +56,8 @@ runtime.
## Workspace posture

- `apps/decodex/` owns the Rust package that builds the `decodex` CLI and runtime.
- `apps/decodex-app/` owns the native macOS app that manages Decodex
Codex accounts through the bundled Rust app helper.
- `site/` owns the Astro static site and checked-in public content.
- `scripts/github/` owns deterministic GitHub bundle, release-delta, render, and
validation scripts.
Expand Down Expand Up @@ -127,7 +130,10 @@ file, and project configs do not own an account-pool path override. Set
`[codex.accounts].fixed_account` in `~/.codex/decodex/config.toml` to pin all new
account-pool runs to one account. When that global selector is absent, Decodex balances
new runs across the pool. The operator dashboard Accounts UI writes and clears the same
global selector; project configs do not pin specific accounts.
global selector; project configs do not pin specific accounts. To switch the account
used by the Codex CLI itself, run `decodex account use <selector>` or use the Decodex
App row action; this overwrites `$CODEX_HOME/auth.json` or `~/.codex/auth.json` from
the matching `accounts.jsonl` entry.

`decodex diagnose --json` writes the local agent evidence index under
`~/.codex/decodex/agent-evidence/<service-id>/` and prints the same handoff index for
Expand Down Expand Up @@ -247,8 +253,8 @@ The tracked workspace currently keeps:
- `docs/plans/` as historical saved plan artifacts from the static-site bootstrap
- `dev/` as local development helpers outside `dev/skills/`, such as the operator
dashboard mock server
- `assets/` as shared static assets that are not owned by the Astro app's generated
output
- `assets/` as generated Decodex App icon source notes, Icon Composer foreground,
generated `.icns`, and menu bar template assets
- `.github/` as CI, release, Pages deployment, and content-refresh workflows

Generated or local-only directories such as `target/`, `site/dist/`, `site/.astro/`,
Expand Down
11 changes: 11 additions & 0 deletions apps/decodex-app/.codex/environments/environment.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# THIS IS AUTOGENERATED. DO NOT EDIT MANUALLY
name = "Decodex App"
version = 1

[setup]
script = ""

[[actions]]
command = "./script/build_and_run.sh"
icon = "run"
name = "Run"
14 changes: 14 additions & 0 deletions apps/decodex-app/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// swift-tools-version: 6.0

import PackageDescription

let package = Package(
name: "DecodexApp",
platforms: [.macOS(.v14)],
products: [
.executable(name: "DecodexApp", targets: ["DecodexApp"]),
],
targets: [
.executableTarget(name: "DecodexApp"),
],
)
76 changes: 76 additions & 0 deletions apps/decodex-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Decodex App

Purpose: Native macOS app for the local Decodex account pool.

Read this when: You are building or running the first Decodex desktop UI surface.

Not this document: Runtime scheduling, retained-lane orchestration, public site behavior,
or the full operator dashboard.

## Scope

The first Decodex App release only manages the shared Codex account pool through the
bundled `decodex-app-helper`, which links the Rust account service directly:

- list accounts without printing token material
- pin future Decodex runs to one account
- return future Decodex runs to balanced selection
- force Codex itself to use a stored account
- run isolated Codex device login, then import the resulting auth file
- remove a stored account from the local pool

The app does not schedule Decodex runs, own project registration, or replace
`decodex serve`. It is a native UI over the shared Rust account-management service,
not a wrapper around the `decodex` CLI binary.

## Development

Build the SwiftPM app:

```sh
swift build --package-path apps/decodex-app
```

Run it as a local `.app` bundle:

```sh
apps/decodex-app/script/build_and_run.sh
```

Stage a signed bundle without launching it:

```sh
apps/decodex-app/script/build_and_run.sh stage
cargo make test-decodex-app-stage
```

The staging script builds both the Swift app and the Rust `decodex-app-helper`, then
copies the helper into `Contents/Helpers/`. Direct SwiftPM launches are development-only;
when needed, point them at a workspace-built helper:

```sh
cargo build -p decodex --bin decodex-app-helper
DECODEX_APP_HELPER="$(pwd)/target/debug/decodex-app-helper" swift run --package-path apps/decodex-app DecodexApp
```

The staging script follows the local Rsnap-style signing path: it writes
`target/decodex-app/Decodex App.app`, signs the bundle with an Apple Development
identity, enables hardened runtime, and verifies the signature before launch. Override
the signing identity with `DECODEX_APP_SIGN_IDENTITY`; override the staging directory
with `DECODEX_APP_STAGE_DIR`. This is local development signing, not a notarized
distribution build.

The "Use in Codex" action overwrites Codex's `auth.json` from one stored
`~/.codex/decodex/accounts.jsonl` entry. The destination is `$CODEX_HOME/auth.json`
when `CODEX_HOME` is set, otherwise `~/.codex/auth.json`.

App icon assets live under `assets/app-icon/` with `source/`, `composer/`, and
`generated/` lanes. Menu bar icon assets live under `assets/tray-icon/` with matching
`source/` and `generated/` lanes. Regenerate the full icon set with:

```sh
scripts/assets/render_decodex_app_icons.swift
```

The staging script copies `app-icon.icns`, the template status item image, and the
signed `decodex-app-helper` into the app bundle.
Loading