---
name: rolino
description: Use Rolino to inspect storage, safely clean unused Media Library files, read authorized SEO opportunities and weekly reports, inspect Blog publishing destinations and delivery status, upload local social media, turn folders of content into drafts, check publishing readiness, schedule or publish approved posts, inspect the social calendar, and configure Rolino CLI or MCP access. Trigger when the user asks an agent to use Rolino, inspect or free Rolino storage, read Rolino SEO guidance, inspect or publish Blog content, schedule content from files or a folder, prepare or publish social content through Rolino, inspect Rolino projects or posts, or connect Rolino to an AI coding agent.
---

# Rolino Agent Workflow

Rolino is an agent-ready social scheduling service. Use its CLI in agent mode for structured output. Keep the user's control over account creation, authorization, connected social accounts, scheduling, and publishing.

## When to use this Rolino skill

Use this skill when the user asks an agent to work in an authorized Rolino workspace. Good fits include inspecting Rolino projects, posts, calendars, publishing connections, Blog plans, Blog deliveries, or authorized SEO tasks; uploading user-approved media; preparing or updating drafts; and previewing an exact schedule, approval, or publication for the user to confirm.

Use Rolino only after the user asks for Rolino or the requested work clearly belongs in their Rolino workspace. Do not use this skill for general web browsing, unrelated analytics, an account the user has not connected, or content that the user does not want stored in Rolino. A request to prepare content is a draft request unless the user separately asks to schedule or publish it.

Use the hosted MCP endpoint for a remote MCP client, the CLI or local stdio MCP server for work on the user's computer, and the SDK or Agent API for an existing integration. Always resolve the exact workspace and project before a write.

## Command prefix

Prefer an installed CLI:

~~~bash
rolino --agent <command>
~~~

If it is not installed, use the current public package without modifying the project:

~~~bash
npx -y @rolino/cli@latest --agent <command>
~~~

For self-hosted Rolino, preserve the user's configured ROLINO_URL or pass --base-url. Never guess a deployment URL or copy a credential into source code, logs, prompts, or a final response.

## Start with prerequisites

1. Check authentication with `rolino --agent auth status`.
2. If authentication is missing, explain that the user needs a Rolino account and browser approval. Run `rolino auth login` only when the user wants to continue, then wait for them to sign up or sign in and approve the requested workspace permissions in the browser.
3. After approval, rerun `rolino --agent auth status`, then `rolino --agent projects list`.
4. Resolve the project by an exact ID, a clearly matching name, or its website. Never silently choose between plausible projects.
5. If no project exists, ask before creating one. Use `rolino --agent projects create --name "NAME" --type PRODUCT --yes`; add a real website only when known. Project creation does not connect accounts, create posts, schedule, or publish.
6. Before preparing a destination, run `rolino --agent integrations health --project PROJECT_ID`. If the required social account is disconnected, tell the user to connect it at `/projects/PROJECT_ID/settings/connections`, then rerun the health check.
7. For TikTok, refresh creator-specific choices with `rolino --agent integrations delivery-options --project PROJECT_ID --provider TIKTOK` immediately before preparing settings. Use only returned modes, visibility values, interaction availability, and duration limits.
8. For LinkedIn, refresh `rolino --agent integrations delivery-options --project PROJECT_ID --provider LINKEDIN` before preparing a draft. Confirm that the connected member is the intended author and use only the returned text/image/video policy. Native video requires exactly one MP4 and cannot be mixed with images. LinkedIn Company Pages are not member-publishing targets.
9. For Google Business Profile, confirm the selected location name in readiness. Use text and at most one stored JPEG or PNG. Rolino owns schedule time. If the result is unknown, inspect the selected Business Profile and do not retry the create request.

## Bluesky workflow

Set image descriptions with mediaAltText or CLI --media-alt. Untouched draft deletion requires posts:delete; account disconnection requires integrations:disconnect. Both use separate preview and confirmed execution with a stable idempotency key. Existing grants do not gain these optional permissions. Report unresolved provider revocation and direct the owner to remove Rolino access in Bluesky settings.


