Standalone AI agent for OpenSVC cluster diagnostics, used by the OpenSVC webapp.
- Go 1.25.5 or later to build.
- An OpenSVC MCP server on the same host, with its local Unix socket.
- An LLM endpoint and model.
- A TLS certificate covering the agent's hostname, with its private key.
From the repository root, on a Linux host:
go build -o bin/opensvc-ai-agentd ./cmd/opensvc-ai-agentd
sudo useradd --system --user-group --no-create-home --shell /usr/sbin/nologin opensvc-ai
sudo install -Dm755 bin/opensvc-ai-agentd /usr/local/libexec/opensvc-ai-agentd
sudo install -d -m750 -o root -g opensvc-ai /etc/opensvc-ai
sudo install -d -m700 -o opensvc-ai -g opensvc-ai /var/lib/opensvc-ai-agentPlace the TLS certificate at /etc/opensvc-ai/agent.crt and the private key
at /etc/opensvc-ai/agent.key. Both must be readable by opensvc-ai; restrict
the private key to that user.
Create /etc/opensvc-ai/agent-llm.env, owned by root:opensvc-ai with mode 0640:
OPENSVC_AI_LISTEN_ADDR=0.0.0.0:8090
OPENSVC_AI_TLS_CERT_FILE=/etc/opensvc-ai/agent.crt
OPENSVC_AI_TLS_KEY_FILE=/etc/opensvc-ai/agent.key
OPENSVC_AI_CONVERSATION_DB_PATH=/var/lib/opensvc-ai-agent/conversations.db
OPENSVC_AI_OM3_MCP_SOCKET=/run/opensvc-mcp/delegated.sock
OPENSVC_AI_LLM_PROTOCOL=responses
OPENSVC_AI_LLM_BASE_URL=https://llm.example.test/v1
OPENSVC_AI_LLM_MODEL=your-model
OPENSVC_AI_LLM_AUTH_MODE=bearer
OPENSVC_AI_LLM_API_TOKEN=replace-meReplace the example values. The conversation database is created on first
start. The agent refuses a database written by another schema version: remove
the file to start with an empty one. Use chat_completions instead of
responses when required by the provider. For a provider without authentication, set
OPENSVC_AI_LLM_AUTH_MODE=none and omit the API token.
For the Anthropic Messages API, use:
OPENSVC_AI_LLM_PROTOCOL=messages
OPENSVC_AI_LLM_BASE_URL=https://api.anthropic.com/v1
OPENSVC_AI_LLM_MODEL=your-anthropic-model
OPENSVC_AI_LLM_AUTH_MODE=api_key
OPENSVC_AI_LLM_API_TOKEN=replace-meapi_key sends x-api-key; bearer remains available for Messages endpoints.
Messages supports streamed text and MCP tool calls, without extended thinking
or provider-hosted tools. Keep the API key only in the protected environment
file, never in Git or conversation history.
The agent serves the om3 backend under /v1/om3 and reaches its MCP only
through the local Unix socket OPENSVC_AI_OM3_MCP_SOCKET. It also serves the
oc3 backend under /v1/oc3 when OPENSVC_AI_OC3_MCP_SOCKET names the local
Unix socket of the collector MCP. Run each MCP on the agent host, typically as
resources of one OpenSVC service, and give the opensvc-ai user access to
its socket through its group. A socket need not exist when the agent starts.
Restrict network access to the agent port.
With OPENSVC_AI_DOCS_URL, the root of the OpenSVC book, the om3 and
oc3 backends offer the model search_docs, a search of the book: at
startup the agent reads its versions.json, the llms.txt of its latest
release line and the pages under agent/ and the keyword history it lists,
from that host only, in 60 s at most, and holds their index in memory, about
2 MiB. A book that cannot be read at startup is read again on a search,
every minute at most, said in the log; the search answers meanwhile that it
cannot be read, the rest served. Every 15 minutes, on a search, the agent
reads versions.json and the llms.txt of the latest book again, and the
latest book when its build changed: a book deployed again is seen without a
restart. The book of an earlier release line, under its own path, is read
the first time a search asks for it. A mirror of the book serves its own
versions.json and llms.txt; see the
client contract.
With OPENSVC_AI_CODE_URL, the tar.gz archive of the om3 source code at a
git reference, {ref} in it, such as
https://codeload.github.com/opensvc/om3/tar.gz/{ref}, the om3 and oc3
backends offer the model search_code, a search of the Go source code of
the daemon. On om3 it searches by default the code of the version the
nodes of the cluster of the conversation run, the newest when they differ,
as search_docs takes the book of that version; on oc3, a fleet, the
latest code, at OPENSVC_AI_CODE_REF, main by default, read again every
6 hours; on both, the version the user names, a tag or a commit. The
archive of a version is read the first time a search asks for it, in
memory, and indexed by declaration, its tests and its generated code left
out: about 50 MB kept per version, 100 MB while one is indexed, three
versions kept or being read, the latest code always among them, two read at
once. A question searches the
code 6 times at most. A mirror serves the same archives at its own URL.
For browser clients, set OPENSVC_AI_CORS_ALLOWED_ORIGINS to comma-separated
webapp origins, or * to allow all origins. Empty by default. See the
browser client guide for examples and restrictions.
| Variable | Default | Bounds |
|---|---|---|
OPENSVC_AI_LISTEN_ADDR |
127.0.0.1:8090 |
explicit IP address and port 1-65535 |
OPENSVC_AI_CONVERSATION_DB_PATH |
/var/lib/opensvc-ai-agent/conversations.db |
|
OPENSVC_AI_CONVERSATION_LIFETIME |
168h |
1h to 8760h |
OPENSVC_AI_FEEDBACK_RETENTION |
4320h (180 days) |
24h to 26280h |
OPENSVC_AI_CONVERSATION_MAX |
4096 conversations for the instance |
1 to 1000000 |
OPENSVC_AI_CONVERSATION_MAX_PER_USER |
128, or the instance limit if lower |
1 to the instance limit |
OPENSVC_AI_CONVERSATION_MAX_DATABASE_MIB |
256 |
32 to 1048576 |
OPENSVC_AI_CONVERSATION_MAX_USER_MIB |
an eighth of the database, at least 32 |
32 to the database size: the messages one user stores on a backend and cluster |
OPENSVC_AI_OC3_MCP_SOCKET |
unset: oc3 not served |
absolute path |
OPENSVC_AI_DOCS_URL |
unset: no documentation search | https URL of the root of the book, such as https://book.opensvc.com/; one naming its llms.txt is its directory |
OPENSVC_AI_CODE_URL |
unset: no code search | https URL of a tar.gz archive of the om3 source holding {ref}, such as https://codeload.github.com/opensvc/om3/tar.gz/{ref} |
OPENSVC_AI_CODE_REF |
main |
git reference of the latest code, read by an oc3 code search that names no version, or an om3 one whose cluster version cannot be read |
OPENSVC_AI_CORS_ALLOWED_ORIGINS |
empty: no CORS | exact origins or * |
OPENSVC_AI_MAX_CONCURRENT_ASKS |
4 |
1 to 128: the runs of the whole instance, every user, backend and cluster together |
OPENSVC_AI_MAX_CONCURRENT_ASKS_PER_USER |
2, or the instance limit if lower |
1 to the instance limit: the runs of one user of a backend and cluster at once |
OPENSVC_AI_SHUTDOWN_TIMEOUT |
30s |
1s to 5m |
OPENSVC_AI_AGENT_MAX_ITERATIONS |
8 |
1 to 32 |
OPENSVC_AI_AGENT_TIMEOUT |
5m |
1s to 30m |
OPENSVC_AI_TOOL_SEARCH_SCORE_RATIO |
0.30 |
0 to 1; 0 shows every search result |
OPENSVC_AI_TOOL_SEARCH_THRESHOLD |
20 |
1 to 1024, or -1 to search only catalogs too large for one model request |
OPENSVC_AI_LLM_TIMEOUT |
2m |
any positive duration |
OPENSVC_AI_LLM_MAX_OUTPUT_TOKENS |
4096 |
1 to 131072 |
OPENSVC_AI_LLM_REASONING_EFFORT |
unset: the model applies its own | none, minimal, low, medium, high or xhigh, as the model accepts; responses and chat_completions protocols only |
Durations use the Go syntax, such as 90s or 2h30m. An invalid value
prevents startup.
sudo -u opensvc-ai sh -c '
set -a
. /etc/opensvc-ai/agent-llm.env
set +a
exec /usr/local/libexec/opensvc-ai-agentd
'For managed deployments, use an OpenSVC app.simple resource to launch the
binary with the same environment. The agent reads environment variables, not
the environment file itself; its launcher must load that file if used.
Check health using the hostname covered by the certificate:
curl https://agent.example.test:8090/healthAdd --cacert /path/to/ca.pem if the agent uses a private CA.
The client API lists the routes of each backend and how they authenticate. Browser clients, such as the webapp, also follow the browser client guide.
go fmt ./...
go test ./...
go vet ./...
go run honnef.co/go/tools/cmd/staticcheck@v0.7.0 ./...The CI runs the same checks, plus module verification and a race-enabled test
run. internal/llm/staticcheck.conf keeps the capital letter of the provider
API names that start its error messages.
Licensed under the Apache License, Version 2.0. See LICENSE.