100% free and open source · every tool, every host, no licence key · read the licence
Secronyx

Reference

Command line

The secronyx binary's invocation forms, direct query mode, and the apikey, ssh-sign and service subcommands with their exact usage.

Secronyx ships as a single binary, secronyx, that is both the MCP server and its own administration tool. This page covers everything you run by hand: version and help output, the direct query mode used for testing and scripting, and the apikey, ssh-sign and service subcommands. Server flags are on the Configuration reference; the wire protocol is on the JSON-RPC API page.

Invocation forms

secronyx [OPTIONS]                    Run as MCP server (stdio)
secronyx --transport http [OPTIONS]   Run as HTTP server with OAuth
secronyx --transport http --saas-url <url> --api-key <key>  SaaS agent mode
secronyx --query <NAME> [--json]      Run query directly (testing)
secronyx service <action> [OPTIONS]   Manage system service installation
secronyx apikey <create|list|revoke>  Manage the API key store
secronyx ssh-sign [OPTIONS]           Sign an HTTP request with an SSH key

That block is the binary's own USAGE text. One line in it needs a caveat: an --api-key (or SECRONYX_API_KEY) with no --mode selects hybrid mode before the transport is consulted, so the third form does not reach the HTTP agent-registration path; see Hybrid and SaaS mode.

The three subcommands are recognised only as the first argument and are dispatched before the main flag set is parsed, so secronyx apikey list --file keys.json works but secronyx --no-audit apikey list does not. Each subcommand has its own flags; the server flags do not apply to them.

Exit status is 0 on success and 1 on any error, with the message on stderr prefixed Error:. ssh-sign exits 2 when its flags fail to parse.

--version

$ secronyx --version
secronyx 1.0.0
  commit: 3f2a9c1
  built:  2026-09-10T14:22:07Z
  go:     go1.23.0
  os:     linux/amd64

Version, commit and build date are injected at link time; a plain go build prints dev, none and unknown.

--help

Prints usage grouped by option family, worked examples, the service actions and a summary of tools by scope. The tool summary in the help text is a curated subset; the authoritative inventory is tools/list or the Tool reference.

Direct queries

--query <name> runs one collector in-process and prints its result, bypassing the MCP protocol entirely: no server starts, no JSON-RPC envelope is involved and no client is needed. It is the quickest way to see what a tool returns on a given host, to script a one-off collection, or to confirm that a platform-specific collector works after a build.

secronyx --query get_cpu_info --json
secronyx --query get_capabilities --pid 1 --json
secronyx --query get_npm_lock --path /srv/app/package-lock.json --json

Without --json the output is a title line followed by the same indented JSON:

$ secronyx --query get_uptime
=== get_uptime ===

{
  "boot_time": "2026-08-27T23:55:40.247613688+01:00",
  "uptime": 1760957260000000,
  "uptime_str": "20 days, 9 hours, 9 minutes, 17 seconds",
  "timestamp": "2026-09-17T09:04:57.507615875+01:00"
}

With --json only the JSON is printed, on stdout, so it can be piped into jq. An unknown name prints Error: unknown query '<name>' and Use --help to see available queries. on stderr and exits 1; a collector failure prints Error: <message> and exits 1.

There is no --list-tools flag. To enumerate the inventory, send tools/list to the server (see the stdio session at the end of the JSON-RPC API page) or consult the Tool reference. The CLI knows over 500 query names: the long switch in runQuery plus the batches that the query_*.go files register at start-up. They are the tool names, with exceptions at both ends. Some tools have no --query handler at all (get_gpu_info, get_processes_sampled, get_container_logs and generate_system_report among them), and a few IIS queries are spelled differently on each side: --query get_iis_app_pool_cpu against the tool get_iis_apppool_cpu.

What direct queries do and do not apply

Because --query runs after redaction, the path policy, the probe policy and audit configuration have been installed, it behaves like a tool call in most respects, with two important differences:

  • Redaction applies. It is implemented inside the collectors, so --no-redact is needed to see raw secrets from the CLI just as it is over MCP.
  • Path and probe policies apply. --allowed-paths, --probe-allow-hosts and their relatives govern --query exactly as they govern tools.
  • Scope policy does not apply. --query calls the collector directly, so --scopes and --enable-sensitive have no effect; secronyx --query get_env_vars runs regardless. Direct queries are for the operator at the keyboard, who already has shell access.
  • No tool-call audit event is written. The audit provider is opened (or falls back to stderr with a warning), but tool-call events are emitted only by the MCP server, which --query bypasses. If you need an audited record, go through the server.

