Echo/Docs

CLI command

voice

A product's brand voice and threshold: every blog post of its surfaces is scored against it before the blog admin publishes it, and one below the threshold is held for a reviewer.

Invocation#

Shell
echo-cli voice show --product <id>
echo-cli voice set --product <id> --file <voice.json> --threshold <0-1> --by <name>
echo-cli voice remove --product <id>
echo-cli voice score --post <post-id> --by <name>
echo-cli voice scores --post <post-id>

Inputs and output#

show, set and remove write the profile: product_id, voice, examples, threshold, set_by and set_at (show writes null when the product declares no voice). score writes the stored score and scores a post's scores, newest first: id, post_id, product_id, score, threshold, passed, reasons, route, scored_by and scored_at.

State effect#

Every verb calls Echo Web's authenticated /api/analytics/voice with ECHO_INTERNAL_BEARER at ECHO_WEB_BASE_URL; the Brand voice section of the blog admin calls the same operations, and echo-mcp reads them as echo_voice_profile and echo_voice_scores. --file holds one JSON object { voice, examples }: how the product sounds in the operator's words, and at least one passage written in it. The threshold is the least score, a share from 0 to 1 of a full match, a post must reach to be published without review. A post is scored by the route ECHO_VOICE_ROUTE declares, through Brama, which must call its scoring tool with a score from 0 to 1 and its reasons; every score is stored in voice_scores. When the blog admin's Publish button is pressed for a post whose surface's product declares a voice, the post is scored first: at or above the threshold it is published as before; below it, it is not published but held in the approval queue as publish_blog_post with the score and reasons as the request's reason, and the button answers "not published: voice score <score> is below the threshold <threshold> (<reasons>); held for approval as request <id>". A reviewer's approval publishes it without scoring it again. A product with no voice publishes without a voice check.

Refusals#

  • A wrong invocation is refused before anything is sent: "voice takes <every verb's usage, separated by semicolons>; got <word>", "voice <verb> does not take <flag>; it takes …", "<flag> needs a value", "voice <verb> needs <flag>", "--threshold must be a number from 0 to 1; got <value>", "--file <path> is not a readable JSON file: <cause>" and "--file <path> must hold one JSON object { voice, examples }".
  • Echo Web answers a bad request with "product_id is required: …", "voice is required: how the product sounds, in the operator's words", "examples is required: at least one passage written in the voice", "threshold must be a number from 0 to 1: the least score a post must reach to be published without review; got <value>", "post_id is required: …" or "blog surface <slug> names no product, so no voice says how its posts must sound; echo-cli glossary surface --surface <slug> --product <id> names it"; not found with "no product has id <id>; echo-cli products lists the ones that exist", "no blog post has id <id>", "product <id> has no voice profile, so there is no threshold to score post <id> against; echo-cli voice set --product <id> declares one" or "product <id> has no voice profile; echo-cli voice set declares one". A deployment without ECHO_VOICE_ROUTE answers "ECHO_VOICE_ROUTE is required", and a route that answers without the scoring tool, with a score outside 0 to 1 or without reasons is the error naming it. The command prints Echo Web's sentence and exits 1.