CLI Surface
retectl and flor command reference for C0
CLI Surface
Two binaries, split by audience:
retectl— operator workstation only. Authors rete state: CA operations, validation, compilation, bundle issuance. Never touches a running agent and never ships to a node.flor— every node. The daemon plus the node-local user CLI: enrollment, apply, status. One binary serves end users, server admins, and the system service.
This matches the author-vs-participant split used by kubectl/kubelet, terraform/agent, and similar tooling — and the names mirror the layer each acts on: retectl administers the rete (the trust domain — not any single flor, and not one Coordinator), while flor is the node agent, exactly as kubectl administers the cluster and kubelet runs on the node. The -ctl suffix names the thing controlled (the rete), which is why it is not florctl: the tool never controls a flor, it authors rete state. An end user installing Florete on their laptop gets flor with a small, focused command set; operators additionally install retectl on their own machine for rete-authoring work.
retectl (operator, authoring)
retectl ca init --out <dir> # once per rete: generate CA keypair + ca.crt
retectl ca sign <csr> --name <name>
--kind <user|service|node|management-plane|control-plane|vertex>
[--scope rete|node]
# sign a CSR; append to enrollment.log.
# All six kinds are recognised from day one;
# `vertex` and `control-plane` aren't exercised
# at runtime in C0 (see ADR-0005).
# `management-plane` is how the rete's
# mgmt-envelope signer is minted in C0 — e.g.
# retectl ca sign --kind management-plane \
# --name primary
# produces the keypair `retectl publish` signs with.
retectl issue-bundle --node <node-name> --rete <config-server-url>
[--csr <csr-bundle>] [--validity <duration>] [--out <bundle>]
# per-node enrollment bundle: CA cert, node
# identity, and every workload identity
# (users/services) declared in YAML to run
# on this node, plus config-server bootstrap.
# Flow B: consume `flor id create` CSR bundle.
retectl validate [--repo <dir>] [-f <file|glob>…]
# schema + cross-ref + access consistency
retectl compile [--node <name>] [--repo <dir>] [--out <dir>] [-f <file|glob>…]
# compile all nodes (or one); write to
# <repo>/.flor/compiled/ by default
retectl publish [--repo <dir>] [--target <config-server-url>]
# push compiled artifacts to the rete
# config-server (see Config-server)Notes:
- Source discovery.
validate/compilerequirerete.yamlat the--reporoot; if it is missing or nested elsewhere, discovery cannot start and a command fails. Then recursively glob*.yaml/*.ymlunder--repo(skipping.flor/,certs/, dotfiles; honoringinclude/excludeinrete.yaml), then merge same-kind collections into one whole-view before compiling. File layout is operator-chosen — see Source Layout.-f <file|glob>…(repeatable) overrides discovery for partial or CI runs; when used, at least one selected file must contain the singletonreteblock. retectl ca initruns once per rete. CA private key never leaves operator's secure storage.retectl ca signis the low-level primitive;retectl issue-bundleis the high-level wrapper that computes which principals live on a node (fromusers.yaml+services.yaml), signs each of their certs, and packages everything alongside the node identity and config-server bootstrap info. One bundle per node, not per principal (avoids the combinatorial mess of separate bundles for a node hosting five services).--kindonca signselects the SPIFFE path namespace and the X.509 extension policy applied to the resulting cert. All six kinds are accepted from day one (user,service,node,management-plane,control-plane,vertex);vertexandcontrol-planearen't exercised at runtime in C0 but the CLI surface is stable. TLS-capable kinds (user,service,node,vertex) getkeyUsage: digitalSignature, keyEncipherment+extKeyUsage: serverAuth, clientAuth; signing-only kinds (management-plane,control-plane) getkeyUsage: digitalSignatureonly, noextKeyUsage— see ADR-0005 for the rationale.retectl compilewrites artifacts to.flor/compiled/<node>/mgmt/inside the repo (withagent.jsonandvertices/flor.jsonper node). Artifacts contain only scope-relative path references (bare filenames likeca.crt,alpha.crt) — the agent resolves them against the rete install root at startup. No secrets in artifacts; committing them turns the git log into an auditable shipment history. Nodes don't pull from git; they fetch from the config-server (see Config-server).retectl publishuploads the current.flor/compiled/tree to the rete's config-server; nodes fetch their own artifacts on the nextflor agent sync. Publish is separate from compile so the operator can review the diff (and the audit commit) before the change is visible to nodes. Publish is idempotent — re-running with the same tree is a no-op on the server.- Nothing in
retectlaffects running agents directly. It reads and writes the rete repo plus operator-local CA material, and talks to the config-server over the rete's own Florete. Safe to run anywhere the operator has the repo checked out and is enrolled as an operator principal.
flor (node, daemon + user CLI)
flor id create --node <node> [--principal <kind>/<name>]...
# generate keypairs locally for the node and
# any workload principals to run on it;
# package CSRs into a bundle (Flow B)
flor enroll <bundle> [--as <scope>] # bootstrap: install certs, install initial
# compiled artifacts, start agent
# (two-step: bundle → sync)
# scope defaults to rete name in bundle;
# --as overrides if name collides locally
flor version # binary version
flor agent run [--rete <scope>] # the supervisor daemon (system service);
# reads <root>/mgmt/agent.json; auto-detects
# the scope if only one rete is enrolled;
# supervises one `flor vertex run` in C0
flor agent sync [--rete <scope>] # select rete by scope name;
[--commit-timeout <d>] # auto-detected if only one rete enrolled
[--dry-run] # default timeout 5m; 0 disables
[--confirm] # show artifact diff, no restart
# finalise a pending commit-timeout sync
flor agent status [--rete <scope>] # local agent state + active artifact version
flor vertex run [--rete <scope>] # the data-plane daemon spawned by the agent;
--name <name> # same rete scope as the agent (auto-detected if
# only one enrolled). Under the rete root
# ~/.flor/retes/<scope>/ it reads
# mgmt/vertices/<name>.json (plus the ctrl/
# sibling for mesh in C1+) and resolves
# ca.crt + identities there; run by hand to debugNotes:
- flor home. Node-local commands resolve their install root from
<flor-home>:$FLOR_HOMEif set, otherwise$HOME/.flor. Enrolled retes live at<flor-home>/retes/<scope>/. The$FLOR_HOMEoverride exists mainly to relocate the tree for development and CI (currently at<flor-repo>/.flor-dev/, git-ignored); production uses the$HOME/.flordefault. flor id createruns on the target machine for Flow B (security-purist) enrollment; generates keypairs for the named node + any principals hosted on it, emitting a CSR bundle for the operator to sign. The operator tells the user which principal names to include (out-of-band), so the bundle matches whatusers.yaml+services.yamldeclare for that node.flor enroll <bundle>is a two-step bootstrap. Step 1: unpack the bundle (CA cert + node cert + key + workload certs + keys + config-server URL + expected config-server SPIFFE ID + a currentagent.jsonandvertices/flor.json) and write everything to~/.flor/retes/<scope>/, where<scope>is the rete name embedded in the bundle (override with--as <scope>if it collides with an already-enrolled rete). This gives the node enough material to start running immediately. Step 2: startflor agent run, which brings up the vertex and then runsflor agent synconce to refresh against whatever the rete currently runs. Re-keying (or adding a new workload on this node) re-runs the same command with a freshly-issued bundle.flor agent syncfetches<this-node>/{agent.json, vertices/flor.json}from the rete's config-server over Florete (acting as thenode/<node>principal via the local vertex's SOCKS5), installs the new artifacts, and restarts the supervised vertex with a commit-timeout guard. No compilation on the node — artifacts were pre-compiled by the operator and published to the config-server.--commit-timeoutis on by default (5 min). New artifacts become active; ifflor agent sync --confirmisn't run within the timeout, the previous artifacts are restored and the vertex restarts. Cisco IOScommit confirmedpattern.flor agent runis the long-running supervisor process per node. It reads<root>/mgmt/agent.json(where<root> = ~/.flor/retes/<scope>/) and spawns aflor vertex run --rete <scope> --name <name>per entry in itsverticeslist. In C0 that's one child; C1 adds a second vertex for the mesh-flor layer. How exactly the agent launches vertices (direct fork, systemd unit, future local workload-runtime interface) is intentionally not pinned here; the runtime contract is just "a vertex starts when given its scope and name".flor vertex runis the data-plane daemon. Given--rete <scope>(the same scope the agent runs under) and--name <name>, it resolves the rete root~/.flor/retes/<scope>/, readsmgmt/vertices/<name>.json(and, for a mesh vertex, thectrl/sibling), resolves itsca.crtand per-principal certs/keys against that root, and runs the workloads/io/transport-endpoint/connection-manager described there. It does not re-verify signatures (the agent is the sole verifier); apart from resolving its own scope directory it is unaware of the agent, the config-server, and the rest of the rete.flor agent statusreads from a per-rete Unix socket (~/.flor/retes/<scope>/agent.sock) exposed by that rete's agent.--rete <scope>selects which socket to use; auto-detected when only one rete is enrolled. A future tray-icon GUI (B1+) will be another client of the same socket — CLI and GUI share the same daemon API.
Explicitly deferred from C0:
- Any YAML-mutation subcommands.
- Multi-hop paths and label allocation (C1 feature).
- SIGHUP hot reload.
- CRL / OCSP. (Revocation is by name removal +
flor agent sync.) - Delta state updates.
- iptables-based transparent outbound redirection for services that can't speak SOCKS5.