Blog Topic How-to Tutorials

Social scheduler stack: Jev + OpenQuok's posting API

1 min read Rati Montreewat
Blog post content
Social scheduler stack: Jev + OpenQuok's posting API

Decide what to post before you schedule it

Your social scheduler should not publish every idea an AI or a teammate drops in chat. Good practice is to ask three questions before you post: Is it relevant? Is it engaging? Is it actionable? You should also ask whether the copy fits each network — or whether one Global caption is enough.

Add two more checks: do you have strong visuals, and is the post customized for the channel it will appear on? Cross-posting the same text everywhere without edits often underperforms.

OpenQuok models that split in the composer: Global mode shares one caption and one media list across selected channels. Per-channel mode lets each network keep its own copy and attachments. The Public API uses body, isGlobal, bodiesByIntegrationId, and mediaByIntegrationId — the same idea as the dashboard globe vs channel avatars. See Global vs per-channel.

Jev (a decision model from TypeSafe AI) can score those checks in one fast call. It returns typed answers and confidence — not a long essay. OpenQuok does not ship Jev. You compose both in your app. Full sample: Jev decision routing example.

LLMs write. Decision models choose — and cost less at the gate

Large language models generate text token by token. That is ideal for drafts and rewrites. Many scheduling gates do not need prose. They need labels: ready or not, Global or per-channel, needs media or not.

Decision models answer inside a schema you define. Jev supports Choice, Score, and Noul (yes/no probability). You pay for compact input; structured answers are cheap compared with asking a large LLM to write a paragraph every time a teammate pastes a caption. Use Jev on every proposal as the whether and how gate. Call an LLM only when copy still needs rewriting.

That split matters in a CLI or agent loop: you can run Jev on hundreds of drafts without paying full chat-completion prices, then fill a predefined OpenQuok JSON recipe only when the scores pass.

Encode “what to post” as Jev questions

One systemOne call can score all five checks. If a gate fails, stop or send the item to a human — do not enqueue a scheduled post.

  • Relevant — Noul: is this useful to the audience (inform, entertain, or community)?

    If it fails: do not create an OpenQuok draft.

  • Engaging — Score: would someone want to read and react?

    If it fails: send to human review and revise copy.

  • Actionable — Noul: would someone share, comment, or click?

    If it fails: optional extra gate before automation.

  • Visuals — Noul: does this need a photo or video?

    If it fails: still create a draft, but add a kanban note to attach media.

  • Channel fit — Choice: compose_mode (Global, per-channel copy, settings-only, or not ready).

    If it fails or is not_ready: skip the API call; edit in the composer.

The compose_mode choice maps directly to OpenQuok JSON — the same shapes the CLI and openquok-core skill already ship as examples:

  • global_same_copy — one body, isGlobal: true, multiple integrationIds (like threads-text-only.json).

  • per_channel_copybodiesByIntegrationId for different captions per UUID (like multi-platform-campaign.json).

  • global_copy_per_channel_settings — shared body, different providerSettingsByIntegrationId (YouTube title, Instagram post_type, etc. — like youtube-video-title-privacy.json).

  • not_ready — no API call; human edits in the composer.

Those files live under agent/skills/openquok-core/resources/examples/. Agents do not invent payload shape from scratch: Jev picks a mode, your script copies the matching example, fills channel UUIDs and caption, then runs openquok posts:create --json. Install the skill from CLI getting started or assemble recipes in Skill Builder. To inspect the same JSON in a browser, use Payload Wizard.

Architecture: decide → fill a recipe → approve

  1. Decide — Jev runs relevant / engaging / actionable / visuals / compose_mode in one cheap systemOne call.

  2. Compose — Map compose_mode to a predefined openquok-core example (or preview it in Payload Wizard) and fill PublicCreatePostDto.

  3. Execute — CLI: openquok posts:create --json. SDK: postAsAgent() against the posting API. Use scheduling API examples when you need scheduledAt or repeatInterval.

  4. Approve — Teammates review on the OpenQuok calendar or kanban, attach media if needed, then schedule.

