hikyo
Documentation

Server configuration

Configure the datastore, network, cryptography, authentication cost, and backup policy.

Production configuration is explicit. Unknown HIKYO_* variables produce a warning, while malformed security settings stop startup.

Server flags

FlagDefaultPurpose
--listen ADDR127.0.0.1:8080Public API/UI listener; HTTPS when a TLS pair is configured.
--operational-listen ADDR127.0.0.1:8081Plaintext health, readiness, and metrics listener.
--tls-cert-file PATHnonePEM certificate chain; configure with the key file.
--tls-key-file PATHnoneMatching PEM private key; mode 0400 or 0600.
--root-key-file PATHnoneMode-0600, 64-hex-character root key.
--auto-migrate=BOOLtrueApply pending migrations before serving.
--devoffEvaluation datastore, root key, and text logs.

Do not use --dev for real secret material or any non-loopback deployment.

Production network baseline

VariableMeaning
HIKYO_DBRequired: sqlite:PATH or postgres://... datastore.
HIKYO_PG_POOL_MAXOptional positive PostgreSQL connection-pool maximum.
HIKYO_EXTERNAL_ORIGINSet explicitly to the canonical public HTTPS origin.
HIKYO_TLS_CERT_FILE, HIKYO_TLS_KEY_FILENative TLS pair; both or neither.
HIKYO_OPERATIONAL_LISTENSeparate operational bind; default 127.0.0.1:8081.
HIKYO_TRUSTED_PROXY_CIDRSAlternative proxy mode for a non-loopback plaintext public listener.
HIKYO_ADAPTER_EGRESS_POLICY_FILEOptional startup-only Forgejo origin-to-CIDR exception policy.

When origin is unset, Hikyo derives https://<listen> with native TLS and http://<listen> otherwise. Proxy mode should set the public HTTPS origin explicitly because the private listener cannot infer it.

Native TLS is the default direct-deployment posture. Hikyo validates the pair at startup, rejects expired or mismatched files, warns within 14 days of expiry, polls for replacements every 10 seconds, and also reloads on SIGHUP. A bad replacement leaves the last known-good certificate live and increments hikyo_tls_reload_failures_total.

Proxy mode requires trusted CIDRs when the plaintext public listener is not loopback. The list names proxies, not browser client networks. Operational routes never exist on the public router; keep the operational bind private.

MCP endpoint

The MCP endpoint is disabled by default. These settings control its exact public exposure:

VariableDefaultMeaning
HIKYO_MCP_ENABLEDfalseEnables the stateless JSON POST /mcp endpoint.
HIKYO_MCP_ALLOWED_ORIGINSemptyComma-separated, exact browser origins admitted at /mcp. Wildcards, null, paths, queries, fragments, and credentials are rejected.

Production requires an HTTPS HIKYO_EXTERNAL_ORIGIN. Development permits plain HTTP only on a loopback origin. Requests without an Origin header are accepted for non-browser MCP clients. An allowed browser origin does not enable CORS response headers, so it is an additional request check rather than a cross-origin browser API grant.

Treat every configured MCP client and its model provider as a recipient of MCP tool results. The five read tools expose bounded key definitions, environments, configuration cells, caller-owned pending changes, and revision metadata. Results may include non-secret configuration plaintext and caller-owned non-secret draft plaintext. Secret values and secret draft material are never returned. Tool calls accept only an existing workload or automation service-account bearer and repeat current authorization on every page.

For Helm and Compose deployment, client profiles, least-privilege grants, rotation, public validation, and failure diagnosis, use the MCP operations runbook.

Security response headers

Every public response carries the same set, refusals and API errors included:

HeaderValue
Content-Security-PolicySelf-only baseline, no inline script or style, frame-ancestors 'none'. Served documents extend connect-src with the configured remote origins only.
X-Content-Type-Optionsnosniff
Referrer-Policyno-referrer
Cross-Origin-Opener-Policysame-origin-allow-popups
Cross-Origin-Resource-Policysame-origin
Permissions-Policycamera=(), microphone=(), geolocation=()
Strict-Transport-Securitymax-age=31536000, conditional; see below.