Query-specific flags

Most queries take no input. Those that do read it from the flags below; a flag that a query does not use is ignored. Defaults apply when a flag is unset or zero.

Flag Queries Behaviour
--pid <n> get_process_environ, get_capabilities Target process.
--image-id <id> get_docker_image_history Image to inspect.
--path <file> get_npm_lock, get_pip_lock, get_cargo_lock, get_go_sum, get_gemfile_lock, get_yarn_lock, get_pnpm_lock, get_poetry_lock, get_composer_lock, get_mix_lock, get_pubspec_lock, get_swift_resolved, get_podfile_lock, get_gradle_lock, get_conda_lock, get_app_config File to parse; must sit under an allowed root.
--service <name> get_service_log_view Unit or service whose log to show.
--lines <n> get_service_log_view Lines to return (default 100).
--limit <n> get_recent_reboots (10), get_recent_service_failures (20), get_recent_kernel_events (50), get_recent_resource_incidents (20), get_recent_config_changes (50), get_recent_critical_events (30), get_deployment_events (20), get_iis_failed_requests (50) Row limit; defaults in parentheses.
--hours <n> get_auth_failure_summary, get_audit_trail Look-back window (default 24).
--days <n> get_recently_installed_software Look-back window (default 7).
--period <p> get_historical_metrics, get_trend_analysis 1h, 24h or 7d (default 1h).
--framework <f> get_compliance_check cis, pci-dss, hipaa or stig (default cis).
--hive <h>, --regpath <p> get_registry_key, get_registry_tree, get_registry_security Windows registry hive (default HKLM) and key path.
--max-depth <n> get_registry_tree Recursion depth (default 3).
--appid <guid> get_dcom_permissions DCOM AppID.
--site-name <s> Site-scoped get_iis_* queries IIS site.
--app-pool <p> Pool-scoped get_iis_* queries IIS application pool.

Some queries use fixed inputs in CLI mode that are arguments over MCP: get_processes returns the top 10 processes by CPU; get_journal_logs, get_syslog, get_kernel_logs, get_auth_logs, get_app_logs and get_event_log return 50 lines; get_network_latency probes 8.8.8.8, 1.1.1.1 and google.com, subject to the probe policy. Use the MCP interface when you need other values.

--audit-verify

$ secronyx --audit-verify --audit-output /var/log/secronyx/audit.jsonl
Audit verification OK: 4213 events verified

Walks the hash chain of the audit file and exits 0, or prints Audit verification FAILED: <reason> and exits 1. --no-audit is ignored when --audit-verify is present. The audit chain tutorial shows what a tampered file looks like.

--login and --logout

These belong to the consumer SaaS flow described under Hybrid and SaaS mode. --login requires --email; --saas-url already carries a default. If --password is not given it prompts Password: and reads the value from stdin with echo enabled, through fmt.Scanln, which stops at the first space, so type it only on a terminal nobody is watching or supply it another way. On success it registers the device, stores the credentials under --config-dir and prints the instance ID. --logout deletes the stored credentials and exits.

apikey

Manages the JSON key store consumed by --api-keys-file. The full workflow is in the per-operator API keys tutorial.

Usage: secronyx apikey <action> [OPTIONS]

Actions:
    create   Generate a key and add it to the store. The key is printed once.
    list     Show stored keys (ids, names, scopes, expiry; never secrets).
    revoke   Disable a key by id.

Options:
    --file <path>      Key store file (created with mode 0600 if missing)
    --name <name>      create: human-readable owner, e.g. "ci-runner"
    --scopes <list>    create: comma-separated tool scopes (default: core)
    --expires <dur>    create: lifetime such as 90d, 12h, 30m (default: none)
    --cidr <list>      create: comma-separated CIDRs the key may be used from
    --id <id>          revoke: key id to disable

Examples:
    secronyx apikey create --file /etc/secronyx/keys.json --name ci --scopes core,logs --expires 90d
    secronyx apikey list --file /etc/secronyx/keys.json
    secronyx apikey revoke --file /etc/secronyx/keys.json --id 3fa9c1e2

--file is required by every action. apikey help (also --help or -h) prints the usage above.

apikey create

Requires --name. --scopes must name at least one scope and may not contain *; the command refuses with refusing to issue a wildcard (*) API key; list the scopes explicitly. --expires accepts any Go duration (12h, 30m) plus a d suffix for days; the expiry is stored as an RFC 3339 UTC timestamp truncated to the second. Each --cidr entry must parse as a CIDR.

$ secronyx apikey create --file /etc/secronyx/keys.json --name ci-runner --scopes core,logs --expires 90d --cidr 10.0.0.0/8
Created API key 3fa9c1e2 for "ci-runner" (scopes: core,logs, expires 2026-12-16T09:04:57Z, from 10.0.0.0/8)
This key is shown once and cannot be recovered:
msk_3fa9c1e2_Qm1vZ2xlR3Jvd2xlUGx1bWJlcmFuZFRoZUhhY2tlcnM

A key has the form msk_<id>_<secret>: an 8-character lowercase-hex id used for lookup, and a 32-byte random secret in unpadded base64url. The store holds only sha256:<hex> of the secret, so a leaked store file cannot be turned back into keys. The file is written atomically (to <file>.tmp, then renamed) with mode 0600.

apikey list

$ secronyx apikey list --file /etc/secronyx/keys.json
ID         NAME                 STATUS     CREATED                EXPIRES                SCOPES
3fa9c1e2   ci-runner            active     2026-09-17T09:04:57Z   2026-12-16T09:04:57Z   core,logs
8b02d7aa   ops-laptop           revoked    2026-08-01T10:00:00Z   -                      core

STATUS is revoked when the record is disabled, expired when its expiry has passed, and active otherwise. An empty store prints no keys.

apikey revoke

Sets disabled: true on the record with the given --id and saves the store. It prints revoked key <id> (<name>), or key <id> was already revoked, or fails with no key with id "<id>". A running server polls the store's modification time (at most every 2 seconds) and reloads it, so a revocation takes effect without a restart; a store that fails to parse after an edit is ignored and the previous key set stays in force.

Store format

{
  "version": 1,
  "keys": [
    {
      "id": "3fa9c1e2",
      "name": "ci-runner",
      "hash": "sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
      "scopes": ["core", "logs"],
      "created_at": "2026-09-17T09:04:57Z",
      "expires_at": "2026-12-16T09:04:57Z",
      "disabled": false,
      "allowed_cidrs": ["10.0.0.0/8"]
    }
  ]
}

expires_at and allowed_cidrs are omitted when unset. The server refuses to load a store that other users can read.

ssh-sign

Produces the Authorization header for a request signed with an SSH key, or a complete curl command that sends it, so operators and CI jobs can call the HTTP transport with the keys they already hold. The server side is --ssh-authorized-keys and --ssh-ca-keys; the end-to-end flow is in the SSH key request signing tutorial.

Usage: secronyx ssh-sign --url <url> (--key <path> | --agent [--fingerprint <fp>]) [--cert <path>] [--body <file>|-] [--curl]
  -agent
        Sign with a key from ssh-agent ($SSH_AUTH_SOCK)
  -body string
        Request body file, or - for stdin (default: empty body)
  -cert string
        Path to an SSH certificate (-cert.pub) for the key
  -curl
        Print a complete curl command instead of just the header
  -fingerprint string
        SHA256 fingerprint of the agent key to use
  -key string
        Path to the OpenSSH private key
  -method string
        HTTP method (default "POST")
  -passphrase-env string
        Environment variable holding the key passphrase
  -url string
        Full request URL, e.g. https://mcp.example.com/

Rules the command enforces:

  • --url is required and must be absolute (scheme and host). The signature covers the method, the request URI (path and query), the lower-cased host, a timestamp, a nonce and the SHA-256 of the body, so the request must be sent exactly as described here.
  • Exactly one of --key or --agent. With --key, the file must not be readable by group or others on Unix (chmod 600), and an encrypted key needs --passphrase-env <VAR>; the passphrase is read from that variable, never from the command line. With --agent, the socket is $SSH_AUTH_SOCK; if the agent holds more than one key you must pick one with --fingerprint SHA256:... (as printed by ssh-keygen -lf), otherwise the command fails with <n> keys available; choose one with --fingerprint.
  • --cert attaches an SSH certificate whose key must match the signing key; the server then authenticates through the issuing CA (--ssh-ca-keys) instead of an authorized_keys entry.
  • --body names a file, or - for stdin. At most 1 MiB is signed; a larger body is refused with body exceeds 1048576 bytes.
  • DSA keys and RSA keys under 2048 bits are refused. RSA signatures always use rsa-sha2-512.

