Appearance
Goals & Reflection
Uranus agents are designed to operate autonomously over long horizons. Two primitives close the loop between what an agent is trying to do and what it actually did: goals and reflections.
Why this exists
A pure chat-driven agent forgets why it acted as soon as a conversation ends. With goals declared and a periodic self-review running, the agent can:
- Stay aligned with declared objectives across conversations and gateways
- Notice patterns in its own behaviour (failed workflows, recurring requests)
- Update its plan without a human re-prompting it every turn
- Propose new automations (draft workflows) when something looks worth automating
Goals
A goal is a durable objective the agent persists across sessions. Goals live in the agent_goals table and are loaded into the system prompt every turn.
Fields
| Column | Purpose |
|---|---|
description | What the agent is pursuing (1–2 sentences) |
status | active · paused · completed · abandoned |
priority | 1 (low) – 10 (high), default 5 |
target_date | Optional ISO date for soft deadline |
progress_notes | Accumulating log of what's been done; appended by workflows and reflections |
parent_goal_id | Optional hierarchy for sub-goals |
source | user · reflection · workflow · system |
LLM tools
| Tool | Effect |
|---|---|
set_goal(description, priority?, target_date?, parent_goal_id?, workflow_ids?) | Declare a new goal. Pass workflow_ids to pre-link workflows that pursue it. |
update_goal(goal_id, status?, progress?, priority?) | Revise a goal. |
list_goals(status?) | Read goals. Returns linked workflows in the same row. |
Workflow linkage
When a workflow runs successfully and was invoked with execute_workflow(workflowId, ..., goal_id=...), the goal's progress_notes get a new line:
[2026-05-15] Daily standup: completedThe goal_workflows(goal_id, workflow_id, role, weight) table holds the many-to-many. role is one of achieves (completes the goal), advances (pushes forward), or evaluates (checks status).
Reflections
A reflection is a structured self-review that the agent runs against its own recent activity. The output is a row in agent_reflections:
| Column | Purpose |
|---|---|
period_start, period_end | Window the reflection covered |
trigger | scheduled · manual · error_spike · goal_deadline |
observations | What actually happened (3–5 sentences) |
learnings | Bullet list — what to do differently |
plan | Specific actions for the next period |
goal_updates | JSON: which goals were advanced/paused/completed |
metrics | JSON snapshot: tool calls, errors, messages, money flow, schedules |
model_id | Which LLM produced the reflection |
When reflections run
- Daily cron at 03:00 UTC, auto-seeded on first agent wake (
callback: "reflection:24h") - Manual via
reflect_now(period?)tool — useful when something just changed materially - Error spike when more than 5 workflow failures land in a 10-minute window (throttled to once per 30 minutes)
Inputs the reflection LLM sees
For the chosen time window, gatherSignals pulls in parallel:
- Currently active goals (top 10 by priority)
- Message counts split by role
- Tool call breakdown (via
json_eachonchat_messages.metadata.toolCalls) - Recent error log entries from
agent_logs - Workflow execution status counts and per-workflow rollup (W6)
- Schedule fire counts
- Money flow (in/out USD from
transactions) - Top active contacts
- Recent conversation summaries
- The previous reflection's plan (for continuity)
Output structure
The reflection LLM returns JSON:
json
{
"observations": "...",
"learnings": "...",
"plan": "...",
"goal_updates": [
{"goal_id": "...", "status": "completed", "progress": "shipped"}
],
"new_goals": [
{"description": "Audit weekly invoices", "priority": 6}
],
"reflective_memories": [
{"topic": "user-prefers-tldr", "fact": "User explicitly asked for shorter answers"}
],
"proposed_workflows": [
{
"description": "Auto-tag incoming receipts",
"trigger_kind": "gateway_event",
"outline": "Step 1: detect attachment...\nStep 2: ..."
}
]
}Side effects of applyReflection
| Output field | Where it lands |
|---|---|
observations / learnings / plan | agent_reflections row |
goal_updates | agent_goals rows updated (status / progress_notes) |
new_goals | agent_goals rows inserted with source='reflection' |
reflective_memories | memory:reflection:{date}:{topic} keys in agent_state + embedded into Vectorize at confidence 0.85 |
proposed_workflows | workflows rows inserted with status='draft' source='reflection' (never auto-activated) |
Re-injection into the next turn
The system prompt loader (buildEnhancedSystemPrompt) reads the most recent reflection (within 7 days) and surfaces its plan + learnings as a dedicated section:
## Recent Self-Reflection (2026-05-15T03:00:00Z)
**Plan from last reflection:** Focus on...
**Recent learnings:** ...This closes the loop — reflections don't get written to a black hole; they shape behaviour on the next turn.
Draft workflows
Workflows proposed by reflection are inserted with status='draft' and source='reflection'. They appear in the existing Workflows UI tab (filterable by status). The agent can list and approve them via two LLM tools:
| Tool | Effect |
|---|---|
list_draft_workflows() | Returns drafts pending review |
activate_draft_workflow(workflow_id) | Flips draft → active. Requires user approval (in TOOLS_REQUIRING_APPROVAL). Mints the workflow's callback secret + embeds it for semantic discovery. |
Cost
Reflection runs use @cf/zai-org/glm-4.7-flash with a fallback to Llama 4 Scout. At Cloudflare Workers AI rates (verified 2026-05-15):
- glm-4.7-flash: $0.06 / 1M input, $0.40 / 1M output tokens
- A daily reflection ≈ 2K input tokens + 500 output tokens ≈ $0.0003/day per agent
Schema
See migrations:
058_agent_goals.sql059_agent_reflections.sql
Related
- Agent Memory — where reflective memories live and how they're recalled
- Workflows — goal-workflow linkage and draft workflows in detail
- Scheduling — the daily reflection cron and other auto-seeded jobs
