Skip to main content

Overview

The create-handoff-marker worker creates a structured handoff record when an agent needs to escalate to another agent. It returns a pre-formatted Escalations block and optionally creates a tracking Task in Notion. Key features:
  • Generates pre-formatted handoff block for copy-paste into digest
  • Creates tracking task in Tasks database with relations and due dates
  • Circuit breaker: Prevents duplicate tasks within 7-day window
  • Escalation cap: Blocks creation after 2 escalations in same direction
  • Returns manual review flag when cap is hit

Input Parameters

source_agent
string
required
Name of the agent initiating the escalation. Must be a valid agent name.
target_agent
string
required
Name of the agent receiving the escalation. Must be a valid agent name.
escalation_reason
string
required
Description of why escalation is needed. Example: "Stale spike in CI failures; needs client repo audit"
source_digest_url
string
required
Notion URL of the source agent’s digest page. Used for traceability.
create_task
boolean
required
Whether to create a tracking task in Tasks database. Set to false if you only need the handoff block text.
task_priority
'🔴 High' | '🟡 Medium' | '🟢 Low'
Priority for created task. Required if create_task: true.
client_relation_ids
array
Array of Notion page IDs to link in Client relation property of created task
project_relation_ids
array
Array of Notion page IDs to link in Project relation property of created task

Output Format

All outputs include these fields:
success
boolean
required
Whether the operation succeeded. False only on validation errors or API failures.

On Success (success: true)

handoff_block
string
required
Pre-formatted text block for copy-paste into source digest’s Escalations section:
Escalated To: [target_agent]
Escalation Reason: [escalation_reason]
Escalation Owner: [target_agent]
Handoff Complete: No
Source: [source_digest_url]
task_created
boolean
required
Whether a task was created. False if:
  • create_task: false
  • Circuit breaker prevented duplicate
  • Escalation cap reached
task_url
string | null
required
Notion URL of created task, or null if not created
task_id
string | null
required
Notion page ID of created task, or null if not created
duplicate_prevented
boolean
required
Whether circuit breaker prevented duplicate task creation. True if an open handoff task for same direction exists within 7 days.
existing_task_url
string | null
required
URL of existing task if duplicate was prevented, or null
escalation_capped
boolean
required
Whether escalation cap blocked task creation. True if 2+ escalations in same direction within 7 days.
needs_manual_review
boolean
required
Whether item needs manual review. True when escalation cap is hit.

On Failure (success: false)

error
string
Error message describing validation failure:
  • "Invalid source_agent: ..."
  • "Invalid target_agent: ..."
  • "escalation_reason and source_digest_url are required"
  • "task_priority is required when create_task is true"
  • "[Notion API error message]"

Usage Examples

const input = {
  source_agent: "GitHub Insyncerator",
  target_agent: "Client Repo Auditor",
  escalation_reason: "Stale spike in CI failures; needs client repo audit",
  source_digest_url: "https://www.notion.so/github-sync-2026-02-28-abc123",
  create_task: true,
  task_priority: "🟡 Medium",
  client_relation_ids: ["client-page-id-123"],
  project_relation_ids: ["project-page-id-456"],
};

const result = await worker.execute(input);
// {
//   success: true,
//   handoff_block: "Escalated To: Client Repo Auditor\nEscalation Reason: Stale spike in CI failures; needs client repo audit\nEscalation Owner: Client Repo Auditor\nHandoff Complete: No\nSource: https://www.notion.so/github-sync-2026-02-28-abc123",
//   task_created: true,
//   task_url: "https://www.notion.so/handoff-github-client-2026-02-28-xyz",
//   task_id: "xyz789...",
//   duplicate_prevented: false,
//   existing_task_url: null,
//   escalation_capped: false,
//   needs_manual_review: false
// }

// Paste result.handoff_block into Escalations section of source digest
// Link to result.task_url in Actions Taken if needed

Circuit Breaker Logic

The circuit breaker prevents duplicate handoff tasks within a 7-day rolling window for the same source → target direction.
When circuit breaker fires:
  1. Worker queries Tasks database for handoff tasks matching "Handoff: [source] → [target]"
  2. Filters results to tasks created within last 7 days
  3. Checks if any matching tasks have open status (not “Done”, “Closed”, “Complete”)
  4. If open task found:
    • Returns duplicate_prevented: true
    • Returns existing_task_url for reuse
    • Does NOT create new task
