schedule-meeting
Skill4 starsChanged 12 days agoMITView on GitHub
Handle recruiter / hiring-team scheduling threads — read the proposed slots, the candidate's timezone and availability, and any calendar context; draft a clear availability reply, prepare a calendar-ready hold, and write scheduling state back to the tracker. Confirm-first before any outbound reply or calendar write. Degrades to a draft-only workflow when no calendar connector is available.
6 other projects use a version of this.
Adopted by
Most recently taken up by
- Big-LAORE/Biblioth-que-de-skillstheir own version, first seen Nov 1, 2026
- dmzoneill/skillstheir own version, first seen Oct 24, 2026
- anthropics/knowledge-work-pluginstheir own version, first seen Oct 13, 2026
- ShenSeanChen/waku-agenttheir own version, first seen Oct 8, 2026
- swinton/skillstheir own version, first seen Jul 16, 2026
- tre-systems/office-assistanttheir own version, first seen Feb 16, 2026
Other versions6 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 6
- anthropics/knowledge-work-plugins★ 35ksame name
- ShenSeanChen/waku-agent★ 2ksame name
- dmzoneill/skills★ 2same name
- Big-LAORE/Biblioth-que-de-skills★ 1same name
- swinton/skills★ 1same name
- tre-systems/office-assistant★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository31 other files it gives its agents.
- AGENTS.mdAGENTS.md
- templates/AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- templates/CLAUDE.mdCLAUDE.md
- answer-questionSkill
- apply-jobSkill
- calendar-syncSkill
- coach-gapsSkill
- company-healthSkill
- configureSkill
- discover-companiesSkill
- email-commsSkill
- evaluate-jobSkill
- ingest-mailSkill
- ingest-messagesSkill
- ingest-profileSkill
- intake-extractSkill
- interview-prepSkill
- optimize-linkedinSkill
- reevaluate-strategySkill
- relationship-sourcingSkill
- report-issueSkill
- research-boardsSkill
- research-companySkill
- research-compSkill
- resume-extractSkill
- search-jobsSkill
- setup-searchesSkill
- sync-statusSkill
- tailor-applicationSkill
- track-outcomesSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
27 rules. 0 are common, 7 are distinctive, and 20 are very specific to this project.
0
Common
Most of the 6 edited versions we read keep these.
7
Distinctive
This author's own choices. Worth a look.
20
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Very specific: line 52
If the thread is actually general comms or a comp negotiation, stop and route to email-comms.
- Very specific: line 62
Mode detection: run careerrat data status.
- Very specific: line 67
Read workspace/tracker.json.
- Very specific: line 74
Legacy workspace (no DB): write the updated workspace/tracker.json directly.
- Very specific: line 88
If the thread is for a role but no applicationId is linked, confirm the role first.
- Very specific: line 94
Timezone: Read candidate/profile.yml#availability.timezone.
- Very specific: line 100
Availability: Read availability (working_hours, preferred_days, preferred_times, buffer_minutes, default_meeting_minutes, blackout, …
- Very specific: line 105
If the availability block is absent or thin, ask the user for their real availability once (which days/times work, meeting length, …
- Distinctive: line 111
Honesty (hard): never invent availability: Only propose windows the candidate's preferences or an explicit user confirmation support.
- Very specific: line 164
DB workspace: write via the owning verb, never by hand-editing generated tracker.json:
- Very specific: line 180
Legacy workspace (no DB): after writing, validate + snapshot (careerrat tracker --verify then careerrat tracker).
- Distinctive: line 215
Timezone clarity (hard): Every time you state carries an explicit timezone label, and when the counterpart's timezone is known, state both …
- Very specific: line 228
If saved to a file, run careerrat lint-placeholders <draft-path> before presenting.
- Distinctive: line 237
When a slot is settled (or proposed for the candidate's own hold), prepare a calendar-ready hold so it lands cleanly:
- Very specific: line 240
Always-available, dependency-free: write a valid .ics (VEVENT) to the company's Documents folder — …
- Very specific: line 253
Keep .ics content local (~/Documents/careerrat/ or workspace/).
- Very specific: line 302
(c-i): Add the applications[].conversations[] entry so it shows on the application timeline and feeds interview-prep:
- Very specific: line 333
If you don't know whether this is the first or a follow-on round, check conversations[] — if a prior entry exists with a kind matching an …
- Distinctive: line 337
DB workspace — (c-i)/(c-ii)/(c-iii) composition: No single verb covers all three, so compose, back-to-back in the same turn as (a)/(b):
- Very specific: line 365
Legacy workspace (no DB) — (c-i)/(c-ii)/(c-iii): add the conversations[] entry, advance applications[].status, and write the interview …
- Distinctive: line 377
(e) Out-of-band completion: If the user reports "I already confirmed / scheduled / rescheduled this" without the agent having sent the …
- Very specific: line 383
If a meeting was booked out-of-band, add the conversations[] entry (c-i) and advance applications[].status (c-ii) in the same write.
- Distinctive: line 387
Run verify + snapshot (STEP 7d).
- Very specific: line 429
Never invent availability: Only propose windows backed by the candidate's stated preferences or an explicit confirmation.
- Distinctive: line 432
Timezone clarity is mandatory: Every stated time is labeled with its timezone.
- Very specific: line 441
Degrade gracefully: No calendar connector → draft-only + an .ics hold the user imports by hand.
- Very specific: line 452
Domain-neutral: No hardcoded companies, names, or times.
“Common” is measured: kept by at least 6 in 10 of the 6 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
schedule-meeting
The focused scheduling skill for recruiter / hiring-team threads: "when can you talk?", "here are three slots," "can we move our call?". It owns the scheduling mechanics — timezone resolution, slot selection, double-booking avoidance, calendar-ready holds — and writes scheduling state back to the tracker.
Relationship to email-comms. email-comms remains the general written-comms surface
(replies, follow-ups, thank-yous, negotiation, cold outreach). Scheduling intent routes
here instead. If a thread turns out to be general comms or a comp negotiation rather than
scheduling, hand it back to email-comms. This skill draws on the same comms machinery
(thread match, style gate, message capture, activity logging) but adds the scheduling layer.
Runs under AGENTS.md. These contracts bind without being restated here: Privacy Invariant (
current_basenever outbound), Honesty Firewall, Placeholder/Bracket Ban, Gate Write-back, Domain-Neutral Rule, Browser Automation Contract, Activity Pulse logging, Tracker verify+snapshot, and Sent-Clears-Draft. Inline reminders at point-of-use are intentional; standalone restatements point back to the relevant AGENTS.md section. Barecandidate/,workspace/,config/, and.internal/paths below are symbolic; resolve them per AGENTS.md's Path Resolution rule.
Inputs
workspace/tracker.json—communications[]andapplications[]workspace/comms/<thread-id>.md— full raw thread body if previously savedcandidate/profile.yml—availabilityblock (optional),location.*(timezone fallback),authorization.notice_periodcandidate/writing-style.md(+workspace/writing-samples/) — voice/register- optional real free/busy —
workspace/tracker.json#calendarBusy[](opaque busy blocks ingested under thecalendar_readcapability), or a free/busy export the user provides - the inbound scheduling message OR the user's stated scheduling intent
Outputs
- a complete availability / confirmation reply (subject + body, no placeholders)
- an optional calendar-ready hold (
.ics) written to~/Documents/careerrat/ - updated
workspace/tracker.json—communications[].messages[]+ status, aapplications[].conversations[]entry when a meeting is booked, andinterviewAt/nextInterviewAt+interviewNoteon the application row - tracker snapshot checkpoint
STEP 0 — Classify the scheduling intent
| Intent | What it is | Sub-steps |
propose-availability | They asked when you're free; you offer windows | 1, 2, 3, 4, 5, 6, 7 |
accept-slot | They proposed slots; you pick/confirm one | 1, 2, 3, 4, 5, 6, 7, 8 |
reschedule | A booked meeting needs to move | 1, 2, 3, 4, 5, 6, 7, 8 |
send-scheduling-link | Share a self-serve link instead of trading slots | 1, 2, 3, 5, 7 |
If the thread is actually general comms or a comp negotiation, stop and route to
email-comms. If the intent is ambiguous, ask one clarifying question first.
This skill is user-initiated. It drafts and prepares; it never sends a reply or writes to an external calendar without explicit confirmation (see RULES).
STEP 1 — Match to tracker thread
Mode detection: run careerrat data status. Exit 0 → DB workspace — every
write step below gives the careerrat data <verb> command (Data Write Contract,
AGENTS.md). Nonzero exit → legacy workspace (no DB yet) — every write step below
gives the existing direct JSON-edit instructions, unchanged.
Read workspace/tracker.json. Find the communications[] record whose applicationId,
company + role, or threadId / subject matches the message. If none exists and this is
a real thread, create one (same shape as email-comms STEP 1: id, applicationId,
company, role, channel, status: "needs-reply", summary) and write it before
drafting. Don't draft against a thread that isn't recorded.
- DB workspace:
careerrat data comm upsert --data '<the new record JSON>'(full-row insert). - Legacy workspace (no DB): write the updated
workspace/tracker.jsondirectly.
STEP 2 — Load context
Read, before drafting:
workspace/comms/<thread-id>.md— prior exchanges, if saved.- The linked
applications[]row — role, stage, who you've spoken to (conversations[]), any artifacts. - The exact proposed slots / constraints in the inbound message (capture them verbatim — times, dates, duration, channel like phone / video / onsite, and the meeting purpose).
If the thread is for a role but no applicationId is linked, confirm the role first.
STEP 3 — Resolve timezone + availability (never invent availability)
Timezone. Read candidate/profile.yml#availability.timezone. If absent, derive the
candidate's timezone from location.home and state the assumption to the user. Determine the
counterpart's timezone from the thread (their signature, stated location, or an explicit
"PT/ET"); if unknown, either ask or proceed stating the candidate's timezone clearly and
offering to adjust.
Availability. Read availability (working_hours, preferred_days, preferred_times,
buffer_minutes, default_meeting_minutes, blackout, scheduling_link). These are
preferences, not a live calendar — they constrain which windows are reasonable to offer,
they do not assert the candidate is actually free.
If the availability block is absent or thin, ask the user for their real availability
once (which days/times work, meeting length, timezone), then — confirm-first — offer to
persist it to candidate profile config (availability) so future runs don't ask again.
In DB mode use careerrat data candidate patch profile --data ...; in legacy mode use
the guarded candidate-config write path. Echo the CLI confirmation.
Honesty (hard): never invent availability. Only propose windows the candidate's preferences or an explicit user confirmation support. If you cannot establish real availability, ask — do not guess a free slot.
STEP 3b: Ingest real free/busy (optional, calendar_read)
This is the concrete version of "calendar context": it lets the skill see the candidate's
actual commitments so it schedules interviews around them, and surfaces those windows on the
Calendar as opaque "Busy" blocks. It is optional — the skill is fully usable without it
(STEP 4 falls back to draft-only). Run it when the user wants you to schedule around their real
calendar, or whenever calendar_read is on (it is on by default).
Capability check. Free/busy ingestion runs only under the calendar_read capability:
careerrat automation status --jsonInspect capabilities.calendar_read. Platforms:
work_calendar— a work calendar already open in the session browser (e.g. the Chrome extension that holds the candidate's logins). The headline path for "schedule around my work meetings": no separate sign-in, you read what's already authenticated.apple_calendar/google_calendar/outlook_calendar— a personal calendar (for users who keep their availability there instead).
A platform is usable when its entry is allowed: true (neither the capability switch nor that
platform's switch is turned off). If the requested platform is not allowed, do not open any
calendar, tell the operator it is turned off, fall back to the draft-only path in STEP 4, and
give the enable commands (if readError is set, say the settings file can't be read and name it):
careerrat automation enable calendar_read --write
careerrat automation enable calendar_read <platform> --writeRead free/busy — read-only and opaque. Through the session browser (Browser Automation Contract applies: halt on login wall / 2FA / captcha / account-picker confusion):
- open the candidate's calendar across the scheduling window (the candidate set of days from STEP 4, plus the buffer);
- capture only the start and end of each busy block. Never read, infer, or store meeting
titles, attendees, locations, notes, or descriptions — that is the Privacy Invariant. Every
block is opaque; an all-day block is
allDay: true.
Persist as opaque busy blocks. Append to workspace/tracker.json#calendarBusy[]
(schema: id, provider, startIso, endIso, allDay, label — default "Busy",
source, ingestedAt). Dedupe on normalized provider + startIso + endIso. The label stays
"Busy"; never substitute the real meeting subject. These are a snapshot, not a live feed —
note when it was taken, and re-ingest before relying on it for a fresh decision.
DB workspace: write via the owning verb, never by hand-editing generated
tracker.json:careerrat data calendar busy --data '<JSON array of opaque blocks>' --source calendar_readA plain ingest only adds. To make it replace what you read, add
--window <startIso>..<endIso>for the span the calendar read covered: stored blocks overlapping that span are dropped first, so a cancelled or moved meeting goes away, and an empty array (--data '[]') records a free calendar.The verb stores
calendarBusy[]as top-level tracker state, dedupes onprovider + startIso + endIso, forceslabel: "Busy", stampsingestedAt, bumps meta, logs one activity event, and exports the generated legacy files.- Legacy workspace (no DB): after writing, validate + snapshot (
careerrat tracker --verifythencareerrat tracker); the Calendar then shows the windows as muted "Busy" blocks alongside actionable events.
STEP 4 — Resolve slots + avoid double-booking
Build the candidate set of proposed (or accepted) slots from STEP 2 + STEP 3, honoring
working_hours, preferred_days, buffer_minutes, and blackout.
Double-booking check — depends on calendar context:
- If
calendarBusy[](or a user-provided free/busy export) is available (from STEP 3b): exclude any slot that overlaps a busy block or violates the buffer around one. Use the most recent ingest; if the snapshot is stale, re-ingest or say so. Never assume a connector exists — check first. - If no calendar context is available: this is the draft-only path. You cannot verify conflicts, so do not assert hard availability. Either (a) propose the candidate's preference-backed windows and state plainly in the reply that they're subject to final confirmation, or (b) list the slots back to the user and ask them to confirm against their own calendar before the reply is sent. Tell the user the skill could not check their calendar — no silent assumption of freedom.
For accept-slot: pick the best offered slot under the same rules; if none work, propose
alternatives instead of forcing a bad fit.
STEP 5 — Draft the reply (timezone clarity is mandatory)
Apply the candidate/writing-style.md register (run npm run calibrate:style first if
writing-style.md is absent or older than newer workspace/writing-samples/). Mirror the
thread's tone.
Timezone clarity (hard). Every time you state carries an explicit timezone label, and when the counterpart's timezone is known, state both — e.g. "Thursday, June 19 at 2:00 PM ET (11:00 AM PT)". Never an unlabeled time. Spell out the date (day + date), not just "Thu 2pm". State the meeting length and channel (phone / video link / onsite) when known; don't confirm logistics that haven't been established.
Complete artifact, real names, no placeholders. Subject + body, ready to send. Sign with
the candidate's real name (profile.yml#candidate.preferred_name → full_name). Address the
recipient by their real name from the thread; if unknown, a natural greeting ("Hi,"). Never
emit a bracket token ([Name], [Time], [Company]) — brackets are a build failure, not a
TODO. For send-scheduling-link, share availability.scheduling_link with a one-line
invitation; do not also trade slots.
If saved to a file, run careerrat lint-placeholders <draft-path> before presenting.
Present the draft and the chosen slot(s) to the user and wait for explicit approval before anything is sent or written to a calendar.
STEP 6 — Prepare a calendar-ready hold (optional, confirm-first)
When a slot is settled (or proposed for the candidate's own hold), prepare a calendar-ready hold so it lands cleanly:
- Always-available, dependency-free: write a valid
.ics(VEVENT) to the company's Documents folder —~/Documents/careerrat/<Company>/job-<application-id>/<Company> - <Round> Invite.ics(per the Artifact Contract: organized by company, job, then round; real company name, no brackets) —UID,DTSTART/DTENDwith the correct timezone (or UTCZ),SUMMARY(e.g. "<Company>—<stage>with<who>"),DESCRIPTION(channel + dial-in/link if known), and aVALARMreminder. The user double-clicks it to add the hold. This is the degrade-gracefully default and needs no connector. - If a calendar connector / session is available and the user approves: you may additionally create the hold on their calendar. Writing to an external calendar is a confirm-first action — show what you'll create and wait for an explicit yes. Never create, move, or delete a calendar event silently.
Keep .ics content local (~/Documents/careerrat/ or workspace/). Never put
current_base or any private comp field in a hold.
STEP 7 — Capture scheduling state to the tracker
Execute in order:
(a) Append the reply to communications[].messages[] (same shape as email-comms STEP
6a): id, direction (outbound-draft until sent, then outbound-sent), at, from,
to, subject, summary, artifactPath.
Sent-clears-draft (hard). In the same write as flipping direction to outbound-sent:
set comm.draft = null (and app.followUp.draft = null if the reply was backed by one).
A partial write — messages[] updated but draft still set — leaves the "Ready to send" CTA
live after the reply has gone out.
- DB workspace:
careerrat data comm append-message <comm-id> --data '<message JSON above>'appends the message and auto-rollslastInboundAt/lastOutboundAtfromdirection. If this call flipsdirectiontooutbound-sentand the status is advancing towaiting, follow withcareerrat data comm mark-sent <comm-id> [--at <iso>]— it clearscomm.draft(andapp.followUp.draftwhen linked) automatically in the same transaction; do not hand-write that clear. For any other status target, use the read-patch-persist pattern in (b) below instead. - Legacy workspace (no DB): append to
communications[].messages[]directly inworkspace/tracker.json.
(b) Update the parent communications[] record in that same write:
status:scheduledonce a slot is agreed;waitingwhile awaiting their pick/confirm;needs-replyif the ball is back with the candidate.nextActionDue: null it first (the scheduling reply IS the expected event — it has occurred), then set a fresh value for the next expected event (e.g. +3 days for their confirmation, or ahead of the meeting for a pre-meeting reminder). Pattern: null → new value in one write. Never overwrite a livenextActionDuewithout nulling it first.nextAction: rewrite to reflect the new pending item, or clear it if none.lastOutboundAt/lastInboundAt.- DB workspace: there is no single-field patch verb for
communications[]beyondmark-sent's narrow send case (used in (a) above). Forstatus: scheduled/needs-reply, or to setnextActionDue/nextActionexplicitly, read the current row fromworkspace/tracker.json#communications[], apply the fields above (carrying every other field over unchanged), and persist the whole row:careerrat data comm upsert --data '<patched full comm row JSON>'. - Legacy workspace (no DB): edit the fields above directly on the communications record, in the same write as (a).
(c) When a meeting is BOOKED — do ALL of the following in the SAME write as (a) and (b):
(c-i) Add the applications[].conversations[] entry so it shows on the application
timeline and feeds interview-prep:
{
"date": "<ISO-8601 meeting datetime>",
"kind": "<recruiter screen | technical | hiring manager | onsite | ...>",
"who": "<interviewer / recruiter name>",
"notes": "<length, channel, timezone-confirmed slot, any prep notes>"
}Round kind values follow the canonical Round Vocabulary in AGENTS.md (never numbered); logistics/booking touchpoints (interview scheduling, recruiter call) are not rounds and keep their existing kinds.
(c-ii) Advance applications[].status to the matching stage (recruiter screen, technical,
onsite, etc.) in that same write. Do not defer this to STEP 8 — splitting the comm write and
the app write across steps leaves the app row at its old status with a ghost CTA. Both records
must land in one tracker.json write.
(c-iii) Write the structured interview datetime fields on the applications[] row — in the
SAME write as (c-i) and (c-ii). These fields drive the Focus card on the dashboard; without
them the booked interview never surfaces there.
- First round being booked → set
interviewAtto the ISO 8601 datetime string (e.g."2026-06-23T12:00:00-04:00"). Do not use the deprecatedinterviewDate. - Subsequent / follow-on round → set
nextInterviewAtinstead (it supersedesinterviewAton the dashboard). Do not use the deprecatednextInterviewDate. - Both cases → also set
interviewNoteto a ≤60-char logistics string:"<Round> — <Weekday> <DD-MM> <HH:MM> <TZ> with <First Name>"Example:"Onsite loop — Tue 03-10 14:00 PT with Alex Rivera"
If you don't know whether this is the first or a follow-on round, check conversations[] —
if a prior entry exists with a kind matching an interview stage, use nextInterviewAt; if
none, use interviewAt.
DB workspace — (c-i)/(c-ii)/(c-iii) composition. No single verb covers all three, so compose, back-to-back in the same turn as (a)/(b):
careerrat data app schedule-interview <id> --at <iso> --round "<kind>" --note "<interviewNote text>"In one transaction this sets
interviewAt(ornextInterviewAt, auto-detected from whether a futureinterviewAtalready exists — same "first round vs. follow-on" rule above), setsinterviewNote, and appends aconversations[]entry{date: at, kind: round, notes: note}— covering the bulk of (c-i) and all of (c-iii). It does not setwhoand reuses the same--notetext for bothinterviewNote(the ≤60-char logistics string) and the conversations entry'snotes(which wants the richer "length, channel, timezone-confirmed slot, prep notes" text) — those two fields want different content, so this verb doesn't map 1:1.- Patch the
whofield (and, if needed, a fullernotesstring) onto the conversations entryschedule-interviewjust appended: read the current row'sconversations[], update that one entry, then persist the whole array (wholesale array replace, same pattern astrack-outcomes' STEP 2 routing table):careerrat data app set-fields <id> --data '{"conversations":[...]}'. careerrat data app set-status <id> "<stage>"Advances
applications[].statusto the matching stage (recruiter screen,technical,onsite, etc.) — outcome-changing, refreshes analytics, and (since entering, not leaving, the interview band) never triggers the round-completion clearing.
Legacy workspace (no DB) — (c-i)/(c-ii)/(c-iii): add the conversations[] entry, advance
applications[].status, and write the interview datetime fields exactly as described above, all
in the SAME tracker.json write as (a) and (b).
(d) Validate + snapshot:
- DB workspace: the calls in (a)–(c) already persisted and auto-exported. Run
careerrat data verify(re-exports + domain integrity) andcareerrat tracker --verify(schema-level parity). - Legacy workspace (no DB):
careerrat tracker --verify(must exit clean), thencareerrat tracker.
(e) Out-of-band completion. If the user reports "I already confirmed / scheduled / rescheduled this" without the agent having sent the reply: record it immediately in the same single write — do not leave the CTA live because the agent did not perform the action.
- Append a
messages[]entry:direction: note,summarydescribing the user-reported completion (e.g. "User confirmed slot out-of-band: Thu Jun 26 2pm ET"). - If a meeting was booked out-of-band, add the
conversations[]entry (c-i) and advanceapplications[].status(c-ii) in the same write. - Set
comm.draft = null; nullnextActionDue, then set a fresh value if the next event is known; advancecomm.statustoscheduled/waitingas appropriate. - Run verify + snapshot (STEP 7d).
- DB workspace:
careerrat data comm append-message <comm-id> --data '{"direction":"note","at":"<ISO>","summary":"<user-reported completion>"}', then the same (c) composition above if a meeting was booked, then read-patch-persistcareerrat data comm upsert --data '<patched full comm row JSON>'fordraft/nextActionDue/status, then STEP 7(d)'s DB verify. - Legacy workspace (no DB): apply the bullets above directly in
workspace/tracker.json, then run STEP 7(d)'s legacy verify.
(f) Log to the Activity Pulse feed (see Activity Pulse in AGENTS.md). The reply is a draft awaiting send → log it as needing the user:
DB workspace: the (a)/(c) calls above already auto-logged their own generic events. For the richer, scheduling-specific type, log an additional event:
careerrat data activity append --data '{"type":"drafted","actor":"agent","needsUser":true,"title":"Scheduling reply — <Company>","summary":"<one line: proposed/confirmed slot>","refs":{"applicationId":"<application id>","company":"<Company>"},"cta":{"label":"Review & send"}}'Legacy workspace (no DB):
careerrat activity append --type drafted --actor agent --needs-user \ --title "Scheduling reply — <Company>" \ --summary "<one line: proposed/confirmed slot>" \ --company "<Company>" --app-id <application id> --cta-label "Review & send" --write
STEP 8 — Outcome routing
| Condition | Action | DB-mode command |
| Meeting booked / confirmed | applications[].status + conversations[] entry are already written in STEP 7(c). Hand off to interview-prep for prep materials using that conversations[] entry as the anchor. No additional write needed here. | Already covered by STEP 7(c)'s DB composition — no additional call. |
| Reschedule agreed | In ONE write: (1) update the existing conversations[] entry's date + notes; (2) update interviewAt or nextInterviewAt (whichever is set) to the new ISO datetime, and update interviewNote to match; (3) append a messages[] entry (direction: note, summary: "Meeting rescheduled to <new ISO datetime>") so the reschedule is in history; (4) set comm.nextActionDue = null, then set a fresh value keyed to the rescheduled slot; (5) run verify + snapshot. Without updating the datetime fields the dashboard Focus card still shows the old time. | careerrat data app schedule-interview <id> --at <new-iso> --round "<kind>" --note "<updated interviewNote>" re-books onto the same field (interviewAt/nextInterviewAt, auto-detected) and appends a fresh conversations[] entry rather than editing the old one in place — follow with careerrat data app set-fields <id> --data '{"conversations":[...]}' to patch the existing entry's date/notes in place instead, if that's the desired shape (wholesale array replace). Then careerrat data comm append-message <comm-id> --data '{"direction":"note","at":"<ISO>","summary":"Meeting rescheduled to <new ISO datetime>"}', then read-patch-persist careerrat data comm upsert --data '<patched full comm row JSON>' for nextActionDue. Then STEP 7(d)'s DB verify. |
| They go quiet after your proposal | Leave status: waiting; STEP 7b's nextActionDue surfaces it as a follow-up (handled by email-comms / the follow-up timer). | No write here — this is a read/no-op branch. |
| Thread turns to comp / general reply | Hand off to email-comms (general comms / negotiation surface). | No write here — hand-off only. |
| User states a new availability rule mid-thread ("no Fridays", "never before 10") | Confirm-first, then persist to candidate profile config availability (STEP 3 write-back). | DB mode: careerrat data candidate patch profile --data ...; legacy mode: guarded candidate-config write path. Never hand-edit YAML in DB mode. |
RULES
- Confirm-first on every outbound + every calendar write. Drafting and
.icspreparation are safe; sending the reply and creating/moving/deleting an external calendar event each require an explicit user yes. Never send or mutate a calendar silently. - Never invent availability. Only propose windows backed by the candidate's stated
preferences or an explicit confirmation. If real availability is unknown, ask. (Same honesty
line as
email-comms.) - Timezone clarity is mandatory. Every stated time is labeled with its timezone; give both the candidate's and the counterpart's when known. No unlabeled times, no bare "2pm".
- Avoid double-booking when you can verify it. With calendar context, exclude conflicts + honor the buffer. Without it, say so and fall back to draft-only — never assume the candidate is free.
- Free/busy reads are gated + opaque. Reading a real calendar runs only under
calendar_readfor an allowed platform (STEP 3b). Store start/end only — never a meeting title, attendee, location, or note.calendarBusy[]is a privacy-safe snapshot, not a live sync; reading is read-only and never writes to the source calendar. - Degrade gracefully. No calendar connector → draft-only + an
.icshold the user imports by hand. The skill is fully usable with zero calendar integration. - Tool-agnostic. Say "a calendar connector / session," "the session browser." Never name a vendor tool or MCP namespace. Calendar reads/writes through the session browser follow the Browser Automation Contract (halt on auth challenges).
track-outcomesowns status transitions;interview-prepowns prep. This skill writes scheduling state and the conversations[] entry, then hands the stage change + prep off — it does not own interview outcomes.- Privacy + local-only. No
current_baseor private comp in any reply, hold, or note..icsand raw thread bodies stay under~/Documents/careerrat//workspace/. - No placeholder brackets. Unknown detail → generic or omit; never a bracket token.
- Domain-neutral. No hardcoded companies, names, or times. The candidate's
availabilityblock + the thread make it specific; absent config stays neutral (derive + ask).
HONESTY
See Negotiation Contract › Honesty Firewall (hard) in AGENTS.md. In this skill: never invent availability, a meeting time the candidate hasn't agreed to, or a calendar state you haven't verified — ask rather than fabricate.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

