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
42 changes: 42 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Bug report
description: Report reproducible incorrect or unsafe behavior
title: "Bug: "
labels: [bug]
body:
- type: markdown
attributes:
value: >-
Do not paste tokens, credentials, private transcripts, or sensitive
terminal output. Use private vulnerability reporting for security issues.
- type: input
id: versions
attributes:
label: Versions
description: CX Deck, macOS, iTerm2, Codex CLI, and zmx versions.
placeholder: "CX Deck 0.8.1; macOS …; iTerm2 …; Codex …; zmx …"
validations:
required: true
- type: input
id: command
attributes:
label: Command used
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected behavior
validations:
required: true
- type: textarea
id: actual
attributes:
label: Actual behavior
validations:
required: true
- type: textarea
id: doctor
attributes:
label: Redacted cx doctor output
description: Remove sensitive paths, hostnames, UUIDs, PIDs, and project names.
render: text
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
blank_issues_enabled: true
contact_links:
- name: Report a security vulnerability privately
url: https://github.com/lrgthu/cxdeck/security/advisories/new
about: Use GitHub Private Vulnerability Reporting for security-sensitive reports.
23 changes: 23 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Feature request
description: Propose a focused improvement to daily CX Deck use
title: "Feature: "
body:
- type: textarea
id: problem
attributes:
label: User problem
description: What repeated workflow or failure would this solve?
validations:
required: true
- type: textarea
id: outcome
attributes:
label: Desired outcome
description: Describe the user-visible result without assuming an implementation.
validations:
required: true
- type: textarea
id: safety
attributes:
label: Identity, runtime, or presentation impact
description: Note any effect on conversation identity, zmx runtime, or iTerm views.
16 changes: 16 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
## What changed

## Why

## Safety impact

- [ ] Conversation identity rules are unchanged or explicitly reviewed.
- [ ] No unintended Codex/zmx restart or termination is possible.
- [ ] No hidden terminal input or prompt injection was added.
- [ ] Presentation-only changes preserve the exact zmx generation.

## Validation

- [ ] Unit suite
- [ ] Static and public-source checks
- [ ] Disposable integration when applicable
3 changes: 3 additions & 0 deletions .github/workflows/iterm-gui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ on:
branches: ['release/**']
permissions:
contents: read
concurrency:
group: iterm-gui-${{ github.ref }}
cancel-in-progress: true
jobs:
gui:
runs-on: macos-latest
Expand Down
10 changes: 9 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: tests
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
inputs:
Expand All @@ -10,6 +11,9 @@ on:
default: false
permissions:
contents: read
concurrency:
group: tests-${{ github.workflow }}-${{ github.event.pull_request.head.ref || github.ref }}
cancel-in-progress: true
jobs:
test:
strategy:
Expand All @@ -27,7 +31,9 @@ jobs:
if: runner.os == 'Linux'
run: |
sudo apt-get update && sudo apt-get install -y zsh build-essential
curl -fL https://github.com/neurosnap/zmx/releases/download/v0.8.1/zmx-0.8.1-linux-x86_64.tar.gz -o /tmp/zmx.tar.gz
curl --proto '=https' --tlsv1.2 --fail --location --show-error \
https://github.com/neurosnap/zmx/releases/download/v0.8.1/zmx-0.8.1-linux-x86_64.tar.gz \
-o /tmp/zmx.tar.gz
echo 'dfd75720b942466f28870731cc86dbc07afa72fb8f3bd5eeb4ff707e4eecebe8 /tmp/zmx.tar.gz' | sha256sum -c -
tar -xzf /tmp/zmx.tar.gz -C /tmp
sudo install -m 0755 /tmp/zmx /usr/local/bin/zmx
Expand All @@ -47,6 +53,8 @@ jobs:
zsh -n uninstall.sh
zsh -n tests/prepare_ci_iterm.zsh
python3 -m compileall -q .
- name: Public-source privacy audit
run: python3 tools/public_release_audit.py
- name: Unit and disposable real-backend tests (no real Codex API calls)
run: python3 -m unittest discover -s tests -v
- name: Install and register iTerm2 scripting dictionary (macOS)
Expand Down
14 changes: 6 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,18 @@

## 0.8.1

- Added exact native iTerm workspace capture and ordered split-tree restoration;
split ratios and window frames remain best-effort hints.
- Reuse and move verified iTerm Sessions without restarting Codex or replacing
zmx generations.
- Added unified conversation/runtime/view health, metadata-only search,
next/previous focus, and workspace-scoped presentation repair.
- Materialize iTerm session GUID and TTY values before serializing live view
inventory, avoiding an AppleScript coercion race immediately after supported
session moves.
- Allow disposable exact-restore acceptance enough time for iTerm to finish an
asynchronous presentation-client close.

