SuperAPI AI Directory

postey-voice

Design & creation

View repository

Updated 10-16 03:44

About this skill

Postey Voice

Two ways to learn a voice, and they compose:

Cold start Warm loop
What it reads Posts already published What happens to each draft — edits, approvals, deletions
When it runs Once, on first use Every time a draft is acted on
Needs history? Yes — nothing to read on a new account No, it builds its own
Produces The initial profile Rules appended to the ledger
Recoverable later? Yes, published posts persist No — capture live or lose it

One profile per account — ask first

Read postey://accounts and, if more than one is connected, ask which account this profile is for. Never derive a voice without naming the account.

A creator with one account, a brand with three, and an agency with twelve are the same code path and different failure costs. For the agency, applying one profile to the wrong account puts a client's voice in another client's post.

Situation What to do
One account connected Use it, and say which one you used
Several connected, user named one Use that one
Several connected, user named none Ask. Do not infer from the most recent post or the first in the list
Deriving from local files, no account in play Allowed, but the profile is unscoped — say so

Every profile carries profile_for. A profile whose profile_for is null was derived without an account and must not be applied to a named account — re-derive with the account set. corpus.accounts is a separate field: the accounts the evidence was read from.

The CLI mirrors this. --account <id> records the scope and names the output voice-profile-<id>.json, so two accounts cannot overwrite each other's profile. Omitting it writes profile_for: null and warns.

What this skill cannot know

It knows nothing before it is installed. Say so rather than implying otherwise.

The server has no REJECTED state — PostStatusEnum is DRAFT | SCHEDULED | PUBLISHING | PUBLISHED. Rejection is expressed by deleting the draft, which destroys the evidence. So:

Signal Available retroactively?
Published posts, and which performed best yes — this is the cold start
Reviewer notes (internal comments) yes
What was edited between draft and publish no — must be captured live
What was rejected, and why no — must be captured live

A rejection made in the Postey web UI is invisible to this skill, permanently. Only drafts this agent created in-session can be tracked through to their verdict.

Bulk ingest — content the user already has

Fastest path to a first profile, and it needs no account access at all:

${CLAUDE_SKILL_DIR}/scripts/voice.js ingest ./their-writing --account 317

Pass --account whenever the profile is for a connected account — it names the output voice-profile-317.json and records the scope. Omit it only when the corpus genuinely belongs to no account yet; the result is then explicitly unscoped.

Accepts a directory, a single file, or a JSON export (.md, .txt, .json; a bare array, {posts:[…]} or {data:[…]}). A JSON export becomes one document per row, keeping post_id, platform and published_at; a text file becomes one document dated by its mtime.

Useful flags: --account <id> to scope the profile, --scope LINKEDIN to attribute everything to one platform, --since <ISO> to ignore old work, --out <file> to write the ledger.

It emits countable features and rule observations — never an opinion. Judgements like "warm but authoritative" are yours to make from reading the corpus; the CLI only measures what cannot be argued with, so that every rule can name its evidence.

Then compile:

${CLAUDE_SKILL_DIR}/scripts/voice.js compile ./voice-ledger.json

Full flag list: command-reference.md.

Cold start — the published corpus

  1. get_posts(status=PUBLISHED) per account.
  2. Read each one's text: postey://posts/{post_id}/content/{platform}.
  3. Weight by postey://accounts/{account_id}/analytics/posts — profile what worked, not merely what shipped. Check the numbers are real first. On the account checked during development, every LinkedIn post reported zero impressions while the same content on X reported between 481 and 2,935. Weighting by a metric that is uniformly zero silently weights by nothing; say so and fall back to unweighted rather than implying the ranking meant something.

Corpus hygiene — read this before trusting a pass

A Postey account accumulates QA and pipeline-test posts, and they are PUBLISHED like anything else. A real account checked during development had 88 published LinkedIn posts, of which a large share were artifacts: AUDIT-PUBLISH-PROBE, publish-fix validation test, testf, sdsd sdssdaaaa, qwetgvdbmFgh. Ingest those and you will learn that the user writes gibberish.

Exclude a post from the corpus when any of these hold:

  • the title or text reads as a probe — test, probe, validation, [dev], please ignore
  • the text is not language — no sentence structure, repeated character runs
  • it is a duplicate of another post with a near-identical opening

Then say how many you dropped and why. A silent filter is as misleading as no filter.

  1. Derive observable features only: sentence length distribution, how posts open and close, punctuation habits, emoji and hashtag rate, whether there is a CTA and what shape it takes.

Write findings into the profile with the post IDs they came from. A claim about the user's voice with no citation is a guess, and it will be treated as evidence later.

Warm loop — the verdict ledger

The edit delta is the core of this skill. It is free, it is specific, and it states exactly what was wrong in the user's own correction. Analytics is the tiebreaker, not the primary signal.

Two gates. Both are mandatory; skip either and the loop silently never runs:

  • Before drafting anything — read the profile and the active rules.
  • After every outcome — append a verdict to the ledger.

Append verdicts to the same ledger file, then re-run voice.js compile. Thresholds are applied by the script, not by eye — counting evidence across sessions by hand is exactly what drifts.

Format and thresholds: rules-ledger.md. Profile shape: voice-profile-schema.md.

Where the profile lives

Client-side — memory, project knowledge, or a file the user keeps. The MCP server has no write path for skill state, and the hub's brand-profile-template.md already establishes this pattern.

It is user content. Never commit it, never log it, never send it anywhere.

Hard limits

A learned rule never overrides a platform limit. Character counts, media rules and platform mechanics come from postey://platform-limits and the hub, which owns platform truth. If a rule and a limit disagree, the limit wins and the rule is noted as inapplicable there.

The interview flow

When there is no corpus and no profile — a new account, or a user who wants to state their voice rather than have it inferred — run the interview: references/brand-voice.md. Prefer evidence over self-report where both exist: what someone publishes is a better record of how they write than what they say about how they write.