Skip to content

fluree-cli plugin: probe-first CLI companion with a manifest-checked contract - #1

Merged
aaj3f merged 2 commits into
mainfrom
feat/fluree-cli-plugin
Jul 30, 2026
Merged

fluree-cli plugin: probe-first CLI companion with a manifest-checked contract#1
aaj3f merged 2 commits into
mainfrom
feat/fluree-cli-plugin

Conversation

@aaj3f

@aaj3f aaj3f commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Why

Fluree AI already hands its users' AI assistants off to the fluree CLI (the Build-an-App prompt, the LLM-targeted served docs). This plugin is the Claude-Code-native half of that story: it packages the operating doctrine — how to drive the CLI safely — while deliberately refusing to carry command reference, which the binary itself serves version-exactly via its embedded docs. That division is what keeps the plugin from drifting: most CLI changes require zero plugin changes, and the few facts the plugin does hard-code are machine-validated in CI.

What

plugins/fluree-cli/:

  • Skill (auto-triggers on Fluree/terminal work): probe-first rule (check fluree docs / --help / the MCP docs tools before composing commands; a missing command usually means a feature-gated build), safety rails (destructive-op confirmation for drop/branch drop, .fluree/ token hygiene, auth token vs config list --reveal, explicit import budgets on shared machines, policy-correlation verification), machine-output map, and the Fluree AI remote choreography — including that fluree auth login blocks on the human approving a device code at the stack's /activate page. Deep material in references/ (workflows, remote-fluree-ai, policy, troubleshooting).
  • /fluree-cli:setup: binary check + install pointers, the ≥ 4.1.3 version gate, docs-access verification, duplicate-MCP-registration cleanup, .fluree/ gitignore hygiene.
  • .mcp.json: auto-connects fluree mcp serve --toolsets docs (the binary's embedded, version-exact documentation as docs_search/docs_get/docs_examples/docs_tree). Missing binary degrades gracefully.
  • contract/cli-facts.json + scripts/check-cli-contract.mjs: every command path and flag the plugin's text mentions, validated against the fluree-cli-manifest.json release asset that fluree/db now publishes (a JSON surface description generated from the CLI's own clap definitions, so it cannot drift from the binary).
  • CI (.github/workflows/ci.yml): claude plugin validate --strict over every plugin in the marketplace, a marketplace↔plugin version-sync check (both verified passing locally), and the contract check — which skips with a notice until the first fluree/db release ships the manifest asset, then should be made required.

Cross-repo pairing

  • CLI agent-surface truth + the manifest rail db#1571 (feat/cli-ai-surface): ships the hidden fluree manifest command + the fluree-cli-manifest.json release asset this repo's CI validates against, plus docs/ai/claude-code.md — the in-binary agent guide this skill defers to.
  • fluree/solo#893 (feat/cli-ai-surface): the platform half (its cli-snippets module rides the same manifest rail; its Build-an-App prompt and this plugin divide labor — prompt = per-stack bootstrap, plugin = durable procedure).

This PR is safe to land before either: the contract check self-skips until the manifest asset exists.

Validation

claude plugin validate --strict: ✔ both plugins and the marketplace root. check-version-sync.mjs: ✔ 2 plugins. Contract checker run against a locally built manifest from fluree/db#1571's branch: 42 commands OK — and its very first run caught a real error in my own draft (fluree list has no --json; the skill text shipped corrected), which is the rail doing its job.

Notes for reviewers

  • The skill's description is the auto-trigger surface — worth a critical read.
  • Naming (fluree-cli, hence /fluree-cli:setup) follows the settled decision to leave room for future platform-side plugins.
  • Follow-up once a fluree/db release ships the manifest: flip the CI contract step from skip-if-absent to required, and pin min_cli_version messaging if the release number differs from 4.1.3-era expectations.

…cked contract

New plugin teaching Claude Code to drive the fluree CLI:

- skill (auto-triggering): probe-first doctrine (the binary's embedded
  docs are the reference; the skill deliberately carries almost no
  command reference so it cannot rot), destructive-op + credential +
  import-budget safety rails, machine-output map, Fluree AI remote
  choreography (device-code login the human approves at /activate).
  references/: workflows, remote-fluree-ai, policy correlation,
  troubleshooting (server-routed vs --direct divergences).
- /fluree-cli:setup command: binary check/install pointers, >=4.1.3
  version gate, docs-access verification, duplicate-MCP cleanup,
  .fluree/ gitignore hygiene.
- .mcp.json: auto-connects 'fluree mcp serve --toolsets docs'
  (docs_search/get/examples/tree, version-exact; degrades gracefully
  when the binary is absent).
