> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gainable.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent action log

> The audit trail for everything a Autopilot agent does

## What is the action log?

Every time a Autopilot agent runs, the runtime records what happened. The result is a structured, queryable log that lives in your app as the `AgentAction` collection. If something is in doubt, the action log is the source of truth.

The log captures four things for every run:

1. **The trigger.** Which playbook fired and why.
2. **The observation.** What the agent looked at (records, signals, prior actions).
3. **The reasoning.** What the agent decided and why.
4. **The outcome.** Which tools ran, what they returned, what happened next.

This isn't optional. The log is always on. The runtime cannot run a tool without writing to it.

## Why every action is logged

* **Trust.** Users approve drafts faster when they can see the full reasoning chain. Skeptics become believers when they can audit every step.
* **Debugging.** When a playbook misbehaves, the log shows where the reasoning went sideways.
* **Compliance.** Regulated environments need provable audit trails. The log is structured for export.
* **Graduation.** [Risk tier graduation](/autopilot/risk-tiers) uses approval rates from the log. No log, no graduation.
* **Improvement.** Approval and skip patterns reveal which objectives are tuned correctly and which need editing.

## Schema

The `AgentAction` collection is a system-managed collection in every Gainable app. You can query it through the [Copilot](/copilots/overview), the dashboard, or the action log UI in [Autopilot](/autopilot/inbox).

| Field | Type | What it stores |
| - | - | - |
| `id` | string | Unique action ID |
| `agent_id` | string | The agent that produced the action |
| `playbook_id` | string | The playbook that ran |
| `objective_id` | string | The objective the playbook was working toward |
| `scope` | enum | `app_wide` or `personal` |
| `trigger_type` | enum | `schedule`, `data_change`, `webhook`, `user_triggered` |
| `trigger_payload` | json | Full payload of the trigger |
| `observation` | json | Records and signals the agent considered |
| `reasoning` | text | Human-readable reasoning chain |
| `tool_calls` | array | Each tool the playbook called, with inputs and outputs |
| `outcome` | enum | `approved`, `skipped`, `auto_executed`, `rate_limited`, `error`, `pending` |
| `owner_user_id` | string | The user the action's draft was routed to |
| `created_at` | timestamp | When the run began |
| `resolved_at` | timestamp | When the action reached a terminal outcome |
| `parent_action_id` | string | If this action was a follow-up to another |

## Outcomes

| Outcome | What it means |
| - | - |
| `pending` | Draft is waiting in Autopilot |
| `approved` | Owner approved; underlying tool ran |
| `skipped` | Owner skipped the draft |
| `auto_executed` | Action ran without approval (auto tier or auto-with-undo) |
| `rate_limited` | Action was blocked by a rate limit |
| `error` | Tool call failed; reason captured in `tool_calls[*].error` |

## Querying the log

The action log is just a collection, so you can query it the same way you query anything else.

### From Copilot

Ask the [Copilot](/copilots/overview) directly:

```text theme={null}
Show all SLA-enforcer actions from the last 7 days
where the outcome was skipped.
```

```text theme={null}
Which playbook produced the most rate_limited
outcomes this month?
```

### From a dashboard

Drop a chart or table view onto a dashboard scoped to the `AgentAction` collection:

```text theme={null}
Add a chart to the operations dashboard showing
SLA-enforcer outcomes (approved, skipped, error)
over the last 30 days, grouped by week.
```

### From a playbook

Yes, agents can read their own action log. This is how follow-up playbooks know what's already been tried:

```yaml theme={null}
- tool: query_collection
  collection: AgentAction
  filter: "playbook_id = 'stalled_deal_chaser' AND owner_user_id = {{ deal.owner }} AND created_at > now - 7_days"
  limit: 1
```

If a stalled-deal playbook sees that it already drafted a nudge for this deal in the last 7 days, it can skip drafting another. Ackermann-class loops are bounded.

## What gets logged for each tool

| Tool | Logged inputs | Logged outputs |
| - | - | - |
| `query_collection` | Filter, sort, limit, fields | Record IDs returned, count |
| `update_records` | Filter, set clause | IDs updated, prior values for undo |
| `send_email` | Recipient, subject, body hash | Provider message ID, delivery status |
| `send_slack` | Channel, message hash | Slack message ID |
| `send_sms` | Recipient hash, body hash | Provider message ID |
| `notify_user` | User ID, title, body | Notification ID |
| `call_external` | URL, method, body hash | Status code, response hash |
| `ask_human` | User ID, question, options | Answer, response time |
| `create_task` | Task fields | Created task ID |
| `draft_for_approval` | Underlying payload | Draft ID, owner |

Bodies of outbound messages are hashed by default for compactness. The full content is retained on the draft itself in [Autopilot](/autopilot/inbox) until the configured retention window closes.

## Retention

| Data | Retention |
| - | - |
| Action records | Indefinite (or per-org configured) |
| Full draft bodies | 90 days after `resolved_at` (configurable) |
| Tool input/output payloads | 30 days (configurable) |
| Hashes and metadata | Same as the action record |

For regulated environments, retention can be raised to 7+ years. For consumer-facing apps with privacy obligations, retention can be tightened.

## Common queries

### Approval rate per playbook

```text theme={null}
Show approval rate per playbook over the last 30 days,
sorted highest to lowest.
```

This is the number you watch when deciding whether to graduate a playbook to a higher [risk tier](/autopilot/risk-tiers).

### Why was this draft created?

Open the draft in [Autopilot](/autopilot/inbox). The `reasoning` and `observation` fields render alongside the proposed action. No need to query the log directly.

### What did this agent do this morning?

```text theme={null}
Show all actions from the daily-briefing agent
in the last 24 hours.
```

### Where are skips concentrated?

```text theme={null}
Which objectives have the lowest approval rate this month?
```

A low approval rate means the objective is producing drafts that don't match what users actually want. Tighten the trigger filter or revise the template.

## Best practices

<AccordionGroup>
  <Accordion title="Add a log dashboard early">
    A dashboard with approval rate, skip reasons, and rate-limited counts is the single most useful artifact for tuning agents. Add it during the autonomy build phase.
  </Accordion>

  <Accordion title="Watch errors aggressively">
    Errors in `tool_calls` are usually a sign of upstream changes (renamed fields, missing API keys, deleted records). Spikes mean something broke.
  </Accordion>

  <Accordion title="Use parent_action_id for follow-ups">
    When playbook B runs because playbook A's draft was approved, link them. The thread of reasoning becomes traceable.
  </Accordion>

  <Accordion title="Don't write to AgentAction yourself">
    The runtime owns the schema. Custom apps that try to insert their own action records will fail validation. Use [`create_task`](/autopilot/tools) for human-visible TODOs instead.
  </Accordion>
</AccordionGroup>

## Learn more

<CardGroup cols={2}>
  <Card title="Tools" icon="screwdriver-wrench" href="/autopilot/tools">
    What gets logged per tool
  </Card>

  <Card title="Risk tiers" icon="shield-check" href="/autopilot/risk-tiers">
    How the log feeds graduation
  </Card>

  <Card title="Inbox" icon="inbox" href="/autopilot/inbox">
    Where the log surfaces in the UI
  </Card>

  <Card title="Scopes" icon="user-shield" href="/autopilot/scopes">
    How log slicing maps to scope
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.