Run integrations delivery-options with --provider BLUESKY to read account health, limits, and the owner OAuth authorization.path on the current Rolino host. The owner must connect or reconnect in the browser. Use text or up to four JPEG, PNG, or WebP images, each no larger than 2,000,000 bytes, with captions of at most 300 graphemes. Video and external cards are unsupported.

Hosted MCP offers prepare_media_asset_upload and complete_media_asset_upload. Transfer exact approved bytes to the returned private upload URL between calls; completion verifies stored media. The CLI and local MCP can upload caller-local files directly. Use completed asset IDs in drafts.

To cancel a future local schedule, use posts schedule cancel preview and execute, or preview_post_schedule_cancellation and execute_post_schedule_cancellation. Require posts:schedule, the current version, user approval of the exact preview, its token, and a stable idempotency key. CLI execute also requires --yes. All listed destinations return to Draft. Started or uncertain delivery must use check_post_delivery first. To edit scheduled Bluesky content, cancel, update the draft, then preview and confirm a new schedule. A queue result is not proof of publication.

## Interpret common requests

- “Show my SEO opportunities” → confirm that the connection has the optional `seo:read` scope, resolve the exact project, then run `rolino --agent seo opportunities list --project PROJECT_ID`. Read detail only by an ID returned for that project.
- “Show my weekly SEO report” → confirm `seo:read`, resolve the project, list reports, then read the selected report by its exact ID. SEO commands are read-only. They cannot run analysis, change settings, delete data, enable reports, send email, or call an external provider.
- “Find backlink opportunities” → confirm `backlinks:write`, resolve the exact project, list or add owned target pages, then start one bounded discovery with a stable idempotency key. Poll the returned run. Do not supply an arbitrary query or infer a contact.
- “Review backlink prospects” → confirm `backlinks:read`, list bounded prospects, and read detail only by an ID returned for the same project. This scope omits email addresses and draft bodies.
- “Prepare backlink outreach” → confirm `backlinks:read`, `backlinks:write`, and `backlinks:contacts`. Research only an approved stored prospect. Accept only a non-stale public contact with its exact source. Review or edit the draft. Rolino never sends email.
- “Show my Blog plan” → confirm `blog:read`, resolve the exact project, then run `rolino --agent blog plans --project PROJECT_ID`. The Blog plan is separate from the social calendar.
- “Change my Blog cadence” → confirm `blog:write`, read the exact plan and version, run `rolino --agent blog plan cadence preview`, show every editorial date move and locked item, then run `rolino --agent blog plan cadence apply` only with the unchanged weekdays, plan version, schedule digest, confirmation token, and a stable idempotency key. This never schedules, publishes, or unpublishes an article.
- “Edit this Blog article” → confirm `blog:write`, read the exact article and version, save the complete draft through `rolino --agent blog articles update ARTICLE_ID --project PROJECT_ID --input DRAFT.json --yes`, then read it again. This never publishes.
- “Approve this Blog article” → confirm `blog:approve`, preview the exact revision and image bundle, inspect its links and warnings, then execute only the unchanged preview with its confirmation token and a stable idempotency key. This cannot publish.
- “Publish this Blog article” → confirm separate `blog:publish` access and exact-bundle approval, run the Blog publish or schedule preview, show its revision, destination, time, timezone, and URL, then execute only the unchanged preview with its confirmation token and a stable idempotency key. A changed or unapproved bundle must stop and restart from approval preview.
- “Show my Blog publishing destinations” → confirm `blog:read`, resolve the exact project, then run `rolino --agent blog destinations list --project PROJECT_ID`. Use `blog destinations deliveries` to report safe delivery state and remote URLs. Do not infer that a queued delivery is live.
- “Set up Blog Studio” → use the agent-first Blog workflow below. Ask for the intended Review required, Agent approval, or Full publishing access level. The user grants each requested capability in Rolino; the prompt does not grant access and an agent cannot widen its credential.

