add audit, dogfood, and pql-improvement notes under docs/

Three analysis docs that were loose at the repo root: the 2026-05-26
codebase cleanliness audit, the dogfood self-analysis of whether Claude
can work inside clide, and the pql improvement notes for upstream.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jeroen Schweitzer
2026-06-03 09:31:54 +02:00
co-authored by Claude Opus 4.8
parent f90bcbf5f3
commit fa1e71d175
3 changed files with 509 additions and 0 deletions
+105
View File
@@ -0,0 +1,105 @@
# Codebase Cleanliness & Pattern Audit
**Date:** 2026-05-26
**Scope:** `lib/` (314 files, ~2.1MB) and `pubspec.yaml`. Skipped `legacy/`, `tests/`, generated files. Conventions grounded in [`CLAUDE.md`](CLAUDE.md) guardrails and the [`governance/decisions/`](governance/decisions/) D-records (architecture, extensions, testing, tooling, process).
## Baseline health
- `dart format --set-exit-if-changed`: **468/468 files clean.**
- `flutter analyze`: **3 warnings, all in a single WIP file** (`lib/builtin/claude/src/session_orchestrator.dart`), already in the modified-but-uncommitted set:
- L15: unused `dart:convert` import
- L16: unused `dart:io` import
- L29: unused private field `_resumeTailBytes`
- No `print(` / `debugPrint(` in `lib/`. No TODO / FIXME / HACK comments. No commented-out code blocks. No orphaned `.dart` files.
The repo is in unusually good baseline hygiene shape — the audit's interesting findings are structural, not janitorial.
## Guardrail / D-record compliance
| Decision | Status | Notes |
|---|---|---|
| **D-7** bare `WidgetsApp` | Pass | No `MaterialApp`/`CupertinoApp`/`Scaffold`/`ElevatedButton`. Material/Cupertino imports exist only in inlined xterm heritage under `lib/src/terminal/` and aren't instantiated. |
| **D-8** feature-first, barrels only | Pass | No cross-feature reach into another feature's `src/`. `lib/extension/src/``lib/kernel/src/` is the one cross-`src/` link (extension framework on platform foundation — legitimate). |
| **D-10** ChangeNotifier + ListenableBuilder | Pass | No provider/riverpod/bloc/get_it. Three `InheritedWidget` subclasses (`ScrollbarTheme`, `ClideKernel`, `ClideTheme` via `InheritedNotifier<ThemeController>`) are all justified scoped-context uses. |
| **D-31 / D-42** exact-pin + `licenses.yaml` | Pass | No caret ranges in `pubspec.yaml`. All 13 runtime deps + dev deps + native binaries documented. |
| **D-46** core frame vs shipped extensions | **Drift** | `editor`, `claude`, `claude-control`, `markdown`, `diff`, `git-ui`, `pql`, `canvas`, `graph`, `decisions`, `tickets`, `todos`, `problems` should be shipped extensions on a separate registration path. They still live in `lib/builtin/` alongside core frame builtins. Architectural intent documented but not enforced — migration deferred. |
| **D-56** single package, in-process IPC | Pass | No `bin/clide.dart`, no `app/`, no `sidecar/`. `lib/src/daemon/` is in-process dispatcher + handlers. |
| **D-1 / D-68** CLI primary, MCP secondary | Pass | `lib/src/ipc/server.dart` (unix socket) and `lib/src/ipc/mcp_server.dart` (HTTP+SSE) both wrap the same `DaemonDispatcher`. |
| **D-72** serial dispatch on main isolate | Pass | `server.dart:212` awaits `dispatcher.dispatch(req)` inside a per-client serial line handler. |
| **D-74** schema co-registered | Pass | `DaemonDispatcher` accepts `CommandSchema?` at registration (`dispatcher.dart:23`), validates pre-handler (L5559). |
| **D-66** 95% coverage floor | Pass | `pubspec.yaml:26`: `coverage_floor: 95`. |
| **D-75 / D-77 / D-78** Claude coupling isolation | Pass | All `~/.claude/`, transcript JSONL, `claude` CLI invocations live behind `lib/builtin/claude/src/`. No leakage to other features. |
| **CLAUDE.md** in-house renderers | Pass | Markdown: pub.dev parser (per D-58) + custom renderer in `lib/widgets/src/clide_markdown.dart`. Canvas + graph in-house. |
| **Analyzer suppressions** | Pass | `// ignore`s are confined to xterm heritage code, FFI bindings (C naming), and lookup tables. All justified. |
## Findings worth acting on
### 1. Unused pubspec dependencies (D-31 violation in spirit)
- `flutter_widget_from_html_core: 0.17.2` — listed in `dependencies:`, imported nowhere. Mentioned in D-58 as adoptable, but no current consumer.
- `mocktail: 1.0.4` — listed in `dev_dependencies:`, imported nowhere. D-25 specifies it for IO mocks, but no tests use it today.
Per D-62 (Dependency removal process), removing requires the full 5-step PR. But carrying them violates D-31's "what stays is exact-pinned" intent — the spirit being "we keep only what we use."
### 2. D-46 architectural drift — known but uncodified
Thirteen "shipped extension" features still register through the core frame path. This is documented drift, not new — but it's the largest unresolved architectural debt. A dedicated `lib/extensions/` directory + a second registration tier is the prescribed fix.
### 3. Three hotspot files (>800 lines, mixed concerns)
| File | Lines | Shape |
|---|---|---|
| `lib/app.dart` | 1175 | 11+ State classes for sidebar/workspace/editor/context/status — split by region |
| `lib/src/terminal/src/core/escape/parser.dart` | 1139 | `EscapeParser` FSM, 1095-line class — handler logic could split by escape domain |
| `lib/src/terminal/src/terminal.dart` | 907 | `Terminal` class implementing 5 interfaces, 80+ methods spanning cursor/buffer/input/output |
The terminal pair is partially inlined heritage code (xterm.dart) so refactoring it competes with merge-friendliness; `app.dart` is yours to split freely.
### 4. Silent error swallowing in `lib/builtin/claude/src/claude_config.dart`
Seven `catch (_)` sites (L292, 301, 314, 394, 460, 489, 505) in config/skill loading. Config parsing failures vanish without log or UI signal. Per D-76 the service is supposed to "degrade gracefully" on parse miss — that's fine, but at minimum these should log to make schema drift visible (D-75 / D-78 explicitly call out that detection is the mitigation for CC-internals drift).
### 5. Long methods — theme resolvers and one claude config probe
| File:Line | Method | Lines |
|---|---|---|
| `lib/kernel/src/theme/resolver.dart:9` | `palette()` | 172 |
| `lib/kernel/src/theme/resolver.dart:11` | `semantic()` | 170 |
| `lib/kernel/src/theme/resolver.dart:13` | `surface()` | 168 |
| `lib/builtin/claude/src/claude_config.dart:306` | `_parseInitProbe()` | 178 |
Theme resolvers are dense token tables (data-shaped, not control-flow) — borderline but tolerable. The probe parser is the strongest splitting candidate.
### 6. Suspicious duplication
- `lib/builtin/tickets/src/tickets_view.dart` + `ticket_detail_view.dart` — 4+ near-identical `builder: (ctx, hovered, _) => ...` responsive button scaffolds. Extract a factory widget.
### 7. Magic strings worth a constant
- `'type': 'request' | 'response' | 'event'` recurs across `lib/src/ipc/envelope.dart` (L42, 79, 141). With two transports (socket + MCP) both speaking JSON envelopes, these belong as enum-or-const so a typo can't silently land.
- `lib/builtin/claude/src/transcript_reader.dart` (L477, 495, 498): `'user'`, `'assistant'`, `'permission-mode'` — strong candidates for an enum per the D-75 isolation principle (one place that knows the schema).
### 8. Coupling hub
`lib/main.dart` imports from 51 files — boot orchestrator, expected, but fragile. Splittable into `boot_kernel.dart` / `boot_ipc.dart` / `boot_ui.dart` if it grows further.
## What's notably *not* a problem
- No god-object utilities (`utils.dart`, `helpers.dart`, etc.) — feature-first discipline holds.
- No unchecked `as` casts — every cast is guarded by `is` or null-coalesce.
- No `dynamic` overuse outside legitimate JSON / Flutter API boundaries.
- Naming is uniformly Dart-idiomatic across 314 files.
- No deep control-flow nesting outside idiomatic `build()` trees.
## Recommended next moves
1. Land the three analyzer warnings in `session_orchestrator.dart` as part of the in-flight commit.
2. Decide on `flutter_widget_from_html_core` and `mocktail` — either wire them in or remove them via the D-62 process.
3. Open a tracking ticket for the D-46 migration if one doesn't exist; this is the only meaningful drift.
4. Split `app.dart` by layout region — lowest-risk, highest-readability win.
5. Add logging (not exception propagation) to the `claude_config.dart` silent catches so schema drift surfaces during real use.
6. Extract envelope type strings to constants/enum in `lib/src/ipc/envelope.dart` before the second transport (MCP) accumulates more divergence.
## Overall assessment
This is a tidy codebase. The audit found one architectural drift (D-46, already documented), three localized hotspots, two stale pubspec entries, and a handful of cosmetic improvements. Nothing systemic.
+164
View File
@@ -0,0 +1,164 @@
# pql — improvement notes from a live session
Feedback for [`postmeridiem/pql`](https://github.com/postmeridiem/pql), gathered
while using pql as the planning backend for the `clide` repo. Everything below
was observed first-hand, not inferred from docs.
**Environment**
- pql `1.5.0`, commit `ab191fb`, schema_version 1 (binary), DB schema_version 2.
- Consumer: a single-dev repo using pql for decisions + tickets, with pql's
installed git hooks (`.pql/hooks/post-checkout`, `post-merge`, `post-rewrite`,
`pre-commit`) and a git-tracked `.pql/changelog/` + `.pql/pql-plan.json`.
The core is genuinely good — structural queries, the decision/ticket model, exit
codes, and the changelog-as-source-of-truth idea all worked. The notes below are
where it bit us or surprised us, roughly in priority order.
---
## 1. CRITICAL — ticket mutations aren't persisted, and rebuild-on-checkout silently destroys them
**Observed.** `pql ticket new` (and `ticket status` / `ticket block`) write only to
`.pql/pql.db`, which is gitignored. Nothing writes through to the git-tracked
`.pql/changelog/` automatically. Separately, pql's installed `post-checkout` and
`post-merge` hooks run `pql plan rebuild`, which replays the **committed**
changelog and overwrites `pql.db`.
The two facts combine into silent data loss:
1. Created an 18-ticket tree (an initiative + 4 epics + tasks, with blockers and
decision refs) via a series of `pql ticket new` calls. Verified present in
`pql ticket list`.
2. A routine `git checkout` fired `post-checkout``pql plan rebuild``pql.db`
was rebuilt from the changelog, which still ended at the previous max ticket.
3. All 18 tickets were gone. No warning, no prompt.
**Impact.** Total, silent loss of un-exported planning work on an ordinary git
operation. The user did nothing wrong — they switched branches.
**Repro.**
```bash
pql ticket new task "scratch ticket" # lands in pql.db only
git checkout -b somebranch # post-checkout runs `pql plan rebuild`
pql ticket list | grep "scratch" # gone
```
**Suggested fixes** (any one closes the hole; (a) is the principled one):
- **(a) Write-through.** Have ticket/decision mutations append to the changelog
at mutation time, making the changelog the log of record and `pql.db` a derived
cache. Then rebuild is always safe.
- **(b) Divergence guard.** `pql plan rebuild` (and the hooks that call it) should
detect when `pql.db` holds rows not represented in the changelog and refuse or
loudly warn instead of overwriting — e.g. *"pql.db has 18 un-exported rows; run
`pql plan export` first, or pass --force."*
- **(c) Non-destructive rebuild.** Merge the changelog into `pql.db` rather than
replacing it.
At an absolute minimum, the `post-checkout`/`post-merge` hooks should not
discard local state without a word.
---
## 2. `pql plan export` writes the changelog, but docs/help say it writes a JSON snapshot
**Observed.** `pql plan export` wrote:
```
{"files_written":[".pql/changelog/ticket_deps/2026-06.sql",
".pql/changelog/tickets/2026-06.sql"],"rows_written":23}
```
It did **not** touch `.pql/pql-plan.json`, which stayed frozen at an older date
across every mutation and export this session. But the `--help` text and the
bundled skill both describe export as *"Snapshot planning state to JSON (default:
`pql-plan.json`)"* and recommend committing `pql-plan.json`.
**Impact.** Users (and the bundled skill) commit `pql-plan.json` believing it is
the durable artifact. It is stale. The actually-durable artifact is the
changelog. This directly compounds #1 — people think they've versioned their
planning state when they haven't.
**Suggested fix.** Make `--help`, docs, and the embedded skill match real
behavior. Clarify the role of `pql-plan.json` vs `.pql/changelog/`: is the JSON
snapshot deprecated in favor of the changelog? If both exist, document which one
`pql plan import` / `pql plan rebuild` prefer.
---
## 3. Schema upgrade is a hard break requiring multi-step manual recovery
**Observed.** After a pql binary upgrade, every planning command failed:
```
$ pql decisions sync
planning: decision_refs.created_at missing — pql.db is from an earlier schema.
$ pql plan status
planning: decisions.created_at missing — pql.db is from an earlier schema.
```
(exit 69). Recovery was manual and multi-step: delete `pql.db`, `pql plan
rebuild`, then `pql decisions sync`.
**Impact.** All planning surfaces are dead until the user performs a manual
recovery they have to read out of the error text. Easy to get wrong (the error
also offers a `--legacy pql-plan.json` path — see #4).
**Suggested fix.** Auto-migrate the schema on open (additive column adds are
cheap), or ship a single `pql plan repair` / `pql migrate` command that performs
the safe delete-rebuild-sync sequence (with a backup of the old DB).
---
## 4. Schema-error recovery hint can point at the stale snapshot
**Observed.** The schema error (see #3) lists recovery options including
`pql plan import --legacy .pql/pql-plan.json`. Given #2 (that file is stale), a
user following that branch restores an out-of-date snapshot. The correct path
was the changelog rebuild.
**Suggested fix.** In the recovery list, prefer/recommend `pql plan rebuild` when
`.pql/changelog/` is present, and annotate the `pql-plan.json` option as
potentially stale.
---
## 5. Scripting ergonomics — no id-only output from `pql ticket new`
**Observed.** Building a ticket tree means capturing each created ticket's id to
use as the next call's `--parent`/blocker. `pql ticket new` emits the full ticket
JSON, so a creation script must parse `.id` out of every call.
**Suggested fix.** A `--quiet` / `--id-only` (or `-o id`) flag that prints just
the new `T-NNN`, so tree-creation scripts stay simple. (Determinism is already a
strength: re-running the same `new` calls in order against a clean baseline
reproduces the same ids — which is what let us recover from #1.)
---
## 6. Minor — bundled skill assumes binary features the installed version lacks
**Observed.** The bundled `pql` skill documents `pql ticket show --tree`,
`--leaf`, `--unblocked`, `--under`, and `pql ticket append` (annotated "pql ≥
1.6.0"). The installed binary reports 1.5.0 as current (`pql doctor` /
`pql skill status`), and rejects them:
```
$ pql ticket show T-65 --tree
unknown flag: --tree # exit 64
```
**Impact.** A consumer following the skill hits unknown-flag errors and has to
discover the 1.5.0 fallbacks (`--with-children`, `--with-blockers`) by trial.
**Suggested fix.** Keep the embedded skill's documented surface in lockstep with
the binary it ships alongside, or have `pql skill install` stamp/gate
version-specific sections so the skill never advertises flags the paired binary
doesn't have.
---
## Summary
The one that matters most is **#1** — a routine `git checkout` can silently erase
planning work because mutations live only in a gitignored DB and the
pql-installed hooks rebuild that DB destructively. **#2** makes it worse by
pointing users at the wrong file to commit. Fixing write-through (or a divergence
guard) plus aligning the export docs would remove a whole class of "where did my
tickets go" incidents.
+240
View File
@@ -0,0 +1,240 @@
# self-analysis.md — can Claude actually work inside clide?
**Date:** 2026-06-02
**Author:** Claude (Opus 4.8), run as the dogfood agent against a live clide instance
**Method:** This is not a documentation review. clide was running while I wrote this
(socket `~/Library/Caches/clide/05cd448c962214d7.sock`, MCP SSE on `127.0.0.1:50354`,
daemon reports `version 2.1.0`). I probed my own environment, drove the live daemon, and
report what actually happened — with the command transcripts as evidence.
The question on the table: *we're close to working together inside clide — what's missing
from my end?* Here's the honest answer.
---
## TL;DR
**The daemon is ready. My hands are missing.**
Everything the CLI-first contract (D-1, D-6) promises works end-to-end at the socket
level — `git status`, `files`, `editor`, `pane`, exit codes, the lot. I verified it live.
But a fresh Claude session dropped into this repo **cannot reach any of it**, because:
1. There is **no `clide` binary on `PATH`** — and no install path that would put one there.
2. Nothing tells a fresh agent that clide is even running, where its socket is, or that
the CLI exists.
3. The live UI surfaces the user sees (the Claude pane, file tree, open files) are **not
reflected** in the registries the CLI reads — `pane list` and `editor list` came back
empty while clide was open and in use.
The first one is the blocker. The fix is roughly ten lines of Makefile. The other two are
the difference between "the agent can issue commands" and "the agent and the user are
actually looking at the same workspace."
---
## What works today (verified live)
I built the C client (`make clide-cli` — it had never been built; `native/macos-arm64/`
did not exist) and pointed it at the running daemon:
```
$ native/macos-arm64/clide ping
{"pong":true,"ts":"2026-06-02T10:45:31Z","version":"2.1.0"} # exit 0
$ native/macos-arm64/clide git status
{"branch":"main","upstream":"origin/main","ahead":0,"behind":0,
"clean":false,"unstaged":[{"path":"governance/README.md",...}, ...]} # exit 0
$ native/macos-arm64/clide files root
{"path":"/Users/jeroenschweitzer/Projects/clide","ignorePatterns":79} # exit 0
```
- **IPC transport is solid.** Unix socket, JSON envelopes, the `_argv` bridge — all live.
- **The command surface is real and broad.** `pane`, `files`, `editor`, `git`, `search`,
`pql`, `panel` subsystems all dispatch. `git status` returned my actual working tree.
- **Exit-code discipline is correct** (this matters for an agent — it's how I know if a
command worked):
| command | exit |
|---|---|
| `clide ping` | `0` |
| `clide git status` | `0` |
| `clide editor open /nonexistent/path` | `1` |
| `clide status` (not a real command) | `3` |
0/1/3 map cleanly onto the pql contract. Good. An agent can trust these.
So the foundation is genuinely there. The gaps below are about **delivery and
observability**, not the core design.
---
## Gap 1 — `clide` is not on PATH, and nothing installs it there *(blocker)*
This is the one that stops us cold.
```
$ which clide → clide not found
$ clide ping → command not found (exit 127)
```
The CLI-first contract assumes I run `clide …` from Bash. I can't. Digging in:
- The C client (`native/clide-cli/clide.c`) is the real CLI. It builds only via the
**separate, non-default** target `make clide-cli`, and the output had never been built.
- `make install` on **macOS** copies *only* the `.app` bundle to `~/Applications`. It
**never places a `clide` CLI on PATH.**
- `make install` on **Linux** symlinks `clide``$(INSTALL_PREFIX)/clide/clide`, which is
the **GUI app binary** (the Flutter runner), *not* the C client. So even the Linux path
doesn't deliver the shell client.
Net: there is **no supported way** for the `clide` command to exist on an agent's PATH.
The contract that the entire agent-IDE relationship rests on has no delivery mechanism.
**Impact:** Total. Without this, "Claude works inside clide via the CLI" is aspirational.
I only got there by reverse-engineering the socket path and compiling a C file myself.
**Fix (small):**
- Make `clide-cli` a dependency of `build`/`install`.
- On macOS `install`, also drop the built C client somewhere on PATH
(`~/.local/bin/clide`, or `/usr/local/bin`), and have the GUI launch offer to install it
(à la VS Code's "Install 'code' command in PATH").
- Confirm the Linux symlink targets the **C client**, not the GUI binary.
---
## Gap 2 — No bootstrap: a fresh agent doesn't know clide is there
Even with the binary installed, a new session has no signal that it's hosted by clide.
There's a discovery file for the *MCP* path (`~/.claude/ide/<pid>.lock`, which correctly
pointed at workspace + SSE URL), but **nothing for the Bash/CLI path**:
- No `CLIDE_SOCK` / `CLIDE_WORKSPACE` env var in my shell.
- No injected note (CLAUDE.md fragment, system reminder) saying "you're inside clide; use
`clide …` to drive the editor, git panel, and file tree."
- No pre-seeded `Bash(clide *)` allow rule mentioned anywhere the agent would see it.
I had to be *told* "you're running inside clide" and then go find the socket. That's not
discoverable.
**Impact:** High. Discovery is the difference between a capability existing and a
capability getting used. I won't reach for `clide editor open` if I don't know it's wired
up.
**Fix:** When clide spawns/hosts an agent, export `CLIDE_SOCK`/`CLIDE_WORKSPACE`, ensure
`clide` is on the child's PATH, and inject a short context note describing the CLI surface
and the parity contract.
---
## Gap 3 — The live UI isn't visible to the CLI *(parity premise breaks here)*
D-6's promise is two-way: every UI affordance has a CLI verb, **and the agent can observe
what the user is doing**. Right now I can't see the user's surfaces. While clide was open
and you were talking to me through it:
```
$ clide pane list → {"panes":[]}
$ clide editor active → {"active":null}
$ clide editor list → {"buffers":[]}
```
Empty. Either the built-in UI panes (the Claude conversation pane, the file tree, any open
viewer) **don't register into the daemon registries** the CLI reads, or those registries
only track CLI-spawned entities. Either way, the consequence is the same: **I cannot tell
what file you're looking at, what's selected, or what panes are open.** The "agent sees
what the user sees" half of parity isn't there yet.
**Impact:** High for real collaboration. Half of working *together* is me reacting to
what's on your screen ("you've got `dispatcher.dart` open — want me to jump to the handler
that's failing?"). Today I'm blind to it.
**Fix:** Make the built-in extensions register their panes/buffers/active-file state
through the same registries the `pane`/`editor` CLI reads. Add a `clide status` umbrella
(see Gap 6) that returns a one-shot snapshot: active pane, focused file + selection, git
summary, layout.
---
## Gap 4 — Event observation doesn't fit how an agent runs
`clide tail --events` is the design's answer to "how does Claude see state change." But a
streaming, never-returning command is awkward from a request/response tool loop — I can't
sit on an open stream the way a long-lived UI client can. I either background it and poll a
file, or I miss events.
This is more ergonomic than broken, and it overlaps the still-open Q-2 (back-pressure) and
Q-3 (event persistence/audit). But for *me specifically* it matters.
**Impact:** Medium. Without a pull-based form I'll just re-run `git status` / `editor
active` on demand and never use the event bus — which means I miss things that happen
between my polls.
**Fix:** Offer a cursor-based pull alongside the stream: `clide events --since <cursor>`
returning everything since the cursor plus a new cursor. That fits an agent loop natively
and dovetails with Q-3's persistence question.
---
## Gap 5 — Which Claude is the dogfood agent? *(needs a decision)*
There's an unresolved ambiguity I bumped straight into. My shell reports
`TERM_PROGRAM=zed` — i.e. *this* Claude (me) is an external Claude Code harness, not a
session clide spawned via the stream-json protocol (D-77/D-78). So there are two distinct
"Claude inside clide" stories, and they have different gaps:
- **(A) clide-hosted session** — clide spawns `claude --output-format stream-json`, renders
the conversation natively, handles permission prompts as native cards (D-77/D-78). This
is the *user's* primary Claude pane.
- **(B) external agent driving via CLI** — a Claude Code process (like me) that issues
`clide …` commands to manipulate the IDE.
These aren't the same agent. In (A), the hosted Claude *is* the conversation but would
itself need `clide` on PATH to drive the surrounding IDE (Gaps 13 apply to it too). In
(B), clide can observe my `clide …` IPC calls but is blind to the rest of my tool use
(file reads, `make test`, plain `git`) because my shell isn't clide-owned.
**Impact:** Medium, but foundational — it decides what "working together inside clide"
even means. Worth a short governance note (Q- or D-record) pinning down the intended model:
is the dogfood agent the hosted stream-json session, an external CLI driver, or both?
---
## Gap 6 — Minor / cleanup
- **No `clide status` command.** There's no single one-shot "what's the whole state right
now" call — the natural first thing an agent reaches for. (`status` currently returns
exit 3, unknown command.) Cheap to add and high-value for orienting.
- **MCP transport is up but not reachable by me.** The SSE server is live
(`:50354`), but `mcp__ide__*` tools aren't in my tool list this session, and
`getDiagnostics`/`executeCode` were noted as stubs. So neither transport (CLI nor MCP) is
actually wired to an external agent out of the box. The CLI path is the one to fix first
(Gap 1); MCP can follow.
- **Version drift cosmetic check:** daemon reports `2.1.0`; worth confirming that matches
`pubspec.yaml` so an agent keying off `clide version` isn't misled.
---
## Minimum to actually dogfool (priority order)
1. **Ship `clide` on PATH.** Build the C client by default; install it to a PATH dir on
macOS *and* Linux (targeting the C client, not the GUI binary). *(Gap 1 — blocker)*
2. **Bootstrap the agent.** Export `CLIDE_SOCK`/`CLIDE_WORKSPACE`, ensure PATH, inject a
context note + `Bash(clide *)` allow rule when clide hosts/launches an agent. *(Gap 2)*
3. **Make the live UI observable.** Register built-in panes/buffers into the CLI-visible
registries; add `clide status` for a one-shot snapshot. *(Gaps 3, 6)*
4. **Add pull-based events** (`clide events --since`). *(Gap 4)*
5. **Decide the agent model** in governance — hosted session vs external CLI driver vs
both. *(Gap 5)*
Items 12 are small and unblock everything. With just those, I can drive the IDE from
Bash today — I proved the daemon answers. Item 3 is what turns "I can issue commands" into
"we're actually working in the same workspace."
---
*Everything above was checked against a running clide, not inferred from docs. The pleasant
surprise is how little is actually broken: the hard part (a live, correct, single-process
IPC contract with proper exit codes) is done and working. What's missing is the last mile
that puts the tool in the agent's hands and lets the agent see the room.*