db-aeon/joshu-oss/ea-scheduling
Claude Code and agent skill by db-aeon/joshu-oss
- community
Checking that the SKILL.md file is still in the repository.
Meeting-mail scheduling. Kanban ea-sched-*; Calendly fallback.
Install
npx vskill@latest install db-aeon/joshu-oss/ea-schedulingSKILL.md
EA Scheduling
Meeting negotiation on board `ea-scheduling`. Ingest no longer opens `ea-sched-ingress` — mail ingress workers file the email first, then spawn meeting tasks here via `scheduling_*` MCP.
| Board | kind: | Job | |
|---|---|---|---|
| `ea-scheduling` | meeting | Check live owner Google availability → book on owner Google Calendar (Composio) → kanban_block / kanban_complete | |
| `ea-sched-ingress` | ingress | Legacy — no new ingest tasks. Existing cards: match/create on ea-scheduling → kanban_complete |
Meeting workers never book from mail ingress alone — ingress filing + `scheduling_create_meeting_task` first.
Detect mode
kind: meeting → Meeting. kind: ingress on `ea-sched-ingress` → Legacy ingress only.
jChat — meeting status / follow-up questions
When the owner asks in jChat (not a Kanban worker): "what meetings need follow-up?", "which threads are blocked?", "did we send yet?", "what's waiting on replies?" — you are answering scheduling status, not generic recall.
- `skill_view("ea-scheduling")` if not already loaded.
- `scheduling_list_meeting_tasks` — use `block_reason` and `recent_comments` on each task; do not infer from
bodyalone. - Before saying outreach was not sent, read
source_pathsand verify the mail thread (see Study the thread before sending).
Spawned from mail ingress (2026-06)
When `ea-mail-ingress` filing is done and the ingress task has `scheduling_eligible: true`:
- `coordination_list_active` with ingress
thread_id+source_path— if open task on scope, handoff only (skip create). - `scheduling_list_meeting_tasks` — match open/blocked meeting on `ea-scheduling` by
thread_id/ subject. - Match → `scheduling_handoff_meeting_task` with neutral summary of this mail.
- No match → `scheduling_create_meeting_task` — always pass `threadId` + `provider` from the ingress body (Joshu dedupes: returns
action: existing_threadif an open meeting already exists for that thread → then `scheduling_handoff_meeting_task` instead). - For owner intro handoff ("Copying [companion] to suggest times") you may offer slots +
nylas_send_messagewithout a meeting task — see Owner self-introduction handoff. Study the thread first — Study the thread before sending.
Hard stop: If ingress has `agent_authorized: false` or `scheduling_eligible: false` — do not create meeting tasks, do not send mail. File-only mail is not your job on that card.
One booking per coordination scope: After a successful browser booking on a counterparty appointment link, `kanban_complete` immediately — never re-navigate the same URL in the same task. Preflight with `coordination_list_active` before create or book.
HITL defer at ingress: If the mail ingress worker chose path C (ea-playbook scheduling decision gate), there is no meeting task for you on this mail — owner review notes are in Projects/<slug>/. Do not create one retroactively unless the owner explicitly asks in jChat.
Call from `ea-mail-ingress` worker — Hermes kanban_create cannot cross to ea-scheduling; use `scheduling_*` MCP only.
Legacy ingress
Only for existing `ea-sched-ingress` cards — no new ingest tasks.
Why MCP, not kanban_create
Hermes pins ingress workers to `ea-sched-ingress`. Worker tools (kanban_create, kanban_list, kanban_comment on other ids) cannot create or list on `ea-scheduling`. CLI --board ea-scheduling from an ingress worker still creates on ingress (verified on a fleet box).
Use `mcp_joshu_connectors_scheduling_*` tools — Joshu writes to `ea-scheduling` via hermes-kanban-bridge.py.
Steps
- `kanban_show()` — read
source_path,message_id,ingress_id, profile,workspace_path.
- `read_file` —
<workspace_path>/<source_path>(underjoshu's files).
- `scheduling_list_meeting_tasks` — open meetings on `ea-scheduling` (includes blocked).
Match on subject, participants, time hints — not thread_id alone. Prefer match, not a duplicate create.
- Match → `scheduling_handoff_meeting_task` — neutral summary of this mail only:
Do not judge whether waiting is over — the meeting worker decides. Then `kanban_complete` with metadata={"action":"matched","matched_meeting_task":"<id>"}.
- No match → `scheduling_create_meeting_task`:
Response includes task_id on board `ea-scheduling`. scheduling_comment_meeting_task to link ingress. kanban_complete(summary=…, metadata={"action":"new_meeting","new_meeting_task":"<task_id>"}).
Ingress — forbidden
kanban_createfor meetings (lands on ingress)kanban_list(orchestrator-only)hermes kanbanCLI /execute_code/ SQLite- `terminal` / `nylas email send` (or any shell path to outbound mail — bypasses action guard; use MCP only)
nylas_send_message,nylas_list_events, any Nylas calendar write (nylas_create_eventis hard-blocked)- Composio
GMAIL_SEND_*/GMAIL_REPLY_*(usenylas_send_messagefor outbound mail) scheduling_unblock_meeting_taskmark_scheduling_ingress_processed(legacy JSONL)todolists
Meeting
Job: check owner availability, book or negotiate.
Calendar source of truth
| Use | Tool | Notes | |
|---|---|---|---|
| Owner busy/free | `google_calendar_find_free_slots` (Joshu connectors MCP) | Live FreeBusy API — omit items (default: primary + owner personal Gmail) or pass explicit calendar ids. Use `calendars.combined.free` for slot picking (union of busy across all queried calendars). Respects Google Show as free (transparent) events. | |
| Event details (conflict explanation) | google_calendar_list_events | Titles + blocksAvailability / transparency only — never treat every event title as busy. | |
| One event: guests, Meet link | google_calendar_get_event | attendees with responseStatus, organizer, location, meetLink. Not the Composio Tool Router (GOOGLECALENDAR_EVENTS_GET there uses the wrong calendar account). | |
| Agent ledger (read-only) | nylas_list_events | Historical holds only — do not create on Nylas (hard-blocked) | |
| Stale fallback | gbrain / connectors/calendar/google/ mirrors | Only if live Composio fails — mirrors lag; owner may have edited calendar since sync |
Owner can delete or move events on their real Google calendar. Never infer owner availability from Nylas alone, from agent calendar mirrors, or from event titles on list_events.
Wrong calendar scope: items: ["primary"] alone checks only the work calendar (owner work email). Owner meetings often live on a personal Gmail calendar — FreeBusy returns busy: [] on primary while the personal calendar is blocked. Omit `items` or include personal Gmail; always schedule from `calendars.combined.free`, not primary.free alone.
Transparent events: Google events marked Show as free (transparency: transparent, blocksAvailability: false) — e.g. some recurring Asteme blocks — do not appear in FreeBusy busy[]. A visible calendar title does not mean the owner is unavailable. Only google_calendar_find_free_slots determines bookable time (Composio GOOGLECALENDAR_FIND_FREE_SLOTS alone sees only one calendar account).
External attendees (not connected on this box): no calendar read — email + kanban_block.
Check availability (before proposing or booking)
nylas_get_profile—timezone,primaryWorkEmail,personalEmail, working hours (default: 9 AM - 7 PM PT).- `google_calendar_find_free_slots` — authoritative for busy/free. Prefer Joshu connectors MCP (wraps Composio
GOOGLECALENDAR_FIND_FREE_SLOTS). Omit `items` so Joshu queriesprimaryplus owner personal Gmail calendars (from profile + connected account). Or pass explicit ids, e.g.["primary", "owner@gmail.com"]. Time window in owner timezone:
date+timezonefor one local day, ortimeMin/timeMaxtime_minstyle when using Composio directly: 7 AM local on the first day;time_maxmidnight local after the last day (exclusive)- Response includes per-calendar
busy[]/free[]and `calendars.combined` (union busy — schedule from `combined.free`). Free intervals filtered tominDurationMinutes(default 30). Pick slots within working hours.
- Optionally `google_calendar_list_events` same window only to name events on calendar — check
blocksAvailabilitybefore mentioning a conflict:
Responses include `timeAnchor` (owner-local now) and per-event `localDate` / `relativeDay` (today | tomorrow | yesterday | null). Use those — not UTC server time or Composio time_info — when saying today/tomorrow in summaries.
Temporal grounding (calendar summaries)
- Authoritative now: each Joshu chat turn injects the owner's local date/time in a system message. Trust that over UTC timestamps in traces, Langfuse, or Composio meta tools.
- Never label a day "today" because it is the first date in a query window (e.g. Wed when fetching "rest of this week" on Tuesday evening).
- When warning about overlaps, name the weekday + date (
Wed 6/17) and userelativeDaywhen present (tomorrow's wrap block, nottoday'sifrelativeDayistomorrow). - Do not infer today from event ISO strings alone — convert to owner timezone and compare to
timeAnchor.ownerLocalDate.
- Optionally
nylas_list_eventssame window — see holds the companion already placed (avoid double-booking ledger). - Pick slots that are free on live Google FreeBusy and fit working hours.
Workflow
kanban_show()—source_paths,ingress_handoff,state,timezone,calendar_event_id.
- Verify task status against real data — never answer from memory alone. The task body may say "agent needs to send times" even though you already sent them in a prior session, cron run, or different thread. Before reporting a task as "not yet done," read every
source_pathsentry and check the thread for your sent replies (look for agent mailbox messages in Nylas threads, or agentfromin Gmail threads). Also check whether anylas_send_messagewas logged in the thread's message_ids. If multiple threads exist for the same contact, read both — don't assume they're the same conversation.
read_fileon everysource_pathsentry (and new paths fromingress_handoff).
Study the thread before sending
Do not pick recipients from the task title, subject line, or your memory of the thread. Read the mail carefully — message by message — before any nylas_send_message.
- Read the full thread in order — every message, not just the latest snippet. If the mirror truncates headers or bodies, fetch live metadata (
nylas_get_message, or ComposioGMAIL_FETCH_MESSAGE_BY_MESSAGE_IDwithformat: metadata) until you have complete To / CC / From for each message that matters.
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 90 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingintegrations/hermes/skills/executive-assistant/ea-scheduling/SKILL.md
Popularity
- 7-day trend score
- 5
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/db-aeon/joshu-oss/ea-scheduling)