Skip to content

Add a LinkedIn sync schedule that runs on the org's agent - #19

Open
pallaoro wants to merge 3 commits into
linkedin-channelfrom
linkedin-sync
Open

pallaoro wants to merge 3 commits into
linkedin-channelfrom
linkedin-sync

Conversation

@pallaoro

@pallaoro pallaoro commented Sep 17, 2026

Copy link
Copy Markdown
Member

Stacked on #18 (LinkedIn channel). Merge #18 first; this PR then retargets to main.

What

A LinkedIn sync page: pick the agent signed in to LinkedIn, pick how often, and turn it on. The app creates one schedule on that agent through @clawnify/agents. The agent's own scheduler keeps the time, and the app never runs a timer of its own.

Each run follows skills/linkedin-sync/SKILL.md, which a build step (scripts/build-linkedin-skill.mjs) snapshots into the schedule's task text with its hash:

  1. Open a run.
  2. Mirror new LinkedIn messages.
  3. Send the queued LinkedIn messages (openers to 1st-degree connections only).
  4. Close the run with counts, or with what LinkedIn showed.

Guarantees

  • Consent: off until a person turns it on, because every run spends the agent's credits.
  • Cadences: office hours only, weekdays 8:00–18:00: hourly (default), every 30 minutes, or every 10 minutes (labelled as costing the most).
    • Times use the saving browser's time zone.
  • One run at a time: POST /api/linkedin-sync/runs is idempotent on the agent's run id. A partial unique index refuses a second open run (409), so an overlapping fire stops at its first call. A run that never reports back stops blocking after 45 minutes.
  • Off means off: once sync is off, a run gets 410 even if the scheduler couldn't be reached to pause.
  • One schedule:
    • Creation uses a stored idempotency key, so a retry after a timeout replays the same creation. Saving again updates the same schedule.
    • Moving to another agent deletes the old schedule first and stops, with a visible error, if that fails.
    • Off pauses the schedule; Remove deletes it.
  • Who can do what:
    • Run routes are in the OpenAPI description and are agent-only.
    • The settings, agents, run-now and remove routes are left out of the description and need a signed-in person, so a task never teaches its agent to schedule or dispatch itself.
  • Run now uses a request id kept by the browser, so a double click or retry dispatches once.

Checked

  • pnpm test: 35 pass (including Add LinkedIn as a connections-only channel #18's), 12 new in tests/linkedin-sync.test.mjs. They run against the real worker in Miniflare with a fake agents API that records every call.
  • The one-run-at-a-time test fails without the partial index. The agent-move test fails if the create goes ahead after the old schedule couldn't be removed.
  • pnpm run typecheck and pnpm run build pass (both run the skill snapshot first).
  • UI, locally:
    • The page renders, and the cadence dropdown uses the existing Popover + Command.
    • With no platform token, the agent picker shows "This app can't reach your agents yet".
    • No sideways scroll at 390px.
  • Not run: a real schedule on a deployed app. That needs the platform token, which only a deployed app gets.

A new "LinkedIn sync" page lets a person pick the agent signed in to LinkedIn,
how often it runs, and turn it on. The app then creates one schedule on that
agent through @clawnify/agents; the agent's own scheduler keeps the time, and
the app never runs a timer of its own.

The procedure the agent follows is skills/linkedin-sync/SKILL.md. A build step
snapshots it into the schedule's task text (under the 4,000-character task
limit) with its hash, and every save rewrites the text, so a newer skill
reaches the agent.

- Off until a person turns it on, because every run spends credits. Cadences
  default to office hours; the fastest is every 10 minutes and says it costs
  the most.
- One run at a time: the agent opens a run first and a partial unique index
  refuses a second while one is open (409), so an overlapping fire stops at
  its first call. A run that never reports back stops blocking after 45
  minutes. Turning sync off makes the next run stop immediately (410), even if
  the scheduler cannot be reached.
- Schedule creation is idempotent on a stored key, so a retry after a timeout
  cannot add a second schedule. Moving to another agent removes the old
  schedule first and stops if that fails; turning it off pauses it; removing
  it deletes it.
- The run routes are in the OpenAPI description for the agent. The settings
  routes are not, and accept only a signed-in person, so a task never teaches
  its agent to schedule itself.

The page lists recent runs with what each mirrored and sent, or what stopped it.
The every-3-hours option also ran through nights and weekends, which is the
pattern LinkedIn reads as automation. The remaining cadences all run on
weekdays between 8:00 and 18:00.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant