App and project settings

Overview

mouaif manages settings through a three-layer hierarchy: built-in defaults → global app settings → project-level settings. Project values override app-level defaults when they conflict, giving you shared defaults across your environment while allowing fine-grained customization per codebase.

API shapes (GET /api/settings/project, GET /api/settings/resolved)

The app-level and project-level payloads are projected differently, because the two stores hold different kinds of data:

// GET /api/settings/project?projectDir=/abs/path
{
  "project": { "name": "app", "skills": true, "agentFiles": false, "tags": ["web"] },
  "path": "/abs/path/.mouaif.json",
  "dbBacked": false
}

Two fields are always removed: __dbBacked (internal storage bookkeeping, never part of the user's settings) and apiKey on any providers / models entry, which is replaced by a response-only hasApiKey boolean. Credentials belong in the app store only.

Where the app store lives

App-level settings are stored as one JSON object in the app_kv row of ~/.mouaif/store.sqlite (key settings), next to the purpose-built tables for project settings, the MCP tool cache and recent models.

Because every route reads that row, an unreadable value must not take the server down — but it must not destroy the user's data either. If the stored blob does not parse (or is not a JSON object), the server:

  1. moves the stored text to a quarantine row keyed settings.corrupt-<timestamp>-<random>;

  2. deletes the unreadable live row, so the app starts from the built-in defaults;

  3. logs the quarantine key on stderr.

    The result is the same empty-but-working store the old silent {} fallback produced, except the original bytes are still in the database:

sqlite3 ~/.mouaif/store.sqlite \
  "SELECT key, value FROM app_kv WHERE key LIKE 'settings.corrupt-%'"

settings.listQuarantinedAppSettings() returns the same rows from Node. Restore an entry by copying its value back into the settings row once you have repaired the JSON.

How settings work

Managing settings in the UI

  1. AI Providers & Keys — open Settings → Providers to add or edit API keys and OAuth connections. Provider credentials are global and never committed to individual project folders.

  2. Access & Security — configure optional password protection, passkeys, and manage sessions from Settings → Access & passkeys (see Authentication).

  3. Project Customizations — open project settings to configure rules, instruction files (such as AGENTS.md or CLAUDE.md), and tool permissions for that project.

  4. Database-backed settings (Clean tree) — by default, project settings are stored next to your code in .mouaif.json. If you prefer to keep your working directory untouched by tooling files, enable Store settings in app DB in project settings.

  5. Chat defaults — open Settings → App defaults → Chat defaults to set the default prompt style and two composer toggles (Enter inserts a newline; Auto-retry failed sends). All three save automatically as soon as you change them; there is no Save button. Each setting is a row card with a per-row status line that confirms the change.

  6. Dictation — open Settings → App defaults → Dictation to pick the speech-to-text model. The choice is stored under the app-level dictation key ({ modelId, providerId }) and is read by the Dictation page and the chat composer's microphone alike, so both agree on which model a recording is sent to (see Dictation).