Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2350e2b
docs: design read-only IDE snapshot protocol
wellwei Aug 5, 2026
9933126
docs: plan read-only IDE snapshot implementation
wellwei Aug 5, 2026
210a31b
feat(ide): define snapshot protocol model
wellwei Aug 5, 2026
3885a63
fix(ide): align snapshot fixture contract
wellwei Aug 5, 2026
9759acf
feat(ide): inspect workspaces without side effects
wellwei Aug 5, 2026
1ad07f9
fix(ide): restrict workspace package selector aliases
wellwei Aug 5, 2026
5336e9f
fix(ide): harden workspace inspection paths
wellwei Aug 5, 2026
68e1bbb
fix(ide): contain workspace inspection paths
wellwei Aug 6, 2026
1b6b6a1
feat(ide): serialize versioned workspace snapshots
wellwei Aug 6, 2026
4e99879
feat(cli): add read-only ide snapshot command
wellwei Aug 6, 2026
fee82fe
test(ide): prove snapshot is read only
wellwei Aug 6, 2026
c58bdf4
docs(ide): define universal project model and early CDB plan
wellwei Aug 6, 2026
e8dbd2c
feat(ide): define configuration and event protocol
wellwei Aug 6, 2026
0c9c2e4
feat(build): add fresh compile database publication
wellwei Aug 6, 2026
54faf3e
feat(ide): publish compile database before build
wellwei Aug 6, 2026
1e8f1f4
fix(ide): stage module prerequisites before publishing cdb
wellwei Aug 6, 2026
67587e3
test(ide): gate llvm configure e2e and track release version
wellwei Aug 6, 2026
18f41e8
docs(ide): record configure validation boundaries
wellwei Aug 6, 2026
b2d092b
fix(ide): keep configure events machine-readable
wellwei Aug 7, 2026
9ae6d9f
fix(ide): make configure publication portable
wellwei Aug 7, 2026
458c1a0
chore(release): bootstrap pin -> 2026.8.6.3
wellwei Aug 7, 2026
bd3843d
fix(ide): harden configured snapshot publication
wellwei Aug 7, 2026
50daf50
fix(test): preserve best-effort test inventory
wellwei Aug 7, 2026
10c8142
fix(ide): distinguish publication lock failures
wellwei Aug 7, 2026
0e519e0
docs(ide): document protocol and client lifecycle
wellwei Aug 7, 2026
07bbc16
docs(ide): clarify client trust and protocol limits
wellwei Aug 7, 2026
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
2 changes: 1 addition & 1 deletion .xlings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"workspace": {
"mcpp": "2026.8.6.2"
"mcpp": "2026.8.6.3"
}
}
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ import mcpplibs.cmdline;
- Fingerprinted BMI cache: hashed by compiler/flags/standard library, shared across projects
- Ninja backend: auto-generated build.ninja, parallel compilation
- compile_commands.json generated automatically (ready for clangd / ccls)
- `mcpp ide configure` publishes a fresh CDB for ordinary and `tests/**/*.cpp`
translation units (including test dev-dependency flags) before compilation,
and persists the configured snapshot
so clangd can analyze a project whose source currently has build errors
- First-class C support: `.c` files auto-detected, mixed C/C++ projects
- User-defined cflags / cxxflags / ldflags / c_standard

Expand Down
268 changes: 268 additions & 0 deletions docs/11-ide-protocol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
# 11 - IDE Protocol

This document describes the IDE protocol implemented by the current `mcpp`
binary. It is intended for IDE integrations, language-tool launchers and other
machine clients. The protocol is separate from the human-oriented CLI output;
clients must request and parse the documented format instead of scraping
progress text.

## 1. Scope and compatibility

The public commands are:

```text
mcpp ide snapshot [selectors]
mcpp ide configure [selectors]
```

Both commands currently use schema version `1`. For a snapshot response, clients
should check `schemaVersion`, `kind` and the `mcpp.protocol` range; for configure
events, clients should validate `schemaVersion`, `type`, `seq` and
`operationId`. Unknown fields must be ignored. `events`, `model`, `inspect` and
`publish` are internal C++ modules, not public CLI subcommands. The future `prepare`,
configuration index, cancellation and progress protocol are not implemented.

The project root is found by searching upward from the current directory for
`mcpp.toml`; the commands do not currently accept a project path argument.

## 2. Selectors

Both commands accept the following options:

| Option | Meaning |
| --- | --- |
| `-p, --package MEMBER` | Select one member by workspace-relative path or directory basename. |
| `--workspace` | `snapshot`: inspect every member. `configure`: currently rejected. |
| `--profile NAME` | Request a build profile. |
| `--target TRIPLE` | Request a target triple. |
| `--features LIST` | Comma-separated feature selectors. |
| `--cap LIST` | Comma-separated capability-provider pins. |
| `--include-dev-dependencies` | Include development dependencies explicitly. |
| `--format FORMAT` | `snapshot` accepts `json`; `configure` accepts `ndjson`. |