Multi-tenant apps store each user’s opo_ token after OAuth2 Authorization Code. CLI and CI use a workspace programmatic token instead. See OAuth2 for apps and the full walkthrough at Jev decision routing example.

TypeScript sketch

Ask Jev whether the post is ready and how to compose it. Then map compose_mode onto a known OpenQuok recipe instead of generating JSON from an LLM:

                      const decision = await jev.systemOne({
                      state: { proposal: { caption: globalCaption, targets: ["threads", "linkedin"] } },
                      questions: {
                      relevant: noul("The post is relevant — it informs, entertains, or serves the audience"),
                      engaging: score("How engaging is this copy for social feeds?", [
                      "Flat or generic",
                      "Acceptable — clear but not compelling",
                      "Strong — likely to earn likes or replies",
                      ]),
                      actionable: noul("A reader would want to share, comment, or take a clear next step"),
                      needs_media: noul("The post requires or strongly benefits from a photo or video"),
                      compose_mode: choice("How should OpenQuok compose this post?", {
                      global_same_copy: "One caption for every selected channel",
                      per_channel_copy: "Different caption per network",
                      global_copy_per_channel_settings: "Same caption; platform settings differ",
                      not_ready: "Copy is not ready to schedule",
                      }),
                      },
                      });
                      if (decision.answers.compose_mode.choice === "global_same_copy") {
                      await openquok.postAsAgent({
                      status: "draft",
                      body: globalCaption,
                      integrationIds: [threadsId, linkedInId],
                      isGlobal: true,
                      isAgent: true,
                      scheduledAt: tomorrowIso,
                      });
                      }
                    

Runnable copy: sdk/examples/jev-route-draft.mjs (aligned with the doc page). The CLI equivalent is: pick threads-text-only.json (or multi-platform-campaign.json), substitute IDs, then openquok posts:create --json ./payload.json.

When to stay Global vs customize per channel

Stay Global when the same announcement and attachments should go everywhere and only settings differ (post type, title, tags). Customize per channel when tone, length, hashtags, or media differ — Threads casual, LinkedIn formal, Instagram square crop. Jev’s per_channel_copy branch matches the second case; your team still approves in the composer before publish.

CLI, MCP, and the posting API

The decision step is identical everywhere. Only execution changes:

  • CLIopenquok-core examples are the contract. Jev chooses the file; the CLI posts it. See CLI usages and CLI examples.

  • MCP — Agents using OpenQuok MCP can call schedulePostTool with the same JSON after Jev decides.

  • HTTP / SDK — Same payload on the posting API hub; add scheduledAt from the scheduling API hub when you need a future publish.

What we are not claiming

  • OpenQuok does not operate or resell Jev.

  • Decision models do not replace LLMs for writing great captions.

  • Automated drafts should stay draft until a human confirms relevance, visuals, and channel fit.

Takeaway

A modern social scheduler stack separates judgment from scheduling. Jev is a cheap typed gate for “should we post this, and how?” OpenQuok already has predefined JSON recipes for Global vs per-channel posts — fill them from the CLI, Payload Wizard, or posting API. Start with Jev decision routing example.

Frequently asked questions

How to

  1. 1. Define Jev decision questions text

    List relevant, engaging, actionable, visuals, and compose_mode as Jev questions. See Jev decision routing example.

  2. 2. Run systemOne on the proposal text

    Pass caption and target channels in state. Block automation when relevance or engagement scores are below your threshold.

  3. 3. Map compose_mode to OpenQuok JSON

    Global: isGlobal: true. Per-channel: bodiesByIntegrationId. Settings-only: providerSettingsByIntegrationId. Optionally preview in Payload Wizard.

  4. 4. Create a draft via the posting API text

    Call postAsAgent() with the user’s opo_ token. Platform examples: posting API.

  5. 5. Approve in the workspace text

    Review on the calendar or kanban. Attach media if Jev flagged needs_media, then promote to scheduled.

Comments

No comments yet.

Add a comment

Sign in to comment.

0/1000

Start free. Publish with confidence.

Connect your agent, review every draft, and schedule posts across channels before anything goes live.

Discord Support