Files
clide/docs/self-analysis.md
T
Jeroen SchweitzerandClaude Opus 4.8 fa1e71d175 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>
2026-06-03 09:31:54 +02:00

241 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.*