## 0.8.0

- Added exact native iTerm workspace capture and ordered split-tree restoration.
- Reuse and move verified iTerm Sessions without restarting Codex or replacing zmx generations.
- Added a unified conversation/runtime/view inventory, view-health status, metadata-only search, and next/previous focus.
- Added workspace-scoped presentation refresh and rebuild while preserving exact UUID and generation safety gates.
- Exact tree structure is verified after restoration; split ratios and window frames remain best-effort hints.

## 0.7.0

- Renamed the product to CX Deck and prepared the repository for public review.
Expand Down
29 changes: 24 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
# Contributing

Open an issue before a large behavioral change. Keep zmx limited to persistent
PTY lifecycle, keep iTerm2 responsible for presentation, and preserve exact
Codex UUID identity. Do not add prompt injection, cross-pane input, terminal
content scraping, or hidden package installation.
For a focused change, fork the repository or create a branch, add relevant
tests, and open a pull request. Discuss large behavioral changes in an issue
first. Keep pull requests small enough to review as one safety contract.

Preserve these architecture boundaries:

```text
Codex UUID = durable conversation identity
zmx = persistent PTY/runtime only
iTerm2 = native presentation
CX Deck = control plane
```

Do not substitute titles, paths, PIDs, zmx names, or iTerm identifiers for exact
conversation identity. Do not add prompt injection, cross-pane input, terminal
content scraping, hidden package installation, or automatic session destruction.

Run before opening a pull request:

Expand All @@ -14,8 +26,15 @@ zsh -n cxdeck.zsh
zsh -n install.sh
zsh -n uninstall.sh
zsh -n tests/prepare_ci_iterm.zsh
python3 tools/public_release_audit.py
git diff --check
```

Real zmx and iTerm checks must use disposable runtime directories, fake Codex
processes, and temporary homes. Never use a person's active sessions as fixtures.
processes, temporary homes, and disposable iTerm views. Never use a person's
active sessions as fixtures. Describe which disposable integration checks you
ran in the pull request.

See [the release procedure](docs/RELEASING.md) for maintainer-only release gates.
The public repository is the canonical development history. Never import Git
objects from historical private repositories into this graph.
31 changes: 20 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ cd cxdeck
./install.sh
source "$HOME/.cxdeck.zsh"
cx doctor
cx upgrade status
cx
```

The installer checks prerequisites and installs CX Deck under
Expand All @@ -74,8 +74,16 @@ cx # start a persistent Codex session here
cx "Model Evaluation" # start or reuse an exact display name
cx new --split # new native iTerm2 split
cx resume # select from saved and live conversations
cx focus "Model Evaluation"
cx status
cx dashboard

cx workspace save daily
cx workspace capture daily # optional exact topology support
cx workspace open daily

