Documentation
Configuration directory
The configuration folder, its files, merge rules and the settings registry.
All user configuration lives in one directory of human-readable files, so power users can keep it in a dotfiles repo, share it with a team, or symlink it. This is a quiet capability: document it in docs/reference/config-files.md, but don't feature it on the welcome page or in the README's headline features.
Location
Resolution order:
--config-dir <path>CLI flagRAML_KQL_CONFIG_DIRenv var- Default:
- macOS/Linux:
~/.raml-kql/(on Linux, if$XDG_CONFIG_HOMEis set, use$XDG_CONFIG_HOME/raml-kql/) - Windows:
%USERPROFILE%\.raml-kql\
- macOS/Linux:
The command "Open Config Folder" opens it in the file manager.
Machine-local data that must never be shared (the encrypted MSAL token cache and the session result cache) lives in the OS app-data folder, not here. RAML_KQL_USER_DATA_DIR (an absolute path) moves it, like VS Code's --user-data-dir; the e2e tests use it (D-032).
Files
~/.raml-kql/
settings.jsonc all settings (VS Code-style flat keys)
keybindings.jsonc VS Code format
workspaces.jsonc enabled/disabled, aliases, tags, preferred access paths (keyed by resource/tenant id)
groups.jsonc tenant/workspace groups
accounts.jsonc account labels + order + provider (NO tokens)
sources.jsonc pack sources (url, ref, pinned sha)
extensions.jsonc installed extensions (source, version, sha256), enabled state
permissions.jsonc "always" grants for extensions
queries/ My Queries (.kql with front-matter)
themes/ user colour themes (VS Code JSON format), auto-listed
── machine-local (safe to .gitignore; the app writes a .gitignore here on first run) ──
state/ tabs.json, history.jsonl, inventory.json, schema-cache/, ui layout
sources/ cloned source repos
extensions/ installed extension files
audit/ audit log
On first run, write a .gitignore in the config dir excluding state/, sources/, extensions/ and audit/, plus a short README.md explaining which files are shareable.
Rules
- JSONC (comments and trailing commas allowed) for all
*.jsoncfiles. Parse withjsonc-parser. Preserve the user's comments and formatting on programmatic edits by usingjsonc-parser'smodify+applyEdits; never rewrite the whole file. - Every file has a zod schema and a generated JSON Schema, which gives validation and completions when the file is opened in the app's JSON editor.
- Invalid files never crash the app. Show a notification "settings.jsonc has errors (line 12) — Open", keep the last valid in-memory config, and highlight the errors.
- Watch all files (chokidar or
fs.watchwith debounce). External edits (git pull of a dotfiles repo) apply live. - No secrets in the config dir files. Tokens, API keys and git credentials go to MSAL's encrypted cache or Electron
safeStorage. Config files only hold references ("credentialRef": "src-3f2a"). - Portability: IDs are tenant/resource IDs, not machine paths. Machine-specific values (window bounds, last export folder) go in
state/. - Config profiles (optional, keep simple):
settings.jsoncmay contain"[profile:work]": { ... }overrides, selected with--profile work. Only build this if cheap; otherwise log it as post-1.0 in the roadmap. - Import/Export: "Export Configuration…" zips the shareable files. "Import Configuration…" shows a diff/preview and merges or replaces. This is useful for team onboarding without git.
- Merge semantics for team-shared configs: an optional
settings.jsonckey"extends": ["./team/settings.jsonc", "https://…"]. Remote URLs are not allowed (security); only relative or absolute local paths, applied in order, with the user file winning. Same forgroups.jsoncandworkspaces.jsonc. This lets a team keep a shared config in a repo and include it.
Settings registry
All settings are declared in src/shared/settings/registry.ts as { key, schema (zod), default, description, category, scope: 'user' | 'machine', tags }. The Settings UI, JSON Schema, defaults and docs (docs/reference/settings.md, generated by a script in CI) all come from this registry.
Settings referenced in the specs (non-exhaustive):
| Key | Default |
|---|---|
workbench.colorTheme | "Raml Dark" (follows OS if window.autoDetectColorScheme) |
editor.fontFamily, editor.fontSize, editor.minimap.enabled, editor.wordWrap, editor.runScope | see spec 05 |
auth.provider | "builtin" |
accounts.showTenantsWithoutAccess | false |
workspaces.newWorkspaceDefault | "enabled" |
targets.groupBySubscription | false |
query.maxConcurrentPerAccount | 4 |
query.maxConcurrentTotal | 16 |
query.timeoutSeconds | 180 |
query.failFastOnSemanticError | true |
query.fallbackAccessPaths | true |
results.location | "panel" |
results.maxMergedRows | 1000000 |
results.memoryBudgetMB | 1024 |
results.attributionColumns | ["_TenantName","_WorkspaceName"] visible |
results.cellFilterMode | "grid" |
results.copyWithHeaders | true |
time.displayZone | "utc" |
schema.cacheHours | 24 |
history.maxEntries | 5000 |
privacy.aliasing.enabled | true |
privacy.aliasing.activeOnStartup | true |
privacy.aliasing.confirmReveal | true |
privacy.aliasing.applyToExports | "ask" |
privacy.aliasing.autoAliasFormat | "Customer {nn}" |
privacy.maskingRules | [] |
audit.enabled | true |
audit.includeQueryText | true |
audit.retentionMonths | 12 |
extensions.autoUpdate | false |
extensions.permissions.defaultScope | "run" |
sources.autoUpdate | false |
sources.checkForUpdates | true (startup check, at most once a day per source) |
update.channel | "stable" |
update.checkAutomatically | true |
crashReporting.mode | "ask" (spec 10) |
links.enabled | true |
log.level | "info" |