# Agent Tasks: Short-Term Memory via Context-Injected Task List

## Summary

Add a **tasks** system that serves as the agent's short-term working memory. The agent can break down goals into steps, track progress, and see its current task list in every prompt context. Tasks are file-backed (not stored on Nostr) and managed via a dedicated `task_manage` tool.

## How It Works

```mermaid
flowchart TD
    A[User sends message] --> B[Context builder runs]
    B --> C[Template resolver hits tasks_content variable]
    C --> D[Read tasks.json from disk]
    D --> E{Tasks exist?}
    E -->|Yes| F[Format tasks as readable text]
    E -->|No| G[Return empty string - section skipped]
    F --> H[Inject as system message in prompt]
    G --> H
    H --> I[LLM sees current tasks in context]
    I --> J{LLM decides to update tasks?}
    J -->|Yes| K[LLM calls task_manage tool]
    K --> L[Tool updates tasks.json on disk]
    L --> M[Tool result returned to LLM]
    J -->|No| N[LLM responds normally]
```

## Design

### Storage: `tasks.json`

A simple JSON file in the agent's working directory. Structure:

```json
{
  "tasks": [
    {
      "id": 1,
      "text": "Query admin relay list to find active relays",
      "status": "done",
      "created_at": 1709535600,
      "updated_at": 1709535660
    },
    {
      "id": 2,
      "text": "Draft long-form article about Nostr relay setup",
      "status": "active",
      "created_at": 1709535600,
      "updated_at": 1709535600
    },
    {
      "id": 3,
      "text": "Publish article as kind 30023",
      "status": "pending",
      "created_at": 1709535600,
      "updated_at": 1709535600
    }
  ],
  "next_id": 4
}
```

Task statuses: `pending`, `active`, `done`

### Tool: `task_manage`

A single tool with an `action` parameter that covers all operations:

| Action | Parameters | Description |
|--------|-----------|-------------|
| `list` | *(none)* | Return all tasks with status |
| `add` | `text`, optional `status` | Add a new task, default status `pending` |
| `update` | `id`, optional `text`, optional `status` | Update text and/or status of a task |
| `remove` | `id` | Remove a task by ID |
| `clear` | optional `status` | Remove all tasks, or all with a given status |
| `replace` | `tasks` (array of text strings) | Replace entire task list with new items |

The `replace` action is important — it lets the LLM rewrite the whole plan in one call rather than doing add/remove/update one at a time. This is the most common pattern: the agent works out a plan and writes all steps at once.

**Tool schema:**

```json
{
  "name": "task_manage",
  "description": "Manage the agent task list - short-term working memory for tracking steps in a plan. Tasks appear in your context on every message.",
  "parameters": {
    "type": "object",
    "properties": {
      "action": {
        "type": "string",
        "enum": ["list", "add", "update", "remove", "clear", "replace"]
      },
      "text": { "type": "string" },
      "id": { "type": "integer" },
      "status": { "type": "string", "enum": ["pending", "active", "done"] },
      "tasks": {
        "type": "array",
        "items": { "type": "string" }
      }
    },
    "required": ["action"]
  }
}
```

### Context Section: `agent_tasks`

New section in the context template, placed after `adopted_skills` and before `dm_history`:

```yaml
- section: agent_tasks
  role: system
  skip_if_empty: true
  content: |
    {{tasks_content}}
```

### Template Variable: `{{tasks_content}}`

New resolver in `agent_template_resolve_var()` that:

1. Reads `tasks.json` from the working directory
2. Parses the JSON
3. Formats active/pending tasks as readable text
4. Returns empty string if no tasks exist (section gets skipped via `skip_if_empty`)

**Rendered format in context:**

```
### Current Tasks

Your active task list - short-term working memory for tracking plan steps.

- [x] 1. Query admin relay list to find active relays
- [-] 2. Draft long-form article about Nostr relay setup
- [ ] 3. Publish article as kind 30023
```

Legend: `[x]` = done, `[-]` = active, `[ ]` = pending

Done tasks are included so the agent has continuity about what it already accomplished, but they could be pruned after a configurable count or age to save tokens.

### System Prompt Addition

Add to the agent's behavioral rules in the soul/system prompt:

```
### Task Management
- You have a task list that serves as your short-term working memory.
- When working on multi-step goals, use task_manage to track your plan.
- Update task status as you complete steps.
- Your current tasks appear in your context automatically.
```

## Implementation Steps

### 1. Add `task_manage` tool implementation in `tools.c`

- New `execute_task_manage()` function
- Reads/writes `tasks.json` in the working directory (uses `build_tool_path` for sandboxing)
- Handles all 6 actions: list, add, update, remove, clear, replace
- Returns JSON result with success/failure and current task list

### 2. Register `task_manage` tool schema in `tools_build_openai_schema_json()`

- Add tool definition (t35 or next available) with the schema above

### 3. Wire `task_manage` into `tools_execute()` dispatch

- Add `strcmp(tool_name, "task_manage")` branch calling `execute_task_manage()`

### 4. Add `{{tasks_content}}` template variable resolver in `agent.c`

- New `build_tasks_content_string()` function
- Reads `tasks.json`, formats as markdown checklist
- Add to `agent_template_resolve_var()` for var name `tasks_content`

### 5. Add `agent_tasks` section to context template

- Add the new section in `context_template.md`
- Place after `adopted_skills`, before `dm_history`
- Use `skip_if_empty: true` so it costs zero tokens when no tasks exist

### 6. Add section detection for context logging

- Add `agent_tasks` detection in `detect_context_section()` in `agent.c`

### 7. Add task management guidance to system prompt

- Brief behavioral instruction so the agent knows when/how to use the task list

## Token Budget Considerations

- Empty task list: **0 tokens** (skipped via `skip_if_empty`)
- Typical 5-task plan: **~80-120 tokens**
- Maximum reasonable list of 15 tasks: **~250-350 tokens**
- Consider pruning done tasks older than N turns or keeping only the last M done tasks

## Future: User-Facing To-Do List (Nostr)

This is explicitly **not** the user-facing to-do list. That future feature would:
- Store items as Nostr events (likely a NIP-51 style list or custom kind)
- Be visible to the user via Nostr clients
- Have its own separate tool (`todo_manage` or similar)
- Potentially reference agent tasks that graduate to user-visible items

The agent tasks system is purely internal working memory.

## Files Modified

| File | Change |
|------|--------|
| `src/tools.c` | Add `execute_task_manage()`, tool schema, dispatch entry |
| `src/agent.c` | Add `build_tasks_content_string()`, resolver entry, section detection |
| `context_template.md` | Add `agent_tasks` section |
| Soul/system prompt (kind 31120) | Add task management behavioral guidance |