The server accepts a signature within 5 minutes of its own clock and remembers the nonce for 10 minutes, so a captured header cannot be replayed.

$ secronyx ssh-sign --url https://mcp.example.com/ --agent --fingerprint SHA256:Yx0K...
SSH-Sig keyid="SHA256:Yx0K...", ts="1789981497", nonce="q3Zr...", sig="AAAAC3NzaC1lZDI1NTE5AAAAQ..."

With --curl and a body, the output is a runnable command that sends the same body from the same file (@- for stdin):

$ echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' > req.json
$ secronyx ssh-sign --url https://mcp.example.com/ --key ~/.ssh/id_ed25519 --body req.json --curl
curl -sS -X POST 'https://mcp.example.com/' -H 'Authorization: SSH-Sig keyid="SHA256:...", ts="...", nonce="...", sig="..."' -H 'Content-Type: application/json' --data-binary '@req.json'

On the server, each authorized_keys line may carry scopes="core,logs", expires=YYYY-MM-DD (or an RFC 3339 timestamp), from="10.0.0.0/8,192.168.1.0/24" and, on CA lines, principals="alice,bob". Any other option is rejected when the file loads, so a typo cannot widen access.

service

Installs and controls the binary as a system service: a systemd unit on Linux, a launchd daemon on macOS and a Windows Service on Windows. install, uninstall, start, stop and restart need root, or administrator rights on Windows; status does not. Platform guidance is on Windows service and Fleet deployment.

Usage: secronyx service <action> [options]

Actions:
    install     Install as a system service
    uninstall   Remove the system service
    start       Start the service
    stop        Stop the service
    restart     Restart the service
    status      Show service status

Options:
    --name <name>   Service name (default: secronyx)
    --              Pass remaining arguments to the service

--name must start with a letter and contain only letters, digits, hyphens and underscores, at most 63 characters; anything else is rejected before any command runs. remove is accepted as an alias for uninstall. Arguments after -- (or, when there is no --, everything after the action) are stored in the service definition and handed to service run at start, which is how a service-managed instance is configured:

sudo secronyx service install -- --mode hybrid --api-key sk_xxx
sudo secronyx service start
secronyx service status

On Linux, install writes /etc/systemd/system/<name>.service with ExecStart=<path-to-binary> service run <args>, Restart=on-failure and a hardened [Service] section (NoNewPrivileges=true, ProtectSystem=strict, ProtectHome=read-only), then runs systemctl daemon-reload and systemctl enable <name>. The undocumented run action is what the service manager invokes, and it does not re-enter the full flag set. On both Linux and Windows it parses only --mode, --transport, --token, --api-key, --saas-url, --config-dir, --ws-url, --wakeup-url, --instance-id, --device-token, --poll-timeout and --idle-timeout; Windows adds --debug and defaults --config-dir to the executable's directory. An argument outside that set fails the parse and the service stops without serving. Of those, only --mode hybrid starts anything: --transport http logs that HTTP transport is not yet implemented for the service and waits for the stop signal, so an HTTP deployment runs the binary directly rather than through service. Under systemd, run also sends READY=1 and STOPPING=1 over NOTIFY_SOCKET; on macOS it is a placeholder that waits for the stop signal without starting a server. See Windows service.

Companion binary: secronyx-token-server

The repository also builds secronyx-token-server, a small JWT issuer for deployments that want token-based access without an external identity provider. Its subcommands are serve (the default, with --config, --listen defaulting to 127.0.0.1:8444, --issuer, --audience defaulting to secronyx, --key-dir, --clients, --tls-cert and --tls-key), client add|list|remove, rotate and help. It exposes GET /.well-known/jwks.json, POST /token and GET /health. See Authentication for how the server is pointed at it.

Built 2026-09-19. Source: levantar-ai/secronyx. Found a mistake? Tell us.