How the Follow-Up Cadence Calculator Determines Optimal Contact Timing in Career-Ops
The follow-up cadence calculator analyzes application statuses and historical outreach data to compute personalized contact schedules based on configurable rules for different pipeline stages.
The follow-up cadence calculator in the santifer/career-ops repository automates the scheduling of job-search communications by calculating exactly when to send the next message based on where an application sits in the hiring pipeline. By parsing your application tracker and follow-up history, the system eliminates guesswork and ensures consistent, appropriately timed outreach. This article explains the algorithmic logic behind the timing calculations, referencing the actual implementation in followup-cadence.mjs.
Configuration Strategy for Contact Timing
The calculator builds its timing recommendations from a layered configuration system that merges defaults with user preferences and runtime overrides.
Default Cadence Policies
The DEFAULT_CADENCE object (lines 34-42 in followup-cadence.mjs) defines the baseline timing rules:
- applied_first: Days to wait after initial application before the first follow-up
- applied_subsequent: Interval between follow-ups while status remains "applied"
- applied_max_followups: Maximum number of follow-ups before marking the candidate as "cold"
- responded_initial: Days to wait after receiving a response before following up
- responded_subsequent: Interval between follow-ups after initial response
- interview_thankyou: Days after an interview to send a thank-you note
User Profile Overrides
The system supports persistent customization through config/profile.yml. The PROFILE_CADENCE_KEYS mapping (lines 44-51) translates profile YAML keys to cadence fields, while the loadProfileCadence helper (lines 58-73) validates these values as positive integers and merges them with defaults. This allows users to maintain permanent preferences for aggressive or conservative outreach strategies.
CLI Temporary Overrides
For one-off adjustments, the resolveCadenceConfig function (lines 75-80) processes command-line flags such as --applied-days, which temporarily replaces applied_first without modifying stored configuration. The final merged configuration is stored in the CADENCE object (line 82).
Processing Application Data
Before calculating dates, the system normalizes raw tracker data into a consistent format.
Status Normalization
Application statuses from data/applications.md may appear with variant spellings or formatting. The normalizeStatus function (lines 99-105) maps these variations to canonical values (applied, responded, interview, etc.). Only statuses listed in ACTIONABLE_STATUSES (line 99) proceed to cadence calculations; others are filtered out.
Date Arithmetic Utilities
To avoid external dependencies, the calculator implements pure JavaScript date helpers:
parseDate(lines 112-115): Validates ISO-date stringsdaysBetween(lines 117-119): Computes whole-day differences between datesaddDays(lines 121-124): Adds days to a date and returns an ISO-formatted string
These utilities enable precise calendar arithmetic for determining intervals between application events and scheduled follow-ups.
Core Calculation Logic
The heart of the system lies in two functions that determine when to contact and how urgent that contact is.
The computeNextFollowupDate Algorithm
The computeNextFollowupDate function (lines 176-233) implements status-specific branching logic:
For "applied" status:
- If
applied_max_followupshas been reached, returnsnull(candidate is "cold") - If no prior follow-ups exist, schedules the first contact after
applied_firstdays - For subsequent follow-ups, adds
applied_subsequentdays to the most recent follow-up date
For "responded" status:
- Schedules the first follow-up after
responded_initialdays - Sets subsequent intervals using
responded_subsequent
For "interview" status:
- Schedules a single thank-you follow-up after
interview_thankyoudays
The function returns an ISO-date string or null when no further contact is recommended.
Urgency Classification
The computeUrgency function (lines 198-214) categorizes each pending contact using the same temporal logic but adds priority labels:
- Cold: Maximum follow-ups reached
- Overdue: Time since last action exceeds the configured cadence interval
- Urgent: Early-response scenarios requiring immediate attention
- Waiting: Within normal cadence parameters
The urgencyOrder map (line 302) sorts these classifications to prioritize your daily outreach tasks.
Full Analysis Pipeline
The analyze function orchestrates the complete workflow:
- Parse Inputs: Reads
data/applications.mdviaparseTracker(lines 28-44) anddata/follow-ups.mdviaparseFollowups(lines 48-68) - Group Events: Associates follow-up entries with application IDs
- Calculate Metrics: For each actionable application, computes days since application and days since last follow-up
- Extract Contacts: Uses
extractContacts(lines 73-86) to pull email addresses from application notes - Determine Timing: Invokes
computeUrgencyandcomputeNextFollowupDatefor each entry - Sort by Priority: Orders results using the
urgencyOrderranking - Return Payload: Outputs JSON (lines 310-323) containing
nextFollowupDate,urgencylevel, and effective configuration
Implementation Examples
Run the calculator from the command line to see a human-readable dashboard:
node followup-cadence.mjs --summary
This outputs a formatted table showing application numbers, companies, days elapsed, follow-up counts, next scheduled dates, urgency levels, and contact information.
Import the module programmatically to integrate with other tools:
import { analyze } from './followup-cadence.mjs';
(async () => {
const result = analyze();
console.log('Next contact for app #1:', result.entries[0].nextFollowupDate);
console.log('Urgency level:', result.entries[0].urgency);
})();
Override the first-follow-up interval temporarily for faster outreach:
node followup-cadence.mjs --applied-days 3 --summary
This command replaces the applied_first value with 3 days, causing earlier reminders for new applications without changing your default configuration.
Summary
- The follow-up cadence calculator in
followup-cadence.mjscombines default policies, user profile settings, and CLI flags to determine optimal contact timing - Status-specific rules govern intervals for "applied," "responded," and "interview" stages, with maximum follow-up limits preventing over-communication
- Urgency classification automatically prioritizes contacts as cold, overdue, urgent, or waiting
- Pure JavaScript date utilities handle all calendar arithmetic without external dependencies
- The system reads from
data/applications.mdanddata/follow-ups.md, outputting structured JSON via theanalyzefunction
Frequently Asked Questions
How does the calculator handle different application statuses?
The calculator treats each status according to distinct rules defined in DEFAULT_CADENCE. For "applied" statuses, it tracks the number of follow-ups against applied_max_followups and spaces them using applied_first and applied_subsequent. For "responded" statuses, it uses responded_initial and responded_subsequent intervals. Interview statuses trigger a single thank-you reminder after interview_thankyou days. The normalizeStatus function ensures consistent status mapping before these calculations apply.
Can I customize the timing intervals?
Yes, customization occurs at two levels. Persistent changes belong in config/profile.yml under the followup_cadence section, which the loadProfileCadence function validates and merges with defaults. Temporary adjustments use CLI flags like --applied-days, which resolveCadenceConfig processes at runtime. Both methods override the DEFAULT_CADENCE values defined in lines 34-42.
What happens when I reach the maximum number of follow-ups?
When the follow-up count for an "applied" status meets or exceeds applied_max_followups, the computeNextFollowupDate function returns null and computeUrgency labels the entry as cold. This prevents automated suggestions for further contact, effectively archiving the application unless the status changes to "responded" or "interview," which reset the cadence logic with their own intervals.
How does the tool determine if a contact is overdue?
The computeUrgency function compares the days elapsed since the last action (application or follow-up) against the configured cadence interval for that status. If the elapsed time exceeds the expected interval (such as applied_subsequent or responded_subsequent), the entry receives the overdue label. This calculation runs for every actionable entry in the pipeline, allowing the system to surface priority contacts in the daily summary.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →