Automate

Automating content: from one-off run to a pipeline that publishes itself

A single diagnose-and-fix pass is useful once. A playbook is the same steps wired to run on their own, on a schedule or a trigger, all the way through to a published post. Here is how that actually works under the hood.

~7 min read . Automate

Running analyze_content, then optimize_content, then publishing the result once is useful. Doing that same sequence every week, for every new draft, without you opening the tool each time, is automation. AdAstra's playbooks are how a one-off tool run becomes a pipeline: a graph of steps with branching, retries and a schedule, ending wherever you want the finished content to land.

From one-off to pipeline

A playbook is a directed graph of nodes and edges: tool calls (analyze_content, optimize_content, optimize_headline, generate_keyword_ideas and the rest) wired together with control-flow nodes that decide what runs next. Nothing about a playbook changes what a tool does; it changes when it runs, in what order, and what happens to its output next. The same analyze-then-optimize sequence you would run by hand becomes a run you kick off once, and reuse indefinitely.

Under the hood, a run walks the graph from its root nodes, executing each one and following its outgoing edges to whatever comes next. Every node reports its own status, ok or error, and its output; downstream nodes reference that output directly, so a later step reads exactly what an earlier tool call produced rather than you copying values around by hand.

Playbooks and control flow

Four node kinds give a playbook actual logic instead of a straight line. An if node evaluates a set of conditions and sends the run down its true or false branch. A switch node checks a list of named rules in order and follows whichever one matches first, or falls through to a default branch if none do. A filter node checks a condition and either lets the run continue (pass), or the branch simply stops there, with nothing downstream. A loop node walks an array, either one item at a time (each) or in fixed-size groups (batch), running its body once per item or batch up to a configured maximum number of iterations.

Conditions themselves are the same building block everywhere: compare a value against another using operators like equals, contains, greater-than, is-empty or matches-regex, combined with AND or OR. A node with two or more incoming branches (a diamond join, where two paths merge back into one) waits for every branch that is actually going to run before it continues, so a fast branch never races ahead of a slower one still in flight.

Failures are handled per tool node, not per playbook. Each tool call carries a retry policy, a maximum number of tries and a wait between attempts, either a fixed delay or exponential backoff that doubles each time. Only errors classed as transient (a temporary outage) or rate-limited get retried; a permanent error, like invalid input, fails immediately. Once retries are exhausted, the node's onError setting decides what happens next: stop the whole run, continue down the regular path anyway, or continue down a dedicated error branch.

Scheduling and triggers

A playbook can start in one of three ways. A manual trigger runs it on demand, the same as running a tool by hand. A webhook trigger gives the playbook its own token-protected URL, so an external system, or you, can start a run with a request. A cron trigger runs the playbook on a recurring schedule, defined as a cron expression with its own timezone.

text
cron: "0 8 * * 1"
timezone: "Europe/Berlin"
# illustrative: every Monday at 08:00, Europe/Berlin

That is an illustrative schedule, not a fixed default: any valid cron expression is accepted, and it is validated when the trigger is saved rather than discovered as a runtime surprise later. A cron trigger's next run time is computed from the expression and timezone together, so a schedule keeps meaning "eight in the morning" through a daylight-saving shift instead of drifting by an hour.

A background tick enumerates every playbook due to run right now and runs each one in turn, in its own isolated failure and timeout domain, so one hung run cannot stall the rest of the batch. What matters most is what happens if a playbook is still running when its next slot arrives: AdAstra claims each run atomically before starting it, so a playbook already in progress cannot be triggered a second time on top of itself. A cron slot that lands mid-run is recorded as skipped, not started as an overlapping run. Only a cron-fired run advances the schedule forward; a manual run never eats into the next cron slot.

Publishing to WordPress

WordPress publishing is not a node inside the playbook graph above: the tool registry a playbook draws on has no WordPress tool, so no tool_call node can carry a run's output to a site directly. It runs through a second, separate automation surface instead. Asking AdAstra to automate publishing, on a daily, weekly, biweekly or monthly cadence, registers a recurring job against a connected WordPress profile, independent of the graph-based scheduler covered above.

That job authenticates the same way anywhere else in AdAstra does: against the site's own JWT endpoint (wp-json/jwt-auth/v1/token) with your WordPress credentials, then uses the token it gets back to create the post through the standard WordPress REST API (wp-json/wp/v2/posts), with title, content, tags and, if supplied, a featured image uploaded to the media library first. You choose the resulting post status the same way you would publishing by hand: live immediately, or a draft so a human reviews it first.

Guardrails

Automation does not turn off the checks that apply everywhere else in AdAstra. A scheduled or webhook-triggered run still calls the same analyze_content, optimize_content and optimize_headline tools covered elsewhere: the same three-theme diagnosis, the same grounded Google Ads numbers, no fabricated keyword data standing in for a lookup that failed. A failure inside a playbook is not a silent skip either: it is recorded on the node with its error class, and either stops the run or routes down whatever error path you configured.

The double-run prevention matters most for guardrails, not convenience. Without an atomic claim on each run, an overlapping trigger could start a second pass over content a first pass has not finished optimizing, or publish a duplicate draft from a run that should have been skipped. Claiming the run before any tool executes is what keeps a scheduled pipeline safe to leave unattended.

The short version

  • A playbook is a graph of tool calls plus control-flow nodes; it changes when and in what order tools run, not what any single tool does.
  • if, switch, filter and loop nodes give a playbook branching, named-rule matching, drop conditions and per-item or per-batch iteration, all driven by the same AND/OR condition rows.
  • Every tool node carries its own retry policy (fixed or exponential backoff, transient and rate-limited errors only) and an onError setting: stop, continue regular, or continue down an error branch.
  • Playbooks start from a manual run, a token-protected webhook, or a cron schedule with its own timezone; only a cron-fired run advances that schedule forward.
  • An atomic run-claim prevents a playbook from running twice at once; a cron slot that lands mid-run is recorded as skipped, not started as a second overlapping run.
  • WordPress publishing is a separate, cadence-based automation, not a playbook step: a recurring job publishes to a connected site via JWT auth and the standard REST API, as a live post or a draft awaiting review.
  • Automated runs get no exceptions on data quality: the same grounded diagnosis and optimization checks apply, and failures are recorded and routed, never silently skipped.
Was this helpful?

Let your content pipeline run itself.

AdAstra schedules the diagnose-and-fix loop all the way to a published draft.

Join the waitlist