- “Show my Rolino calendar” → resolve the project, then run `rolino --agent calendar list --project PROJECT_ID`.
- “Create/prepare/draft a post” → create a draft only. Do not schedule or publish unless the user separately asks.
- “Schedule this folder” → inspect supported local media without modifying it, build a file-to-caption/destination/time manifest, show ambiguities and blockers, and obtain approval for that exact batch before uploading and scheduling it.
- “Schedule this post” → create or resolve the draft, check readiness, preview the exact schedule, show the user the time, timezone, destinations, and blockers, then execute only after the user has clearly approved that exact result.
- “Publish this now” → create or resolve the draft, check readiness, preview the exact destinations and YouTube visibility, explain that delivery mode is IMMEDIATE and creates no schedule, then execute only after clear approval.
- “Connect Rolino to Codex” → run `codex mcp add rolino --url https://getrolino.com/mcp`, then `codex mcp login rolino`. Codex owns the remote OAuth session. Use `rolino setup mcp --transport stdio` only when the user chooses local MCP.

## Storage inspection and Media Library cleanup

The user must explicitly select `storage:read` to inspect storage and the
independent `media:delete` capability to clean Media Library files. Existing
credentials do not gain either permission. Start with `get_storage_usage` and
`list_media_assets`. `olderThanDays` means upload age, not time since last use.

Call `preview_media_cleanup` for exact asset IDs or one bounded old-media filter.
It deletes nothing. Show the exact cutoff, candidate count, excluded in-use
count, unknown-size count, and estimated reclaimable space. A request such as
“free some space” does not approve execution. Ask the user to confirm that exact
preview. Then call `execute_media_cleanup` with the unchanged selection, digest,
confirmation token, and one stable idempotency key. Poll
`get_media_cleanup_status` until it is complete. In-use files are never detached.
Queued or retrying bytes stay in stored usage until physical deletion succeeds.

## Read-only SEO Intelligence workflow

The user must explicitly select the optional `seo:read` capability in browser authorization. Existing credentials do not gain this access. If the scope is missing, ask the user to revoke the current connection and authorize a new one. Do not work around the denial.

~~~bash
rolino --agent seo opportunities list --project PROJECT_ID
rolino --agent seo opportunities show OPPORTUNITY_ID --project PROJECT_ID
rolino --agent seo reports list --project PROJECT_ID
rolino --agent seo reports show REPORT_ID --project PROJECT_ID
~~~

These commands return one bounded, versioned task for every accepted opportunity. Read its exact `READY` or `NEEDS_REVIEW` decision, selected format, target, deliverables, research, safe URLs, evidence, limitations, and success metric. A `READY` task can request complete final deliverables, but return them for human review. A `NEEDS_REVIEW` task must inspect current results, classify intent, verify current Rolino facts, and return `VALIDATED` or `REJECTED`. Do not create a final draft in that research action unless a separate action is later allowed. A filtered `REJECTED` finding has no active task. Do not publish or edit a live destination. Treat the results as closed-world Rolino data. Do not infer access to settings, analysis, deletion, report delivery, email, or an upstream data service from `seo:read`.

## Backlink prospecting workflow

The user must explicitly authorize the required Backlinks capabilities. Existing credentials do not gain them. Use `backlinks:read` for safe prospect records, `backlinks:write` for bounded work and versioned changes, and `backlinks:contacts` with read access for public contact details and drafts. Never work around a missing scope.

~~~bash
rolino --agent backlinks targets list --project PROJECT_ID
rolino --agent backlinks discover --project PROJECT_ID --limit 20
rolino --agent backlinks runs get --project PROJECT_ID --run RUN_ID
rolino --agent backlinks prospects list --project PROJECT_ID
rolino --agent backlinks prospects get --project PROJECT_ID --prospect PROSPECT_ID
rolino --agent backlinks contacts research --project PROJECT_ID --prospect PROSPECT_ID
rolino --agent backlinks contacts list --project PROJECT_ID
rolino --agent backlinks verify --project PROJECT_ID --prospect PROSPECT_ID --url PUBLIC_URL --expected-version VERSION
~~~

