# Users guide This guide is for contributors and operators who need to understand the user-visible behaviour of repovec-appliance and its repository automation. It focuses on what a user can expect to happen, not on the internal crate layout. ## Documentation gate decisions When a change reaches continuous integration (CI), the workflow decides whether documentation validation is required and whether Mermaid diagram validation should also run. The decision is based on the changed-file list, whether any documentation-tooling configuration changed, and, for Markdown files, whether the current file contents contain Mermaid diagrams. Figure 1. Accessible flow diagram showing how the CI policy decides whether the documentation gate and Mermaid validation are required from the changed-file list, including the conservative fallback path used when the list is empty or malformed. ```mermaid flowchart TD Start["Start
Receive_changed_file_list"] --> Validate[Validate_input_list] Validate --> IsEmpty{List_empty_or_malformed?} IsEmpty -->|Yes| Fallback[Apply_safe_default_policy] IsEmpty -->|No| Classify[Classify_changes_by_path] Classify --> DocsOnly{Only_documentation_inputs_changed?} DocsOnly -->|Yes| RequireDocs[Set docs_gate_required = true] DocsOnly -->|No| MixedOrCode[Mixed_or_code_only_changes] MixedOrCode --> HasDocs{Any_documentation_inputs_changed?} HasDocs -->|Yes| RequireDocs HasDocs -->|No| SkipDocs[Set docs_gate_required = false] RequireDocs --> CheckNixie{Mermaid_or_conservative_path?} CheckNixie -->|Yes| RequireNixie[Set nixie_required = true] CheckNixie -->|No| SkipNixie[Set nixie_required = false] Fallback --> Output["Emit_policy_output
with_safe_defaults"] SkipDocs --> SkipNixie RequireNixie --> Output SkipNixie --> Output Output --> End["End
Workflow_consumes_flags"] ``` In practice, the current policy behaves as follows: - If the changed-file list is unavailable, CI runs both the documentation gate and Mermaid validation as a safe default. - If no documentation inputs changed, the documentation gate is skipped. - If Markdown files changed, the documentation gate runs. - If documentation-tooling configuration changed, the documentation gate and Mermaid validation both run as a conservative default. - Mermaid validation runs only when one of the changed Markdown files contains a Mermaid diagram, or when the workflow takes that conservative fallback. The CI workflow publishes these decisions as stable flags so the `docs-gate` job can stay required even when it skips documentation-specific work. When the workflow takes the conservative Mermaid path because a file could not be read, it also publishes which files triggered that fallback. ## GitHub device-flow authentication repovec-appliance authenticates to GitHub using OAuth device flow. This lets an operator authorize the appliance over SSH without opening a browser on the VM. The appliance requests a device code, shows the verification URL and user code, then polls GitHub until the user approves the request, denies it, or the code expires. During login, the operator-visible values are: - verification URL: `https://github.com/login/device` - user code: the short code to enter in GitHub's browser flow The token polling loop respects GitHub's polling interval and handles the standard device-flow terminal responses: - `slow_down`: wait longer before the next poll. - `access_denied`: stop the login attempt because the user denied access. - `expired_token`: stop the login attempt because the device code expired. The access token is encrypted at rest in `/etc/repovec/github-oauth-token.cred`. Operators should treat that file as secret material even though it is encrypted. The encrypted credential is bound to the appliance through `systemd-creds` using the credential name `repovec-github-oauth-token`. After a restart, the appliance restores only the bearer secret from this encrypted credential. Scope-dependent permissions must be revalidated against GitHub before the control plane relies on them, and operators may need to run a fresh login if that revalidation fails. Roadmap item `2.1.1` provides the runtime client, encrypted token-store adapter, and mock-server test binary. The interactive TUI login screen is a later roadmap item and will call this authentication surface. ## Qdrant service repovec-appliance ships Qdrant as an appliance-internal Podman Quadlet. Operators should treat it as a local dependency of the appliance rather than a general-purpose network service. The checked-in Quadlet is installed to `/etc/containers/systemd/qdrant.container`. It tracks the official Qdrant `docker.io/qdrant/qdrant:v1` image stream and enables `AutoUpdate=registry` so the systemd-managed container can participate in Podman's registry-based auto-update flow within the current major version. Qdrant's REST and gRPC ports are published only on loopback: - REST: `127.0.0.1:6333` - gRPC: `127.0.0.1:6334` Persistent vector storage lives at `/var/lib/repovec/qdrant-storage` on the host and is mounted into the container at `/qdrant/storage`. The mount uses an explicit `:Z` SELinux relabel so the rootful Podman service can write to the directory on enforcing hosts. Qdrant requires an API key. On first boot, `repovec-qdrant-api-key.service` generates a random raw key at `/etc/repovec/qdrant-api-key`, restricts the file to `repovec:repovec` with mode `0400`, and refreshes the rootful Podman secret `repovec-qdrant-api-key`. The Qdrant Quadlet injects that Podman secret as `QDRANT__SERVICE__API_KEY` inside the container. Operators can inspect service state without printing the key: ```sh systemctl status repovec-qdrant-api-key.service qdrant.service journalctl -u repovec-qdrant-api-key.service stat -c '%U:%G %a %n' /etc/repovec/qdrant-api-key podman secret inspect repovec-qdrant-api-key ``` Local clients authenticate by reading the key as the `repovec` user and sending it in Qdrant's `api-key` header: ```sh sudo -u repovec sh -c \ 'api_key="$(cat /etc/repovec/qdrant-api-key)" curl --config - http://127.0.0.1:6333/collections <`. ## Appliance systemd target repovec-appliance ships a base systemd target and static daemon service files under `packaging/systemd/`: - `repovec.target` - `repovecd.service` - `repovec-mcpd.service` - `repovec-grepai@.service` Install these files to `/etc/systemd/system/`, then reload systemd: ```sh sudo install -m 0644 packaging/systemd/repovec.target /etc/systemd/system/repovec.target sudo install -m 0644 packaging/systemd/repovecd.service /etc/systemd/system/repovecd.service sudo install -m 0644 packaging/systemd/repovec-mcpd.service /etc/systemd/system/repovec-mcpd.service sudo install -m 0644 packaging/systemd/repovec-grepai@.service /etc/systemd/system/repovec-grepai@.service sudo systemctl daemon-reload ``` The target wants `qdrant.service`, `repovecd.service`, `repovec-mcpd.service`, and `cloudflared.service`. The Qdrant service name is the generated systemd unit from the installed `/etc/containers/systemd/qdrant.container` Quadlet; dependent services must use `qdrant.service`. `repovec-grepai@.service` is the template used for future per-repository indexer instances. It runs `grepai watch` as the `repovec` user, sets `HOME=/var/lib/repovec`, works in `/var/lib/repovec/worktrees/%I`, and writes stdout and stderr to journald. Later reconciliation work creates and manages concrete instances; operators should not expect installing the template alone to start indexers. Enable and start the appliance service group with: ```sh sudo systemctl enable repovec.target sudo systemctl start repovec.target ``` > **Note:** `repovecd` and `repovec-mcpd` validate the checked-in systemd unit > contract and Qdrant liveness at startup before doing any other work. If > validation fails, the daemon exits immediately with a non-zero exit code. > Inspect the journal with > `journalctl -u repovecd.service --no-pager | tail -20` or > `journalctl -u repovec-mcpd.service --no-pager | tail -20`; the error message > identifies the violated unit contract or Qdrant liveness condition. This > validation does not prove that the host has `/usr/bin/grepai`, concrete > worktrees, or a compatible systemd version. Starting the target may fail until these prerequisites are present on the host: - The `repovec` system user exists and matches the checked-in unit contract. - `/etc/repovec/qdrant-api-key` has been provisioned with the Qdrant API key and can be read by the daemon services. - The required daemon binaries, `repovecd` and `repovec-mcpd`, exist at the paths referenced by the unit files. - `qdrant.service` can start and accept authenticated gRPC requests before the bounded daemon readiness wait expires. If any prerequisite is missing, the target fails closed instead of starting partially configured services. ### Startup validation logging Both `repovecd` and `repovec-mcpd` validate their checked-in systemd unit contracts at startup before starting any async work. The outcome is observable in the systemd journal: **Success** — a `TRACE`-level event followed by a `DEBUG`-level confirmation: ```text TRACE systemd unit contract validated DEBUG systemd unit contract validated at daemon startup ``` **Failure** — an `ERROR`-level event with structured fields identifying the violating unit and the nature of the failure, followed by a non-zero process exit: ```text ERROR systemd unit contract violation — aborting startup unit=repovecd.service error=repovecd.service is missing [Service] ``` The `unit` field contains the logical systemd unit name (e.g. `repovecd.service`) and the `error` field contains the human-readable description of the contract violation. The Qdrant Quadlet validator emits `INFO`, `WARN`, and `ERROR` events; use a target-scoped filter such as `RUST_LOG=repovec_core::qdrant_quadlet=info` to inspect those validation events. The systemd unit validator emits `TRACE`, `DEBUG`, and `ERROR` events; use `RUST_LOG=repovec_core::systemd_units=trace` when startup ordering or unit-contract diagnostics require the lower-level trace. Concrete grepai indexer instances also start after and require both Qdrant and `repovecd`.