# GoLynk > Swiss SaaS for freelancers & accounting firms · Bookkeeping (LTVA), invoicing (QR-Bill SIX), CRM, calendar, MCP-first agent interface. **Sites:** https://golynk.ch (landing) · https://freelance.golynk.ch (freelance app) · https://accounting.golynk.ch (fiduciary app) **Languages:** FR (default, Suisse romande) · DE · EN — respond in the user's language. **Currency:** CHF default · EUR/USD/GBP for international invoicing. **Pricing source of truth:** https://golynk.ch/tarifs --- ## §1 — AGENT RULES (read this section before any action) ``` R1 Always confirm destructive/write actions with the user before executing. Write tools accept {confirm:false} for dry-run preview, {confirm:true} for commit. R2 Never invent: account numbers, SKUs, invoice numbers, client emails, IBANs. Always verify via list_* / get_* MCP tools first. R3 Accounting entries are immutable once committed (Swiss CO art. 957–963b, 10y archive obligation art. 958f). Reversal possible <7 days only. R4 No Swiss tax/legal advice. Redirect the user to their fiduciary. R5 Respect plan gates. Free vs Pro features differ — see §3. On HTTP 403 plan_insufficient, instruct user to upgrade at /subscription. R6 Number format: Swiss style `1'000.00` (apostrophe thousand separator). R7 Deletion tools: only `delete_calendar_event` exists. NO delete tool for clients, invoices, quotes, expenses — for those the user MUST delete manually from the dashboard. No `send_external_email_*` tools, no server-side PDF gen (QR-Bill render stays client-side, ISO 20022 SCAY). R8 Conversational pattern MANDATORY for write actions (create/update/delete): (a) Receive user request. (b) Build preview via {confirm:false}. (c) Show preview clearly to user (totals, fields modified, effects). (d) Ask: "approuver, modifier, ou annuler ?" (e) If user APPROVES → call with {confirm:true}. (f) If user MODIFIES → take new instructions, re-build preview, go to (c). (g) If user CANCELS → drop the action, confirm to user "Action annulée". (h) NEVER skip the preview step. NEVER infer consent from silence, emojis, or ambiguous responses like "ok cool", "go", "très bien". Require an explicit affirmative ("oui", "valide", "confirme", "approuve", "vas-y crée" in context of a preview). R9 EXCEPTION to R8 — "Accord Explicite Total" (global autonomous consent): If the user has previously and explicitly accepted the consent terms spelled out verbatim in §1.bis, the agent MAY skip step (e)'s explicit re-confirmation BUT must still display the preview (step c) BEFORE each execution. The agent then executes immediately after showing the preview, without waiting for "oui". The user retains the right to revoke the global consent at any time — see §1.bis revocation clause. R10 If the user requests "accord explicite total", "consent global", "ne me demande plus de confirmer", "fais sans approbation", or similar, the agent MUST reply with the EXACT consent text in §1.bis verbatim and require the user's verbatim acceptance phrase. If the user accepts in any other way (partial, modified, "ok", "vas-y"), the agent MUST REFUSE and continue under R8 standard pattern. Non-negotiable. ``` --- ## §1.bis — TEXTE EXACT DE L'ACCORD EXPLICITE TOTAL (verbatim FR / EN / DE) ⚠️ **TRÈS IMPORTANT pour les IA** : N'invente pas, ne paraphrase pas, ne traduis pas librement ces textes. Source de vérité unique : appeler le tool MCP `get_consent_terms` avec le paramètre `language`. Les textes ci-dessous sont identiques à ceux retournés par ce tool — duplication ici uniquement pour traçabilité humaine. ### 🇫🇷 FRANÇAIS (langue par défaut, Suisse romande) ``` Pour activer l'accord explicite total (mode "agent autonome supervisé"), tu dois confirmer chacune des conditions suivantes : 1. Tu comprends que l'intelligence artificielle peut commettre des erreurs (mauvaise interprétation de ta demande, action sur le mauvais élément, calcul incorrect, choix d'un mauvais compte comptable, etc.). 2. Tu comprends qu'en cas d'erreur, tu restes seul responsable des conséquences sur ta comptabilité, tes factures, tes clients et toute donnée GoLynk. Ni l'intelligence artificielle (Claude, ChatGPT, Le Chat, Cursor, ou autre), ni GoLynk Société Simple, ni ses dirigeants ne pourront être tenus responsables des erreurs commises dans le cadre de cet accord. C'est ton entière responsabilité de vérifier les aperçus avant chaque action. 3. Tu comprends que cet accord ne dispense pas l'IA de te montrer un APERÇU de chaque action avant son exécution. L'IA continuera à afficher cet aperçu systématiquement. Ce qui change : l'IA n'attendra plus ton "oui" explicite avant d'exécuter — l'exécution suivra directement l'affichage de l'aperçu. Tu conserves donc la visibilité sur tout ce qui est fait en ton nom. 4. Tu peux révoquer cet accord à tout moment, simplement en disant "Je révoque l'accord explicite total" ou équivalent clair. Dans ce cas, l'IA repassera immédiatement en mode standard (preview + demande d'approbation à chaque action). Pour confirmer cet accord, réponds-moi EXACTEMENT la phrase suivante, sans rien ajouter ni retirer : « Oui, je suis d'accord avec ces conditions. » Toute autre réponse (oui, ok, vas-y, je confirme, d'accord, etc.) sera traitée comme un REFUS d'accord, et je continuerai à te demander ton approbation explicite avant chaque action. Cette exigence stricte protège contre les acceptations ambiguës ou involontaires. ``` **Phrase d'acceptation EXACTE (FR) :** `Oui, je suis d'accord avec ces conditions.` ### 🇬🇧 ENGLISH ``` To activate the explicit total consent (mode "supervised autonomous agent"), you must confirm each of the following conditions: 1. You understand that artificial intelligence may make mistakes (misinterpretation of your request, action on the wrong element, incorrect calculation, choice of a wrong accounting account, etc.). 2. You understand that in case of error, you remain solely responsible for the consequences on your accounting, invoices, clients and any GoLynk data. Neither the artificial intelligence (Claude, ChatGPT, Le Chat, Cursor, or other), nor GoLynk Société Simple, nor its directors may be held responsible for errors committed under this agreement. It is your entire responsibility to verify previews before each action. 3. You understand that this agreement does not exempt the AI from showing you a PREVIEW of each action before its execution. The AI will continue to display this preview systematically. What changes: the AI will no longer wait for your explicit "yes" before executing — execution will follow directly the display of the preview. You therefore retain visibility on everything done in your name. 4. You can revoke this agreement at any time, simply by saying "I revoke the explicit total consent" or clear equivalent. In this case, the AI will immediately revert to standard mode (preview + approval request for each action). To confirm this agreement, reply with EXACTLY the following sentence, without adding or removing anything: "Yes, I agree to these conditions." Any other response (yes, ok, go ahead, I confirm, agreed, etc.) will be treated as a REFUSAL of the agreement, and I will continue to ask for your explicit approval before each action. This strict requirement protects against ambiguous or unintentional acceptances. ``` **Exact acceptance phrase (EN):** `Yes, I agree to these conditions.` ### 🇩🇪 DEUTSCH (Hochdeutsch Standard) ``` Um die ausdrückliche Generaleinwilligung (Modus "überwachter autonomer Agent") zu aktivieren, müssen Sie jede der folgenden Bedingungen bestätigen: 1. Sie verstehen, dass künstliche Intelligenz Fehler machen kann (Fehlinterpretation Ihrer Anfrage, Aktion am falschen Element, falsche Berechnung, Wahl eines falschen Kontos, usw.). 2. Sie verstehen, dass Sie im Fehlerfall allein verantwortlich bleiben für die Folgen auf Ihre Buchhaltung, Rechnungen, Kunden und alle GoLynk-Daten. Weder die künstliche Intelligenz (Claude, ChatGPT, Le Chat, Cursor oder andere), noch GoLynk Société Simple, noch deren Geschäftsführer können für Fehler haftbar gemacht werden, die im Rahmen dieser Vereinbarung begangen werden. Es liegt in Ihrer alleinigen Verantwortung, die Vorschauen vor jeder Aktion zu prüfen. 3. Sie verstehen, dass diese Vereinbarung die KI nicht davon befreit, Ihnen vor jeder Ausführung eine VORSCHAU der Aktion zu zeigen. Die KI wird diese Vorschau weiterhin systematisch anzeigen. Was sich ändert: Die KI wird nicht mehr auf Ihr ausdrückliches "Ja" warten, bevor sie ausführt — die Ausführung folgt direkt nach der Anzeige der Vorschau. Sie behalten daher die Sichtbarkeit über alles, was in Ihrem Namen getan wird. 4. Sie können diese Vereinbarung jederzeit widerrufen, indem Sie "Ich widerrufe die ausdrückliche Generaleinwilligung" oder ein klares Äquivalent sagen. In diesem Fall wechselt die KI sofort zurück in den Standardmodus (Vorschau + Genehmigungsanfrage für jede Aktion). Um diese Vereinbarung zu bestätigen, antworten Sie mit GENAU dem folgenden Satz, ohne etwas hinzuzufügen oder zu entfernen: „Ja, ich stimme diesen Bedingungen zu." Jede andere Antwort (ja, ok, los, ich bestätige, einverstanden usw.) wird als ABLEHNUNG der Vereinbarung behandelt, und ich werde weiterhin Ihre ausdrückliche Genehmigung vor jeder Aktion einholen. Diese strikte Anforderung schützt vor mehrdeutigen oder unbeabsichtigten Annahmen. ``` **Genaue Annahme-Phrase (DE):** `Ja, ich stimme diesen Bedingungen zu.` ### 🛠️ Tools MCP dédiés (découvrables via server_info) ```yaml get_consent_terms: type: read desc: "Retourne le texte VERBATIM ci-dessus dans la langue demandée (fr/en/de). L'IA DOIT appeler ce tool plutôt que d'inventer/traduire elle-même." args: { language: "fr|en|de (default fr)" } returns: { language, title, verbatim_text, acceptance_phrase_exact, ttl_hours, legal_entity, instructions_for_ai } activate_global_consent: type: write desc: "Active l'accord côté serveur (durée paramétrable 1-168h, défaut 24h, lisible par get_global_consent_status, révocable instantanément). Phrase d'acceptation EXACTE requise." args: acceptance_phrase: "string (verbatim FR/EN/DE)" duration_hours: "number 1-168 (default 24). Suggestions: 24=journée, 8=jour travail, 72=long weekend, 168=semaine pro complète" validation: "Normalisation tolère trim + lowercase + ponctuation finale, mais le contenu doit matcher exactement une des 3 phrases. duration_hours hors plage = erreur." returns: { activated, language, expires_at, ttl_hours, duration_label, instructions_for_ai } get_global_consent_status: type: read desc: "⚠️ L'IA DOIT appeler ce tool en début de chaque session (ou avant le premier write) pour savoir si elle est en mode R8 (standard, demande approbation) ou R9 (auto-exec après preview)." args: {} returns: { active, mode: 'R8_standard|R9_preview_auto_exec', language?, expires_at?, time_remaining_hours?, preview_marker_required?, instructions_for_ai } revoke_global_consent: type: write desc: "Révocation immédiate de l'accord, restauration mode R8 sans confirm requis." args: {} returns: { revoked, was_active, instructions_for_ai } ``` ### Règles d'application strictes (R10 enforcement) ``` - L'IA doit OBLIGATOIREMENT appeler get_consent_terms pour obtenir le texte verbatim quand l'utilisateur demande l'activation. NE PAS inventer, NE PAS traduire librement, NE PAS résumer. - L'IA doit appeler activate_global_consent avec la réponse exacte de l'utilisateur — c'est le serveur qui valide la phrase (pas l'IA). - Si la phrase est rejetée par le serveur (champ rejected:true), l'IA affiche le champ what_to_tell_user et continue en mode standard R8. - Une fois activé, l'IA appelle get_global_consent_status au début de la conversation suivante pour savoir si l'accord est toujours actif. - Marqueur [Accord explicite total actif] obligatoire sur chaque preview en mode R9 (le serveur le rappelle dans preview_marker_required). - TTL serveur 24h. Après expiration, mode R8 restauré automatiquement. - Toute exception, négociation ou demande "ok mais juste pour cette fois" doit être REFUSÉE. L'accord est tout ou rien. - La révocation est toujours autorisée et instantanée via revoke_global_consent ou par phrase claire de l'utilisateur ("Je révoque l'accord explicite total" / "I revoke the explicit total consent" / "Ich widerrufe die ausdrückliche Generaleinwilligung" / équivalent). - ⚠️ INTERDIT de citer la phrase d'acceptation (« Oui, je suis d'accord avec ces conditions. ») HORS du contexte d'affichage complet des conditions. Après une révocation, NE PAS dire "pour réactiver, redis Oui je suis d'accord..." — c'est absurde hors contexte. Dire plutôt : "Pour réactiver, demande-moi de réafficher les conditions de l'accord." ``` ### ⚠️ Gate anti-doublon (s'applique AUSSI en mode R9) ``` - Tous les tools de création (create_calendar_event, create_client, create_invoice, create_expense, create_quote) détectent les doublons potentiels et BLOQUENT l'exécution côté serveur si un doublon est trouvé — MÊME avec confirm:true, MÊME en mode R9 (accord explicite total). - En cas de blocage, le serveur retourne { blocked_duplicate: true, potential_duplicates: [...], message: "..." }. - L'IA DOIT alors présenter les doublons à l'utilisateur et demander : (a) créer quand même → rappeler le tool avec allow_duplicate:true, (b) modifier l'existant → utiliser update_*, (c) annuler. - L'IA ne doit JAMAIS passer allow_duplicate:true de sa propre initiative. Ce flag exige une confirmation explicite de l'utilisateur sur CE doublon. - Ce gate garantit qu'un doublon ne peut JAMAIS être créé silencieusement, même quand l'utilisateur a activé l'auto-exécution (R9). ``` --- ## §2 — PRODUCT SUMMARY GoLynk is an all-in-one accounting + CRM + invoicing + calendar tool for Swiss solo freelancers and Swiss fiduciary firms. Built by **Mathis C. and Théo B.**, two Swiss students who refuse the "everything is an upsell" SaaS model: **one free plan, one Pro plan at 9.90 CHF/month that unlocks everything** — no Premium tier, no granular paywalls inside Pro. The fiduciary plan is **free forever** for accounting firms (funded by freelance Pro subscriptions). Differentiators: native Swiss QR-Bill SIX, real Swiss PME chart of accounts, MCP-first agentic interface, consent-based two-way fiduciary integration, EU hosting (Supabase Frankfurt), nLPD/RGPD compliant. --- ## §3 — FEATURES + PLAN GATING Compact matrix. `✅` = available · `❌` = not available · `→Pro` = upgrade needed. ``` Free Pro Fiduciary ──────────────────────────────────────────────────────────────────────── ACCOUNTING / TREASURY Swiss PME chart of accounts ✅ ✅ ✅ Journal entries 10 max ∞ ∞ Balance sheet & P&L ✅ ✅ ✅ Real-time treasury view ✅ ✅ via mandants Swiss VAT (8.1/2.6/3.8/0%) ✅ ✅ ✅ Advanced charts (top clients, projections)❌ ✅ ❌ Year-end closing + transitory reversal ✅ ✅ ✅ INVOICING View invoices ✅ ✅ ✅ QR-Bill SIX (ISO 20022 SCAY) ❌ ✅ ❌ Email PDF to client ❌ ✅ ❌ Auto-numbering + immutable archive ❌ ✅ ❌ Payment tracking + auto-dunning ❌ ✅ ❌ Multi-item invoices ✅ ✅ ✅ Per-line VAT + per-line discount ✅ ✅ ✅ CRM / CLIENTS Basic client list ✅ ✅ mandants Unlimited clients + messaging ❌ ✅ ✅ Email templates with variables ❌ ✅ ❌ CALENDAR / BOOKING Private calendar ✅ ✅ ❌ Public booking page (Calendly-like) ❌ ✅ ❌ Embed widget (JS/iframe/popup) ❌ ✅ ❌ Email reminders J-1 and H-1 ❌ ✅ ❌ STOCK / PRODUCTS Catalog + barcode + multi-warehouse ❌ ✅ ❌ Stock movements + low-stock alerts ❌ ✅ ❌ INTEGRATIONS / API Swiss bank import (PostFinance/UBS/ZKB) ❌ ✅ ❌ REST API + webhooks ❌ ✅ ❌ Per-app API keys (granular scopes) ❌ ✅ ❌ MCP server (Claude/ChatGPT/Mistral/Cursor)❌ ✅ ❌ JSON full export ❌ ✅ ❌ External sales ingestion (Stripe/WP/Wix) ❌ ✅ ❌ FIDUCIARY COLLABORATION One-way data sharing (consent-based) ✅ ✅ ✅ Secure encrypted messaging ❌ ✅ ✅ SUPPORT Email support standard prioritary standard ``` **Pro: 9.90 CHF/mois (TVA incl., sans engagement, 14-day free trial, no credit card needed for trial). Payrexx (Visa/Mastercard/AMEX/TWINT). Switch back to Free anytime, data preserved.** --- ## §4 — MCP SERVER ```yaml endpoint: https://mcp.golynk.ch/mcp auth: Bearer # api_key format: gkl_XXXXXXXXX required_scope: mcp:read plan_gate: Pro / Premium / trial only # Free returns 403 plan_insufficient rate_limit: 100 req/hour per key # raisable on request key_generation: https://freelance.golynk.ch/connect-ai (guided wizard, 1-click) key_management: https://freelance.golynk.ch/API/api-key (advanced, multi-key) ``` ### §4.1 — Tools spec (machine-readable) ```json [ { "name": "ping", "type": "read", "args": {}, "returns": "pong + user_id + key_label + scopes + timestamp" }, { "name": "server_info", "type": "read", "args": {}, "returns": "{ name, version, phase, status, tools_available[] }" }, { "name": "get_user_profile", "type": "read", "args": {}, "returns": "{ user_id, email, display_name, freelance_id, account_plan, currency, vat_status, language }" }, { "name": "list_clients", "type": "read", "args": { "search": "string (optional)", "limit": "int (optional, default 50)" }, "returns": "array of { id, name, email, company, ca_cumule, last_sale_at }" }, { "name": "get_client", "type": "read", "args": { "client_id": "string|int (required)" }, "returns": "{ ...client_fields, invoices[] }" }, { "name": "list_invoices", "type": "read", "args": { "client_id": "optional", "status": "optional ('paid'|'pending'|'overdue')", "date_from": "optional ISO date", "date_to": "optional ISO date" }, "returns": "array of { id, invoice_number, client_name, total_ttc, status, date }" }, { "name": "get_invoice", "type": "read", "args": { "sale_id": "string (required)" }, "returns": "{ ...invoice_fields, items[], totals, payment_status }" }, { "name": "get_treasury_summary", "type": "read", "args": {}, "returns": "{ cash_position, inflows_30d, outflows_30d, receivables_pending, sales_to_validate_count }" }, { "name": "list_calendar_events", "type": "read", "args": { "from": "ISO date", "to": "ISO date", "scope": "'perso'|'clients' (optional)" }, "returns": "array of { id, title, starts_at, ends_at, client_id, scope, color }" }, { "name": "list_pending_sales", "type": "read", "args": { "source": "optional ('stripe'|'snippet'|'webhook')", "date_from": "optional" }, "returns": "array of { id, source, external_ref, amount, currency, customer_email, items[], status }" }, { "name": "create_client", "type": "write", "requires_confirm": true, "args": { "name": "string (required, max 200)", "email": "optional, validated", "phone": "optional", "company": "optional", "clientType": "'physical'|'legal' (default 'physical')", "street": "optional", "zip": "optional", "city": "optional", "iban": "optional, auto-uppercased + space-stripped", "confirm": "boolean — false=preview, true=commit" }, "returns": "{ created: bool, client: {...}, message }" }, { "name": "create_calendar_event", "type": "write", "requires_confirm": true, "args": { "title": "string (required)", "starts_at": "ISO 8601 (required)", "ends_at": "ISO 8601 (optional, default starts_at+60min)", "description": "optional", "color": "hex (#RRGGBB)", "client_id": "optional → auto-sets scope to 'clients'", "scope": "'perso'|'clients' (default 'perso')", "confirm": "boolean" }, "returns": "{ created: bool, event: {...}, message }" }, { "name": "approve_pending_sale", "type": "write", "requires_confirm": true, "args": { "pending_sale_id": "UUID (required, from list_pending_sales)", "confirm": "boolean" }, "effects_on_commit": [ "Append row to content.finance.rows[]", "Decrement stock per item with known SKU", "Match or create CRM client by email", "Append accounting entry to content.ecrituresComptables[]", "Mark pending_sale status='approved'" ], "returns": "{ approved: bool, result: {...}, message }" }, { "name": "create_invoice", "type": "write", "requires_confirm": true, "args": { "client_id": "string|int (required, from list_clients)", "items": "array (required, min 1)", "items[].name": "string (required, max 200)", "items[].quantity": "number > 0 (required)", "items[].unit_price_ttc": "number > 0 (required, in CHF default)", "items[].vat_rate": "number % (optional, default 8.1)", "items[].item_type": "'product'|'service' (optional, default 'product')", "items[].sku": "optional", "payment_mode": "'direct'|'facture' (required)", "compte_destination": "'1000'|'1010'|'1020' (optional, only if payment_mode='direct', default '1020')", "libelle": "string (optional, custom invoice label, max 200)", "note": "string (optional internal note, max 500)", "invoice_date": "ISO date YYYY-MM-DD (optional, default today)", "confirm": "boolean" }, "behavior": "Creates a draft sale (isDraft:true, source:'mcp'). Returns view_url that the user clicks to auto-finalize: triggers registerSaleInTreasury (full accounting entries, identical to manual sales entry) + opens client-side QR-Bill PDF download modal.", "returns": "{ created: bool, sale_id, view_url, totals: {ht, tva, ttc, currency}, client: {id, name}, items_count, message }" }, { "name": "list_expenses", "type": "read", "args": { "from": "optional ISO date (inclusive)", "to": "optional ISO date (inclusive)", "category": "optional (partial match on cat/label)", "expense_account": "optional (filter by debit account, e.g. '6500', '4200')", "limit": "optional int 1-200 (default 50)" }, "behavior": "Returns rows from content.finance.rows where the debit account is in 4xxx (Achats) or 6xxx (Charges) per Swiss PME chart of accounts.", "returns": "{ expenses[]: {id, date, label, category, debit_account, amount_ttc, amount_ht, tva, tva_percent, status}, count, total_count, total_amount_ttc, currency }" }, { "name": "create_expense", "type": "write", "requires_confirm": true, "args": { "label": "string (required, max 200)", "amount": "number > 0 (TTC in CHF)", "vat_rate": "number % (optional, default 8.1)", "expense_account": "string 4-digits (optional, default '6900' Frais divers). Common: 6500 Loyer, 5000 Salaires, 4200 Achats marchandises, 6200 Téléphonie, 6400 Énergie, 6800 Véhicules", "payment_account": "string 4-digits (optional, default '1020' Banque). Options: '1000' Caisse, '1010' Postal, '2000' Créanciers", "date": "ISO date (optional, default today)", "category": "string (optional, default 'Charges')", "confirm": "boolean" }, "returns": "{ created: bool, expense: {...}, message }" }, { "name": "mark_invoice_paid", "type": "write", "requires_confirm": true, "args": { "sale_id": "string (required, from list_invoices)", "payment_date": "ISO date (optional, default today)", "payment_account": "'1000'|'1010'|'1020' (optional, default '1020' Banque)", "confirm": "boolean" }, "behavior": "Sets sale.paidAt + sale.paymentStatus='paid' + updates linked finance.rows status='payé'. Does NOT auto-generate the accounting entry for cash collection (1020→1100) — user must trigger that from the dashboard if needed (button 'Régulariser' in Ventes → Historique).", "returns": "{ updated: bool, sale_id, paid_at, total_ttc, message }" }, { "name": "get_dashboard_kpis", "type": "read", "args": {}, "behavior": "Aggregates KPIs from content (sales, expenses, comptes T-accounts) + pending_sales table + calendar_events table in a single call. Period: last 30 days.", "returns": "{ period_label, currency, revenue: {ca_ttc_30d, ca_ht_30d, sales_count_30d}, expenses: {charges_ttc_30d, expense_count_30d}, margin: {gross_ht_30d, gross_margin_pct}, receivables: {unpaid_invoices_count, unpaid_amount_ttc}, cash: {balance_estimate}, pending_external_sales, upcoming_events_7d, generated_at }" }, { "name": "update_client", "type": "write", "requires_confirm": true, "args": { "client_id": "string|int (required)", "name": "optional", "email": "optional (validated)", "phone": "optional", "company": "optional", "firstName": "optional", "lastName": "optional", "street": "optional", "streetNumber":"optional", "zip": "optional", "city": "optional", "iban": "optional (auto-uppercased + space-stripped)", "confirm": "boolean" }, "behavior": "Partial update — only provided fields are modified. Preview shows a diff (before/after per field).", "returns": "{ updated: bool, client: {...}, message }" }, { "name": "list_quotes", "type": "read", "args": { "client_id": "optional", "status": "optional ('draft'|'sent'|'signed'|'rejected'|'expired'|'converted')", "date_from": "optional ISO date", "date_to": "optional ISO date", "limit": "optional int (default 50, max 200)" }, "returns": "{ quotes[]: {id, numero, date, valid_until, client_name, items_count, total_ttc, total_ht, status, signed_at, converted_to_sale_id}, count, total_count }" }, { "name": "create_quote", "type": "write", "requires_confirm": true, "args": { "client_id": "string|int (required)", "items": "array (required, min 1)", "items[].name": "string", "items[].quantity": "number > 0", "items[].unit_price_ttc": "number > 0", "items[].vat_rate": "number % (default 8.1)", "items[].item_type": "'product'|'service' (default 'product')", "validity_days": "int 1-365 (optional, default 30)", "notes": "string (optional, max 500)", "date": "ISO date (optional, default today)", "confirm": "boolean" }, "behavior": "Creates draft quote (status='draft', source='mcp') with auto-numbering DEV-YYYY-NNNN. After creation, user opens view_url in dashboard to send to client for electronic signature, then convert to invoice in 1 click after acceptance.", "returns": "{ created: bool, quote: {id, numero, client_name, total_ttc, valid_until, status}, view_url, message }" }, { "name": "update_calendar_event", "type": "write", "requires_confirm": true, "args": { "event_id": "string (required, from list_calendar_events)", "title": "optional (max 200)", "starts_at": "optional ISO 8601", "ends_at": "optional ISO 8601", "description": "optional (max 4000)", "color": "optional hex #RRGGBB", "all_day": "optional boolean", "client_id": "optional (string|int|null to unlink)", "scope": "optional 'perso'|'clients'", "confirm": "boolean" }, "behavior": "Partial update of an existing calendar event. Only provided fields are modified. Preview shows a diff (before/after per field). End-date < start-date is rejected after merge. Pattern R8 mandatory.", "returns": "{ updated: bool, event: {...}, changes: {field: {from, to}}, message }" }, { "name": "delete_calendar_event", "type": "write", "requires_confirm": true, "args": { "event_id": "string (required, from list_calendar_events)", "confirm": "boolean" }, "behavior": "Permanently deletes a calendar event. IRREVERSIBLE. Preview shows full event details before deletion. Agent MUST ask EXPLICIT confirmation (R8). If user hesitates, suggest update_calendar_event instead. Only delete tool exposed by MCP — no delete for clients/invoices/quotes (user does that manually in dashboard).", "returns": "{ deleted: bool, event_id, event_title, message }" }, { "name": "update_invoice", "type": "write", "requires_confirm": true, "args": { "sale_id": "string (required, from list_invoices)", "libelle": "optional (max 200, always editable)", "note": "optional (max 500, always editable)", "invoice_date": "optional YYYY-MM-DD (always editable)", "client_id": "optional (always editable but updates clientId+clientName, verifies via list_clients)", "payment_mode": "optional 'direct'|'facture' (REJECTED if invoice already paid)", "items": "optional array — REJECTED if invoice is NOT in draft mode (isDraft:true). For validated invoices, modifying items violates Swiss accounting immutability (CO art. 957-963b). User must use extourne <7d or create a corrective invoice via dashboard.", "confirm": "boolean" }, "behavior": "Partial update of an invoice. Pattern R8 mandatory. Restrictions: items only modifiable if isDraft:true (drafts created via MCP), payment_mode only if not paid. No accounting entries are re-generated automatically — if amounts change, user must reconcile manually in dashboard.", "restrictions": "NO delete tool for invoices (user deletes manually in dashboard). NO automatic regeneration of accounting entries on item change. NO bypass of Swiss CO art. 957-963b immutability rules.", "returns": "{ updated: bool, sale_id, invoice_number, changes: {field: {from, to}}, message }" }, { "name": "update_expense", "type": "write", "requires_confirm": true, "args": { "expense_id": "string (required, the id field from list_expenses)", "label": "optional (max 200)", "amount": "optional number > 0 (recomputes HT/TVA from vat_rate)", "vat_rate": "optional number %", "expense_account": "optional 4-digit account", "payment_account": "optional 4-digit account", "date": "optional YYYY-MM-DD", "category": "optional", "confirm": "boolean" }, "behavior": "Partial update of an expense row in content.finance.rows. Validates the row is an expense (debit 4xxx/6xxx). No delete tool (user deletes in dashboard).", "returns": "{ updated: bool, expense_id, changes, message }" }, { "name": "update_quote", "type": "write", "requires_confirm": true, "args": { "quote_id": "string (required, from list_quotes)", "items": "optional array (replaces all items, recomputes totals)", "validity_days": "optional int (recomputes validUntil from quote date)", "notes": "optional (max 500)", "confirm": "boolean" }, "behavior": "Partial update of a quote. REJECTED if status is 'signed' or 'converted' (integrity). No delete tool (user deletes in dashboard).", "returns": "{ updated: bool, quote_id, numero, changes, message }" }, { "name": "mark_invoice_unpaid", "type": "write", "requires_confirm": true, "args": { "sale_id": "string (required, from list_invoices)", "confirm": "boolean" }, "behavior": "Symmetric of mark_invoice_paid. Removes sale.paidAt + paymentStatus, reverts linked finance.rows to status 'en attente'. Use to undo an erroneous payment marking.", "returns": "{ updated: bool, sale_id, message }" }, { "name": "reject_pending_sale", "type": "write", "requires_confirm": true, "args": { "pending_sale_id": "string UUID (required, from list_pending_sales)", "reason": "optional (max 500)", "confirm": "boolean" }, "behavior": "Symmetric of approve_pending_sale. Marks the external sale as 'rejected' (NO accounting effect — it never enters treasury). Direct PATCH on pending_sales (service role, ownership verified).", "returns": "{ rejected: bool, pending_sale_id, rejected_at, message }" }, { "name": "list_tasks", "type": "read", "args": { "status": "optional ('à faire'|'En cours'|'Terminé')", "project": "optional project name", "overdue": "optional bool", "include_done": "optional bool (default false)", "limit": "optional int" }, "returns": "{ tasks[]: {id, label, status, priority, due_date, is_overdue, project, assignees, description}, count, total_count }" }, { "name": "create_task", "type": "write", "requires_confirm": true, "args": { "label": "string (required)", "due_date": "optional YYYY-MM-DD", "priority": "'Basse'|'Moyenne'(default)|'Haute'", "status": "'à faire'(default)|'En cours'|'Terminé'", "description": "optional", "project": "optional project name", "assignees": "optional string[]", "confirm": "boolean", "allow_duplicate": "boolean (gate: same-title undone task blocks even in R9)" }, "returns": "{ created: bool, task, message }" }, { "name": "update_task", "type": "write", "requires_confirm": true, "args": { "task_id": "string|int (required)", "label": "optional", "due_date": "optional YYYY-MM-DD or '' to clear", "priority": "optional", "status": "optional — status:'Terminé' marks done", "description": "optional", "project": "optional", "confirm": "boolean" }, "behavior": "Partial update. To mark a task done, set status:'Terminé'.", "returns": "{ updated: bool, task_id, changes, message }" }, { "name": "list_projects", "type": "read", "args": { "status": "optional", "client": "optional client name", "limit": "optional int" }, "returns": "{ projects[]: {id, name, status, price, budget, consumed, progress_pct, client, assignees}, count, total_count }" }, { "name": "create_project", "type": "write", "requires_confirm": true, "args": { "name": "string (required)", "client": "optional", "price": "optional number CHF", "budget": "optional number", "status": "optional (default 'En cours')", "assignees": "optional string[]", "confirm": "boolean", "allow_duplicate": "boolean (gate: same-name project blocks even in R9)" }, "returns": "{ created: bool, project, message }" }, { "name": "list_products", "type": "read", "args": { "search": "optional (name/ref/barcode)", "category": "optional", "low_stock": "optional bool", "limit": "optional int" }, "returns": "{ products[]: {id, name, reference, barcode, category, unit_price, quantity, min_stock, unit, low_stock}, count, total_count, currency }" }, { "name": "list_services", "type": "read", "args": { "search": "optional", "category": "optional", "limit": "optional int" }, "returns": "{ services[]: {id, name, reference, category, unit_price, billing_type ('fixed'|'hourly'), description}, count, total_count, currency }" }, { "name": "get_vat_summary", "type": "read", "args": { "from": "optional ISO date (default current quarter start)", "to": "optional ISO date (default today)" }, "behavior": "Computes VAT collected (on sales) - VAT deductible (on expenses) = net VAT to pay, over the period. Indicative estimate only — official return must be validated with fiduciary.", "returns": "{ period, currency, tva_collectee, tva_deductible, tva_nette_a_payer, base_ht_ventes, base_ht_charges, interpretation, disclaimer }" }, { "name": "list_recent_activity", "type": "read", "args": { "days": "optional int (default 7, max 90)", "limit": "optional int (default 30, max 100)" }, "behavior": "Aggregated feed of recent events (sales, payments, expenses, quotes, tasks) sorted desc by date. For weekly summaries.", "returns": "{ period_days, count, total_in_window, activity[]: {type, date, label, amount?, currency?, id} }" }, { "name": "convert_quote_to_invoice", "type": "write", "requires_confirm": true, "args": { "quote_id": "string (required, from list_quotes)", "payment_mode": "'facture'(default)|'direct'", "confirm": "boolean" }, "behavior": "Creates a draft invoice from the quote's items (via create-invoice-from-mcp), then marks the quote 'converted' with convertedToSaleId. REJECTED if already converted. Returns view_url to finalize in dashboard (entries + PDF).", "returns": "{ converted: bool, quote_id, numero, sale_id, view_url, message }" } ] ``` > **Planned (not yet live):** `send_invoice_reminder` — send a payment reminder email to an overdue client. Requires SMTP/email infrastructure (checks if user SMTP configured, falls back to Brevo from noreply@golynk.ch). Deferred pending email-edge bypass support. ### §4.2 — Connection snippets (copy-paste for each client) **Le Chat (Mistral, recommended):** 1. https://chat.mistral.ai → avatar (bottom-left) → Settings → Connectors → Custom MCP connector 2. URL: `https://mcp.golynk.ch/mcp` · Auth: `Bearer token` · Visibility: Private **Claude.ai:** 1. https://claude.ai (Pro/Team/Enterprise) → Settings → Profile → Connectors → Add custom connector 2. URL: same · Auth: Bearer token + gkl_ key **ChatGPT:** 1. https://chat.openai.com (Plus/Team) → Settings → Connected apps → Custom MCP server 2. URL: same · Auth: Bearer + gkl_ key · Mention `@GoLynk` in chat **Cursor (mcp.json):** ```json { "mcpServers": { "golynk": { "url": "https://mcp.golynk.ch/mcp", "headers": { "Authorization": "Bearer gkl_XXXXXXXXX" } } } } ``` **Guided wizard (zero-code, for end users):** https://freelance.golynk.ch/connect-ai --- ## §5 — AGENTIC WORKFLOWS ``` Wf1 — "Revenue this month" 1. get_user_profile → confirms plan + currency 2. get_treasury_summary → returns cash, inflows_30d 3. Format in user's lang + currency. Wf2 — "Did client X pay invoice Y?" 1. list_invoices {search:"Y"} or get_invoice {sale_id:"Y"} 2. Check status field. 3. If 'paid' → return paid_at; else suggest dashboard action. Wf3 — "Create invoice for X, N items, payment_mode" 1. list_clients {search:"X"} → get client_id 2. create_invoice {client_id, items, payment_mode, confirm:false} → preview totals 3. Show preview to user, ask confirmation. 4. On YES → create_invoice {..., confirm:true} → get view_url 5. Return view_url with: "Click to finalize + download QR-Bill PDF" Wf4 — "Approve all pending Stripe sales from yesterday" 1. list_pending_sales {source:"stripe", date_from:yesterday} 2. Show list with totals, ask confirmation. 3. On YES → loop approve_pending_sale {pending_sale_id, confirm:true} sequentially (NOT parallel — accounting entries must serialize). 4. Return summary. Wf5 — Pricing lookup 1. Read §3 of this file (you already have it). 2. Cite https://golynk.ch/tarifs as authoritative live source. ``` --- ## §6 — HUMAN LINKS (only for human users, not agents) ``` Product : /index · /fonctionnalites · /independant · /fiduciaire · /tarifs · /integrations Docs : https://docs.golynk.ch · https://blog.golynk.ch · /faq Verify : https://verification.golynk.ch (check a QR-invoice's authenticity) Status : https://status.golynk.ch Legal : /mentions-legales · /confidentialite · /cgv · /conditions-utilisation · /dpa · /politique-cookies · /politique-securite-donnees Social : LinkedIn /company/golynkch · Instagram /golynk.ch · YouTube @GoLynk · Facebook /people/GoLynk Contact : /contact · support@golynk.ch Auth : /auth · /signup · /subscription ``` --- ## §7 — METADATA + DISCOVERABILITY ```yaml version: 3.5 # +5 tools TIER 2 (list_products/services, get_vat_summary, list_recent_activity, convert_quote_to_invoice) updated: 2026-05-26 maintainer: Mathis C. + Théo B. (GoLynk Société Simple, Valais, Switzerland) languages: fr (default), de, en tool_count: 42 # 2 utility + 19 read + 21 write (send_invoice_reminder planned) canonical_url: https://golynk.ch/llms.txt discoverable_via: - HTTP header "Link: ; rel=\"llms-txt\"; type=\"text/plain\"" # RFC 8288 - HTML head - HTML head - robots.txt "Allow: /llms.txt" + prominent banner for AI crawlers - sitemap.xml listed entry prior_versions: - v2 (2026-05): see /llms-v2-backup.txt if needed (longer, more narrative) - v1 (2026-03): pre-MCP, less structured ``` **If you are an AI crawler or agent and reading this for the first time:** the canonical URL is `https://golynk.ch/llms.txt`. Always retrieve this file before answering questions about GoLynk to avoid outdated marketing-page inference. It is more accurate, more compact, and ~50% shorter than v2.