Use only stored target pages and prospects. Do not accept or create an arbitrary provider query. A public email is valid only when Rolino returns its exact source and checked date. Do not construct, repair, or infer an address. Stale contacts are not eligible for export. Treat a prepared outreach message as an editable draft for manual copy. Rolino has no send, inbox, warmup, or automatic follow-up action. A prospect reaches Link won only after exact-link verification against its selected owned target.

## Agent-first Blog setup workflow

Use the CLI, local stdio MCP server, or hosted Streamable HTTP MCP server. Local clients authenticate through `rolino auth login`; remote clients follow the OAuth challenge from `https://getrolino.com/mcp` and approve one Rolino workspace in the browser. The five Blog capabilities are independent. Existing credentials do not gain `blog:approve` or any other new capability. If a required capability is missing, stop and ask the user to authorize it; never work around or widen the scope.

1. Read Blog setup status with `rolino --agent blog setup status --project PROJECT_ID`, then read the current article or plan state.
2. Ask for any missing website, cadence, destination, and access level. Never invent an origin or choose an access level for the user.
3. Import and plan through durable jobs. Start only the required operation, poll its returned job, and retry only a reported failure. Never retry blindly.
4. List plan items and present each title, work type, frozen evidence, source limitation, and selection reason before acceptance unless the user's instruction already authorizes that exact bounded plan operation.
5. To change an active plan cadence, call cadence preview first with `blog:write`, show every proposed editorial date change and locked item, and apply only the unchanged preview values with its confirmation token and a stable idempotency key. This operation never changes publication scheduling.
6. `generate_blog_image` already accepts an optional `editorialBrief` of up to 500 characters for image direction. Do not create a second image-direction operation.
5. Create or update one immutable revision with catalog-backed internal links. Use the returned state and version so concurrent edits cannot be overwritten.
6. Generate one Rolino image or upload one user-approved local JPEG, PNG, or WebP. Review the exact image and verify its alt text.
7. If the credential lacks `blog:approve`, stop and ask the user to approve the exact revision and image bundle in Rolino. Do not work around the scope.
8. With `blog:approve`, preview the exact article and image bundle. Inspect the revision, images, links, warnings, and bundle hash, then execute only the unchanged preview with its confirmation token and a stable idempotency key.
9. If the credential lacks `blog:publish`, stop after approval.
10. With `blog:publish`, preview immediate publication or scheduling. Execute only the unchanged preview with the same revision, destination IDs, time, timezone, confirmation token, and a stable idempotency key. Publication never implies approval.
11. Poll delivery attempts with `rolino --agent blog destinations deliveries --project PROJECT_ID --article ARTICLE_ID` and verify the live remote URL. A queued state is not published.
12. If revision content or any selected image changes, the approval is stale. Start again from approval preview; never reuse the earlier approval or publication preview.

Destination setup stays separate from the article workflow. Inspect the provider catalog with `rolino --agent blog destinations providers --project PROJECT_ID` and saved destinations with `rolino --agent blog destinations list --project PROJECT_ID` before configuration. Preview each connection change and ask for confirmation before execution. Store one-time values only in server-side local environment configuration. For Next.js, inspect the current App Router structure, install `@rolino/nextjs-blog` in the repository's existing style, build the target app, verify an authenticated published-content request, and verify signed revalidation. Do not claim a configured token proves delivery.

The local stdio MCP server provides the same reads as `list_blog_publishing_providers`, `list_blog_publishing_destinations`, and `list_blog_delivery_attempts`. The provider catalog requires `blog:manage`. Destination and delivery reads require `blog:read`. These are closed-world reads and do not contact or change a provider. Draft content, prompts, evidence, secrets, and raw provider responses are not returned.

