Skip to content
Draft
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
30 changes: 30 additions & 0 deletions .context/DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
<!-- INDEX:START -->
| Date | Decision |
|----|--------|
| 2026-05-31 | Journal screen renders ctx journal source verbatim instead of parsing it |
| 2026-05-31 | ctx Desktop shells out via std::process::Command, not tauri-plugin-shell |
| 2026-05-30 | Name the add JSON-ingest flag --json-file, not --json |
| 2026-05-28 | ctxctl PATH-installed alongside ctx for clean roots and one binary across worktrees |
| 2026-05-28 | Memory pressure detection uses OS-native signals (macOS pressure level + Linux PSI), not occupancy |
Expand Down Expand Up @@ -158,6 +160,34 @@ For significant decisions:

-->

## [2026-05-31-094649] Journal screen renders ctx journal source verbatim instead of parsing it

**Status**: Accepted

**Context**: The Journal timeline needs session data, but ctx journal source emits a whitespace-aligned table with no --json mode, and columns (usage/turns) drop out on short sessions.

**Decision**: Journal screen renders ctx journal source verbatim instead of parsing it

**Rationale**: A column parser misaligns when fields are absent; rendering the text verbatim in a monospace panel is honest and robust for P0.

**Consequence**: Journal is a styled text view, not structured cards; a proper timeline awaits a journal source --json mode upstream (same pattern as the artifact list --json commands).

---

## [2026-05-31-094649] ctx Desktop shells out via std::process::Command, not tauri-plugin-shell

**Status**: Accepted

**Context**: The GUI must run the ctx binary for every read and write. Tauri 2 offers tauri-plugin-shell with capability-scoped command allowlists.

**Decision**: ctx Desktop shells out via std::process::Command, not tauri-plugin-shell

**Rationale**: Running ctx inside our own #[tauri::command] via std::process::Command avoids all shell-plugin permission/capability wiring and keeps the adapter a single Rust module. ctx resolves its context from $PWD/.context, so each call sets current_dir to the selected project root.

**Consequence**: No shell capability in capabilities/default.json; the adapter owns PATH augmentation and git provenance synthesis; a CLI/output change is a one-file fix in ctx_adapter.rs.

---

## [2026-05-30-114429] Name the add JSON-ingest flag --json-file, not --json

**Status**: Accepted
Expand Down
22 changes: 22 additions & 0 deletions .context/LEARNINGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ DO NOT UPDATE FOR:
<!-- INDEX:START -->
| Date | Learning |
|----|--------|
| 2026-05-31 | macOS GUI apps inherit a minimal PATH; augment it to find a user-installed CLI |
| 2026-05-31 | Tauri 2 requires rustc >= 1.88; bump the toolchain before cargo check |
| 2026-05-30 | Capture golden fixtures from the live legacy code path before deleting it |
| 2026-05-30 | tpl package is magic-string-audit-exempt but its call sites are not |
| 2026-05-30 | New exported types must live in types.go or TestTypeFileConvention fails |
Expand Down Expand Up @@ -169,6 +171,26 @@ DO NOT UPDATE FOR:

---

## [2026-05-31-094649] macOS GUI apps inherit a minimal PATH; augment it to find a user-installed CLI

**Context**: A bundled Tauri app launched via Finder/launchd gets a minimal PATH (/usr/bin:/bin:...), so /usr/local/bin/ctx is not found even though it resolves in a terminal-launched dev run.

**Lesson**: Do not rely on inherited PATH when spawning user-installed CLIs from a desktop GUI.

**Application**: ctx_adapter prepends /usr/local/bin:/opt/homebrew/bin to PATH on every std::process::Command invocation.

---

## [2026-05-31-094649] Tauri 2 requires rustc >= 1.88; bump the toolchain before cargo check

**Context**: cargo check for the ctx-desktop Tauri app failed: darling, serde_with, time and plist transitive deps require rustc 1.88, but the local toolchain was 1.87.

**Lesson**: Tauri 2's dependency tree tracks recent rustc releases; the pinned-stable assumption breaks builds.

**Application**: Run rustup update stable before building a Tauri 2 app; this project moved 1.87 -> 1.96.

---

## [2026-05-30-212109] Capture golden fixtures from the live legacy code path before deleting it

**Context**: Behavior-preserving refactors of LoopScript composition and the recall <details>/<table> assembly had fragile whitespace where hand-transcribing the expected output risked silent drift from the original bytes.
Expand Down
24 changes: 24 additions & 0 deletions ctx-desktop/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
110 changes: 110 additions & 0 deletions ctx-desktop/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# ctx Desktop

