32 KiB
Meeting Assistant Configuration
Meeting Assistant uses normal .NET configuration under the MeetingAssistant section. The checked-in appsettings.json stores local paths, model names, endpoints, and environment variable names. It should not store secret values; use the configured KeyEnv fields for API keys.
Example
This example is abbreviated so the most common shape is readable. The checked-in appsettings.json is the canonical full example.
{
"MeetingAssistant": {
"Hotkey": {
"Toggle": "Ctrl+Alt+M",
"Abort": "Ctrl+Alt+Z"
},
"Vault": {
"BaseFolder": "%USERPROFILE%\\OpenCloud\\Persönlich\\Vault\\Exxeta",
"TranscriptsFolder": "Meetings\\Transcripts",
"MeetingNotesFolder": "Meetings\\Notes",
"AssistantContextFolder": "Meetings\\Assistant Context",
"SummariesFolder": "Meetings\\Summaries",
"ProjectsFolder": "Projects",
"DictationWordsPath": "Meetings\\dictation-words.md"
},
"Recording": {
"TranscriptionProvider": "funasr",
"SampleRate": 16000,
"Channels": 1,
"MicrophoneDeviceId": "",
"MicrophoneMixGain": 1,
"SystemAudioMixGain": 1,
"StopProcessingTimeout": "00:10:00",
"MinimumCompletedMeetingDuration": "00:01:00",
"MaxMetadataAttendeeImportCount": 30,
"TemporaryRecordingsFolder": "%LOCALAPPDATA%\\MeetingAssistant\\Recordings",
"InactivitySafeguard": {
"Enabled": true,
"FirstPromptAfter": "00:02:00",
"ReminderPromptAfter": [ "00:05:00", "00:10:00" ],
"AutoStopAfter": "00:30:00",
"InferredEndPadding": "00:01:00",
"CheckInterval": "00:00:15"
}
},
"Automation": {
"RulesPath": "meeting-rules.local.yaml"
},
"CalendarRecordingPrompts": {
"Enabled": true,
"SyncInterval": "00:30:00",
"PromptWindow": "00:05:00"
},
"WorkflowRulesEditor": {
"Endpoint": "",
"KeyEnv": "",
"Model": ""
},
"Screenshots": {
"Hotkey": "Ctrl+Alt+S",
"AttachmentsFolder": "Attachments"
},
"Agent": {
"Endpoint": "https://litellm.schweigert.cloud",
"KeyEnv": "LITELLM_API_KEY",
"Model": "chatgpt/gpt-5.5"
},
"Api": {
"PublicBaseUrl": "http://localhost:5090"
},
"LaunchProfiles": {
"english": {
"Hotkey": {
"Toggle": "Ctrl+Alt+L"
},
"AzureSpeech": {
"Language": "en-US",
"AutoDetectLanguages": [ "en-US" ]
}
}
}
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
Paths And Overrides
Meeting Assistant expands environment variables such as %USERPROFILE% and supports ~ at the start of paths.
Relative vault paths are resolved under Vault:BaseFolder. Absolute paths bypass BaseFolder. For example, Vault:MeetingNotesFolder set to Meetings\Notes resolves below BaseFolder, while C:\Notes is used directly.
Launch profiles live under MeetingAssistant:LaunchProfiles:{profileName}. A profile starts with the default MeetingAssistant options and then binds its profile section over those defaults. This allows profile-specific language, provider, hotkey, screenshot, or agent overrides without duplicating the whole configuration.
The default profile is always named default. Non-default profile hotkeys are registered only when the specific profile explicitly configures that hotkey section. This avoids accidental hotkey collisions from inherited defaults. Array options currently need explicit profile override handling for AzureSpeech:AutoDetectLanguages and FunAsr:ChunkSize; both are supported.
Vault
Vault configures where Meeting Assistant writes meeting notes, transcripts, assistant context notes, generated summaries, project knowledge, and dictation words. Meeting notes link to separate transcript, assistant context, and summary markdown artifacts using these configured folders.
BaseFolder is the root for relative vault paths. Use relative paths for files that should move with the vault root, and absolute paths for external files.
ProjectsFolder contains project knowledge. Each direct subfolder is treated as one project, and a meeting binds projects by listing those subfolder names in the meeting note projects frontmatter.
DictationWordsPath is reserved for providers that can accept vocabulary hints. It points to a markdown word list containing unusual project, person, product, or domain terms that should be biased during transcription when the provider supports it.
Recording
Recording:TranscriptionProvider selects the speech recognition pipeline. Supported values include funasr, whisper-local, and azure-speech.
| Setting | Purpose |
|---|---|
SampleRate |
PCM sample rate for captured audio. The current providers expect 16000 Hz. |
Channels |
PCM channel count for the mixed stream. The current providers expect mono (1). |
MicrophoneDeviceId |
Optional Windows microphone capture endpoint id. Blank uses the Windows default capture endpoint. |
MicrophoneMixGain |
Gain applied to cleaned microphone samples before final mixing. |
SystemAudioMixGain |
Gain applied to system loopback samples before final mixing. |
StopProcessingTimeout |
Maximum time to wait for post-stop processing such as transcription drain, finalization, OCR wait, and summary handoff. |
MinimumCompletedMeetingDuration |
Runs stopped before this duration are treated like aborts, so accidental same-minute starts do not produce meeting artifacts. |
MetadataLookupTimeout |
Foreground timeout for initial metadata lookup when starting a meeting. |
BackgroundMetadataLookupTimeout |
Longer background timeout for metadata that can continue after transcription starts. |
MaxMetadataAttendeeImportCount |
Maximum Outlook attendee count that will be copied into meeting frontmatter. |
OpenMeetingNoteDelay |
Delay before opening the newly created Obsidian note, giving the file system and app time to settle. |
DictationWordsReadTimeout |
Maximum time to wait for optional dictation-word hints before starting without them. |
TemporaryRecordingsFolder |
Folder for temporary mixed WAV files while a run is active. |
InactivitySafeguard |
Controls prompts and automatic normal stop for active meetings with no new transcript text. |
During recording, Meeting Assistant captures microphone and system loopback separately, buffers both streams to align samples, cleans the microphone stream through a local adaptive echo canceller using loopback as the far-end reference, then mixes the cleaned microphone and system streams into the normal 16 kHz mono PCM chunks. If one source is quiet beyond the alignment timeout, the available source is mixed with synthetic silence so microphone-only speech and system-only playback keep flowing to transcription.
On Windows, Recording:MicrophoneDeviceId can pin capture to a specific active microphone endpoint id. Leave it blank to follow the Windows default capture endpoint. The tray icon menu also exposes Microphone, listing active microphone endpoints with the effective endpoint checked. Selecting a microphone there overrides the configured/default microphone for later recording starts until another microphone is selected or the process exits.
Recording:MicrophoneMixGain and Recording:SystemAudioMixGain are applied during the final mix and default to 1. Recording:TemporaryRecordingsFolder controls where the temporary mixed WAV is written while the run is active. Temporary WAV files are deleted after the run completes, and stale temporary recordings from interrupted runs are deleted when the application starts. If an Azure Speech meeting cannot drain transcription before Recording:StopProcessingTimeout, Meeting Assistant keeps the WAV and writes a durable backlog item under TemporaryRecordingsFolder\offline-transcription-backlog. The background backlog worker retries those queued meetings, replays each WAV through a fresh speech pipeline, rewrites the original transcript, completes meeting metadata and summary generation, then removes the backlog item and WAV.
Recording:MaxMetadataAttendeeImportCount limits how many attendees Outlook metadata enrichment imports into meeting-note frontmatter. The default is 30; when an appointment has more attendees than that, Meeting Assistant still imports title, agenda, and scheduled end time, but leaves attendees empty because large invites are usually presentation-style meetings.
Recording:InactivitySafeguard watches active recordings for long periods without transcript text. The timer starts at meeting start and resets whenever a live transcript segment with text arrives. By default the app asks whether to stop after 2, 5, and 10 minutes of inactivity through native Windows app notifications with action buttons, requests reminder-style toast behavior, keeps each stop reminder actionable for 1 minute, and automatically stops normally after 30 minutes. Ignoring a notification does not block later checks or auto-stop. Safeguard stops are not aborts: transcription drain, speaker processing, screenshots, and summary generation continue through the normal stop flow. When the safeguard stops a run, the meeting end time is inferred as the last transcript segment timestamp plus InferredEndPadding; if no transcript text arrived, it uses meeting start plus the same padding.
| Setting | Purpose |
|---|---|
Enabled |
Enables the inactivity safeguard for active recordings. |
FirstPromptAfter |
First transcript-inactivity duration before showing the stop prompt. |
ReminderPromptAfter |
Additional transcript-inactivity durations before showing another stop prompt. |
AutoStopAfter |
Transcript-inactivity duration after which Meeting Assistant stops the recording normally without prompting again. |
InferredEndPadding |
Padding added to the last transcript timestamp, or meeting start when no transcript arrived, for safeguard-triggered end times. |
CheckInterval |
Polling interval for checking the active recording inactivity state. |
Hotkey:Abort configures a global discard shortcut. The default is Ctrl+Alt+Z. Aborting an active recording stops capture/transcription, deletes the meeting note, transcript, assistant context, summary file if present, and linked screenshot attachments for that run, and skips automatic summary generation.
Launch profile toggle hotkeys start a meeting when idle. When a different launch profile toggle is pressed during an active meeting, Meeting Assistant keeps the same meeting note, transcript, assistant context, and metadata; drains the current speech recognition pipeline without summarizing; appends a transcript marker; clears run-local speaker mappings; and continues transcription through the target profile.
FunASR
funasr streams 16 kHz PCM audio to the configured FunASR WebSocket endpoint. When FunAsr:Backend:Enabled is true, Meeting Assistant manages a local Docker-backed FunASR runtime. On application startup it begins a non-blocking warm-up for the default launch profile and any named launch profile that selects funasr.
| Setting | Purpose |
|---|---|
Endpoint |
WebSocket endpoint for the FunASR streaming server. |
Mode |
FunASR mode sent in streaming requests, usually 2pass. |
ChunkSize |
Three-part FunASR chunk size array. |
ChunkInterval |
FunASR chunk interval sent with streaming requests. |
EncoderChunkLookBack |
Encoder lookback count for streaming context. |
DecoderChunkLookBack |
Decoder lookback count for streaming context. |
Itn |
Enables inverse text normalization when the backend supports it. |
EmitOnlinePartials |
Emits online partial transcripts instead of waiting only for final two-pass text. |
WavName |
Logical WAV name sent to FunASR. |
FinalResultTimeout |
Time to wait for a final FunASR response after the stream ends. |
The warm-up pulls the configured online streaming image, prepares the mounted model and hotword folder, replaces any stale container with the configured name, starts the two-pass WebSocket server mapped to the endpoint port, keeps the container alive after the FunASR startup script backgrounds the server process, and stops it when the app shuts down. Recording can start while the backend is still warming up; captured audio is queued and then streamed once the WebSocket backend is healthy.
FunAsr:Backend controls the managed Docker runtime:
| Setting | Purpose |
|---|---|
Enabled |
Starts and warms up the Docker-backed backend from Meeting Assistant. |
DockerCommand |
Docker executable name or path. |
Image |
FunASR runtime image. |
ContainerName |
Container name used for replacement, startup, and shutdown. |
ModelsFolder |
Host folder mounted as persistent model and hotword storage. |
ContainerPort |
Container and host port used by the WebSocket endpoint. |
Privileged |
Runs the container with Docker privileged mode when true. |
CommandTimeout |
Timeout for Docker commands such as pull/run/build. |
StartupTimeout |
Timeout for backend WebSocket readiness. |
StopOnDispose |
Stops the managed container when the app shuts down. |
ServerCommand |
Shell command executed inside the container to start FunASR. |
FunASR response fields such as spk_name, spk, and sentence-level speaker metadata are preserved in transcript segments; missing speaker fields are written as Unknown.
If FunAsr:Diarization:Enabled is true, FunASR Python AutoModel can run with VAD, punctuation, and CAMPPlus over the temporary WAV after capture stops and the streaming ASR provider drains the already-captured audio. If sentence-level speaker labels are returned, the transcript markdown is rewritten with the final speaker-attributed segments. If final diarization is disabled or returns no segments, the live streaming transcript is kept.
FunAsr:Diarization controls that final pass:
| Setting | Purpose |
|---|---|
Enabled |
Runs the final FunASR diarization/finalization pass over the temporary WAV. |
AsrModel |
FunASR ASR model name for finalization. |
VadModel |
FunASR VAD model name. |
PunctuationModel |
FunASR punctuation model name. |
SpeakerModel |
FunASR speaker model, for example cam++. |
BatchSizeSeconds |
Audio batch size for finalization. |
BatchSizeThresholdSeconds |
Threshold used by the finalizer before batching. |
PresetSpeakerCount |
Optional fixed speaker-count hint for diarization. |
CommandTimeout |
Timeout for the final FunASR command. |
Whisper Local
whisper-local uses Whisper.NET with a local ggml model and remains available by setting Recording:TranscriptionProvider to whisper-local. The model file is not committed to this repository; place it at the configured WhisperLocal:ModelPath before using live transcription.
| Setting | Purpose |
|---|---|
ModelPath |
Path to the local ggml Whisper model file. |
Language |
Whisper language hint, or auto for automatic detection. |
WindowSeconds |
Window size used when streaming audio into local Whisper. |
When WhisperLocal:Diarization:Enabled is true, the final post-processing pass runs pyannote in Docker over the temporary WAV and reads the Hugging Face token from WhisperLocal:Diarization:Token or TokenEnv (HF_TOKEN by default). AnnotationSource selects pyannote's speaker_diarization or exclusive_speaker_diarization output. AlignmentMode selects whether Meeting Assistant assigns the best-overlap pyannote speaker label to each Whisper segment or rebuilds the finished transcript as pyannote speaker-turn segments with matching Whisper text.
Active pyannote runtimes are warmed up on application start so image setup and model download do not wait for the first diarization request.
Pyannote diarization settings are shared by local Whisper finalization and speaker-identification validation:
| Setting | Purpose |
|---|---|
Enabled |
Enables the pyannote-backed pass. |
DockerCommand |
Docker executable name or path. |
BaseImage |
Python base image used when building the local pyannote image. |
Image |
Local pyannote Docker image tag. |
BuildImage |
Builds the local image when it is missing. |
ModelsFolder |
Host folder mounted as Hugging Face, torch, and pip cache. |
Model |
Pyannote model name. |
AnnotationSource |
Selects SpeakerDiarization or ExclusiveSpeakerDiarization. |
AlignmentMode |
Selects BestOverlap or PyannoteTurns transcript alignment. |
Token |
Optional Hugging Face token value. Prefer TokenEnv for normal use. |
TokenEnv |
Environment variable name that contains the Hugging Face token. |
CommandTimeout |
Timeout for the pyannote command. |
Azure Speech
azure-speech streams Meeting Assistant's captured PCM chunks to Azure AI Speech using the Speech SDK ConversationTranscriber; it does not use MSAL, an Azure-owned microphone capture, or a separate MAS/AEC input path.
Configure AzureSpeech:Endpoint, Region, Language, and either Key or KeyEnv; this repository uses AZURE_SPEECH_KEY by default and does not store the key in appsettings. DiarizeIntermediateResults enables diarization for intermediate and final conversation transcription results.
If Azure Speech reports a transient connection failure, Meeting Assistant starts a new SDK session instead of completing the transcript with an error. The transcript note shows a single status line such as <Reconnecting... 1/5>, updates that line across retry attempts, and replaces it with the next real transcript line after Azure emits speech again. After the configured immediate attempts are exhausted, the same line changes to an Azure disconnected marker while retries continue. Reconnect starts a fresh Azure conversation session, so live speaker mappings are reset before processing the first resumed speech line.
| Setting | Purpose |
|---|---|
Endpoint |
Optional Azure Speech endpoint. When blank, Region plus subscription key is used. |
Region |
Azure Speech region used for subscription-based config. |
Language |
Fixed recognition language. Set to auto to enable Azure source language auto-detection. |
AutoDetectLanguages |
Candidate languages used only when Language is auto. |
LanguageIdMode |
Azure language identification mode; AtStart or Continuous. Other values normalize to Continuous. |
Key |
Optional inline Azure Speech key. Prefer KeyEnv. |
KeyEnv |
Environment variable name that contains the Azure Speech key. |
RecognitionStopTimeout |
Timeout while stopping the ConversationTranscriber after closing the audio stream. |
ReconnectAttemptsBeforeDisconnectedMarker |
Immediate reconnect-marker attempt count before the transcript status changes to the longer disconnected marker. |
ReconnectDelay |
Delay between Azure Speech SDK session reconnect attempts. |
DiarizeIntermediateResults |
Requests diarized intermediate results from Azure. |
PostProcessingOption |
Accepted by config but currently skipped for the live ConversationTranscriber path; the app logs a warning if set. |
PhraseListWeight |
Weight applied to dictation-word phrase-list hints. |
Azure returns generic speaker IDs such as Guest-1 and Guest-2, which Meeting Assistant writes directly into live transcript segments. RecognitionStopTimeout bounds SDK shutdown after the captured audio stream has been closed; the default is 3 minutes so Azure has time to finalize longer speaker-recognition samples.
Speaker Identification
Speaker identity matching keeps candidate samples only after a diarized speaker has at least SpeakerIdentification:MinimumSampleSpeechDuration of continuous speech, defaulting to 30 seconds. Adjacent same-speaker segments may be combined when the gap is no larger than MaximumSampleSegmentGap, but a different speaker resets the pending span.
| Setting | Purpose |
|---|---|
Enabled |
Enables live speaker identity matching and sample collection. |
DatabasePath |
SQLite database path for identities, aliases, references, and samples. |
InitialDelay |
Delay after recording starts before the first live identity pass. |
Interval |
Interval between live identity passes. |
MatchBatchSize |
Number of identities processed per model matching batch. |
MaxMatchCandidates |
Maximum known identities considered during one match pass. |
MatchIdentityActiveAge |
Age window for identities considered active enough for automatic matching. |
MaxSnippetsPerSpeaker |
Maximum stored voice snippets retained per speaker identity. |
MinimumSampleSpeechDuration |
Minimum uninterrupted same-speaker speech span needed before storing a sample. |
MaximumSampleSegmentGap |
Maximum gap allowed when combining adjacent same-speaker segments into one sample. |
SilenceBetweenSnippetsSeconds |
Silence padding inserted between snippets during Azure identity matching. |
LiveSampleBufferDuration |
How long live transcript/audio material is retained for extracting samples. |
MergeRecentIdentityAge |
Age window used by diagnostics that merge recent duplicate identities. |
MatchTimeout |
Timeout for an Azure-backed identity matching request. |
SpeakerIdentification:AzureSpeech is an advanced nested override for speaker identity matching. It uses the same shape as AzureSpeech and lets identity matching use different Azure language, endpoint, or key settings than live transcription when needed. If it is left unset, the normal Azure Speech settings remain the practical default.
SpeakerIdentification:PyannoteValidation is an optional secondary confidence layer. When enabled, pyannote rejects multi-speaker samples and must confirm an Azure-confirmed identity match before Meeting Assistant accepts it. It uses the same Docker-based pyannote runtime shape as local Whisper finalization and defaults the validation command timeout to 1 hour because local model setup can take substantial time.
| Setting | Purpose |
|---|---|
MinimumSingleSpeakerCoverage |
Required fraction of the tested sample that pyannote must attribute to a single speaker. |
MinimumMatchingKnownSnippetRatio |
Required pyannote agreement ratio between the new sample and known snippets for an accepted identity. |
Diarization |
Nested pyannote settings used for this validation pass. |
Automation
Automation:RulesPath points to an optional local YAML rules file. The default meeting-rules.local.yaml is ignored by git. Rules can trigger on meeting creation, assistant-context state transitions, identified speakers, or transcript line writes; conditions are evaluated with NCalc-style expressions and step values can use Razor syntax against Model.Meeting, Model.Event, Model.Speaker, and Model.Transcript.
See docs/meeting-workflow-engine.md for the detailed YAML format, supported variables, examples, and extension notes.
POST /diagnostics/workflow/reload reloads application configuration so workflow automation settings such as Automation:RulesPath can be changed without restarting the application. A meeting run that already captured its options keeps using those options.
Calendar Recording Prompts
CalendarRecordingPrompts controls optional Outlook Classic calendar prompts for starting recordings. It is enabled by default on Windows.
When enabled on Windows, Meeting Assistant periodically syncs today's Outlook Classic calendar appointments through COM, filters all non-canceled Teams meeting markers for the day into an in-memory cache, and schedules prompt checks from that cache. It does not query Outlook for every prompt. The notification asks Record meeting? with Yes and No actions when a cached Teams meeting reaches its start window, requests reminder-style toast behavior, and remains actionable for 5 minutes. Accepting starts a recording. If another recording is active, Meeting Assistant stops that recording through the normal stop path first, then starts the new recording, so the usual empty/too-short cleanup and summary handoff rules still apply.
| Setting | Purpose |
|---|---|
Enabled |
Enables scheduled Outlook Teams recording-start prompts. |
SyncInterval |
How often Meeting Assistant refreshes today's Outlook calendar cache. Defaults to 30 minutes when unset or invalid. |
PromptWindow |
How long after a Teams appointment's scheduled start it remains eligible for the one-time prompt. Defaults to 5 minutes when unset or invalid. |
Screenshots
Screenshots:Hotkey configures a global hotkey that captures the currently active window during an active meeting. Screenshots are written under Screenshots:AttachmentsFolder, which defaults to an Attachments folder beside the assistant context note, and each capture appends a timestamped markdown image link to the assistant context.
Screenshots:Ocr optionally enables vision extraction for screenshots. Blank Endpoint or Model values fall back to the summary Agent endpoint and model. Key or KeyEnv can be set specifically for OCR; otherwise the summary agent key configuration is used. Automatic summarization scans the meeting note for user-added Obsidian image embeds such as ![[whiteboard.png]] and Markdown image embeds such as , adds resolvable local images to the assistant context without copying them or changing the meeting note, runs OCR without crop or attendee updates, and waits for all pending OCR work to complete or hit Timeout before the assistant context moves to summarizing. Failed or timed-out screenshot OCR writes a retry link that targets /meetings/screenshot-ocr/retry with the exact saved screenshot and OCR block id.
| Setting | Purpose |
|---|---|
Enabled |
Sends screenshots to the OCR/vision model when true. |
Endpoint |
Optional OpenAI-compatible Responses endpoint override. |
Key |
Optional inline API key. Prefer KeyEnv. |
KeyEnv |
Environment variable name for the OCR API key. |
Model |
Optional OCR model override. Blank falls back to Agent:Model. |
Prompt |
OCR instruction prompt. The default asks for visible speakers/presenters, slide text as markdown, diagrams as Mermaid, scene descriptions, participant certainty, attendee metadata, and presentation/shared-screen crop coordinates when confidently isolatable. |
Timeout |
Maximum time to wait for OCR before summarization continues. |
Agent And Summary
Agent configures the Microsoft Agent Framework summary pipeline. Key may be set directly for local testing, but KeyEnv is preferred; by default the API key is read from LITELLM_API_KEY.
| Setting | Purpose |
|---|---|
Endpoint |
OpenAI-compatible endpoint base URL. |
Key |
Optional inline API key. Prefer KeyEnv. |
KeyEnv |
Environment variable name for the agent API key. |
Model |
Model id sent to the endpoint. |
UseStreaming |
Uses the Responses SSE transport when true (the default); uses the non-streaming Responses transport when false. |
EnableThinking |
Enables reasoning options in requests when supported by the model/backend. |
ReasoningEffort |
Reasoning effort: None, Low, Medium, High, or ExtraHigh. |
ReconnectionAttempts |
Retry count for transient model endpoint failures. |
ReconnectionDelay |
Delay between retry attempts. |
ContextWindowTokens |
Estimated context-window size used by compaction decisions. |
MaxOutputTokens |
Maximum output tokens for agent responses. |
EnableCompaction |
Enables conversation compaction before requests exceed the configured context budget. |
CompactionRemainingRatio |
Remaining-context ratio that triggers compaction. |
ResponsesCompactPath |
Relative Responses compaction path, usually responses/compact. |
InitialPrompt |
Optional complete replacement for the default summary-agent system instructions. |
After transcription has fully finished, Meeting Assistant automatically runs the summary pipeline for the meeting. The summary agent writes the full markdown summary through write_summary and must provide a required oneliner value, which is stored in summary frontmatter and must not contain line breaks.
The built-in summary-agent instructions treat assistant context as persistent meeting-specific memory. When the agent encounters an unexpected problem, missing information, or an assumption while summarizing, it appends a concise note through write_context so later work on the same meeting can use that history. A configured Agent:InitialPrompt completely replaces the built-in instructions, so custom prompts must include equivalent guidance when this behavior is desired.
The summary agent can add and remove meeting-note attendees when transcript or OCR evidence is clear. It can override transcript speaker labels only when the evidence is very certain, and it can delete wrongfully matched identities. Final speaker identity learning and candidate updates run after the summary pipeline finishes so they use the summary-refined attendee list and any recorded speaker identity changes.
ContextWindowTokens, MaxOutputTokens, EnableCompaction, and CompactionRemainingRatio configure summary-agent context monitoring. Meeting Assistant estimates the outgoing Responses payload size, logs the estimated token count and remaining context, and compacts the conversation when only the configured remaining ratio is left.
Workflow Rules Editor
WorkflowRulesEditor configures the tray-launched Meeting Summary Agent window. Blank values inherit from Agent, so it uses the summarizer endpoint, key, model, Responses transport, reasoning, retry, output, and compaction settings unless explicitly overridden.
The overridable fields are Endpoint, Key, KeyEnv, Model, UseStreaming, EnableThinking, ReasoningEffort, ReconnectionAttempts, ReconnectionDelay, ContextWindowTokens, MaxOutputTokens, EnableCompaction, CompactionRemainingRatio, ResponsesCompactPath, and InitialPrompt.
The assistant can edit workflow rules, manage speaker identities, read and replace the local appsettings file, read this configuration document, search and read copied OpenSpec specs, inspect application logs, create/search/read/write project files, and post-process past meeting artifacts by listing recent summaries and reading, writing, or searching summaries, transcripts, meeting notes, and assistant context files. For artifact metadata repairs, it has frontmatter-specific write tools that preserve the markdown body.
When asked to fix or investigate a meeting or summary, the agent is instructed to treat the matching assistant context as meeting-specific memory and read it for clues about problems, missing information, assumptions, prior fixes, and conclusions. After completing a repair, it appends a concise record of its fixes and conclusions to that context for future work on the meeting. This meeting-memory guidance is appended to the effective interactive-agent prompt even when WorkflowRulesEditor:InitialPrompt is configured.
It also has in-process diagnostic tools that mirror the local HTTP diagnostics for health, recording status, current Outlook meeting lookup, recent speaker identity merging, workflow configuration reload, and ASR transcribe/diarize checks.
The search_spec and read_spec_file tools are scoped to the copied openspec/specs markdown tree. Spec files are copied into build and publish output through an MSBuild glob, so newly added folders under openspec/specs are included automatically.
Logs
The top-level Logging section is standard ASP.NET Core logging configuration and controls framework/console log levels, for example Logging:LogLevel:Microsoft.AspNetCore.
Independently from stdout and stderr redirection, Meeting Assistant writes an application-owned log under:
%TEMP%\MeetingAssistant\Logs\meeting-assistant.log
On startup it rotates the previous current file to meeting-assistant.log.1 and keeps up to .4. The tray-launched assistant reads and searches these current and rotated files. If another app instance or test host still has the file open, rotation is skipped and logging appends to the current file so startup is not blocked.
API
Api:PublicBaseUrl is used to build clickable local links, such as summary retry links in generated failure notes.