# Agent Smith System Prompt Workflow

## Overview

Agent Smith builds a **single system-prompt string** per turn from deterministic blocks, then prepends it to conversation messages for the LLM.

High-level behavior:

1. Resolve active role (`direct` / `orchestrator` / `worker` / `explorer`).
2. Build prompt blocks in fixed order.
3. Join non-empty blocks with double newlines.
4. Prepend result as `system` message before transcript messages.
5. Build tool specs separately (`tool:llm_specs(role)`), independent from prompt text.

Primary assembly entrypoint: `agent_smith/agent_smith/prompt.lua` (`build_system_prompt`, `build_messages`).

---

## Source-of-truth files

- Prompt assembly
  - `agent_smith/agent_smith/prompt.lua`
  - `agent_smith/agent_smith/prompt/template.lua`
  - `agent_smith/agent_smith/prompt/role.lua`
  - `agent_smith/agent_smith/prompt/project.lua`
- Role specs + policy matrix
  - `agent_smith/agent_smith/role.lua`
  - `agent_smith/agent_smith/role/matrix.lua`
- Runtime/turn call sites
  - `agent_smith/agent_smith/core/turn.lua`
  - `agent_smith/agent_smith/core/runtime.lua`
  - `agent_smith/agent_smith/conversation.lua`
- Dispatch child-role path
  - `agent_smith/agent_smith/dispatch/worker.lua`
- `/prompt` command path
  - `agent_smith/agent_smith/command/builtin.lua`
- Supporting docs
  - `agent_smith/README.md`
  - `agent_smith/docs/ARCHITECTURE.md`

---

## End-to-end runtime call flow (normal turn)

1. `runtime:process_raw_input(line)` routes non-slash input to `runtime:run_turn(...)`
   (`process_raw_input` / `run_turn` in `core/runtime.lua`).
2. `runtime:run_turn` delegates to `core.turn.run`
   (`run_turn` in `core/runtime.lua`).
3. During the turn, project memories for the turn scope are loaded from
   persistence and injected into the prompt build:
   `repos = services.persistence.repositories()` → `repos.project_memory.list(active_turn.project_id)` →
   `services.prompt.build_system_prompt(active_turn, role_spec, project_memories)`
   (`load_project_memories` and the `build_system_prompt` call in `core/turn.lua`).
4. User message is appended to conversation state (`append_user` in
   `core/turn.lua` / `conversation.lua`).
5. `conversation.build_model_messages` prepends the `system` message, then the
   transcript messages (`build_model_messages` in `conversation.lua`).
6. Tool definitions are attached separately via `services.tool:llm_specs(role_spec.name)`
   (`core/turn.lua`).
7. LLM request is sent with `{ model, messages, tools? }` (`core/turn.lua`).
---

## Exact system-prompt block order

`build_system_prompt(context, role_spec, project_memories)` in `prompt.lua` builds blocks in this order:

1. **Role frame**
2. **Project context**
3. **Project-memory index** (only when memories are provided)

Assembly behavior:

- The `assemble` helper in `prompt/template.lua` filters empty blocks and concatenates non-empty blocks with `"\n\n"` (double newline).
---

## Per-block details

### 1) Role frame

- Source: `prompt/role.lua`
- Selector: `role_spec.prompt_profile` from role catalog (`role.lua`)
- API: `get_prompt_fragment(profile_name)` (`prompt/role.lua`)

Profiles provided:

- `direct`: full coding assistant, can dispatch worker/explorer.
- `orchestrator`: planning/delegation assistant, no file mutation, use record/recall.
- `worker`: delegated implementation agent, may dispatch to explorer.
- `explorer`: read-focused investigation agent, do not mutate files.

### 2) Project context

- Source: `prompt/project.lua`
- The block is emitted only when `turn.project` is present.
- Markdown shape:

```md
## Project information
- CWD: <turn.cwd>                       # included when available
- Repository root: <project.root|cwd>   # included when available
- Git origin: <project.origin>           # optional
- Normalized origin: <project.normalized># optional
- Project ID: <turn.project_id>          # optional

## Project context                         # optional section
<contents of <repo-root>/<runtime.index_file>>
```

- `runtime.index_file` defaults to `INDEX.md` (config loader default).
- The index file is resolved only at Git repository root (`<repo-root>/<runtime.index_file>`), not relative to arbitrary CWD locations.
- The `## Project context` section is appended only when the resolved index file exists and is non-empty.

