Goal
Execute a scheduled job run: generate N posts and schedule them directly (autopilot mode) — BUT only if governance allows. Falls back to Inbox if not permitted.
V2 Changes
- Direct scheduling capability — for trusted agents when Safe Mode OFF
- Workspace-level Safe Mode enforcement — if ON, downgrades to inbox routing
- Role-gated — only Editor/Admin agents can use this skill
- Graceful degradation — if scheduling denied, routes to inbox instead of failing
- Same agent memory integration as
bolta.cron.generate_to_review
When to Use This Skill vs bolta.cron.generate_to_review
| Skill |
Use When |
Routing |
bolta.cron.generate_to_review |
Safe automation (always human review) |
Always → Inbox |
bolta.cron.generate_and_schedule |
Autopilot (trusted agents, proven performance) |
→ Scheduled (if allowed) OR → Inbox (if not) |
Governance Decision Tree
Can this agent schedule directly?
├─ Is Safe Mode ON?
│ └─ YES → route to Inbox (Safe Mode overrides everything)
│ └─ NO → check role
│ ├─ Is agent role Editor or Admin?
│ │ └─ YES → schedule directly ✅
│ │ └─ NO → route to Inbox (Creator/Viewer always need approval)
Policy Rules
- Safe Mode ON → always route to Inbox (regardless of agent role)
- Safe Mode OFF + Editor/Admin role → schedule directly
- Safe Mode OFF + Creator/Viewer role → route to Inbox
- Scheduling requires valid schedule_times — if missing or malformed, route to Inbox
- Voice soft-delete → pause job immediately
- Account disconnected → pause job immediately
Steps
Pre-flight checks (same as generate_to_review):
bolta.get_workspace_policy(workspace_id) → extract safe_mode
bolta.get_my_capabilities(workspace_id) → verify scheduling capability
bolta.get_voice_profile(voice_profile_id) → verify active
bolta.get_account_info(account_id) → verify connected
- If voice deleted or account disconnected: fail and pause job
Determine execution mode:
if safe_mode == true:
execution_mode = "inbox"
reason = "Safe Mode ON"
else if agent.role in ["editor", "admin"]:
execution_mode = "schedule"
else:
execution_mode = "inbox"
reason = "Agent role requires approval"
Load agent memory for context (same as generate_to_review):
bolta.recall(agent_id, "top_performing_topics")
bolta.recall(agent_id, "preferred_hook_style")
bolta.recall(agent_id, "best_posting_times") → use if schedule_times not provided
Load recent posts:
bolta.list_recent_posts(account_ids, limit=10) → avoid repetition
Generate N posts (same logic as generate_to_review):
- For each of
n_posts:
- Render template OR generate from voice + memory
- Apply
run_instructions if provided
bolta.draft_post(...) → collect post_id
Route based on execution mode:
If execution_mode == "schedule":
For each post (index i):
If ALL posts scheduled successfully:
final_state = "scheduled"
If SOME scheduled, SOME to inbox:
final_state = "mixed"
- Create inbox_item for the failed ones
If NONE scheduled (all failed):
final_state = "inbox"
- Create single inbox_item for all posts
If execution_mode == "inbox":
- All posts transition to
inbox state
- Create
inbox_item_id for the bundle
final_state = "inbox"
- Add
reason to warnings (why downgraded: Safe Mode ON, role insufficient, etc.)
Update agent memory:
bolta.remember(agent_id, "last_scheduled_run", ISO_timestamp)
- If execution_mode == "schedule":
bolta.remember(agent_id, "scheduled_times_used", schedule_times) → learn optimal times
- If any posts failed to schedule:
bolta.remember(agent_id, "recent_failures", failure_reasons) → avoid repeating
Return execution summary:
run_id
scheduled_post_ids (posts that were scheduled)
inbox_post_ids (posts that were routed to inbox)
inbox_item_id (if any posts went to inbox)
final_state (scheduled | inbox | mixed)
warnings (downgrade reasons, scheduling failures, etc.)
tokens_used
Output Examples
Success (all scheduled)
{
"run_id": "uuid",
"scheduled_post_ids": ["uuid1", "uuid2", "uuid3"],
"inbox_post_ids": [],
"inbox_item_id": null,
"final_state": "scheduled",
"warnings": [],
"tokens_used": { "prompt": 1234, "completion": 567 }
}
Downgraded (Safe Mode ON)
{
"run_id": "uuid",
"scheduled_post_ids": [],
"inbox_post_ids": ["uuid1", "uuid2", "uuid3"],
"inbox_item_id": "bundle-uuid",
"final_state": "inbox",
"warnings": [
"Downgraded to inbox: Safe Mode ON (workspace-level governance)"
],
"tokens_used": { "prompt": 1234, "completion": 567 }
}
Mixed (partial failure)
{
"run_id": "uuid",
"scheduled_post_ids": ["uuid1", "uuid2"],
"inbox_post_ids": ["uuid3"],
"inbox_item_id": "bundle-uuid",
"final_state": "mixed",
"warnings": [
"Post 3: schedule_time missing, routed to inbox"
],
"tokens_used": { "prompt": 1234, "completion": 567 }
}
Failure Handling
Same as bolta.cron.generate_to_review:
- Voice deleted → pause job
- Account disconnected → pause job
- Template rendering fails → fall back to voice generation
- Max retries exceeded → create inbox item with error context
Additional (scheduling-specific):
- Invalid schedule_time → route that post to inbox, continue with others
- Platform API scheduling fails → route to inbox, add warning
- Missing schedule_times → route to inbox with suggestion to add times or use memory
When to Use This Skill (User Guidance)
Use bolta.cron.generate_to_review when:
- First setting up automation (test before trusting)
- High-sensitivity brands (every post needs eyes)
- New voice profiles (not proven yet)
- Experimental content strategies
Use bolta.cron.generate_and_schedule when:
- Agent proven reliable (reviewed 50+ posts, 95%+ approval rate)
- Safe Mode OFF (workspace decision)
- Editor/Admin role agents (trusted with scheduling)
- High-volume automation (24/7 content flow)
- Agency autopilot mode (30+ clients, can't manually review everything)
Migration path:
- Start with
generate_to_review (Safe Mode ON)
- Review agent output for 1-2 weeks
- If quality high: turn Safe Mode OFF, switch job to
generate_and_schedule
- Monitor audit logs; revert if quality drops
Agent Types That Use This Skill
- content_creator — Primary use case (autopilot content generation)
- custom — User-defined agents with full automation enabled
Example Job Configuration
{
"id": "job-uuid",
"agent_id": "trusted-creator-uuid",
"name": "Daily LinkedIn Autopilot",
"voice_profile_id": "bolta-voice-uuid",
"account_ids": ["linkedin-uuid"],
"schedule": {"cron": "0 10 * * 1-5"},
"trigger": "scheduled",
"status": "active",
"n_posts": 1,
"schedule_times": ["10:00"],
"client_tag": "Acme Corp",
"run_instructions": "Professional thought-leadership posts. Balance education vs promotion 70/30."
}
When Celery fires this job at 10am on weekdays:
- Checks Safe Mode (OFF) + agent role (Editor) → execution_mode = "schedule"
- Generates 1 post using voice + memory
- Schedules for 10:00am same day
- Post goes live at 10:00am without human intervention
- Human reviews retrospectively via audit logs
1---2name: bolta-cron-generate-and-schedule3version: 2.0.04description: V2 Job execution skill with direct scheduling - Agent generates N posts and schedules them ONLY if Safe Mode OFF AND agent is Editor/Admin. Otherwise routes to Inbox.5category: automation6roles_allowed: [Editor, Admin]7agent_types: [content_creator, custom]8safe_defaults:9 respect_safe_mode: true10 downgrade_to_review_on_deny: true11tools_required:12 - bolta.get_workspace_policy13 - bolta.get_my_capabilities14 - bolta.get_voice_profile15 - bolta.list_templates16 - bolta.render_template17 - bolta.draft_post18 - bolta.schedule_post19 - bolta.list_recent_posts20 - bolta.get_account_info21 - bolta.remember22 - bolta.recall23inputs_schema:24 type: object25 required: [workspace_id, agent_id, job_id, voice_profile_id, account_ids]26 properties:27 workspace_id: { type: string }28 agent_id: { type: string, description: "V2 - Agent executing this job (must have Editor/Admin role)" }29 job_id: { type: string, description: "V2 - Job ID for this run" }30 run_id: { type: string, description: "V2 - Run ID for audit logging" }31 voice_profile_id: { type: string }32 account_ids: { type: array, items: { type: string } }33 template_id: { type: string, description: "Optional template to use" }34 n_posts: { type: number, default: 3 }35 schedule_times: { type: array, items: { type: string }, description: "ISO timestamps; length >= n_posts preferred" }36 topic_seeds: { type: array, items: { type: string } }37 run_instructions: { type: string, description: "Job-specific override instructions" }38 client_tag: { type: string, description: "V2 - Agency client tag" }39outputs_schema:40 type: object41 properties:42 run_id: { type: string }43 scheduled_post_ids: { type: array, items: { type: string } }44 inbox_post_ids: { type: array, items: { type: string } }45 inbox_item_id: { type: string, description: "If any posts routed to inbox" }46 final_state: { type: string, enum: [scheduled, inbox, mixed] }47 warnings: { type: array, items: { type: string } }48 tokens_used: { type: object }49organization: bolta.ai50author: Max Fritzhand51---5253## Goal54Execute a scheduled job run: generate N posts and schedule them directly (autopilot mode) — BUT only if governance allows. Falls back to Inbox if not permitted.5556## V2 Changes57- **Direct scheduling capability** — for trusted agents when Safe Mode OFF58- **Workspace-level Safe Mode enforcement** — if ON, downgrades to inbox routing59- **Role-gated** — only Editor/Admin agents can use this skill60- **Graceful degradation** — if scheduling denied, routes to inbox instead of failing61- **Same agent memory integration** as `bolta.cron.generate_to_review`6263## When to Use This Skill vs `bolta.cron.generate_to_review`6465| Skill | Use When | Routing |66|---|---|---|67| `bolta.cron.generate_to_review` | Safe automation (always human review) | Always → Inbox |68| `bolta.cron.generate_and_schedule` | Autopilot (trusted agents, proven performance) | → Scheduled (if allowed) OR → Inbox (if not) |6970## Governance Decision Tree7172```73Can this agent schedule directly?74├─ Is Safe Mode ON?75│ └─ YES → route to Inbox (Safe Mode overrides everything)76│ └─ NO → check role77│ ├─ Is agent role Editor or Admin?78│ │ └─ YES → schedule directly ✅79│ │ └─ NO → route to Inbox (Creator/Viewer always need approval)80```8182## Policy Rules831. **Safe Mode ON → always route to Inbox** (regardless of agent role)842. **Safe Mode OFF + Editor/Admin role → schedule directly**853. **Safe Mode OFF + Creator/Viewer role → route to Inbox**864. **Scheduling requires valid schedule_times** — if missing or malformed, route to Inbox875. **Voice soft-delete → pause job immediately**886. **Account disconnected → pause job immediately**8990## Steps91921. **Pre-flight checks (same as generate_to_review):**93 - `bolta.get_workspace_policy(workspace_id)` → extract `safe_mode`94 - `bolta.get_my_capabilities(workspace_id)` → verify scheduling capability95 - `bolta.get_voice_profile(voice_profile_id)` → verify active96 - `bolta.get_account_info(account_id)` → verify connected97 - If voice deleted or account disconnected: fail and pause job98992. **Determine execution mode:**100 ```101 if safe_mode == true:102 execution_mode = "inbox"103 reason = "Safe Mode ON"104 else if agent.role in ["editor", "admin"]:105 execution_mode = "schedule"106 else:107 execution_mode = "inbox"108 reason = "Agent role requires approval"109 ```1101113. **Load agent memory for context (same as generate_to_review):**112 - `bolta.recall(agent_id, "top_performing_topics")`113 - `bolta.recall(agent_id, "preferred_hook_style")`114 - `bolta.recall(agent_id, "best_posting_times")` → use if schedule_times not provided1151164. **Load recent posts:**117 - `bolta.list_recent_posts(account_ids, limit=10)` → avoid repetition1181195. **Generate N posts (same logic as generate_to_review):**120 - For each of `n_posts`:121 - Render template OR generate from voice + memory122 - Apply `run_instructions` if provided123 - `bolta.draft_post(...)` → collect `post_id`1241256. **Route based on execution mode:**126127 **If execution_mode == "schedule":**128 - For each post (index i):129 - Get schedule time:130 - If `schedule_times[i]` provided → use it131 - Else if agent memory has `best_posting_times` → use learned time132 - Else → add warning, fall back to inbox for this post133 134 - Validate schedule time:135 - Must be future timestamp (> now + 5 minutes)136 - If invalid → add warning, route this post to inbox137 138 - `bolta.schedule_post(post_id, schedule_time)`139 - On success → add to `scheduled_post_ids`140 - On failure (API error, platform issue) → add to `inbox_post_ids` + warning141 142 - If ALL posts scheduled successfully:143 - `final_state = "scheduled"`144 - If SOME scheduled, SOME to inbox:145 - `final_state = "mixed"`146 - Create inbox_item for the failed ones147 - If NONE scheduled (all failed):148 - `final_state = "inbox"`149 - Create single inbox_item for all posts150151 **If execution_mode == "inbox":**152 - All posts transition to `inbox` state153 - Create `inbox_item_id` for the bundle154 - `final_state = "inbox"`155 - Add `reason` to warnings (why downgraded: Safe Mode ON, role insufficient, etc.)1561577. **Update agent memory:**158 - `bolta.remember(agent_id, "last_scheduled_run", ISO_timestamp)`159 - If execution_mode == "schedule":160 - `bolta.remember(agent_id, "scheduled_times_used", schedule_times)` → learn optimal times161 - If any posts failed to schedule:162 - `bolta.remember(agent_id, "recent_failures", failure_reasons)` → avoid repeating1631648. **Return execution summary:**165 - `run_id`166 - `scheduled_post_ids` (posts that were scheduled)167 - `inbox_post_ids` (posts that were routed to inbox)168 - `inbox_item_id` (if any posts went to inbox)169 - `final_state` (scheduled | inbox | mixed)170 - `warnings` (downgrade reasons, scheduling failures, etc.)171 - `tokens_used`172173## Output Examples174175### Success (all scheduled)176```json177{178 "run_id": "uuid",179 "scheduled_post_ids": ["uuid1", "uuid2", "uuid3"],180 "inbox_post_ids": [],181 "inbox_item_id": null,182 "final_state": "scheduled",183 "warnings": [],184 "tokens_used": { "prompt": 1234, "completion": 567 }185}186```187188### Downgraded (Safe Mode ON)189```json190{191 "run_id": "uuid",192 "scheduled_post_ids": [],193 "inbox_post_ids": ["uuid1", "uuid2", "uuid3"],194 "inbox_item_id": "bundle-uuid",195 "final_state": "inbox",196 "warnings": [197 "Downgraded to inbox: Safe Mode ON (workspace-level governance)"198 ],199 "tokens_used": { "prompt": 1234, "completion": 567 }200}201```202203### Mixed (partial failure)204```json205{206 "run_id": "uuid",207 "scheduled_post_ids": ["uuid1", "uuid2"],208 "inbox_post_ids": ["uuid3"],209 "inbox_item_id": "bundle-uuid",210 "final_state": "mixed",211 "warnings": [212 "Post 3: schedule_time missing, routed to inbox"213 ],214 "tokens_used": { "prompt": 1234, "completion": 567 }215}216```217218## Failure Handling219220**Same as `bolta.cron.generate_to_review`:**221- Voice deleted → pause job222- Account disconnected → pause job223- Template rendering fails → fall back to voice generation224- Max retries exceeded → create inbox item with error context225226**Additional (scheduling-specific):**227- Invalid schedule_time → route that post to inbox, continue with others228- Platform API scheduling fails → route to inbox, add warning229- Missing schedule_times → route to inbox with suggestion to add times or use memory230231## When to Use This Skill (User Guidance)232233**Use `bolta.cron.generate_to_review` when:**234- First setting up automation (test before trusting)235- High-sensitivity brands (every post needs eyes)236- New voice profiles (not proven yet)237- Experimental content strategies238239**Use `bolta.cron.generate_and_schedule` when:**240- Agent proven reliable (reviewed 50+ posts, 95%+ approval rate)241- Safe Mode OFF (workspace decision)242- Editor/Admin role agents (trusted with scheduling)243- High-volume automation (24/7 content flow)244- Agency autopilot mode (30+ clients, can't manually review everything)245246**Migration path:**2471. Start with `generate_to_review` (Safe Mode ON)2482. Review agent output for 1-2 weeks2493. If quality high: turn Safe Mode OFF, switch job to `generate_and_schedule`2504. Monitor audit logs; revert if quality drops251252## Agent Types That Use This Skill253- **content_creator** — Primary use case (autopilot content generation)254- **custom** — User-defined agents with full automation enabled255256## Example Job Configuration257```json258{259 "id": "job-uuid",260 "agent_id": "trusted-creator-uuid",261 "name": "Daily LinkedIn Autopilot",262 "voice_profile_id": "bolta-voice-uuid",263 "account_ids": ["linkedin-uuid"],264 "schedule": {"cron": "0 10 * * 1-5"},265 "trigger": "scheduled",266 "status": "active",267 "n_posts": 1,268 "schedule_times": ["10:00"],269 "client_tag": "Acme Corp",270 "run_instructions": "Professional thought-leadership posts. Balance education vs promotion 70/30."271}272```273274When Celery fires this job at 10am on weekdays:2751. Checks Safe Mode (OFF) + agent role (Editor) → execution_mode = "schedule"2762. Generates 1 post using voice + memory2773. Schedules for 10:00am same day2784. Post goes live at 10:00am without human intervention2795. Human reviews retrospectively via audit logs