# shellcheck shell=bash # ════════════════════════════════════════════════════════════════════════════ # app.env — SynaptoMind service configuration # # Vendored from bun-templates/deploy (see lib/common.sh and install.sh). # Provenance: https://forgejo.home.lan/authelia/bun-templates commit 89be318daf8adab5ddca957162b3b7df8429e725 # ════════════════════════════════════════════════════════════════════════════ # ── Identity ─────────────────────────────────────────────────────────────── APP_NAME="synaptomind" APP_DESC="SynaptoMind — thought-graph engine" # ── Distribution ─────────────────────────────────────────────────────────── # "binary" installs the published release tarball (see # synaptomind/adr/2026-10-01-unify-deploy-framework-adr.md): no bun, # no node_modules, no git checkout on the host. Flip to "source" for a # developer install from a git checkout. DIST="binary" # ── binary mode ──────────────────────────────────────────────────────────── # Asset URL = ${RELEASES_BASE}/${TAG}/${ASSET_PATTERN} RELEASES_BASE="https://github.com/zumik3-del/synaptomind/releases/download" # The LIST endpoint, not /releases/latest: /latest silently excludes prereleases # and cannot express CHECKOUT_POLICY. Unauthenticated = 60 requests/hour per IP, # so a 403/429 surfaces as an explicit error naming the --version remedy. RELEASE_API="https://api.github.com/repos/zumik3-del/synaptomind/releases?per_page=30" # SINGLE QUOTES ARE REQUIRED: load_app_env() sources this file, so double quotes # would expand ${APP_NAME}/${TAG}/${OS}/${ARCH} here and leave render_template() # nothing to substitute. Same for APP_VERSION_CMD, whose ${BIN} is set by # app_version() at call time. ASSET_PATTERN='${APP_NAME}-${TAG}-${OS}-${ARCH}.tar.gz' APP_VERSION_CMD='${BIN} --version' # ── source mode (retained for developer installs) ────────────────────────── # REPO_URL stays REQUIRED even in binary mode: the frozen updater.sh bootstrap # shallow-clones the chosen tag to stage that release's own deploy/update.sh. REPO_URL="https://github.com/zumik3-del/synaptomind.git" # stable | latest | prerelease select a release tag. A value is # rejected in binary mode — a branch has no release asset. CHECKOUT_POLICY="stable" # ── Paths ────────────────────────────────────────────────────────────────── INSTALL_DIR="/opt/synaptomind" DATA_DIR="/var/lib/synaptomind" RUN_DIR="" # R1 (ADR addendum #1122): the app's own config home is DATA_DIR. The resolver is # cwd-relative and has no flag (src/config.ts:267 loadFileConfig() -> # join(process.cwd(), 'config.json')) and the unit's WorkingDirectory is fixed at # /opt/synaptomind, so the two are bridged by CONFIG_LINK_NAME below: the config # LIVES in /var/lib/synaptomind and is REACHED through the link. CONFIG_FILE # itself is documentation and assertion material — no framework code reads it. # It exists so "where does synaptomind's config live?" has ONE answer per class of # file: settings here, operator/secret env in /etc (R2), deploy state in RUN_DIR. CONFIG_FILE="/var/lib/synaptomind/config.json" # The link itself, created/refreshed by the installer AFTER seeding. On the live # host this link already exists (hand-made), so an install reports it preserved. CONFIG_LINK_NAME="config.json" # ── First-run seeding ────────────────────────────────────────────────────── # config.json is NOT in SEED_FILES any more: the payload tree is swapped on every # binary update, so a config seeded there competes with the operator's own file # for one pathname. It is seeded into DATA_DIR and reached through the link above. SEED_FILES=".env.example:.env" SEED_FILES_DATA="config.json.example:config.json" GENERATE_SECRET_IN=".env" # ── Runtime / service ────────────────────────────────────────────────────── # Explicit, not empty. An empty SERVICE_USER makes resolve_target_user() # (lib/common.sh:162) fall through to SUDO_USER and then `id -un`, so the same # installer run renders User=root when invoked as root without SUDO_USER, and # the service silently runs as root. Naming the user removes the dependence on # who ran the installer (ADR addendum #1122 R4). TARGET_GROUP defaults to this # value, so the rendered unit also gains Group=opencode. SERVICE_USER="opencode" EXEC_START="" PORT="3105" # Optional. Port written to mcp.httpPort when a FRESH config.json is seeded; empty # means "PORT + 1" (resolve_mcp_port in lib/common.sh). An existing config.json is # never rewritten, so this affects new installs only — it exists to break the +1 # when 3106 is already taken on the host. Must differ from PORT. MCP_PORT="" HEALTH_URL="" HEALTH_TIMEOUT="60" # A SECOND health window, used only when HEALTH_TIMEOUT expired with no answer at # all. A timeout is this run's own bound, not a fact about the service, so an # update that cannot confirm the new version is reported UNVERIFIED instead of # failed-with-a-rollback (which stops the unit and restores the database). Raise # this on a host with a slow start. 0 disables the re-check — not recommended. HEALTH_CONFIRM_TIMEOUT="30" # ── host requirements ────────────────────────────────────────────────────── # "no" — a binary host needs no bun at install time or at runtime; the embedder # is the same executable spawned as `synaptomind --embedder`. REQUIRES_BUN="no" # "git tar" — tar extracts the release payload, git is only the updater.sh # bootstrap (it clones the tag to stage that release's update.sh). SYSTEM_DEP_CMDS="git tar" HOOKS_DIR="" LIB_RAW_URL="https://raw.githubusercontent.com/zumik3-del/synaptomind/main/deploy/lib/common.sh"