Configuration
AgentNotify is configured through a single per-user JSON file. The file is created on first launch with safe defaults and a generated bearer token. Unknown or malformed fields fall back to defaults; partial files are tolerated and rewritten with missing keys on startup.
Source: src/AgentNotify.Core/Config/AgentNotifyConfig.cs, src/AgentNotify.Core/Config/ConfigStore.cs, src/AgentNotify.Core/Config/NotificationTypeDefinition.cs.
File location and format
Default directory and files (src/AgentNotify.Core/Config/ConfigStore.cs):
| Path | Purpose |
|---|---|
%LOCALAPPDATA%\AgentNotify\config.json |
Typed configuration and bearer token |
%LOCALAPPDATA%\AgentNotify\agentnotify.db |
SQLite notification history |
%LOCALAPPDATA%\AgentNotify\logs\ |
Daily log files |
%LOCALAPPDATA%\AgentNotify\sounds\ |
Managed WAV/MP3 files |
%LOCALAPPDATA% is Environment.SpecialFolder.LocalApplicationData. All four paths are derived from the same config directory.
Format: JSON serialized with AgentNotify.Protocol.Json.Options (System.Text.Json with JsonSerializerDefaults.Web, PropertyNameCaseInsensitive: true, JsonStringEnumConverter(JsonNamingPolicy.SnakeCaseLower)). JSON property names are therefore camelCase (port, authToken, toastLocation) while enum strings on the wire are snake_case.
Loading behavior:
- Missing file returns defaults.
- Malformed JSON is caught as
JsonException; defaults are kept and a subsequentSaverewrites a healthy file. - After load
AgentNotifyConfig.ApplyDefaults()normalizes and fills missing keys. - Environment overrides
AGENTNOTIFY_PORTandAGENTNOTIFY_TOKENare applied whenConfigStore(applyEnvOverrides: true)(the CLI default).HasTokenFileand some app startup paths useapplyEnvOverrides: false.
Saving is atomic: write to a temporary file then File.Move(overwrite: true).
Warning:
config.jsoncontains the local bearer token (authToken). This value authenticates any local process that can reach127.0.0.1:47821. Do not copy, commit, email, or otherwise share the file. Delete%LOCALAPPDATA%\AgentNotifyonly when intentionally removing the token, history, and logs.
Settings reference
All settings are properties of AgentNotifyConfig. The table lists the JSON name (as written), the .NET type, the default, and the effect. Validation and clamping described here are performed by ApplyDefaults.
| JSON property | Type | Default | Description |
|---|---|---|---|
port |
int |
47821 |
Loopback Kestrel port. When <= 0 or > 65535 reset to 47821. Env AGENTNOTIFY_PORT overrides. Editable in Settings → General (1–65535). Changing it requires restarting AgentNotify. |
apiVersion |
string |
"v1" |
Read-only API version returned in health responses. |
authToken |
string |
"" then generated |
Bearer token for all /v1/* routes. Generated on first run as 32 random bytes rendered as base64url (RandomNumberGenerator.GetBytes(32)). Env AGENTNOTIFY_TOKEN overrides at runtime but is not persisted. ConfigStore.EnsureAuthToken creates and saves it when empty. |
toastLocation |
string |
"BottomRight" |
Toast corner: BottomRight or TopRight (case-insensitive check). Empty/whitespace reset to BottomRight. Editable in Settings → Toasts. |
maxVisibleToasts |
int |
5 |
Maximum simultaneously visible toasts. When <= 0 reset to 5. Editable in Settings → Toasts (1–20). Overflow notifications are queued and shown as others close. |
historyRetentionDays |
int |
30 |
Retention for non-active notifications. When < 0 reset to 30. Pruning uses max(1, value) days and deletes status != active && updated_at < cutoff. Editable in Settings → General (0–3650). |
launchAtStartup |
bool |
false |
Launch at Windows logon. Mirrored to HKCU\Software\Microsoft\Windows\CurrentVersion\Run\AgentNotify and toggled from the tray menu. Not directly edited in the Settings window. |
pauseNotifications |
bool |
false |
When true, notifications are stored but no toasts are shown (ToastStackManager returns early; sound policy also returns false). Editable in Settings → General and the tray menu "Pause notifications". |
doNotDisturb |
bool |
false |
Reserved scheduling stub. Currently only affects sound policy. Editable in Settings → General. |
soundsEnabled |
bool |
false |
Master switch for notification sounds. Editable in Settings → Sounds. |
soundVolume |
double |
0.8 |
Playback volume 0.0–1.0, clamped with Math.Clamp. Edited as 0–100 in Settings → Sounds (value/100). |
defaultSoundFile |
string? |
null |
Global sound filename. Normalized to Path.GetFileName and accepted only when extension is .wav or .mp3 (case-insensitive); otherwise null. Stored as a bare filename inside the managed sounds directory. Editable in Settings → Sounds (choose/preview/clear). |
typeSoundFiles |
object |
{} |
Per-type override map: type ID → filename. Keys are normalized with NotificationTypes.Normalize; values normalized as for defaultSoundFile. Invalid entries are dropped; duplicate normalized keys keep the last value. Case-insensitive. Editable in Settings → Sounds per type. |
playCriticalSoundsDuringDoNotDisturb |
bool |
false |
When true, critical-priority sounds play even when doNotDisturb is true. Editable in Settings → Sounds. See Sound policy. |
maxRequestBodyBytes |
long |
65536 (64*1024) |
Kestrel MaxRequestBodySize. When <= 0 reset to 65536. Not editable in Settings. Bodies larger than this are rejected before routing. |
rateLimitPerSecond |
int |
30 |
Simple fixed-window limit applied to every POST under /v1/notifications and to POST /v1/events (per token, 1-second window); GET and PATCH are not limited. When <= 0 reset to 30. Not editable in Settings. Env does not override. |
maxMetadataBytes |
int |
8192 |
Serialized metadata map size cap. When <= 0 reset to 8192. Not editable in Settings. Validation uses JsonSerializer.SerializeToUtf8Bytes(metadata, Json.Options). |
toastDurations |
object |
see below | Map of type ID → auto-dismiss seconds. 0 means sticky until dismissed/resolved. Backfilled from defaults and normalized. Editable in Settings → Toasts per built-in type (0–86400). |
customNotificationTypes |
array |
[] |
User-defined type definitions. See Custom types. Editable in Settings → Custom types. |
Toast duration defaults
AgentNotifyConfig.DefaultDurations():
| Type ID | Seconds |
|---|---|
completed |
5 |
success |
5 |
info |
7 |
warning |
12 |
error |
15 |
input_required |
0 |
permission_required |
0 |
blocked |
0 |
During ApplyDefaults:
- An empty or missing map is replaced with the defaults.
- Existing keys are normalized; if the normalized form differs and is absent, the value is copied.
- Every default key is added when absent (
TryAdd).
Effective duration is resolved by ToastDurationSeconds(type):
- If a custom definition is enabled and
Idequals the normalized type, itsdurationSeconds. - Else if
toastDurationscontains the normalized type, that value. - Else
7.
Sound policy
NotificationSoundPolicy.ShouldPlay (src/AgentNotify.Core/Services/NotificationSoundPolicy.cs):
if (!soundsEnabled || pauseNotifications) return false;
return !doNotDisturb || (priority == critical && playCriticalSoundsDuringDoNotDisturb);
File resolution uses ManagedSoundStore.Resolve against %LOCALAPPDATA%\AgentNotify\sounds\. Missing files are logged and no sound plays; the notification itself is unaffected.
Files imported through Settings → Sounds are validated by ManagedSoundStore.Import (src/AgentNotify.Core/Services/ManagedSoundStore.cs): must be .wav/.mp3, 1 byte–10 MB, copied with a content-addressed safe name {safeBase}-{hash16}{ext} where safeBase is sanitized to [A-Za-z0-9_-] (max 40). Built-in tones (chime.wav, ping.wav, alert.wav, knock.wav) are seeded idempotently from embedded resources.
Custom notification types
Custom types are presentation and behavior policy stored in customNotificationTypes. Notification rows persist only the stable identifier; deleting or disabling a definition never makes historical rows unreadable — they fall back to generic info styling and a 7-second lifetime.
Schema (src/AgentNotify.Core/Config/NotificationTypeDefinition.cs):
| Field | JSON name | Type | Default | Constraints |
|---|---|---|---|---|
| Stable identifier | id |
string |
"custom" |
Normalized with NotificationTypes.Normalize (trim, - → _, lower-case, inputrequired/permissionrequired aliases). Must match ^[a-z][a-z0-9_]{0,63}$. Must not collide with the eight built-in IDs. Must be unique among customs. Invalid or duplicate definitions are dropped during ApplyDefaults. |
| Display name | displayName |
string |
"Custom" |
When empty/whitespace set to id.Replace('_',' '); otherwise trimmed. |
| Accent color | accentColor |
string |
"#4A90D9" |
Must be #RRGGBB hex; validated and upper-cased, otherwise reset to "#4A90D9". |
| Default priority | defaultPriority |
enum | "normal" |
low/normal/high/critical (snake_case JSON via JsonStringEnumConverter). Used by NotificationService.CreateAsync when the request omits priority. |
| Lifetime | durationSeconds |
int |
7 |
Auto-dismiss seconds; 0 is sticky. Clamped 0–86400. |
| Enabled | enabled |
bool |
true |
Only enabled definitions are considered for effective duration, default priority, and accent. |
Fallback behavior: a notification whose type has no enabled custom definition uses the built-in toastDurations entry or 7 seconds, normal priority, and generic accent.
Example fragment:
{
"port": 47821,
"toastLocation": "BottomRight",
"customNotificationTypes": [
{
"id": "deployment_waiting",
"displayName": "Deployment waiting",
"accentColor": "#7C3AED",
"defaultPriority": "high",
"durationSeconds": 0,
"enabled": true
}
]
}
Settings window coverage
The tray Settings window (src/AgentNotify.App/SettingsWindow.xaml, .xaml.cs) edits these config properties directly:
- General tab:
port(1–65535),historyRetentionDays(0–3650),pauseNotifications,doNotDisturb. - Toasts tab:
toastLocation,maxVisibleToasts(1–20), eighttoastDurationsentries (0–86400 each). - Custom types tab: full
customNotificationTypesCRUD with the validation rules above. - Sounds tab:
soundsEnabled,soundVolume(0–100),playCriticalSoundsDuringDoNotDisturb,defaultSoundFile,typeSoundFiles, built-in tone picker (Chime, Ping, Alert, Knock) and WAV/MP3 import. - Channels tab: provider profiles and delivery routes (persisted in SQLite, not in
config.json).
These properties have no control in the Settings window and are edited by editing config.json or through the tray menu / environment:
authToken— generated and shown only viaagentnotify tokenor the file itself.apiVersion— read-only.maxRequestBodyBytes,rateLimitPerSecond,maxMetadataBytes— code defaults and file edits only.launchAtStartup— toggled from the tray menu (registry is the source of truth; reconciled to the file on startup).