CSV selectors discard empty items but do not trim whitespace. There is no
`--offline` selector in this protocol.

When `configure` discovers `tests/**/*.cpp`, it automatically enables
development dependencies even without `--include-dev-dependencies`. This makes
test translation units use the same include paths and defines as a real test
build.

## 3. Read-only snapshot

`mcpp ide snapshot` defaults to `--format json` and does not resolve
dependencies, write project files or publish a CDB. A valid inspection exits `0` for
`partial`, `stale` or `configured`; an unavailable inspection exits `3`.

The top-level shape is:

```json
{
"schemaVersion": 1,
"kind": "mcpp.ide.snapshot",
"snapshotId": "fnv1a64:...",
"state": "partial",
"mcpp": {
"version": "2026.8.7.1",
"protocol": {"min": 1, "max": 1},
"capabilities": [
"workspace-inspection",
"manifest-diagnostics",
"compile-commands-location"
]
},
"request": {"root": ".", "mode": "read-only", "selectors": {}},
"workspace": {"root": ".", "manifest": "...", "members": [], "selectedMembers": []},
"artifacts": {"state": "partial", "compileCommands": []},
"diagnostics": []
}
```

`workspace.members[]` describes each parsed package with `name`, `version`,
`workspacePath`, `root`, `manifest` and `targets[]`. A target contains `name`,
`kind` (`library`, `shared-library`, `binary` or `test-binary`) and, when
available, `main`.

Each `artifacts.compileCommands[]` entry contains `member`, `path`, `state`
(`missing`, `configured` or `stale`) and optional `snapshotId` and
`configurationId` values.

The inspection state is aggregated as follows:

```text
missing artifacts -> partial
unverified regular root CDB -> stale
valid configured metadata and an existing regular-file reply CDB -> configured
```

`ready` is reserved for a future artifact-prepared state and is not currently
produced.

Diagnostics contain `code`, `severity`, `message`, `source: "mcpp"`, and may
include `path` and a one-based `range` with `line` and `column` positions.
Known codes include `MCPP_IDE_MANIFEST_NOT_FOUND`,
`MCPP_IDE_MANIFEST_INVALID`, `MCPP_IDE_MEMBER_MANIFEST_MISSING`,
`MCPP_IDE_MEMBER_MANIFEST_INVALID`, `MCPP_IDE_WORKSPACE_MEMBER_NOT_FOUND`,
`MCPP_IDE_ARTIFACTS_MISSING`, `MCPP_IDE_ARTIFACTS_UNVERIFIED`,
`MCPP_IDE_ARTIFACTS_UNAVAILABLE`, `MCPP_IDE_SNAPSHOT_INVALID`,
`MCPP_IDE_SNAPSHOT_STALE` and `MCPP_IDE_UNSUPPORTED_FORMAT`.

The snapshot inspection checks metadata, project-root containment and whether
the CDB path is still a regular file. It does not open or parse the CDB, nor
recompute the manifest, lockfile, source set, selectors or toolchain
fingerprint. Therefore `configured` only means that the last published metadata
still points to an existing regular file. Clients may validate the JSON before
handing it to a language server and should run `configure` after inputs change.

## 4. Configure and NDJSON events

`mcpp ide configure` defaults to `--format ndjson`. Every stdout line is one
JSON object. A successful invocation emits, in order:

```text
operation-started
snapshot-published
operation-finished (success)
```

A failed invocation emits:

```text
operation-started
diagnostic
operation-finished (failed)
```

All events have a common envelope:

```json
{
"schemaVersion": 1,
"seq": 2,
"type": "snapshot-published",
"operationId": "operation-fnv1a64:..."
}
```

`seq` starts at `1` and increases strictly. All events for one invocation use
the same `operationId`.

The `operation-started` event identifies `operation: "configure"`. The
`snapshot-published` event includes `phase`, `state`, `projectId`,
`configurationId`, `snapshotId`, the content-addressed `compileCommands` path,
the compatibility CDB path, `compileCommandCount`, `toolchain` and
`toolchainFingerprint`. It may include:

```json
"stdModule": {
"kind": "std-module",
"path": "...",
"state": "ready"
}
```

The successful `operation-finished` event includes `status: "success"`,
`operation`, `phase` and `configurationId`. A failure has a diagnostic event
with code `MCPP_IDE_CONFIGURE_FAILED`, followed by a finished event with
`status: "failed"` and `diagnosticCodes`.

Configure returns `0` after publication, `2` for a format error (before the
operation starts), and `3` for manifest, resolution, selector, tool, staging,
publication or unexpected failures. Cancellation, timeout and exit code `130`
are not protocol features yet.

## 5. IDs and published files

The IDs have different scopes:

- `projectId` identifies the physical workspace root.
- `configurationId` identifies normalized selectors, resolved profile/target,
cache mode, language standard and toolchain fingerprint.
- `snapshotId` identifies the configured CDB publication and its provenance.
The read-only snapshot's top-level `fnv1a64:*` is an inspection document ID;
it is not the same ID type as the configured `snapshot-*` value.

After a successful configure, the relevant files are:

```text
<project>/.mcpp/ide/replies/compile_commands-<hash>.json
<project>/.mcpp/ide/replies/snapshot-<hash>.json
<project>/.mcpp/ide/current.json
<project>/compile_commands.json
<project>/.mcpp/ide/.lock
```

The reply CDB is the protocol source of truth. The root CDB is a compatibility
projection for existing clangd clients. `current.json` records
`schemaVersion`, `kind: "mcpp.ide.configured-snapshot"`, phase, IDs, project
root, both CDB paths, command count and toolchain identity.

Each individual JSON file is written through a temporary file and replacement.
The root CDB and `current.json` are separate replacement points, not one
cross-file operating-system transaction. Normal publication errors attempt to
restore the previous root CDB; a process crash between the two replacements can
still leave a new CDB alongside old metadata.

## 6. What configure does

Configure resolves the project and produces a CDB from the resolved `BuildPlan`
and compile flags. It does not compile ordinary project translation units or
link the final executable. It is not read-only: resolution can install
dependencies or toolchains, execute root-project and dependency `build.mcpp`
code, update `mcpp.lock`, write target resolution metadata, create or update
caches, discover tests, and stage standard-library or cached dependency BMIs.
An IDE must obtain workspace trust or equivalent explicit permission before it
runs configure for an untrusted project. Read-only discovery should use
`snapshot` instead.

The CDB includes ordinary sources and discovered test sources. Cached module
prerequisites are staged before the CDB is published. Uncached project or
dependency module BMIs are not fully built by this command, so module completion
may remain pending until a normal build or a future prepare command. Staging a
GCC `.gcm` or MSVC `.ifc` file does not promise that clangd can consume that
toolchain's module format.

`mcpp ide configure --workspace` is currently rejected. Select one member with
`--package` and run configure separately for each member.

## 7. Client lifecycle

The following behavior belongs in the IDE client and does not require another
mcpp protocol command:

1. Run `snapshot --format json` to discover members and existing artifacts.
2. For a workspace, use `workspace.members[].workspacePath` and run one
`configure --package <workspacePath>` operation per member. Do not pass
`--workspace` to configure. Serialize operations per member, or use bounded
concurrency across independent members.
3. Reconfigure after the root/member `mcpp.toml`, `mcpp.lock`, `build.mcpp`,
source-set/module declarations, selected profile/target/features/capabilities
or toolchain selection changes. Debounce file events and reconfigure after an
mcpp dependency or toolchain command completes. Do not immediately retrigger
on `mcpp.lock`, target metadata or cache events produced by the configure
operation that is already in progress. A plain source-content edit that does
not change the source set or module graph does not require a new CDB.
4. Validate `seq`, correlate events by `operationId`, and ignore events from a
superseded operation. The protocol has no cancellation yet, so the client
should not start overlapping configure operations for the same member.
5. Treat `snapshot-published` as the publication boundary. The reply CDB is the
protocol source of truth; a language server that requires a literal
`compile_commands.json` may use `compatibilityCompileCommands`, but only after
that event from the same operation. On startup or recovery, rerun configure
instead of trusting a root CDB merely because it exists.
6. If configure fails, keep the previous usable clangd configuration, surface
the structured diagnostic and mark it stale. Version 1 reports configure
failures under the generic `MCPP_IDE_CONFIGURE_FAILED` code; clients must not
parse the human message to infer lock contention or I/O categories. Serialize
operations per member and expose a user-initiated retry for other failures.
7. Do not interpret `configured` as full module readiness. Start clangd for the
available TUs, show module support as pending when required BMIs are absent,
and offer a normal `mcpp build` (or `mcpp test` for test-only preparation) when
the user requests complete module semantics. Reconfigure after that command
finishes. Do not start a full build silently during workspace discovery.
8. Keep stdout reserved for the requested JSON protocol. Human diagnostics may
appear on stderr; clients should not parse them as events.

The protocol is intentionally one-shot today. Daemon mode, cancellation,
workspace fan-out, active freshness recomputation, a ready artifact snapshot and
last-known-good indexes remain future extensions.
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- [08 - Toolchain Internals](08-toolchain-internals.md)
- [09 - Releasing mcpp](09-release.md)
- [10 - Publishing a Library to mcpp-index](10-publishing-a-library.md)
- [11 - IDE Protocol](11-ide-protocol.md)

## Specifications

Expand Down
Loading
Loading