add initial plan for the Flutter rebuild

docs/initial-plan.md is the new north star. It states the rebuild's
premise explicitly: Python Clide's IDE skeleton gets rebuilt native
in Flutter, a sharpened subset of Obsidian's ideas (just canvas and
graph — no vault, no bases, no plugin inheritance) folds in, and
the architectural patterns from the short-lived claudian plugin
port over via ADRs 0001–0004.

Tier 0 is "Flutter app + sidecar daemon connected, empty IDE."
Tier 1 is "Claude runs inside clide, session survives app restart."
Later tiers layer panes, git, pql integration, canvas and graph,
and an extension API — each ordered so the guardrails (CLI-first,
user/Claude parity, pql-as-subsystem) stay enforceable at every
step.

Future Claude Code instances should read this before proposing
changes that touch architecture.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-20 20:41:43 +02:00
co-authored by Claude Opus 4.7
parent a782511470
commit 005d19ae93
2 changed files with 342 additions and 0 deletions
+1
View File
@@ -25,6 +25,7 @@ heading, and (b) bumping `project.yaml` `version:` in the same commit.
[ADR 0002](docs/ADRs/0002-sidecar-language-go.md) — Sidecar language: Go.
[ADR 0003](docs/ADRs/0003-pql-as-supporter-tool.md) — pql as supporter tool; wrap, don't duplicate; pql is a Clide subsystem when present.
[ADR 0004](docs/ADRs/0004-ignore-file-strategy.md) — Ignore file strategy (`ignore_files:` in `.pql/config.yaml`, layered).
- [`docs/initial-plan.md`](docs/initial-plan.md) — the north-star design document for the Flutter rebuild. Captures what we kept from Python Clide (pane model, git skills, Claude-always-visible), what we took from Obsidian (canvas and graph — no vault, no bases, no plugin inheritance), what Claudian's short experiment contributed (Go sidecar, CLI-first, pql-as-subsystem, ignore-file strategy), and the tier roadmap (Tier 0 app+sidecar handshake → Tier 5 canvas+graph).
- Claude Code configuration under `.claude/`: project-level
allow/deny permissions and two skills — `skill-create` (generic
skill authoring guidance) and `git-commit` (this repo's commit
+341
View File
@@ -0,0 +1,341 @@
# Clide — Initial Plan (Flutter rebuild)
**Working name:** clide (unchanged from the Python era). Repo root:
`/var/mnt/data/projects/clide`. Flutter desktop app + Go sidecar/CLI.
## Context
Clide v1.2.0 is a Python Textual TUI — terminal-only, polished, with
a pane model, panel set, git skills, plugin system, and a ttyd-backed
web variant. That implementation is archived under `legacy/` in this
repo; `git log -- legacy/` preserves its history.
In parallel, a two-day experiment called **claudian** explored a
"thin Obsidian plugin + Go sidecar" approach to the same problem:
run Claude Code inside a markdown-aware IDE. That project was tossed
when the implementation hit two walls:
1. Obsidian is Electron. Terminal rendering in Electron has a
documented failure mode on macOS (repaint thrash, WebGL context
loss, display-drag ghosting) that the user has lived through.
xterm.js mitigations soften the pain; they don't remove it.
2. Most of "Obsidian's value" turned out, on examination, to be two
features: canvas and graph. The rest — the vault concept, inline
YAML "bases," the wikilink implementation, the plugin ecosystem —
was either parallel ceremony to what the git repo already
provides, or better solved elsewhere (pql).
The lesson: we were fighting the host instead of using it. Clide
becomes a Flutter desktop app, with the Python Clide IDE skeleton
rebuilt natively and a sharpened subset of Obsidian's ideas folded
in. Claudian's architectural patterns (Go sidecar, CLI-first,
pql-as-subsystem, ignore-file strategy, supply-chain gate,
changelog discipline) port over as ADRs 00010004 and the
`.claude/skills/git-commit` rules; the plugin code itself does not.
**Intended outcome:** Clide is the IDE you open on a code repo.
Claude runs inside it (the terminal is first-class, always visible).
Markdown files are first-class content. Canvas and graph surfaces
support concept development. pql is the query engine. The Go
sidecar handles PTYs, subprocesses, file watching, git, and pql
invocations; the Flutter app renders. Claude drives the UI through
a `clide` CLI with the same contract as pql.
## Guardrails / non-negotiables
- **Flutter desktop is the UI host.** No Electron, ever. Web target
may work as a happy accident; don't compromise desktop fidelity for
it. `xterm.dart` is the terminal renderer.
- **No heavy lifting in the UI layer.** Flutter app stays focused on
rendering and interaction. PTYs, subprocesses, file watching, git,
pql invocations all live in the Go sidecar.
- **CLI-first, not MCP.** Claude talks Bash (`clide ...`), same
contract style as pql. See [ADR 0001](ADRs/0001-cli-first-not-mcp.md).
- **Sidecar language: Go.** Static binary, same idioms as pql. See
[ADR 0002](ADRs/0002-sidecar-language-go.md).
- **User/Claude parity.** Every `clide` subcommand has a UI
affordance in the Flutter app, and every UI action has a
corresponding subcommand. Incomplete otherwise.
- **pql is a supporter tool and a clide-managed subsystem.** The
only place clide contains pql logic is `sidecar/internal/pql/`
pure shell-outs. See [ADR 0003](ADRs/0003-pql-as-supporter-tool.md).
- **Repo-is-the-workspace.** The git repo root is the workspace.
No parallel "vault" concept. Ignore behaviour drives through
`.pql/config.yaml` — see [ADR 0004](ADRs/0004-ignore-file-strategy.md).
- **Dependencies: version-locked and CVE-checked.** Go deps exact-
pinned and govulncheck-gated; Dart deps prefer-zero-then-exact-
pinned. See the memory files under
`~/.claude/projects/-var-mnt-data-projects-clide/memory/`.
## What carries forward from each parent project
| From Python clide (`legacy/`) | Carried forward as |
|---|---|
| Pane/visibility model (Sidebar / Workspace / Context) | Same model, rendered in Flutter widget trees |
| Workspace tabs (Editor / Diff / Terminal — appear when needed) | Same pattern; `xterm.dart` hosts the Terminal tab |
| Claude-always-visible in the workspace center | Unchanged; the centrepiece |
| Git panel (staged/unstaged, click actions) | Port widget-for-widget; sidecar shells out to git |
| Git skills (`/commit`, `/stash`, `/pull`, `/push`) | Rewire to call `clide git ...` under the new CLI |
| Context panel (Jira / TODOs / Problems) | Port; data providers become sidecar subsystems |
| TODO.md parsing for the TODOs panel | Preserve the format; sidecar parses and serves |
| Theme system (22 themes, TOML) | Port the palette over time; Flutter theming is first-class so no bespoke system needed |
| Plugin system (pluggy hookspecs) | Translates into a Dart extension API we design fresh; not imported |
| From Obsidian (as an idea, not a dep) | Carried forward as |
|---|---|
| Canvas | Flutter `CustomPaint` + `InteractiveViewer`; `.canvas` JSON-schema-compatible where easy |
| Graph view | Flutter-native; data from pql, not a re-parser |
| Wikilink syntax (`[[page]]`) | Parser + renderer, nothing more |
| Frontmatter | Standard YAML; pql already parses it |
| From Obsidian, **rejected** |
|---|
| "Vault" concept — the git repo is the workspace |
| Inline bases (YAML query tables) — pql at the repo level |
| Obsidian's wikilink implementation — syntax only |
| Plugin ecosystem — clide's extension API is its own |
| From claudian (2-day experiment) | Carried forward as |
|---|---|
| Go sidecar + CLI-first architecture | Unchanged; ADRs 00010002 |
| pql-as-supporter-tool + pql-as-clide-subsystem rules | Unchanged; ADR 0003 |
| Ignore-file strategy (`ignore_files:` in `.pql/config.yaml`) | Unchanged; ADR 0004 |
| Supply-chain gate (`make security`, `make vuln`, lockfile discipline) | Port for Go sidecar; Dart equivalent TBD |
| Changelog discipline (Keep a Changelog, `project.yaml` version sync) | Port verbatim |
| Commit conventions (imperative, no types, HEREDOC, attribution trailer, logical splits) | Port verbatim to `.claude/skills/git-commit` |
**Python clide's future:** feature-frozen at v1.2.0. Stays under
`legacy/` for reference. No back-porting.
## Architecture
```
┌────────────────── clide (Flutter Desktop) ───────────────────┐
│ │
│ ┌─────────────┬────────────────────────────┬─────────────┐ │
│ │ Sidebar │ Workspace │ Context │ │
│ │ │ ┌──── Editor / Diff ─────┐ │ │ │
│ │ Files │ │ (appears when needed) │ │ Jira │ │
│ │ Git │ └────────────────────────┘ │ TODOs │ │
│ │ Tree │ │ Problems │ │
│ │ │ ┌──── Claude (xterm.dart) │ │ │ │
│ │ │ │ (always visible) │ │ │ │
│ │ │ └────────────────────────┘ │ │ │
│ │ │ ┌──── Terminal (optional)│ │ │ │
│ │ │ └────────────────────────┘ │ │ │
│ ├─────────────┤ ├─────────────┤ │
│ │ ⎇ main │ Canvas + Graph live as │ │ │
│ │ staged: 2 │ full-screen views │ │ │
│ └─────────────┴────────────────────────────┴─────────────┘ │
│ │ │
│ │ Dart IPC client │
│ ▼ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ clide sidecar daemon (Go, same binary as CLI) │ │
│ │ - real PTYs (for xterm.dart panes) │ │
│ │ - subprocess management │ │
│ │ - filesystem watchers │ │
│ │ - git shelling-out │ │
│ │ - pql wrapper │ │
│ │ - IPC server (unix socket, token auth, JSON-lines) │ │
│ └─────────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ ┌─────────────────────────┐ │
│ │ Claude Code (inside │ │ pql (Go CLI, external) │ │
│ │ a workspace PTY pane) │ │ called by sidecar and │ │
│ │ │ │ by Claude directly │ │
│ │ $ clide open wiki/... │ └─────────────────────────┘ │
│ └────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
```
**Three surfaces, one coherent tool:**
- **`clide` Flutter app** (UI): renders panels via widget trees,
hosts `xterm.dart` panes for terminals, connects to the sidecar
over IPC.
- **`clide` CLI** (one-shot): Claude's entry point. Parses args,
opens the sidecar socket, sends a request, prints JSON on stdout
with the pql-style exit-code contract, exits.
- **`clide --daemon`** (long-running sidecar): Same binary, different
mode. Owns PTYs, subprocesses, file watchers, git, pql shell-outs.
IPC server for app + CLI. Started by the app on load; survives app
restarts so Claude sessions persist.
## Repo layout (target)
```
projects/clide/
├── README.md # pitch + link to this plan
├── LICENSE
├── CHANGELOG.md
├── CLAUDE.md # lean orientation for Claude Code
├── project.yaml # single source of truth: version, module path, schema version
├── Makefile # drives both app (flutter) and sidecar (go)
├── .gitignore / .editorconfig
├── .clideignore # optional; see ADR 0004
├── .claude/ # project-level Claude Code config + skills (committed)
├── .githooks/pre-push # push-gate runs lint/test/vuln on both app and sidecar
├── ci/ # lint.sh, test.sh, security.sh, release.sh
├── docs/
│ ├── initial-plan.md # this document
│ └── ADRs/0001..0005 # decisions
├── app/ # Flutter desktop (generated by `flutter create`)
│ ├── pubspec.yaml
│ ├── lib/ # main.dart + panels/, widgets/, ipc/, theme/
│ ├── linux/ macos/ windows/ # platform scaffolding
│ └── test/
├── sidecar/ # Go sidecar + CLI, single binary, two modes
│ ├── go.mod
│ ├── cmd/clide/main.go
│ └── internal/
│ ├── cli/ # one-shot subcommand dispatch
│ ├── daemon/ # --daemon mode
│ ├── ipc/ # unix-socket server (for app + CLI)
│ ├── pty/ # real PTYs for xterm.dart panes
│ ├── proc/ # subprocess management
│ ├── git/ # git shell-outs
│ ├── pql/ # thin wrappers around the pql binary
│ ├── diag/ # exit-code contract + stderr-JSON
│ └── version/ # ldflag-stamped build info
├── legacy/ # archived Python clide v1.2.0
└── tests/ # integration tests that span app + sidecar
```
## Tier roadmap (prioritized)
### Tier 0 — Foundation: Flutter app + sidecar daemon connected, empty IDE
- Flutter app scaffold (`app/`) with a three-column layout, placeholders.
- Go sidecar daemon (`sidecar/`) — socket, token auth, JSON-lines
protocol, single-instance lock, graceful shutdown.
- `clide` CLI one-shot mode — version + a `ping` subcommand.
- Dart IPC client — auto-reconnect, JSON-lines envelope.
**Acceptance:** `clide --daemon` runs; Flutter app connects; the app
shows a connected-status indicator and the panels as placeholders.
### Tier 1 — Claude runs inside clide
- `xterm.dart` Terminal pane in the Workspace center, connected to
a sidecar-owned PTY.
- Session persistence: sidecar keeps PTYs alive across app restarts.
- "Open Claude" button that spawns a PTY running `claude` (or
`tmux attach -t claude` for team mode when that ships later).
**Acceptance:** open clide → Claude is running in the workspace →
quit and reopen clide → Claude session is still there.
### Tier 2 — Pane model and active-file awareness
- File tree panel (Sidebar/Files), drag-to-reveal, click-to-open.
- Editor tab — markdown and code via `flutter_highlight` or our own
light renderer; saves through the sidecar's file watcher.
- `clide open <path>`, `clide active`, `clide insert`,
`clide replace-selection`, `clide tail --events …` — the CLI
surface Claude uses to drive the UI. Equal UI affordance for each.
**Acceptance:** Claude says *"opening `notes/today.md`"* → runs
`clide open notes/today.md` → the file appears in the Editor tab.
### Tier 3 — Git
- Git panel (Sidebar/Git) — staged/unstaged groups, hunk-level
stage/unstage, conflict UI. Sidecar shells out to git; Flutter
renders.
- Diff tab in the Workspace (side-by-side + unified toggle).
- `clide git …` subcommands back the panel actions. Python clide's
`/commit`, `/stash`, `/pull`, `/push` skills rewire to call
`clide git …`.
**Acceptance:** the common day-to-day git flow works entirely in
clide, with Claude driving the same operations.
### Tier 4 — pql integration (Query panel + everywhere else)
- Query panel renders `pql <args>` output as table / list.
- Results click-through opens the referenced file in the Editor
tab.
- File tree, canvas node sources, graph view, backlinks indicator,
problems panel — all pull from pql where applicable.
**Acceptance:** `pql tags` output renders in a Query panel; clicking
a tag narrows the file tree; backlinks show in the Context panel.
### Tier 5 — Canvas and graph
- Canvas surface: `CustomPaint` + `InteractiveViewer`, pan/zoom,
node creation, connection drawing. Format aims for `.canvas`
JSON-schema compatibility with Obsidian.
- Graph view: force-directed layout, link data from pql.
- `clide canvas node …`, `clide canvas connect …`,
`clide graph open` — CLI parity.
**Acceptance:** open a canvas file from the Sidebar; drag a new
node; Claude can add a node by `clide canvas node …`.
### Tier 6 — Extension API (later)
- Dart extension API (design fresh, not ported from pluggy).
- Settings page, theme picker, keybinding editor.
- Distributable builds (macOS/Linux) via Flutter's native tooling.
## Critical integration points
- **`sidecar/cmd/clide/main.go`** — Cobra root: `clide <subcommand>`
(one-shot) vs `clide --daemon` (long-running).
- **`sidecar/internal/ipc/server.go`** — single socket; token-auth;
dispatches to subsystems (pty, proc, git, pql, canvas, panes).
- **`sidecar/internal/pql/`** — *only* place Clide contains pql
logic; pure wrappers, no re-implementation.
- **`app/lib/ipc/client.dart`** — Dart IPC client; reconnect-on-
reload; JSON-lines envelope.
- **Claude settings** — `.claude/settings.json` allow rule
`Bash(clide *)`; no MCP config.
- **pql** — first-class supporter tool, called by Claude directly
AND wrapped by Clide where ergonomics justify it.
## Decisions locked
1. **Name:** clide (unchanged). Binary: `clide`. Flutter app bundle
id: `clide`.
2. **First milestone:** Tier 0 + Tier 1.
3. **Packaging:** single app + single sidecar/CLI binary. Platform
builds via Flutter's native tooling.
4. **Distribution:** personal-only now, MIT-licensed (carried from
legacy/).
5. **CLI-first, not MCP** (ADR 0001).
6. **No Electron, no Node in the UI layer** — Flutter and Dart only.
7. **pql is a supporter tool; wrap, don't duplicate; pql is a Clide
subsystem when present** (ADR 0003).
8. **User-and-Claude parity** — every CLI has a UI affordance and
vice versa.
9. **Dataview / bases out of scope** — pql is the query engine (ADR
0003).
10. **Workspace = git repo root** — no vault concept.
## Open questions (investigate in-repo, not now)
- **`.canvas` schema compatibility** — how strictly do we match
Obsidian's format? Decide during Tier 5 spike.
- **Extension API shape** — widgets? subcommands? both? Decide
during Tier 6 planning.
- **IPC wire-format stability** — when to lock the schema,
versioning strategy. Mirror in `project.yaml`
`schema_version:` when it lands.
- **Code editor quality bar** — does the Editor tab need full LSP
integration via the sidecar, or a lighter tree-sitter-based
highlight-only view first? Decide during Tier 2.
## Remaining assumptions (flag if wrong)
- **Flutter Desktop on Linux + macOS** is the primary target;
Windows is a stretch goal. Mobile is not a goal.
- **Gitea remote** (`git.schweitz.net/jpmschweitzer/clide`) remains
the canonical host.
- **`pql` stays untouched** for Tiers 02; upstream pql work
happens in pql's repo during Tiers 35.
- **tmux** is optional plumbing the sidecar can compose for team
mode; not a hard dependency for Tier 1's session persistence
(the sidecar holds the PTY fd directly).