If you work across both SMA and Moral Fabric, your colleagues in one org can't see your busy time in the other — even if you've shared the calendar across. This page explains why, and gives you a small Apps Script that mirrors events between the two so everything just works.
We tried meetergo and similar EU-native tools (Zeeg, Doodle, < Cal.com > hosted). All of them solve external booking pages well, but none of them fix the internal problem: when an SMA colleague does "Find a time" on you in Google Calendar, Google only checks your primary SMA calendar. Your MF events stay invisible. Same in reverse. The only fix is to make sure the events actually live in both calendars. Mirroring via Apps Script does that in ~30 lines, costs nothing, and means:
- 
Colleagues see you as "Busy" in free/busy lookups - 
Google's appointment booking pages on either side respect both calendars - 
Event details stay private to you (colleagues just see "Busy") - 
No per-user scheduling tool subscription
You need admin on both orgs, or someone who does, to enable cross-org sharing.
In each org's Admin console:
Apps → Google Workspace → Calendar → Sharing settings → External sharing options for primary calendars
Set to: (or "...but outsiders cannot change calendars" if you want safer — full details still show).
Changes can take up to 24h to propagate.
From your SMA Calendar:
- Settings → Settings for my calendars → [your SMA calendar] → Share with specific people or groups
- Add your MF email, permission:
- Click the "Add this calendar" link in the email that arrives at MF
Repeat the other way (MF calendar → SMA email).
You can now see both calendars in both accounts. But colleagues still can't — that's what the script fixes.
You'll create two Apps Script projects: one in each account. They each pull from the other calendar and mirror events into your primary, marked private so colleagues see "Busy" only.
New project → paste the code below
Edit the CONFIG block at the top
Save (Ctrl/Cmd+S)
Function dropdown: select syncCalendars → Run → authorize when prompted
Check execution log: should say "Synced N events"
Triggers (clock icon, left sidebar) → Add Trigger → syncCalendars, time-driven, every 15 minutes
Repeat in the account, swapping source/target IDs and the emoji prefix
const SOURCE_CALENDAR_ID = 'your-other-email@otherorg.com';
const TARGET_CALENDAR_ID = 'primary';
const MIRROR_TAG = 'ðŸ§';
function syncCalendars() {
const end = new Date(now.getTime() + DAYS_AHEAD * 24 * 60 * 60 * 1000);
const source = CalendarApp.getCalendarById(SOURCE_CALENDAR_ID);
const target = CalendarApp.getCalendarById(
TARGET_CALENDAR_ID === 'primary' ? Session.getActiveUser().getEmail() : TARGET_CALENDAR_ID
if (!source) throw new Error('Source calendar not found. Is it shared and added?');
if (!target) throw new Error('Target calendar not found.');
const existingMirrors = target.getEvents(now, end)
.filter(e => e.getTag('mirror') === 'true');
existingMirrors.forEach(e => e.deleteEvent());
const sourceEvents = source.getEvents(now, end)
.filter(e => e.getTag('mirror') !== 'true');
sourceEvents.forEach(e => {
if (e.getMyStatus && e.getMyStatus() === CalendarApp.GuestStatus.NO) return;
const title = `${MIRROR_TAG} ${e.getTitle()}`;
mirror = target.createAllDayEvent(title, e.getAllDayStartDate(), e.getAllDayEndDate(), {
description: e.getDescription(),
location: e.getLocation()
mirror = target.createEvent(title, e.getStartTime(), e.getEndTime(), {
description: e.getDescription(),
location: e.getLocation()
mirror.setTag('mirror', 'true');
mirror.setVisibility(CalendarApp.Visibility.PRIVATE);
mirror.removeAllReminders();
console.log(`Synced ${sourceEvents.length} events.`);
In the account that received the shared calendar:
Calendar → left sidebar → hover the shared calendar → three dots →
Scroll to "Integrate calendar" → copy the
Paste into SOURCE_CALENDAR_ID
If you ever want to undo all mirrors in this account:
function removeAllMirrors() {
const target = CalendarApp.getCalendarById(Session.getActiveUser().getEmail());
const start = new Date(2020, 0, 1);
const end = new Date(2030, 0, 1);
const mirrors = target.getEvents(start, end).filter(e => e.getTag('mirror') === 'true');
mirrors.forEach(e => e.deleteEvent());
console.log(`Deleted ${mirrors.length} mirror events.`);
Run it once → all script-created events disappear → your real events are untouched.
- 
or 
prefix tells you at a glance which org the event originated in - Colleagues only see "Busy" (visibility is set to Private per event)
- "Find a time" and Appointment Schedule conflict-checking now work properly
- Your own primary calendar view shows the full title with emoji prefix
- Only future 30 days are mirrored (configurable via
DAYS_AHEAD) - Recurring events get expanded into individual instances — fine for most cases
- Declined events are skipped
- Edits in the source propagate within 15 minutes
- Don't invite people to mirror events — they're regenerated every sync
- If you have very dense calendars (>1000 events), watch Apps Script quotas; usually fine
Internal "Find a time" works



(only fixes external booking) Privacy (event details hidden from colleagues)




Booking pages respect both calendars

(via Google's native tool) 

Round-robin / routing forms




Low — script runs itself
Low — but vendor lock-in
If you need round-robin or smart routing forms (lead qualification, multi-host distribution), a paid tool still makes sense. For most MF–SMA dual-hatters, the script covers it.
Questions or improvements? Ping Ruben.