Cross-Origin-Opener-Policy is same-origin-allow-popups rather than same-origin because the browser UI runs the identity-provider and workspace handoff ceremonies in popups that navigate to another origin and then close themselves; strict same-origin leaves those windows stranded open. The popups are opened with noopener and answer over a same-origin BroadcastChannel, so nothing reaches back through window.opener either way.

Permissions-Policy names no WebAuthn feature on purpose: publickey-credentials-get and publickey-credentials-create default to self, which is what passkey sign-in and reauthentication need.

HSTS

Strict-Transport-Security: max-age=31536000 is emitted when both hold:

  • HIKYO_EXTERNAL_ORIGIN has the https scheme (explicitly set, or derived as https://<listen> because a native TLS pair is configured), and
  • the external origin’s browser-visible host is not loopback.

The scheme of the configured public origin decides, not which process holds the certificate, so a reverse proxy terminating TLS in front of the plaintext listener emits it too, including when that internal listener binds to loopback. A plain-http external origin and any loopback external-origin host never emit it. A development instance must not pin localhost to https in the browser’s HSTS store for every other project on the machine.

If your reverse proxy already adds Strict-Transport-Security, do not also let it rewrite or append: two headers, or one with a shorter max-age, is a policy the browser resolves by rules you did not intend. Either let Hikyo emit it and pass the header through untouched, or strip Hikyo’s at the proxy and own the value there, including includeSubDomains or preload, which Hikyo deliberately does not send because they commit hostnames it does not serve.

Operational metrics

/metrics on the operational listener serves Prometheus text exposition (text/plain; version=0.0.4) using the official Prometheus Go client. Scraping requires no sidecar, external service, or egress. It is plaintext and unauthenticated by design — keep the operational bind private and scrape it from the host or a trusted network.

Alongside the retention and TLS gauges it exposes RED-style request metrics keyed by a closed surface classauth, hierarchy, values, revisions, delivery, scim, admin, and a fail-closed other. There are no raw paths and no identifiers in any label, so cardinality is bounded no matter the traffic.

MetricTypeLabelsMeaning
hikyo_http_requests_totalcounterclass, status (2xx/3xx/4xx/5xx/other)Requests per surface class and status bucket. A recovered panic counts as 5xx.
hikyo_http_request_errors_totalcounterclass, status (4xx/5xx)Client and server errors per surface class.
hikyo_http_requests_in_flightgaugeRequests currently executing in the API stack.
hikyo_http_request_duration_secondshistogramclassRequest latency; fixed buckets 0.005, 0.025, 0.1, 0.5, 1, 5 seconds plus +Inf.
hikyo_mcp_requests_totalcountermethod, tool, statusMCP requests by closed protocol method, registered tool name, and status bucket.
hikyo_mcp_requests_in_flightgaugenoneMCP requests currently executing.
hikyo_mcp_request_duration_secondshistogrammethod, toolMCP request latency using the fixed HTTP bucket grid.
hikyo_admission_concurrency_limitgaugeDerived Argon2id verification slots.
hikyo_admission_in_flightgaugeVerification slots currently held.
hikyo_admission_queue_depth_limitgaugeBound on simultaneous pre-auth waiters.
hikyo_admission_queue_waitinggaugeWaiters currently queued for a slot.
hikyo_admission_active_backoffsgaugeAccounts currently past the failure-backoff threshold.

Counters cover all /api/v1/* traffic. Unmatched paths, unsupported methods, and CORS preflights use the closed other class.

Under --dev the server also emits a per-request access log (method, surface class, status, duration) at debug level. The production handler starts at Info, so these Debug request lines are absent unless debug logging is enabled.

Adapter egress is public-address-only by default. To approve a private Forgejo origin, point HIKYO_ADAPTER_EGRESS_POLICY_FILE at a JSON object whose keys are exact canonical bare HTTPS origins and whose values are CIDR lists:

{
  "https://git.internal.example": ["10.40.0.0/24", "fd42:40::/64"]
}

The file is read and validated only at startup. Origins must have no path, query, fragment, or user information. An exception applies only when both the configured origin and every dialed IP match the same entry. It does not disable TLS verification, redirects remain refused, and DNS answers are checked again when connecting.

Root key

Choose exactly one source:

  • --root-key-file PATH, including a service-manager credential path.
  • HIKYO_ROOT_KEY, the weakest delivery tier.

The key must be 64 hexadecimal characters. Keep it outside the datastore and outside the backup identity’s custody store.

Datastore

SQLite uses HIKYO_DB=sqlite:/absolute/path/hikyo.db. Ensure the service user owns the parent directory and no other user can read it. The write pool uses one connection and the WAL read pool is capped at four, so concurrent readers cannot open unlimited connections or retain unbounded WAL snapshots.

Remote PostgreSQL must name one host explicitly and use sslmode=verify-full or sslmode=verify-ca. Multi-host DSNs and remote plaintext connections are refused. The connection-pool maximum defaults to 10. Set HIKYO_PG_POOL_MAX to a positive 32-bit integer for larger hardware, or put pool_max_conns=N in the PostgreSQL DSN. The environment variable takes precedence when both are present. Hikyo logs the effective pool maximum once at startup for either datastore.

Authentication cost controls

VariableDefaultMeaning
HIKYO_ARGON2_MEMORY_KIB65536Memory per Argon2id operation.
HIKYO_ARGON2_TIME3Argon2id time cost.
HIKYO_REAUTH_WINDOW_SECONDS0 (900 under --dev)Instance-default disclosure reauthentication window. 0 means every reveal takes its own ceremony, which only a passkey can satisfy; a positive value lets an authenticator code open a sliding window. Environments override it in project settings; protected environments are always 0.
HIKYO_ARGON2_PARALLELISM2Argon2id parallelism.
HIKYO_ADMISSION_BUDGET_MIB272Process-wide memory admission budget.

Tune these together under representative load. A malformed value is a startup error, not a fallback to the default.

Update notifications

VariableDefaultMeaning
HIKYO_UPDATE_CHANNELstableServer-wide WebUI notification track: stable, nightly, or off.

The server checks Hikyo’s public GitHub releases at most once every six hours. Only signed-in principals holding instance-config@instance see a toast and a badge on the profile icon. Dismissing the toast keeps the badge until the installed version catches up. Checks never download or install software, and a release-source outage does not stop the server.

HIKYO_DEV_ADMISSION_PER_IP_PER_MINUTE is for development only. A production server refuses to start when it is present.

Backup policy

VariableMeaning
HIKYO_BACKUP_RECIPIENTSComma-separated age public recipients.
HIKYO_BACKUP_DIRDestination for automatic pre-migration exports.

Recipients without a destination are a configuration error. When neither is configured, migrations continue but record a loud skip with no recovery archive.

Client variables

VariablePurpose
HIKYO_STATE_DIROverride local trust, context, and session storage.
HIKYO_TRUST_BUNDLEProvision trust for non-interactive automation.
HIKYO_CONTEXTSelect a named context for one invocation.
HIKYO_INSTANCE, HIKYO_ORG, HIKYO_PROJECT, HIKYO_ENVSupply target dimensions.
HIKYO_TOKENSupply a machine credential when a token file is unavailable.

The CLI channel is local machine state, separate from the server-wide setting:

hikyo update channel stable
hikyo update channel nightly
hikyo update channel off
hikyo update check

Stable and nightly release artifacts start on their matching channel. Direct source builds stay on off; install a published artifact before selecting a release channel. Interactive command invocations refresh release metadata before dispatch at most once per 24 hours and offer an in-place binary update when one is available; hikyo update check refreshes immediately.

Prefer flags for visible, one-off target changes and --token-file for machine credentials. See contexts and targets.