- contract/cli-facts.json: every command path/flag the plugin's text
  hard-codes, validated by scripts/check-cli-contract.mjs against the
  fluree-cli-manifest.json release asset (fluree/db#1571). Verified
  against a locally built manifest: 42 commands OK — and the checker's
  first run caught a real error (list has no --json), already fixed.
- CI: claude plugin validate --strict on every plugin, marketplace<->
  plugin version-sync check, and the contract check (skips with a
  notice until the first fluree/db release ships the manifest asset).

Marketplace entry + README row included.
aaj3f added a commit that referenced this pull request Jul 30, 2026
Response to independent review of #1; every finding verified before
fixing. The three text blockers were all real against v4.1.4, the
latest installable release:

- SKILL.md credential rail was INVERTED: it said config list redacts on
  'current versions' when redaction ships only in the first release
  after fluree/db#1571 — an agent on 4.1.4 would have blessed a command
  that dumps auth.token AND refresh_token in plaintext. Rewritten to be
  safe on binaries that exist: treat config list output as secret
  through v4.1.4; verify --reveal exists before assuming redaction.
- workflows.md taught 'branch diff main dev', which does not parse
  (one positional + --target, defaulting to the source's parent).
- The 'start here' pointer to docs get ai/claude-code is now hedged the
  same way the manifest pointer already was (page ships after #1571),
  and 'supersedes' narrowed to command-surface authority.

Floor moves to 4.1.4 in lockstep with the paired solo review (auth
token does not exist at 4.1.3) — SKILL, setup, README, cli-facts.

CI honesty (the job could report green while running nothing):
- 404 is the only skip; every other curl outcome is now ::error + fail.
  The skip is a ::warning with an owner and expiry (issue #2 filed).
- Marketplace root now validated (the per-plugin loop never saw it);
  claude-code npm install pinned (2.1.220); .mcp.json syntax-checked in
  CI (validate --strict provably ignores it) and its nonstandard
  description key dropped.

Checker soundness:
- exit 2 (not a stack trace masquerading as 'contract violated') for
  unreadable/malformed inputs; commands-array guard; version fallback.
- min_cli_version is now load-bearing: the checker fails when the
  manifest is older than the contract's floor. manifest_source is now
  read by CI (single source of truth for the URL).
- hidden entries assert ABSENCE from the manifest (catches a
  hidden->visible promotion of ); checked-count counts
  checked commands, not list length.

Contract covers the prose it missed: query --at/--policy-class, --json
on the four docs subcommands, bare model, branch diff --target/--json,
branch revert --json.

New: the inbound-MCP section WS-4 asked for (claude mcp add --transport
http against a Space's /v1/mcp?space=<id> — the Data Admin tab documents
Claude Desktop only); README states the two intentional doctrine-mirror
relationships and what wins where; honest failed-server description for
a missing binary; .DS_Store untracked + .gitignore added; homepage in
plugin.json; skill trigger scoped to terminal contexts + SDK-only
check in the body.

Declined with reason (recorded in the response doc): flag-VALUE
validation — mcp init's --ide/--toolsets and query --format expose no
possible_values in the manifest today (plain strings), so the mechanism
would be vacuous; riding the 'convert --format flags to value enums'
follow-up in fluree/db instead.
Response to independent review of #1; every finding verified before
fixing. The three text blockers were all real against v4.1.4, the
latest installable release:

- SKILL.md credential rail was INVERTED: it said config list redacts on
  'current versions' when redaction ships only in the first release
  after fluree/db#1571 — an agent on 4.1.4 would have blessed a command
  that dumps auth.token AND refresh_token in plaintext. Rewritten to be
  safe on binaries that exist: treat config list output as secret
  through v4.1.4; verify --reveal exists before assuming redaction.
- workflows.md taught 'branch diff main dev', which does not parse
  (one positional + --target, defaulting to the source's parent).
- The 'start here' pointer to docs get ai/claude-code is now hedged the
  same way the manifest pointer already was (page ships after #1571),
  and 'supersedes' narrowed to command-surface authority.

Floor moves to 4.1.4 in lockstep with the paired solo review (auth
token does not exist at 4.1.3) — SKILL, setup, README, cli-facts.

CI honesty (the job could report green while running nothing):
- 404 is the only skip; every other curl outcome is now ::error + fail.
  The skip is a ::warning with an owner and expiry (issue #2 filed).
- Marketplace root now validated (the per-plugin loop never saw it);
  claude-code npm install pinned (2.1.220); .mcp.json syntax-checked in
  CI (validate --strict provably ignores it) and its nonstandard
  description key dropped.

Checker soundness:
- exit 2 (not a stack trace masquerading as 'contract violated') for
  unreadable/malformed inputs; commands-array guard; version fallback.
- min_cli_version is now load-bearing: the checker fails when the
  manifest is older than the contract's floor. manifest_source is now
  read by CI (single source of truth for the URL).
- hidden entries assert ABSENCE from the manifest (catches a
  hidden->visible promotion of 'fluree manifest'); checked-count counts
  checked commands, not list length.

Contract covers the prose it missed: query --at/--policy-class, --json
on the four docs subcommands, bare model, branch diff --target/--json,
branch revert --json.

New: the inbound-MCP section WS-4 asked for (claude mcp add --transport
http against a Space's /v1/mcp?space=<id> — the Data Admin tab documents
Claude Desktop only); README states the two intentional doctrine-mirror
relationships and what wins where; honest failed-server description for
a missing binary; .DS_Store untracked + .gitignore added; homepage in
plugin.json; skill trigger scoped to terminal contexts + SDK-only
check in the body.

Declined with reason (recorded in the response doc): flag-VALUE
validation — mcp init's --ide/--toolsets and query --format expose no
possible_values in the manifest today (plain strings), so the mechanism
would be vacuous; riding the 'convert --format flags to value enums'
follow-up in fluree/db instead.
@aaj3f
aaj3f force-pushed the feat/fluree-cli-plugin branch from 74d2119 to be22d19 Compare July 30, 2026 21:31
@aaj3f
aaj3f merged commit a8c3a77 into main Jul 30, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant