# Profiles

Profiles define the agent's identity, tools, and behaviour for a specific domain.

## Profile definition (`navi/profiles/base.py`)

Each profile is loaded from a directory under `navi/profiles/<id>/`:
- `config.json` — all fields below
- `system_prompt.txt` — domain-specific instructions
- `subagent_system_prompt.txt` — injected into subagents spawned from this profile (optional)

---

## All `config.json` fields

### Identity

| Key | Type | Default | Description |
|---|---|---|---|
| `id` | str | **required** | Unique profile identifier (matches directory name) |
| `name` | str | **required** | Human-readable name shown in UI |
| `description` | str | **required** | Longer description shown in profile picker |
| `short_description` | str | `""` | One-line summary injected into every profile's system prompt (cross-profile awareness) |
| `full_description` | dict | `{}` | Structured dict: `specialization`, `when_to_use`, `key_tools` keys |

### LLM

| Key | Type | Default | Description |
|---|---|---|---|
| `llm_backend` | str | `"ollama"` | Backend key: `"ollama"`, `"openai"` |
| `model` | str or list[str] | `["gemma4:31b-cloud"]` | Model priority list — first available wins. String is accepted and auto-wrapped. |
| `temperature` | float | `0.7` | Sampling temperature for main loop calls |
| `max_iterations` | int | `20` | Hard cap on tool-calling iterations per turn |

### Tools

| Key | Type | Default | Description |
|---|---|---|---|
| `enabled_tools` | list[str] | **required** | Tool names available in the main loop |
| `subagent_tools` | list[str] | `[]` | Tools available to sub-agents spawned from this profile. Falls back to `enabled_tools` if empty. |

### Thinking mechanics

| Key | Type | Default | Description |
|---|---|---|---|
| `think_enabled` | bool | `true` | Pass `think=True` to LLM on every call (extended reasoning). Disable for latency-sensitive profiles. |
| `iteration_budget_enabled` | bool | `true` | Inject remaining iteration count into context so the model knows when to wrap up. |
| `goal_anchoring_enabled` | bool | `true` | Inject a goal-reminder system message every N iterations to prevent drift. |
| `goal_anchoring_interval` | int | `5` | N for goal anchoring. |
| `anti_stall_enabled` | bool | `true` | Detect looping without todo progress and inject a hard warning. |
| `anti_stall_threshold` | int | `8` | Consecutive iterations without progress before stall warning fires. |
| `step_validation_enabled` | bool | `false` | After each todo step is marked done, run a lightweight LLM check: "did the result satisfy the goal?" Adds ~1 LLM call per step. |
| `adaptive_replan_enabled` | bool | `false` | When a todo step is marked failed, trigger a re-planning pass. Depends on `step_validation_enabled`. |

### Planning

The planning pipeline runs before the main tool-calling loop and produces a structured execution plan. It has three phases:

- **Phase 1 — Analysis**: reformulates the task, identifies subtasks and unknowns. Can output `DIRECT` to skip to execution immediately.
- **Phase 2 — Structured review**: one LLM call critiques the Phase 1 analysis through Critic / Pragmatist / Detailer sections and emits Plan Adjustments. Runs only when Phase 1 signals `REFLECT: yes`.
- **Phase 3 — Execution plan**: assigns each subtask to `TOOL / AGENT / SELF` and uses adaptive plan depth.

| Key | Type | Default | Description |
|---|---|---|---|
| `planning_enabled` | bool | `false` | Run the planning pipeline on every user message (not just the first). First-message planning always runs regardless of this flag. |
| `planning_mandatory` | bool | `false` | `true` — the `DIRECT` shortcut is never offered to the model; all three phases always run. `false` — the model can output `DIRECT` in Phase 1 to skip straight to execution. First-message planning is always forced regardless of this flag. |
| `planning_phase1_enabled` | bool | `true` | Enable Phase 1 (task analysis). When disabled, Phase 3 runs without analysis context. |
| `planning_phase2_enabled` | bool | `false` | Enable Phase 2 structured review. Adds one LLM call only when Phase 1 signals `REFLECT: yes`. |
| `planning_phase3_enabled` | bool | `true` | Enable Phase 3 (structured execution plan). When disabled, only Phase 1 (analysis) runs. |

### Sub-agent planning

| Key | Type | Default | Description |
|---|---|---|---|
| `subagent_planning_enabled` | bool | `false` | Sub-agents spawned from this profile also run the planning pipeline before their tool loop. |

---

## Active profiles

| ID | Name | Models (priority order) | Temp | Planning |
|---|---|---|---|---|
| `secretary` | Personal Secretary | gemma4:31b-cloud → gemma4:26b-a4b-it-q4_K_M | 0.65 | Yes |
| `server_admin` | Server Administrator | gemma4:31b-cloud → gemma4:26b-a4b-it-q4_K_M | 0.3 | Yes |
| `developer` | Developer | gemma4:31b-cloud → gemma4:26b-a4b-it-q4_K_M | 0.45 | Yes |
| `tool_developer` | Tool Developer | gemma4:31b-cloud → gemma4:26b-a4b-it-q4_K_M | 0.35 | Yes |
| `discuss` | Discussion | gemma4:31b-cloud → gemma4:26b-a4b-it-q4_K_M | 0.85 | No |
| `modeler_3d` | 3D Modeler | gemma4:26b-a4b-it-q4_K_M → gemma4:31b-cloud | 0.35 | Yes |

All profiles share a base tool set. User tools from `tools/enabled.json` are merged in at runtime.

---

## System prompt construction

The LLM sees (injected fresh on every call, never stored in session):

```
{persona.txt content}

---

{profile system_prompt.txt content}
```

`persona.txt` — global layer: personality, CONTEXT FIRST principle, self-extension rules, scratchpad/todo/memory instructions, delegation rules.

`system_prompt.txt` — domain layer: tool priorities, workflow, safety rules for this profile.

---

## Adding a profile

1. Create directory `navi/profiles/my_profile/`
2. Add `config.json` (minimal example):
```json
{
  "id": "my_profile",
  "name": "My Profile",
  "description": "...",
  "short_description": "...",
  "model": ["gemma4:31b-cloud", "gemma4:26b-a4b-it-q4_K_M"],
  "temperature": 0.5,
  "max_iterations": 20,
  "enabled_tools": ["todo", "scratchpad", "web_search", "filesystem"],
  "subagent_tools": ["todo", "filesystem", "terminal"],
  "planning_enabled": true,
  "planning_mandatory": false,
  "planning_phase1_enabled": true,
  "planning_phase2_enabled": false,
  "planning_phase3_enabled": true,
  "think_enabled": true,
  "iteration_budget_enabled": true,
  "goal_anchoring_enabled": true,
  "goal_anchoring_interval": 5,
  "anti_stall_enabled": true,
  "anti_stall_threshold": 8,
  "step_validation_enabled": false,
  "adaptive_replan_enabled": false,
  "subagent_planning_enabled": false
}
```
3. Add `system_prompt.txt` with domain-specific instructions.
4. Optionally add `subagent_system_prompt.txt`.
5. The profile is auto-discovered at startup — no registration needed.

---

## Profile switching

`switch_profile` tool updates `session.profile_id` in the DB. After each tool execution batch, `run_stream()` checks for a profile change and reloads profile + tools. Takes effect on the next LLM call.

Rules (in persona): don't switch for a single off-topic question; switch when the domain clearly changes; never switch back and forth repeatedly.