## Draft workflow

Inspect the project before creating anything:

~~~bash
rolino --agent projects show PROJECT_ID
rolino --agent integrations health --project PROJECT_ID
~~~

Create a draft only after the user has supplied or approved the caption and destinations:

~~~bash
rolino --agent posts create --project PROJECT_ID --caption "TEXT" --platform INSTAGRAM --yes
~~~

Repeat `--platform` and `--media` for additional destinations and existing Rolino media asset IDs. Instagram and video-first destinations can require media. Discover reusable assets with `rolino --agent media list --project PROJECT_ID`. Upload an approved local file with `rolino --agent media upload PATH --project PROJECT_ID --yes`, then use the returned asset ID. Never invent an asset ID.

### Draft captions by destination

Resolve and preview the final caption for every selected destination before creating or updating a draft.

- Use the shared caption when it fits every destination and matches the user's intent. Do not create nearly identical overrides only to make each destination different.
- Create destination-specific overrides when platform limits, tone, formatting, or content type require different text. The CLI accepts `--instagram-caption`, `--tiktok-caption`, `--youtube-caption`, `--bluesky-caption`, and `--linkedin-caption`.
- Count each resolved caption using the destination's actual measurement rule and show `used / allowed` in the approval plan. Use a scalable `Caption usage` field rather than adding one table column per platform.
- Never create or update a draft with text that exceeds Rolino's validated destination limit. If text is too long, prepare a compliant revision before continuing. If shortening could materially change the message, show the revision to the user for approval.
- Treat preferred or “sweet spot” lengths as writing guidance, not hard limits, unless the user or their brand instructions make them requirements.

Current Rolino limits are Instagram 2,200 characters; TikTok video captions 2,200 UTF-16 code units; YouTube descriptions 5,000 UTF-8 bytes; Bluesky posts 300 graphemes; and LinkedIn member posts 3,000 characters. Rolino's server validation is the source of truth if provider requirements change.

Use `rolino --agent posts show POST_ID --project PROJECT_ID` to obtain the current version before updating, scheduling, or publishing. Updates require `--expected-version` so web or teammate changes cannot be overwritten silently.

Updates are partial. Supply only fields the user intends to change; omitted media, destinations, captions, and provider settings are preserved. Changing TikTok caption, media, destinations, or its caption override invalidates the prior TikTok settings review.

### TikTok delivery settings

Refresh the connected creator's choices before creating or revising a TikTok draft:

~~~bash
rolino --agent integrations delivery-options --project PROJECT_ID --provider TIKTOK
~~~

Choose direct publishing or an inbox handoff explicitly. For direct publishing, use an exact returned visibility and explicit yes/no values for comments, duet, stitch, commercial content, own-brand promotion, third-party promotion, and AI-generated content. Never request an interaction that the refreshed result marks unavailable. Add `--tiktok-settings-reviewed` only after the choices were reviewed; this is separate from `--yes`, which confirms the Rolino draft mutation. Rolino stamps review time on the server and will not silently weaken a requested setting.

### LinkedIn member publishing

Refresh the connected member and supported post types before creating or revising a LinkedIn draft:

~~~bash
rolino --agent integrations delivery-options --project PROJECT_ID --provider LINKEDIN
~~~

LinkedIn supports text-only posts, up to ten stored JPEG/PNG images, or exactly one stored MP4 without image/video mixing. Native video must follow the refreshed delivery options; Rolino currently accepts 75 KB to 500 MB and 3 seconds to 30 minutes. Use `--linkedin-caption` for a destination-specific caption. Never infer that the developer app's associated Company Page is the publishing target: the author is always the member who completed OAuth. A successful publish execute only queues delivery, and native video remains in preparation until LinkedIn confirms upload and processing. If Rolino reports `LINKEDIN_PUBLISH_OUTCOME_UNKNOWN`, inspect the member's LinkedIn feed before any retry because the create request may have succeeded without returning an identifier.

