Command line
Every vcon-server command: what it does, what it prints, its exit codes, and which may run beside a serving server.
Every command but mcp takes --config <file>, the same file serve reads,
and acts on the data directory it names. Like serve, each turns core dumps off and
locks its memory before it reads a key, so it needs the same memory-lock
allowance (see getting started).
Run each as the service account that owns the data directory, never as root.
With the objects in an S3 bucket (storage.objects = "s3"; see
keep vCons in an S3 bucket),
every command but mcp and rekey master (which touches only
server.sqlite) also reads the secret key file, reaches the bucket,
reads its versioning and checks the claim on its prefix before it does
anything else, and exits 1 with the storage cannot be used: and the reason
when one of these fails. So the bucket must be reachable from the host
where the commands run, as from the server. check reads every object, one
request for each version, and backup copies every object from the bucket
into files.
Serving
| Command | Prints | Runs beside serve |
|---|---|---|
serve --config <file> | log lines on standard error; nothing on standard output | no |
serve runs the server until SIGTERM or SIGINT, then exits 0. It refuses to
start, with exit code 1 and the reason, when the configuration, the master
key, the data directory, the certificate or the storage cannot be used.
Getting started runs it under systemd, and
operations lists the lines it logs.
Output and exit codes
- Each command prints what the matching admin route
answers: one JSON object per line, so the output can be piped to
jqor read line by line. A command with nothing to report prints nothing. - 0: done.
- 1: refused or failed. Nothing is printed on standard output (except by
check, which prints its report first); standard error says why, asvcon-server: <reason>. - 2: the command line does not parse, such as a missing
--configor--override-holdswithout--force.
Tenants
| Command | Prints | Runs beside serve |
|---|---|---|
tenant create <name> [--retention <period>] | {"id"} | no |
tenant list | {"id", "name", "retention", "metadata"} per tenant, by name | yes |
tenant set-retention <id> <period or default> | {"id", "retention"} | yes |
tenant set-metadata <id> <none, counts or full> | {"id", "metadata"} | yes |
tenant remove <id> [--force [--override-holds]] | nothing | no |
tenant remove without --force removes only a tenant that keeps no
version. --force also removes one that does, unless a uuid of it is under a
legal hold. --override-holds destroys even held vCons; it exists only here,
never over HTTP, and only with the server stopped.
tenant set-metadata sets which clear columns the tenant's Parquet exports
carry: none (the default), counts or full. See
export to Parquet.
Keys
| Command | Prints | Runs beside serve |
|---|---|---|
key create --tenant <id> --scope <s> [--scope <s>...] --label <label> | {"id", "token"} | yes |
key create --operator --label <label> | {"id", "token"} | yes |
key list [--tenant <id>] | {"id", "tenant", "scopes", "label", "created_at", "revoked_at"} per key, oldest first | yes |
key revoke <id> | nothing | yes |
A token is printed once and never again; the server keeps only its hash.
key create --operator is the only way to make an operator key, which is
what the admin routes need. key list without --tenant lists every key,
operator keys included (their tenant is null).
Audit logs
| Command | Prints | Runs beside serve |
|---|---|---|
audit export --admin [--since <seq>] | the admin log's records | yes |
audit export --tenant <id> [--since <seq>] | the tenant's log's records | yes |
Records are written oldest first, after --since if given; keep the last
seq you read and pass it next time. See audit logs
for the fields.
Key rotation
| Command | Prints | Runs beside serve |
|---|---|---|
rekey tenant <id> | nothing | no |
rekey master --new-master <file> | {"master_key_id", "next"} | no |
rekey tenant gives the tenant a new key: every stored version's data key is
rewrapped under it, in batches, and the tenant's catalog is re-encrypted under
it, so the old key opens nothing the tenant keeps. Bodies are not
re-encrypted. A run that stops, for any reason, is finished by running it
again.
rekey master rewraps every tenant key, and every key a stopped
rekey tenant left pending, under the master key in --new-master. It works
on a copy of server.sqlite under the new key and renames the copy over the
original only once it is complete, so until then the original is untouched. A
run stopped before the rename starts again; one stopped after it has nothing
left to do. Afterwards, point master_key in the configuration at the new
file; the old key no longer opens anything. The full procedure is in
operations.
Checking
| Command | Prints | Runs beside serve |
|---|---|---|
check | one line per tenant, then a summary | no |
check is the one command that prints its report and still exits 1, when it
found a problem: the report says what. See
checking the data for each field.
Backup
| Command | Prints | Runs beside serve |
|---|---|---|
backup <dir> | {"tenants", "tries", "versions"} | yes |
backup writes a consistent copy of the data directory to <dir>, which
must not exist yet, while the server runs. See
back up and restore for what it
copies, how to restore the copy, and what to keep apart from it.
Export
| Command | Prints | Runs beside serve |
|---|---|---|
export parquet --tenant <id> --to <dir or s3://bucket/prefix> [--since <time>] [--until <time>] | {"tenant", "metadata", "to", "manifest", "seq", "files", "rows", "bytes", "skipped", "unread"} | yes |
export parquet writes a copy of the tenant's kept versions, current and
hidden, as Parquet files under tenant=<id>/date=<yyyy-mm-dd>/, and then a
manifest, tenant=<id>/manifest/<seq>.json, that names them. It reads the
store and changes nothing in it but one export record in the tenant's audit
log. --since and --until are RFC 3339 times; a version stored at or after
--since and before --until is exported. See
export to Parquet.
Storage
| Command | Prints | Beside a server |
|---|---|---|
storage move-objects | {"tenant", "moved", "missing"} per tenant, then {"moved"} | no |
storage move-objects moves every tenant's sealed objects from the data
directory to the bucket that storage.objects = "s3" names (see
keep vCons in an S3 bucket).
Each object is written to the bucket, read back and compared byte for byte
before its file is removed, so a run that stops loses nothing: run it again
to move the rest. missing counts the versions check finds without an
object afterwards. It is refused when the configuration keeps the objects in
the data directory.
MCP for an AI agent
| Command | Prints | Runs beside serve |
|---|---|---|
mcp --config <client file> | MCP messages on standard output | yes |
mcp is for an AI agent that starts its MCP servers as commands. It reads MCP
messages on standard input, sends each to a running server's /mcp with one
API key, and writes the server's answers to standard output, so the agent
reaches the same tools, scopes and audit log as over HTTPS. It reads a client
file instead of the server's configuration, and it opens no data directory
and no master key, so it can run on another machine. It stops with exit code
0 when standard input ends.
url = "https://vcon.example.com:8443/mcp"
key_file = "/home/agent/.config/vcon-server/agent.token"
ca = "/home/agent/.config/vcon-server/ca.pem"
url: the server's MCP address. It must start withhttps://.key_file: a file holding one API token and nothing else. The token is never on the command line or in the environment.ca: optional. PEM certificates to trust for the server, such as a private CA's; without it, the system's trusted roots are used.
The command connects directly, through no proxy. It exits with code 1 when the
client file or the key file cannot be read, when the server cannot be reached,
or when the server refuses the key: vcon-server: the server refused the key (401). Like the other commands it locks its memory, so the account that runs
it needs the same memory-lock allowance.
Running beside the server
Commands marked "no" refuse while serve, or any other command, holds the
data directory, with exit code 1 and the data directory is in use; stop the server and any other command first. The others run beside the server, and
the server sees their changes at its next request: a revoked key is refused at
once. See operations.
A first tenant, from nothing
sudo -u vcon vcon-server tenant create acme --config /etc/vcon-server/vcon-server.toml
# {"id":"3f0c…"}
sudo -u vcon vcon-server key create --operator --label ops --config /etc/vcon-server/vcon-server.toml
# {"id":"…","token":"vcs_…"} keep this token: it manages tenants over HTTP
sudo -u vcon vcon-server key create --tenant 3f0c… --scope write --label recorder-1 \
--config /etc/vcon-server/vcon-server.toml
# {"id":"…","token":"vcs_…"} give this one to the producer
Source of this page: website/content/docs/command-line.md