
You will build a private assistant that does not quietly miss messages, expose raw business context, or act without approval. The result is an n8n AI assistant self hosted on a Mac mini that collects approved inputs, reasons with Claude, stores durable memory, and reports when a workflow goes quiet. In 2026, n8n Docs identifies the self-hosted AI Assistant as a preview that should run on the latest stable release with an isolated sandbox provider. This tutorial therefore treats the assistant as an operated system, not a single chat workflow. In 2026, SkillScope reported an 88.56% reduction in triggered over-privileged actions under fine-grained controls (SkillScope research paper). Expect a moderate build spread across several focused sessions, followed by a controlled observation period.
Self-hosting is worth the effort when an assistant must follow work across messages, mail, meetings, calls, and business systems without turning every piece of context into another cloud account. An n8n AI assistant self hosted on a Mac mini gives you control over ingestion, storage, credentials, approvals, and failure handling while still allowing selected prompts to reach Claude.
In 2025, Microsoft found that heavily messaged knowledge workers faced 275 meeting, email, or chat interruptions per day (Microsoft, Breaking Down the Infinite Workday). In 2025, the same report found that 60% of meetings were unscheduled or ad hoc, which explains why a useful assistant needs event-driven capture rather than a neat daily checklist.
This guide is for an owner or technical operator who can manage Docker, API credentials, and macOS permissions but wants a production-minded design: private access, read-only defaults, nightly memory, explicit approvals, open exports, and alerts for silent failures.
<figure> <style> .c1 { --surface:#fcfcfb;--ink-1:#0b0b0b;--ink-2:#52514e;--muted:#898781;--grid:#e1e0d9;--accent:#2a78d6;--accent-2:#1baf7a;--negative:#c05a3e; } .c1 text { font-family:system-ui, sans-serif; } @media (prefers-color-scheme: dark){ .c1 { --surface:#1a1a19;--ink-1:#ffffff;--ink-2:#c3c2b7;--muted:#898781;--grid:#2c2c2a;--accent:#3987e5;--accent-2:#199e70;--negative:#d0674a; } } </style> <svg class='c1' viewBox='0 0 560 380' role='img' aria-label='Donut chart showing that 60 percent of meetings were ad hoc or unscheduled and 40 percent were scheduled.'> <rect x='0' y='0' width='560' height='380' fill='var(--surface)'/> <text x='28' y='34' font-size='18' font-weight='700' fill='var(--ink-1)'>Scheduled Versus Ad Hoc Meetings</text> <text x='28' y='55' font-size='12' fill='var(--ink-2)'>Percent of meetings in the analyzed Microsoft population</text> <circle cx='175' cy='205' r='100' fill='none' stroke='var(--grid)' stroke-width='40'/> <circle cx='175' cy='205' r='100' fill='none' stroke='var(--accent)' stroke-width='40' stroke-dasharray='376.98 628.3' stroke-dashoffset='0' transform='rotate(-90 175 205)'/> <circle cx='175' cy='205' r='100' fill='none' stroke='var(--accent-2)' stroke-width='40' stroke-dasharray='251.32 628.3' stroke-dashoffset='-376.98' transform='rotate(-90 175 205)'/> <text x='175' y='198' text-anchor='middle' font-size='30' font-weight='700' fill='var(--ink-1)'>60%</text> <text x='175' y='220' text-anchor='middle' font-size='11' fill='var(--muted)'>ad hoc</text> <rect x='335' y='137' width='14' height='14' rx='2' fill='var(--accent)'/> <text x='360' y='150' font-size='13' fill='var(--ink-1)'>Ad hoc or unscheduled</text> <text x='515' y='150' text-anchor='end' font-size='16' font-weight='700' fill='var(--ink-1)'>60%</text> <rect x='335' y='197' width='14' height='14' rx='2' fill='var(--accent-2)'/> <text x='360' y='210' font-size='13' fill='var(--ink-1)'>Scheduled</text> <text x='515' y='210' text-anchor='end' font-size='16' font-weight='700' fill='var(--ink-1)'>40%</text> <text x='28' y='354' font-size='11' fill='var(--muted)'>Takeaway: most meetings were not planned in advance.</text> </svg> <figcaption>Source: Microsoft Work Trend Index, 2025.</figcaption> </figure><iframe width="560" height="315" src="https://www.youtube.com/embed/qil5iBwd0IA" title="Self-hosted n8n AI assistant overview" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>Key points: keep the Mac off the public internet; give each connector the smallest useful permission set; separate retrieval from action; make every proposed change auditable; and treat missed runs as incidents, not minor inconveniences.
A reliable n8n AI assistant self-hosted build needs a supported Mac, persistent storage, private-network access, an isolated execution sandbox, and deliberately scoped accounts before any workflow is imported. In 2026, Tailscale documents macOS Monterey 12.0 or later as the current client baseline, so compatibility is the first check.
Use an Apple Silicon Mac mini with wired Ethernet, enough free disk for the database, audio, exports, and multiple backup generations. Install a current macOS release, Docker Desktop or Docker Engine-compatible tooling, Docker Compose, the latest stable n8n image, PostgreSQL, and the sandbox provider required by the preview.
Prepare a Tailscale account, an Anthropic API account, a Microsoft tenant app registration, and credentials for each business platform. Create separate service identities where possible. Do not reuse the owner’s everyday Microsoft account, Apple login, or administrator shell for background automation.
Start with read-only mail, calendar, message, transcript, and business-record ingestion. Add drafting next. Add external writes only after the data model, approvals, alerts, and restore process have been tested together. The difficult part is not connecting nodes; it is proving that the assistant cannot act outside its assigned boundary.
The finished assistant will collect approved signals, turn them into linked memory and open loops, and prepare role-specific drafts without sending or changing anything on its own. In 2025, Microsoft measured 275 daily interruptions in heavily messaged work, so the architecture is designed to reduce context hunting rather than create another inbox (Microsoft Work Trend Index).
An inbound adapter reads iMessage locally, polls Microsoft Graph for mail and calendar changes, downloads call metadata or voicemail from the phone provider, and imports Omi transcripts. n8n normalizes each event into a common envelope containing source, source identifier, timestamp, people, company, project, text, attachments, and permission class.
A classifier decides whether the event is informational, a commitment, a financial signal, or a proposed action. Retrieval then loads relevant memory. Claude receives only the minimum context needed for the current task. The result is stored as a draft, summary, or proposed action; an approval node must release anything that changes an external system.
Raw archives, identity maps, original audio, message databases, credentials, approval history, and exports stay on the Mac or its encrypted backup. Claude receives selected text snippets, task instructions, and stable identifiers that do not expose more personal data than the task requires.
| Area | Common demo build | Private production build |
|---|---|---|
| Access | Public editor or webhook | Tailscale-only operator access |
| Memory | Chat history in one workflow | Relational records plus searchable semantic context |
| Permissions | Broad connector credentials | Read-only scopes and separate service identities |
| Actions | Model calls the tool directly | Draft, approval, execution, audit |
| Reliability | Error shown in execution view | Heartbeat, missing-run detection, restore drill |
| Portability | Vendor-specific state | JSON, Markdown, database dump, original media |
The security baseline is a private network, encrypted storage, isolated execution, least-privilege identities, and secrets that never appear inside workflow JSON. In 2024, Apple documented that M1-and-later devices use AES-256 in XTS mode for Data Protection encryption (Apple Platform Security, Data Protection overview).
Bind n8n and PostgreSQL to loopback or an internal Docker network. Reach the editor through Tailscale, not a router port-forward. Disable public webhook use unless a channel truly requires it; prefer outbound polling from the Mac.
Use Tailscale access rules so only named operator devices can reach the host. Do not grant the whole tailnet access to the database or Docker socket.
Put database passwords, the n8n encryption key, Anthropic credentials, and connector secrets in an environment file readable only by the service account. n8n credentials should reference encrypted credential storage rather than plain Set nodes. Run the AI sandbox separately from the main n8n process, with no access to the host filesystem except an explicit working directory.
Check FileVault status, active listeners, container networks, and file permissions before importing workflows.
bash fdesetup status lsof -nP -iTCP -sTCP:LISTEN docker compose ps docker network inspect assistant_private stat -f "%Sp %Su %Sg %N" .env
The expected state is simple: FileVault reports active, n8n is not bound to a public interface, PostgreSQL is visible only inside the private network, all core containers are healthy, and the environment file is readable only by the service identity.
| Problem | Cause | Fix | Verification |
|---|---|---|---|
| n8n opens from the public LAN | Host port bound to every interface | Bind to loopback and use Tailscale access | Repeat the listener check |
| Credentials break after restart | Encryption key changed or missing | Restore the original key from the secret store | Open and test an existing credential |
| Sandbox can read host files | Broad volume mount | Mount only a disposable work directory | Attempt a denied read outside the mount |
| Database accepts host connections | PostgreSQL port published | Remove the published port | Confirm only the Docker network can connect |
The Mac mini is ready when it boots securely, remains awake for scheduled work, runs automation under a dedicated account, and accepts operator access only over Tailscale. In 2026, Tailscale requires macOS 12.0 or later, so an older host should be upgraded before any service configuration (Tailscale macOS variants).
In System Settings → Users & Groups, create a standard account for the assistant. Give it no administrator rights for routine operation. Log into that account once so macOS creates its home folders, then install or authorize only the applications the workflows require.
Enable FileVault in System Settings Privacy & Security FileVault and store the recovery key outside the Mac. In System Settings Energy, prevent automatic sleep while the display may still turn off. Enable automatic restart after power failure when the hardware and power setup support it.
For any process reading Messages data, grant Full Disk Access only to the exact executable or launcher used by the service, not every terminal application on the machine.
Install Tailscale, sign in, approve the device, and assign a clear hostname. Restrict access with tailnet policy so only operator devices can reach the service. Verify from an approved device and again from a non-approved network path.
bash tailscale status tailscale ip ping assistant-mac
A passing result shows the Mac as connected, reachable through its private address, and unreachable through the router’s public address. Record the device approval owner and expiry policy in the runbook.
The core stack is complete when n8n, PostgreSQL, and the isolated AI sandbox start predictably, keep state across restarts, and expose health only through the private path. In 2026, n8n’s self-hosted Webhook node accepts 16 MB by default, so large audio or document payloads should be stored first and passed by reference (n8n Webhook documentation).
Use a small project directory with a Compose file, a protected environment file, a backup folder, and named volumes. Pin the exact n8n image digest after the preview works on the latest stable release; that gives you reproducible restarts without staying permanently on a moving tag.
yaml services: n8n: image: ${N8N_IMAGE} restart: unless-stopped env_file: .env ports: - "127.0.0.1:${N8N_PORT}:${N8N_PORT}" volumes: - n8n_data:/home/node/.n8n depends_on: postgres: condition: service_healthy networks: [assistant_private]
postgres: image: ${POSTGRES_IMAGE} restart: unless-stopped env_file: .env volumes: - postgres_data:/var/lib/postgresql/data networks: [assistant_private]
sandbox: image: ${SANDBOX_IMAGE} restart: unless-stopped read_only: true volumes: - sandbox_work:/work networks: [assistant_private]
networks: assistant_private: internal: true
volumes: n8n_data: postgres_data: sandbox_work:
Set N8N_ENCRYPTION_KEY, database credentials, editor base URL, execution mode, and log settings in .env. Use a long random encryption key and back it up separately; losing it can make stored credentials unusable.
Start the services and inspect logs for schema migrations, database readiness, and sandbox registration.
bash docker compose pull docker compose up -d docker compose logs --tail=all n8n postgres sandbox
Create a disposable credential and workflow, restart the stack, and confirm both remain. Then restart the Mac and confirm the stack returns without an interactive login dependency. Check that the editor is reachable through Tailscale and not from a public address.
<iframe width="560" height="315" src="https://www.youtube.com/embed/BkaCrG3xUYk" title="Deploying persistent n8n services" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>Claude is connected safely when the API key stays in encrypted credential storage, prompts contain only task-relevant data, and budget, timeout, retry, and rotation rules are enforced outside the model. In 2026, Anthropic recommends regular key rotation and gives 90 days as an example interval (Anthropic Support, API key best practices).
Create an Anthropic credential in n8n or inject the secret from an external secret source. Never paste the key into a Code node, prompt template, exported workflow, or execution sample. Limit access to the credential by project and operator role.
Use the Anthropic API documentation to select a supported model identifier. Keep the identifier configurable so model changes do not require editing multiple workflows.
Place a deterministic guard node before each model call. It should enforce allowed task type, maximum input size, approved data classes, model choice, and retry policy. Log request identifiers, token accounting, task category, and outcome, but not raw secrets or unnecessary personal content.
For this 2026 build, Anthropic documents a standard commercial retention period of 30 days, subject to account terms and feature-specific exceptions (Claude Platform Documentation, data usage). That makes local redaction and selective context assembly part of the design, not an optional privacy improvement.
Test with synthetic data that resembles a real message but contains no private record. Confirm the output schema, timeout path, retry path, and cost logging. Then revoke the test key, create a replacement, update the credential, and rerun the same workflow. A rotation procedure is not proven until the old key fails and the new key succeeds.

Each channel should enter through a read-only adapter that produces the same normalized event envelope and never exposes the Mac to unsolicited public traffic. For this 2026 build, Anthropic’s documented 30-day standard commercial retention window reinforces why raw channel archives should stay local and only selected text should reach the model (Claude Platform data-usage documentation).
The Messages database lives under the service user’s Library at ~/Library/Messages/chat.db. Grant Full Disk Access to the exact process that performs the read. Do not query the live database repeatedly from parallel workflows; copy it to a temporary read-only snapshot, then query the snapshot to avoid lock conflicts.
Store the message row identifier, chat identifier, sender handle, sent time, text, attachment references, and a content hash. The content hash prevents the same message from being re-imported after a restart.
Create a dedicated Microsoft Entra app and use Microsoft Graph authentication with delegated or application access chosen for the actual operating model. Begin with Mail.Read, Calendars.Read, User.Read, and offline_access where required. Avoid Mail.Send, calendar write scopes, directory-wide reads, and broad tenant consent during ingestion.
Poll for changes and store the Graph item identifier plus change token or modified timestamp. Verify with a test mailbox and calendar, then inspect the consent record in the tenant before connecting the owner’s account.
For Quo, formerly OpenPhone, prefer outbound API polling from the Mac when the account plan supports it. Pull call metadata, participants, disposition, voicemail references, and recordings into local storage. If the provider requires webhooks, terminate them at a small signed relay that stores no audio and lets the Mac pull events outbound.
Normalize phone numbers before identity matching. Keep the original provider identifier so retries cannot create duplicate calls or transcripts.
Nightly memory should convert raw conversations and records into searchable evidence, linked entities, and ranked commitments while preserving the original source for audit. For this 2026 build, Anthropic says Message Batches can reduce processing cost by 50%, with most batches finishing in less than one hour (Claude Platform Documentation, batch processing).
<figure> <style> .c4 { --surface:#fcfcfb;--ink-1:#0b0b0b;--ink-2:#52514e;--muted:#898781;--grid:#e1e0d9;--accent:#2a78d6;--accent-2:#1baf7a;--negative:#c05a3e; } .c4 text { font-family:system-ui, sans-serif; } @media (prefers-color-scheme: dark){ .c4 { --surface:#1a1a19;--ink-1:#ffffff;--ink-2:#c3c2b7;--muted:#898781;--grid:#2c2c2a;--accent:#3987e5;--accent-2:#199e70;--negative:#d0674a; } } </style> <svg class='c4' viewBox='0 0 560 380' role='img' aria-label='Lollipop chart showing a cost index of 100 for regular synchronous processing and 50 for Message Batches processing.'> <rect x='0' y='0' width='560' height='380' fill='var(--surface)'/> <text x='28' y='34' font-size='18' font-weight='700' fill='var(--ink-1)'>Relative Claude Processing Cost</text> <text x='28' y='55' font-size='12' fill='var(--ink-2)'>Nightly batch work compared with regular synchronous processing</text> <line x1='200' y1='95' x2='200' y2='290' stroke='var(--grid)' stroke-width='1'/> <line x1='330' y1='95' x2='330' y2='290' stroke='var(--grid)' stroke-width='1'/> <line x1='460' y1='95' x2='460' y2='290' stroke='var(--grid)' stroke-width='1'/> <text x='200' y='310' text-anchor='middle' font-size='11' fill='var(--muted)'>0</text> <text x='330' y='310' text-anchor='middle' font-size='11' fill='var(--muted)'>50</text> <text x='460' y='310' text-anchor='middle' font-size='11' fill='var(--muted)'>100</text> <text x='180' y='150' text-anchor='end' font-size='13' fill='var(--ink-1)'>Regular processing</text> <line x1='200' y1='145' x2='460' y2='145' stroke='var(--negative)' stroke-width='3' stroke-linecap='round'/> <circle cx='460' cy='145' r='7' fill='var(--negative)'/> <text x='478' y='150' font-size='16' font-weight='700' fill='var(--ink-1)'>100</text> <text x='180' y='240' text-anchor='end' font-size='13' fill='var(--ink-1)'>Message Batches</text> <line x1='200' y1='235' x2='330' y2='235' stroke='var(--accent-2)' stroke-width='3' stroke-linecap='round'/> <circle cx='330' cy='235' r='7' fill='var(--accent-2)'/> <text x='348' y='240' font-size='16' font-weight='700' fill='var(--ink-1)'>50</text> <text x='28' y='354' font-size='11' fill='var(--muted)'>Takeaway: batch processing halves the relative cost index.</text> </svg> <figcaption>Source: Claude Platform Documentation.</figcaption> </figure>Export or retrieve records from Omi’s documentation and account tools and place original transcript or audio files in dated local folders. Create an ingestion record before processing so a failed transcript can resume without duplicating the source.
Use local transcription for sensitive audio when possible. Store the transcript, speaker segments, language, source timestamp, and original-media path. For already transcribed Omi records, preserve the raw export beside your normalized copy.
Use PostgreSQL for canonical entities and a vector extension such as pgvector for semantic retrieval. Exact identifiers should win before similarity: normalized email, normalized phone, platform account identifier, and standardized address. Similarity can suggest a match, but ambiguous merges should enter a review queue.
Ask Claude for structured fields: commitment text, owner, counterparty, due date, amount, currency, project, evidence references, confidence, and status. Validate the returned structure before saving. If the model cannot point to source evidence, classify the item as an unverified suggestion rather than a commitment.
Use deterministic parsing for obvious dates and amounts, then let the model resolve context such as “after the inspection” or “send the revised scope.”
Rank with explicit business rules, not a vague importance score. Put overdue commitments first, then high-value unresolved items, then older items with repeated mentions, followed by routine follow-ups. The report should show why each item ranked where it did and link back to the supporting message, email, call, or transcript.
Business workflows should read broadly enough to prepare useful drafts but act only after a named approver releases a specific proposal. In 2026, the SkillScope evaluation reported an 88.56% reduction in triggered over-privileged agent actions when fine-grained controls were applied (SkillScope research paper).
<figure> <style> .c3 { --surface:#fcfcfb;--ink-1:#0b0b0b;--ink-2:#52514e;--muted:#898781;--grid:#e1e0d9;--accent:#2a78d6;--accent-2:#1baf7a;--negative:#c05a3e; } .c3 text { font-family:system-ui, sans-serif; } @media (prefers-color-scheme: dark){ .c3 { --surface:#1a1a19;--ink-1:#ffffff;--ink-2:#c3c2b7;--muted:#898781;--grid:#2c2c2a;--accent:#3987e5;--accent-2:#199e70;--negative:#d0674a; } } </style> <svg class='c3' viewBox='0 0 560 380' role='img' aria-label='Grouped bar chart showing a baseline index of 100 before privilege controls and 11.44 after privilege controls.'> <rect x='0' y='0' width='560' height='380' fill='var(--surface)'/> <text x='28' y='34' font-size='18' font-weight='700' fill='var(--ink-1)'>Fine-Grained Controls Reduce Excess Privilege</text> <text x='28' y='55' font-size='12' fill='var(--ink-2)'>Baseline index; lower is better</text> <line x1='70' y1='300' x2='520' y2='300' stroke='var(--grid)' stroke-width='1'/> <line x1='70' y1='245' x2='520' y2='245' stroke='var(--grid)' stroke-width='1'/> <line x1='70' y1='190' x2='520' y2='190' stroke='var(--grid)' stroke-width='1'/> <line x1='70' y1='135' x2='520' y2='135' stroke='var(--grid)' stroke-width='1'/> <line x1='70' y1='80' x2='520' y2='80' stroke='var(--grid)' stroke-width='1'/> <text x='60' y='304' text-anchor='end' font-size='11' fill='var(--muted)'>0</text> <text x='60' y='249' text-anchor='end' font-size='11' fill='var(--muted)'>25</text> <text x='60' y='194' text-anchor='end' font-size='11' fill='var(--muted)'>50</text> <text x='60' y='139' text-anchor='end' font-size='11' fill='var(--muted)'>75</text> <text x='60' y='84' text-anchor='end' font-size='11' fill='var(--muted)'>100</text> <rect x='140' y='80' width='110' height='220' rx='4' fill='var(--negative)'/> <text x='195' y='70' text-anchor='middle' font-size='16' font-weight='700' fill='var(--ink-1)'>100</text> <text x='195' y='325' text-anchor='middle' font-size='13' fill='var(--ink-1)'>Before controls</text> <rect x='340' y='274.832' width='110' height='25.168' rx='4' fill='var(--accent-2)'/> <text x='395' y='264' text-anchor='middle' font-size='16' font-weight='700' fill='var(--ink-1)'>11.4</text> <text x='395' y='325' text-anchor='middle' font-size='13' fill='var(--ink-1)'>After controls</text> <text x='28' y='354' font-size='11' fill='var(--muted)'>Takeaway: triggered over-privileged actions fell 88.56%.</text> </svg> <figcaption>Source: SkillScope research paper, 2026.</figcaption> </figure>self hosted ai personal assistant with private Mac hosting, nightly memory ingestion, and failure alerts.
Connect Roofr, Spotio, QuickBooks, CompanyCam, HailTrace, and OneClick Code through their supported APIs or exports, but begin with read-only credentials. Pull only the fields needed for the use case: lead status, estimate state, job photos, claim events, permit or code data, invoice status, and account balances.
Do not give the assistant payment, bank-change, user-administration, or delete permissions. Those capabilities do not belong in the same credential set as reporting.
Create separate outputs for owner, sales, production, and finance. The owner may receive cross-company exceptions; sales receives stale leads and draft follow-ups; production receives job blockers; finance receives receivables and reconciliation questions.
Role routing should happen after data validation and before any message draft is rendered, so one role never sees fields assigned to another.
Represent every side effect as a proposal with states such as proposed, approved, rejected, expired, executed, and failed. The approval must bind to the exact payload hash, destination, credential, and proposed action. Editing the draft creates a new proposal rather than silently changing an approved one.
Keep the assistant in approval mode throughout the initial operating period. Autonomy is earned by repeated evidence, not enabled because a demo looked correct.
Store proposal time, source evidence, model version, prompt version, approver, approval time, execution result, external record identifier, and rollback note. The log should answer who knew what, who approved what, and exactly what changed.
Operations are complete only when the system can detect missing work, restore its state, rotate credentials, and export the full corpus without vendor lock-in. In 2026, Tailscale documents a default node-key expiry of 180 days, which is one reason maintenance must run from a dated calendar rather than memory (Tailscale auth-key documentation).
<figure> <style> .c2 { --surface:#fcfcfb;--ink-1:#0b0b0b;--ink-2:#52514e;--muted:#898781;--grid:#e1e0d9;--accent:#2a78d6;--accent-2:#1baf7a;--negative:#c05a3e; } .c2 text { font-family:system-ui, sans-serif; } @media (prefers-color-scheme: dark){ .c2 { --surface:#1a1a19;--ink-1:#ffffff;--ink-2:#c3c2b7;--muted:#898781;--grid:#2c2c2a;--accent:#3987e5;--accent-2:#199e70;--negative:#d0674a; } } </style> <svg class='c2' viewBox='0 0 560 380' role='img' aria-label='Horizontal bar chart showing 730 days of QuickBooks audit-log availability, 180 days until default Tailscale node-key expiry, a 90-day Anthropic API-key rotation example, and 30 days of standard Anthropic commercial retention.'> <rect x='0' y='0' width='560' height='380' fill='var(--surface)'/> <text x='28' y='34' font-size='18' font-weight='700' fill='var(--ink-1)'>Security and Retention Intervals</text> <text x='28' y='55' font-size='12' fill='var(--ink-2)'>Days between reviews, expiry, rotation, or retained history</text> <line x1='170' y1='82' x2='170' y2='285' stroke='var(--grid)' stroke-width='1'/> <line x1='247.5' y1='82' x2='247.5' y2='285' stroke='var(--grid)' stroke-width='1'/> <line x1='325' y1='82' x2='325' y2='285' stroke='var(--grid)' stroke-width='1'/> <line x1='402.5' y1='82' x2='402.5' y2='285' stroke='var(--grid)' stroke-width='1'/> <line x1='480' y1='82' x2='480' y2='285' stroke='var(--grid)' stroke-width='1'/> <text x='160' y='105' text-anchor='end' font-size='13' fill='var(--ink-1)'>QuickBooks audit log</text> <rect x='170' y='90' width='310' height='20' rx='3' fill='var(--accent-2)'/> <text x='492' y='105' font-size='16' font-weight='700' fill='var(--ink-1)'>730</text> <text x='160' y='155' text-anchor='end' font-size='13' fill='var(--ink-1)'>Tailscale node key</text> <rect x='170' y='140' width='76.44' height='20' rx='3' fill='var(--accent)'/> <text x='258' y='155' font-size='16' font-weight='700' fill='var(--ink-1)'>180</text> <text x='160' y='205' text-anchor='end' font-size='13' fill='var(--ink-1)'>Anthropic key rotation</text> <rect x='170' y='190' width='38.22' height='20' rx='3' fill='var(--accent)'/> <text x='220' y='205' font-size='16' font-weight='700' fill='var(--ink-1)'>90</text> <text x='160' y='255' text-anchor='end' font-size='13' fill='var(--ink-1)'>Anthropic retention</text> <rect x='170' y='240' width='12.74' height='20' rx='3' fill='var(--negative)'/> <text x='195' y='255' font-size='16' font-weight='700' fill='var(--ink-1)'>30</text> <text x='170' y='305' text-anchor='middle' font-size='11' fill='var(--muted)'>0</text> <text x='247.5' y='305' text-anchor='middle' font-size='11' fill='var(--muted)'>182.5</text> <text x='325' y='305' text-anchor='middle' font-size='11' fill='var(--muted)'>365</text> <text x='402.5' y='305' text-anchor='middle' font-size='11' fill='var(--muted)'>547.5</text> <text x='480' y='305' text-anchor='middle' font-size='11' fill='var(--muted)'>730</text> <text x='28' y='354' font-size='11' fill='var(--muted)'>Takeaway: one maintenance cadence cannot cover every interval.</text> </svg> <figcaption>Source: Tailscale Docs (2026); Anthropic Support (2026); Claude Platform Documentation; Intuit QuickBooks Support.</figcaption> </figure>Each scheduled workflow should write a heartbeat containing workflow name, expected cadence, started time, completed time, input count, output count, last source cursor, and status. A separate monitor compares expected runs with observed heartbeats.
Use an n8n error workflow for execution failures and a separate silence detector for missed schedules. Send alerts through a channel independent from the failing connector. Include the workflow, failure stage, last successful cursor, affected data window, and safe retry instruction.
In 2026, Anthropic gives 90 days as an example key-rotation interval, while its commercial documentation states a standard 30-day retention period. Track both alongside the Tailscale expiry rather than treating “security review” as one generic task.
Back up PostgreSQL, n8n data, encryption keys, workflow exports, local media, entity maps, and configuration. Encrypt the backup and keep a copy away from the Mac. A backup is not accepted until a restore on a clean environment can open credentials, query memory, and rerun a synthetic workflow.
For this 2026 operating plan, Intuit documents QuickBooks audit-log events as available for two years (QuickBooks Online audit log). Preserve assistant audit records with a policy that supports the same review horizon where financial workflows are involved.
Export canonical records as JSON, human-readable summaries as Markdown, relational data as database dumps, and original recordings in their source format. Include a manifest mapping each export item to its source identifier and checksum.
The assistant passes only when every selected channel reaches memory, duplicates are prevented, approvals block all side effects, failures create alerts, and a clean restore reproduces the same evidence. In 2026, n8n still labels the self-hosted AI Assistant as a preview, so verification must cover the surrounding operating controls as well as the happy path (n8n preview setup documentation).
Send one synthetic event through each enabled channel. Confirm that the event arrives, receives a stable source identifier, is normalized once, and appears in the operator view. Pass only when every expected event appears exactly once and no connector requests a write scope.
Use a synthetic scenario spanning a message, email, calendar event, call note, and transcript that refer to the same person and project. Confirm that entity matching links them without merging an unrelated contact. The extracted commitment must cite its evidence and appear in the open-loops report.
Measure processing latency from source timestamp to stored result and compare it with the service objective agreed for that channel. Record the actual result rather than assuming “near real time.”
Stop a connector, revoke a test credential, make the sandbox unavailable, and interrupt the database path one failure at a time. Confirm that the expected error or missing heartbeat reaches the independent alert channel and that replay resumes from the last safe cursor.
A failure test passes only when no source event is lost, no duplicate side effect occurs, and the operator can follow the alert’s retry instruction.
Verify private-only access, FileVault status, secret-file permissions, credential scopes, sandbox mounts, disabled public ingress, approval enforcement, audit completeness, backup encryption, restore success, export readability, and key-rotation ownership.
Most self-hosted failures come from preview prerequisites, macOS permissions, connector consent, payload handling, or monitoring that watches errors but not silence. In 2026, n8n documents a 16 MB default webhook payload limit, so oversized recordings should be stored externally and passed into workflows by reference (n8n Webhook node documentation).
Confirm the latest stable n8n release, the preview configuration, and the isolated sandbox provider. Then inspect container logs and verify that the sandbox can be reached from n8n without gaining access to unrelated host paths.
Check consent, cursor state, polling schedule, and source filters before changing credentials. For iMessage, confirm Full Disk Access and snapshot the database before reading. For Microsoft Graph, verify the granted permission in the tenant rather than trusting the requested scope in code.
Inspect the source identifier, content hash, normalized email, normalized phone, and address standardization. Never solve duplicate entities by increasing similarity tolerance globally; add an alias, improve normalization, or send the ambiguous pair to review.
Confirm that the external heartbeat monitor expected the run and that the alert channel does not depend on the failed connector. Then inspect the last successful cursor and replay only the missing window.
| Problem | Symptom | Likely cause | Fix | Verification |
|---|---|---|---|---|
| Preview setup | Assistant panel never becomes ready | Missing sandbox or incompatible release | Correct the preview prerequisites | Preview loads and a synthetic prompt returns |
| Apple Silicon container | Service exits or restarts | Wrong image architecture or dependency | Use a compatible image and inspect the manifest | Container stays healthy after restart |
| Graph permissions | Sign-in works but data is empty | Consent missing or wrong tenant | Grant the minimum required read scope | Test mailbox data appears |
| iMessage access | Database read is denied | Full Disk Access missing | Authorize the exact process | Snapshot query succeeds |
| Transcript ingestion | Audio job stalls | Oversized inline payload | Store media locally and pass a path | Job completes from the stored object |
| Duplicate entities | One person appears twice | Identifier normalization mismatch | Merge through reviewed aliases | New events resolve to one canonical entity |
| Missed schedule | No execution and no error | Scheduler or host sleep | Correct startup and heartbeat monitoring | The next expected run records a heartbeat |
| Failed alert | Error exists but nobody is notified | Alert shares the failed dependency | Use an independent channel | Injected failure produces a visible alert |
The safest extensions are forecasting, read-only financial review, and approval-based replenishment because each can be useful without granting payment or account-control permissions. For this 2026 plan, Intuit says QuickBooks audit-log events remain available for two years, giving a defined evidence window for future monthly review (Intuit QuickBooks Support).
Use closed jobs, estimate revisions, labor, material cost, seasonality, and lead-source history. Keep forecasts separate from booked results and require backtesting against held-out periods before anyone uses them for staffing or purchasing.
Compare ledger activity, receivables aging, duplicate vendors, unusual category changes, and missing supporting records. Produce questions and evidence links, not journal entries.
Calculate proposed quantities from usage, open jobs, supplier lead time, and existing stock. Block payment methods, supplier-account changes, and unattended ordering. Every proposal should identify the source records and wait for a named approver.
A dependable assistant is defined less by its chat interface than by its boundaries: private access, local evidence, narrow credentials, explicit approvals, independent heartbeats, tested restores, and portable exports. In 2026, n8n still classifies the self-hosted AI Assistant as a preview, so the surrounding controls remain part of the product rather than optional polish. The n8n AI assistant self-hosted reference build shows how private Mac hosting, nightly memory ingestion, and failure alerts fit together.