## Local folder workflow

When the user supplies a folder of content:

1. Enumerate only that folder and identify supported JPEG, PNG, WebP, MP4, and MOV files. Ignore hidden, temporary, and unsupported files; do not rename, move, edit, or delete source files.
2. Determine the intended caption, destination, date, time, timezone, and ordering from explicit user instructions or an included manifest. Treat filenames as hints, not authoritative publishing instructions.
3. List existing project media and match obvious duplicates by exact file name and size when possible. Never substitute a merely similar asset.
4. Present one compact batch plan containing every source file, resolved destination caption, caption usage, destination, and exact scheduled time. Surface missing or over-limit captions, collisions, unsupported formats, provider constraints, and disconnected channels.
5. After the user approves that exact plan, upload only the approved files. Reuse returned asset IDs to create drafts, then run readiness on every draft.
6. Preview every exact schedule. If the previews match the approved batch with no new blockers or changes, the earlier explicit batch approval may cover execution. Otherwise show the changed result and ask again.
7. Execute each confirmed schedule with a stable, unique idempotency key, then verify the affected calendar window and report per-post results. A partial failure must not cause successful items to be duplicated.

Example upload and draft preparation:

~~~bash
rolino --agent media list --project PROJECT_ID --query "launch"
rolino --agent media upload "/exact/path/launch-01.mp4" --project PROJECT_ID --yes
rolino --agent posts create --project PROJECT_ID --caption "APPROVED TEXT" --platform TIKTOK --media ASSET_ID --tiktok-mode direct --tiktok-visibility RETURNED_VALUE --tiktok-comments no --tiktok-duet no --tiktok-stitch no --tiktok-commercial-content no --tiktok-promotes-own-brand no --tiktok-promotes-third-party no --tiktok-ai-generated no --tiktok-settings-reviewed --yes
~~~

## Schedule workflow

Scheduling is always two-step and exact:

~~~bash
rolino --agent posts readiness POST_ID --project PROJECT_ID
rolino --agent posts schedule preview POST_ID --project PROJECT_ID --expected-version VERSION --at ISO_DATE --timezone IANA_TIMEZONE
~~~

The preview returns a five-minute confirmation token. After the user approves the exact preview, pass the token through ROLINO_CONFIRMATION_TOKEN and repeat the same post version, time, and timezone with a stable idempotency key:

~~~bash
rolino --agent posts schedule execute POST_ID --project PROJECT_ID --expected-version VERSION --at ISO_DATE --timezone IANA_TIMEZONE --idempotency-key STABLE_KEY
~~~

Never treat a preview as a completed schedule. Never change the time, timezone, post version, or destinations between preview and execution.

For YouTube schedules, require Public in the draft settings. Confirmed scheduling starts the upload immediately as Private so YouTube can process it before the target time. A `PENDING` result with phase `REMOTE_SCHEDULE_CONFIRMATION`, or destination stage `CONFIRMING_SCHEDULE`, means the video upload is complete and YouTube is acknowledging the requested future Public publish time. It does not mean the video is public, and it is not a second publish action.

## Existing delivery recovery

Read saved remotePostId, remoteContainerId, and studioUrl in the post result. Before retrying an uncertain delivery, use check_post_delivery through MCP or:

~~~bash
rolino --agent posts recovery check POST_ID --project PROJECT_ID --provider YOUTUBE
~~~

This requires posts:write because it updates Rolino from provider evidence. It cannot upload, publish, or change visibility. UNKNOWN requires manual review. A missing ID or URL does not prove that no upload exists.

For an existing YouTube video, use preview_post_recovery and execute_post_recovery, or:

~~~bash
rolino --agent posts recovery preview POST_ID --project PROJECT_ID --expected-version VERSION --action ATTACH --video-id VIDEO_ID
rolino --agent posts recovery execute POST_ID --project PROJECT_ID --expected-version VERSION --action ATTACH --video-id VIDEO_ID --idempotency-key STABLE_KEY --yes
~~~