A cross-platform desktop client for [`ctx`](https://github.com/ActiveMemory/ctx) —
a calm, local-first window into your project's persistent AI context. It is a
**thin client over the `ctx` CLI**: every read and write shells out to `ctx`, so
the `.context/` files stay the single source of truth.

Stack: **Tauri 2 + React + TypeScript + Tailwind v4** (Vite).

## Prerequisites

| Tool | Version | Notes |
|------|---------|-------|
| **Node.js** | 18+ (built with 22) | https://nodejs.org |
| **Rust** | **1.88+** (built with 1.96) | Tauri 2's deps require ≥1.88. `rustup update stable` |
| **`ctx` CLI** | 0.8.1+ | Must be on your `PATH`. https://ctx.ist |
| **System deps** | per-OS | See Tauri's prerequisites (below) |

Install the per-OS native dependencies (WebView, build tools) by following the
official guide: https://tauri.app/start/prerequisites/

- **macOS:** Xcode Command Line Tools (`xcode-select --install`); WebKit is built in.
- **Linux:** `webkit2gtk`, `libgtk`, `librsvg`, `build-essential` (see the link).
- **Windows:** Microsoft C++ Build Tools + WebView2 (preinstalled on Win 11).

## Setup & run

```bash
git clone https://github.com/ActiveMemory/ctx.git
cd ctx/ctx-desktop
git checkout feat/ctx-desktop # until merged to main

npm install # JS deps
npm run tauri dev # build + launch the app (hot-reloads)
```

The first `tauri dev` compiles the Rust backend (a few minutes); later runs are
fast. A native **ctx Desktop** window opens. Click **Workspace…**, pick a folder
that contains your ctx projects, and switch between them from the dropdown.

## Production build

```bash
npm run tauri build
```

Produces signed-installer artifacts under `src-tauri/target/release/bundle/`
(`.dmg`/`.app` on macOS, `.deb`/`.AppImage` on Linux, `.msi`/`.exe` on Windows).

## The `ctx` CLI dependency

The app calls `ctx` for everything. Most screens work with **released `ctx`
0.8.1**, but the **list/count views** (Overview counts, Tasks/Decisions/Learnings
lists) require the `ctx <artifact> list --json` commands, which currently live on
the `feat/ctx-artifact-list-json` branch (not yet in a release). To enable them,
build and install that branch once:

```bash
git checkout feat/ctx-artifact-list-json
make build && sudo make install # installs ctx to /usr/local/bin
git checkout feat/ctx-desktop
```

Adding entries, the Context Packet, Journal, and Health screens all work on stock
`ctx` 0.8.1 without this step.

> macOS note: a bundled app launched from Finder inherits a minimal `PATH`, so the
> adapter prepends `/usr/local/bin` and `/opt/homebrew/bin` to find a
> user-installed `ctx`. In `npm run tauri dev` (launched from a terminal) the
> inherited `PATH` already works.

## Architecture

```
ctx-desktop/
├── src/ React + TS + Tailwind frontend
│ ├── adapter/ctx.ts typed invoke() wrappers + CLI JSON types (one file)
│ ├── hooks/useReload.ts debounced "ctx-changed" → reload key
│ ├── screens/ Overview, Tasks, Decisions, Learnings,
│ │ ContextPacket, Journal, Health
│ └── App.tsx nav shell, workspace switcher, top bar
└── src-tauri/ Rust host
└── src/
├── ctx_adapter.rs THE module that spawns `ctx` (reads + writes)
├── discover.rs workspace scan for .context projects
└── watcher.rs fs-watch on .context → emits "ctx-changed"
```

- All `ctx` access funnels through `ctx_adapter.rs` (Rust) and `adapter/ctx.ts`
(TS), so a CLI/output change is a one- or two-file fix.
- Writes synthesize provenance (`--session-id`, and `--branch`/`--commit` from
git) in the Rust adapter.
- The app spawns `ctx` via `std::process::Command` directly — no
`tauri-plugin-shell`, so no shell capability wiring.

## Useful scripts

| Command | What |
|---------|------|
| `npm run tauri dev` | Build + launch with hot reload |
| `npm run tauri build` | Production bundles |
| `npm run build` | Type-check + build the frontend only (`tsc && vite build`) |
| `cargo fmt && cargo clippy` (in `src-tauri/`) | Format + lint Rust |
| `cargo test` (in `src-tauri/`) | Run Rust unit tests |

## Privacy

Local-only. No network calls except an optional, explicit update check. Nothing
outside the selected project's `.context/` is read or transmitted; every change
routes through `ctx` to preserve its audit trail.
14 changes: 14 additions & 0 deletions ctx-desktop/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tauri + React + Typescript</title>
</head>

<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading
Loading