Status considered open:
  • Any status except: “Done”, “Closed”, “Complete”
  • Status property can be named “Status” or “status”
  • Status can be select or status property type

Escalation Cap Logic

The escalation cap blocks task creation after 2 escalations in the same direction within 7 days. This prevents runaway escalation loops.
When escalation cap hits:
  1. Worker counts ALL tasks (open + closed) matching "Handoff: [source] → [target]" within 7 days
  2. If count >= 2:
    • Returns escalation_capped: true
    • Returns needs_manual_review: true
    • Does NOT create task
    • Agent should move item to “Needs Manual Review” section
Cap constants:
  • HANDOFF_WINDOW_DAYS = 7 (src/workers/create-handoff-marker.ts:10)
  • ESCALATION_CAP = 2 (src/workers/create-handoff-marker.ts:11)

Task Structure

When create_task: true and no circuit breaker/cap triggers, the worker creates: Task properties:
  • Name: "Handoff: [source_agent] → [target_agent] — [due_date]"
  • Priority: From task_priority input
  • Due: Next business day (src/shared/date-utils.ts:nextBusinessDay)
  • Client: Relations from client_relation_ids
  • Project: Relations from project_relation_ids
Task content:
Escalation from [source_agent]. Reason: [escalation_reason]. 
Source digest: [source_digest_url]
Due date is calculated as next business day (Monday–Friday). Weekends are skipped.

Handoff Block Format

The handoff_block output is designed for direct paste into source digest’s “Escalations / Hand-offs” section:
Escalated To: [target_agent]
Escalation Reason: [escalation_reason]
Escalation Owner: [target_agent]
Handoff Complete: No
Source: [source_digest_url]
Field meanings:
  • Escalated To: Target agent name
  • Escalation Reason: Why escalation is needed
  • Escalation Owner: Who is responsible (usually target agent)
  • Handoff Complete: Always “No” at creation time
  • Source: URL back to originating digest for traceability
The handoff block matches the format expected by write-agent-digest worker’s escalations section (src/workers/write-agent-digest.ts:103-113).

Error Handling

Validation errors return success: false:
{
  "success": false,
  "error": "Invalid source_agent: Unknown Agent"
}
The worker returns structured errors. Always check success field before using output.

Implementation Details

Source Files

  • Worker implementation: src/workers/create-handoff-marker.ts:27-197
  • Schema definition: src/index.ts:65-85
  • Type definitions: src/shared/types.ts:101-125

Query Strategy

The worker uses a two-phase query: Phase 1: Find candidates
filter: {
  property: "Name",
  title: { contains: `Handoff: ${source_agent}${target_agent}` }
}
sorts: [{ timestamp: "created_time", direction: "descending" }]
page_size: 20
Phase 2: Filter by window
  • Filter results to created_time >= (now - 7 days)
  • Separate open vs closed tasks
  • Count total for cap check

Date Calculations

Window calculation:
const since = new Date();
since.setDate(since.getDate() - HANDOFF_WINDOW_DAYS);
const sinceMs = since.getTime();
Due date calculation:
const dueDate = nextBusinessDay();
const dueStr = dueDate.toISOString().slice(0, 10);
nextBusinessDay() skips Saturday/Sunday (src/shared/date-utils.ts).

Best Practices

const result = await createHandoffMarker(input);

if (!result.success) {
  console.error(result.error);
  return;
}

// Circuit breaker fired
if (result.duplicate_prevented) {
  console.log(`Reusing existing task: ${result.existing_task_url}`);
  // Use existing_task_url in digest
}

// Escalation cap hit
if (result.escalation_capped) {
  console.log(`Escalation cap reached, needs manual review`);
  // Move item to Needs Manual Review section
  // Investigate why repeated escalations
}

// Normal creation
if (result.task_created) {
  console.log(`Created task: ${result.task_url}`);
}

// Always use handoff_block in digest
console.log(result.handoff_block);

Build docs developers (and LLMs) love