Skip to content

AGENTS.md

117 lines · 4.0 KB · Markdown
Raw

@kody/linkedin — agent notes

Human setup and intent live in README.md. This file is for agents: imports, smoke/dryRun execute snippets, and edge cases. Auth is the saved OAuth integration named linkedin — never paste tokens. Do not disable live webhooks or jobs. No /account/secrets/new token path for this package.

Auth

  • Integration id: linkedin (createAuthenticatedFetch('linkedin'))
  • API origin: https://api.linkedin.com
  • Scopes expected: openid, profile, email, w_member_social
  • Author URN comes from /v2/userinfo (urn:li:person:{sub}) unless overridden

Import paths

ExportImport
overview / safety metadatakody:@kody/linkedin
smoke-testkody:@kody/linkedin/smoke-test
get-user-infokody:@kody/linkedin/get-user-info
get-person-urnkody:@kody/linkedin/get-person-urn
requestkody:@kody/linkedin/request
create-postkody:@kody/linkedin/create-post
create-text-postkody:@kody/linkedin/create-text-post
create-article-postkody:@kody/linkedin/create-article-post
create-image-postkody:@kody/linkedin/create-image-post
create-video-postkody:@kody/linkedin/create-video-post
delete-postkody:@kody/linkedin/delete-post
register-image-uploadkody:@kody/linkedin/register-image-upload
register-video-uploadkody:@kody/linkedin/register-video-upload
upload-video-partkody:@kody/linkedin/upload-video-part
finalize-video-uploadkody:@kody/linkedin/finalize-video-upload

Prefer static kody:@kody/linkedin/... imports from execute. Do not lead with packages.invoke. For smoke against a forked package runtime that must bind the caller's OAuth grant, a dynamic invoke of bare kody id linkedin is acceptable — prefer the fork's published export once connected.

Smoke test (read-only)

import smokeTest from 'kody:@kody/linkedin/smoke-test'

export default async function main() {
	return await smokeTest()
	// => { ok: true, integration: 'linkedin', hasSubject: true, personUrnPresent: true }
}

Identity helpers:

import getPersonUrn from 'kody:@kody/linkedin/get-person-urn'

export default async function main() {
	return await getPersonUrn()
}
import request from 'kody:@kody/linkedin/request'

export default async function main() {
	return await request({ path: '/v2/userinfo', dryRun: true })
}

dryRun / confirm (writes)

Posting and upload helpers never mutate LinkedIn when dryRun: true. A live write requires a fresh confirm: true after the user approved the exact payload.

import createTextPost from 'kody:@kody/linkedin/create-text-post'

export default async function main() {
	return await createTextPost({ text: 'Draft text', dryRun: true })
}
import createArticlePost from 'kody:@kody/linkedin/create-article-post'

export default async function main() {
	return await createArticlePost({
		text: 'Read this',
		url: 'https://example.com',
		title: 'Example article',
		description: 'A useful article.',
		thumbnailUrl: 'https://example.com/thumbnail.jpg',
		dryRun: true,
	})
}

LinkedIn does not scrape Open Graph metadata for API-created article posts. Pass title, description, and either an existing LinkedIn image thumbnail URN or an HTTPS thumbnailUrl.

Native video: register-video-upload → upload-video-part (each part) → finalize-video-upload → create-video-post.

Edge cases / fork notes

  • Fork first; connect the caller's LinkedIn app. Do not treat the live @kody/linkedin integration as theirs.
  • No refresh token without LinkedIn partner access — on 401, reconnect at /connect/oauth?provider=linkedin.
  • HTTP 403 on posting: Share on LinkedIn product + w_member_social, then reconnect.
  • redirect_uri must be exactly https://kody.codes/connect/oauth.
  • Do not hard-code a member URN. Do not use this as an org-page poster.
  • Never treat smoke success as permission to post.
  • Keep LICENSE (MIT), ## Intent, and community-icon.svg for community listing.