Goal
Move posts from Inbox → Approved, optionally → Scheduled, based on workspace governance and scheduling preferences.
Which Agent Types Use This
- reviewer — Primary use case (human-guided approvals or auto-approvals after triage)
- custom — User-defined agents with approval permissions
Hard Rules
- Must have Editor or Admin role (only these roles can approve).
- Scheduling requires additional permission (
posts:schedule capability).
- Never publish directly — this skill routes to
approved or scheduled, NOT published.
- Respect per-post metadata:
- If post has
suggested_time in metadata, use it (unless overridden)
- If post has
do_not_schedule flag, skip scheduling even if requested
- If Safe Mode ON: scheduling is separate action after approval.
- If Safe Mode OFF: approval can include scheduling in one step.
Steps
1. Check policy & capabilities
bolta.get_workspace_policy(workspace_id) → extract safe_mode
bolta.get_my_capabilities(workspace_id) → verify review:approve and posts:schedule
- If missing
review:approve: fail immediately (unauthorized)
2. Load post metadata
- For each
post_id:
bolta.get_inbox_item(post_id) → fetch post content, current state, suggested_time, metadata
- Verify state is
inbox (can't approve what's not in inbox)
- Extract
suggested_time from metadata if present
3. Approve posts (Inbox → Approved)
- For each post_id:
bolta.approve_post(post_id)
- On success: post transitions to
approved state
- Add to
approved_ids
- If agent_id provided: add comment
bolta.add_comment(post_id, "Approved by {agent.name}")
- On failure (permission denied, invalid state):
- Add to
failed array with reason
- Continue with remaining posts
4. Route to Scheduled (if requested)
If schedule_mode == "approve_only":
- Stop here. Posts remain in
approved state.
- Human can schedule them later manually.
final_states[post_id] = "approved"
If schedule_mode == "use_suggested_time":
- For each approved post:
- If post has
suggested_time in metadata:
- Validate time (must be future, > now + 5 minutes)
bolta.schedule_post(post_id, suggested_time)
- On success: add to
scheduled_ids, final_states[post_id] = "scheduled"
- On failure: add to
failed, post remains approved
- Else (no suggested_time):
- Add warning: "No suggested_time, post remains approved"
final_states[post_id] = "approved"
If schedule_mode == "set_fixed_time":
- Requires
fixed_time parameter
- For each approved post:
bolta.schedule_post(post_id, fixed_time)
- On success: add to
scheduled_ids
- On failure: add to
failed, post remains approved
If schedule_mode == "use_agent_memory":
- Requires
agent_id
bolta.recall(agent_id, "best_posting_times") → get learned optimal times
- For each approved post (index i):
- Pick schedule time from agent memory
bolta.schedule_post(post_id, calculated_time)
- On success: add to
scheduled_ids
- On failure: add to
failed, post remains approved
If schedule_times array provided:
- Must match length of
post_ids
- For each post (index i):
bolta.schedule_post(post_ids[i], schedule_times[i])
- On success: add to
scheduled_ids
- On failure: add to
failed, post remains approved
5. Handle scheduling failures gracefully
- If platform API fails (Twitter down, account disconnected):
- Post remains in
approved state
- Add to
failed with specific error
- Don't revert approval (human can retry scheduling later)
- If schedule time invalid (past, too soon):
- Add to
failed with validation error
- Post remains
approved
6. Update agent memory (if agent context)
- If
agent_id provided:
bolta.remember(agent_id, "last_approval_batch_size", post_ids.length)
bolta.remember(agent_id, "approval_success_rate", success_count / total_count)
- If scheduling used:
bolta.remember(agent_id, "scheduled_times_used", schedule_times)
Output
{
"approved_ids": ["uuid1", "uuid2", "uuid3"],
"scheduled_ids": ["uuid1", "uuid2"],
"failed": [
{
"post_id": "uuid3",
"reason": "Platform API error: Twitter rate limit exceeded",
"recoverable": true
}
],
"final_states": {
"uuid1": "scheduled",
"uuid2": "scheduled",
"uuid3": "approved"
}
}
Failure Handling
- Partial approval failure: If some posts fail to approve, continue with others.
- Partial scheduling failure: If some fail to schedule, others still succeed.
- Never revert approvals: Once approved, post stays approved even if scheduling fails.
- Bulk operation resilience: One failure doesn't block the batch.
V2 Agent Context
When agents use this skill:
Reviewer agent reasoning:
"I triaged 8 inbox items and identified 5 as ready to approve. I'll approve them with schedule_mode=use_agent_memory to use the posting times I've learned perform best."
Key workflow:
bolta.inbox.triage → identify ready items
bolta.review.approve_and_route → approve + schedule
bolta.remember → store approval patterns
Example Use Cases
Scenario 1: Human Manual Approval (No Scheduling)
{
"workspace_id": "uuid",
"post_ids": ["uuid1", "uuid2", "uuid3"],
"schedule_mode": "approve_only"
}
Result: 3 posts → approved state, human schedules them later
Scenario 2: Bulk Approve & Schedule with Suggested Times
{
"workspace_id": "uuid",
"post_ids": ["uuid1", "uuid2", "uuid3"],
"schedule_mode": "use_suggested_time"
}
Result: 3 posts approved → scheduled using each post's suggested_time metadata
Scenario 3: Reviewer Agent Auto-Approval
- Reviewer agent runs
bolta.inbox.triage
- Identifies 8 posts as "ready to approve" (high confidence)
- Calls this skill with those 8 post_ids +
schedule_mode: use_agent_memory
- Agent uses learned optimal posting times
- 8 posts → approved → scheduled
- Human reviews retrospectively
Scenario 4: Agency Bulk Scheduling
- Agency approves 20 client posts
- Wants them all to go out at 10am tomorrow
schedule_mode: set_fixed_time, fixed_time: "2026-02-21T10:00:00Z"
- 20 posts → approved → scheduled for same time
Scenario 5: Partial Failure Recovery
- Approve 5 posts, schedule 5
- 2 scheduling calls fail (Twitter API down)
- Output: 5 approved, 3 scheduled, 2 failed (but still approved)
- Human can retry scheduling the 2 later when Twitter is back
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: bolta-review-approve-and-route3description: Approve inbox posts and route to Approved→Scheduled based on workspace governance. Handles bulk approvals with flexible scheduling. Use when this capability is needed.4---56## Goal7Move posts from Inbox → Approved, optionally → Scheduled, based on workspace governance and scheduling preferences.89## Which Agent Types Use This10- **reviewer** — Primary use case (human-guided approvals or auto-approvals after triage)11- **custom** — User-defined agents with approval permissions1213## Hard Rules141. Must have Editor or Admin role (only these roles can approve).152. Scheduling requires additional permission (`posts:schedule` capability).163. Never publish directly — this skill routes to `approved` or `scheduled`, NOT `published`.174. Respect per-post metadata:18 - If post has `suggested_time` in metadata, use it (unless overridden)19 - If post has `do_not_schedule` flag, skip scheduling even if requested205. If Safe Mode ON: scheduling is separate action after approval.216. If Safe Mode OFF: approval can include scheduling in one step.2223## Steps2425### 1. Check policy & capabilities26- `bolta.get_workspace_policy(workspace_id)` → extract `safe_mode`27- `bolta.get_my_capabilities(workspace_id)` → verify `review:approve` and `posts:schedule`28- If missing `review:approve`: fail immediately (unauthorized)2930### 2. Load post metadata31- For each `post_id`:32 - `bolta.get_inbox_item(post_id)` → fetch post content, current state, suggested_time, metadata33 - Verify state is `inbox` (can't approve what's not in inbox)34 - Extract `suggested_time` from metadata if present3536### 3. Approve posts (Inbox → Approved)37- For each post_id:38 - `bolta.approve_post(post_id)`39 - On success: post transitions to `approved` state40 - Add to `approved_ids`41 - If agent_id provided: add comment `bolta.add_comment(post_id, "Approved by {agent.name}")`42 - On failure (permission denied, invalid state):43 - Add to `failed` array with reason44 - Continue with remaining posts4546### 4. Route to Scheduled (if requested)4748**If schedule_mode == "approve_only":**49- Stop here. Posts remain in `approved` state.50- Human can schedule them later manually.51- `final_states[post_id] = "approved"`5253**If schedule_mode == "use_suggested_time":**54- For each approved post:55 - If post has `suggested_time` in metadata:56 - Validate time (must be future, > now + 5 minutes)57 - `bolta.schedule_post(post_id, suggested_time)`58 - On success: add to `scheduled_ids`, `final_states[post_id] = "scheduled"`59 - On failure: add to `failed`, post remains `approved`60 - Else (no suggested_time):61 - Add warning: "No suggested_time, post remains approved"62 - `final_states[post_id] = "approved"`6364**If schedule_mode == "set_fixed_time":**65- Requires `fixed_time` parameter66- For each approved post:67 - `bolta.schedule_post(post_id, fixed_time)`68 - On success: add to `scheduled_ids`69 - On failure: add to `failed`, post remains `approved`7071**If schedule_mode == "use_agent_memory":**72- Requires `agent_id`73- `bolta.recall(agent_id, "best_posting_times")` → get learned optimal times74- For each approved post (index i):75 - Pick schedule time from agent memory76 - `bolta.schedule_post(post_id, calculated_time)`77 - On success: add to `scheduled_ids`78 - On failure: add to `failed`, post remains `approved`7980**If schedule_times array provided:**81- Must match length of `post_ids`82- For each post (index i):83 - `bolta.schedule_post(post_ids[i], schedule_times[i])`84 - On success: add to `scheduled_ids`85 - On failure: add to `failed`, post remains `approved`8687### 5. Handle scheduling failures gracefully88- If platform API fails (Twitter down, account disconnected):89 - Post remains in `approved` state90 - Add to `failed` with specific error91 - Don't revert approval (human can retry scheduling later)92- If schedule time invalid (past, too soon):93 - Add to `failed` with validation error94 - Post remains `approved`9596### 6. Update agent memory (if agent context)97- If `agent_id` provided:98 - `bolta.remember(agent_id, "last_approval_batch_size", post_ids.length)`99 - `bolta.remember(agent_id, "approval_success_rate", success_count / total_count)`100 - If scheduling used: `bolta.remember(agent_id, "scheduled_times_used", schedule_times)`101102## Output103```json104{105 "approved_ids": ["uuid1", "uuid2", "uuid3"],106 "scheduled_ids": ["uuid1", "uuid2"],107 "failed": [108 {109 "post_id": "uuid3",110 "reason": "Platform API error: Twitter rate limit exceeded",111 "recoverable": true112 }113 ],114 "final_states": {115 "uuid1": "scheduled",116 "uuid2": "scheduled",117 "uuid3": "approved"118 }119}120```121122## Failure Handling123- **Partial approval failure:** If some posts fail to approve, continue with others.124- **Partial scheduling failure:** If some fail to schedule, others still succeed.125- **Never revert approvals:** Once approved, post stays approved even if scheduling fails.126- **Bulk operation resilience:** One failure doesn't block the batch.127128## V2 Agent Context129130**When agents use this skill:**131132**Reviewer agent reasoning:**133> "I triaged 8 inbox items and identified 5 as ready to approve. I'll approve them with schedule_mode=use_agent_memory to use the posting times I've learned perform best."134135**Key workflow:**1361. `bolta.inbox.triage` → identify ready items1372. `bolta.review.approve_and_route` → approve + schedule1383. `bolta.remember` → store approval patterns139140## Example Use Cases141142### Scenario 1: Human Manual Approval (No Scheduling)143```json144{145 "workspace_id": "uuid",146 "post_ids": ["uuid1", "uuid2", "uuid3"],147 "schedule_mode": "approve_only"148}149```150**Result:** 3 posts → `approved` state, human schedules them later151152### Scenario 2: Bulk Approve & Schedule with Suggested Times153```json154{155 "workspace_id": "uuid",156 "post_ids": ["uuid1", "uuid2", "uuid3"],157 "schedule_mode": "use_suggested_time"158}159```160**Result:** 3 posts approved → scheduled using each post's suggested_time metadata161162### Scenario 3: Reviewer Agent Auto-Approval163- Reviewer agent runs `bolta.inbox.triage`164- Identifies 8 posts as "ready to approve" (high confidence)165- Calls this skill with those 8 post_ids + `schedule_mode: use_agent_memory`166- Agent uses learned optimal posting times167- 8 posts → approved → scheduled168- Human reviews retrospectively169170### Scenario 4: Agency Bulk Scheduling171- Agency approves 20 client posts172- Wants them all to go out at 10am tomorrow173- `schedule_mode: set_fixed_time`, `fixed_time: "2026-02-21T10:00:00Z"`174- 20 posts → approved → scheduled for same time175176### Scenario 5: Partial Failure Recovery177- Approve 5 posts, schedule 5178- 2 scheduling calls fail (Twitter API down)179- Output: 5 approved, 3 scheduled, 2 failed (but still approved)180- Human can retry scheduling the 2 later when Twitter is back181182---183> Converted and distributed by [TomeVault](https://tomevault.io/claim/boltaai) — claim your Tome and manage your conversions.184<!-- tomevault:4.0:skill_md:2026-04-13 -->