From d30c1641840c20fc4d3bffda15dd6e5f55341efc Mon Sep 17 00:00:00 2001 From: James Maes Date: Thu, 23 Jul 2026 17:04:53 -0500 Subject: [PATCH 01/43] docs: replace Mermaid text diagram with PlantUML PNG image --- README.md | 49 +----------------------------------------- docs/architecture.png | Bin 0 -> 33574 bytes 2 files changed, 1 insertion(+), 48 deletions(-) create mode 100644 docs/architecture.png diff --git a/README.md b/README.md index d8b29ab..d5ef850 100644 --- a/README.md +++ b/README.md @@ -29,54 +29,7 @@ Nuncio operates on a **Hybrid Daemon-First Architecture**. Centralized state management, SQLite WAL persistence, credential security enclaves, and protocol synchronizers reside inside a standalone background daemon (`nunciod`). Four decoupled interfaces communicate with `nunciod` over native IPC socket streams: -```mermaid -graph TD - subgraph Four Great Interfaces - CLI["nuncio-cli (POSIX CLI)"] - TUI["nuncio-tui (Ratatui TUI)"] - GUI["nuncio-gui (Tauri v2 Desktop GUI)"] - MCP["nuncio-mcp (Native MCP LLM Agent Interface)"] - end - - subgraph IPC Client Engine - Client["IpcClient (Auto-Spawn + Retry Loop + JSON-RPC 2.0 Framing)"] - end - - subgraph Native OS Sockets - UnixSocket["POSIX: UNIX Domain Socket (~/.nuncio/nuncio.sock)"] - WinPipe["Windows: Named Pipe (\\\\.\\pipe\\nuncio-ipc)"] - end - - subgraph Central Background Daemon - DaemonServer["IpcDaemonServer (Security Enclave)"] - DaemonProcess["nunciod Daemon Process"] - EventBus["nuncio-core EventBus"] - end - - subgraph Core Engine & Protocol Libraries - MailEngine["nuncio-mail (IMAP / SMTP / JMAP)"] - CalEngine["nuncio-cal (CalDAV / iCal / rrule)"] - StoreEngine["nuncio-store (SQLite WAL / FTS5 Trigram / Age Cipher)"] - end - - CLI --> Client - TUI --> Client - GUI --> Client - MCP --> Client - - Client --> UnixSocket - Client --> WinPipe - - UnixSocket --> DaemonServer - WinPipe --> DaemonServer - - DaemonServer --> DaemonProcess - DaemonProcess --> EventBus - - EventBus --> MailEngine - EventBus --> CalEngine - EventBus --> StoreEngine -``` +![Nuncio Central Daemon Topology & Multi-Shell Architecture](docs/architecture.png) 1. **`nuncio-cli` (POSIX CLI)**: Scriptable ` ` commands with deterministic `--json` output and offline-resilient local SQLite reads. 2. **`nuncio-tui` (Terminal TUI)**: Keyboard-first 3-pane split view built in Ratatui with Vim navigation (`j`/`k`/`h`/`l`) and live `CoreEvent` push updates. diff --git a/docs/architecture.png b/docs/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..9803eef80fff7fa12229aee623e7f5a1b7a8364e GIT binary patch literal 33574 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 Date: Sun, 26 Jul 2026 19:52:06 -0500 Subject: [PATCH 02/43] docs: reset project docs to verified state + engine-first roadmap Remove fabricated PLAN-*/EXECUTIVE-*/TODO/TICKET/spec docs; add authoritative ROADMAP, ADR-0001 (engine-first gRPC), and Phase 0/1 BACKLOG; rewrite README, CLAUDE.md, ARCHITECTURE, and wiki Home to honest reality; add status banners to the NSQL and self-healing specs; make wiki-sync mirror-with-delete. --- .github/workflows/wiki-sync.yml | 7 +- CLAUDE.md | 156 +++++++----- README.md | 157 ++++-------- docs/ARCHITECTURE.md | 227 ++++++------------ docs/Architecture-Specification.md | 23 -- docs/BACKLOG.md | 121 ++++++++++ docs/Database-Corruption-Self-Healing.md | 6 + docs/EXECUTIVE-AUDIT-REVIEW.md | 62 ----- docs/EXECUTIVE-REVIEW.md | 100 -------- docs/Four-Great-Interfaces.md | 23 -- docs/Home.md | 68 ++---- docs/Multi-Platform-Release-Auto-Update.md | 15 -- docs/NSQL-Filter-Language-Specification.md | 8 + docs/PLAN-enhanced-roadmap-v1-v2-v3.md | 173 ------------- docs/PLAN-hybrid-daemon-architecture.md | 88 ------- docs/PLAN-multi-shell-parity-v1-v3.md | 86 ------- docs/PLAN-nuncio-roadmap.md | 61 ----- docs/PLAN-production-roadmap-100-plus.md | 215 ----------------- ...AN-testing-matrix-and-v3-release-policy.md | 83 ------- docs/ROADMAP.md | 114 +++++++++ docs/SESSION-STATE.md | 6 - docs/TICKET-Database-Corruption-Recovery.md | 93 ------- docs/TICKET-NSQL-Filter-Engine.md | 111 --------- docs/TODO.md | 121 ---------- .../0001-engine-first-grpc-architecture.md | 74 ++++++ docs/architecture.png | Bin 33574 -> 0 bytes 26 files changed, 569 insertions(+), 1629 deletions(-) delete mode 100644 docs/Architecture-Specification.md create mode 100644 docs/BACKLOG.md delete mode 100644 docs/EXECUTIVE-AUDIT-REVIEW.md delete mode 100644 docs/EXECUTIVE-REVIEW.md delete mode 100644 docs/Four-Great-Interfaces.md delete mode 100644 docs/Multi-Platform-Release-Auto-Update.md delete mode 100644 docs/PLAN-enhanced-roadmap-v1-v2-v3.md delete mode 100644 docs/PLAN-hybrid-daemon-architecture.md delete mode 100644 docs/PLAN-multi-shell-parity-v1-v3.md delete mode 100644 docs/PLAN-nuncio-roadmap.md delete mode 100644 docs/PLAN-production-roadmap-100-plus.md delete mode 100644 docs/PLAN-testing-matrix-and-v3-release-policy.md create mode 100644 docs/ROADMAP.md delete mode 100644 docs/SESSION-STATE.md delete mode 100644 docs/TICKET-Database-Corruption-Recovery.md delete mode 100644 docs/TICKET-NSQL-Filter-Engine.md delete mode 100644 docs/TODO.md create mode 100644 docs/adr/0001-engine-first-grpc-architecture.md delete mode 100644 docs/architecture.png diff --git a/.github/workflows/wiki-sync.yml b/.github/workflows/wiki-sync.yml index 51e9a18..d110862 100644 --- a/.github/workflows/wiki-sync.yml +++ b/.github/workflows/wiki-sync.yml @@ -27,15 +27,18 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} path: wiki-repo - - name: Sync docs and assets to Wiki + - name: Sync docs and assets to Wiki (mirror with delete) run: | + # Mirror docs/ -> wiki so that files removed from docs/ are also removed + # from the wiki. Preserve only the wiki's .git directory. + find wiki-repo -mindepth 1 -maxdepth 1 -not -name '.git' -exec rm -rf {} + mkdir -p wiki-repo/assets cp -r docs/* wiki-repo/ 2>/dev/null || true cp -r assets/* wiki-repo/assets/ 2>/dev/null || true cd wiki-repo git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git add . + git add -A if git diff --staged --quiet; then echo "No changes to commit to Wiki." else diff --git a/CLAUDE.md b/CLAUDE.md index 5d491ce..79814dd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,79 +1,111 @@ -# Nuncio Codebase Guidelines (CLAUDE.md) +# CLAUDE.md -Nuncio ([nuncio.mx](https://nuncio.mx)) is a cross-platform mail and calendar solution written in Rust. +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. -## Semantic Versioning 2.0.0 & Release Policy +## What this repo is -- **SemVer Standard**: All releases follow **Semantic Versioning 2.0.0** (`MAJOR.MINOR.PATCH`). -- **UNIFIED V3 RELEASE MANDATE**: **No public release tag or binary distribution will be cut until Phase V3 (Platform & AI Automation) is 100% feature complete, verified, and working across all 4 presentation UIs on Linux, macOS, and Windows.** -- **Git Tag Format**: Release tags MUST follow `vMAJOR.MINOR.PATCH` format (e.g. `v3.0.0` for GA launch). -- **Automated GitHub Releases Workflow**: Pushing a `v*.*.*` tag triggers [.github/workflows/release.yml](file:///R:/Git.Local/KofTwentyTwo/nuncio/.github/workflows/release.yml) to compile, package, compute SHA256 checksums, and publish release binaries for Windows (`.zip` / `.msi`), macOS (`.tar.gz` / `.dmg`), and Linux (`.tar.gz` / `.AppImage`). +Nuncio is a **local-first mail, calendar, and contacts engine** written in Rust +(edition 2021, Cargo workspace). It is **pre-alpha and under active +reconstruction** after a 2026-07-26 forensic assessment found the original +AI-generated proof of concept was largely non-functional and its documentation +substantially fabricated. **Trust the code and this file over any older prose.** -## JetBrains RustRover IDE Integration +Read these before substantive work: +- [`docs/ROADMAP.md`](docs/ROADMAP.md) — the authoritative plan and target architecture +- [`docs/adr/0001-engine-first-grpc-architecture.md`](docs/adr/0001-engine-first-grpc-architecture.md) — the governing architecture decision +- [`docs/BACKLOG.md`](docs/BACKLOG.md) — engineering-ready Phase 0 / Phase 1 stories -Nuncio is pre-configured for **JetBrains RustRover** out of the box: -- **Workspace Cargo Resolution**: RustRover automatically recognizes all 9 workspace member crates (`crates/*`). -- **Pre-Configured Shared Run Configurations**: Located in `.idea/runConfigurations/`: - - `Cargo Check All`: Executes `cargo check-all` with warnings treated as errors. - - `Cargo Test All`: Executes `cargo test-all` for the full workspace. - - `Cargo Coverage Gate`: Executes `cargo cov` measuring 100% unit test line coverage. - - `Run nuncio-cli (status)`: Executes `cargo run -p nuncio-cli -- status`. - - `Run nuncio-tui`: Executes `cargo run -p nuncio-tui`. - - `Run nuncio-gui`: Executes `cargo run -p nuncio-gui`. -- **Code Style & Formatting**: `.idea/codeStyles/Project.xml` configures RustRover to format files automatically via `rustfmt` on save. +## Architecture (target) -## Multi-Agent Execution Framework +The daemon is the product; UIs are thin clients over a published contract. -- **Master Orchestrator Agent (`agy` / Antigravity)**: Manages high-level task decomposition, roadmap tracking ([docs/PLAN-nuncio-roadmap.md](file:///R:/Git.Local/KofTwentyTwo/nuncio/docs/PLAN-nuncio-roadmap.md), [docs/TODO.md](file:///R:/Git.Local/KofTwentyTwo/nuncio/docs/TODO.md)), subagent dispatching, quality gate validation (`cargo verify`, `cargo cov`), git branch workflows, and wiki documentation. -- **Claude Code Subagent (`claude`)**: Assigned to headless engine crates (`crates/nuncio-core`, `crates/nuncio-mail`, `crates/nuncio-cal`, `crates/nuncio-store`), SQLite FTS5 migrations, protocol parsers, `rrule` recurrence math, `age` encryption, and 100% unit test coverage. -- **OpenAI Codex Subagent (`codex`)**: Assigned to CLI subcommands and shell pipeline automation (`crates/nuncio-cli`). -- **Antigravity Worker Subagent (`agy-worker`)**: Assigned to TUI (`crates/nuncio-tui`), GUI (`crates/nuncio-gui`), webview sandboxing, and CI/CD cross-platform release matrix. +- **`nunciod`** owns all state (SQLite/WAL), credentials (OS keyring), protocol + sync logic, the filter engine, and all business logic. The `nuncio-*` library + crates are composed by the daemon. +- The daemon **publishes a versioned gRPC API** (`proto/nuncio/v1/*.proto`, being + introduced in roadmap Phase 1) over **loopback TCP with a bearer-token + handshake** (token in the OS keyring). **Server-streaming RPCs carry push** + (new mail, sync progress, events). +- The `.proto` files are the single source of truth for the contract. **Feature + parity across clients is guaranteed by the contract, not by discipline.** +- **`nuncio-cli` is the in-repo reference client** and E2E driver. All other UIs + (native macOS/Windows GUIs, TUI, MCP bridge) become separate repositories. -## Architecture Guidelines +### Current vs target state -1. **Library-First ("Ghost" Decoupled Model)**: - - Business logic, protocol clients, offline state synchronization, SQLite FTS5 search indexing, and cryptographic key management MUST reside strictly inside headless Rust crates: `crates/nuncio-core`, `crates/nuncio-mail`, `crates/nuncio-cal`, and `crates/nuncio-store`. - - Presentation shells (`crates/nuncio-cli`, `crates/nuncio-tui`, `crates/nuncio-gui`, `crates/nuncio-mcp`) MUST remain thin UI layers interacting with `nuncio-core` via `IpcClient` and async Tokio channels. +The workspace still contains `nuncio-tui`, `nuncio-gui` (+ `src-tauri`, `ui`), and +`nuncio-mcp`; these are slated to move out (Phase 0.D) and are reference-only. The +current transport is a hand-rolled length-prefixed JSON-RPC over **loopback TCP +`127.0.0.1:9422`** (note: *not* Unix sockets / named pipes, despite older docs); +it is being replaced by gRPC in Phase 1. Do not build new features on the old IPC. -2. **Standing Rule: 100% Multi-Shell Feature Parity Equivalence**: - - **Mandatory 1:1 Parity**: Any feature, action, search query, configuration setting, or workflow exposed in one presentation shell MUST be fully implemented and accessible across ALL FOUR presentation shells (`nuncio-cli`, `nuncio-tui`, `nuncio-gui`, `nuncio-mcp`). - - Adding a new feature to V1, V2, or V3 automatically requires implementing its CLI subcommand (`--json`), TUI keyboard shortcut/modal, GUI React component, and MCP LLM tool handler. +### Library-first boundary -3. **Language & Code Quality Standards**: - - **Rust Edition**: 2021 edition across all workspace crates. - - **Compiler & Linter Gates**: `rustflags = ["-D", "warnings"]` configured in `.cargo/config.toml`. All compiler and clippy warnings MUST be treated as hard build errors during normal development. - - **Formatting**: `cargo fmt` enforced. No unformatted code allowed. - - **Error Handling**: Use `thiserror` for library crates (`nuncio-core`, `nuncio-mail`, `nuncio-cal`, `nuncio-store`). `unwrap()` and `expect()` are **forbidden** in production library code (permitted only in tests and prototypes). - - **Security**: Never store plain-text passwords, tokens, or encryption keys in source files or SQLite tables. Route all credentials to OS native vaults via `keyring`. Payload attachments encrypted at rest via `age`. Untrusted HTML email sandboxed inside `