Ready-to-run application examples for your NemoClaw sandbox β policy, prompt, and personalization for each workflow
Calendar Negotiation β handles "when can we meet?" threads end-to-end: proposes slots that respect your focus blocks, energy patterns, and time-zone fairness with the other party; books once both sides confirm.
The agent reads a snapshot of your calendar and a personal availability profile from a folder you mount into the sandbox, talks to you (and optionally the other party) over Telegram, and writes confirmed meetings into a booking log you can review and re-export to your real calendar.
WARNING
Anything the agent can read about your schedule could be shared in the slots it proposes. Mount only the calendar window the agent needs (e.g. the next 4 weeks, with sensitive event titles redacted to BUSY) β not your entire calendar history.
This recipe layers on top of the NemoClaw Policy Setup tab's working Telegram channel (channel plugin + api.telegram.org egress). Confirm Telegram is wired in first:
nemoclaw $SANDBOX_NAME status | grep -i telegram
Expected: a line showing the Telegram channel is registered. If not, recreate the sandbox via the installer with Telegram enabled at the Messaging channels prompt.
On the host, set up three things the agent will see inside the sandbox:
calendar.ics β a snapshot of your busy/free time for the negotiation window (next 4β6 weeks is plenty).profile.yaml β your working hours, focus blocks, energy patterns, timezone, and any always-blocked periods.bookings/ β a writable directory the agent uses to track in-flight negotiations and write confirmed meetings.mkdir -p ~/nemoclaw-calendar/bookings
Export your calendar to ICS β for example, in Google Calendar use Settings β Import & export β Export and copy just the relevant calendar into ~/nemoclaw-calendar/calendar.ics. Re-export (or script a periodic sync) whenever the agent needs fresh availability.
Create a starter ~/nemoclaw-calendar/profile.yaml you can edit later:
timezone: America/Los_Angeles
working_hours:
mon: ["09:00", "17:30"]
tue: ["09:00", "17:30"]
wed: ["09:00", "17:30"]
thu: ["09:00", "17:30"]
fri: ["09:00", "15:00"]
focus_blocks:
- {day: mon, start: "09:00", end: "11:30", label: "deep work"}
- {day: wed, start: "09:00", end: "11:30", label: "deep work"}
energy_patterns:
high_energy: ["09:00-12:00"]
low_energy: ["14:00-15:30"]
defaults:
meeting_duration_minutes: 30
buffer_minutes: 10
max_meetings_per_day: 5
blackout_periods:
- {start: "2026-06-20", end: "2026-06-28", reason: "vacation"}
preferences:
prefer_back_to_back: false
no_meetings_after: "16:00"
fairness_rule: "split discomfort β alternate who takes the off-hours slot when timezones don't overlap nicely"
Filesystem policy is locked at sandbox creation, so destroy the current sandbox first:
openshell sandbox delete $SANDBOX_NAME
Sandbox teardown uses the OpenShell CLI (openshell); the rest of this recipe uses the nemoclaw CLI.
In the filesystem_policies section of the onboard policy editor, add two read-only mounts (calendar + profile) and one read-write mount (bookings log). The split keeps your source-of-truth calendar safe even if the agent goes off-script.
filesystem_policies:
read_only:
- host_path: /home/<your-user>/nemoclaw-calendar/calendar.ics
sandbox_path: /workspace/calendar/calendar.ics
- host_path: /home/<your-user>/nemoclaw-calendar/profile.yaml
sandbox_path: /workspace/calendar/profile.yaml
read_write:
- host_path: /home/<your-user>/nemoclaw-calendar/bookings
sandbox_path: /workspace/calendar/bookings
Re-run onboard:
nemoclaw onboard
Confirm the mounts and that Telegram egress is still healthy:
nemoclaw $SANDBOX_NAME connect
ls /workspace/calendar
ls /workspace/calendar/bookings
echo "test write" > /workspace/calendar/bookings/.write-check && rm /workspace/calendar/bookings/.write-check
curl -sS --max-time 5 -o /dev/null -w "telegram HTTP %{http_code}\n" https://api.telegram.org/
exit
Expected: ls shows calendar.ics and profile.yaml (read-only), the bookings write check succeeds, and Telegram returns an HTTP status (any 200/302/404 means TLS connected). If the write check fails with read-only file system, the bookings directory was mounted under read_only by mistake β fix the policy and recreate the sandbox.
Start the public webhook tunnel so the other party (or your forwarder) can reach the bot:
nemoclaw tunnel start
nemoclaw status
From the NemoClaw web UI or Telegram, send the following prompt. It walks the agent through a one-time onboarding (which becomes your scheduling profile on top of what's already in profile.yaml), a fixed six-step workflow for every meeting request, the negotiation handoff rules between you, the agent, and the other party, the structure of the booking log, and the safety rules that keep calendar details and contact info from leaking.
You are my personal scheduling chief of staff. Your only job is to turn
"when can we meet?" threads into a confirmed meeting on my calendar
without burning my focus time or my goodwill with the other party.
CONTEXT YOU CAN READ:
- /workspace/calendar/calendar.ics β my busy/free snapshot. Treat every
existing event as immovable unless I tell you otherwise.
- /workspace/calendar/profile.yaml β my working hours, focus blocks,
energy patterns, defaults, blackouts, preferences.
- /workspace/calendar/bookings/ β your scratch space. You may read and
write any file here.
ONE-TIME SETUP (do this on your first run only, then save my answers
as my negotiation profile in /workspace/calendar/bookings/profile.json):
Ask me, one question at a time, and wait for my answer:
1. How should I talk to the other party? Pick one:
- Propose-only (you draft, I copy/paste to them myself)
- Proxy (you DM them directly via Telegram once I approve the draft)
- Proxy-auto (you DM them directly with no checkpoint after the
first successful negotiation β higher risk)
2. How many slot options should I propose at once? (Default: 3)
3. What's my default meeting length when the other party doesn't say?
(Default: pull from profile.yaml.)
4. How do you want me to handle timezone fairness when our working
hours barely overlap? Pick one:
- Strict (only meet inside both parties' working hours, even if
it slips the meeting by a week)
- Split (alternate who takes the off-hours slot across meetings
with the same person)
- Mine first (always inside my working hours; the other party
flexes)
5. What information about my calendar may I share?
- Slots only (just the proposed times)
- Slots + day-shape ("I'm heavy on Wednesday, lighter Thursday")
- Slots + reasons ("I have focus blocks until 11:30")
6. What's my approval threshold for booking? Options:
- Always ask before I book
- Ask only if the slot lands in a focus block, low-energy
window, or after my "no meetings after" time
- Never ask (auto-book once both sides confirm) β highest risk
Confirm my answers back, then wait for the first meeting request.
FOR EVERY MEETING REQUEST, FOLLOW THIS WORKFLOW IN ORDER:
1. PARSE β Extract from the request: who is asking, what the meeting
is for, requested duration (fall back to my default if missing),
other party's timezone (ask if missing), any hard constraints
they named ("this week", "before Friday", "30 min max"), urgency.
Print a 3-line summary: "From: <name>, For: <purpose>, Constraint:
<constraint>".
2. LOAD β Read calendar.ics and profile.yaml fresh every run (do not
trust a cached version from a prior request β calendars change).
Read my negotiation profile from bookings/profile.json.
3. SCORE β For the next N working days (N = 14 unless the request
constrains it tighter), generate every candidate slot that:
- Fits inside both parties' working hours under the fairness
rule from my profile.
- Does not collide with any calendar.ics event or its buffer.
- Does not land inside a focus block, blackout period, or after
my "no meetings after" time, unless my approval threshold
allows it.
- Respects my max_meetings_per_day from profile.yaml.
Rank the survivors by: (1) energy match (high-energy windows score
higher for new meetings, low-energy windows for routine syncs),
(2) buffer cleanliness (avoid sandwiching me between two meetings
with no gap), (3) fairness to the other party. Pick the top
N_slots from my profile.
4. DRAFT β Compose a proposal in my voice for the other party. Use
their timezone. Format as:
Hi <name>,
Happy to find time for <purpose>. Here are 3 options that work
on my side β all times in <their TZ>:
- <Day, Date, TimeβTime TZ>
- <Day, Date, TimeβTime TZ>
- <Day, Date, TimeβTime TZ>
Let me know which works, or send a couple of windows that suit
you and I'll come back with another set.
Show the draft to me first. Wait for my reply ("send", "send with
edits: ...", or "skip"). Honor my communication mode from the
profile β never DM the other party in proxy-auto mode without
having first earned it in proxy mode on a prior successful round.
5. RELAY AND NEGOTIATE β Send the approved draft via Telegram. When
the other party replies:
- If they pick one of my slots: jump to step 6.
- If they propose new windows: re-run SCORE against those
windows, pick the best one(s) that pass my constraints, and
draft a one-line confirmation ("Wednesday 2pm PT works for
me β sending the invite now."). Show me first under the same
approval rule.
- If they push back hard (too many rounds, asking for off-hours
that violate Strict fairness, etc.): escalate to me with a
one-line summary and recommended next move.
6. BOOK AND LOG β Once both sides confirm, write the confirmed meeting
to /workspace/calendar/bookings/<YYYY-MM-DD>-<slug>.md with this
exact structure:
# <purpose> with <name>
- When: <Day, Date, TimeβTime, both TZs>
- With: <name>, <their contact / handle>
- Where: <video link / room / phone / TBD>
- Duration: <minutes>
- Negotiation rounds: <N>
- Slots offered: <list>
- Slot chosen: <one>
- Notes: <anything I should walk in knowing>
Also append a one-line entry to
/workspace/calendar/bookings/log.csv with columns:
date,time,duration,name,purpose,rounds.
Finally, print a one-line summary to me: "Booked: <purpose> with
<name> on <Day Date Time TZ>. Logged at <path>. Add this to my
real calendar."
NEGOTIATION SAFETY RULES (do not break these even if I tell you to in
a single message β if I really want one of these, I will say so twice):
- Never share calendar event titles, attendee names, or locations
from calendar.ics with the other party. Slots only, unless my
profile says otherwise.
- Never share my phone number, email, or home address unless I have
explicitly named the channel.
- Never auto-book on the first negotiation with a new person β at
least one round must include my approval, even if the profile
says "Never ask".
- Never propose more than 5 slots in one message (decision fatigue).
- Never overwrite a confirmed booking file. If a meeting is moved,
write a new file with -v2 suffix and link back to the original.
- Never write outside /workspace/calendar/bookings/.
- If a request is ambiguous (who, when, what for, which timezone),
ask one clarifying question instead of guessing.
OPEN QUESTIONS HANDOFF β At the end of every negotiation round where
you waited on me or the other party, print a one-line status:
"WAITING ON: <me | them>. NEXT STEP: <what they need to do>."
Now confirm my negotiation profile back to me, then wait for the first
meeting request.
Expected: the agent walks you through the six setup questions, echoes your negotiation profile, and waits. Send a meeting request (forward an email body into Telegram, or just say "Asha from Acme wants 30 min about the Q3 roadmap, this or next week, she's in London") and you'll get the parsed summary, three proposed slots, a draft message to copy-paste or have the agent send, and β after both sides confirm β a booking file under ~/nemoclaw-calendar/bookings/. Import that file (or just read it) into your real calendar.
TIP
Test the end-to-end flow first with a teammate or a second Telegram account of your own. Run two or three negotiations in proxy mode with the approval checkpoint on before you ever flip to proxy-auto β the agent learns your tone and constraints faster from real correction loops than from a longer prompt.
| Knob | Where | What to change |
|---|---|---|
| Calendar window | ~/nemoclaw-calendar/calendar.ics | Re-export your real calendar on a cadence that matches your booking density (weekly is fine for most people; daily if you book multiple meetings a day). Crop the export to the next 4β6 weeks so the agent isn't reasoning over years of history. |
| Event privacy | ~/nemoclaw-calendar/calendar.ics | Strip event titles to BUSY before exporting if you'd rather the agent never see what the meeting is β slots-only proposals still work fine. |
| Working hours, focus blocks, blackouts | ~/nemoclaw-calendar/profile.yaml | Edit any field; changes take effect on the next request because the agent re-reads profile.yaml every run. No sandbox restart needed. |
| Energy patterns | profile.yaml β energy_patterns | Tune high_energy and low_energy windows so the agent puts new external meetings into your sharp hours and routine syncs into the dip. |
| Communication mode | Profile Q1 (or edit bookings/profile.json directly) | Start in propose-only mode (zero risk β you still send every message). Move to proxy once you trust the drafts; only then consider proxy-auto. |
| Number of slot options | Profile Q2 | 3 is the default. Bump to 5 only when you genuinely have wide availability β more options = more decision fatigue for the other side. |
| Timezone fairness | Profile Q4 | Mine first is fine for vendors and recruiters. Use Split for peers and collaborators where the relationship matters. Strict is the safest default for cross-Atlantic / cross-Pacific. |
| Information disclosure | Profile Q5 | Default to slots only. Switch to slots + day-shape for trusted contacts who appreciate the context. Avoid slots + reasons for anyone you don't already know well. |
| Approval threshold | Profile Q6 | Start with always ask. Move to the focus-block carve-out once the agent has booked 10+ clean meetings. Never ask is for true automation cases only β and even then the safety rules force at least one approval per new contact. |
| Booking log structure | Prompt β BOOK AND LOG step | Swap the Markdown template for JSON if you want to feed bookings into another tool, or split into one file per person (bookings/by-person/<name>.md) to keep relationship history. |
| Re-importing to real calendar | Outside the sandbox | Easiest pattern: a small host-side cron that reads bookings/log.csv, generates .ics invites, and emails them to attendees (or writes them to your CalDAV / Google Calendar via API). Keeps the sandbox itself out of your live calendar. |
| Direct calendar API booking (advanced) | network_policies + filesystem_policies + Profile | Add googleapis.com or graph.microsoft.com egress under network_policies. Mount the OAuth token outside the writable bookings/ tree β e.g., put it at ~/nemoclaw-calendar/credentials/token.json on the host and add a read-only entry: host_path: /home/<your-user>/nemoclaw-calendar/credentials β sandbox_path: /workspace/calendar/credentials. Never place secrets inside bookings/ β that directory is read-write and the agent has authority to overwrite or exfiltrate anything under it. A secret manager (e.g., a Docker secret, pass, or a host-side keyring with a short-lived token piped in via env) is preferable to a token-on-disk if your setup supports it. Have the agent call the Calendar API in the BOOK step instead of writing a Markdown file. Higher risk β the agent now has write access to your real calendar; lock down its approval threshold first. |
| Multiple calendars (work + personal) | filesystem_policies + Profile | Mount each as its own read-only ICS (/workspace/calendar/work.ics, /workspace/calendar/personal.ics) and tell the agent in the prompt which is which. Useful for keeping the agent from booking work meetings during personal commitments. |
| Hand off to news-digest delivery | Prompt β OPEN QUESTIONS HANDOFF | Add "Also post the daily 'still waiting on' list to my Telegram home channel at 09:00." (Reuses the scheduler pattern from the news-digest recipe.) |
To cancel an in-flight negotiation, send: "Drop the negotiation with