cx views status
cx find evaluation
cx focus --next
```

Closing the pane detaches the view. The Codex process remains in its zmx PTY.
Expand Down Expand Up @@ -132,14 +140,14 @@ Display names, pins, groups, workspace membership, and layout metadata live in
their UUID or runtime generation. A workspace records a provider-neutral native
layout plan and reconstructs verified views without nesting another terminal UI.
`cx workspace capture NAME [--replace]` can add an optional exact native split
tree after double-read verification. This read-only feature lazily requires the
explicitly installed `iterm2==2.23` Python package; membership-only workspaces
remain valid. Install that optional support into the same Python used by `cx`
with `python3 -m pip install --user 'iterm2==2.23'`. Opening a captured workspace resolves every exact UUID and checks
duplicates before moving verified iTerm Sessions into the saved tree. Frames and
ratios are best-effort hints. Use `cx workspace open NAME --adaptive` to
deliberately use the older adaptive layout; exact restore never falls back to it
silently.
tree after double-read verification. This feature lazily requires the explicitly
installed `iterm2==2.23` Python package; ordinary CX Deck commands and
membership-only workspaces do not. Install that optional support into the same
Python used by `cx` with `python3 -m pip install --user 'iterm2==2.23'`.
Opening a captured workspace resolves every exact UUID and checks duplicates
before moving verified iTerm Sessions into the saved tree. Frames and ratios are
best-effort hints. Use `cx workspace open NAME --adaptive` to deliberately use
the older adaptive layout; exact restore never falls back to it silently.

`cx status`, `cx resume --json`, and `cx views status --json` use the normalized
`cxdeck.inventory/v1` model. Conversation, runtime, external-process, and view
Expand Down Expand Up @@ -199,7 +207,8 @@ Run `cx doctor` first. It reports Codex and zmx paths and versions, managed
session counts, launch policies, unidentified external processes, iTerm2
automation, and upgrade compatibility. GUI errors leave Codex and zmx running;
use `cx status` to inspect runtime health and `cx views rebuild` to reconstruct
missing views.
missing views. Before posting diagnostics publicly, remove sensitive hostnames,
paths, UUIDs, PIDs, and project names.

## Uninstall

Expand Down
9 changes: 6 additions & 3 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# Security policy

Report a suspected vulnerability privately through GitHub's security advisory
feature for this repository. Do not include credentials, transcripts, or private
conversation data in a public issue.
Report suspected vulnerabilities through
[GitHub Private Vulnerability Reporting](https://github.com/lrgthu/cxdeck/security/advisories/new).
Do not open a public issue for credential exposure, session hijacking, arbitrary
command execution, identity confusion, or destructive runtime behavior. Never
include credentials, transcripts, private terminal output, or private
conversation data in a public report.

Security fixes target the latest release branch. CX Deck treats exact Codex UUID
identity, zmx generation verification, process ownership, private state-file
Expand Down
46 changes: 46 additions & 0 deletions docs/RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Releasing CX Deck

CX Deck uses ordinary public Git history. The public repository is the canonical
development history; never import Git objects from historical private
repositories into this graph.

## Version policy

- Patch releases contain bug and compatibility fixes.
- Minor releases add backward-compatible features.
- Major releases may change conversation identity, runtime compatibility, or
the public CLI contract.

The version lives in `cx_version.py`. A release updates that value and
`CHANGELOG.md` in the same pull request. A controller version change does not by
itself require running zmx generations to restart; runtime requirements remain
an explicit compatibility decision in `cx_upgrade.py`.

## Release checks

Run from a clean release branch:

```zsh
python3 -m unittest discover -s tests -v
python3 -m compileall -q .
zsh -n cxdeck.zsh
zsh -n install.sh
zsh -n uninstall.sh
zsh -n tests/prepare_ci_iterm.zsh
python3 tools/public_release_audit.py
git diff --check
```

Run the six disposable real-zmx tests and `tools/zmx_behavior_probe.py`. When a
change affects presentation, also run the applicable disposable real-iTerm
capture, MOVE_REUSE, restore, and navigation acceptance tools. These tests must
use temporary homes, private zmx runtime directories, dummy processes, and
disposable iTerm views. Never use active user sessions as fixtures.

Review the privacy audit, the complete pull-request diff, and the actual regular
CI job conclusions. Merge through a pull request. Then create and push an
annotated version tag and publish a GitHub Release from that exact tag. Never
move, replace, or delete an existing published version tag.

Exact workspace tests require the explicitly installed `iterm2==2.23` package.
The package remains optional for ordinary CX Deck use.
50 changes: 50 additions & 0 deletions tests/test_public_release_audit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Regression tests for the dependency-free public-source privacy gate."""
from pathlib import Path
import tempfile
import unittest
from unittest import mock

from tools import public_release_audit as audit


class PublicReleaseAuditTests(unittest.TestCase):
def test_current_public_tree_passes(self):
root = Path(__file__).resolve().parents[1]
self.assertEqual(audit.scan(root, audit.tracked_files(root)), [])

def test_sensitive_markers_are_detected_without_echoing_values(self):
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
path = root / "fixture.txt"
path.write_text("\n".join((
"/" + "Users" + "/alice/project",
"ghp_" + "a" * 30,
"-----BEGIN " + "PRIVATE KEY-----",
"https://github.com/example/cxdeck-" + "private-archive",
)))
categories = {row[0] for row in audit.scan(root, [path])}
self.assertEqual(categories,
{"PERSONAL_USER_PATH", "GITHUB_TOKEN",
"PRIVATE_KEY", "PRIVATE_ARCHIVE"})

def test_synthetic_paths_and_identifiers_are_allowed(self):
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
path = root / "fixture.txt"
path.write_text("/home/test/.codex\n/Users/example/project\n"
"11174064+project@users.noreply.github.com\n"
"00000000-0000-4000-8000-000000000001\n")
self.assertEqual(audit.scan(root, [path]), [])

def test_scan_does_not_resolve_network_fqdn(self):
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
path = root / "fixture.txt"
path.write_text("ordinary public source\n")
with mock.patch.object(audit.socket, "getfqdn",
side_effect=AssertionError("network lookup")):
self.assertEqual(audit.scan(root, [path]), [])


if __name__ == "__main__":
unittest.main()
Loading
Loading