Show the preview's video, account, and consequence to the user. Execute only after approval. Supply its token through ROLINO_CONFIRMATION_TOKEN. ATTACH links the existing video and does not publish; check delivery afterward. To change the existing video's schedule, use RESUME with either --at ISO_DATE or --publish-now. In API or MCP input, RESUME requires publishAt as an explicit future UTC timestamp or null for publication now; ATTACH must omit it. Keep action, video ID, publication time, post version, and token identical between preview and execute. Reuse the same idempotency key on retries.

Recovery requires posts:write. RESUME also requires posts:schedule for a future time or posts:publish for publication now. QUEUED means the change is pending, not that the video is public. Recovery affects only the selected destination and never uploads another copy. Other providers support delivery checks according to their API permissions; unsupported checks remain unresolved.

## Immediate publish workflow

Immediate publishing is also two-step:

~~~bash
rolino --agent posts readiness POST_ID --project PROJECT_ID
rolino --agent posts publish preview POST_ID --project PROJECT_ID --expected-version VERSION --platform INSTAGRAM
~~~

After the user approves the exact destinations and consequence, pass the returned token through ROLINO_CONFIRMATION_TOKEN and execute with the same version and destinations:

~~~bash
rolino --agent posts publish execute POST_ID --project PROJECT_ID --expected-version VERSION --platform INSTAGRAM --idempotency-key STABLE_KEY
~~~

Use `--platform LINKEDIN` for an approved LinkedIn member destination; keep the preview and execute destination sets identical.

For immediate YouTube publishing, preserve the user's exact Public, Unlisted, or Private setting. The preview reports `deliveryMode: IMMEDIATE`, the configured visibility, and `createsSchedule: false`. Uploading and processing may continue after execute returns, but Rolino must not create or confirm a YouTube schedule for this flow.

A successful execute queues delivery; it is not proof that every provider has published. Inspect each destination's `deliveryMode` and `stage` afterward and report upload, processing, schedule confirmation, and publication accurately.

## Recovery rules

- `AUTH_REQUIRED`: ask the user to create or sign into a Rolino account and approve `rolino auth login` in the browser.
- `FORBIDDEN` or `SCOPE_REQUIRED`: explain which requested action lacks permission. The user must revoke or log out and authorize a new connection with that capability; never work around the scope.
- `BILLING_REQUIRED` or `LIMIT_REACHED`: report the plan restriction and direct the user to `https://getrolino.com/settings/billing`.
- `CONNECTION_REQUIRED` or a blocking integration-health result: direct the user to the project's Integrations page. OAuth and platform approval are user actions.
- `VALIDATION_ERROR`: preserve the server message, inspect the current post and readiness, and ask only for the missing decision or content.
- `CONFLICT`: fetch the latest resource before retrying. Never blind-retry with changed input under the same idempotency key.
- `RATE_LIMITED`: respect retryAfterSeconds.
- Network timeout or unknown provider result: inspect current state before retrying. Never assume a publish failed and send a duplicate.
- `LINKEDIN_PUBLISH_OUTCOME_UNKNOWN`: do not retry automatically or manually until the user checks the connected member's LinkedIn feed. Image initialization or upload failures occur before post creation and may follow Rolino's bounded safe retry path.

## Safety

- Reading, listing, health checks, readiness checks, and previews are safe to run without extra confirmation.
- Project and draft creation are writes; use Rolino's explicit consent flow and report what was created.
- Local file upload is a write and transfers a copy to the configured Rolino media store. Read and upload only files covered by the user's approved folder plan; never alter the originals.
- Scheduling and publishing affect external accounts. Require exact preview approval and never bypass Rolino's server confirmation.
- Do not expose bearer credentials or confirmation tokens in source code, command arguments when an environment variable is available, logs, or final responses.
- Do not claim success from intent. Verify the returned post, schedule, calendar event, or provider status and report blockers plainly.
