Claude Code and the Fluree CLI
How an AI coding agent — Claude Code in particular, but the pattern generalizes — should drive the fluree CLI. This page ships inside the binary (fluree docs get ai/claude-code), so what it says is true for the exact version you are running; agent-side packaging (the fluree-cli Claude Code plugin, a stack’s generated build prompt) deliberately defers to it rather than copying it.
Setup
Register the CLI’s MCP server with your agent:
fluree mcp init --ide claude-code # or cursor / vscode / windsurf / zed
This wires fluree mcp serve with the docs toolset (ranked search over this documentation, version-exact) and the memory toolset (persistent project memory). Use --toolsets docs to skip memory. Without MCP, the same corpus is available as plain commands: fluree docs search, fluree docs get, fluree docs examples, fluree docs tree.
The fluree-cli plugin in fluree/claude-plugins registers the docs MCP server (--toolsets docs — no memory toolset; run fluree mcp init yourself if you want that too) and adds skills for driving the CLI, which defer to this page rather than restating it. The same marketplace carries fluree-companion for stack-first workflows — connecting to a Fluree AI stack, authenticating against it, and working through the stack’s own surfaces.
Probe, don’t assume
The CLI’s surface varies by version and by compiled features — and an agent’s trained knowledge of it is always stale. Before composing a nontrivial invocation:
- Check the docs or
--helpfirst.fluree docs search "<topic>"/fluree <cmd> --helpare authoritative for the running binary. - A missing command usually means a feature-gated build, not a typo.
validate(SHACL) andcluster(server) vanish entirely from--helpin builds without their features. The hiddenfluree manifestcommand emits a machine-readable JSON of the full surface, including afeaturesarray that distinguishes “not compiled in” from “does not exist”. - Check the version when a server is involved.
fluree --version; a stack that advertisescli.min_versionin its/.well-known/fluree.jsontriggers a warning atfluree remote addwhen your binary is older than what its docs teach (governancefluree modelcommands exist only in 4.1.3+).
Machine-readable output
Support is per-command, not global:
queryandmulti-querytake--format json(plus CSV/TSV/NDJSON variants);query --format ndjson --envelopeadds a self-describing head/rows/end wrapper (--envelopepairs with ndjson only).graph list,branch diff,branch revert --preview, and the fourdocssubcommands take boolean--json.list,info, andshoware human-formatted only (as of 4.1.x).- Errors are human text; the only machine signal is the exit code (
0ok,1error,2usage). Parse stderr only as a last resort.
Working against a remote (Fluree Solo / Fluree AI stacks)
--remote <name>takes a configured alias, never a URL. Set one up withfluree remote add <name> <url>; the compound positionalname/ledgerform is equivalent on data commands.- Passing the stack’s API base (
https://<stack>/v1/fluree) as<url>is robust: discovery of/.well-known/fluree.jsonignores the input path, and if discovery is unreachable an input already ending in/flureeis stored as-is. fluree auth loginneeds the human. It prints a device code and opens the stack’s/activatepage — the user approves it in their browser while the CLI polls. Run the command, then tell the user to approve; continue only afterfluree auth statusshows a configured token. There are no environment-variable credentials.- Scripting a token:
fluree auth tokenprints exactly the access token (for.envfiles,curl).fluree config listmasks credentials as[redacted];--revealprints them raw and its output must never be pasted into logs, commits, or chat. .fluree/contains the remote config including live access and refresh tokens — it must be gitignored in any project where an agent runsfluree init.- The stack documents itself, separately from this corpus. A Fluree AI stack serves an unauthenticated markdown index at
https://<stack>/api/docs, with each page at/api/docs/{category}/{slug}. Those pages describe the stack — its UI, its HTTP surface, its provisioning; this corpus describes the binary. A task that spans both needs both.
Destructive operations — confirm with the user first
fluree drop --forceis a hard delete (storage removed, not recoverable), andfluree branch drophas no confirmation flag at all — on a leaf branch it permanently deletes storage and cascades into retracted ancestors.mainhas no special protection. Name the exact target and get explicit user confirmation before running either.- Never drop and recreate a ledger underneath a running server — the server keeps stale index pointers and fails partially (some queries work, others 404 on leaf files). Stop the server first.
Resource limits on shared machines
--memory-budget-mb 0 (the default) auto-sizes to 80% of system RAM and assumes it owns the box; a large create --from import on a machine also running an IDE, Docker, or a browser can OOM the machine. On anything but a dedicated host, pass an explicit budget and modest --parallelism (2–4). Note FLUREE_IMPORT_THREADS silently overrides --parallelism.
Policy work
Author policy as a single where (object, or array of patterns correlated by shared variables) that constrains ?$this; unknown keys in f:query are silently ignored, and a policy whose where never touches ?$this matches everything — silently allowing what it was meant to restrict. Verify with --track-policy on direct/local execution (its allowed/evaluated counts expose an uncorrelated policy immediately); server-routed --track-policy is unreliable. See the policy cookbook.
Query hygiene for agents
- Prefer
--explainto inspect a plan without executing. --attime travel on server-routed queries injects aFROMclause by scanning for the literalwheresubstring — keepWHEREon the same line asSELECT, and never combine--atwith an explicitFROM.- Auto-routing silently targets a detected local server (a stderr notice is the only sign);
--directforces local execution when behavior differs.