Skip to content

feat(cli): point top-level cli --help at --format json - #2140

Merged
DeusData merged 2 commits into
DeusData:mainfrom
Lowpower:cursor/cli-help-format-json-cb65
Sep 23, 2026
Merged

DeusData merged 2 commits into
DeusData:mainfrom
Lowpower:cursor/cli-help-format-json-cb65

Conversation

@Lowpower

Copy link
Copy Markdown
Contributor

What does this PR do?

Help-only discoverability fix for #2102 (direction c only).

Top-level cli --help already described outer --json (the raw MCP result envelope) but did not mention that tools which accept format support --format tree|json. Habitual CLI users look at cli --help first; per-tool --help already documented --format.

This PR adds two lines to CLI_USAGE:

  • Tools that accept format support --format tree|json (default: tree).
  • --format json prints payload JSON; outer --json prints the full MCP envelope.

No session-wide --format flag, no CBM_CLI_FORMAT env var, and no change to output defaults.

CBM_CLI_USAGE lives in src/cli/cli.h so tests/test_cli.c can assert on the same string run_cli() prints.

Checklist

  • Every commit is signed off (git commit -s) — required, CI rejects unsigned commits
  • CLI suite passes locally (scripts/test.sh --suites cli — including cli_usage_points_to_tool_format_json_issue2102)
  • New behavior is covered by a test

Fixes #2102

@Lowpower
Lowpower requested a review from DeusData as a code owner September 10, 2026 03:22
@github-actions

Copy link
Copy Markdown

Thanks for opening this — it has been seen, and it is queued.

This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence.

Current review status: working through a backlog. 0.9.1-rc.1 is out, so the release freeze that held reviews is over — but it left a large queue of open pull requests behind it, and we are reading through them oldest-first. The background is in discussion #1144.

What that means for this PR, concretely:

  • It will not be closed for inactivity. No stale bot touches pull requests here.
  • It may still sit a while before a human reads it. That is on us, not on you.
  • Older PRs are read first, so a recent one is not being skipped — it is behind a queue.

Things that will genuinely speed it up whenever review does happen:

  • Keep it rebased on main — the tree is moving quickly right now, and a conflicting branch cannot be reviewed as the diff you intended.
  • Get CI green, or say which failures you believe are pre-existing.
  • Keep the change to one claim. Bundled features and refactors get split before they get merged, which costs you a round trip.
  • Every commit needs a sign-off (git commit -s) — CI enforces DCO.

If this fixes a bug, a reproduction we can run is worth more than a description of the symptom.

Thanks for contributing, and sorry in advance for the wait.

@Lowpower
Lowpower force-pushed the cursor/cli-help-format-json-cb65 branch from a1d11e7 to b74c035 Compare September 17, 2026 05:40
@cursor
cursor Bot force-pushed the cursor/cli-help-format-json-cb65 branch from b52df4b to ca34611 Compare September 18, 2026 03:30
@DeusData DeusData added documentation Improvements or additions to documentation ux/behavior Display bugs, docs, adoption UX priority/normal Standard review queue; useful PR with ordinary maintainer urgency. labels Sep 19, 2026
@DeusData

Copy link
Copy Markdown
Owner

Thank you for improving top-level help. The current diff also changes a daemon timeout test and retries the search_code JSON check, which are independent of help discoverability. Please separate those changes and keep this PR to the help text plus a deterministic help regression. The outer CLI already has a JSON-format path; the test should establish the advertised help contract without retrying another operation.

CLI_USAGE described outer --json but did not mention tool-level
--format json. Add a help-only pointer that tools which accept format
support --format tree|json, and distinguish payload JSON from the full
MCP envelope. No new flags, env vars, or output-default changes.

Fixes DeusData#2102

Signed-off-by: Lowpower <3133734+Lowpower@users.noreply.github.com>
Signed-off-by: Lowpower <3133734+Lowpower@users.noreply.github.com>
@cursor
cursor Bot force-pushed the cursor/cli-help-format-json-cb65 branch from fca3371 to 2f557f5 Compare September 21, 2026 23:48
@DeusData

Copy link
Copy Markdown
Owner

A quick request, because it is costing you time rather than saving it: please do not rebase onto main again until this is merged. Your previous head was one CI job from green — everything else had passed and the merge was queued on my side — and the rebase to 28b4093c discarded that run and started a full matrix from zero, which takes about two hours on tonight's runner pool. The content is identical (same two commits), so nothing was gained.

main will keep moving tonight; that does not matter for this PR. The merge result is already verified locally against the current main (cli 320, linter unchanged, and the test does not compile without the production change). As soon as this run is green it merges. Nothing else is needed from you.

@DeusData
DeusData merged commit 95c91b8 into DeusData:main Sep 23, 2026
39 checks passed
@DeusData

Copy link
Copy Markdown
Owner

Merged — thank you @Lowpower, and thank you for splitting it exactly as asked: the PR is now the help text, one macro in cli.h, and a deterministic test that pins the wording, including that the synopsis still has no session-wide --format.

Verified on the merge result with the current main (e783f73d): cli 320 passed, the memory-core linter is unchanged, and with the production change reverted the test does not even compile (CBM_CLI_USAGE undeclared) — the strongest binding a test can have. The reds you saw on earlier runs were ours, not yours: a timing-sensitive MSan test that #2272 fixes, and a Windows cold-start race that #2275 fixes.

Small, and it removes a real point of confusion between --json and --format json.

timothybrush pushed a commit to timothybrush/codebase-memory-mcp that referenced this pull request Sep 24, 2026
…ure on Windows

Several processes first-starting together against a runtime directory
that does not exist yet -- test-windows-guards' section_cold_storm, or a
host that launches more than one MCP server on its very first run -- all
observe the final path component absent. One CreateDirectoryW wins; the
others get ERROR_ALREADY_EXISTS. win_private_directory_tree_secure()
treated that as a failure and recorded no validation detail, so every
loser exited with a bare

    secure CLI coordination could not be created (endpoint)

The function called right after the walk, win_runtime_directory_secure(),
has always tolerated ERROR_ALREADY_EXISTS for the same directory, and the
POSIX walk tolerates EEXIST at the same point; only the Windows walk in
front of them did not.

Seen four times on 2026-09-21 on unrelated PRs (DeusData#1768 three attempts in
a row, DeusData#2140, DeusData#1999, DeusData#808). The racy lines date from July; the guard
began exercising them on 2026-09-03, when each guard section was given
its own empty CBM_RUNTIME_DIR, so the final component is now absent at
storm time on every run.

The walk now treats ERROR_ALREADY_EXISTS from its own CreateDirectoryW as
"the directory I wanted exists". Nothing is trusted because of that: an
ancestor still goes through win_directory_component_secure(), and the
final component through win_runtime_directory_secure(), which refuses a
non-directory or reparse point and enforces owner and DACL.

Every refusal on this path now names its component and its rule. The
walk reports the Windows error when it can neither create nor inspect a
component, and win_runtime_directory_secure() says whether the path
could not be created, cannot be inspected, exists but is not a directory,
or is a reparse point. One helper owns the wide-to-UTF-8 conversion for
these messages and the existing ancestor message now uses it too, so
src/daemon/ipc.c stays at its memory-core baseline.

Deterministic reproduction, no threads and no timing: a test seam fires
in the walk between "component observed absent" and CreateDirectoryW,
and the test plays the process that wins the creation.

  daemon_ipc_windows_private_directory_survives_lost_creation_race
  daemon_ipc_windows_private_directory_refuses_and_names_a_planted_file

Verification. macOS arm64 (ASan+UBSan): build clean, daemon_ipc 53 passed
(2 Windows-only skips), daemon_bootstrap 28 passed, lint-memory-core
unchanged (ipc.c stays at 146 raw sites). The two new tests are Windows-only
and have NOT been run locally: the Windows VM was down when this was written,
so the RED run on the seam-only tree and the GREEN run with this fix are
delegated to CI's windows-latest legs (test-windows shards, test-windows-guards)
by an explicit maintainer decision. If the guard suite's cold storm still
fails with this in place, the attribution above is wrong and this reverts.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
DeusData added a commit to htarnacki/codebase-memory-mcp that referenced this pull request Sep 25, 2026
… its verdict

daemon_bootstrap_fails_fast_when_daemon_dies_at_publication went red on
the MSan lane of three PRs that touch no daemon code at all (DeusData#2245,
DeusData#2158, DeusData#2140) with

    tests/test_daemon_bootstrap.c:1116: ASSERT(daemon_named_cause)

and green on a rerun of the identical commit.

Cause, attributed 2026-09-20. The test forks a real daemon host whose
record publication fails with ENOSPC, and asserts that the client names
that cause instead of waiting out its 30 s startup deadline. But before
it listens, the host SHA-256s its own executable image, and the test
runner is ~450 MB: ~3 s natively, 20-32 s under MSan (48 CI samples,
median 25.8 s). The spawn override returned as soon as it had forked, so
the client's 30 s clock raced the host's hash. On a slow run the
deadline fired first, the reaper SIGKILLed a host that had not failed
yet, and the log had no listen_failed line to find. Nothing was wrong
with the product: with a 28 s artificial delay the client does learn the
recorded ENOSPC cause.

The spawn override now reaps the forked host before it returns. The
host writes its start-failure record and only then releases its lifetime
reservation and exits, so "record on disk, reservation released" is a
stable state pinned by construction when the client takes its first look
-- and that first look is guaranteed: the client's post-spawn wait loop
runs at least once even past the deadline, and its first failure check
after a spawn is unthrottled. How long the host takes no longer matters.
No production code changes; the assertions are unchanged.

A regression to the pre-DeusData#1828 behaviour (a client that ignores the
record) still fails the unchanged assertions: its message no longer
names the failure, the errno and the path.

Proof, one build with temporary env-switched instrumentation that is
not part of this commit (a sleep in the forked host before it starts,
and a switch back to the old fire-and-forget spawn):

  spawn          forked host delayed   daemon_bootstrap suite
  synchronous    no                    28 passed
  old (async)    31 s                  27 passed, 1 failed:
                                       ASSERT(log_read)
  synchronous    31 s                  28 passed

The old spawn fails under the delay one assertion earlier than CI did
(log_read, not daemon_named_cause): the injected sleep sits before the
host opens its log, whereas in CI the host was killed mid-hash with the
log already open. Same mechanism -- the client's deadline beating the
host -- and the 2026-09-20 attribution reproduced the CI message itself
with a delay placed after the log is opened.

The final tree, without the instrumentation: daemon_bootstrap 28 passed,
three runs in a row.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation priority/normal Standard review queue; useful PR with ordinary maintainer urgency. ux/behavior Display bugs, docs, adoption UX

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(cli): top-level --format / CBM_CLI_FORMAT default for tools (follow-up from #1867)

2 participants