### 3) Project-memory index

- Builder: `prompt.lua`
- Added only when `project_memories` is non-empty
- Structure:
  - `## Project memory index`
  - `project_id`
  - per-entry `id` + `label` (the memory's first content line, capped ~80 chars)

## Role-by-role prompt differences

Role spec source: `role.lua`; policy source: `role/matrix.lua`; role text source: `prompt/role.lua`.

### direct

- `prompt_profile`: `direct` (`role.lua`)
- Dispatch targets: `worker`, `explorer` (`role.lua`, `matrix.lua`)
- Allowed tools (`matrix.lua`):
  - `bash`, `read`, `code_map`, `code_grep`, `code_files`, `code_symbols`, `code_outline`, `edit`, `write`, `web_search`, `web_fetch`, `note`, `dispatch`
- Denied tools:
  - `report`, `record`, `recall`

### orchestrator

- `prompt_profile`: `orchestrator` (`role.lua`)
- Dispatch targets: `worker`, `explorer` (`role.lua`, `matrix.lua`)
- Allowed tools (`matrix.lua`):
  - `read`, `code_map`, `code_grep`, `code_files`, `code_symbols`, `code_outline`, `git`, `record`, `recall`, `note`, `dispatch`
- Denied tools:
  - `bash`, `edit`, `write`, `web_search`, `web_fetch`, `report`

### worker

- `prompt_profile`: `worker` (`role.lua`)
- Dispatch targets: `explorer` only (`role.lua`, `matrix.lua`)
- Allowed tools (`matrix.lua`):
  - `bash`, `read`, `code_map`, `code_grep`, `code_files`, `code_symbols`, `code_outline`, `edit`, `write`, `web_search`, `web_fetch`, `report`, `dispatch`
- Denied tools:
  - `record`, `recall`, `note`

### explorer

- `prompt_profile`: `explorer` (`role.lua`)
- Dispatch targets: none (`role.lua`, `matrix.lua`)
- Allowed tools (`matrix.lua`):
  - `bash`, `read`, `code_map`, `code_grep`, `code_files`, `code_symbols`, `code_outline`, `web_search`, `web_fetch`, `report`
- Denied tools:
  - `edit`, `write`, `record`, `recall`, `note`, `dispatch`

---

## `/prompt` command path

Route + execution path:

1. `/prompt` parsed by the command router (`command/router.lua`).
2. Runtime slash path invokes `runtime:run_command(...)` (`core/runtime.lua`).
3. Builtin handler routes to `handle_prompt` (`command/builtin.lua`).
4. Preferred path uses `build_current_system_prompt` from the runtime context (`command/builtin.lua`).
5. Runtime callback loads memories for the current scope via `persistence.repositories().project_memory.list(scope.project_id)` and builds the prompt (`core/runtime.lua`).
6. Fallback path resolves repositories from the command context and likewise loads `repos.project_memory.list(project_id)` before prompt build (`command/builtin.lua`).
7. If project id/repositories/listing are unavailable or fail, both paths degrade to `project_memories = {}` and still return a prompt (without the memory block).

---

## Dispatch child-role prompt path

Child dispatch flow (`dispatch/worker.lua`):

1. Build child execution context with `active_role = job.target_role` (`dispatch/worker.lua`).
2. Build child turn request with `role = job.target_role` (`dispatch/worker.lua`).
3. Launch child via `core.turn.run(child_runtime, child_request, ...)` (`dispatch/worker.lua`).
4. Child turn uses the same normal turn prompt path, including `load_project_memories(...)` and `build_system_prompt(active_turn, role_spec, project_memories)` (`core/turn.lua`).

So dispatch children inherit the same turn-based memory loading behavior as normal turns.

---

## Project-memory runtime behavior

- Normal turns load project memories from persistence repositories via `project_memory.list(active_turn.project_id)` before prompt assembly (`load_project_memories` in `core/turn.lua`).
- `/prompt` loads memories for the current scope in the runtime callback and in the builtin fallback using command-context repositories (`core/runtime.lua`, `command/builtin.lua`).
- On missing `project_id`, missing repositories, or repository/list failures, prompt building continues with empty memories; the project-memory block is omitted.
